draw.c

Go to the documentation of this file.
00001 /*
00002  * gEDA - GNU Electronic Design Automation
00003  * This file 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 #ifdef HAVE_CONFIG_H
00030 #include <config.h>
00031 #endif
00032 
00033 #include <stdio.h>
00034 #include <stdlib.h>
00035 #include <math.h>  /* ceil(), atan2() */
00036 
00037 #ifdef HAVE_STRING_H
00038 #include <string.h>
00039 #endif
00040 
00041 #include <gtk/gtk.h>
00042 #include "gerbv.h"
00043 #include "draw.h"
00044 #include "draw-gdk.h"
00045 #include <cairo.h>
00046 
00047 #define dprintf if(DEBUG) printf
00048 static void
00049 draw_check_if_object_is_in_selected_area (cairo_t *cairoTarget, gboolean isStroke,
00050               gerbv_selection_info_t *selectionInfo, gerbv_image_t *image, struct gerbv_net *net){
00051        gdouble corner1X,corner1Y,corner2X,corner2Y;
00052 
00053        corner1X = selectionInfo->lowerLeftX;
00054        corner1Y = selectionInfo->lowerLeftY;
00055        corner2X = selectionInfo->upperRightX;
00056        corner2Y = selectionInfo->upperRightY;
00057 
00058        /* calculate the coordinate of the user's click in the current
00059           transformation matrix */
00060        cairo_device_to_user  (cairoTarget, &corner1X, &corner1Y);
00061        cairo_device_to_user  (cairoTarget, &corner2X, &corner2Y);
00062        if (selectionInfo->type == GERBV_SELECTION_POINT_CLICK) {
00063               /* use the cairo in_fill routine to see if the point is within the
00064                  drawn area */
00065               if ((isStroke && cairo_in_stroke (cairoTarget, corner1X, corner1Y)) ||
00066                      (!isStroke && cairo_in_fill (cairoTarget, corner1X, corner1Y))) {
00067                      /* add the net to the selection array */
00068                      gerbv_selection_item_t sItem = {image, net};
00069                      g_array_append_val (selectionInfo->selectedNodeArray, sItem);
00070               }
00071        }
00072        else if (selectionInfo->type == GERBV_SELECTION_DRAG_BOX) {
00073               gdouble x1,x2,y1,y2;
00074               gdouble minX,minY,maxX,maxY;
00075               
00076               /* we can't assume the "lowerleft" corner is actually in the lower left,
00077                  since the cairo transformation matrix may be mirrored,etc */
00078               minX = MIN(corner1X,corner2X);
00079               maxX = MAX(corner1X,corner2X);
00080               minY = MIN(corner1Y,corner2Y);
00081               maxY = MAX(corner1Y,corner2Y);
00082               if (isStroke)
00083                      cairo_stroke_extents (cairoTarget, &x1, &y1, &x2, &y2);
00084               else
00085                      cairo_fill_extents (cairoTarget, &x1, &y1, &x2, &y2);
00086               
00087               if ((minX < x1) && (minY < y1) && (maxX > x2) && (maxY > y2)) {
00088                      /* add the net to the selection array */
00089                      gerbv_selection_item_t sItem = {image, net};
00090                      g_array_append_val (selectionInfo->selectedNodeArray, sItem); 
00091               }
00092        }
00093        /* clear the path, since we didn't actually draw it and cairo
00094                doesn't reset it after the previous calls */
00095        cairo_new_path (cairoTarget);
00096 }
00097 
00098 static void
00099 draw_fill (cairo_t *cairoTarget, gchar drawMode, gerbv_selection_info_t *selectionInfo,
00100               gerbv_image_t *image, struct gerbv_net *net){
00101        if ((drawMode == DRAW_IMAGE) || (drawMode == DRAW_SELECTIONS))
00102               cairo_fill (cairoTarget);
00103        else
00104               draw_check_if_object_is_in_selected_area (cairoTarget, FALSE,
00105                      selectionInfo, image, net);
00106 }
00107 
00108 static void
00109 draw_stroke (cairo_t *cairoTarget, gchar drawMode, gerbv_selection_info_t *selectionInfo,
00110               gerbv_image_t *image, struct gerbv_net *net){
00111        if ((drawMode == DRAW_IMAGE) || (drawMode == DRAW_SELECTIONS))
00112               cairo_stroke (cairoTarget);
00113        else
00114               draw_check_if_object_is_in_selected_area (cairoTarget, TRUE,
00115                      selectionInfo, image, net);
00116 }
00117 
00118 /*
00119  * Draws a circle _centered_ at x,y with diameter dia
00120  */
00121 static void 
00122 gerbv_draw_circle(cairo_t *cairoTarget, gdouble diameter)
00123 {
00124     cairo_arc (cairoTarget, 0.0, 0.0, diameter/2.0, 0, 2.0*M_PI);
00125     return;
00126 } /* gerbv_draw_circle */
00127 
00128 
00129 /*
00130  * Draws a rectangle _centered_ at x,y with sides x_side, y_side
00131  */
00132 static void
00133 gerbv_draw_rectangle(cairo_t *cairoTarget, gdouble width, gdouble height)
00134 {
00135     cairo_rectangle (cairoTarget, - width / 2.0, - height / 2.0, width, height);
00136     return;
00137 } /* gerbv_draw_rectangle */
00138 
00139 
00140 /*
00141  * Draws an oblong _centered_ at x,y with x axis x_axis and y axis y_axis
00142  */ 
00143 static void
00144 gerbv_draw_oblong(cairo_t *cairoTarget, gdouble width, gdouble height)
00145 {
00146     /*
00147     cairo_new_path (cairoTarget);
00148     cairo_set_line_cap (cairoTarget, CAIRO_LINE_CAP_ROUND);
00149     cairo_set_line_width (cairoTarget, height);
00150     cairo_move_to (cairoTarget, -width/2.0 + height/2.0, 0);
00151     cairo_line_to (cairoTarget, width/2.0 - height/2.0, 0);
00152     draw_stroke (cairoTarget, drawMode, selectionInfo);
00153     */
00154     /* cairo doesn't have a function to draw ovals, so we must
00155      * draw an arc and stretch it by scaling different x and y values
00156      */
00157     cairo_save (cairoTarget);
00158     cairo_scale (cairoTarget, width, height);
00159     gerbv_draw_circle (cairoTarget, 1);
00160     cairo_restore (cairoTarget);
00161     return;
00162 } /* gerbv_draw_oval */
00163 
00164 
00165 static void
00166 gerbv_draw_polygon(cairo_t *cairoTarget, gdouble outsideDiameter,
00167                  gdouble numberOfSides, gdouble degreesOfRotation)
00168 {
00169     int i, numberOfSidesInteger = (int) numberOfSides;
00170     
00171     cairo_rotate(cairoTarget, degreesOfRotation * M_PI/180);
00172     cairo_move_to(cairoTarget, outsideDiameter / 2.0, 0);
00173     /* skip first point, since we've moved there already */
00174     /* include last point, since we may be drawing an aperture hole next
00175        and cairo may not correctly close the path itself */
00176     for (i = 1; i <= (int)numberOfSidesInteger; i++){
00177        gdouble angle = (double) i / numberOfSidesInteger * M_PI * 2.0;
00178        cairo_line_to (cairoTarget, cos(angle) * outsideDiameter / 2.0,
00179                      sin(angle) * outsideDiameter / 2.0);
00180     }
00181     return;
00182 } /* gerbv_draw_polygon */
00183 
00184 
00185 static void 
00186 gerbv_draw_aperature_hole(cairo_t *cairoTarget, gdouble dimensionX, gdouble dimensionY)
00187 {
00188     if (dimensionX) {
00189        if (dimensionY) {
00190            gerbv_draw_rectangle (cairoTarget, dimensionX, dimensionY);
00191        } else {
00192            gerbv_draw_circle (cairoTarget, dimensionX);
00193        }
00194     }
00195     return;
00196 } /* gerbv_draw_aperature_hole */
00197 
00198 gboolean
00199 draw_update_macro_exposure (cairo_t *cairoTarget, cairo_operator_t clearOperator,
00200               cairo_operator_t darkOperator, gdouble exposureSetting){
00201 
00202        if (exposureSetting == 0.0) {
00203               cairo_set_operator (cairoTarget, clearOperator);
00204        }
00205        else if (exposureSetting == 1.0) {
00206               cairo_set_operator (cairoTarget, darkOperator);
00207        }
00208        else if (exposureSetting == 2.0) {
00209               /* reverse current exposure setting */
00210               cairo_operator_t currentOperator = cairo_get_operator (cairoTarget);
00211               if (currentOperator == clearOperator) {
00212                      cairo_set_operator (cairoTarget, darkOperator);
00213               }
00214               else {
00215                      cairo_set_operator (cairoTarget, clearOperator);
00216               }
00217        }
00218        return TRUE;
00219 }
00220 
00221            
00222 int
00223 gerbv_draw_amacro(cairo_t *cairoTarget, cairo_operator_t clearOperator,
00224        cairo_operator_t darkOperator, gerbv_simplified_amacro_t *s,
00225        gint usesClearPrimative, gchar drawMode, gerbv_selection_info_t *selectionInfo,
00226        gerbv_image_t *image, struct gerbv_net *net)
00227 {
00228     int handled = 1;  
00229     gerbv_simplified_amacro_t *ls = s;
00230 
00231     dprintf("Drawing simplified aperture macros:\n");
00232     if (usesClearPrimative)
00233        cairo_push_group (cairoTarget);
00234     while (ls != NULL) {
00235            /* 
00236             * This handles the exposure thing in the aperture macro
00237             * The exposure is always the first element on stack independent
00238             * of aperture macro.
00239             */
00240            cairo_save (cairoTarget);
00241            cairo_new_path(cairoTarget);
00242            cairo_operator_t oldOperator = cairo_get_operator (cairoTarget);
00243 
00244            if (ls->type == GERBV_APTYPE_MACRO_CIRCLE) {
00245               
00246              if (draw_update_macro_exposure (cairoTarget, clearOperator, 
00247                      darkOperator, ls->parameter[CIRCLE_EXPOSURE])){
00248                      cairo_translate (cairoTarget, ls->parameter[CIRCLE_CENTER_X],
00249                                    ls->parameter[CIRCLE_CENTER_Y]);
00250                      
00251                      gerbv_draw_circle (cairoTarget, ls->parameter[CIRCLE_DIAMETER]);
00252                      draw_fill (cairoTarget, drawMode, selectionInfo, image, net);
00253               }
00254            } else if (ls->type == GERBV_APTYPE_MACRO_OUTLINE) {
00255               int pointCounter,numberOfPoints;
00256               /* Number of points parameter seems to not include the start point,
00257                * so we add one to include the start point.
00258                */
00259               numberOfPoints = (int) ls->parameter[OUTLINE_NUMBER_OF_POINTS] + 1;
00260               
00261               if (draw_update_macro_exposure (cairoTarget, clearOperator, 
00262                                    darkOperator, ls->parameter[OUTLINE_EXPOSURE])){
00263                      cairo_rotate (cairoTarget, ls->parameter[(numberOfPoints - 1) * 2 + OUTLINE_ROTATION] * M_PI/180.0);
00264                      cairo_move_to (cairoTarget, ls->parameter[OUTLINE_FIRST_X], ls->parameter[OUTLINE_FIRST_Y]);
00265                      
00266                      for (pointCounter=0; pointCounter < numberOfPoints; pointCounter++) {
00267                          cairo_line_to (cairoTarget, ls->parameter[pointCounter * 2 + OUTLINE_FIRST_X],
00268                                       ls->parameter[pointCounter * 2 + OUTLINE_FIRST_Y]);
00269                      }
00270                      /* although the gerber specs allow for an open outline,
00271                         I interpret it to mean the outline should be closed by the
00272                         rendering softare automatically, since there is no dimension
00273                         for line thickness.
00274                      */
00275                      draw_fill (cairoTarget, drawMode, selectionInfo, image, net);
00276               }
00277            } else if (ls->type == GERBV_APTYPE_MACRO_POLYGON) {
00278              if (draw_update_macro_exposure (cairoTarget, clearOperator, 
00279                             darkOperator, ls->parameter[POLYGON_EXPOSURE])){
00280                      cairo_translate (cairoTarget, ls->parameter[POLYGON_CENTER_X],
00281                                    ls->parameter[POLYGON_CENTER_Y]);
00282                      gerbv_draw_polygon(cairoTarget, ls->parameter[POLYGON_DIAMETER],
00283                                       ls->parameter[POLYGON_NUMBER_OF_POINTS], ls->parameter[POLYGON_ROTATION]);
00284                      draw_fill (cairoTarget, drawMode, selectionInfo, image, net);
00285               }
00286            } else if (ls->type == GERBV_APTYPE_MACRO_MOIRE) {
00287               gdouble diameter, gap;
00288               int circleIndex;
00289               
00290               cairo_translate (cairoTarget, ls->parameter[MOIRE_CENTER_X],
00291                             ls->parameter[MOIRE_CENTER_Y]);
00292               cairo_rotate (cairoTarget, ls->parameter[MOIRE_ROTATION] * M_PI/180);
00293               diameter = ls->parameter[MOIRE_OUTSIDE_DIAMETER] -  ls->parameter[MOIRE_CIRCLE_THICKNESS];
00294               gap = ls->parameter[MOIRE_GAP_WIDTH] + ls->parameter[MOIRE_CIRCLE_THICKNESS];
00295               cairo_set_line_width (cairoTarget, ls->parameter[MOIRE_CIRCLE_THICKNESS]);
00296               
00297               for (circleIndex = 0; circleIndex < (int)ls->parameter[MOIRE_NUMBER_OF_CIRCLES];  circleIndex++) {
00298                   gdouble currentDiameter = (diameter - gap * (float) circleIndex);
00299                   gerbv_draw_circle (cairoTarget, currentDiameter);
00300                   draw_stroke (cairoTarget, drawMode, selectionInfo, image, net);
00301               }
00302               
00303               gdouble crosshairRadius = (ls->parameter[MOIRE_CROSSHAIR_LENGTH] / 2.0);
00304               
00305               cairo_set_line_width (cairoTarget, ls->parameter[MOIRE_CROSSHAIR_THICKNESS]);
00306               cairo_move_to (cairoTarget, -crosshairRadius, 0);
00307               cairo_line_to (cairoTarget, crosshairRadius, 0);        
00308               cairo_move_to (cairoTarget, 0, -crosshairRadius);
00309               cairo_line_to (cairoTarget, 0, crosshairRadius);
00310               draw_stroke (cairoTarget, drawMode, selectionInfo, image, net);
00311            } else if (ls->type == GERBV_APTYPE_MACRO_THERMAL) {
00312               gint i;
00313               gdouble startAngle1, startAngle2, endAngle1, endAngle2;
00314               
00315               cairo_translate (cairoTarget, ls->parameter[THERMAL_CENTER_X],
00316                             ls->parameter[THERMAL_CENTER_Y]);
00317               cairo_rotate (cairoTarget, ls->parameter[THERMAL_ROTATION] * M_PI/180.0);
00318               startAngle1 = atan (ls->parameter[THERMAL_CROSSHAIR_THICKNESS]/ls->parameter[THERMAL_INSIDE_DIAMETER]);
00319               endAngle1 = M_PI/2 - startAngle1;
00320               endAngle2 = atan (ls->parameter[THERMAL_CROSSHAIR_THICKNESS]/ls->parameter[THERMAL_OUTSIDE_DIAMETER]);
00321               startAngle2 = M_PI/2 - endAngle2;
00322               for (i = 0; i < 4; i++) {
00323                      cairo_arc (cairoTarget, 0, 0, ls->parameter[THERMAL_INSIDE_DIAMETER]/2.0, startAngle1, endAngle1);
00324                      cairo_rel_line_to (cairoTarget, 0, ls->parameter[THERMAL_CROSSHAIR_THICKNESS]);
00325                      cairo_arc_negative (cairoTarget, 0, 0, ls->parameter[THERMAL_OUTSIDE_DIAMETER]/2.0,
00326                             startAngle2, endAngle2);
00327                      cairo_rel_line_to (cairoTarget, -ls->parameter[THERMAL_CROSSHAIR_THICKNESS],0);
00328                      draw_fill (cairoTarget, drawMode, selectionInfo, image, net);
00329                      cairo_rotate (cairoTarget, 90 * M_PI/180);
00330               }
00331            } else if (ls->type == GERBV_APTYPE_MACRO_LINE20) {
00332              if (draw_update_macro_exposure (cairoTarget, clearOperator, 
00333                             darkOperator, ls->parameter[LINE20_EXPOSURE])){
00334                      cairo_set_line_width (cairoTarget, ls->parameter[LINE20_LINE_WIDTH]);
00335                      cairo_set_line_cap (cairoTarget, CAIRO_LINE_CAP_BUTT);
00336                      cairo_rotate (cairoTarget, ls->parameter[LINE20_ROTATION] * M_PI/180.0);
00337                      cairo_move_to (cairoTarget, ls->parameter[LINE20_START_X], ls->parameter[LINE20_START_Y]);
00338                      cairo_line_to (cairoTarget, ls->parameter[LINE20_END_X], ls->parameter[LINE20_END_Y]);
00339                      draw_stroke (cairoTarget, drawMode, selectionInfo, image, net);
00340               }
00341            } else if (ls->type == GERBV_APTYPE_MACRO_LINE21) {
00342               gdouble halfWidth, halfHeight;
00343               
00344               if (draw_update_macro_exposure (cairoTarget, clearOperator,
00345                                           darkOperator, ls->parameter[LINE22_EXPOSURE])){
00346                      halfWidth = ls->parameter[LINE21_WIDTH] / 2.0;
00347                      halfHeight = ls->parameter[LINE21_HEIGHT] / 2.0;
00348                      cairo_translate (cairoTarget, ls->parameter[LINE21_CENTER_X], ls->parameter[LINE21_CENTER_Y]);
00349                      cairo_rotate (cairoTarget, ls->parameter[LINE21_ROTATION] * M_PI/180.0);
00350                      cairo_rectangle (cairoTarget, -halfWidth, -halfHeight,
00351                                     ls->parameter[LINE21_WIDTH], ls->parameter[LINE21_HEIGHT]);
00352                      draw_fill (cairoTarget, drawMode, selectionInfo, image, net);
00353               }      
00354            } else if (ls->type == GERBV_APTYPE_MACRO_LINE22) {
00355               gdouble halfWidth, halfHeight;
00356               
00357               if (draw_update_macro_exposure (cairoTarget, clearOperator,
00358                                    darkOperator, ls->parameter[LINE22_EXPOSURE])){
00359                      halfWidth = ls->parameter[LINE22_WIDTH] / 2.0;
00360                      halfHeight = ls->parameter[LINE22_HEIGHT] / 2.0;
00361                      cairo_translate (cairoTarget, ls->parameter[LINE22_LOWER_LEFT_X],
00362                                    ls->parameter[LINE22_LOWER_LEFT_Y]);
00363                      cairo_rotate (cairoTarget, ls->parameter[LINE22_ROTATION] * M_PI/180.0);
00364                      cairo_rectangle (cairoTarget, 0, 0,
00365                                    ls->parameter[LINE22_WIDTH], ls->parameter[LINE22_HEIGHT]);
00366                      draw_fill (cairoTarget, drawMode, selectionInfo, image, net);
00367               }
00368            } else {
00369               handled = 0;
00370            }
00371            cairo_set_operator (cairoTarget, oldOperator);
00372            cairo_restore (cairoTarget);
00373            ls = ls->next;
00374     }
00375     if (usesClearPrimative) {
00376        cairo_pop_group_to_source (cairoTarget);
00377       cairo_paint (cairoTarget);
00378     }
00379     return handled;
00380 } /* gerbv_draw_amacro */
00381 
00382 
00383 void
00384 draw_apply_netstate_transformation (cairo_t *cairoTarget, gerbv_netstate_t *state) 
00385 {
00386        /* apply scale factor */
00387        cairo_scale (cairoTarget, state->scaleA, state->scaleB);
00388        /* apply offset */
00389        cairo_translate (cairoTarget, state->offsetA, state->offsetB);
00390        /* apply mirror */
00391        switch (state->mirrorState) {
00392               case GERBV_MIRROR_STATE_FLIPA:
00393                      cairo_scale (cairoTarget, -1, 1);
00394                      break;
00395               case GERBV_MIRROR_STATE_FLIPB:
00396                      cairo_scale (cairoTarget, 1, -1);
00397                      break;
00398               case GERBV_MIRROR_STATE_FLIPAB:
00399                      cairo_scale (cairoTarget, -1, -1);
00400                      break;
00401               default:
00402                      break;
00403        }
00404        /* finally, apply axis select */
00405        if (state->axisSelect == GERBV_AXIS_SELECT_SWAPAB) {
00406               /* we do this by rotating 270 (counterclockwise, then mirroring
00407                  the Y axis */
00408               cairo_rotate (cairoTarget, 3 * M_PI / 2);
00409               cairo_scale (cairoTarget, 1, -1);
00410        }
00411 }
00412 
00413 void
00414 draw_render_polygon_object (gerbv_net_t *oldNet, cairo_t *cairoTarget, gdouble sr_x, gdouble sr_y,
00415               gerbv_image_t *image, gchar drawMode, gerbv_selection_info_t *selectionInfo ){
00416        gerbv_net_t *currentNet, *polygonStartNet;
00417        int haveDrawnFirstFillPoint = 0;
00418        gdouble x1,y1,x2,y2,cp_x=0,cp_y=0;
00419        
00420        haveDrawnFirstFillPoint = FALSE;
00421        /* save the first net in the polygon as the "ID" net pointer
00422           in case we are saving this net to the selection array */
00423        polygonStartNet = oldNet;
00424        cairo_new_path(cairoTarget);
00425               
00426        for (currentNet = oldNet->next; currentNet!=NULL; currentNet = currentNet->next){
00427               x1 = currentNet->start_x + sr_x;
00428               y1 = currentNet->start_y + sr_y;
00429               x2 = currentNet->stop_x + sr_x;
00430               y2 = currentNet->stop_y + sr_y;
00431            
00432               /* translate circular x,y data as well */
00433               if (currentNet->cirseg) {
00434                      cp_x = currentNet->cirseg->cp_x + sr_x;
00435                      cp_y = currentNet->cirseg->cp_y + sr_y;
00436               }
00437               if (!haveDrawnFirstFillPoint) {
00438                      cairo_move_to (cairoTarget, x2,y2);
00439                      haveDrawnFirstFillPoint=TRUE;
00440                      continue;
00441               }
00442               switch (currentNet->interpolation) {
00443                      case GERBV_INTERPOLATION_x10 :
00444                      case GERBV_INTERPOLATION_LINEARx01 :
00445                      case GERBV_INTERPOLATION_LINEARx001 :
00446                      case GERBV_INTERPOLATION_LINEARx1 :
00447                             cairo_line_to (cairoTarget, x2,y2);
00448                             break;
00449                      case GERBV_INTERPOLATION_CW_CIRCULAR :
00450                      case GERBV_INTERPOLATION_CCW_CIRCULAR :
00451                             if (currentNet->cirseg->angle2 > currentNet->cirseg->angle1) {
00452                                    cairo_arc (cairoTarget, cp_x, cp_y, currentNet->cirseg->width/2.0,
00453                                           currentNet->cirseg->angle1 * M_PI/180,currentNet->cirseg->angle2 * M_PI/180);
00454                             }
00455                             else {
00456                                    cairo_arc_negative (cairoTarget, cp_x, cp_y, currentNet->cirseg->width/2.0,
00457                                           currentNet->cirseg->angle1 * M_PI/180,currentNet->cirseg->angle2 * M_PI/180);
00458                             }
00459                             break;
00460                      case GERBV_INTERPOLATION_PAREA_END :
00461                             cairo_close_path(cairoTarget);
00462                             /* turn off anti-aliasing for polygons, since it shows seams
00463                                with adjacent polygons (usually on PCB ground planes) */
00464                             cairo_antialias_t oldAlias = cairo_get_antialias (cairoTarget);
00465                             cairo_set_antialias (cairoTarget, CAIRO_ANTIALIAS_NONE);
00466                             draw_fill (cairoTarget, drawMode, selectionInfo, image, polygonStartNet);
00467                             cairo_set_antialias (cairoTarget, oldAlias);
00468                             return;
00469                      default :
00470                             break;
00471               }
00472        }
00473 }
00474 
00475 int
00476 draw_image_to_cairo_target (cairo_t *cairoTarget, gerbv_image_t *image,
00477                                    gboolean invertLayer, gdouble pixelWidth,
00478                                    gchar drawMode, gerbv_selection_info_t *selectionInfo)
00479 {
00480        struct gerbv_net *net, *polygonStartNet=NULL;
00481        double x1, y1, x2, y2, cp_x=0, cp_y=0;
00482        gdouble p1, p2, p3, p4, p5, dx, dy;
00483        gerbv_netstate_t *oldState;
00484        gerbv_layer_t *oldLayer;
00485        int repeat_X=1, repeat_Y=1;
00486        double repeat_dist_X = 0, repeat_dist_Y = 0;
00487        int repeat_i, repeat_j;
00488        cairo_operator_t drawOperatorClear, drawOperatorDark;
00489        gboolean invertPolarity = FALSE;
00490        
00491     /* do initial justify */
00492        cairo_translate (cairoTarget, image->info->imageJustifyOffsetActualA,
00493                image->info->imageJustifyOffsetActualB);
00494 
00495     /* set the fill rule so aperture holes are cleared correctly */    
00496     cairo_set_fill_rule (cairoTarget, CAIRO_FILL_RULE_EVEN_ODD);
00497     /* offset image */
00498     cairo_translate (cairoTarget, image->info->offsetA, image->info->offsetB);
00499     /* do image rotation */
00500     cairo_rotate (cairoTarget, image->info->imageRotation);
00501     /* load in polarity operators depending on the image polarity */
00502     invertPolarity = invertLayer;
00503     if (image->info->polarity == GERBV_POLARITY_NEGATIVE)
00504        invertPolarity = !invertPolarity;
00505     if (invertPolarity) {
00506        drawOperatorClear = CAIRO_OPERATOR_OVER;
00507        drawOperatorDark = CAIRO_OPERATOR_CLEAR;
00508        cairo_set_operator (cairoTarget, CAIRO_OPERATOR_OVER);
00509        cairo_paint (cairoTarget);
00510        cairo_set_operator (cairoTarget, CAIRO_OPERATOR_CLEAR);
00511     }
00512     else {
00513       drawOperatorClear = CAIRO_OPERATOR_CLEAR;
00514        drawOperatorDark = CAIRO_OPERATOR_OVER;
00515     }
00516     /* next, push two cairo states to simulate the first layer and netstate
00517        translations (these will be popped when another layer or netstate is
00518        started */
00519 
00520     cairo_save (cairoTarget);
00521     cairo_save (cairoTarget);
00522     /* store the current layer and netstate so we know when they change */
00523     oldLayer = image->layers;
00524     oldState = image->states;
00525 
00526     for (net = image->netlist->next ; net != NULL; net = gerbv_image_return_next_renderable_object(net)) {
00527 
00528        /* check if this is a new layer */
00529        if (net->layer != oldLayer){
00530               /* it's a new layer, so recalculate the new transformation matrix
00531                  for it */
00532               cairo_restore (cairoTarget);
00533               cairo_restore (cairoTarget);
00534               cairo_save (cairoTarget);
00535               /* do any rotations */
00536               cairo_rotate (cairoTarget, net->layer->rotation);
00537               /* handle the layer polarity */
00538               if ((net->layer->polarity == GERBV_POLARITY_CLEAR)) {
00539                      cairo_set_operator (cairoTarget, drawOperatorClear);
00540               }
00541               else {
00542                      cairo_set_operator (cairoTarget, drawOperatorDark);
00543               }
00544               /* check for changes to step and repeat */
00545               repeat_X = net->layer->stepAndRepeat.X;
00546               repeat_Y = net->layer->stepAndRepeat.Y;
00547               repeat_dist_X = net->layer->stepAndRepeat.dist_X;
00548               repeat_dist_Y = net->layer->stepAndRepeat.dist_Y;
00549               /* draw any knockout areas */
00550               if (net->layer->knockout.firstInstance == TRUE) {
00551                      cairo_operator_t oldOperator = cairo_get_operator (cairoTarget);
00552                      if (net->layer->knockout.polarity == GERBV_POLARITY_CLEAR) {
00553                             cairo_set_operator (cairoTarget, drawOperatorClear);
00554                      }
00555                      else {
00556                             cairo_set_operator (cairoTarget, drawOperatorDark);
00557                      }
00558                      cairo_new_path (cairoTarget);
00559                      cairo_rectangle (cairoTarget, net->layer->knockout.lowerLeftX - net->layer->knockout.border,
00560                                    net->layer->knockout.lowerLeftY - net->layer->knockout.border,
00561                                    net->layer->knockout.width + (net->layer->knockout.border*2),
00562                                    net->layer->knockout.height + (net->layer->knockout.border*2));
00563                      draw_fill (cairoTarget, drawMode, selectionInfo, image, net);
00564                      cairo_set_operator (cairoTarget, oldOperator);
00565               }
00566               /* finally, reapply old netstate transformation */
00567               cairo_save (cairoTarget);
00568               draw_apply_netstate_transformation (cairoTarget, net->state);
00569               oldLayer = net->layer;
00570        }
00571        /* check if this is a new netstate */
00572        if (net->state != oldState){
00573               /* pop the transformation matrix back to the "pre-state" state and
00574                  resave it */
00575               cairo_restore (cairoTarget);
00576               cairo_save (cairoTarget);
00577               /* it's a new state, so recalculate the new transformation matrix
00578                  for it */
00579               draw_apply_netstate_transformation (cairoTarget, net->state);
00580               oldState = net->state;      
00581        }
00582        /* if we are only drawing from the selection buffer, search if this net is
00583           in the buffer */
00584        if (drawMode == DRAW_SELECTIONS) {
00585               /* this flag makes sure we don't draw any unintentional polygons...
00586                  if we've successfully entered a polygon (the first net matches, and
00587                  we don't want to check the nets inside the polygon) then
00588                  polygonStartNet will be set */
00589               if (!polygonStartNet) {
00590                      int i;
00591                      gboolean foundNet = FALSE;
00592                      
00593                      for (i=0; i<selectionInfo->selectedNodeArray->len; i++){
00594                             gerbv_selection_item_t sItem = g_array_index (selectionInfo->selectedNodeArray,
00595                                    gerbv_selection_item_t, i);
00596                             if (sItem.net == net)
00597                                    foundNet = TRUE;
00598                      }
00599                      if (!foundNet)
00600                             continue;
00601               }
00602               
00603        }
00604        for(repeat_i = 0; repeat_i < repeat_X; repeat_i++) {
00605            for(repeat_j = 0; repeat_j < repeat_Y; repeat_j++) {
00606               double sr_x = repeat_i * repeat_dist_X;
00607               double sr_y = repeat_j * repeat_dist_Y;
00608               
00609               x1 = net->start_x + sr_x;
00610               y1 = net->start_y + sr_y;
00611               x2 = net->stop_x + sr_x;
00612               y2 = net->stop_y + sr_y;
00613            
00614               /* translate circular x,y data as well */
00615               if (net->cirseg) {
00616                      cp_x = net->cirseg->cp_x + sr_x;
00617                      cp_y = net->cirseg->cp_y + sr_y;
00618               }
00619               
00620               /* render any labels attached to this net */
00621               /* NOTE: this is currently only used on PNP files, so we may
00622                  make some assumptions here... */
00623               if (net->label) {
00624                      cairo_set_font_size (cairoTarget, 0.05);
00625                      cairo_save (cairoTarget);
00626                      
00627                      cairo_move_to (cairoTarget, x1, y1);
00628                      cairo_scale (cairoTarget, 1, -1);
00629                      cairo_show_text (cairoTarget, net->label->str);
00630                      cairo_restore (cairoTarget);
00631               }
00632               /*
00633               * Polygon Area Fill routines
00634               */
00635               switch (net->interpolation) {
00636                      case GERBV_INTERPOLATION_PAREA_START :
00637                             draw_render_polygon_object (net, cairoTarget, sr_x, sr_y, image,
00638                                    drawMode, selectionInfo);
00639                             continue;
00640                      case GERBV_INTERPOLATION_DELETED:
00641                             continue;
00642                      default :
00643                             break;
00644               }
00645        
00646               /*
00647                * If aperture state is off we allow use of undefined apertures.
00648                * This happens when gerber files starts, but hasn't decided on 
00649                * which aperture to use.
00650                */
00651               if (image->aperture[net->aperture] == NULL) {
00652                 /* Commenting this out since it gets emitted every time you click on the screen 
00653                 if (net->aperture_state != GERBV_APERTURE_STATE_OFF)
00654                   GERB_MESSAGE("Aperture D%d is not defined\n", net->aperture);
00655                 */
00656                 continue;
00657               }
00658               switch (net->aperture_state) {
00659                      case GERBV_APERTURE_STATE_ON :
00660                             /* if the aperture width is truly 0, then render as a 1 pixel width
00661                                line.  0 diameter apertures are used by some programs to draw labels,
00662                                etc, and they are rendered by other programs as 1 pixel wide */
00663                             /* NOTE: also, make sure all lines are at least 1 pixel wide, so they
00664                                always show up at low zoom levels */
00665                             if (image->aperture[net->aperture]->parameter[0] > pixelWidth)
00666                                    cairo_set_line_width (cairoTarget, image->aperture[net->aperture]->parameter[0]);
00667                             else
00668                                    cairo_set_line_width (cairoTarget, pixelWidth);
00669                             switch (net->interpolation) {
00670                                    case GERBV_INTERPOLATION_x10 :
00671                                    case GERBV_INTERPOLATION_LINEARx01 :
00672                                    case GERBV_INTERPOLATION_LINEARx001 :
00673                                    case GERBV_INTERPOLATION_LINEARx1 :
00674                                           cairo_set_line_cap (cairoTarget, CAIRO_LINE_CAP_ROUND);
00675                                           switch (image->aperture[net->aperture]->type) {
00676                                                  case GERBV_APTYPE_CIRCLE :
00677                                                         cairo_move_to (cairoTarget, x1,y1);
00678                                                         cairo_line_to (cairoTarget, x2,y2);
00679                                                         draw_stroke (cairoTarget, drawMode, selectionInfo, image, net);
00680                                                         break;
00681                                                  case GERBV_APTYPE_RECTANGLE :                           
00682                                                         dx = (image->aperture[net->aperture]->parameter[0]/ 2);
00683                                                         dy = (image->aperture[net->aperture]->parameter[1]/ 2);
00684                                                         if(x1 > x2)
00685                                                                dx = -dx;
00686                                                         if(y1 > y2)
00687                                                                dy = -dy;
00688                                                         cairo_new_path(cairoTarget);
00689                                                         cairo_move_to (cairoTarget, x1 - dx, y1 - dy);
00690                                                         cairo_line_to (cairoTarget, x1 - dx, y1 + dy);
00691                                                         cairo_line_to (cairoTarget, x2 - dx, y2 + dy);
00692                                                         cairo_line_to (cairoTarget, x2 + dx, y2 + dy);
00693                                                         cairo_line_to (cairoTarget, x2 + dx, y2 - dy);
00694                                                         cairo_line_to (cairoTarget, x1 + dx, y1 - dy);
00695                                                         draw_fill (cairoTarget, drawMode, selectionInfo, image, net);
00696                                                         break;
00697                                                  /* for now, just render ovals or polygons like a circle */
00698                                                  case GERBV_APTYPE_OVAL :
00699                                                  case GERBV_APTYPE_POLYGON :
00700                                                         cairo_move_to (cairoTarget, x1,y1);
00701                                                         cairo_line_to (cairoTarget, x2,y2);
00702                                                         draw_stroke (cairoTarget, drawMode, selectionInfo, image, net);
00703                                                         break;
00704                                                  /* macros can only be flashed, so ignore any that might be here */
00705                                                  default :
00706                                                         break;
00707                                           }
00708                                           break;
00709                                    case GERBV_INTERPOLATION_CW_CIRCULAR :
00710                                    case GERBV_INTERPOLATION_CCW_CIRCULAR :
00711                                           /* cairo doesn't have a function to draw oval arcs, so we must
00712                                            * draw an arc and stretch it by scaling different x and y values
00713                                            */
00714                                           cairo_new_path(cairoTarget);
00715                                           if (image->aperture[net->aperture]->type == GERBV_APTYPE_RECTANGLE) {
00716                                                  cairo_set_line_cap (cairoTarget, CAIRO_LINE_CAP_SQUARE);
00717                                           }
00718                                           else {
00719                                                  cairo_set_line_cap (cairoTarget, CAIRO_LINE_CAP_ROUND);
00720                                           }
00721                                           cairo_save (cairoTarget);
00722                                           cairo_translate(cairoTarget, cp_x, cp_y);
00723                                           cairo_scale (cairoTarget, net->cirseg->width, net->cirseg->height);
00724                                           if (net->cirseg->angle2 > net->cirseg->angle1) {
00725                                                  cairo_arc (cairoTarget, 0.0, 0.0, 0.5, net->cirseg->angle1 * M_PI/180,
00726                                                         net->cirseg->angle2 * M_PI/180);
00727                                           }
00728                                           else {
00729                                                  cairo_arc_negative (cairoTarget, 0.0, 0.0, 0.5, net->cirseg->angle1 * M_PI/180,
00730                                                         net->cirseg->angle2 * M_PI/180);
00731                                           }
00732                                           cairo_restore (cairoTarget);
00733                                           draw_stroke (cairoTarget, drawMode, selectionInfo, image, net);
00734                                           break;
00735                                    default :
00736                                           break;
00737                             }
00738                             break;
00739                      case GERBV_APERTURE_STATE_OFF :
00740                             break;
00741                      case GERBV_APERTURE_STATE_FLASH :
00742                             p1 = image->aperture[net->aperture]->parameter[0];
00743                             p2 = image->aperture[net->aperture]->parameter[1];
00744                             p3 = image->aperture[net->aperture]->parameter[2];
00745                             p4 = image->aperture[net->aperture]->parameter[3];
00746                             p5 = image->aperture[net->aperture]->parameter[4];
00747 
00748                             cairo_save (cairoTarget);
00749                             cairo_translate (cairoTarget, x2, y2);
00750 
00751                             switch (image->aperture[net->aperture]->type) {
00752                                    case GERBV_APTYPE_CIRCLE :
00753                                           gerbv_draw_circle(cairoTarget, p1);
00754                                           gerbv_draw_aperature_hole (cairoTarget, p2, p3);
00755                                           break;
00756                                    case GERBV_APTYPE_RECTANGLE :
00757                                           gerbv_draw_rectangle(cairoTarget, p1, p2);
00758                                           gerbv_draw_aperature_hole (cairoTarget, p3, p4);
00759                                           break;
00760                                    case GERBV_APTYPE_OVAL :
00761                                           gerbv_draw_oblong(cairoTarget, p1, p2);
00762                                           gerbv_draw_aperature_hole (cairoTarget, p3, p4);
00763                                           break;
00764                                    case GERBV_APTYPE_POLYGON :
00765                                           gerbv_draw_polygon(cairoTarget, p1, p2, p3);
00766                                           gerbv_draw_aperature_hole (cairoTarget, p4, p5);
00767                                           break;
00768                                    case GERBV_APTYPE_MACRO :
00769                                           gerbv_draw_amacro(cairoTarget, drawOperatorClear, drawOperatorDark,
00770                                                           image->aperture[net->aperture]->simplified,
00771                                                           (int) image->aperture[net->aperture]->parameter[0],
00772                                                           drawMode, selectionInfo, image, net);
00773                                           break;   
00774                                    default :
00775                                           GERB_MESSAGE("Unknown aperture type\n");
00776                                           return 0;
00777                             }
00778                             /* and finally fill the path */
00779                             draw_fill (cairoTarget, drawMode, selectionInfo, image, net);
00780                             cairo_restore (cairoTarget);
00781                             break;
00782                      default:
00783                             GERB_MESSAGE("Unknown aperture state\n");
00784                             return 0;
00785               }
00786            }
00787        }
00788     }
00789 
00790     /* restore the initial two state saves (one for layer, one for netstate)*/
00791     cairo_restore (cairoTarget);
00792     cairo_restore (cairoTarget);
00793 
00794     return 1;
00795 }
00796 
00797 

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