* fix a bug where clicking on the message tab made keyboard accelerators stop working
[geda-gerbv.git] / src / gerb_image.c
bloba83ebaaaa52c379fd6d184bf2c056d4e02d5a502
1 /*
2 * gEDA - GNU Electronic Design Automation
3 * This files is a part of gerbv.
5 * Copyright (C) 2000-2003 Stefan Petersen (spe@stacken.kth.se)
7 * $Id$
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.
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.
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
24 /** \file gerb_image.c
25 \brief This file contains general files for handling the gerbv_image_t structure
26 \ingroup libgerbv
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
33 #include <stdlib.h>
34 #include <string.h>
35 #include <glib.h>
36 #include <math.h>
38 #include "gerbv.h"
39 #include "gerb_image.h"
40 #include "gerber.h"
41 #include "amacro.h"
43 typedef struct {
44 int oldAperture;
45 int newAperture;
46 } gerb_translation_entry_t;
48 gerbv_image_t *
49 gerbv_create_image(gerbv_image_t *image, const gchar *type)
51 gerbv_destroy_image(image);
53 /* Malloc space for image */
54 if ((image = (gerbv_image_t *)g_malloc(sizeof(gerbv_image_t))) == NULL) {
55 return NULL;
57 memset((void *)image, 0, sizeof(gerbv_image_t));
59 /* Malloc space for image->netlist */
60 if ((image->netlist = (gerbv_net_t *)g_malloc(sizeof(gerbv_net_t))) == NULL) {
61 g_free(image);
62 return NULL;
64 memset((void *)image->netlist, 0, sizeof(gerbv_net_t));
66 /* Malloc space for image->info */
67 if ((image->info = (gerbv_image_info_t *)g_malloc(sizeof(gerbv_image_info_t))) == NULL) {
68 g_free(image->netlist);
69 g_free(image);
70 return NULL;
72 memset((void *)image->info, 0, sizeof(gerbv_image_info_t));
74 /* Set aside position for stats struct */
75 image->gerbv_stats = NULL;
76 image->drill_stats = NULL;
78 image->info->min_x = HUGE_VAL;
79 image->info->min_y = HUGE_VAL;
80 image->info->max_x = -HUGE_VAL;
81 image->info->max_y = -HUGE_VAL;
83 /* create our first layer and fill with non-zero default values */
84 image->layers = g_new0 (gerbv_layer_t, 1);
85 image->layers->stepAndRepeat.X = 1;
86 image->layers->stepAndRepeat.Y = 1;
87 image->layers->polarity = GERBV_POLARITY_DARK;
89 /* create our first netstate and fill with non-zero default values */
90 image->states = g_new0 (gerbv_netstate_t, 1);
91 image->states->scaleA = 1;
92 image->states->scaleB = 1;
94 /* fill in some values for our first net */
95 image->netlist->layer = image->layers;
96 image->netlist->state = image->states;
98 if (type == NULL)
99 image->info->type = g_strdup ("unknown");
100 else
101 image->info->type = g_strdup (type);
103 /* the individual file parsers will have to set this. */
104 image->info->attr_list = NULL;
105 image->info->n_attr = 0;
107 return image;
111 void
112 gerbv_destroy_image(gerbv_image_t *image)
114 int i;
115 gerbv_net_t *net, *tmp;
116 gerbv_layer_t *layer;
117 gerbv_netstate_t *state;
118 gerbv_simplified_amacro_t *sam,*sam2;
120 if(image==NULL)
121 return;
124 * Free apertures
126 for (i = 0; i < APERTURE_MAX; i++)
127 if (image->aperture[i] != NULL) {
128 for (sam = image->aperture[i]->simplified; sam != NULL; ){
129 sam2 = sam->next;
130 g_free (sam);
131 sam = sam2;
134 g_free(image->aperture[i]);
135 image->aperture[i] = NULL;
139 * Free aperture macro
142 if (image->amacro) {
143 free_amacro(image->amacro);
147 * Free format
149 if (image->format)
150 g_free(image->format);
153 * Free info
155 if (image->info) {
156 g_free(image->info->name);
157 g_free(image->info->type);
158 gerbv_attribute_destroy_HID_attribute (image->info->attr_list, image->info->n_attr);
159 g_free(image->info);
163 * Free netlist
165 for (net = image->netlist; net != NULL; ) {
166 tmp = net;
167 net = net->next;
168 if (tmp->cirseg != NULL) {
169 g_free(tmp->cirseg);
170 tmp->cirseg = NULL;
172 if (tmp->label) {
173 g_string_free (tmp->label, TRUE);
175 g_free(tmp);
176 tmp = NULL;
178 for (layer = image->layers; layer != NULL; ) {
179 gerbv_layer_t *tempLayer = layer;
181 layer = layer->next;
182 g_free (tempLayer);
184 for (state = image->states; state != NULL; ) {
185 gerbv_netstate_t *tempState = state;
187 state = state->next;
188 g_free (tempState);
190 gerbv_stats_destroy(image->gerbv_stats);
191 gerbv_drill_stats_destroy(image->drill_stats);
194 * Free and reset the final image
196 g_free(image);
197 image = NULL;
199 return;
204 * Check that the parsed gerber image is complete.
205 * Returned errorcodes are:
206 * 0: No problems
207 * 1: Missing netlist
208 * 2: Missing format
209 * 4: Missing apertures
210 * 8: Missing info
211 * It could be any of above or'ed together
213 gerb_verify_error_t
214 gerbv_image_verify(gerbv_image_t const* image)
216 gerb_verify_error_t error = GERB_IMAGE_OK;
217 int i, n_nets;;
218 gerbv_net_t *net;
220 if (image->netlist == NULL) error |= GERB_IMAGE_MISSING_NETLIST;
221 if (image->format == NULL) error |= GERB_IMAGE_MISSING_FORMAT;
222 if (image->info == NULL) error |= GERB_IMAGE_MISSING_INFO;
224 /* Count how many nets we have */
225 n_nets = 0;
226 if (image->netlist != NULL) {
227 for (net = image->netlist->next ; net != NULL; net = net->next) {
228 n_nets++;
232 /* If we have nets but no apertures are defined, then complain */
233 if( n_nets > 0) {
234 for (i = 0; i < APERTURE_MAX && image->aperture[i] == NULL; i++);
235 if (i == APERTURE_MAX) error |= GERB_IMAGE_MISSING_APERTURES;
238 return error;
239 } /* gerb_image_verify */
242 static void
243 gerbv_image_interpolation(gerbv_interpolation_t interpolation)
245 switch (interpolation) {
246 case GERBV_INTERPOLATION_LINEARx1:
247 printf("linearX1");
248 break;
249 case GERBV_INTERPOLATION_x10:
250 printf("linearX10");
251 break;
252 case GERBV_INTERPOLATION_LINEARx01:
253 printf("linearX01");
254 break;
255 case GERBV_INTERPOLATION_LINEARx001:
256 printf("linearX001");
257 break;
258 case GERBV_INTERPOLATION_CW_CIRCULAR:
259 printf("CW circular");
260 break;
261 case GERBV_INTERPOLATION_CCW_CIRCULAR:
262 printf("CCW circular");
263 break;
264 case GERBV_INTERPOLATION_PAREA_START:
265 printf("polygon area start");
266 break;
267 case GERBV_INTERPOLATION_PAREA_END:
268 printf("polygon area end");
269 break;
270 default:
271 printf("unknown");
273 } /* gerb_image_interpolation */
275 static void
276 gerbv_image_aperture_state(gerbv_aperture_state_t state)
278 switch (state) {
279 case GERBV_APERTURE_STATE_OFF:
280 printf("..state off");
281 break;
282 case GERBV_APERTURE_STATE_ON:
283 printf("..state on");
284 break;
285 case GERBV_APERTURE_STATE_FLASH:
286 printf("..state flash");
287 break;
288 default:
289 printf("..state unknown");
293 /* Dumps a written version of image to stdout */
294 void
295 gerbv_image_dump(gerbv_image_t const* image)
297 int i, j;
298 gerbv_aperture_t * const* aperture;
299 gerbv_net_t const * net;
301 /* Apertures */
302 printf("Apertures:\n");
303 aperture = image->aperture;
304 for (i = 0; i < APERTURE_MAX; i++) {
305 if (aperture[i]) {
306 printf(" Aperture no:%d is an ", i);
307 switch(aperture[i]->type) {
308 case GERBV_APTYPE_CIRCLE:
309 printf("circle");
310 break;
311 case GERBV_APTYPE_RECTANGLE:
312 printf("rectangle");
313 break;
314 case GERBV_APTYPE_OVAL:
315 printf("oval");
316 break;
317 case GERBV_APTYPE_POLYGON:
318 printf("polygon");
319 break;
320 case GERBV_APTYPE_MACRO:
321 printf("macro");
322 break;
323 default:
324 printf("unknown");
326 for (j = 0; j < aperture[i]->nuf_parameters; j++) {
327 printf(" %f", aperture[i]->parameter[j]);
329 printf("\n");
333 /* Netlist */
334 net = image->netlist;
335 while (net){
336 printf("(%f,%f)->(%f,%f) with %d (", net->start_x, net->start_y,
337 net->stop_x, net->stop_y, net->aperture);
338 gerbv_image_interpolation(net->interpolation);
339 gerbv_image_aperture_state(net->aperture_state);
340 printf(")\n");
341 net = net->next;
343 } /* gerbv_image_dump */
346 gerbv_layer_t *
347 gerbv_image_return_new_layer (gerbv_layer_t *previousLayer)
349 gerbv_layer_t *newLayer = g_new0 (gerbv_layer_t, 1);
351 *newLayer = *previousLayer;
352 previousLayer->next = newLayer;
353 /* clear this boolean so we only draw the knockout once */
354 newLayer->knockout.firstInstance = FALSE;
355 newLayer->next = NULL;
357 return newLayer;
358 } /* gerbv_image_return_new_layer */
361 gerbv_netstate_t *
362 gerbv_image_return_new_netstate (gerbv_netstate_t *previousState)
364 gerbv_netstate_t *newState = g_new0 (gerbv_netstate_t, 1);
366 *newState = *previousState;
367 previousState->next = newState;
368 newState->scaleA = 1.0;
369 newState->scaleB = 1.0;
370 newState->next = NULL;
372 return newState;
373 } /* gerbv_image_return_new_netstate */
375 gerbv_layer_t *
376 gerbv_image_duplicate_layer (gerbv_layer_t *oldLayer) {
377 gerbv_layer_t *newLayer = g_new (gerbv_layer_t,1);
379 *newLayer = *oldLayer;
380 newLayer->name = g_strdup (oldLayer->name);
381 return newLayer;
384 gerbv_netstate_t *
385 gerbv_image_duplicate_state (gerbv_netstate_t *oldState) {
386 gerbv_netstate_t *newState = g_new (gerbv_netstate_t,1);
388 *newState = *oldState;
389 return newState;
392 gerbv_aperture_t *
393 gerbv_image_duplicate_aperture (gerbv_aperture_t *oldAperture){
394 gerbv_aperture_t *newAperture = g_new0 (gerbv_aperture_t,1);
395 gerbv_simplified_amacro_t *simplifiedMacro, *tempSimplified;
397 *newAperture = *oldAperture;
399 /* delete the amacro section, since we really don't need it anymore
400 now that we have the simplified section */
401 newAperture->amacro = NULL;
402 newAperture->simplified = NULL;
404 /* copy any simplified macros over */
405 tempSimplified = NULL;
406 for (simplifiedMacro = oldAperture->simplified; simplifiedMacro != NULL; simplifiedMacro = simplifiedMacro->next) {
407 gerbv_simplified_amacro_t *newSimplified = g_new0 (gerbv_simplified_amacro_t,1);
408 *newSimplified = *simplifiedMacro;
409 if (tempSimplified)
410 tempSimplified->next = newSimplified;
411 else
412 newAperture->simplified = newSimplified;
413 tempSimplified = newSimplified;
415 return newAperture;
418 void
419 gerbv_image_copy_all_nets (gerbv_image_t *sourceImage, gerbv_image_t *newImage, gerbv_layer_t *lastLayer,
420 gerbv_netstate_t *lastState, gerbv_net_t *lastNet, gerbv_user_transformation_t *transform,
421 GArray *translationTable){
422 gerbv_netstate_t *oldState,*newSavedState;
423 gerbv_layer_t *oldLayer,*newSavedLayer;
424 gerbv_net_t *currentNet,*newNet,*newSavedNet;
425 int i;
427 oldLayer = sourceImage->layers;
428 oldState = sourceImage->states;
430 newSavedLayer = lastLayer;
431 newSavedState = lastState;
432 newSavedNet = lastNet;
434 /* when copying, skip the first net, since it's always zero due to the way we parse things */
435 for (currentNet = sourceImage->netlist->next; currentNet; currentNet = currentNet->next){
436 /* check for any new layers and duplicate them if needed */
437 if (currentNet->layer != oldLayer) {
438 newSavedLayer->next = gerbv_image_duplicate_layer (currentNet->layer);
439 newSavedLayer = newSavedLayer->next;
441 /* check for any new states and duplicate them if needed */
442 if (currentNet->state != oldState) {
443 newSavedState->next = gerbv_image_duplicate_state (currentNet->state);
444 newSavedState = newSavedState->next;
446 /* create and copy the actual net over */
447 newNet = g_new (gerbv_net_t,1);
448 *newNet = *currentNet;
450 if (currentNet->cirseg) {
451 newNet->cirseg = g_new (gerbv_cirseg_t,1);
452 *(newNet->cirseg) = *(currentNet->cirseg);
455 if (currentNet->label)
456 newNet->label = g_string_new(currentNet->label->str);
458 newNet->state = newSavedState;
459 newNet->layer = newSavedLayer;
460 /* check if we need to translate the aperture number */
461 if (translationTable) {
462 for (i=0; i<translationTable->len; i++){
463 gerb_translation_entry_t translationEntry=g_array_index (translationTable, gerb_translation_entry_t, i);
465 if (translationEntry.oldAperture == newNet->aperture) {
466 newNet->aperture = translationEntry.newAperture;
467 break;
471 /* check if we are transforming the net (translating, scaling, etc) */
472 if (transform) {
473 newNet->start_x += transform->translateX;
474 newNet->start_y += transform->translateY;
475 newNet->stop_x += transform->translateX;
476 newNet->stop_y += transform->translateY;
477 if (newNet->cirseg) {
478 newNet->cirseg->cp_x += transform->translateX;
479 newNet->cirseg->cp_y += transform->translateY;
482 if (newSavedNet)
483 newSavedNet->next = newNet;
484 else
485 newImage->netlist = newNet;
486 newSavedNet = newNet;
491 gint
492 gerbv_image_find_existing_aperture_match (gerbv_aperture_t *checkAperture, gerbv_image_t *imageToSearch) {
493 int i,j;
494 gboolean isMatch;
496 for (i = APERTURE_MIN; i < APERTURE_MAX; i++) {
497 if (imageToSearch->aperture[i] != NULL) {
498 if ((imageToSearch->aperture[i]->type == checkAperture->type) &&
499 (imageToSearch->aperture[i]->simplified == NULL) &&
500 (imageToSearch->aperture[i]->unit == checkAperture->unit)) {
501 /* check all parameters match too */
502 isMatch=TRUE;
503 for (j=0; j<APERTURE_PARAMETERS_MAX; j++){
504 if (imageToSearch->aperture[i]->parameter[j] != checkAperture->parameter[j])
505 isMatch = FALSE;
507 if (isMatch)
508 return i;
512 return 0;
516 gerbv_image_find_unused_aperture_number (int startIndex, gerbv_image_t *image){
517 int i;
519 for (i = startIndex; i < APERTURE_MAX; i++) {
520 if (image->aperture[i] == NULL) {
521 return i;
524 return -1;
527 gerbv_image_t *
528 gerbv_image_duplicate_image (gerbv_image_t *sourceImage, gerbv_user_transformation_t *transform) {
529 gerbv_image_t *newImage = gerbv_create_image(NULL, sourceImage->info->type);
530 int i;
531 int lastUsedApertureNumber = APERTURE_MIN - 1;
532 GArray *apertureNumberTable = g_array_new(FALSE,FALSE,sizeof(gerb_translation_entry_t));
534 newImage->layertype = sourceImage->layertype;
535 /* copy information layer over */
536 *(newImage->info) = *(sourceImage->info);
537 newImage->info->name = g_strdup (sourceImage->info->name);
538 newImage->info->type = g_strdup (sourceImage->info->type);
539 newImage->info->plotterFilm = g_strdup (sourceImage->info->plotterFilm);
541 /* copy apertures over, compressing all the numbers down for a cleaner output */
542 for (i = APERTURE_MIN; i < APERTURE_MAX; i++) {
543 if (sourceImage->aperture[i] != NULL) {
544 gerbv_aperture_t *newAperture = gerbv_image_duplicate_aperture (sourceImage->aperture[i]);
546 lastUsedApertureNumber = gerbv_image_find_unused_aperture_number (lastUsedApertureNumber + 1, newImage);
547 /* store the aperture numbers (new and old) in the translation table */
548 gerb_translation_entry_t translationEntry={i,lastUsedApertureNumber};
549 g_array_append_val (apertureNumberTable,translationEntry);
551 newImage->aperture[lastUsedApertureNumber] = newAperture;
555 /* step through all nets and create new layers and states on the fly, since
556 we really don't have any other way to figure out where states and layers are used */
557 gerbv_image_copy_all_nets (sourceImage, newImage, newImage->layers, newImage->states, NULL, transform, apertureNumberTable);
558 g_array_free (apertureNumberTable, TRUE);
559 return newImage;
562 void
563 gerbv_image_copy_image (gerbv_image_t *sourceImage, gerbv_user_transformation_t *transform, gerbv_image_t *destinationImage) {
564 int lastUsedApertureNumber = APERTURE_MIN - 1;
565 int i;
566 GArray *apertureNumberTable = g_array_new(FALSE,FALSE,sizeof(gerb_translation_entry_t));
568 /* copy apertures over */
569 for (i = APERTURE_MIN; i < APERTURE_MAX; i++) {
570 if (sourceImage->aperture[i] != NULL) {
571 gint existingAperture = gerbv_image_find_existing_aperture_match (sourceImage->aperture[i], destinationImage);
573 /* if we already have an existing aperture in the destination image that matches what
574 we want, just use it instead */
575 if (existingAperture > 0) {
576 gerb_translation_entry_t translationEntry={i,existingAperture};
577 g_array_append_val (apertureNumberTable,translationEntry);
579 /* else, create a new aperture and put it in the destination image */
580 else {
581 gerbv_aperture_t *newAperture = gerbv_image_duplicate_aperture (sourceImage->aperture[i]);
583 lastUsedApertureNumber = gerbv_image_find_unused_aperture_number (lastUsedApertureNumber + 1, destinationImage);
584 /* store the aperture numbers (new and old) in the translation table */
585 gerb_translation_entry_t translationEntry={i,lastUsedApertureNumber};
586 g_array_append_val (apertureNumberTable,translationEntry);
588 destinationImage->aperture[lastUsedApertureNumber] = newAperture;
592 /* find the last layer, state, and net in the linked chains */
593 gerbv_netstate_t *lastState;
594 gerbv_layer_t *lastLayer;
595 gerbv_net_t *lastNet;
597 for (lastState = destinationImage->states; lastState->next; lastState=lastState->next){}
598 for (lastLayer = destinationImage->layers; lastLayer->next; lastLayer=lastLayer->next){}
599 for (lastNet = destinationImage->netlist; lastNet->next; lastNet=lastNet->next){}
601 /* and then copy them all to the destination image, using the aperture translation table we just built */
602 gerbv_image_copy_all_nets (sourceImage, destinationImage, lastLayer, lastState, lastNet, transform, apertureNumberTable);
603 g_array_free (apertureNumberTable, TRUE);
606 void
607 gerbv_image_delete_net (gerbv_net_t *currentNet) {
608 gerbv_net_t *tempNet;
610 g_assert (currentNet);
611 /* we have a match, so just zero out all the important data fields */
612 currentNet->aperture = 0;
613 currentNet->aperture_state = GERBV_APERTURE_STATE_OFF;
615 /* if this is a polygon start, we need to erase all the rest of the
616 nets in this polygon too */
617 if (currentNet->interpolation == GERBV_INTERPOLATION_PAREA_START){
618 for (tempNet = currentNet->next; tempNet; tempNet = tempNet->next){
619 tempNet->aperture = 0;
620 tempNet->aperture_state = GERBV_APERTURE_STATE_OFF;
622 if (tempNet->interpolation == GERBV_INTERPOLATION_PAREA_END) {
623 tempNet->interpolation = GERBV_INTERPOLATION_DELETED;
624 break;
626 /* make sure we don't leave a polygon interpolation in, since
627 it will still draw if it is */
628 tempNet->interpolation = GERBV_INTERPOLATION_DELETED;
631 /* make sure we don't leave a polygon interpolation in, since
632 it will still draw if it is */
633 currentNet->interpolation = GERBV_INTERPOLATION_DELETED;
636 void
637 gerbv_image_delete_selected_nets (gerbv_image_t *sourceImage, GArray *selectedNodeArray) {
638 int i;
639 gerbv_net_t *currentNet;
641 for (currentNet = sourceImage->netlist; currentNet; currentNet = currentNet->next){
642 for (i=0; i<selectedNodeArray->len; i++){
643 gerbv_selection_item_t sItem = g_array_index (selectedNodeArray,
644 gerbv_selection_item_t, i);
645 if (sItem.net == currentNet) {
646 gerbv_image_delete_net (currentNet);
653 void
654 gerbv_image_create_rectangle_object (gerbv_image_t *image, gdouble coordinateX,
655 gdouble coordinateY, gdouble width, gdouble height) {
656 gerbv_net_t *currentNet;
658 /* run through and find last net pointer */
659 for (currentNet = image->netlist; currentNet->next; currentNet = currentNet->next){}
661 /* create the polygon start node */
662 currentNet = gerber_create_new_net (currentNet, NULL, NULL);
663 currentNet->interpolation = GERBV_INTERPOLATION_PAREA_START;
665 /* draw the 4 corners */
666 currentNet = gerber_create_new_net (currentNet, NULL, NULL);
667 currentNet->interpolation = GERBV_INTERPOLATION_LINEARx1;
668 currentNet->aperture_state = GERBV_APERTURE_STATE_ON;
669 currentNet->start_x = coordinateX;
670 currentNet->start_y = coordinateY;
671 currentNet->stop_x = coordinateX + width;
672 currentNet->stop_y = coordinateY;
674 currentNet = gerber_create_new_net (currentNet, NULL, NULL);
675 currentNet->interpolation = GERBV_INTERPOLATION_LINEARx1;
676 currentNet->aperture_state = GERBV_APERTURE_STATE_ON;
677 currentNet->stop_x = coordinateX + width;
678 currentNet->stop_y = coordinateY + height;
680 currentNet = gerber_create_new_net (currentNet, NULL, NULL);
681 currentNet->interpolation = GERBV_INTERPOLATION_LINEARx1;
682 currentNet->aperture_state = GERBV_APERTURE_STATE_ON;
683 currentNet->stop_x = coordinateX;
684 currentNet->stop_y = coordinateY + height;
686 currentNet = gerber_create_new_net (currentNet, NULL, NULL);
687 currentNet->interpolation = GERBV_INTERPOLATION_LINEARx1;
688 currentNet->aperture_state = GERBV_APERTURE_STATE_ON;
689 currentNet->stop_x = coordinateX;
690 currentNet->stop_y = coordinateY;
692 /* create the polygon end node */
693 currentNet = gerber_create_new_net (currentNet, NULL, NULL);
694 currentNet->interpolation = GERBV_INTERPOLATION_PAREA_END;
696 return;
699 gerbv_net_t *
700 gerb_image_return_aperture_index (gerbv_image_t *image, gdouble lineWidth, int *apertureIndex){
701 gerbv_net_t *currentNet;
702 gerbv_aperture_t *aperture=NULL;
703 int i;
705 /* run through and find last net pointer */
706 for (currentNet = image->netlist; currentNet->next; currentNet = currentNet->next){}
708 /* try to find an existing aperture that matches the requested width and type */
709 for (i = APERTURE_MIN; i < APERTURE_MAX; i++) {
710 if (image->aperture[i] != NULL) {
711 if ((image->aperture[i]->type == GERBV_APTYPE_CIRCLE) &&
712 (fabs (image->aperture[i]->parameter[0] - lineWidth) < 0.001)){
713 aperture = image->aperture[i];
714 *apertureIndex = i;
715 break;
720 if (!aperture) {
721 /* we didn't find a useable old aperture, so create a new one */
722 if (!gerber_create_new_aperture (image, apertureIndex,
723 GERBV_APTYPE_CIRCLE, lineWidth, 0)) {
724 /* if we didn't succeed, then return */
725 return FALSE;
728 return currentNet;
731 void
732 gerbv_image_create_arc_object (gerbv_image_t *image, gdouble centerX, gdouble centerY,
733 gdouble radius, gdouble startAngle, gdouble endAngle, gdouble lineWidth,
734 gerbv_aperture_type_t apertureType) {
735 int apertureIndex;
736 gerbv_net_t *currentNet;
737 gerbv_cirseg_t cirSeg = {centerX, centerY, radius, radius, startAngle, endAngle};
739 currentNet = gerb_image_return_aperture_index(image, lineWidth, &apertureIndex);
741 if (!currentNet)
742 return;
744 /* draw the arc */
745 currentNet = gerber_create_new_net (currentNet, NULL, NULL);
746 currentNet->interpolation = GERBV_INTERPOLATION_CCW_CIRCULAR;
747 currentNet->aperture_state = GERBV_APERTURE_STATE_ON;
748 currentNet->aperture = apertureIndex;
749 currentNet->start_x = centerX + (cos(startAngle*M_PI/180) * radius);
750 currentNet->start_y = centerY + (sin(startAngle*M_PI/180) * radius);
751 currentNet->stop_x = centerX + (cos(endAngle*M_PI/180) * radius);
752 currentNet->stop_y = centerY + (sin(endAngle*M_PI/180) * radius);;
753 currentNet->cirseg = g_new0 (gerbv_cirseg_t,1);
754 *(currentNet->cirseg) = cirSeg;
756 return;
759 void
760 gerbv_image_create_line_object (gerbv_image_t *image, gdouble startX, gdouble startY,
761 gdouble endX, gdouble endY, gdouble lineWidth, gerbv_aperture_type_t apertureType) {
762 int apertureIndex;
763 gerbv_net_t *currentNet;
765 currentNet = gerb_image_return_aperture_index(image, lineWidth, &apertureIndex);
767 if (!currentNet)
768 return;
770 /* draw the line */
771 currentNet = gerber_create_new_net (currentNet, NULL, NULL);
772 currentNet->interpolation = GERBV_INTERPOLATION_LINEARx1;
774 /* if the start and end coordinates are the same, use a "flash" aperture state */
775 if ((fabs(startX - endX) < 0.001) && (fabs(startY - endY) < 0.001))
776 currentNet->aperture_state = GERBV_APERTURE_STATE_FLASH;
777 else
778 currentNet->aperture_state = GERBV_APERTURE_STATE_ON;
779 currentNet->aperture = apertureIndex;
780 currentNet->start_x = startX;
781 currentNet->start_y = startY;
782 currentNet->stop_x = endX;
783 currentNet->stop_y = endY;
785 return;
788 void
789 gerbv_image_create_window_pane_objects (gerbv_image_t *image, gdouble lowerLeftX,
790 gdouble lowerLeftY, gdouble width, gdouble height, gdouble areaReduction,
791 gint paneRows, gint paneColumns, gdouble paneSeparation){
792 int i,j;
793 gdouble startX,startY,boxWidth,boxHeight;
795 startX = lowerLeftX + (areaReduction * width) / 2.0;
796 startY = lowerLeftY + (areaReduction * height) / 2.0;
797 boxWidth = (width * (1.0 - areaReduction) - (paneSeparation * (paneColumns - 1))) / paneColumns;
798 boxHeight = (height * (1.0 - areaReduction) - (paneSeparation * (paneRows - 1))) / paneRows;
800 for (i=0; i<paneColumns; i++){
801 for (j=0; j<paneRows; j++) {
802 gerbv_image_create_rectangle_object (image, startX + (i * (boxWidth + paneSeparation)),
803 startY + (j * (boxHeight + paneSeparation)),boxWidth, boxHeight);
807 return;
810 gboolean
811 gerbv_image_reduce_area_of_selected_objects (GArray *selectionArray,
812 gdouble areaReduction, gint paneRows, gint paneColumns, gdouble paneSeparation){
813 int i;
814 gdouble minX,minY,maxX,maxY;
816 for (i=0; i<selectionArray->len; i++) {
817 gerbv_selection_item_t sItem = g_array_index (selectionArray,gerbv_selection_item_t, i);
818 gerbv_image_t *image = sItem.image;
819 gerbv_net_t *currentNet = sItem.net;
821 /* determine the object type first */
822 minX = HUGE_VAL;
823 maxX = -HUGE_VAL;
824 minY = HUGE_VAL;
825 maxY = -HUGE_VAL;
827 if (currentNet->interpolation == GERBV_INTERPOLATION_PAREA_START) {
828 /* if it's a polygon, just determine the overall area of it and delete it */
829 currentNet->interpolation = GERBV_INTERPOLATION_DELETED;
831 for (currentNet = currentNet->next; currentNet; currentNet = currentNet->next){
832 if (currentNet->interpolation == GERBV_INTERPOLATION_PAREA_END)
833 break;
834 currentNet->interpolation = GERBV_INTERPOLATION_DELETED;
835 if (currentNet->stop_x < minX)
836 minX = currentNet->stop_x;
837 if (currentNet->stop_y < minY)
838 minY = currentNet->stop_y;
839 if (currentNet->stop_x > maxX)
840 maxX = currentNet->stop_x;
841 if (currentNet->stop_y > maxY)
842 maxY = currentNet->stop_y;
844 currentNet->interpolation = GERBV_INTERPOLATION_DELETED;
846 else if ((currentNet->interpolation == GERBV_INTERPOLATION_x10) ||
847 (currentNet->interpolation == GERBV_INTERPOLATION_LINEARx01) ||
848 (currentNet->interpolation == GERBV_INTERPOLATION_LINEARx001) ||
849 (currentNet->interpolation == GERBV_INTERPOLATION_LINEARx1)) {
850 gdouble dx=0,dy=0;
851 /* figure out the overall size of this element */
852 switch (image->aperture[currentNet->aperture]->type) {
853 case GERBV_APTYPE_CIRCLE :
854 case GERBV_APTYPE_OVAL :
855 case GERBV_APTYPE_POLYGON :
856 dx = dy = image->aperture[currentNet->aperture]->parameter[0];
857 break;
858 case GERBV_APTYPE_RECTANGLE :
859 dx = (image->aperture[currentNet->aperture]->parameter[0]/ 2);
860 dy = (image->aperture[currentNet->aperture]->parameter[1]/ 2);
861 break;
862 default :
863 break;
865 if (currentNet->start_x-dx < minX)
866 minX = currentNet->start_x-dx;
867 if (currentNet->start_y-dy < minY)
868 minY = currentNet->start_y-dy;
869 if (currentNet->start_x+dx > maxX)
870 maxX = currentNet->start_x+dx;
871 if (currentNet->start_y+dy > maxY)
872 maxY = currentNet->start_y+dy;
874 if (currentNet->stop_x-dx < minX)
875 minX = currentNet->stop_x-dx;
876 if (currentNet->stop_y-dy < minY)
877 minY = currentNet->stop_y-dy;
878 if (currentNet->stop_x+dx > maxX)
879 maxX = currentNet->stop_x+dx;
880 if (currentNet->stop_y+dy > maxY)
881 maxY = currentNet->stop_y+dy;
883 /* finally, delete node */
884 currentNet->interpolation = GERBV_INTERPOLATION_DELETED;
886 /* we don't current support arcs */
887 else
888 return FALSE;
890 /* create new structures */
891 gerbv_image_create_window_pane_objects (image, minX, minY, maxX - minX, maxY - minY,
892 areaReduction, paneRows, paneColumns, paneSeparation);
894 return TRUE;
897 gboolean
898 gerbv_image_move_selected_objects (GArray *selectionArray, gdouble translationX,
899 gdouble translationY) {
900 int i;
902 for (i=0; i<selectionArray->len; i++) {
903 gerbv_selection_item_t sItem = g_array_index (selectionArray,gerbv_selection_item_t, i);
904 gerbv_net_t *currentNet = sItem.net;
906 if (currentNet->interpolation == GERBV_INTERPOLATION_PAREA_START) {
907 /* if it's a polygon, step through every vertex and translate the point */
908 for (currentNet = currentNet->next; currentNet; currentNet = currentNet->next){
909 if (currentNet->interpolation == GERBV_INTERPOLATION_PAREA_END)
910 break;
911 currentNet->start_x += translationX;
912 currentNet->start_y += translationY;
913 currentNet->stop_x += translationX;
914 currentNet->stop_y += translationY;
917 else {
918 /* otherwise, just move the single element */
919 currentNet->start_x += translationX;
920 currentNet->start_y += translationY;
921 currentNet->stop_x += translationX;
922 currentNet->stop_y += translationY;
925 return TRUE;
928 gerbv_net_t *
929 gerbv_image_return_next_renderable_object (gerbv_net_t *oldNet) {
930 gerbv_net_t *currentNet=oldNet;
932 if (currentNet->interpolation == GERBV_INTERPOLATION_PAREA_START) {
933 /* if it's a polygon, step to the next non-polygon net */
934 for (currentNet = currentNet->next; currentNet; currentNet = currentNet->next){
935 if (currentNet->interpolation == GERBV_INTERPOLATION_PAREA_END) {
936 return currentNet->next;
939 return NULL;
941 else {
942 return currentNet->next;