draw-gdk.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-gdk.h"
00044 
00045 #undef round
00046 #define round(x) ceil((double)(x))
00047 
00048 #define dprintf if(DEBUG) printf
00049 
00050 /*
00051  * If you want to rotate a
00052  * column vector v by t degrees using matrix M, use
00053  *
00054  *   M = {{cos t, -sin t}, {sin t, cos t}} in M*v.
00055  *
00056  * From comp.graphics.algorithms Frequently Asked Questions
00057  *
00058  * Due reverse defintion of X-axis in GTK you have to negate
00059  * angels.
00060  *
00061  */
00062 static GdkPoint 
00063 rotate_point(GdkPoint point, int angle)
00064 {
00065     double sint, cost;
00066     GdkPoint returned;
00067     
00068     if (angle == 0)
00069        return point;
00070 
00071     sint = sin(-(double)angle * M_PI / 180.0);
00072     cost = cos(-(double)angle * M_PI / 180.0);
00073     
00074     returned.x = (int)round(cost * (double)point.x - sint * (double)point.y);
00075     returned.y = (int)round(sint * (double)point.x + cost * (double)point.y);
00076     
00077     return returned;
00078 }
00079 
00080 
00081 /*
00082  * Aperture macro primitive 1 (Circle)
00083  */
00084 static void
00085 gerbv_gdk_draw_prim1(GdkPixmap *pixmap, GdkGC *gc, double *p, 
00086                    double scale, gint x, gint y)
00087 {
00088     const int exposure_idx = 0;
00089     const int diameter_idx = 1;
00090     const int x_offset_idx = 2;
00091     const int y_offset_idx = 3;
00092     const gint full_circle = 23360;
00093     GdkGC *local_gc = gdk_gc_new(pixmap);
00094     gint dia    = round(fabs(p[diameter_idx] * scale));
00095     gint real_x = x - dia / 2;
00096     gint real_y = y - dia / 2;
00097     GdkColor color;
00098 
00099     gdk_gc_copy(local_gc, gc);
00100 
00101     real_x += (int)(p[x_offset_idx] * (double)scale);
00102     real_y -= (int)(p[y_offset_idx] * (double)scale);
00103 
00104     /* Exposure */
00105     if (p[exposure_idx] == 0.0) {
00106        color.pixel = 0;
00107        gdk_gc_set_foreground(local_gc, &color);
00108     }
00109 
00110     gdk_gc_set_line_attributes(local_gc, 
00111                             1, /* outline always 1 pixels */
00112                             GDK_LINE_SOLID, 
00113                             GDK_CAP_BUTT, 
00114                             GDK_JOIN_MITER);
00115 
00116     /* 
00117      * A filled circle 
00118      */
00119     gdk_draw_arc(pixmap, local_gc, 1, real_x, real_y, dia, dia, 
00120                0, full_circle);
00121 
00122     gdk_gc_unref(local_gc);
00123 
00124     return;
00125 } /* gerbv_gdk_draw_prim1 */
00126 
00127 
00128 /*
00129  * Aperture macro primitive 4 (outline)
00130  * - Start point is not included in number of points.
00131  * - Outline is 1 pixel.
00132  */
00133 static void
00134 gerbv_gdk_draw_prim4(GdkPixmap *pixmap, GdkGC *gc, double *p, 
00135                    double scale, gint x, gint y)
00136 {
00137     const int exposure_idx = 0;
00138     const int nuf_points_idx = 1;
00139     const int first_x_idx = 2;
00140     const int first_y_idx = 3;
00141     const int rotext_idx = 4;
00142     GdkGC *local_gc = gdk_gc_new(pixmap);
00143     int nuf_points, point;
00144     double rotation;
00145     GdkPoint *points;
00146     GdkColor color;
00147 
00148     /* Include start point */
00149     nuf_points = (int)p[nuf_points_idx] + 1;
00150     points = (GdkPoint *)g_malloc(sizeof(GdkPoint) * nuf_points);
00151     if (!points) {
00152        g_free(points);
00153        return;
00154     }
00155 
00156     rotation = p[(nuf_points - 1) * 2 + rotext_idx];
00157     for (point = 0; point < nuf_points; point++) {
00158        points[point].x = (int)round(scale * p[point * 2 + first_x_idx]);
00159        points[point].y = -(int)round(scale * p[point * 2 + first_y_idx]);
00160        if (rotation != 0.0)
00161            points[point] = rotate_point(points[point], rotation);
00162        points[point].x += x;
00163        points[point].y += y;
00164     }
00165 
00166     gdk_gc_copy(local_gc, gc);
00167 
00168     /* Exposure */
00169     if (p[exposure_idx] == 0.0) {
00170        color.pixel = 0;
00171        gdk_gc_set_foreground(local_gc, &color);
00172     }
00173 
00174     gdk_gc_set_line_attributes(local_gc, 
00175                             1, /* outline always 1 pixels */
00176                             GDK_LINE_SOLID, 
00177                             GDK_CAP_BUTT, 
00178                             GDK_JOIN_MITER);
00179     gdk_draw_polygon(pixmap, local_gc, 1, points, nuf_points);
00180 
00181     g_free(points);
00182 
00183     gdk_gc_unref(local_gc);
00184 
00185     return;
00186 } /* gerbv_gdk_draw_prim4 */
00187 
00188 
00189 /*
00190  * Aperture macro primitive 5 (polygon)
00191  */
00192 static void
00193 gerbv_gdk_draw_prim5(GdkPixmap *pixmap, GdkGC *gc, double *p, 
00194                    double scale, gint x, gint y)
00195 {
00196     const int exposure_idx = 0;
00197     const int nuf_vertices_idx = 1;
00198     const int center_x_idx = 2;
00199     const int center_y_idx = 3;
00200     const int diameter_idx = 4;
00201     const int rotation_idx = 5;
00202     int nuf_vertices, i;
00203     double vertex, tick, rotation, radius;
00204     GdkPoint *points;
00205     GdkGC *local_gc = gdk_gc_new(pixmap);
00206     GdkColor color;
00207 
00208     nuf_vertices = (int)p[nuf_vertices_idx];
00209     points = (GdkPoint *)g_malloc(sizeof(GdkPoint) * nuf_vertices);
00210     if (!points) {
00211        g_free(points);
00212        return;
00213     }
00214 
00215     gdk_gc_copy(local_gc, gc);
00216 
00217     /* Exposure */
00218     if (p[exposure_idx] == 0.0) {
00219        color.pixel = 0;
00220        gdk_gc_set_foreground(local_gc, &color);
00221     }
00222 
00223     tick = 2 * M_PI / (double)nuf_vertices;
00224     rotation = -p[rotation_idx] * M_PI / 180.0;
00225     radius = p[diameter_idx] / 2.0;
00226     for (i = 0; i < nuf_vertices; i++) {
00227        vertex =  tick * (double)i + rotation;
00228        points[i].x = (int)round(scale * radius * cos(vertex)) + x +
00229            p[center_x_idx];
00230        points[i].y = (int)round(scale * radius * sin(vertex)) + y +
00231            p[center_y_idx];
00232     }
00233 
00234     gdk_draw_polygon(pixmap, local_gc, 1, points, nuf_vertices);
00235 
00236     gdk_gc_unref(local_gc);
00237 
00238     g_free(points);
00239     return;
00240 } /* gerbv_gdk_draw_prim5 */
00241 
00242 
00243 /*
00244  * Doesn't handle and explicit x,y yet
00245  * Questions:
00246  *  - is "gap" distance between edges of circles or distance between
00247  *    center of line of circle?
00248  */
00249 static void
00250 gerbv_gdk_draw_prim6(GdkPixmap *pixmap, GdkGC *gc, double *p, 
00251                double scale, gint x, gint y)
00252 {
00253     const int outside_dia_idx = 2;
00254     const int ci_thickness_idx = 3;
00255     const int gap_idx = 4;
00256     const int nuf_circles_idx = 5;
00257     const int ch_thickness_idx = 6;
00258     const int ch_length_idx = 7;
00259     const int rotation_idx = 8;
00260     GdkGC *local_gc = gdk_gc_new(pixmap);
00261     double real_dia;
00262     double real_gap;
00263     int circle;
00264     GdkPoint crosshair[4];
00265     int point;
00266 
00267     gdk_gc_copy(local_gc, gc);
00268     gdk_gc_set_line_attributes(local_gc, 
00269                             (int)round(scale * p[ci_thickness_idx]),
00270                             GDK_LINE_SOLID, 
00271                             GDK_CAP_BUTT, 
00272                             GDK_JOIN_MITER);
00273 
00274     real_dia = p[outside_dia_idx] -  p[ci_thickness_idx] / 2.0;
00275     real_gap = p[gap_idx] + p[ci_thickness_idx];
00276 
00277     for (circle = 0; circle != (int)p[nuf_circles_idx];  circle++) {
00278        /* 
00279         * Non filled circle 
00280         */
00281        const gint full_circle = 23360;
00282        gint dia = (real_dia - real_gap * circle) * scale;
00283        gdk_draw_arc(pixmap, local_gc, 0, x - dia / 2, y - dia / 2, 
00284                    dia, dia, 0, full_circle);
00285                        
00286     }
00287 
00288     /*
00289      * Cross Hair 
00290      */
00291     memset(crosshair, 0, sizeof(GdkPoint) * 4);
00292     crosshair[0].x = (int)((p[ch_length_idx] / 2.0) * scale);
00293     /*crosshair[0].y = 0;*/
00294     crosshair[1].x = -crosshair[0].x;
00295     /*crosshair[1].y = 0;*/
00296     /*crosshair[2].x = 0;*/
00297     crosshair[2].y = crosshair[0].x;
00298     /*crosshair[3].x = 0;*/
00299     crosshair[3].y = -crosshair[0].x;
00300 
00301     gdk_gc_set_line_attributes(local_gc, 
00302                             (int)round(scale * p[ch_thickness_idx]),
00303                             GDK_LINE_SOLID, 
00304                             GDK_CAP_BUTT, 
00305                             GDK_JOIN_MITER);
00306 
00307     for (point = 0; point < 4; point++) {
00308        crosshair[point] = rotate_point(crosshair[point], 
00309                                    p[rotation_idx]);
00310        crosshair[point].x += x;
00311        crosshair[point].y += y;
00312     }
00313     gdk_draw_line(pixmap, local_gc, 
00314                 crosshair[0].x, crosshair[0].y, 
00315                 crosshair[1].x, crosshair[1].y);
00316     gdk_draw_line(pixmap, local_gc, 
00317                 crosshair[2].x, crosshair[2].y, 
00318                 crosshair[3].x, crosshair[3].y);
00319 
00320     gdk_gc_unref(local_gc);
00321 
00322     return;
00323 } /* gerbv_gdk_draw_prim6 */
00324 
00325 
00326 static void
00327 gerbv_gdk_draw_prim7(GdkPixmap *pixmap, GdkGC *gc, double *p, 
00328                double scale, gint x, gint y)
00329 {
00330     const int outside_dia_idx = 2;
00331     const int inside_dia_idx = 3;
00332     const int ch_thickness_idx = 4;
00333     const int rotation_idx = 5;
00334     const gint full_circle = 23360;
00335     GdkGCValues gc_val;
00336     int diameter, i;
00337     GdkGC *local_gc = gdk_gc_new(pixmap);
00338     GdkPoint point[4];
00339     double ci_thickness = (p[outside_dia_idx] - 
00340                         p[inside_dia_idx]) / 2.0;
00341 
00342     gdk_gc_copy(local_gc, gc);
00343     gdk_gc_set_line_attributes(local_gc, 
00344                             (int)round(scale * ci_thickness),
00345                             GDK_LINE_SOLID, 
00346                             GDK_CAP_BUTT, 
00347                             GDK_JOIN_MITER);
00348 
00349     /* 
00350      * Non filled circle 
00351      */
00352     diameter = (p[inside_dia_idx] + ci_thickness) * scale;
00353     gdk_draw_arc(pixmap, local_gc, 0, x - diameter / 2, y - diameter / 2, 
00354                diameter, diameter, 0, full_circle);
00355 
00356     /*
00357      * Cross hair
00358      */ 
00359     /* Calculate the end points of the crosshair */    
00360     /* GDK doesn't always remove all of the circle (round of error probably)
00361        I extend the crosshair line with 2 (one pixel in each end) to make 
00362        sure all of the circle is removed with the crosshair */
00363     for (i = 0; i < 4; i++) {
00364        point[i].x = round((p[outside_dia_idx] / 2.0) * scale) + 2;
00365        point[i].y = 0;
00366        point[i] = rotate_point(point[i], p[rotation_idx] + 90 * i);
00367        point[i].x += x;
00368        point[i].y += y;
00369     }
00370 
00371     gdk_gc_set_line_attributes(local_gc, 
00372                             (int)round(scale * p[ch_thickness_idx]),
00373                             GDK_LINE_SOLID, 
00374                             GDK_CAP_BUTT, 
00375                             GDK_JOIN_MITER);
00376 
00377     /* The cross hair should "cut out" parts of the circle, hence inverse */
00378     gdk_gc_get_values(local_gc, &gc_val);
00379     if (gc_val.foreground.pixel == 1)
00380        gc_val.foreground.pixel = 0;
00381     else
00382        gc_val.foreground.pixel = 1;
00383     gdk_gc_set_foreground(local_gc, &(gc_val.foreground));
00384 
00385     /* Draw the actual cross */
00386     gdk_draw_line(pixmap, local_gc, 
00387                 point[0].x, point[0].y, point[2].x, point[2].y);
00388     gdk_draw_line(pixmap, local_gc,
00389                 point[1].x, point[1].y, point[3].x, point[3].y);
00390 
00391     gdk_gc_unref(local_gc);
00392 
00393     return;
00394 } /* gerbv_gdk_draw_prim7 */
00395 
00396 
00397 /*
00398  * Doesn't handle and explicit x,y yet
00399  */
00400 static void
00401 gerbv_gdk_draw_prim20(GdkPixmap *pixmap, GdkGC *gc, double *p, 
00402                 double scale, gint x, gint y)
00403 {
00404     const int exposure_idx = 0;
00405     const int linewidth_idx = 1;
00406     const int start_x_idx = 2;
00407     const int start_y_idx = 3;
00408     const int end_x_idx = 4;
00409     const int end_y_idx = 5;
00410     const int rotation_idx = 6;
00411     const int nuf_points = 2;
00412     GdkGC *local_gc = gdk_gc_new(pixmap);
00413     GdkPoint points[nuf_points];
00414     GdkColor color;
00415     int i;
00416 
00417     gdk_gc_copy(local_gc, gc);
00418 
00419     /* Exposure */
00420     if (p[exposure_idx] == 0.0) {
00421        color.pixel = 0;
00422        gdk_gc_set_foreground(local_gc, &color);
00423     }
00424 
00425     gdk_gc_set_line_attributes(local_gc, 
00426                             (int)round(scale * p[linewidth_idx]),
00427                             GDK_LINE_SOLID, 
00428                             GDK_CAP_BUTT, 
00429                             GDK_JOIN_MITER);
00430 
00431     points[0].x = (p[start_x_idx] * scale);
00432     points[0].y = (p[start_y_idx] * scale);
00433     points[1].x = (p[end_x_idx] * scale);
00434     points[1].y = (p[end_y_idx] * scale);
00435 
00436     for (i = 0; i < nuf_points; i++) {
00437        points[i] = rotate_point(points[i], -p[rotation_idx]);
00438        points[i].x = x + points[i].x;
00439        points[i].y = y - points[i].y;
00440     }
00441 
00442     gdk_draw_line(pixmap, local_gc, 
00443                 points[0].x, points[0].y, 
00444                 points[1].x, points[1].y);
00445     
00446     gdk_gc_unref(local_gc);
00447 
00448     return;
00449 } /* gerbv_gdk_draw_prim20 */
00450 
00451 
00452 static void
00453 gerbv_gdk_draw_prim21(GdkPixmap *pixmap, GdkGC *gc, double *p, 
00454                 double scale, gint x, gint y)
00455 {
00456     const int exposure_idx = 0;
00457     const int width_idx = 1;
00458     const int height_idx = 2;
00459     const int exp_x_idx = 3;
00460     const int exp_y_idx = 4;
00461     const int rotation_idx = 5;
00462     const int nuf_points = 4;
00463     GdkPoint points[nuf_points];
00464     GdkColor color;
00465     GdkGC *local_gc = gdk_gc_new(pixmap);
00466     int half_width, half_height;
00467     int i;
00468 
00469     half_width = (int)round(p[width_idx] * scale / 2.0);
00470     half_height =(int)round(p[height_idx] * scale / 2.0);
00471 
00472     points[0].x = half_width;
00473     points[0].y = half_height;
00474 
00475     points[1].x = half_width;
00476     points[1].y = -half_height;
00477 
00478     points[2].x = -half_width;
00479     points[2].y = -half_height;
00480 
00481     points[3].x = -half_width;
00482     points[3].y = half_height;
00483 
00484     for (i = 0; i < nuf_points; i++) {
00485        points[i] = rotate_point(points[i], p[rotation_idx]);
00486        points[i].x += (x + (int)(p[exp_x_idx] * scale));
00487        points[i].y += (y - (int)(p[exp_y_idx] * scale));
00488     }
00489 
00490     gdk_gc_copy(local_gc, gc);
00491 
00492     /* Exposure */
00493     if (p[exposure_idx] == 0.0) {
00494        color.pixel = 0;
00495        gdk_gc_set_foreground(local_gc, &color);
00496     }
00497 
00498     gdk_draw_polygon(pixmap, local_gc, 1, points, nuf_points);
00499 
00500     gdk_gc_unref(local_gc);
00501 
00502     return;
00503 } /* gerbv_gdk_draw_prim21 */
00504 
00505 
00506 /*
00507  * Doesn't handle explicit x,y yet
00508  */
00509 static void
00510 gerbv_gdk_draw_prim22(GdkPixmap *pixmap, GdkGC *gc, double *p, 
00511                 double scale, gint x, gint y)
00512 {
00513     const int exposure_idx = 0;
00514     const int width_idx = 1;
00515     const int height_idx = 2;
00516     const int x_lower_left_idx = 3;
00517     const int y_lower_left_idx = 4;
00518     const int rotation_idx = 5;
00519     const int nuf_points = 4;
00520     GdkPoint points[nuf_points];
00521     GdkGC *local_gc = gdk_gc_new(pixmap);
00522     GdkColor color;
00523     int i;
00524 
00525     points[0].x = (int)round(p[x_lower_left_idx] * scale);
00526     points[0].y = (int)round(p[y_lower_left_idx] * scale);
00527 
00528     points[1].x = (int)round((p[x_lower_left_idx] + p[width_idx])
00529                           * scale);
00530     points[1].y = (int)round(p[y_lower_left_idx] * scale);
00531 
00532     points[2].x = (int)round((p[x_lower_left_idx]  + p[width_idx])
00533                           * scale);
00534     points[2].y = (int)round((p[y_lower_left_idx]  - p[height_idx])
00535                           * scale);
00536 
00537     points[3].x = (int)round(p[x_lower_left_idx] * scale);
00538     points[3].y = (int)round((p[y_lower_left_idx] - p[height_idx])
00539                           * scale);
00540 
00541     for (i = 0; i < nuf_points; i++) {
00542        points[i] = rotate_point(points[i], p[rotation_idx]);
00543        points[i].x += x;
00544        points[i].y += y;
00545     }
00546     
00547     gdk_gc_copy(local_gc, gc);
00548 
00549     /* Exposure */
00550     if (p[exposure_idx] == 0.0) {
00551        color.pixel = 0;
00552        gdk_gc_set_foreground(local_gc, &color);
00553     }
00554 
00555     gdk_draw_polygon(pixmap, local_gc, 1, points, nuf_points);
00556 
00557     gdk_gc_unref(local_gc);
00558 
00559     return;
00560 } /* gerbv_gdk_draw_prim22 */
00561 
00562 
00563 static void 
00564 gerbv_gdk_draw_amacro(GdkPixmap *pixmap, GdkGC *gc, 
00565                     gerbv_simplified_amacro_t *s, double scale, 
00566                     gint x, gint y)
00567 {
00568     gerbv_simplified_amacro_t *ls = s;
00569 
00570     dprintf("Drawing simplified aperture macros:\n");
00571     while (ls != NULL) {
00572 
00573        switch (ls->type) {
00574        case GERBV_APTYPE_MACRO_CIRCLE:
00575            gerbv_gdk_draw_prim1(pixmap, gc, ls->parameter, scale, x, y);
00576            dprintf("  Circle\n");
00577            break;
00578        case GERBV_APTYPE_MACRO_OUTLINE:
00579            gerbv_gdk_draw_prim4(pixmap, gc, ls->parameter, scale, x, y);
00580            dprintf("  Outline\n");
00581            break;
00582        case GERBV_APTYPE_MACRO_POLYGON:
00583            gerbv_gdk_draw_prim5(pixmap, gc, ls->parameter, scale, x, y);
00584            dprintf("  Polygon\n");
00585            break;
00586        case GERBV_APTYPE_MACRO_MOIRE:
00587            gerbv_gdk_draw_prim6(pixmap, gc, ls->parameter, scale, x, y);
00588            dprintf("  Moiré\n");
00589            break;
00590        case GERBV_APTYPE_MACRO_THERMAL:
00591            gerbv_gdk_draw_prim7(pixmap, gc, ls->parameter, scale, x, y);
00592            dprintf("  Thermal\n");
00593            break;
00594        case GERBV_APTYPE_MACRO_LINE20:
00595            gerbv_gdk_draw_prim20(pixmap, gc, ls->parameter, scale, x, y);
00596            dprintf("  Line 20\n");
00597            break;
00598        case GERBV_APTYPE_MACRO_LINE21:
00599            gerbv_gdk_draw_prim21(pixmap, gc, ls->parameter, scale, x, y);
00600            dprintf("  Line 21\n");
00601            break;
00602        case GERBV_APTYPE_MACRO_LINE22:
00603            gerbv_gdk_draw_prim22(pixmap, gc, ls->parameter, scale, x, y);
00604            dprintf("  Line 22\n");
00605            break;
00606        default:
00607            GERB_FATAL_ERROR("Unknown simplified aperture macro");
00608        }
00609 
00610        ls = ls->next;
00611     }
00612 
00613 } /* gerbv_gdk_draw_amacro */
00614 
00615 
00616 /*
00617  * Draws a circle _centered_ at x,y with diameter dia
00618  */
00619 static void 
00620 gerbv_gdk_draw_circle(GdkPixmap *pixmap, GdkGC *gc, 
00621                 gint filled, gint x, gint y, gint dia)
00622 {
00623     static const gint full_circle = 23360;
00624     gint real_x = x - dia / 2;
00625     gint real_y = y - dia / 2;
00626     
00627     gdk_draw_arc(pixmap, gc, filled, real_x, real_y, dia, dia, 0, full_circle);
00628     
00629     return;
00630 } /* gerbv_gdk_draw_circle */
00631 
00632 
00633 /*
00634  * Draws a rectangle _centered_ at x,y with sides x_side, y_side
00635  */
00636 static void 
00637 gerbv_gdk_draw_rectangle(GdkPixmap *pixmap, GdkGC *gc, 
00638                    gint filled, gint x, gint y, gint x_side, gint y_side)
00639 {
00640     
00641     gint real_x = x - x_side / 2;
00642     gint real_y = y - y_side / 2;
00643     
00644     gdk_draw_rectangle(pixmap, gc, filled, real_x, real_y, x_side, y_side);
00645     
00646     return;
00647 } /* gerbv_gdk_draw_rectangle */
00648 
00649 
00650 /*
00651  * Draws an oval _centered_ at x,y with x axis x_axis and y axis y_axis
00652  */ 
00653 static void
00654 gerbv_gdk_draw_oval(GdkPixmap *pixmap, GdkGC *gc, 
00655               gint filled, gint x, gint y, gint x_axis, gint y_axis)
00656 {
00657     gint delta = 0;
00658     GdkGC *local_gc = gdk_gc_new(pixmap);
00659 
00660     gdk_gc_copy(local_gc, gc);
00661 
00662     if (x_axis > y_axis) {
00663        /* Draw in x axis */
00664        delta = x_axis / 2 - y_axis / 2;
00665        gdk_gc_set_line_attributes(local_gc, y_axis, 
00666                                GDK_LINE_SOLID, 
00667                                GDK_CAP_ROUND, 
00668                                GDK_JOIN_MITER);
00669        gdk_draw_line(pixmap, local_gc, x - delta, y, x + delta, y);
00670     } else {
00671        /* Draw in y axis */
00672        delta = y_axis / 2 - x_axis / 2;
00673        gdk_gc_set_line_attributes(local_gc, x_axis, 
00674                                GDK_LINE_SOLID, 
00675                                GDK_CAP_ROUND, 
00676                                GDK_JOIN_MITER);
00677        gdk_draw_line(pixmap, local_gc, x, y - delta, x, y + delta);
00678     }
00679 
00680     gdk_gc_unref(local_gc);
00681 
00682     return;
00683 } /* gerbv_gdk_draw_oval */
00684 
00685 
00686 /*
00687  * Draws an arc 
00688  * Draws an arc _centered_ at x,y
00689  * direction:  0 counterclockwise, 1 clockwise
00690  */
00691 static void
00692 gerbv_gdk_draw_arc(GdkPixmap *pixmap, GdkGC *gc,
00693               int x, int y,
00694               int width, int height,
00695               double angle1, double angle2)
00696 {
00697     gint real_x = x - width / 2;
00698     gint real_y = y - height / 2;
00699 
00700     gdk_draw_arc(pixmap, gc, FALSE, real_x, real_y, width, height, 
00701                (gint)(angle1 * 64.0), (gint)(angle2 - angle1) * 64.0);
00702     
00703     return;
00704 } /* gerbv_gdk_draw_arc */
00705 
00706 void
00707 draw_gdk_render_polygon_object (gerbv_net_t *oldNet, gerbv_image_t *image, double sr_x, double sr_y,
00708                      double unit_scale,  double trans_x, double trans_y, GdkGC *gc, GdkGC *pgc,
00709                      GdkPixmap **pixmap) {
00710        gerbv_net_t *currentNet;
00711        gint x1,x2,y1,y2,cp_x=0,cp_y=0,cir_width=0,cir_height=0;
00712        GdkPoint *points = NULL;
00713        int pointArraySize=0;
00714        int curr_point_idx = 0;
00715        int steps,i;
00716        double angleDiff;
00717 
00718        /* save the first net in the polygon as the "ID" net pointer
00719        in case we are saving this net to the selection array */
00720        curr_point_idx = 0;
00721        pointArraySize = 0;
00722 
00723        for (currentNet = oldNet->next; currentNet!=NULL; currentNet = currentNet->next){
00724               x1 = (int)round((image->info->offsetA + currentNet->start_x + sr_x) * unit_scale + trans_x);
00725               y1 = (int)round((-image->info->offsetB - currentNet->start_y - sr_y) * unit_scale + trans_y);
00726               x2 = (int)round((image->info->offsetA + currentNet->stop_x + sr_x) * unit_scale + trans_x);
00727               y2 = (int)round((-image->info->offsetB - currentNet->stop_y - sr_y) * unit_scale + trans_y);
00728 
00729               /* 
00730               * If circle segment, scale and translate that one too
00731               */
00732               if (currentNet->cirseg) {
00733                      cir_width = (int)round(currentNet->cirseg->width * unit_scale);
00734                      cir_height = (int)round(currentNet->cirseg->height * unit_scale);
00735                      cp_x = (int)round((image->info->offsetA + currentNet->cirseg->cp_x) *
00736                      unit_scale + trans_x);
00737                      cp_y = (int)round((image->info->offsetB - currentNet->cirseg->cp_y) *
00738                      unit_scale + trans_y);
00739               }
00740 
00741               switch (currentNet->interpolation) {
00742                      case GERBV_INTERPOLATION_x10 :
00743                      case GERBV_INTERPOLATION_LINEARx01 :
00744                      case GERBV_INTERPOLATION_LINEARx001 :
00745                      case GERBV_INTERPOLATION_LINEARx1 :
00746                             if (pointArraySize < (curr_point_idx + 1)) {
00747                                    points = (GdkPoint *)g_realloc(points,sizeof(GdkPoint) *  (curr_point_idx + 1));
00748                                    pointArraySize = (curr_point_idx + 1);
00749                             }
00750                             points[curr_point_idx].x = x2;
00751                             points[curr_point_idx].y = y2;
00752                             curr_point_idx++;
00753                             break;
00754                      case GERBV_INTERPOLATION_CW_CIRCULAR :
00755                      case GERBV_INTERPOLATION_CCW_CIRCULAR :
00756                             /* we need to chop up the arc into small lines for rendering
00757                             with GDK */
00758                             angleDiff = currentNet->cirseg->angle2 - currentNet->cirseg->angle1;
00759                             steps = (int) abs(angleDiff);
00760                             if (pointArraySize < (curr_point_idx + steps)) {
00761                                    points = (GdkPoint *)g_realloc(points,sizeof(GdkPoint) *  (curr_point_idx + steps));
00762                                    pointArraySize = (curr_point_idx + steps);
00763                             }
00764                             for (i=0; i<steps; i++){
00765                                    points[curr_point_idx].x = cp_x + cir_width / 2.0 * cos ((currentNet->cirseg->angle1 +
00766                                                                      (angleDiff * i) / steps)*M_PI/180);
00767                                    points[curr_point_idx].y = cp_y - cir_width / 2.0 * sin ((currentNet->cirseg->angle1 +
00768                                                                      (angleDiff * i) / steps)*M_PI/180);
00769                                    curr_point_idx++;
00770                             }
00771                             break;
00772                      case GERBV_INTERPOLATION_PAREA_END :
00773                             gdk_gc_copy(pgc, gc); 
00774                             gdk_gc_set_line_attributes(pgc, 1, 
00775                                    GDK_LINE_SOLID, 
00776                                    GDK_CAP_PROJECTING, 
00777                                    GDK_JOIN_MITER);
00778                             gdk_draw_polygon(*pixmap, pgc, 1, points, curr_point_idx);
00779                             g_free(points);
00780                             points = NULL;
00781                             return;
00782                      default:
00783                             break;
00784               }
00785        }
00786        return;
00787 }
00788 
00789 /*
00790  * Convert a gerber image to a GDK clip mask to be used when creating pixmap
00791  */
00792 int
00793 draw_gdk_image_to_pixmap(GdkPixmap **pixmap, gerbv_image_t *image, 
00794             double scale, double trans_x, double trans_y,
00795             gerbv_polarity_t polarity, gchar drawMode, gerbv_selection_info_t *selectionInfo)
00796 {
00797     GdkGC *gc = gdk_gc_new(*pixmap);
00798     GdkGC *pgc = gdk_gc_new(*pixmap);
00799     GdkGCValues gc_values;
00800     struct gerbv_net *net;
00801     gint x1, y1, x2, y2;
00802     int p1, p2, p3;
00803     int cir_width = 0, cir_height = 0;
00804     int cp_x = 0, cp_y = 0;
00805     double unit_scale;
00806     GdkColor transparent, opaque;
00807 
00808 
00809     if (image == NULL || image->netlist == NULL) {
00810        /*
00811         * Destroy GCs before exiting
00812         */
00813        gdk_gc_unref(gc);
00814        gdk_gc_unref(pgc);
00815        
00816        return 0;
00817     }
00818     
00819     /* Set up the two "colors" we have */
00820     opaque.pixel = 0; /* opaque will not let color through */
00821     transparent.pixel = 1; /* transparent will let color through */ 
00822 
00823     /*
00824      * Clear clipmask and set draw color depending image on image polarity
00825      */
00826     if (polarity == GERBV_POLARITY_NEGATIVE) {
00827        gdk_gc_set_foreground(gc, &transparent);
00828        gdk_draw_rectangle(*pixmap, gc, TRUE, 0, 0, -1, -1);
00829        gdk_gc_set_foreground(gc, &opaque);
00830     } else {
00831        gdk_gc_set_foreground(gc, &opaque);
00832        gdk_draw_rectangle(*pixmap, gc, TRUE, 0, 0, -1, -1);
00833        gdk_gc_set_foreground(gc, &transparent);
00834     }
00835 
00836     for (net = image->netlist->next ; net != NULL; net = gerbv_image_return_next_renderable_object(net)) {
00837       int repeat_X=1, repeat_Y=1;
00838       double repeat_dist_X=0.0, repeat_dist_Y=0.0;
00839       int repeat_i, repeat_j;
00840 
00841        /*
00842         * If step_and_repeat (%SR%) used, repeat the drawing;
00843         */
00844        repeat_X = net->layer->stepAndRepeat.X;
00845        repeat_Y = net->layer->stepAndRepeat.Y;
00846        repeat_dist_X = net->layer->stepAndRepeat.dist_X;
00847        repeat_dist_Y = net->layer->stepAndRepeat.dist_Y;
00848        
00849        if (drawMode == DRAW_SELECTIONS) {
00850               int i;
00851               gboolean foundNet = FALSE;
00852               
00853               for (i=0; i<selectionInfo->selectedNodeArray->len; i++){
00854                      gerbv_selection_item_t sItem = g_array_index (selectionInfo->selectedNodeArray,
00855                             gerbv_selection_item_t, i);
00856                      if (sItem.net == net)
00857                             foundNet = TRUE;
00858               }
00859               if (!foundNet)
00860                      continue;
00861        }
00862        
00863       for(repeat_i = 0; repeat_i < repeat_X; repeat_i++) {
00864        for(repeat_j = 0; repeat_j < repeat_Y; repeat_j++) {
00865          double sr_x = repeat_i * repeat_dist_X;
00866          double sr_y = repeat_j * repeat_dist_Y;
00867        
00868       unit_scale = scale;
00869 
00870        /*
00871         * Scale points with window scaling and translate them
00872         */
00873        x1 = (int)round((image->info->offsetA + net->start_x + sr_x) * unit_scale +
00874                      trans_x);
00875        y1 = (int)round((-image->info->offsetB - net->start_y - sr_y) * unit_scale +
00876                      trans_y);
00877        x2 = (int)round((image->info->offsetA + net->stop_x + sr_x) * unit_scale +
00878                      trans_x);
00879        y2 = (int)round((-image->info->offsetB - net->stop_y - sr_y) * unit_scale +
00880                      trans_y);
00881 
00882        /* 
00883         * If circle segment, scale and translate that one too
00884         */
00885        if (net->cirseg) {
00886            cir_width = (int)round(net->cirseg->width * unit_scale);
00887            cir_height = (int)round(net->cirseg->height * unit_scale);
00888            cp_x = (int)round((image->info->offsetA + net->cirseg->cp_x) *
00889                            unit_scale + trans_x);
00890            cp_y = (int)round((image->info->offsetB - net->cirseg->cp_y) *
00891                            unit_scale + trans_y);
00892        }
00893 
00894        /*
00895         * Set GdkFunction depending on if this (gerber) layer is inverted
00896         * and allow for the photoplot being negative.
00897         */
00898        gdk_gc_set_function(gc, GDK_COPY);
00899        if ((net->layer->polarity == GERBV_POLARITY_CLEAR) != (polarity == GERBV_POLARITY_NEGATIVE))
00900            gdk_gc_set_foreground(gc, &opaque);
00901        else
00902            gdk_gc_set_foreground(gc, &transparent);
00903 
00904        /*
00905         * Polygon Area Fill routines
00906         */
00907        switch (net->interpolation) {
00908        case GERBV_INTERPOLATION_PAREA_START :
00909            draw_gdk_render_polygon_object (net,image,sr_x,sr_y,unit_scale,trans_x,trans_y,gc,pgc,pixmap);
00910            continue;
00911        /* make sure we completely skip over any deleted nodes */
00912        case GERBV_INTERPOLATION_DELETED:
00913            continue;
00914        default :
00915            break;
00916        }
00917 
00918        /*
00919         * If aperture state is off we allow use of undefined apertures.
00920         * This happens when gerber files starts, but hasn't decided on 
00921         * which aperture to use.
00922         */
00923        if (image->aperture[net->aperture] == NULL) {
00924          /* Commenting this out since it gets emitted every time you click on the screen 
00925             if (net->aperture_state != GERBV_APERTURE_STATE_OFF)
00926             GERB_MESSAGE("Aperture D%d is not defined\n", net->aperture);
00927          */
00928            continue;
00929        }
00930        
00931        switch (net->aperture_state) {
00932        case GERBV_APERTURE_STATE_ON :
00933            p1 = (int)round(image->aperture[net->aperture]->parameter[0] * unit_scale);
00934            if (image->aperture[net->aperture]->type == GERBV_APTYPE_RECTANGLE)
00935               gdk_gc_set_line_attributes(gc, p1, 
00936                                       GDK_LINE_SOLID, 
00937                                       GDK_CAP_PROJECTING, 
00938                                       GDK_JOIN_MITER);
00939            else
00940               gdk_gc_set_line_attributes(gc, p1, 
00941                                       GDK_LINE_SOLID, 
00942                                       GDK_CAP_ROUND, 
00943                                       GDK_JOIN_MITER);
00944            
00945            switch (net->interpolation) {
00946            case GERBV_INTERPOLATION_x10 :
00947            case GERBV_INTERPOLATION_LINEARx01 :
00948            case GERBV_INTERPOLATION_LINEARx001 :
00949               GERB_MESSAGE("Linear != x1\n");
00950               gdk_gc_set_line_attributes(gc, p1, 
00951                                       GDK_LINE_ON_OFF_DASH, 
00952                                       GDK_CAP_ROUND, 
00953                                       GDK_JOIN_MITER);
00954               gdk_draw_line(*pixmap, gc, x1, y1, x2, y2);
00955               gdk_gc_set_line_attributes(gc, p1, 
00956                                       GDK_LINE_SOLID,
00957                                       GDK_CAP_ROUND, 
00958                                       GDK_JOIN_MITER);
00959               break;
00960            case GERBV_INTERPOLATION_LINEARx1 :
00961               if (image->aperture[net->aperture]->type != GERBV_APTYPE_RECTANGLE)
00962                   gdk_draw_line(*pixmap, gc, x1, y1, x2, y2);
00963               else {
00964                   gint dx, dy;
00965                   GdkPoint poly[6];
00966                   
00967                   dx = (int)round(image->aperture[net->aperture]->parameter[0]
00968                                 * unit_scale / 2);
00969                   dy = (int)round(image->aperture[net->aperture]->parameter[1]
00970                                 * unit_scale / 2);
00971                   if(x1 > x2) dx = -dx;
00972                   if(y1 > y2) dy = -dy;
00973                   poly[0].x = x1 - dx; poly[0].y = y1 - dy;
00974                   poly[1].x = x1 - dx; poly[1].y = y1 + dy;
00975                   poly[2].x = x2 - dx; poly[2].y = y2 + dy;
00976                   poly[3].x = x2 + dx; poly[3].y = y2 + dy;
00977                   poly[4].x = x2 + dx; poly[4].y = y2 - dy;
00978                   poly[5].x = x1 + dx; poly[5].y = y1 - dy;
00979                   gdk_draw_polygon(*pixmap, gc, 1, poly, 6);
00980               }
00981               break;
00982            case GERBV_INTERPOLATION_CW_CIRCULAR :
00983            case GERBV_INTERPOLATION_CCW_CIRCULAR :
00984               gerbv_gdk_draw_arc(*pixmap, gc, cp_x, cp_y, cir_width, cir_height, 
00985                                net->cirseg->angle1, net->cirseg->angle2);
00986               break;
00987            default :
00988               break;
00989            }
00990            break;
00991        case GERBV_APERTURE_STATE_OFF :
00992            break;
00993        case GERBV_APERTURE_STATE_FLASH :
00994            p1 = (int)round(image->aperture[net->aperture]->parameter[0] * unit_scale);
00995            p2 = (int)round(image->aperture[net->aperture]->parameter[1] * unit_scale);
00996            p3 = (int)round(image->aperture[net->aperture]->parameter[2] * unit_scale);
00997            
00998            switch (image->aperture[net->aperture]->type) {
00999            case GERBV_APTYPE_CIRCLE :
01000               gerbv_gdk_draw_circle(*pixmap, gc, TRUE, x2, y2, p1);
01001               /*
01002                * If circle has an inner diameter we must remove
01003                * that part of the circle to make a hole in it.
01004                * We should actually support square holes too,
01005                * but due to laziness I don't.
01006                */
01007               if (p2) {
01008                   //if (p3) GERB_COMPILE_WARNING("Should be a square hole in this aperture.\n");
01009                   gdk_gc_get_values(gc, &gc_values);
01010                   if (gc_values.foreground.pixel == opaque.pixel) {
01011                      gdk_gc_set_foreground(gc, &transparent);
01012                      gerbv_gdk_draw_circle(*pixmap, gc, TRUE, x2, y2, p2);
01013                      gdk_gc_set_foreground(gc, &opaque);
01014                   } else {
01015                      gdk_gc_set_foreground(gc, &opaque);
01016                      gerbv_gdk_draw_circle(*pixmap, gc, TRUE, x2, y2, p2);
01017                      gdk_gc_set_foreground(gc, &transparent);
01018                   }
01019               }
01020 
01021               break;
01022            case GERBV_APTYPE_RECTANGLE:
01023               gerbv_gdk_draw_rectangle(*pixmap, gc, TRUE, x2, y2, p1, p2);
01024               break;
01025            case GERBV_APTYPE_OVAL :
01026               gerbv_gdk_draw_oval(*pixmap, gc, TRUE, x2, y2, p1, p2);
01027               break;
01028            case GERBV_APTYPE_POLYGON :
01029               //GERB_COMPILE_WARNING("Very bad at drawing polygons.\n");
01030               gerbv_gdk_draw_circle(*pixmap, gc, TRUE, x2, y2, p1);
01031               break;
01032            case GERBV_APTYPE_MACRO :
01033               gerbv_gdk_draw_amacro(*pixmap, gc, 
01034                                   image->aperture[net->aperture]->simplified,
01035                                   unit_scale, x2, y2);
01036               break;
01037            default :
01038               GERB_MESSAGE("Unknown aperture type\n");
01039               return 0;
01040            }
01041            break;
01042        default :
01043            GERB_MESSAGE("Unknown aperture state\n");
01044            return 0;
01045        }
01046     }
01047       }
01048     }
01049     /*
01050      * Destroy GCs before exiting
01051      */
01052     gdk_gc_unref(gc);
01053     gdk_gc_unref(pgc);
01054     
01055     return 1;
01056 
01057 } /* image2pixmap */
01058 
01059 

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