gerber.c

Go to the documentation of this file.
00001 /*
00002  * gEDA - GNU Electronic Design Automation
00003  * This is a part of gerbv
00004  *
00005  *   Copyright (C) 2000-2003 Stefan Petersen (spe@stacken.kth.se)
00006  *
00007  * $Id$
00008  *
00009  * This program is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 2 of the License, or
00012  * (at your option) any later version.
00013  *
00014  * This program is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  * GNU General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU General Public License
00020  * along with this program; if not, write to the Free Software
00021  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
00022  */
00023 
00029 #include <stdlib.h>
00030 #include <string.h>
00031 #include <math.h>  /* pow() */
00032 #include <glib.h>
00033 #include <locale.h>
00034 #include <errno.h>
00035 #include <ctype.h>
00036 
00037 #include "config.h"
00038 #include "gerbv.h"
00039 #include "gerb_image.h"
00040 #include "gerber.h"
00041 #include "gerb_stats.h"
00042 #include "amacro.h"
00043 
00044 //#define AMACRO_DEBUG
00045 
00046 #ifndef RENDER_USING_GDK
00047 #include <cairo.h>
00048 #endif
00049 
00050 /* include this for macro enums */
00051 #include "draw-gdk.h"
00052 
00053 /* DEBUG printing.  #define DEBUG 1 in config.h to use this fcn. */
00054 #define dprintf if(DEBUG) printf
00055 
00056 //#define AMACRO_DEBUG
00057 
00058 #define A2I(a,b) (((a & 0xff) << 8) + (b & 0xff))
00059 
00060 #define MAXL 200
00061 
00062 /* Local function prototypes */
00063 static void parse_G_code(gerb_file_t *fd, gerb_state_t *state, 
00064                       gerbv_image_t *image);
00065 static void parse_D_code(gerb_file_t *fd, gerb_state_t *state, 
00066                       gerbv_image_t *image);
00067 static int parse_M_code(gerb_file_t *fd, gerbv_image_t *image);
00068 static void parse_rs274x(gint levelOfRecursion, gerb_file_t *fd, 
00069                       gerbv_image_t *image, gerb_state_t *state, 
00070                       gerbv_net_t *curr_net, gerbv_stats_t *stats, 
00071                       gchar *directoryPath);
00072 static int parse_aperture_definition(gerb_file_t *fd, 
00073                                  gerbv_aperture_t *aperture,
00074                                  gerbv_image_t *image, gdouble scale);
00075 static void calc_cirseg_sq(struct gerbv_net *net, int cw, 
00076                         double delta_cp_x, double delta_cp_y);
00077 static void calc_cirseg_mq(struct gerbv_net *net, int cw, 
00078                         double delta_cp_x, double delta_cp_y);
00079 
00080 static void
00081 gerber_update_min_and_max(gerbv_image_info_t *info, gdouble repeatX, gdouble repeatY,
00082                        gdouble x, gdouble y, gdouble apertureSizeX1,
00083                        gdouble apertureSizeX2,gdouble apertureSizeY1,
00084                        gdouble apertureSizeY2);
00085 
00086 
00087 static void gerber_update_any_running_knockout_measurements(gerbv_image_t *image);
00088 
00089 static void gerber_calculate_final_justify_effects (gerbv_image_t *image);
00090 
00091 gboolean knockoutMeasure = FALSE;
00092 gdouble knockoutLimitXmin, knockoutLimitYmin, knockoutLimitXmax, 
00093     knockoutLimitYmax;
00094 gerbv_layer_t *knockoutLayer = NULL;
00095 
00096 #ifndef RENDER_USING_GDK
00097 cairo_matrix_t currentMatrix;
00098 #endif  
00099 
00100 /* --------------------------------------------------------- */
00101 gerbv_net_t *
00102 gerber_create_new_net (gerbv_net_t *currentNet, gerbv_layer_t *layer, gerbv_netstate_t *state){
00103        gerbv_net_t *newNet = g_new0 (gerbv_net_t, 1);
00104        
00105        currentNet->next = newNet;
00106        if (layer)
00107               newNet->layer = layer;
00108        else
00109               newNet->layer = currentNet->layer;
00110        if (state)
00111               newNet->state = state;
00112        else
00113               newNet->state = currentNet->state;
00114        return newNet;
00115 }
00116 
00117 /* --------------------------------------------------------- */
00118 gboolean
00119 gerber_create_new_aperture (gerbv_image_t *image, int *indexNumber,
00120               gerbv_aperture_type_t apertureType, gdouble parameter1, gdouble parameter2){
00121        int i;
00122        
00123        /* search for an available aperture spot */
00124        for (i = APERTURE_MIN; i <= APERTURE_MAX; i++) {
00125               if (image->aperture[i] == NULL) {
00126                      image->aperture[i] = g_new0 (gerbv_aperture_t, 1);
00127                      image->aperture[i]->type = apertureType;
00128                      image->aperture[i]->amacro = NULL;
00129                      image->aperture[i]->parameter[0] = parameter1;
00130                      image->aperture[i]->parameter[1] = parameter2;
00131                      *indexNumber = i;
00132                      return TRUE;
00133               }
00134        }
00135        return FALSE;
00136 }
00137 
00138 /* --------------------------------------------------------- */
00148 gboolean
00149 gerber_parse_file_segment (gint levelOfRecursion, gerbv_image_t *image, 
00150                         gerb_state_t *state,     gerbv_net_t *curr_net, 
00151                         gerbv_stats_t *stats, gerb_file_t *fd, 
00152                         gchar *directoryPath) {
00153     int read, coord, len, polygonPoints=0;
00154     double x_scale = 0.0, y_scale = 0.0;
00155     double delta_cp_x = 0.0, delta_cp_y = 0.0;
00156     double aperture_size;
00157     double scale;
00158     gboolean foundEOF = FALSE;
00159     gchar *string;
00160     
00161     while ((read = gerb_fgetc(fd)) != EOF) {
00162         /* figure out the scale, since we need to normalize 
00163           all dimensions to inches */
00164         if (state->state->unit == GERBV_UNIT_MM)
00165             scale = 25.4;
00166         else
00167             scale = 1.0;
00168        switch ((char)(read & 0xff)) {
00169        case 'G':
00170            dprintf("... Found G code\n");
00171            parse_G_code(fd, state, image);
00172            break;
00173        case 'D':
00174            dprintf("... Found D code\n");
00175            parse_D_code(fd, state, image);
00176            break;
00177        case 'M':
00178            dprintf("... Found M code\n");
00179            switch(parse_M_code(fd, image)) {
00180            case 1 :
00181            case 2 :
00182            case 3 :
00183               foundEOF = TRUE;
00184               break;
00185            default:
00186               gerbv_stats_add_error(stats->error_list,
00187                                  -1,
00188                                  "Unknown M code found.\n",
00189                                  GERBV_MESSAGE_ERROR);
00190            } /* switch(parse_M_code) */
00191            break;
00192        case 'X':
00193            dprintf("... Found X code\n");
00194            stats->X++;
00195            coord = gerb_fgetint(fd, &len);
00196            if (image->format && image->format->omit_zeros == GERBV_OMIT_ZEROS_TRAILING) {
00197               
00198               switch ((image->format->x_int + image->format->x_dec) - len) {
00199               case 5:
00200                   coord *= 10;
00201               case 4:
00202                   coord *= 10;
00203               case 3:
00204                   coord *= 10;
00205               case 2:
00206                   coord *= 10;
00207               case 1:
00208                   coord *= 10;
00209                   break;
00210               default:
00211                   ;
00212               }
00213            }
00214            if (image->format && (image->format->coordinate==GERBV_COORDINATE_INCREMENTAL))
00215                state->curr_x += coord;
00216            else
00217                state->curr_x = coord;
00218            state->changed = 1;
00219            break;
00220        case 'Y':
00221            dprintf("... Found Y code\n");
00222            stats->Y++;
00223            coord = gerb_fgetint(fd, &len);
00224            if (image->format && image->format->omit_zeros == GERBV_OMIT_ZEROS_TRAILING) {
00225 
00226               switch ((image->format->y_int + image->format->y_dec) - len) {
00227               case 5:
00228                   coord *= 10;
00229               case 4:
00230                   coord *= 10;
00231               case 3:
00232                   coord *= 10;
00233               case 2:
00234                   coord *= 10;
00235               case 1:
00236                   coord *= 10;
00237                   break;
00238               default:
00239                   ;
00240               }
00241            }
00242            if (image->format && (image->format->coordinate==GERBV_COORDINATE_INCREMENTAL))
00243                state->curr_y += coord;
00244            else
00245                state->curr_y = coord;
00246            state->changed = 1;
00247            break;
00248        case 'I':
00249            dprintf("... Found I code\n");
00250            stats->I++;
00251            state->delta_cp_x = gerb_fgetint(fd, NULL);
00252            state->changed = 1;
00253            break;
00254        case 'J':
00255            dprintf("... Found J code\n");
00256            stats->J++;
00257            state->delta_cp_y = gerb_fgetint(fd, NULL);
00258            state->changed = 1;
00259            break;
00260        case '%':
00261            dprintf("... Found %% code\n");
00262            parse_rs274x(levelOfRecursion, fd, image, state, curr_net, stats, directoryPath);
00263            while (1) {
00264               int c = gerb_fgetc(fd);
00265               if(c == EOF || c == '%')
00266                   break;
00267            }
00268            break;
00269        case '*':  
00270            dprintf("... Found * code\n");
00271            stats->star++;
00272            if (state->changed == 0) break;
00273            state->changed = 0;
00274            
00275            /* don't even bother saving the net if the aperture state is GERBV_APERTURE_STATE_OFF and we
00276               aren't starting a polygon fill (where we need it to get to the start point) */
00277            if ((state->aperture_state == GERBV_APERTURE_STATE_OFF)&&(!state->in_parea_fill)&&
00278                      (state->interpolation != GERBV_INTERPOLATION_PAREA_START)) {
00279               /* save the coordinate so the next net can use it for a start point */
00280               state->prev_x = state->curr_x;
00281               state->prev_y = state->curr_y;
00282               break;
00283            }
00284            curr_net = gerber_create_new_net (curr_net, state->layer, state->state);
00285            /*
00286             * Scale to given coordinate format
00287             * XXX only "omit leading zeros".
00288             */
00289            if (image && image->format ){
00290               x_scale = pow(10.0, (double)image->format->x_dec);
00291               y_scale = pow(10.0, (double)image->format->y_dec);
00292            }
00293            x_scale *= scale;
00294            y_scale *= scale;
00295            curr_net->start_x = (double)state->prev_x / x_scale;
00296            curr_net->start_y = (double)state->prev_y / y_scale;
00297            curr_net->stop_x = (double)state->curr_x / x_scale;
00298            curr_net->stop_y = (double)state->curr_y / y_scale;
00299            delta_cp_x = (double)state->delta_cp_x / x_scale;
00300            delta_cp_y = (double)state->delta_cp_y / y_scale;
00301            
00302            
00303            switch (state->interpolation) {
00304            case GERBV_INTERPOLATION_CW_CIRCULAR :
00305               curr_net->cirseg = g_new0 (gerbv_cirseg_t,1);
00306               if (state->mq_on)
00307                   calc_cirseg_mq(curr_net, 1, delta_cp_x, delta_cp_y);
00308               else
00309                   calc_cirseg_sq(curr_net, 1, delta_cp_x, delta_cp_y);
00310               break;
00311            case GERBV_INTERPOLATION_CCW_CIRCULAR :
00312               curr_net->cirseg = g_new0 (gerbv_cirseg_t,1);
00313               if (state->mq_on)
00314                   calc_cirseg_mq(curr_net, 0, delta_cp_x, delta_cp_y);
00315               else
00316                   calc_cirseg_sq(curr_net, 0, delta_cp_x, delta_cp_y);
00317               break;
00318            case GERBV_INTERPOLATION_PAREA_START :
00319               /* 
00320                * To be able to get back and fill in number of polygon corners
00321                */
00322               state->parea_start_node = curr_net;
00323               state->in_parea_fill = 1;
00324               polygonPoints = 0;
00325               break;
00326            case GERBV_INTERPOLATION_PAREA_END :
00327               state->parea_start_node = NULL;
00328               state->in_parea_fill = 0;
00329               polygonPoints = 0;
00330               break;
00331            default :
00332               break;
00333            }  /* switch(state->interpolation) */
00334 
00335            /* 
00336             * Count number of points in Polygon Area 
00337             */
00338            if (state->in_parea_fill && state->parea_start_node) {
00339               /* 
00340                * "...all lines drawn with D01 are considered edges of the
00341                * polygon. D02 closes and fills the polygon."
00342                * p.49 rs274xrevd_e.pdf
00343                * D02 -> state->aperture_state == GERBV_APERTURE_STATE_OFF
00344                */
00345                
00346                /* UPDATE: only end the polygon during a D02 call if we've already
00347                   drawn a polygon edge (with D01) */
00348                  
00349               if ((state->aperture_state == GERBV_APERTURE_STATE_OFF &&
00350                      state->interpolation != GERBV_INTERPOLATION_PAREA_START) && (polygonPoints > 0)) {
00351                   curr_net->interpolation = GERBV_INTERPOLATION_PAREA_END;
00352                   
00353                   curr_net = gerber_create_new_net (curr_net, state->layer, state->state);
00354                   curr_net->interpolation = GERBV_INTERPOLATION_PAREA_START;
00355                   state->parea_start_node = curr_net;
00356                   
00357                   curr_net = gerber_create_new_net (curr_net, state->layer, state->state);            
00358                   curr_net->start_x = (double)state->prev_x / x_scale;
00359                   curr_net->start_y = (double)state->prev_y / y_scale;
00360                   curr_net->stop_x = (double)state->curr_x / x_scale;
00361                   curr_net->stop_y = (double)state->curr_y / y_scale;
00362               }
00363               if (state->interpolation != GERBV_INTERPOLATION_PAREA_START)
00364                   polygonPoints++;
00365               
00366            }  /* if (state->in_parea_fill && state->parea_start_node) */
00367            
00368            curr_net->interpolation = state->interpolation;
00369 
00370            /* 
00371             * Override circular interpolation if no center was given.
00372             * This should be a safe hack, since a good file should always 
00373             * include I or J.  And even if the radius is zero, the endpoint 
00374             * should be the same as the start point, creating no line 
00375             */
00376            if (((state->interpolation == GERBV_INTERPOLATION_CW_CIRCULAR) || 
00377                (state->interpolation == GERBV_INTERPOLATION_CCW_CIRCULAR)) && 
00378               ((state->delta_cp_x == 0.0) && (state->delta_cp_y == 0.0)))
00379               curr_net->interpolation = GERBV_INTERPOLATION_LINEARx1;
00380            
00381            /*
00382             * If we detected the end of Polygon Area Fill we go back to
00383             * the interpolation we had before that.
00384             * Also if we detected any of the quadrant flags, since some
00385             * gerbers don't reset the interpolation (EagleCad again).
00386             */
00387            if ((state->interpolation == GERBV_INTERPOLATION_PAREA_START) ||
00388               (state->interpolation == GERBV_INTERPOLATION_PAREA_END))
00389               state->interpolation = state->prev_interpolation;
00390 
00391            /*
00392             * Save layer polarity and unit
00393             */
00394            curr_net->layer = state->layer;  
00395            
00396            state->delta_cp_x = 0.0;
00397            state->delta_cp_y = 0.0;
00398            curr_net->aperture = state->curr_aperture;
00399            curr_net->aperture_state = state->aperture_state;
00400 
00401            /*
00402             * For next round we save the current position as
00403             * the previous position
00404             */
00405            state->prev_x = state->curr_x;
00406            state->prev_y = state->curr_y;
00407 
00408            /*
00409             * If we have an aperture defined at the moment we find 
00410             * min and max of image with compensation for mm.
00411             */
00412            if ((curr_net->aperture == 0) && !state->in_parea_fill) 
00413               break;
00414            
00415            /* only update the min/max values and aperture stats if we are drawing */
00416            if ((curr_net->aperture_state != GERBV_APERTURE_STATE_OFF)){
00417               double repeat_off_X = 0.0, repeat_off_Y = 0.0;
00418 
00419               /* Update stats with current aperture number if not in polygon */
00420               if (!state->in_parea_fill) {
00421                      dprintf("     In parse_D_code, adding 1 to D_list ...\n");
00422                      int retcode = gerbv_stats_increment_D_list_count(stats->D_code_list, 
00423                                                                 curr_net->aperture, 
00424                                                                 1,
00425                                                                 stats->error_list);
00426                      if (retcode == -1) {
00427                          string = g_strdup_printf("Found undefined D code D%d in file \n%s\n", 
00428                                                curr_net->aperture, 
00429                                                fd->filename);
00430                          gerbv_stats_add_error(stats->error_list,
00431                                             -1,
00432                                             string,
00433                                             GERBV_MESSAGE_ERROR);
00434                          g_free(string);
00435                          stats->D_unknown++;
00436                      }
00437               }
00438 
00439               /*
00440                * If step_and_repeat (%SR%) is used, check min_x,max_y etc for
00441                * the ends of the step_and_repeat lattice. This goes wrong in 
00442                * the case of negative dist_X or dist_Y, in which case we 
00443                * should compare against the startpoints of the lines, not 
00444                * the stoppoints, but that seems an uncommon case (and the 
00445                * error isn't very big any way).
00446                */
00447               repeat_off_X = (state->layer->stepAndRepeat.X - 1) *
00448                   state->layer->stepAndRepeat.dist_X;
00449               repeat_off_Y = (state->layer->stepAndRepeat.Y - 1) *
00450                   state->layer->stepAndRepeat.dist_Y;
00451               
00452               
00453 #ifndef RENDER_USING_GDK
00454               cairo_matrix_init (&currentMatrix, 1, 0, 0, 1, 0, 0);
00455               /* offset image */
00456               cairo_matrix_translate (&currentMatrix, image->info->offsetA, 
00457                                    image->info->offsetB);
00458               /* do image rotation */
00459               cairo_matrix_rotate (&currentMatrix, image->info->imageRotation);
00460               /* it's a new layer, so recalculate the new transformation 
00461                * matrix for it */
00462               /* do any rotations */
00463               cairo_matrix_rotate (&currentMatrix, state->layer->rotation);
00464                      
00465               /* calculate current layer and state transformation matrices */
00466               /* apply scale factor */
00467               cairo_matrix_scale (&currentMatrix, state->state->scaleA, 
00468                                 state->state->scaleB);
00469               /* apply offset */
00470               cairo_matrix_translate (&currentMatrix, state->state->offsetA,
00471                                    state->state->offsetB);
00472               /* apply mirror */
00473               switch (state->state->mirrorState) {
00474               case GERBV_MIRROR_STATE_FLIPA:
00475                   cairo_matrix_scale (&currentMatrix, -1, 1);
00476                   break;
00477               case GERBV_MIRROR_STATE_FLIPB:
00478                   cairo_matrix_scale (&currentMatrix, 1, -1);
00479                   break;
00480               case GERBV_MIRROR_STATE_FLIPAB:
00481                   cairo_matrix_scale (&currentMatrix, -1, -1);
00482                   break;
00483               default:
00484                   break;
00485               }
00486               /* finally, apply axis select */
00487               if (state->state->axisSelect == GERBV_AXIS_SELECT_SWAPAB) {
00488                   /* we do this by rotating 270 (counterclockwise, then 
00489                    *  mirroring the Y axis 
00490                    */
00491                   cairo_matrix_rotate (&currentMatrix, 3 * M_PI / 2);
00492                   cairo_matrix_scale (&currentMatrix, 1, -1);
00493               }
00494 #endif
00495               /* if it's a macro, step through all the primitive components
00496                  and calculate the true bounding box */
00497               if ((image->aperture[curr_net->aperture] != NULL) &&
00498                   (image->aperture[curr_net->aperture]->type == GERBV_APTYPE_MACRO)) {
00499                   gerbv_simplified_amacro_t *ls = image->aperture[curr_net->aperture]->simplified;
00500              
00501                   while (ls != NULL) {
00502                      gdouble offsetx = 0, offsety = 0, widthx = 0, widthy = 0;
00503                      gboolean calculatedAlready = FALSE;
00504                      
00505                      if (ls->type == GERBV_APTYPE_MACRO_CIRCLE) {
00506                          offsetx=ls->parameter[CIRCLE_CENTER_X];
00507                          offsety=ls->parameter[CIRCLE_CENTER_Y];
00508                          widthx=widthy=ls->parameter[CIRCLE_DIAMETER];
00509                      } else if (ls->type == GERBV_APTYPE_MACRO_OUTLINE) {
00510                          int pointCounter,numberOfPoints;
00511                          numberOfPoints = (int) ls->parameter[OUTLINE_NUMBER_OF_POINTS];
00512               
00513                          for (pointCounter = 0; pointCounter < numberOfPoints; pointCounter++) {
00514                             gerber_update_min_and_max (image->info, repeat_off_X, repeat_off_Y,
00515                                                     ls->parameter[pointCounter * 2 + OUTLINE_FIRST_X],
00516                                                     ls->parameter[pointCounter * 2 + OUTLINE_FIRST_Y], 
00517                                                     0,0,0,0);
00518                          }
00519                          calculatedAlready = TRUE;
00520                      } else if (ls->type == GERBV_APTYPE_MACRO_POLYGON) {
00521                          offsetx = ls->parameter[POLYGON_CENTER_X];
00522                          offsety = ls->parameter[POLYGON_CENTER_Y];
00523                          widthx = widthy = ls->parameter[POLYGON_DIAMETER];
00524                      } else if (ls->type == GERBV_APTYPE_MACRO_MOIRE) {
00525                          offsetx = ls->parameter[MOIRE_CENTER_X];
00526                          offsety = ls->parameter[MOIRE_CENTER_Y];
00527                          widthx = widthy = ls->parameter[MOIRE_OUTSIDE_DIAMETER];
00528                      } else if (ls->type == GERBV_APTYPE_MACRO_THERMAL) {
00529                          offsetx = ls->parameter[THERMAL_CENTER_X];
00530                          offsety = ls->parameter[THERMAL_CENTER_Y];
00531                          widthx = widthy = ls->parameter[THERMAL_OUTSIDE_DIAMETER];
00532                      } else if (ls->type == GERBV_APTYPE_MACRO_LINE20) {
00533                          widthx = widthy = ls->parameter[LINE20_LINE_WIDTH];
00534                          gerber_update_min_and_max (image->info, repeat_off_X, repeat_off_Y,
00535                                                  ls->parameter[LINE20_START_X] + offsetx,
00536                                                  ls->parameter[LINE20_START_Y] + offsety, 
00537                                                  widthx/2,widthx/2,widthy/2,widthy/2);
00538                          gerber_update_min_and_max (image->info, repeat_off_X, repeat_off_Y,
00539                                                  ls->parameter[LINE20_END_X] + offsetx,
00540                                                  ls->parameter[LINE20_END_Y] + offsety, 
00541                                                  widthx/2,widthx/2,widthy/2,widthy/2);
00542                          calculatedAlready = TRUE;
00543                      } else if (ls->type == GERBV_APTYPE_MACRO_LINE21) {
00544                          gdouble largestDimension = sqrt (ls->parameter[LINE21_WIDTH]/2 *
00545                                                       ls->parameter[LINE21_WIDTH]/2 + ls->parameter[LINE21_HEIGHT/2] *
00546                                                       ls->parameter[LINE21_HEIGHT]/2);
00547 
00548                          offsetx = ls->parameter[LINE21_CENTER_X];
00549                          offsety = ls->parameter[LINE21_CENTER_Y];
00550                          widthx = widthy=largestDimension;
00551                      } else if (ls->type == GERBV_APTYPE_MACRO_LINE22) {
00552                          gdouble largestDimension = sqrt (ls->parameter[LINE22_WIDTH]/2 *
00553                                                       ls->parameter[LINE22_WIDTH]/2 + ls->parameter[LINE22_HEIGHT/2] *
00554                                                       ls->parameter[LINE22_HEIGHT]/2);
00555 
00556                          offsetx = ls->parameter[LINE22_LOWER_LEFT_X] +
00557                             ls->parameter[LINE22_WIDTH]/2;
00558                          offsety = ls->parameter[LINE22_LOWER_LEFT_Y] +
00559                             ls->parameter[LINE22_HEIGHT]/2;
00560                          widthx = widthy=largestDimension;
00561                      }
00562               
00563                      if (!calculatedAlready) {
00564                          gerber_update_min_and_max (image->info, repeat_off_X, repeat_off_Y,
00565                                                  curr_net->stop_x + offsetx,
00566                                                  curr_net->stop_y + offsety, 
00567                                                  widthx/2,widthx/2,widthy/2,widthy/2);
00568                      }
00569                      ls = ls->next;
00570                   }
00571               } else {
00572                   if (image->aperture[curr_net->aperture] != NULL) {
00573                      aperture_size = image->aperture[curr_net->aperture]->parameter[0];
00574                   } else {
00575                      /* this is usually for polygon fills, where the aperture width
00576                         if "zero" */
00577                      aperture_size = 0;
00578                   }
00579                   
00580                   /* check both the start and stop of the aperture points against
00581                      a running min/max counter */
00582                   /* Note: only check start coordinate if this isn't a flash, 
00583                      since the start point may be bogus if it is a flash */
00584                   if (curr_net->aperture_state != GERBV_APERTURE_STATE_FLASH) {
00585                      gerber_update_min_and_max (image->info, repeat_off_X, repeat_off_Y,
00586                                              curr_net->start_x, curr_net->start_y, 
00587                                              aperture_size/2,aperture_size/2,
00588                                              aperture_size/2,aperture_size/2);
00589                   }
00590                   gerber_update_min_and_max (image->info, repeat_off_X, repeat_off_Y,
00591                                           curr_net->stop_x, curr_net->stop_y, 
00592                                           aperture_size/2,aperture_size/2,
00593                                           aperture_size/2,aperture_size/2);
00594               }
00595            }
00596            break;
00597        case 10 :   /* White space */
00598        case 13 :
00599        case ' ' :
00600        case '\t' :
00601        case 0 :
00602            break;
00603        default:
00604            stats->unknown++;
00605            string = g_strdup_printf("Found unknown character (whitespace?) [%d]%c\n", 
00606                                  read, read);
00607            gerbv_stats_add_error(stats->error_list,
00608                               -1,
00609                               string, 
00610                               GERBV_MESSAGE_ERROR);
00611            g_free(string);
00612        }  /* switch((char) (read & 0xff)) */
00613     }
00614     return foundEOF;
00615 }
00616 
00617 
00618 /* ------------------------------------------------------------------ */
00625 gerbv_image_t *
00626 parse_gerb(gerb_file_t *fd, gchar *directoryPath)
00627 {
00628     gerb_state_t *state = NULL;
00629     gerbv_image_t *image = NULL;
00630     gerbv_net_t *curr_net = NULL;
00631     gerbv_stats_t *stats;
00632     gboolean foundEOF = FALSE;
00633     gchar *string;
00634     
00635     /* added by t.motylewski@bfad.de
00636      * many locales redefine "." as "," and so on, 
00637      * so sscanf and strtod has problems when
00638      * reading files using %f format */
00639     setlocale(LC_NUMERIC, "C" );
00640 
00641     /* 
00642      * Create new state.  This is used locally to keep track
00643      * of the photoplotter's state as the Gerber is read in.
00644      */
00645     state = g_new0 (gerb_state_t, 1);
00646 
00647     /* 
00648      * Create new image.  This will be returned.
00649      */
00650     image = gerbv_create_image(image, "RS274-X (Gerber) File");
00651     if (image == NULL)
00652        GERB_FATAL_ERROR("malloc image failed\n");
00653     curr_net = image->netlist;
00654     image->layertype = GERBV_LAYERTYPE_RS274X;
00655     image->gerbv_stats = gerbv_stats_new();
00656     if (image->gerbv_stats == NULL)
00657        GERB_FATAL_ERROR("malloc gerbv_stats failed\n");
00658     stats = (gerbv_stats_t *) image->gerbv_stats;
00659 
00660     /* set active layer and netstate to point to first default one created */
00661     state->layer = image->layers;
00662     state->state = image->states;
00663     curr_net->layer = state->layer;
00664     curr_net->state = state->state;
00665 
00666     /*
00667      * Start parsing
00668      */
00669     dprintf("In parse_gerb, starting to parse file...\n");
00670     foundEOF = gerber_parse_file_segment (1, image, state, curr_net, stats,
00671                                      fd, directoryPath);
00672 
00673     if (!foundEOF) {
00674        string = g_strdup_printf("File %s is missing Gerber EOF code.\n", fd->filename);
00675        gerbv_stats_add_error(stats->error_list,
00676                            -1,
00677                            string,
00678                            GERBV_MESSAGE_ERROR);
00679        g_free(string);
00680     }
00681     g_free(state);
00682     
00683     dprintf("               ... done parsing Gerber file\n");
00684     gerber_update_any_running_knockout_measurements (image);
00685     gerber_calculate_final_justify_effects(image);
00686 
00687     return image;
00688 } /* parse_gerb */
00689 
00690 
00691 /* ------------------------------------------------------------------- */
00695 gboolean
00696 gerber_is_rs274x_p(gerb_file_t *fd, gboolean *returnFoundBinary) 
00697 {
00698     char *buf;
00699     int len = 0;
00700     char *letter;
00701     int i;
00702     gboolean found_binary = FALSE;
00703     gboolean found_ADD = FALSE;
00704     gboolean found_D0 = FALSE;
00705     gboolean found_D2 = FALSE;
00706     gboolean found_M0 = FALSE;
00707     gboolean found_M2 = FALSE;
00708     gboolean found_star = FALSE;
00709     gboolean found_X = FALSE;
00710     gboolean found_Y = FALSE;
00711    
00712     dprintf ("gerber_is_rs274x_p(%p, %p), fd->fd = %p\n", fd, returnFoundBinary, fd->fd); 
00713     buf = (char *) g_malloc(MAXL);
00714     if (buf == NULL) 
00715        GERB_FATAL_ERROR("malloc buf failed while checking for rs274x.\n");
00716     
00717     while (fgets(buf, MAXL, fd->fd) != NULL) {
00718         dprintf ("buf = \"%s\"\n", buf);
00719        len = strlen(buf);
00720     
00721        /* First look through the file for indications of its type by
00722         * checking that file is not binary (non-printing chars and white 
00723         * spaces)
00724         */
00725        for (i = 0; i < len; i++) {
00726            if (!isprint((int) buf[i]) && (buf[i] != '\r') && 
00727               (buf[i] != '\n') && (buf[i] != '\t')) {
00728               found_binary = TRUE;
00729                 dprintf ("found_binary (%d)\n", buf[i]);
00730            }
00731        }
00732        if (g_strstr_len(buf, len, "%ADD")) {
00733            found_ADD = TRUE;
00734             dprintf ("found_ADD\n");
00735        }
00736        if (g_strstr_len(buf, len, "D00")) {
00737            found_D0 = TRUE;
00738             dprintf ("found_D0\n");
00739        }
00740        if (g_strstr_len(buf, len, "D02")) {
00741            found_D2 = TRUE;
00742             dprintf ("found_D2\n");
00743        }
00744        if (g_strstr_len(buf, len, "M0")) {
00745            found_M0 = TRUE;
00746             dprintf ("found_M0\n");
00747        }
00748        if (g_strstr_len(buf, len, "M00")) {
00749            found_M0 = TRUE;
00750             dprintf ("found_M0\n");
00751        }
00752        if (g_strstr_len(buf, len, "M2")) {
00753            found_M2 = TRUE;
00754             dprintf ("found_M2\n");
00755        }
00756        if (g_strstr_len(buf, len, "M02")) {
00757            found_M2 = TRUE;
00758             dprintf ("found_M2\n");
00759        }
00760        if (g_strstr_len(buf, len, "*")) {
00761            found_star = TRUE;
00762             dprintf ("found_star\n");
00763        }
00764        /* look for X<number> or Y<number> */
00765        if ((letter = g_strstr_len(buf, len, "X")) != NULL) {
00766            if (isdigit((int) letter[1])) { /* grab char after X */
00767               found_X = TRUE;
00768                 dprintf ("found_X\n");
00769            }
00770        }
00771        if ((letter = g_strstr_len(buf, len, "Y")) != NULL) {
00772            if (isdigit((int) letter[1])) { /* grab char after Y */
00773               found_Y = TRUE;
00774                 dprintf ("found_Y\n");
00775            }
00776        }
00777     }
00778     rewind(fd->fd);
00779     free(buf);
00780    
00781     *returnFoundBinary = found_binary;
00782 
00783     /* Now form logical expression determining if the file is RS-274X */
00784     if ((found_D0 || found_D2 || found_M0 || found_M2) && 
00785        found_ADD && found_star && (found_X || found_Y)) 
00786        return TRUE;
00787 
00788     
00789     return FALSE;
00790 
00791 } /* gerber_is_rs274x */
00792 
00793 
00794 /* ------------------------------------------------------------------- */
00798 gboolean
00799 gerber_is_rs274d_p(gerb_file_t *fd) 
00800 {
00801     char *buf;
00802     int len = 0;
00803     char *letter;
00804     int i;
00805     gboolean found_binary = FALSE;
00806     gboolean found_ADD = FALSE;
00807     gboolean found_D0 = FALSE;
00808     gboolean found_D2 = FALSE;
00809     gboolean found_M0 = FALSE;
00810     gboolean found_M2 = FALSE;
00811     gboolean found_star = FALSE;
00812     gboolean found_X = FALSE;
00813     gboolean found_Y = FALSE;
00814     
00815     buf = malloc(MAXL);
00816     if (buf == NULL) 
00817        GERB_FATAL_ERROR("malloc buf failed while checking for rs274d.\n");
00818 
00819     while (fgets(buf, MAXL, fd->fd) != NULL) {
00820        len = strlen(buf);
00821     
00822        /* First look through the file for indications of its type */
00823     
00824        /* check that file is not binary (non-printing chars */
00825        for (i = 0; i < len; i++) {
00826            if (!isprint( (int) buf[i]) && (buf[i] != '\r') && 
00827               (buf[i] != '\n') && (buf[i] != '\t')) {
00828               found_binary = TRUE;
00829            }
00830        }
00831        
00832        if (g_strstr_len(buf, len, "%ADD")) {
00833            found_ADD = TRUE;
00834        }
00835        if (g_strstr_len(buf, len, "D00")) {
00836            found_D0 = TRUE;
00837        }
00838        if (g_strstr_len(buf, len, "D02")) {
00839            found_D2 = TRUE;
00840        }
00841        if (g_strstr_len(buf, len, "M0")) {
00842            found_M0 = TRUE;
00843        }
00844        if (g_strstr_len(buf, len, "M00")) {
00845            found_M0 = TRUE;
00846        }
00847        if (g_strstr_len(buf, len, "M02")) {
00848            found_M2 = TRUE;
00849        }
00850        if (g_strstr_len(buf, len, "*")) {
00851            found_star = TRUE;
00852        }
00853        /* look for X<number> or Y<number> */
00854        if ((letter = g_strstr_len(buf, len, "X")) != NULL) {
00855            /* grab char after X */
00856            if (isdigit( (int) letter[1])) {
00857               found_X = TRUE;
00858            }
00859        }
00860        if ((letter = g_strstr_len(buf, len, "Y")) != NULL) {
00861            /* grab char after Y */
00862            if (isdigit( (int) letter[1])) {
00863               found_Y = TRUE;
00864            }
00865        }
00866     }
00867     rewind(fd->fd);
00868     free(buf);
00869 
00870     /* Now form logical expression determining if the file is RS-274D */
00871     if ((found_D0 || found_D2 || found_M0 || found_M2) && 
00872        !found_ADD && found_star && (found_X || found_Y) && 
00873        !found_binary) 
00874        return TRUE;
00875 
00876     return FALSE;
00877 
00878 } /* gerber_is_rs274d */
00879 
00880 
00881 /* ------------------------------------------------------------------- */
00885 static void 
00886 parse_G_code(gerb_file_t *fd, gerb_state_t *state, gerbv_image_t *image)
00887 {
00888     int  op_int;
00889     gerbv_format_t *format = image->format;
00890     gerbv_stats_t *stats = image->gerbv_stats;
00891     int c;
00892     gchar *string;
00893 
00894     op_int=gerb_fgetint(fd, NULL);
00895     
00896     switch(op_int) {
00897     case 0:  /* Move */
00898        /* Is this doing anything really? */
00899        stats->G0++;
00900        break;
00901     case 1:  /* Linear Interpolation (1X scale) */
00902        state->interpolation = GERBV_INTERPOLATION_LINEARx1;
00903        stats->G1++;
00904        break;
00905     case 2:  /* Clockwise Linear Interpolation */
00906        state->interpolation = GERBV_INTERPOLATION_CW_CIRCULAR;
00907        stats->G2++;
00908        break;
00909     case 3:  /* Counter Clockwise Linear Interpolation */
00910        state->interpolation = GERBV_INTERPOLATION_CCW_CIRCULAR;
00911        stats->G3++;
00912        break;
00913     case 4:  /* Ignore Data Block */
00914        /* Don't do anything, just read 'til * */
00915         /* SDB asks:  Should we look for other codes while reading G04 in case
00916         * user forgot to put * at end of comment block? */
00917        c = gerb_fgetc(fd);
00918        while ((c != EOF) && (c != '*')) {
00919            c = gerb_fgetc(fd);
00920        }
00921        stats->G4++;
00922        break;
00923     case 10: /* Linear Interpolation (10X scale) */
00924        state->interpolation = GERBV_INTERPOLATION_x10;
00925        stats->G10++;
00926        break;
00927     case 11: /* Linear Interpolation (0.1X scale) */
00928        state->interpolation = GERBV_INTERPOLATION_LINEARx01;
00929        stats->G11++;
00930        break;
00931     case 12: /* Linear Interpolation (0.01X scale) */
00932        state->interpolation = GERBV_INTERPOLATION_LINEARx001;
00933        stats->G12++;
00934        break;
00935     case 36: /* Turn on Polygon Area Fill */
00936        state->prev_interpolation = state->interpolation;
00937        state->interpolation = GERBV_INTERPOLATION_PAREA_START;
00938        state->changed = 1;
00939        stats->G36++;
00940        break;
00941     case 37: /* Turn off Polygon Area Fill */
00942        state->interpolation = GERBV_INTERPOLATION_PAREA_END;
00943        state->changed = 1;
00944        stats->G37++;
00945        break;
00946     case 54: /* Tool prepare */
00947        /* XXX Maybe uneccesary??? */
00948        if (gerb_fgetc(fd) == 'D') {
00949            int a = gerb_fgetint(fd, NULL);
00950            if ((a >= APERTURE_MIN) && (a <= APERTURE_MAX)) {
00951               state->curr_aperture = a;
00952            } else { 
00953               string = g_strdup_printf("Found aperture D%d out of bounds while parsing G code in file \n%s\n", 
00954                                     a, fd->filename);
00955               gerbv_stats_add_error(stats->error_list,
00956                                   -1,
00957                                   string,
00958                                   GERBV_MESSAGE_ERROR);
00959               g_free(string);
00960            }
00961        } else {
00962            string =  g_strdup_printf("Found unexpected code after G54 in file \n%s\n", fd->filename);
00963            gerbv_stats_add_error(stats->error_list,
00964                               -1,
00965                               string, 
00966                               GERBV_MESSAGE_ERROR);
00967            g_free(string);
00968            /* Must insert error count here */
00969        }
00970        stats->G54++;
00971        break;
00972     case 55: /* Prepare for flash */
00973        stats->G55++;
00974        break;
00975     case 70: /* Specify inches */
00976        state->state = gerbv_image_return_new_netstate (state->state);
00977        state->state->unit = GERBV_UNIT_INCH;
00978        stats->G70++;
00979        break;
00980     case 71: /* Specify millimeters */
00981        state->state = gerbv_image_return_new_netstate (state->state);
00982        state->state->unit = GERBV_UNIT_MM;
00983        stats->G71++;
00984        break;
00985     case 74: /* Disable 360 circular interpolation */
00986        state->mq_on = 0;
00987        stats->G74++;
00988        break;
00989     case 75: /* Enable 360 circular interpolation */
00990        state->mq_on = 1;
00991        stats->G75++;
00992        break;
00993     case 90: /* Specify absolut format */
00994        if (format) format->coordinate = GERBV_COORDINATE_ABSOLUTE;
00995        stats->G90++;
00996        break;
00997     case 91: /* Specify incremental format */
00998        if (format) format->coordinate = GERBV_COORDINATE_INCREMENTAL;
00999        stats->G91++;
01000        break;
01001     default:
01002        string = g_strdup_printf("Encountered unknown G code G%d in file \n%s\n", op_int, fd->filename);
01003        gerbv_stats_add_error(stats->error_list,
01004                            -1,
01005                            string,
01006                            GERBV_MESSAGE_ERROR);
01007        g_free(string);
01008        string = g_strdup_printf("Ignorning unknown G code G%d\n", op_int);
01009        gerbv_stats_add_error(stats->error_list,
01010                            -1,
01011                            string,
01012                            GERBV_MESSAGE_WARNING);
01013        g_free(string);
01014        stats->G_unknown++;
01015        /* Enter error count here */
01016        break;
01017     }
01018     
01019     return;
01020 } /* parse_G_code */
01021 
01022 
01023 /* ------------------------------------------------------------------ */
01027 static void 
01028 parse_D_code(gerb_file_t *fd, gerb_state_t *state, gerbv_image_t *image)
01029 {
01030     int a;
01031     gerbv_stats_t *stats = image->gerbv_stats;
01032     gchar *string;
01033 
01034     a = gerb_fgetint(fd, NULL);
01035     dprintf("     In parse_D_code, found D number = %d ... \n", a);
01036     switch(a) {
01037     case 0 : /* Invalid code */
01038        string = g_strdup_printf("Found invalid D00 code in file \n%s.\n", fd->filename);
01039         gerbv_stats_add_error(stats->error_list,
01040                            -1,
01041                            string, 
01042                            GERBV_MESSAGE_ERROR);
01043        g_free(string);
01044         stats->D_error++;
01045        break;
01046     case 1 : /* Exposure on */
01047        state->aperture_state = GERBV_APERTURE_STATE_ON;
01048        state->changed = 1;
01049        stats->D1++;
01050        break;
01051     case 2 : /* Exposure off */
01052        state->aperture_state = GERBV_APERTURE_STATE_OFF;
01053        state->changed = 1;
01054        stats->D2++;
01055        break;
01056     case 3 : /* Flash aperture */
01057        state->aperture_state = GERBV_APERTURE_STATE_FLASH;
01058        state->changed = 1;
01059        stats->D3++;
01060        break;
01061     default: /* Aperture in use */
01062        if ((a >= APERTURE_MIN) && (a <= APERTURE_MAX)) {
01063            state->curr_aperture = a;
01064            
01065        } else {
01066            string = g_strdup_printf("Found out of bounds aperture D%d in file \n%s\n", 
01067                                  a, fd->filename);
01068            gerbv_stats_add_error(stats->error_list,
01069                               -1,
01070                               string,
01071                               GERBV_MESSAGE_ERROR);
01072            g_free(string);
01073            stats->D_error++;
01074        }
01075        state->changed = 0;
01076        break;
01077     }
01078     
01079     return;
01080 } /* parse_D_code */
01081 
01082 
01083 /* ------------------------------------------------------------------ */
01084 static int
01085 parse_M_code(gerb_file_t *fd, gerbv_image_t *image)
01086 {
01087     int op_int;
01088     gerbv_stats_t *stats = image->gerbv_stats;
01089     gchar *string;
01090     
01091     op_int=gerb_fgetint(fd, NULL);
01092     
01093     switch (op_int) {
01094     case 0:  /* Program stop */
01095        stats->M0++;
01096        return 1;
01097     case 1:  /* Optional stop */
01098        stats->M1++;
01099        return 2;
01100     case 2:  /* End of program */
01101        stats->M2++;
01102        return 3;
01103     default:
01104        string = g_strdup_printf("Encountered unknown M code M%d in file \n%s\n", 
01105                              op_int, fd->filename);
01106        gerbv_stats_add_error(stats->error_list,
01107                            -1,
01108                            string, 
01109                            GERBV_MESSAGE_ERROR);
01110        g_free(string);
01111        string = g_strdup_printf("Ignorning unknown M code M%d\n", op_int);
01112        gerbv_stats_add_error(stats->error_list,
01113                            -1,
01114                            string, 
01115                            GERBV_MESSAGE_WARNING);
01116        g_free(string);
01117        stats->M_unknown++;
01118     }
01119     return 0;
01120 } /* parse_M_code */
01121 
01122 
01123 /* ------------------------------------------------------------------ */
01124 static void 
01125 parse_rs274x(gint levelOfRecursion, gerb_file_t *fd, gerbv_image_t *image, 
01126             gerb_state_t *state, gerbv_net_t *curr_net, gerbv_stats_t *stats, 
01127             gchar *directoryPath)
01128 {
01129     int op[2];
01130     char str[3];
01131     int tmp;
01132     gerbv_aperture_t *a = NULL;
01133     gerbv_amacro_t *tmp_amacro;
01134     int ano;
01135     gdouble scale = 1.0;
01136     gchar *string;
01137     
01138     if (state->state->unit == GERBV_UNIT_MM)
01139        scale = 25.4;
01140     
01141     op[0] = gerb_fgetc(fd);
01142     op[1] = gerb_fgetc(fd);
01143     
01144     if ((op[0] == EOF) || (op[1] == EOF)) {
01145        string = g_strdup_printf("Unexpected EOF found in file \n%s\n", fd->filename);
01146        gerbv_stats_add_error(stats->error_list,
01147                            -1,
01148                            string, 
01149                            GERBV_MESSAGE_ERROR);
01150        g_free(string);
01151     }
01152 
01153     switch (A2I(op[0], op[1])){
01154        
01155        /* 
01156         * Directive parameters 
01157         */
01158     case A2I('A','S'): /* Axis Select */
01159        op[0] = gerb_fgetc(fd);
01160        op[1] = gerb_fgetc(fd);
01161        state->state = gerbv_image_return_new_netstate (state->state);
01162        
01163        if ((op[0] == EOF) || (op[1] == EOF)) {
01164            string = g_strdup_printf("Unexpected EOF found in file \n%s\n", fd->filename);
01165            gerbv_stats_add_error(stats->error_list,
01166                               -1,
01167                               string,
01168                               GERBV_MESSAGE_ERROR);
01169            g_free(string);
01170        }
01171        
01172        if (((op[0] == 'A') && (op[1] == 'Y')) ||
01173            ((op[0] == 'B') && (op[1] == 'X'))) {
01174            state->state->axisSelect = GERBV_AXIS_SELECT_SWAPAB;
01175        } else {
01176            state->state->axisSelect = GERBV_AXIS_SELECT_NOSELECT;
01177        }
01178 
01179        op[0] = gerb_fgetc(fd);
01180        op[1] = gerb_fgetc(fd);
01181        
01182        if ((op[0] == EOF) || (op[1] == EOF)) {
01183            string = g_strdup_printf("Unexpected EOF found in file \n%s\n", fd->filename);
01184            gerbv_stats_add_error(stats->error_list,
01185                              -1,
01186                               string, 
01187                               GERBV_MESSAGE_ERROR);
01188            g_free(string);
01189        }
01190 
01191        if (((op[0] == 'A') && (op[1] == 'Y')) ||
01192            ((op[0] == 'B') && (op[1] == 'X'))) {
01193            state->state->axisSelect = GERBV_AXIS_SELECT_SWAPAB;
01194        } else {
01195            state->state->axisSelect = GERBV_AXIS_SELECT_NOSELECT;
01196        }
01197        break;
01198 
01199     case A2I('F','S'): /* Format Statement */
01200        image->format = g_new0 (gerbv_format_t,1);
01201        
01202        switch (gerb_fgetc(fd)) {
01203        case 'L':
01204            image->format->omit_zeros = GERBV_OMIT_ZEROS_LEADING;
01205            break;
01206        case 'T':
01207            image->format->omit_zeros = GERBV_OMIT_ZEROS_TRAILING;
01208            break;
01209        case 'D':
01210            image->format->omit_zeros = GERBV_OMIT_ZEROS_EXPLICIT;
01211            break;
01212        default:
01213            string = g_strdup_printf("EagleCad bug detected: Undefined handling of zeros in format code in file \n%s\n",
01214                                  fd->filename);
01215            gerbv_stats_add_error(stats->error_list,
01216                              -1,
01217                               string, 
01218                              GERBV_MESSAGE_ERROR);
01219            g_free(string);
01220            string = g_strdup_printf("Defaulting to omitting leading zeros.\n");
01221            gerbv_stats_add_error(stats->error_list,
01222                               -1,
01223                               string,
01224                               GERBV_MESSAGE_WARNING);
01225            g_free(string);
01226            gerb_ungetc(fd);
01227            image->format->omit_zeros = GERBV_OMIT_ZEROS_LEADING;
01228        }
01229        
01230        switch (gerb_fgetc(fd)) {
01231        case 'A':
01232            image->format->coordinate = GERBV_COORDINATE_ABSOLUTE;
01233            break;
01234        case 'I':
01235            image->format->coordinate = GERBV_COORDINATE_INCREMENTAL;
01236            break;
01237        default:
01238            string = g_strdup_printf("Invalid coordinate type defined in format code in file \n%s\n",
01239                                  fd->filename);
01240            gerbv_stats_add_error(stats->error_list,
01241                               -1,
01242                               string, 
01243                               GERBV_MESSAGE_ERROR);
01244            g_free(string);
01245            string = g_strdup_printf("Defaulting to absolute coordinates.\n");
01246            gerbv_stats_add_error(stats->error_list,
01247                              -1,
01248                               string,
01249                              GERBV_MESSAGE_WARNING);
01250            g_free(string);
01251            image->format->coordinate = GERBV_COORDINATE_ABSOLUTE;
01252        }
01253        op[0] = gerb_fgetc(fd);
01254        while((op[0] != '*')&&(op[0] != EOF)) {
01255            switch (op[0]) {
01256            case 'N':
01257               op[0] = (char)gerb_fgetc(fd);
01258               image->format->lim_seqno = op[0] - '0';
01259               break;
01260            case 'G':
01261               op[0] = (char)gerb_fgetc(fd);
01262               image->format->lim_gf = op[0] - '0';
01263               break;
01264            case 'D':
01265               op[0] = (char)gerb_fgetc(fd);
01266               image->format->lim_pf = op[0] - '0';
01267               break;
01268            case 'M':
01269               op[0] = (char)gerb_fgetc(fd);
01270               image->format->lim_mf = op[0] - '0';
01271               break;
01272            case 'X' :
01273               op[0] = gerb_fgetc(fd);
01274               if ((op[0] < '0') || (op[0] > '6')) {
01275                   string = g_strdup_printf("Illegal format size %c in file \n%s\n", 
01276                                         (char)op[0], fd->filename);
01277                   gerbv_stats_add_error(stats->error_list,
01278                                     -1,
01279                                      string,
01280                                      GERBV_MESSAGE_ERROR);
01281                   g_free(string);
01282               }
01283               image->format->x_int = op[0] - '0';
01284               op[0] = gerb_fgetc(fd);
01285               if ((op[0] < '0') || (op[0] > '6')) {
01286                   string = g_strdup_printf("Illegal format size %c in file \n%s\n", 
01287                                         (char)op[0], fd->filename);
01288                   gerbv_stats_add_error(stats->error_list,
01289                                      -1,
01290                                      string, 
01291                                      GERBV_MESSAGE_ERROR);
01292                   g_free(string);
01293               }
01294               image->format->x_dec = op[0] - '0';
01295               break;
01296            case 'Y':
01297               op[0] = gerb_fgetc(fd);
01298               if ((op[0] < '0') || (op[0] > '6')) {
01299                   string = g_strdup_printf("Illegal format size %c in file \n%s\n", 
01300                                         (char)op[0], fd->filename);
01301                   gerbv_stats_add_error(stats->error_list,
01302                                     -1,
01303                                      string, 
01304                                     GERBV_MESSAGE_ERROR);
01305                   g_free(string);
01306               }
01307               image->format->y_int = op[0] - '0';
01308               op[0] = gerb_fgetc(fd);
01309               if ((op[0] < '0') || (op[0] > '6')) {
01310                   string = g_strdup_printf("Illegal format size %c in file \n%s\n", 
01311                                         (char)op[0], fd->filename);
01312                   gerbv_stats_add_error(stats->error_list,
01313                                     -1,
01314                                      string, 
01315                                      GERBV_MESSAGE_ERROR);
01316                   g_free(string);
01317               }
01318               image->format->y_dec = op[0] - '0';
01319               break;
01320            default :
01321               string = g_strdup_printf("Illegal format statement [%c] in file \n%s\n", 
01322                                     op[0], fd->filename);
01323               gerbv_stats_add_error(stats->error_list,
01324                                  -1,
01325                                   string, 
01326                                  GERBV_MESSAGE_ERROR);
01327               g_free(string);
01328               string = g_strdup_printf("Ignoring invalid format statement.\n");
01329               gerbv_stats_add_error(stats->error_list,
01330                                  -1,
01331                                   string, 
01332                                  GERBV_MESSAGE_WARNING);
01333               g_free(string);
01334            }
01335            op[0] = gerb_fgetc(fd);
01336        }
01337        break;
01338     case A2I('M','I'): /* Mirror Image */
01339        op[0] = gerb_fgetc(fd);
01340        state->state = gerbv_image_return_new_netstate (state->state);
01341        
01342        while ((op[0] != '*')&&(op[0] != EOF)) {
01343             gint readValue=0;
01344            switch (op[0]) {
01345            case 'A' :
01346               readValue = gerb_fgetint(fd, NULL);
01347               if (readValue == 1) {
01348                   if (state->state->mirrorState == GERBV_MIRROR_STATE_FLIPB)
01349                      state->state->mirrorState=GERBV_MIRROR_STATE_FLIPAB;
01350                   else
01351                      state->state->mirrorState=GERBV_MIRROR_STATE_FLIPA;
01352               }
01353               break;
01354            case 'B' :
01355               readValue = gerb_fgetint(fd, NULL);
01356               if (readValue == 1) {
01357                   if (state->state->mirrorState == GERBV_MIRROR_STATE_FLIPA)
01358                      state->state->mirrorState=GERBV_MIRROR_STATE_FLIPAB;
01359                   else
01360                      state->state->mirrorState=GERBV_MIRROR_STATE_FLIPB;
01361               }
01362               break;
01363            default :
01364               string =  g_strdup_printf("Wrong character in mirror:%c\n", op[0]);
01365               gerbv_stats_add_error(stats->error_list,
01366                                  -1,
01367                                   string,
01368                                  GERBV_MESSAGE_ERROR);
01369               g_free(string);
01370            }
01371            op[0] = gerb_fgetc(fd);
01372        }
01373        break;  
01374     case A2I('M','O'): /* Mode of Units */
01375        op[0] = gerb_fgetc(fd);
01376        op[1] = gerb_fgetc(fd);
01377        
01378        if ((op[0] == EOF) || (op[1] == EOF))
01379            gerbv_stats_add_error(stats->error_list,
01380                              -1,
01381                              "Unexpected EOF found.\n",
01382                              GERBV_MESSAGE_ERROR);
01383        switch (A2I(op[0],op[1])) {
01384        case A2I('I','N'):
01385            state->state = gerbv_image_return_new_netstate (state->state);
01386            state->state->unit = GERBV_UNIT_INCH;
01387            break;
01388        case A2I('M','M'):
01389            state->state = gerbv_image_return_new_netstate (state->state);
01390            state->state->unit = GERBV_UNIT_MM;
01391            break;
01392        default:
01393            string = g_strdup_printf("Illegal unit:%c%c\n", op[0], op[1]);
01394            gerbv_stats_add_error(stats->error_list,
01395                              -1,
01396                               string, 
01397                              GERBV_MESSAGE_ERROR);
01398            g_free(string);
01399        }
01400        break;
01401     case A2I('O','F'): /* Offset */
01402        op[0] = gerb_fgetc(fd);
01403        
01404        while ((op[0] != '*')&&(op[0] != EOF)) {
01405            switch (op[0]) {
01406            case 'A' :
01407               state->state->offsetA = gerb_fgetdouble(fd) / scale;
01408               break;
01409            case 'B' :
01410               state->state->offsetB = gerb_fgetdouble(fd) / scale;
01411               break;
01412            default :
01413               string = g_strdup_printf("Wrong character in offset:%c\n", op[0]);
01414               gerbv_stats_add_error(stats->error_list,
01415                                   -1,
01416                                   string, 
01417                                   GERBV_MESSAGE_ERROR);
01418               g_free(string);
01419            }
01420            op[0] = gerb_fgetc(fd);
01421        }
01422        break;
01423     case A2I('I','F'): /* Include file */
01424        {
01425            gchar *includeFilename = gerb_fgetstring(fd, '*');
01426            
01427            if (includeFilename) {
01428               gchar *fullPath;
01429               if (!g_path_is_absolute(includeFilename)) {
01430                   fullPath = g_build_filename (directoryPath, includeFilename, NULL);
01431               } else {
01432                   fullPath = g_strdup (includeFilename);
01433               }
01434               if (levelOfRecursion < 10) {
01435                   gerb_file_t *includefd = NULL;
01436                   
01437                   includefd = gerb_fopen(fullPath);
01438                   if (includefd) {
01439                      gerber_parse_file_segment (levelOfRecursion + 1, image, state, curr_net, stats, includefd, directoryPath);
01440                      gerb_fclose(includefd);
01441                   } else {
01442                      string = g_strdup_printf("In file %s,\nIncluded file %s cannot be found\n",
01443                                            fd->filename, fullPath);
01444                      gerbv_stats_add_error(stats->error_list, 
01445                                          -1,
01446                                          string, 
01447                                          GERBV_MESSAGE_ERROR);
01448                      g_free(string);
01449                   }
01450                   g_free (fullPath);
01451               } else {
01452                   string = g_strdup_printf("Parser encountered more than 10 levels of include file recursion which is not allowed by the RS-274X spec\n");
01453                   gerbv_stats_add_error(stats->error_list, 
01454                                      -1,
01455                                      string, 
01456                                      GERBV_MESSAGE_ERROR);
01457                   g_free(string);
01458               }
01459               
01460            }
01461        }
01462        break;
01463     case A2I('I','O'): /* Image offset */
01464        op[0] = gerb_fgetc(fd);
01465        
01466        while ((op[0] != '*')&&(op[0] != EOF)) {
01467            switch (op[0]) {
01468            case 'A' :
01469               image->info->offsetA = gerb_fgetdouble(fd) / scale;
01470               break;
01471            case 'B' :
01472               image->info->offsetB = gerb_fgetdouble(fd) / scale;
01473               break;
01474            default :
01475               string = g_strdup_printf("In file %s,\nwrong character in image offset %c\n", 
01476                                     fd->filename, op[0]);
01477               gerbv_stats_add_error(stats->error_list,
01478                                  -1,
01479                                   string,
01480                                   GERBV_MESSAGE_ERROR);
01481               g_free(string);
01482            }
01483            op[0] = gerb_fgetc(fd);
01484        }
01485        break;
01486     case A2I('S','F'): /* Scale Factor */
01487        if (gerb_fgetc(fd) == 'A')
01488            state->state->scaleA = gerb_fgetdouble(fd);
01489        else 
01490            gerb_ungetc(fd);
01491        if (gerb_fgetc(fd) == 'B')
01492            state->state->scaleB = gerb_fgetdouble(fd);
01493        else 
01494            gerb_ungetc(fd);
01495        break;
01496     case A2I('I','C'): /* Input Code */
01497        /* Thanks to Stephen Adam for providing this information. As he writes:
01498         *      btw, here's a logic puzzle for you.  If you need to
01499         * read the gerber file to see how it's encoded, then
01500         * how can you read it?
01501         */
01502        op[0] = gerb_fgetc(fd);
01503        op[1] = gerb_fgetc(fd);
01504        
01505        if ((op[0] == EOF) || (op[1] == EOF)) {
01506            string = g_strdup_printf("Unexpected EOF found in file \n%s\n", fd->filename);
01507            gerbv_stats_add_error(stats->error_list,
01508                              -1,
01509                               string,
01510                              GERBV_MESSAGE_ERROR);
01511            g_free(string);
01512        }
01513        switch (A2I(op[0],op[1])) {
01514        case A2I('A','S'):
01515            image->info->encoding = GERBV_ENCODING_ASCII;
01516            break;
01517        case A2I('E','B'):
01518            image->info->encoding = GERBV_ENCODING_EBCDIC;
01519            break;
01520        case A2I('B','C'):
01521            image->info->encoding = GERBV_ENCODING_BCD;
01522            break;
01523        case A2I('I','S'):
01524            image->info->encoding = GERBV_ENCODING_ISO_ASCII;
01525            break;
01526        case A2I('E','I'):
01527            image->info->encoding = GERBV_ENCODING_EIA;
01528            break;
01529        default:
01530            string = g_strdup_printf("In file %s, \nunknown input code (IC): %c%c\n", 
01531                                  fd->filename, op[0], op[1]);
01532            gerbv_stats_add_error(stats->error_list,
01533                              -1,
01534                               string,
01535                              GERBV_MESSAGE_ERROR);
01536            g_free(string);
01537        }
01538        break;
01539        
01540        /* Image parameters */
01541     case A2I('I','J'): /* Image Justify */
01542        op[0] = gerb_fgetc(fd);
01543        image->info->imageJustifyTypeA = GERBV_JUSTIFY_LOWERLEFT;
01544        image->info->imageJustifyTypeB = GERBV_JUSTIFY_LOWERLEFT;
01545        image->info->imageJustifyOffsetA = 0.0;
01546        image->info->imageJustifyOffsetB = 0.0;
01547        while ((op[0] != '*')&&(op[0] != EOF)) {
01548            switch (op[0]) {
01549            case 'A' :
01550               op[0] = gerb_fgetc(fd);
01551               if (op[0] == 'C') {
01552                   image->info->imageJustifyTypeA = GERBV_JUSTIFY_CENTERJUSTIFY;
01553               } else if (op[0] == 'L') {
01554                   image->info->imageJustifyTypeA = GERBV_JUSTIFY_LOWERLEFT;
01555               } else {
01556                   gerb_ungetc (fd);
01557                   image->info->imageJustifyOffsetA = gerb_fgetdouble(fd) / scale;
01558               }
01559               break;
01560            case 'B' :
01561               op[0] = gerb_fgetc(fd);
01562               if (op[0] == 'C') {
01563                   image->info->imageJustifyTypeB = GERBV_JUSTIFY_CENTERJUSTIFY;
01564               } else if (op[0] == 'L') {
01565                   image->info->imageJustifyTypeB = GERBV_JUSTIFY_LOWERLEFT;
01566               } else {
01567                   gerb_ungetc (fd);
01568                   image->info->imageJustifyOffsetB = gerb_fgetdouble(fd) / scale;
01569               }
01570               break;
01571            default :
01572               string = g_strdup_printf("In file %s,\nwrong character in image justify:%c\n", 
01573                                     fd->filename, op[0]);
01574               gerbv_stats_add_error(stats->error_list,
01575                                  -1,
01576                                   string,
01577                                  GERBV_MESSAGE_ERROR);
01578               g_free(string);
01579            }
01580            op[0] = gerb_fgetc(fd);
01581        }
01582        break;
01583     case A2I('I','N'): /* Image Name */
01584        image->info->name = gerb_fgetstring(fd, '*');
01585        break;
01586     case A2I('I','P'): /* Image Polarity */
01587        
01588        for (ano = 0; ano < 3; ano++) {
01589            op[0] = gerb_fgetc(fd);
01590            if (op[0] == EOF) {
01591               string = g_strdup_printf("In file %s,\nunexpected EOF while reading image polarity (IP)\n",
01592                                     fd->filename);
01593               gerbv_stats_add_error(stats->error_list,
01594                                  -1,
01595                                   string,
01596                                  GERBV_MESSAGE_ERROR);
01597               g_free(string);
01598            }
01599            str[ano] = (char)op[0];
01600        }
01601        
01602        if (strncmp(str, "POS", 3) == 0) 
01603            image->info->polarity = GERBV_POLARITY_POSITIVE;
01604        else if (strncmp(str, "NEG", 3) == 0)
01605            image->info->polarity = GERBV_POLARITY_NEGATIVE;
01606        else {
01607            string = g_strdup_printf("Unknown polarity : %c%c%c\n", str[0], str[1], str[2]);
01608            gerbv_stats_add_error(stats->error_list,
01609                              -1,
01610                               string,
01611                              GERBV_MESSAGE_ERROR);
01612            g_free(string);
01613        }
01614        break;
01615     case A2I('I','R'): /* Image Rotation */
01616        tmp = gerb_fgetint(fd, NULL);
01617        if (tmp == 90)
01618            image->info->imageRotation = M_PI / 2.0;
01619        else if (tmp == 180)
01620            image->info->imageRotation = M_PI;
01621        else if (tmp == 270)
01622            image->info->imageRotation = 3.0 * M_PI / 2.0;
01623        else {
01624            string = g_strdup_printf("Image rotation must be 0, 90, 180 or 270 (is actually %d)\n", tmp);
01625            gerbv_stats_add_error(stats->error_list,
01626                              -1,
01627                               string,
01628                              GERBV_MESSAGE_ERROR);
01629            g_free(string);
01630        }
01631        break;
01632     case A2I('P','F'): /* Plotter Film */
01633        image->info->plotterFilm = gerb_fgetstring(fd, '*');
01634        break;
01635        
01636        /* Aperture parameters */
01637     case A2I('A','D'): /* Aperture Description */
01638        a = (gerbv_aperture_t *) g_new0 (gerbv_aperture_t,1);
01639 
01640        ano = parse_aperture_definition(fd, a, image, scale);
01641        if ((ano >= APERTURE_MIN) && (ano <= APERTURE_MAX)) {
01642            a->unit = state->state->unit;
01643            image->aperture[ano] = a;
01644            dprintf("     In parse_rs274x, adding new aperture to aperture list ...\n");
01645            gerbv_stats_add_aperture(stats->aperture_list,
01646                                 -1, ano, 
01647                                 a->type,
01648                                 a->parameter);
01649            gerbv_stats_add_to_D_list(stats->D_code_list,
01650                                  ano);
01651        } else {
01652            string = g_strdup_printf("In file %s,\naperture number out of bounds : %d\n", 
01653                                  fd->filename, ano);
01654            gerbv_stats_add_error(stats->error_list,
01655                              -1,
01656                               string,
01657                              GERBV_MESSAGE_ERROR);
01658            g_free(string);
01659        }
01660        /* Add aperture info to stats->aperture_list here */
01661        
01662        break;
01663     case A2I('A','M'): /* Aperture Macro */
01664        tmp_amacro = image->amacro;
01665        image->amacro = parse_aperture_macro(fd);
01666        if (image->amacro) {
01667            image->amacro->next = tmp_amacro;
01668 #ifdef AMACRO_DEBUG
01669            print_program(image->amacro);
01670 #endif
01671        } else {
01672            string = g_strdup_printf("In file %s, \nfailed to parse aperture macro\n", 
01673                                  fd->filename);
01674            gerbv_stats_add_error(stats->error_list,
01675                              -1,
01676                               string,
01677                              GERBV_MESSAGE_ERROR);
01678            g_free(string);
01679        }
01680        break;
01681        /* Layer */
01682     case A2I('L','N'): /* Layer Name */
01683        state->layer = gerbv_image_return_new_layer (state->layer);
01684        state->layer->name = gerb_fgetstring(fd, '*');
01685        break;
01686     case A2I('L','P'): /* Layer Polarity */
01687        state->layer = gerbv_image_return_new_layer (state->layer);
01688        switch (gerb_fgetc(fd)) {
01689        case 'D': /* Dark Polarity (default) */
01690            state->layer->polarity = GERBV_POLARITY_DARK;
01691            break;
01692        case 'C': /* Clear Polarity */
01693            state->layer->polarity = GERBV_POLARITY_CLEAR;
01694            break;
01695        default:
01696            string = g_strdup_printf("In file %s,\nunknown Layer Polarity: %c\n", 
01697                                  fd->filename, op[0]);
01698            gerbv_stats_add_error(stats->error_list,
01699                              -1,
01700                               string,
01701                              GERBV_MESSAGE_ERROR);
01702            g_free(string);
01703        }
01704        break;
01705     case A2I('K','O'): /* Knock Out */
01706         state->layer = gerbv_image_return_new_layer (state->layer);
01707         gerber_update_any_running_knockout_measurements (image);
01708         /* reset any previous knockout measurements */
01709         knockoutMeasure = FALSE;
01710         op[0] = gerb_fgetc(fd);
01711        if (op[0] == '*') { /* Disable previous SR parameters */
01712            state->layer->knockout.type = GERBV_KNOCKOUT_TYPE_NOKNOCKOUT;
01713            break;
01714        } else if (op[0] == 'C') {
01715            state->layer->knockout.polarity = GERBV_POLARITY_CLEAR;
01716        } else if (op[0] == 'D') {
01717            state->layer->knockout.polarity = GERBV_POLARITY_DARK;
01718        } else {
01719            string = g_strdup_printf("In file %s,\nknockout must supply a polarity (C, D, or *)\n",
01720                                  fd->filename);
01721            gerbv_stats_add_error(stats->error_list,
01722                              -1,
01723                               string,
01724                              GERBV_MESSAGE_ERROR);
01725            g_free(string);
01726        }
01727        state->layer->knockout.lowerLeftX = 0.0;
01728        state->layer->knockout.lowerLeftY = 0.0;
01729        state->layer->knockout.width = 0.0;
01730        state->layer->knockout.height = 0.0;
01731        state->layer->knockout.border = 0.0;
01732        state->layer->knockout.firstInstance = TRUE;
01733        op[0] = gerb_fgetc(fd);
01734        while ((op[0] != '*')&&(op[0] != EOF)) { 
01735            switch (op[0]) {
01736            case 'X':
01737                state->layer->knockout.type = GERBV_KNOCKOUT_TYPE_FIXEDKNOCK;
01738               state->layer->knockout.lowerLeftX = gerb_fgetdouble(fd) / scale;
01739               break;
01740            case 'Y':
01741                state->layer->knockout.type = GERBV_KNOCKOUT_TYPE_FIXEDKNOCK;
01742               state->layer->knockout.lowerLeftY = gerb_fgetdouble(fd) / scale;
01743               break;
01744            case 'I':
01745                state->layer->knockout.type = GERBV_KNOCKOUT_TYPE_FIXEDKNOCK;
01746               state->layer->knockout.width = gerb_fgetdouble(fd) / scale;
01747               break;
01748            case 'J':
01749                state->layer->knockout.type = GERBV_KNOCKOUT_TYPE_FIXEDKNOCK;
01750               state->layer->knockout.height = gerb_fgetdouble(fd) / scale;
01751               break;
01752            case 'K':
01753                state->layer->knockout.type = GERBV_KNOCKOUT_TYPE_BORDER;
01754                state->layer->knockout.border = gerb_fgetdouble(fd) / scale;
01755                /* this is a bordered knockout, so we need to start measuring the
01756                   size of a square bordering all future components */
01757                knockoutMeasure = TRUE;
01758                knockoutLimitXmin = HUGE_VAL;
01759                knockoutLimitYmin = HUGE_VAL;
01760                knockoutLimitXmax = -HUGE_VAL;
01761                knockoutLimitYmax = -HUGE_VAL;
01762                knockoutLayer = state->layer;
01763                break;
01764            default:
01765               string = g_strdup_printf("In file %s, \nunknown variable in knockout",
01766                                     fd->filename);
01767               gerbv_stats_add_error(stats->error_list,
01768                                  -1,
01769                                   string,
01770                                  GERBV_MESSAGE_ERROR);
01771               g_free(string);
01772            }
01773            op[0] = gerb_fgetc(fd);
01774        }
01775        break;
01776     case A2I('S','R'): /* Step and Repeat */
01777         /* start by generating a new layer (duplicating previous layer settings */
01778         state->layer = gerbv_image_return_new_layer (state->layer);
01779        op[0] = gerb_fgetc(fd);
01780        if (op[0] == '*') { /* Disable previous SR parameters */
01781            state->layer->stepAndRepeat.X = 1;
01782            state->layer->stepAndRepeat.Y = 1;
01783            state->layer->stepAndRepeat.dist_X = 0.0;
01784            state->layer->stepAndRepeat.dist_Y = 0.0;
01785            break;
01786        }
01787        while ((op[0] != '*')&&(op[0] != EOF)) { 
01788            switch (op[0]) {
01789            case 'X':
01790               state->layer->stepAndRepeat.X = gerb_fgetint(fd, NULL);
01791               break;
01792            case 'Y':
01793               state->layer->stepAndRepeat.Y = gerb_fgetint(fd, NULL);
01794               break;
01795            case 'I':
01796               state->layer->stepAndRepeat.dist_X = gerb_fgetdouble(fd) / scale;
01797               break;
01798            case 'J':
01799               state->layer->stepAndRepeat.dist_Y = gerb_fgetdouble(fd) / scale;
01800               break;
01801            default:
01802               string = g_strdup_printf("In file %s,\nstep-and-repeat parameter error\n",
01803                                     fd->filename);
01804               gerbv_stats_add_error(stats->error_list,
01805                                  -1,
01806                                   string,
01807                                   GERBV_MESSAGE_ERROR);
01808               g_free(string);
01809            }
01810            
01811            /*
01812             * Repeating 0 times in any direction would disable the whole plot, and
01813             * is probably not intended. At least one other tool (viewmate) seems
01814             * to interpret 0-time repeating as repeating just once too.
01815             */
01816            if(state->layer->stepAndRepeat.X == 0)
01817               state->layer->stepAndRepeat.X = 1;
01818            if(state->layer->stepAndRepeat.Y == 0)
01819               state->layer->stepAndRepeat.Y = 1;
01820            
01821            op[0] = gerb_fgetc(fd);
01822        }
01823        break;
01824        /* is this an actual RS274X command??  It isn't explainined in the spec... */
01825     case A2I('R','O'):
01826        state->layer = gerbv_image_return_new_layer (state->layer);
01827        
01828        state->layer->rotation = gerb_fgetdouble(fd) * M_PI / 180;
01829        op[0] = gerb_fgetc(fd);
01830        if (op[0] != '*') {
01831            string = g_strdup_printf("In file %s,\nerror in layer rotation command\n",
01832                                  fd->filename);
01833            gerbv_stats_add_error(stats->error_list,
01834                              -1,
01835                               string,
01836                              GERBV_MESSAGE_ERROR);
01837            g_free(string);
01838        }
01839        break;
01840     default:
01841        string = g_strdup_printf("In file %s,\nunknown RS-274X extension found %%%c%c%%\n", 
01842                              fd->filename, op[0], op[1]);
01843        gerbv_stats_add_error(stats->error_list,
01844                           -1,
01845                            string,
01846                           GERBV_MESSAGE_ERROR);
01847        g_free(string);
01848     }
01849     
01850     return;
01851 } /* parse_rs274x */
01852 
01853 
01854 /*
01855  * Stack declarations and operations to be used by the simple engine that
01856  * executes the parsed aperture macros.
01857  */
01858 typedef struct {
01859     double *stack;
01860     int sp;
01861 } macro_stack_t;
01862 
01863 
01864 static macro_stack_t *
01865 new_stack(unsigned int stack_size)
01866 {
01867     macro_stack_t *s;
01868 
01869     s = (macro_stack_t *) g_new0 (macro_stack_t,1);
01870     s->stack = (double *) g_new0 (double, stack_size);
01871     s->sp = 0;
01872     return s;
01873 } /* new_stack */
01874 
01875 
01876 static void
01877 free_stack(macro_stack_t *s)
01878 {
01879     if (s && s->stack)
01880        free(s->stack);
01881 
01882     if (s)
01883        free(s);
01884 
01885     return;
01886 } /* free_stack */
01887 
01888 
01889 static void
01890 push(macro_stack_t *s, double val)
01891 {
01892     s->stack[s->sp++] = val;
01893     return;
01894 } /* push */
01895 
01896 
01897 static int
01898 pop(macro_stack_t *s, double *value)
01899 {
01900     /* Check if we try to pop an empty stack */
01901     if (s->sp == 0) {
01902        return -1;
01903     }
01904     
01905     *value = s->stack[--s->sp];
01906     return 0;
01907 } /* pop */
01908 
01909 
01910 /* ------------------------------------------------------------------ */
01911 static int
01912 simplify_aperture_macro(gerbv_aperture_t *aperture, gdouble scale)
01913 {
01914     const int extra_stack_size = 10;
01915     macro_stack_t *s;
01916     gerbv_instruction_t *ip;
01917     int handled = 1, nuf_parameters = 0, i, j, clearOperatorUsed = FALSE;
01918     double *lp; /* Local copy of parameters */
01919     double tmp[2] = {0.0, 0.0};
01920     gerbv_aperture_type_t type = GERBV_APTYPE_NONE;
01921     gerbv_simplified_amacro_t *sam;
01922 
01923     if (aperture == NULL)
01924        GERB_FATAL_ERROR("aperture NULL in simplify aperture macro\n");
01925 
01926     if (aperture->amacro == NULL)
01927        GERB_FATAL_ERROR("aperture->amacro NULL in simplify aperture macro\n");
01928 
01929     /* Allocate stack for VM */
01930     s = new_stack(aperture->amacro->nuf_push + extra_stack_size);
01931     if (s == NULL) 
01932        GERB_FATAL_ERROR("malloc stack failed\n");
01933 
01934     /* Make a copy of the parameter list that we can rewrite if necessary */
01935     lp = (double *)malloc(sizeof(double) * APERTURE_PARAMETERS_MAX);
01936     if (lp == NULL)
01937        GERB_FATAL_ERROR("malloc local parameter storage failed\n");
01938 
01939     memcpy(lp, aperture->parameter, sizeof(double) * APERTURE_PARAMETERS_MAX);
01940     
01941     for(ip = aperture->amacro->program; ip != NULL; ip = ip->next) {
01942        switch(ip->opcode) {
01943        case GERBV_OPCODE_NOP:
01944            break;
01945        case GERBV_OPCODE_PUSH :
01946            push(s, ip->data.fval);
01947            break;
01948         case GERBV_OPCODE_PPUSH :
01949            push(s, lp[ip->data.ival - 1]);
01950            break;
01951        case GERBV_OPCODE_PPOP:
01952            if (pop(s, &tmp[0]) < 0)
01953               GERB_FATAL_ERROR("Tried to pop an empty stack");
01954            lp[ip->data.ival - 1] = tmp[0];
01955            break;
01956        case GERBV_OPCODE_ADD :
01957            if (pop(s, &tmp[0]) < 0)
01958               GERB_FATAL_ERROR("Tried to pop an empty stack");
01959            if (pop(s, &tmp[1]) < 0)
01960               GERB_FATAL_ERROR("Tried to pop an empty stack");
01961            push(s, tmp[1] + tmp[0]);
01962            break;
01963        case GERBV_OPCODE_SUB :
01964            if (pop(s, &tmp[0]) < 0)
01965               GERB_FATAL_ERROR("Tried to pop an empty stack");
01966            if (pop(s, &tmp[1]) < 0)
01967               GERB_FATAL_ERROR("Tried to pop an empty stack");
01968            push(s, tmp[1] - tmp[0]);
01969            break;
01970        case GERBV_OPCODE_MUL :
01971            if (pop(s, &tmp[0]) < 0)
01972               GERB_FATAL_ERROR("Tried to pop an empty stack");
01973            if (pop(s, &tmp[1]) < 0)
01974               GERB_FATAL_ERROR("Tried to pop an empty stack");
01975            push(s, tmp[1] * tmp[0]);
01976            break;
01977        case GERBV_OPCODE_DIV :
01978            if (pop(s, &tmp[0]) < 0)
01979               GERB_FATAL_ERROR("Tried to pop an empty stack");
01980            if (pop(s, &tmp[1]) < 0)
01981               GERB_FATAL_ERROR("Tried to pop an empty stack");
01982            push(s, tmp[1] / tmp[0]);
01983            break;
01984        case GERBV_OPCODE_PRIM :
01985            /* 
01986             * This handles the exposure thing in the aperture macro
01987             * The exposure is always the first element on stack independent
01988             * of aperture macro.
01989             */
01990            switch(ip->data.ival) {
01991            case 1:
01992               dprintf("  Aperture macro circle [1] (");
01993               type = GERBV_APTYPE_MACRO_CIRCLE;
01994               nuf_parameters = 4;
01995               break;
01996            case 3:
01997               break;
01998            case 4 :
01999               dprintf("  Aperture macro outline [4] (");
02000               type = GERBV_APTYPE_MACRO_OUTLINE;
02001               /*
02002                * Number of parameters are:
02003                * - number of points defined in entry 1 of the stack + 
02004                *   start point. Times two since it is both X and Y.
02005                * - Then three more; exposure,  nuf points and rotation.
02006                */
02007               nuf_parameters = ((int)s->stack[1] + 1) * 2 + 3;
02008               break;
02009            case 5 :
02010               dprintf("  Aperture macro polygon [5] (");
02011               type = GERBV_APTYPE_MACRO_POLYGON;
02012               nuf_parameters = 6;
02013               break;
02014            case 6 :
02015               dprintf("  Aperture macro moiré [6] (");
02016               type = GERBV_APTYPE_MACRO_MOIRE;
02017               nuf_parameters = 9;
02018               break;
02019            case 7 :
02020               dprintf("  Aperture macro thermal [7] (");
02021               type = GERBV_APTYPE_MACRO_THERMAL;
02022               nuf_parameters = 6;
02023               break;
02024            case 2  :
02025            case 20 :
02026               dprintf("  Aperture macro line 20/2 (");
02027               type = GERBV_APTYPE_MACRO_LINE20;
02028               nuf_parameters = 7;
02029               break;
02030            case 21 :
02031               dprintf("  Aperture macro line 21 (");
02032               type = GERBV_APTYPE_MACRO_LINE21;
02033               nuf_parameters = 6;
02034               break;
02035            case 22 :
02036               dprintf("  Aperture macro line 22 (");
02037               type = GERBV_APTYPE_MACRO_LINE22;
02038               nuf_parameters = 6;
02039               break;
02040            default :
02041               handled = 0;
02042            }
02043 
02044            if (type != GERBV_APTYPE_NONE) { 
02045               if (nuf_parameters > APERTURE_PARAMETERS_MAX) {
02046                   GERB_COMPILE_ERROR("Number of parameters to aperture macro are more than gerbv is able to store\n");
02047               }
02048 
02049               /*
02050                * Create struct for simplified aperture macro and
02051                * start filling in the blanks.
02052                */
02053               sam = (gerbv_simplified_amacro_t *)malloc(sizeof(gerbv_simplified_amacro_t));
02054               if (sam == NULL)
02055                   GERB_FATAL_ERROR("Failed to malloc simplified aperture macro\n");
02056               sam->type = type;
02057               sam->next = NULL;
02058               memset(sam->parameter, 0, 
02059                      sizeof(double) * APERTURE_PARAMETERS_MAX);
02060               memcpy(sam->parameter, s->stack, 
02061                      sizeof(double) *  nuf_parameters);
02062               
02063               /* convert any mm values to inches */
02064               switch (type) {
02065                   case GERBV_APTYPE_MACRO_CIRCLE:
02066                      if (fabs(sam->parameter[0]) < 0.001)
02067                          clearOperatorUsed = TRUE;
02068                      sam->parameter[1]/=scale;
02069                      sam->parameter[2]/=scale;
02070                      sam->parameter[3]/=scale;
02071                      break;
02072                   case GERBV_APTYPE_MACRO_OUTLINE:
02073                      if (fabs(sam->parameter[0]) < 0.001)
02074                          clearOperatorUsed = TRUE;
02075                      for (j=2; j<nuf_parameters-1; j++){
02076                          sam->parameter[j]/=scale;
02077                      }
02078                      break;
02079                   case GERBV_APTYPE_MACRO_POLYGON:
02080                      if (fabs(sam->parameter[0]) < 0.001)
02081                          clearOperatorUsed = TRUE;
02082                      sam->parameter[2]/=scale;
02083                      sam->parameter[3]/=scale;
02084                      sam->parameter[4]/=scale;
02085                      break;
02086                   case GERBV_APTYPE_MACRO_MOIRE:
02087                      sam->parameter[0]/=scale;
02088                      sam->parameter[1]/=scale;
02089                      sam->parameter[2]/=scale;
02090                      sam->parameter[3]/=scale;
02091                      sam->parameter[4]/=scale;
02092                      sam->parameter[6]/=scale;
02093                      sam->parameter[7]/=scale;
02094                      break;
02095                   case GERBV_APTYPE_MACRO_THERMAL:
02096                      sam->parameter[0]/=scale;
02097                      sam->parameter[1]/=scale;
02098                      sam->parameter[2]/=scale;
02099                      sam->parameter[3]/=scale;
02100                      sam->parameter[4]/=scale;
02101                      break;
02102                   case GERBV_APTYPE_MACRO_LINE20:
02103                      if (fabs(sam->parameter[0]) < 0.001)
02104                          clearOperatorUsed = TRUE;
02105                      sam->parameter[1]/=scale;
02106                      sam->parameter[2]/=scale;
02107                      sam->parameter[3]/=scale;
02108                      sam->parameter[4]/=scale;
02109                      sam->parameter[5]/=scale;
02110                      break;
02111                   case GERBV_APTYPE_MACRO_LINE21:
02112                   case GERBV_APTYPE_MACRO_LINE22:
02113                      if (fabs(sam->parameter[0]) < 0.001)
02114                          clearOperatorUsed = TRUE;
02115                      sam->parameter[1]/=scale;
02116                      sam->parameter[2]/=scale;
02117                      sam->parameter[3]/=scale;
02118                      sam->parameter[4]/=scale;
02119                      break;
02120                   default: 
02121                      break;               
02122               }
02123               /* 
02124                * Add this simplified aperture macro to the end of the list
02125                * of simplified aperture macros. If first entry, put it
02126                * in the top.
02127                */
02128               if (aperture->simplified == NULL) {
02129                   aperture->simplified = sam;
02130               } else {
02131                   gerbv_simplified_amacro_t *tmp_sam;
02132                   tmp_sam = aperture->simplified;
02133                   while (tmp_sam->next != NULL) {
02134                      tmp_sam = tmp_sam->next;
02135                   }
02136                   tmp_sam->next = sam;
02137               }
02138 
02139 #ifdef DEBUG
02140               for (i = 0; i < nuf_parameters; i++) {
02141                   dprintf("%f, ", s->stack[i]);
02142               }
02143 #endif /* DEBUG */
02144               dprintf(")\n");
02145            }
02146 
02147            /* 
02148             * Here we reset the stack pointer. It's not general correct
02149             * correct to do this, but since I know how the compiler works
02150             * I can do this. The correct way to do this should be to 
02151             * subtract number of used elements in each primitive operation.
02152             */
02153            s->sp = 0;
02154            break;
02155        default :
02156            break;
02157        }
02158     }
02159     free_stack(s);
02160 
02161     /* store a flag to let the renderer know if it should expect any "clear"
02162        primatives */
02163     aperture->parameter[0]= (gdouble) clearOperatorUsed;
02164     return handled;
02165 } /* simplify_aperture_macro */
02166 
02167 
02168 /* ------------------------------------------------------------------ */
02169 static int 
02170 parse_aperture_definition(gerb_file_t *fd, gerbv_aperture_t *aperture,
02171                        gerbv_image_t *image, gdouble scale)
02172 {
02173     int ano, i;
02174     char *ad;
02175     char *token;
02176     gerbv_amacro_t *curr_amacro;
02177     gerbv_amacro_t *amacro = image->amacro;
02178     gerbv_stats_t *stats = image->gerbv_stats;
02179     gdouble tempHolder;
02180     gchar *string;
02181     
02182     if (gerb_fgetc(fd) != 'D') {
02183        string = g_strdup_printf("Found AD code with no following 'D' in file \n%s\n", 
02184                              fd->filename);
02185        gerbv_stats_add_error(stats->error_list,
02186                           -1,
02187                            string,
02188                           GERBV_MESSAGE_ERROR);  
02189        g_free(string);
02190        return -1;
02191     }
02192     
02193     /*
02194      * Get aperture no
02195      */
02196     ano = gerb_fgetint(fd, NULL);
02197     
02198     /*
02199      * Read in the whole aperture defintion and tokenize it
02200      */
02201     ad = gerb_fgetstring(fd, '*');
02202     token = strtok(ad, ",");
02203     
02204     if (strlen(token) == 1) {
02205        switch (token[0]) {
02206        case 'C':
02207            aperture->type = GERBV_APTYPE_CIRCLE;
02208            break;
02209        case 'R' :
02210            aperture->type = GERBV_APTYPE_RECTANGLE;
02211            break;
02212        case 'O' :
02213            aperture->type = GERBV_APTYPE_OVAL;
02214            break;
02215        case 'P' :
02216            aperture->type = GERBV_APTYPE_POLYGON;
02217            break;
02218        }
02219        /* Here a should a T be defined, but I don't know what it represents */
02220     } else {
02221        aperture->type = GERBV_APTYPE_MACRO;
02222        /*
02223         * In aperture definition, point to the aperture macro 
02224         * used in the defintion
02225         */
02226        curr_amacro = amacro;
02227        while (curr_amacro) {
02228            if ((strlen(curr_amacro->name) == strlen(token)) &&
02229               (strcmp(curr_amacro->name, token) == 0)) {
02230               aperture->amacro = curr_amacro;
02231               break;
02232            }
02233            curr_amacro = curr_amacro->next;
02234        }
02235     }
02236     
02237     /*
02238      * Parse all parameters
02239      */
02240     for (token = strtok(NULL, "X"), i = 0; token != NULL; 
02241         token = strtok(NULL, "X"), i++) {
02242        if (i == APERTURE_PARAMETERS_MAX) {
02243            string = g_strdup_printf("In file %s,\nmaximum number of allowed parameters exceeded in aperture %d\n", 
02244                                  fd->filename, ano);
02245            gerbv_stats_add_error(stats->error_list,
02246                               -1,
02247                               string, 
02248                               GERBV_MESSAGE_ERROR);
02249            g_free(string);
02250            break;
02251        }
02252        errno = 0;
02253 
02254        tempHolder = strtod(token, NULL);
02255        /* convert any MM values to inches */
02256        /* don't scale polygon angles or side numbers, or macro parmaeters */
02257        if (!(((aperture->type == GERBV_APTYPE_POLYGON) && ((i==1) || (i==2)))||
02258               (aperture->type == GERBV_APTYPE_MACRO))) {
02259            tempHolder /= scale;
02260        }
02261        
02262        aperture->parameter[i] = tempHolder;
02263        if (errno) {
02264            string = g_strdup_printf("Failed to read all parameters exceeded in aperture %d\n", ano);
02265            gerbv_stats_add_error(stats->error_list,
02266                               -1,
02267                               string,
02268                               GERBV_MESSAGE_WARNING);
02269            g_free(string);
02270             aperture->parameter[i] = 0.0;
02271         }
02272     }
02273     
02274     aperture->nuf_parameters = i;
02275     
02276     gerb_ungetc(fd);
02277 
02278     if (aperture->type == GERBV_APTYPE_MACRO) {
02279        dprintf("Simplifying aperture %d using aperture macro \"%s\"\n", ano,
02280               aperture->amacro->name);
02281        simplify_aperture_macro(aperture, scale);
02282        dprintf("Done simplifying\n");
02283     }
02284     
02285     g_free(ad);
02286     
02287     return ano;
02288 } /* parse_aperture_definition */
02289 
02290 
02291 /* ------------------------------------------------------------------ */
02292 static void 
02293 calc_cirseg_sq(struct gerbv_net *net, int cw, 
02294               double delta_cp_x, double delta_cp_y)
02295 {
02296     double d1x, d1y, d2x, d2y;
02297     double alfa, beta;
02298     int quadrant = 0;
02299 
02300     
02301     /*
02302      * Quadrant detection (based on ccw, converted below if cw)
02303      *  Y ^
02304      *   /!\
02305      *    !
02306      *    ---->X
02307      */
02308     if (net->start_x > net->stop_x)
02309        /* 1st and 2nd quadrant */
02310        if (net->start_y < net->stop_y)
02311            quadrant = 1;
02312        else
02313            quadrant = 2;
02314     else
02315        /* 3rd and 4th quadrant */
02316        if (net->start_y > net->stop_y)
02317            quadrant = 3;
02318        else
02319            quadrant = 4;
02320 
02321     /* 
02322      * If clockwise, rotate quadrant
02323      */
02324     if (cw) {
02325        switch (quadrant) {
02326        case 1 : 
02327            quadrant = 3;
02328            break;
02329        case 2 : 
02330            quadrant = 4;
02331            break;
02332        case 3 : 
02333            quadrant = 1;
02334            break;
02335        case 4 : 
02336            quadrant = 2;
02337            break;
02338        default : 
02339            GERB_COMPILE_ERROR("Unknow quadrant value while converting to cw\n");
02340        }
02341     }
02342 
02343     /*
02344      * Calculate arc center point
02345      */
02346     switch (quadrant) {
02347     case 1 :
02348        net->cirseg->cp_x = net->start_x - delta_cp_x;
02349        net->cirseg->cp_y = net->start_y - delta_cp_y;
02350        break;
02351     case 2 :
02352        net->cirseg->cp_x = net->start_x + delta_cp_x;
02353        net->cirseg->cp_y = net->start_y - delta_cp_y;
02354        break;
02355     case 3 : 
02356        net->cirseg->cp_x = net->start_x + delta_cp_x;
02357        net->cirseg->cp_y = net->start_y + delta_cp_y;
02358        break;
02359     case 4 :
02360        net->cirseg->cp_x = net->start_x - delta_cp_x;
02361        net->cirseg->cp_y = net->start_y + delta_cp_y;
02362        break;
02363     default :
02364        GERB_COMPILE_ERROR("Strange quadrant : %d\n", quadrant);
02365     }
02366 
02367     /*
02368      * Some good values 
02369      */
02370     d1x = fabs(net->start_x - net->cirseg->cp_x);
02371     d1y = fabs(net->start_y - net->cirseg->cp_y);
02372     d2x = fabs(net->stop_x - net->cirseg->cp_x);
02373     d2y = fabs(net->stop_y - net->cirseg->cp_y);
02374 
02375     alfa = atan2(d1y, d1x);
02376     beta = atan2(d2y, d2x);
02377 
02378     /*
02379      * Avoid divide by zero when sin(0) = 0 and cos(90) = 0
02380      */
02381     net->cirseg->width = alfa < beta ? 
02382        2 * (d1x / cos(alfa)) : 2 * (d2x / cos(beta));
02383     net->cirseg->height = alfa > beta ? 
02384        2 * (d1y / sin(alfa)) : 2 * (d2y / sin(beta));
02385 
02386     if (alfa < 0.000001 && beta < 0.000001) {
02387        net->cirseg->height = 0;
02388     }
02389 
02390 #define RAD2DEG(a) (a * 180 / M_PI) 
02391     
02392     switch (quadrant) {
02393     case 1 :
02394        net->cirseg->angle1 = RAD2DEG(alfa);
02395        net->cirseg->angle2 = RAD2DEG(beta);
02396        break;
02397     case 2 :
02398        net->cirseg->angle1 = 180.0 - RAD2DEG(alfa);
02399        net->cirseg->angle2 = 180.0 - RAD2DEG(beta);
02400        break;
02401     case 3 : 
02402        net->cirseg->angle1 = 180.0 + RAD2DEG(alfa);
02403        net->cirseg->angle2 = 180.0 + RAD2DEG(beta);
02404        break;
02405     case 4 :
02406        net->cirseg->angle1 = 360.0 - RAD2DEG(alfa);
02407        net->cirseg->angle2 = 360.0 - RAD2DEG(beta);
02408        break;
02409     default :
02410        GERB_COMPILE_ERROR("Strange quadrant : %d\n", quadrant);
02411     }
02412 
02413     if (net->cirseg->width < 0.0)
02414        GERB_COMPILE_WARNING("Negative width [%f] in quadrant %d [%f][%f]\n", 
02415                           net->cirseg->width, quadrant, alfa, beta);
02416     
02417     if (net->cirseg->height < 0.0)
02418        GERB_COMPILE_WARNING("Negative height [%f] in quadrant %d [%f][%f]\n", 
02419                           net->cirseg->height, quadrant, RAD2DEG(alfa), RAD2DEG(beta));
02420 
02421     return;
02422 
02423 } /* calc_cirseg_sq */
02424 
02425 
02426 /* ------------------------------------------------------------------ */
02427 static void 
02428 calc_cirseg_mq(struct gerbv_net *net, int cw, 
02429               double delta_cp_x, double delta_cp_y)
02430 {
02431     double d1x, d1y, d2x, d2y;
02432     double alfa, beta;
02433 
02434     net->cirseg->cp_x = net->start_x + delta_cp_x;
02435     net->cirseg->cp_y = net->start_y + delta_cp_y;
02436 
02437     /*
02438      * Some good values 
02439      */
02440     d1x = net->start_x - net->cirseg->cp_x;
02441     d1y = net->start_y - net->cirseg->cp_y;
02442     d2x = net->stop_x - net->cirseg->cp_x;
02443     d2y = net->stop_y - net->cirseg->cp_y;
02444     
02445     alfa = atan2(d1y, d1x);
02446     beta = atan2(d2y, d2x);
02447 
02448     net->cirseg->width = sqrt(delta_cp_x*delta_cp_x + delta_cp_y*delta_cp_y);
02449     net->cirseg->width *= 2.0;
02450     net->cirseg->height = net->cirseg->width;
02451 
02452     net->cirseg->angle1 = RAD2DEG(alfa);
02453     net->cirseg->angle2 = RAD2DEG(beta);
02454 
02455     /*
02456      * Make sure it's always positive angles
02457      */
02458     if (net->cirseg->angle1 < 0.0) {
02459        net->cirseg->angle1 += 360.0;
02460        net->cirseg->angle2 += 360.0;
02461     }
02462 
02463     if (net->cirseg->angle2 < 0.0) 
02464        net->cirseg->angle2 += 360.0;
02465 
02466     if(net->cirseg->angle2 == 0.0) 
02467        net->cirseg->angle2 = 360.0;
02468 
02469     /*
02470      * This is a sanity check for angles after the nature of atan2.
02471      * If cw we must make sure angle1-angle2 are always positive,
02472      * If ccw we must make sure angle2-angle1 are always negative.
02473      * We should really return one angle and the difference as GTK
02474      * uses them. But what the heck, it works for me.
02475      */
02476     if (cw) {
02477        if (net->cirseg->angle1 <= net->cirseg->angle2)
02478            net->cirseg->angle2 -= 360.0;
02479     } else {
02480        if (net->cirseg->angle1 >= net->cirseg->angle2)
02481            net->cirseg->angle2 += 360.0;
02482     }
02483 
02484     return;
02485 } /* calc_cirseg_mq */
02486 
02487 
02488 static void
02489 gerber_update_any_running_knockout_measurements (gerbv_image_t *image)
02490 {
02491     if (knockoutMeasure) {
02492        knockoutLayer->knockout.lowerLeftX = knockoutLimitXmin;
02493        knockoutLayer->knockout.lowerLeftY = knockoutLimitYmin;
02494        knockoutLayer->knockout.width = knockoutLimitXmax - knockoutLimitXmin;
02495        knockoutLayer->knockout.height = knockoutLimitYmax - knockoutLimitYmin;
02496        knockoutMeasure = FALSE;
02497     }
02498 }
02499 
02500 
02501 static void
02502 gerber_calculate_final_justify_effects(gerbv_image_t *image)
02503 {
02504     gdouble translateA = 0.0, translateB = 0.0;
02505     
02506     if (image->info->imageJustifyTypeA != GERBV_JUSTIFY_NOJUSTIFY) {
02507        if (image->info->imageJustifyTypeA == GERBV_JUSTIFY_CENTERJUSTIFY)
02508            translateA = (image->info->max_x - image->info->min_x) / 2.0;
02509        else
02510            translateA = -image->info->min_x;
02511     }
02512     if (image->info->imageJustifyTypeB != GERBV_JUSTIFY_NOJUSTIFY) {
02513        if (image->info->imageJustifyTypeB == GERBV_JUSTIFY_CENTERJUSTIFY)
02514            translateB = (image->info->max_y - image->info->min_y) / 2.0;
02515        else
02516            translateB = -image->info->min_y;
02517     }
02518 
02519     /* update the min/max values so the autoscale function can correctly
02520        centered a justified image */
02521     image->info->min_x += translateA+ image->info->imageJustifyOffsetA;
02522     image->info->max_x += translateA+ image->info->imageJustifyOffsetA;
02523     image->info->min_y += translateB+ image->info->imageJustifyOffsetB;
02524     image->info->max_y += translateB+ image->info->imageJustifyOffsetB;
02525  
02526     /* store the absolute offset for the justify so we can quickly offset
02527        the rendered picture during drawing */
02528     image->info->imageJustifyOffsetActualA = translateA + 
02529        image->info->imageJustifyOffsetA;
02530     image->info->imageJustifyOffsetActualB = translateB + 
02531        image->info->imageJustifyOffsetB;
02532 } /* gerber_calculate_final_justify_effects */
02533 
02534 
02535 static void
02536 gerber_update_min_and_max(gerbv_image_info_t *info, gdouble repeatX, gdouble repeatY,
02537                        gdouble x, gdouble y, gdouble apertureSizeX1,
02538                        gdouble apertureSizeX2,gdouble apertureSizeY1,
02539                        gdouble apertureSizeY2)
02540 {
02541     gdouble ourX1 = x - apertureSizeX1, ourY1 = y - apertureSizeY1;
02542     gdouble ourX2 = x + apertureSizeX2, ourY2 = y + apertureSizeY2;
02543     
02544     if (repeatX > 0)
02545        ourX2 += repeatX;
02546     if (repeatY > 0)
02547        ourY2 += repeatY;
02548     
02549 #ifndef RENDER_USING_GDK
02550     /* transform the point to the final rendered position, accounting
02551        for any scaling, offsets, mirroring, etc */
02552     /* NOTE: we need to already add/subtract in the aperture size since
02553        the final rendering may be scaled */
02554     cairo_matrix_transform_point (&currentMatrix, &ourX1, &ourY1);
02555     cairo_matrix_transform_point (&currentMatrix, &ourX2, &ourY2);
02556 #endif
02557 
02558     /* check both points against the min/max, since depending on the rotation,
02559        mirroring, etc, either point could possibly be a min or max */
02560     if(info->min_x > ourX1)
02561        info->min_x = ourX1;
02562     if(info->min_x > ourX2)
02563        info->min_x = ourX2;
02564     if(info->max_x < ourX1)
02565        info->max_x = ourX1;
02566     if(info->max_x < ourX2)
02567        info->max_x = ourX2;
02568     if(info->min_y > ourY1)
02569        info->min_y = ourY1;
02570     if(info->min_y > ourY2)
02571        info->min_y = ourY2;
02572     if(info->max_y < ourY1)
02573        info->max_y = ourY1;
02574     if(info->max_y < ourY2)
02575        info->max_y = ourY2;
02576 
02577     if (knockoutMeasure) {
02578        if(knockoutLimitXmin > ourX1)
02579            knockoutLimitXmin = ourX1;
02580        if(knockoutLimitXmin > ourX2)
02581            knockoutLimitXmin = ourX2;
02582        if(knockoutLimitXmax < ourX1)
02583            knockoutLimitXmax = ourX1;
02584        if(knockoutLimitXmax < ourX2)
02585            knockoutLimitXmax = ourX2;
02586        if(knockoutLimitYmin > ourY1)
02587            knockoutLimitYmin = ourY1;
02588        if(knockoutLimitYmin > ourY2)
02589            knockoutLimitYmin = ourY2;
02590        if(knockoutLimitYmax < ourY1)
02591            knockoutLimitYmax = ourY1;
02592        if(knockoutLimitYmax < ourY2)
02593            knockoutLimitYmax = ourY2; 
02594     }
02595 } /* gerber_update_min_and_max */
02596 

Generated on Tue Aug 19 00:14:48 2008 for gerbv by  doxygen 1.5.6