recalculate the bounding boxes when drawing primatives via the libgerbv API
[geda-gerbv.git] / src / gerb_image.c
blobf0273250b1075e616569c307777dd25faeef1d9d
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 for (currentNet = sourceImage->netlist; currentNet; currentNet = currentNet->next){
435 /* check for any new layers and duplicate them if needed */
436 if (currentNet->layer != oldLayer) {
437 newSavedLayer->next = gerbv_image_duplicate_layer (currentNet->layer);
438 newSavedLayer = newSavedLayer->next;
440 /* check for any new states and duplicate them if needed */
441 if (currentNet->state != oldState) {
442 newSavedState->next = gerbv_image_duplicate_state (currentNet->state);
443 newSavedState = newSavedState->next;
445 /* create and copy the actual net over */
446 newNet = g_new (gerbv_net_t,1);
447 *newNet = *currentNet;
449 if (currentNet->cirseg) {
450 newNet->cirseg = g_new (gerbv_cirseg_t,1);
451 *(newNet->cirseg) = *(currentNet->cirseg);
454 if (currentNet->label)
455 newNet->label = g_string_new(currentNet->label->str);
457 newNet->state = newSavedState;
458 newNet->layer = newSavedLayer;
459 /* check if we need to translate the aperture number */
460 if (translationTable) {
461 for (i=0; i<translationTable->len; i++){
462 gerb_translation_entry_t translationEntry=g_array_index (translationTable, gerb_translation_entry_t, i);
464 if (translationEntry.oldAperture == newNet->aperture) {
465 newNet->aperture = translationEntry.newAperture;
466 break;
470 /* check if we are transforming the net (translating, scaling, etc) */
471 if (transform) {
472 newNet->start_x += transform->translateX;
473 newNet->start_y += transform->translateY;
474 newNet->stop_x += transform->translateX;
475 newNet->stop_y += transform->translateY;
476 if (newNet->cirseg) {
477 newNet->cirseg->cp_x += transform->translateX;
478 newNet->cirseg->cp_y += transform->translateY;
481 if (newSavedNet)
482 newSavedNet->next = newNet;
483 else
484 newImage->netlist = newNet;
485 newSavedNet = newNet;
490 gint
491 gerbv_image_find_existing_aperture_match (gerbv_aperture_t *checkAperture, gerbv_image_t *imageToSearch) {
492 int i,j;
493 gboolean isMatch;
495 for (i = 0; i < APERTURE_MAX; i++) {
496 if (imageToSearch->aperture[i] != NULL) {
497 if ((imageToSearch->aperture[i]->type == checkAperture->type) &&
498 (imageToSearch->aperture[i]->simplified == NULL) &&
499 (imageToSearch->aperture[i]->unit == checkAperture->unit)) {
500 /* check all parameters match too */
501 isMatch=TRUE;
502 for (j=0; j<APERTURE_PARAMETERS_MAX; j++){
503 if (imageToSearch->aperture[i]->parameter[j] != checkAperture->parameter[j])
504 isMatch = FALSE;
506 if (isMatch)
507 return i;
511 return 0;
515 gerbv_image_find_unused_aperture_number (int startIndex, gerbv_image_t *image){
516 int i;
518 for (i = startIndex; i < APERTURE_MAX; i++) {
519 if (image->aperture[i] == NULL) {
520 return i;
523 return -1;
526 gerbv_image_t *
527 gerbv_image_duplicate_image (gerbv_image_t *sourceImage, gerbv_user_transformation_t *transform) {
528 gerbv_image_t *newImage = gerbv_create_image(NULL, sourceImage->info->type);
529 int i;
530 int lastUsedApertureNumber = APERTURE_MIN - 1;
531 GArray *apertureNumberTable = g_array_new(FALSE,FALSE,sizeof(gerb_translation_entry_t));
533 newImage->layertype = sourceImage->layertype;
534 /* copy information layer over */
535 *(newImage->info) = *(sourceImage->info);
536 newImage->info->name = g_strdup (sourceImage->info->name);
537 newImage->info->type = g_strdup (sourceImage->info->type);
538 newImage->info->plotterFilm = g_strdup (sourceImage->info->plotterFilm);
539 newImage->info->attr_list = gerbv_attribute_dup (sourceImage->info->attr_list,
540 sourceImage->info->n_attr);
542 /* copy apertures over, compressing all the numbers down for a cleaner output, and
543 moving and apertures less than 10 up to the correct range */
544 for (i = 0; i < APERTURE_MAX; i++) {
545 if (sourceImage->aperture[i] != NULL) {
546 gerbv_aperture_t *newAperture = gerbv_image_duplicate_aperture (sourceImage->aperture[i]);
548 lastUsedApertureNumber = gerbv_image_find_unused_aperture_number (lastUsedApertureNumber + 1, newImage);
549 /* store the aperture numbers (new and old) in the translation table */
550 gerb_translation_entry_t translationEntry={i,lastUsedApertureNumber};
551 g_array_append_val (apertureNumberTable,translationEntry);
553 newImage->aperture[lastUsedApertureNumber] = newAperture;
557 /* step through all nets and create new layers and states on the fly, since
558 we really don't have any other way to figure out where states and layers are used */
559 gerbv_image_copy_all_nets (sourceImage, newImage, newImage->layers, newImage->states, NULL, transform, apertureNumberTable);
560 g_array_free (apertureNumberTable, TRUE);
561 return newImage;
564 void
565 gerbv_image_copy_image (gerbv_image_t *sourceImage, gerbv_user_transformation_t *transform, gerbv_image_t *destinationImage) {
566 int lastUsedApertureNumber = APERTURE_MIN - 1;
567 int i;
568 GArray *apertureNumberTable = g_array_new(FALSE,FALSE,sizeof(gerb_translation_entry_t));
570 /* copy apertures over */
571 for (i = 0; i < APERTURE_MAX; i++) {
572 if (sourceImage->aperture[i] != NULL) {
573 gint existingAperture = gerbv_image_find_existing_aperture_match (sourceImage->aperture[i], destinationImage);
575 /* if we already have an existing aperture in the destination image that matches what
576 we want, just use it instead */
577 if (existingAperture > 0) {
578 gerb_translation_entry_t translationEntry={i,existingAperture};
579 g_array_append_val (apertureNumberTable,translationEntry);
581 /* else, create a new aperture and put it in the destination image */
582 else {
583 gerbv_aperture_t *newAperture = gerbv_image_duplicate_aperture (sourceImage->aperture[i]);
585 lastUsedApertureNumber = gerbv_image_find_unused_aperture_number (lastUsedApertureNumber + 1, destinationImage);
586 /* store the aperture numbers (new and old) in the translation table */
587 gerb_translation_entry_t translationEntry={i,lastUsedApertureNumber};
588 g_array_append_val (apertureNumberTable,translationEntry);
590 destinationImage->aperture[lastUsedApertureNumber] = newAperture;
594 /* find the last layer, state, and net in the linked chains */
595 gerbv_netstate_t *lastState;
596 gerbv_layer_t *lastLayer;
597 gerbv_net_t *lastNet;
599 for (lastState = destinationImage->states; lastState->next; lastState=lastState->next){}
600 for (lastLayer = destinationImage->layers; lastLayer->next; lastLayer=lastLayer->next){}
601 for (lastNet = destinationImage->netlist; lastNet->next; lastNet=lastNet->next){}
603 /* and then copy them all to the destination image, using the aperture translation table we just built */
604 gerbv_image_copy_all_nets (sourceImage, destinationImage, lastLayer, lastState, lastNet, transform, apertureNumberTable);
605 g_array_free (apertureNumberTable, TRUE);
608 void
609 gerbv_image_delete_net (gerbv_net_t *currentNet) {
610 gerbv_net_t *tempNet;
612 g_assert (currentNet);
613 /* we have a match, so just zero out all the important data fields */
614 currentNet->aperture = 0;
615 currentNet->aperture_state = GERBV_APERTURE_STATE_OFF;
617 /* if this is a polygon start, we need to erase all the rest of the
618 nets in this polygon too */
619 if (currentNet->interpolation == GERBV_INTERPOLATION_PAREA_START){
620 for (tempNet = currentNet->next; tempNet; tempNet = tempNet->next){
621 tempNet->aperture = 0;
622 tempNet->aperture_state = GERBV_APERTURE_STATE_OFF;
624 if (tempNet->interpolation == GERBV_INTERPOLATION_PAREA_END) {
625 tempNet->interpolation = GERBV_INTERPOLATION_DELETED;
626 break;
628 /* make sure we don't leave a polygon interpolation in, since
629 it will still draw if it is */
630 tempNet->interpolation = GERBV_INTERPOLATION_DELETED;
633 /* make sure we don't leave a polygon interpolation in, since
634 it will still draw if it is */
635 currentNet->interpolation = GERBV_INTERPOLATION_DELETED;
638 void
639 gerbv_image_delete_selected_nets (gerbv_image_t *sourceImage, GArray *selectedNodeArray) {
640 int i;
641 gerbv_net_t *currentNet;
643 for (currentNet = sourceImage->netlist; currentNet; currentNet = currentNet->next){
644 for (i=0; i<selectedNodeArray->len; i++){
645 gerbv_selection_item_t sItem = g_array_index (selectedNodeArray,
646 gerbv_selection_item_t, i);
647 if (sItem.net == currentNet) {
648 gerbv_image_delete_net (currentNet);
655 void
656 gerbv_image_create_rectangle_object (gerbv_image_t *image, gdouble coordinateX,
657 gdouble coordinateY, gdouble width, gdouble height) {
658 gerbv_net_t *currentNet;
660 /* run through and find last net pointer */
661 for (currentNet = image->netlist; currentNet->next; currentNet = currentNet->next){}
663 /* create the polygon start node */
664 currentNet = gerber_create_new_net (currentNet, NULL, NULL);
665 currentNet->interpolation = GERBV_INTERPOLATION_PAREA_START;
667 /* go to start point (we need this to create correct RS274X export code) */
668 currentNet = gerber_create_new_net (currentNet, NULL, NULL);
669 currentNet->interpolation = GERBV_INTERPOLATION_LINEARx1;
670 currentNet->aperture_state = GERBV_APERTURE_STATE_OFF;
671 currentNet->start_x = coordinateX;
672 currentNet->start_y = coordinateY;
673 currentNet->stop_x = coordinateX;
674 currentNet->stop_y = coordinateY;
676 /* draw the 4 corners */
677 currentNet = gerber_create_new_net (currentNet, NULL, NULL);
678 currentNet->interpolation = GERBV_INTERPOLATION_LINEARx1;
679 currentNet->aperture_state = GERBV_APERTURE_STATE_ON;
680 currentNet->start_x = coordinateX;
681 currentNet->start_y = coordinateY;
682 currentNet->stop_x = coordinateX + width;
683 currentNet->stop_y = coordinateY;
684 gerber_update_min_and_max (&currentNet->boundingBox,currentNet->stop_x,currentNet->stop_y,
685 0,0,0,0);
686 gerber_update_image_min_max (&currentNet->boundingBox, 0, 0, image);
688 currentNet = gerber_create_new_net (currentNet, NULL, NULL);
689 currentNet->interpolation = GERBV_INTERPOLATION_LINEARx1;
690 currentNet->aperture_state = GERBV_APERTURE_STATE_ON;
691 currentNet->stop_x = coordinateX + width;
692 currentNet->stop_y = coordinateY + height;
693 gerber_update_min_and_max (&currentNet->boundingBox,currentNet->stop_x,currentNet->stop_y,
694 0,0,0,0);
695 gerber_update_image_min_max (&currentNet->boundingBox, 0, 0, image);
697 currentNet = gerber_create_new_net (currentNet, NULL, NULL);
698 currentNet->interpolation = GERBV_INTERPOLATION_LINEARx1;
699 currentNet->aperture_state = GERBV_APERTURE_STATE_ON;
700 currentNet->stop_x = coordinateX;
701 currentNet->stop_y = coordinateY + height;
702 gerber_update_min_and_max (&currentNet->boundingBox,currentNet->stop_x,currentNet->stop_y,
703 0,0,0,0);
704 gerber_update_image_min_max (&currentNet->boundingBox, 0, 0, image);
706 currentNet = gerber_create_new_net (currentNet, NULL, NULL);
707 currentNet->interpolation = GERBV_INTERPOLATION_LINEARx1;
708 currentNet->aperture_state = GERBV_APERTURE_STATE_ON;
709 currentNet->stop_x = coordinateX;
710 currentNet->stop_y = coordinateY;
711 gerber_update_min_and_max (&currentNet->boundingBox,currentNet->stop_x,currentNet->stop_y,
712 0,0,0,0);
713 gerber_update_image_min_max (&currentNet->boundingBox, 0, 0, image);
715 /* create the polygon end node */
716 currentNet = gerber_create_new_net (currentNet, NULL, NULL);
717 currentNet->interpolation = GERBV_INTERPOLATION_PAREA_END;
719 return;
722 gerbv_net_t *
723 gerb_image_return_aperture_index (gerbv_image_t *image, gdouble lineWidth, int *apertureIndex){
724 gerbv_net_t *currentNet;
725 gerbv_aperture_t *aperture=NULL;
726 int i;
728 /* run through and find last net pointer */
729 for (currentNet = image->netlist; currentNet->next; currentNet = currentNet->next){}
731 /* try to find an existing aperture that matches the requested width and type */
732 for (i = 0; i < APERTURE_MAX; i++) {
733 if (image->aperture[i] != NULL) {
734 if ((image->aperture[i]->type == GERBV_APTYPE_CIRCLE) &&
735 (fabs (image->aperture[i]->parameter[0] - lineWidth) < 0.001)){
736 aperture = image->aperture[i];
737 *apertureIndex = i;
738 break;
743 if (!aperture) {
744 /* we didn't find a useable old aperture, so create a new one */
745 if (!gerber_create_new_aperture (image, apertureIndex,
746 GERBV_APTYPE_CIRCLE, lineWidth, 0)) {
747 /* if we didn't succeed, then return */
748 return FALSE;
751 return currentNet;
754 void
755 gerbv_image_create_arc_object (gerbv_image_t *image, gdouble centerX, gdouble centerY,
756 gdouble radius, gdouble startAngle, gdouble endAngle, gdouble lineWidth,
757 gerbv_aperture_type_t apertureType) {
758 int apertureIndex;
759 gerbv_net_t *currentNet;
760 gerbv_cirseg_t cirSeg = {centerX, centerY, radius, radius, startAngle, endAngle};
762 currentNet = gerb_image_return_aperture_index(image, lineWidth, &apertureIndex);
764 if (!currentNet)
765 return;
767 /* draw the arc */
768 currentNet = gerber_create_new_net (currentNet, NULL, NULL);
769 currentNet->interpolation = GERBV_INTERPOLATION_CCW_CIRCULAR;
770 currentNet->aperture_state = GERBV_APERTURE_STATE_ON;
771 currentNet->aperture = apertureIndex;
772 currentNet->start_x = centerX + (cos(startAngle*M_PI/180) * radius);
773 currentNet->start_y = centerY + (sin(startAngle*M_PI/180) * radius);
774 currentNet->stop_x = centerX + (cos(endAngle*M_PI/180) * radius);
775 currentNet->stop_y = centerY + (sin(endAngle*M_PI/180) * radius);;
776 currentNet->cirseg = g_new0 (gerbv_cirseg_t,1);
777 *(currentNet->cirseg) = cirSeg;
779 gdouble angleDiff = currentNet->cirseg->angle2 - currentNet->cirseg->angle1;
780 gint i, steps = abs(angleDiff);
781 for (i=0; i<=steps; i++){
782 gdouble tempX = currentNet->cirseg->cp_x + currentNet->cirseg->width / 2.0 *
783 cos ((currentNet->cirseg->angle1 +
784 (angleDiff * i) / steps)*M_PI/180);
785 gdouble tempY = currentNet->cirseg->cp_y + currentNet->cirseg->width / 2.0 *
786 sin ((currentNet->cirseg->angle1 +
787 (angleDiff * i) / steps)*M_PI/180);
788 gerber_update_min_and_max (&currentNet->boundingBox,
789 tempX, tempY,
790 lineWidth/2,lineWidth/2,
791 lineWidth/2,lineWidth/2);
793 gerber_update_image_min_max (&currentNet->boundingBox, 0, 0, image);
794 return;
797 void
798 gerbv_image_create_line_object (gerbv_image_t *image, gdouble startX, gdouble startY,
799 gdouble endX, gdouble endY, gdouble lineWidth, gerbv_aperture_type_t apertureType) {
800 int apertureIndex;
801 gerbv_net_t *currentNet;
803 currentNet = gerb_image_return_aperture_index(image, lineWidth, &apertureIndex);
805 if (!currentNet)
806 return;
808 /* draw the line */
809 currentNet = gerber_create_new_net (currentNet, NULL, NULL);
810 currentNet->interpolation = GERBV_INTERPOLATION_LINEARx1;
812 /* if the start and end coordinates are the same, use a "flash" aperture state */
813 if ((fabs(startX - endX) < 0.001) && (fabs(startY - endY) < 0.001))
814 currentNet->aperture_state = GERBV_APERTURE_STATE_FLASH;
815 else
816 currentNet->aperture_state = GERBV_APERTURE_STATE_ON;
817 currentNet->aperture = apertureIndex;
818 currentNet->start_x = startX;
819 currentNet->start_y = startY;
820 currentNet->stop_x = endX;
821 currentNet->stop_y = endY;
823 gerber_update_min_and_max (&currentNet->boundingBox,currentNet->stop_x,currentNet->stop_y,
824 lineWidth/2,lineWidth/2,lineWidth/2,lineWidth/2);
825 gerber_update_min_and_max (&currentNet->boundingBox,currentNet->start_x,currentNet->start_y,
826 lineWidth/2,lineWidth/2,lineWidth/2,lineWidth/2);
827 gerber_update_image_min_max (&currentNet->boundingBox, 0, 0, image);
828 return;
831 void
832 gerbv_image_create_window_pane_objects (gerbv_image_t *image, gdouble lowerLeftX,
833 gdouble lowerLeftY, gdouble width, gdouble height, gdouble areaReduction,
834 gint paneRows, gint paneColumns, gdouble paneSeparation){
835 int i,j;
836 gdouble startX,startY,boxWidth,boxHeight;
838 startX = lowerLeftX + (areaReduction * width) / 2.0;
839 startY = lowerLeftY + (areaReduction * height) / 2.0;
840 boxWidth = (width * (1.0 - areaReduction) - (paneSeparation * (paneColumns - 1))) / paneColumns;
841 boxHeight = (height * (1.0 - areaReduction) - (paneSeparation * (paneRows - 1))) / paneRows;
843 for (i=0; i<paneColumns; i++){
844 for (j=0; j<paneRows; j++) {
845 gerbv_image_create_rectangle_object (image, startX + (i * (boxWidth + paneSeparation)),
846 startY + (j * (boxHeight + paneSeparation)),boxWidth, boxHeight);
850 return;
853 gboolean
854 gerbv_image_reduce_area_of_selected_objects (GArray *selectionArray,
855 gdouble areaReduction, gint paneRows, gint paneColumns, gdouble paneSeparation){
856 int i;
857 gdouble minX,minY,maxX,maxY;
859 for (i=0; i<selectionArray->len; i++) {
860 gerbv_selection_item_t sItem = g_array_index (selectionArray,gerbv_selection_item_t, i);
861 gerbv_image_t *image = sItem.image;
862 gerbv_net_t *currentNet = sItem.net;
864 /* determine the object type first */
865 minX = HUGE_VAL;
866 maxX = -HUGE_VAL;
867 minY = HUGE_VAL;
868 maxY = -HUGE_VAL;
870 if (currentNet->interpolation == GERBV_INTERPOLATION_PAREA_START) {
871 /* if it's a polygon, just determine the overall area of it and delete it */
872 currentNet->interpolation = GERBV_INTERPOLATION_DELETED;
874 for (currentNet = currentNet->next; currentNet; currentNet = currentNet->next){
875 if (currentNet->interpolation == GERBV_INTERPOLATION_PAREA_END)
876 break;
877 currentNet->interpolation = GERBV_INTERPOLATION_DELETED;
878 if (currentNet->stop_x < minX)
879 minX = currentNet->stop_x;
880 if (currentNet->stop_y < minY)
881 minY = currentNet->stop_y;
882 if (currentNet->stop_x > maxX)
883 maxX = currentNet->stop_x;
884 if (currentNet->stop_y > maxY)
885 maxY = currentNet->stop_y;
887 currentNet->interpolation = GERBV_INTERPOLATION_DELETED;
889 else if ((currentNet->interpolation == GERBV_INTERPOLATION_x10) ||
890 (currentNet->interpolation == GERBV_INTERPOLATION_LINEARx01) ||
891 (currentNet->interpolation == GERBV_INTERPOLATION_LINEARx001) ||
892 (currentNet->interpolation == GERBV_INTERPOLATION_LINEARx1)) {
893 gdouble dx=0,dy=0;
894 /* figure out the overall size of this element */
895 switch (image->aperture[currentNet->aperture]->type) {
896 case GERBV_APTYPE_CIRCLE :
897 case GERBV_APTYPE_OVAL :
898 case GERBV_APTYPE_POLYGON :
899 dx = dy = image->aperture[currentNet->aperture]->parameter[0];
900 break;
901 case GERBV_APTYPE_RECTANGLE :
902 dx = (image->aperture[currentNet->aperture]->parameter[0]/ 2);
903 dy = (image->aperture[currentNet->aperture]->parameter[1]/ 2);
904 break;
905 default :
906 break;
908 if (currentNet->start_x-dx < minX)
909 minX = currentNet->start_x-dx;
910 if (currentNet->start_y-dy < minY)
911 minY = currentNet->start_y-dy;
912 if (currentNet->start_x+dx > maxX)
913 maxX = currentNet->start_x+dx;
914 if (currentNet->start_y+dy > maxY)
915 maxY = currentNet->start_y+dy;
917 if (currentNet->stop_x-dx < minX)
918 minX = currentNet->stop_x-dx;
919 if (currentNet->stop_y-dy < minY)
920 minY = currentNet->stop_y-dy;
921 if (currentNet->stop_x+dx > maxX)
922 maxX = currentNet->stop_x+dx;
923 if (currentNet->stop_y+dy > maxY)
924 maxY = currentNet->stop_y+dy;
926 /* finally, delete node */
927 currentNet->interpolation = GERBV_INTERPOLATION_DELETED;
929 /* we don't current support arcs */
930 else
931 return FALSE;
933 /* create new structures */
934 gerbv_image_create_window_pane_objects (image, minX, minY, maxX - minX, maxY - minY,
935 areaReduction, paneRows, paneColumns, paneSeparation);
937 return TRUE;
940 gboolean
941 gerbv_image_move_selected_objects (GArray *selectionArray, gdouble translationX,
942 gdouble translationY) {
943 int i;
945 for (i=0; i<selectionArray->len; i++) {
946 gerbv_selection_item_t sItem = g_array_index (selectionArray,gerbv_selection_item_t, i);
947 gerbv_net_t *currentNet = sItem.net;
949 if (currentNet->interpolation == GERBV_INTERPOLATION_PAREA_START) {
950 /* if it's a polygon, step through every vertex and translate the point */
951 for (currentNet = currentNet->next; currentNet; currentNet = currentNet->next){
952 if (currentNet->interpolation == GERBV_INTERPOLATION_PAREA_END)
953 break;
954 currentNet->start_x += translationX;
955 currentNet->start_y += translationY;
956 currentNet->stop_x += translationX;
957 currentNet->stop_y += translationY;
960 else {
961 /* otherwise, just move the single element */
962 currentNet->start_x += translationX;
963 currentNet->start_y += translationY;
964 currentNet->stop_x += translationX;
965 currentNet->stop_y += translationY;
968 return TRUE;
971 gerbv_net_t *
972 gerbv_image_return_next_renderable_object (gerbv_net_t *oldNet) {
973 gerbv_net_t *currentNet=oldNet;
975 if (currentNet->interpolation == GERBV_INTERPOLATION_PAREA_START) {
976 /* if it's a polygon, step to the next non-polygon net */
977 for (currentNet = currentNet->next; currentNet; currentNet = currentNet->next){
978 if (currentNet->interpolation == GERBV_INTERPOLATION_PAREA_END) {
979 return currentNet->next;
982 return NULL;
984 else {
985 return currentNet->next;
989 void
990 gerbv_image_create_dummy_apertures (gerbv_image_t *parsed_image) {
991 gerbv_net_t *currentNet;
993 /* run through and find last net pointer */
994 for (currentNet = parsed_image->netlist; currentNet->next; currentNet = currentNet->next){
995 if (parsed_image->aperture[currentNet->aperture] == NULL) {
996 parsed_image->aperture[currentNet->aperture] = g_new0 (gerbv_aperture_t, 1);
997 parsed_image->aperture[currentNet->aperture]->type = GERBV_APTYPE_CIRCLE;
998 parsed_image->aperture[currentNet->aperture]->parameter[0] = 0;
999 parsed_image->aperture[currentNet->aperture]->parameter[1] = 0;