00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00030 #ifdef HAVE_CONFIG_H
00031 # include <config.h>
00032 #endif
00033
00034 #ifdef HAVE_STDLIB_H
00035 #include <stdlib.h>
00036 #endif
00037
00038 #ifdef HAVE_STRING_H
00039 #include <string.h>
00040 #endif
00041
00042 #ifdef HAVE_UNISTD_H
00043 #include <unistd.h>
00044 #endif
00045
00046 #ifdef HAVE_LIBGEN_H
00047 #include <libgen.h>
00048 #endif
00049
00050 #include <math.h>
00051
00052 #include "gerbv.h"
00053 #include "main.h"
00054 #include "callbacks.h"
00055 #include "interface.h"
00056 #include "render.h"
00057
00058 #ifdef RENDER_USING_GDK
00059 #include "draw-gdk.h"
00060 #else
00061 #ifdef WIN32
00062 #include <cairo-win32.h>
00063 #else
00064 #include <cairo-xlib.h>
00065 #endif
00066 #include <cairo.h>
00067 #include "draw-gdk.h"
00068 #include "draw.h"
00069 #endif
00070
00071 #define dprintf if(DEBUG) printf
00072
00076 extern gerbv_screen_t screen;
00077
00078 extern gerbv_render_info_t screenRenderInfo;
00079
00080
00081
00082
00083
00084
00085
00086 void
00087 render_zoom_display (gint zoomType, gdouble scaleFactor, gdouble mouseX, gdouble mouseY) {
00088 double us_midx, us_midy;
00089 int half_w, half_h;
00090 gdouble mouseCoordinateX = 0.0;
00091 gdouble mouseCoordinateY = 0.0;
00092 double oldWidth, oldHeight;
00093
00094 half_w = screenRenderInfo.displayWidth / 2;
00095 half_h = screenRenderInfo.displayHeight / 2;
00096
00097 oldWidth = screenRenderInfo.displayWidth / screenRenderInfo.scaleFactorX;
00098 oldHeight = screenRenderInfo.displayHeight / screenRenderInfo.scaleFactorY;
00099 if (zoomType == ZOOM_IN_CMOUSE || zoomType == ZOOM_OUT_CMOUSE) {
00100
00101 mouseCoordinateX = mouseX / screenRenderInfo.scaleFactorX + screenRenderInfo.lowerLeftX;
00102 mouseCoordinateY = (screenRenderInfo.displayHeight - mouseY) /
00103 screenRenderInfo.scaleFactorY + screenRenderInfo.lowerLeftY;
00104 }
00105
00106 us_midx = screenRenderInfo.lowerLeftX + (screenRenderInfo.displayWidth / 2.0 )/
00107 screenRenderInfo.scaleFactorX;
00108 us_midy = screenRenderInfo.lowerLeftY + (screenRenderInfo.displayHeight / 2.0 )/
00109 screenRenderInfo.scaleFactorY;
00110
00111 switch(zoomType) {
00112 case ZOOM_IN :
00113 case ZOOM_IN_CMOUSE :
00114 screenRenderInfo.scaleFactorX += screenRenderInfo.scaleFactorX/3;
00115 screenRenderInfo.scaleFactorY += screenRenderInfo.scaleFactorY/3;
00116 screenRenderInfo.lowerLeftX += (oldWidth - (screenRenderInfo.displayWidth /
00117 screenRenderInfo.scaleFactorX)) / 2.0;
00118 screenRenderInfo.lowerLeftY += (oldHeight - (screenRenderInfo.displayHeight /
00119 screenRenderInfo.scaleFactorY)) / 2.0;
00120 break;
00121 case ZOOM_OUT :
00122 case ZOOM_OUT_CMOUSE :
00123 if ((screenRenderInfo.scaleFactorX > 10)&&(screenRenderInfo.scaleFactorY > 10)) {
00124 screenRenderInfo.scaleFactorX -= screenRenderInfo.scaleFactorX/3;
00125 screenRenderInfo.scaleFactorY -= screenRenderInfo.scaleFactorY/3;
00126 screenRenderInfo.lowerLeftX += (oldWidth - (screenRenderInfo.displayWidth /
00127 screenRenderInfo.scaleFactorX)) / 2.0;
00128 screenRenderInfo.lowerLeftY += (oldHeight - (screenRenderInfo.displayHeight /
00129 screenRenderInfo.scaleFactorY)) / 2.0;
00130 }
00131 break;
00132 case ZOOM_FIT :
00133 gerbv_render_zoom_to_fit_display (mainProject, &screenRenderInfo);
00134 break;
00135 case ZOOM_SET :
00136 screenRenderInfo.scaleFactorX = scaleFactor;
00137 screenRenderInfo.scaleFactorY = scaleFactor;
00138 screenRenderInfo.lowerLeftX += (oldWidth - (screenRenderInfo.displayWidth /
00139 screenRenderInfo.scaleFactorX)) / 2.0;
00140 screenRenderInfo.lowerLeftY += (oldHeight - (screenRenderInfo.displayHeight /
00141 screenRenderInfo.scaleFactorY)) / 2.0;
00142 break;
00143 default :
00144 GERB_MESSAGE("Illegal zoom direction %d\n", zoomType);
00145 }
00146
00147 if (zoomType == ZOOM_IN_CMOUSE || zoomType == ZOOM_OUT_CMOUSE) {
00148
00149 screenRenderInfo.lowerLeftX = mouseCoordinateX - mouseX / screenRenderInfo.scaleFactorX;
00150 screenRenderInfo.lowerLeftY = mouseCoordinateY - (screenRenderInfo.displayHeight - mouseY) /
00151 screenRenderInfo.scaleFactorY;
00152 }
00153
00154 render_refresh_rendered_image_on_screen();
00155 return;
00156 }
00157
00158
00159
00165 void
00166 render_calculate_zoom_from_outline(GtkWidget *widget, GdkEventButton *event)
00167 {
00168 int x1, y1, x2, y2, dx, dy;
00169 double centerPointX, centerPointY;
00170 int half_x, half_y;
00171
00172 x1 = MIN(screen.start_x, event->x);
00173 y1 = MIN(screen.start_y, event->y);
00174 x2 = MAX(screen.start_x, event->x);
00175 y2 = MAX(screen.start_y, event->y);
00176 dx = x2-x1;
00177 dy = y2-y1;
00178
00179 if ((dx >= 4) && (dy >= 4)) {
00180 if (screen.centered_outline_zoom) {
00181
00182 x1 = screen.start_x - dx;
00183 y1 = screen.start_y - dy;
00184 dx *= 2;
00185 dy *= 2;
00186 }
00187 half_x = (x1+x2)/2;
00188 half_y = (y1+y2)/2;
00189 centerPointX = half_x/screenRenderInfo.scaleFactorX + screenRenderInfo.lowerLeftX;
00190 centerPointY = (screenRenderInfo.displayHeight - half_y)/screenRenderInfo.scaleFactorY +
00191 screenRenderInfo.lowerLeftY;
00192
00193 screenRenderInfo.scaleFactorX *= MIN(((double)screenRenderInfo.displayWidth / dx),
00194 ((double)screenRenderInfo.displayHeight / dy));
00195 screenRenderInfo.scaleFactorY = screenRenderInfo.scaleFactorX;
00196 screenRenderInfo.lowerLeftX = centerPointX - (screenRenderInfo.displayWidth /
00197 2.0 / screenRenderInfo.scaleFactorX);
00198 screenRenderInfo.lowerLeftY = centerPointY - (screenRenderInfo.displayHeight /
00199 2.0 / screenRenderInfo.scaleFactorY);
00200 }
00201 render_refresh_rendered_image_on_screen();
00202 }
00203
00204
00205 void
00206 render_draw_selection_box_outline(void) {
00207 GdkGC *gc;
00208 GdkGCValues values;
00209 GdkGCValuesMask values_mask;
00210 gint x1, y1, x2, y2, dx, dy;
00211
00212 memset(&values, 0, sizeof(values));
00213 values.function = GDK_XOR;
00214 if (!screen.zoom_outline_color.pixel)
00215 gdk_colormap_alloc_color(gdk_colormap_get_system(), &screen.zoom_outline_color, FALSE, TRUE);
00216 values.foreground = screen.zoom_outline_color;
00217 values_mask = GDK_GC_FUNCTION | GDK_GC_FOREGROUND;
00218 gc = gdk_gc_new_with_values(screen.drawing_area->window, &values, values_mask);
00219
00220 x1 = MIN(screen.start_x, screen.last_x);
00221 y1 = MIN(screen.start_y, screen.last_y);
00222 x2 = MAX(screen.start_x, screen.last_x);
00223 y2 = MAX(screen.start_y, screen.last_y);
00224 dx = x2-x1;
00225 dy = y2-y1;
00226
00227 gdk_draw_rectangle(screen.drawing_area->window, gc, FALSE, x1, y1, dx, dy);
00228 gdk_gc_unref(gc);
00229 }
00230
00231
00232 void
00233 render_draw_zoom_outline(gboolean centered)
00234 {
00235 GdkGC *gc;
00236 GdkGCValues values;
00237 GdkGCValuesMask values_mask;
00238 gint x1, y1, x2, y2, dx, dy;
00239
00240 memset(&values, 0, sizeof(values));
00241 values.function = GDK_XOR;
00242 if (!screen.zoom_outline_color.pixel)
00243 gdk_colormap_alloc_color(gdk_colormap_get_system(), &screen.zoom_outline_color, FALSE, TRUE);
00244 values.foreground = screen.zoom_outline_color;
00245 values_mask = GDK_GC_FUNCTION | GDK_GC_FOREGROUND;
00246 gc = gdk_gc_new_with_values(screen.drawing_area->window, &values, values_mask);
00247
00248 x1 = MIN(screen.start_x, screen.last_x);
00249 y1 = MIN(screen.start_y, screen.last_y);
00250 x2 = MAX(screen.start_x, screen.last_x);
00251 y2 = MAX(screen.start_y, screen.last_y);
00252 dx = x2-x1;
00253 dy = y2-y1;
00254
00255 if (centered) {
00256
00257 x1 = screen.start_x - dx;
00258 y1 = screen.start_y - dy;
00259 dx *= 2;
00260 dy *= 2;
00261 x2 = x1+dx;
00262 y2 = y1+dy;
00263 }
00264
00265 gdk_draw_rectangle(screen.drawing_area->window, gc, FALSE, x1, y1, dx, dy);
00266 gdk_gc_unref(gc);
00267
00268
00269 memset(&values, 0, sizeof(values));
00270 values.function = GDK_XOR;
00271 values.foreground = screen.zoom_outline_color;
00272 values.line_style = GDK_LINE_ON_OFF_DASH;
00273 values_mask = GDK_GC_FUNCTION | GDK_GC_FOREGROUND | GDK_GC_LINE_STYLE;
00274 gc = gdk_gc_new_with_values(screen.drawing_area->window, &values,
00275 values_mask);
00276
00277 if ((dy == 0) || ((double)dx/dy > (double)screen.drawing_area->allocation.width/
00278 screen.drawing_area->allocation.height)) {
00279 dy = dx * (double)screen.drawing_area->allocation.height/
00280 screen.drawing_area->allocation.width;
00281 }
00282 else {
00283 dx = dy * (double)screen.drawing_area->allocation.width/
00284 screen.drawing_area->allocation.height;
00285 }
00286
00287 gdk_draw_rectangle(screen.drawing_area->window, gc, FALSE, (x1+x2-dx)/2,
00288 (y1+y2-dy)/2, dx, dy);
00289
00290 gdk_gc_unref(gc);
00291 }
00292
00293
00294
00298 void
00299 render_draw_measure_distance(void)
00300 {
00301 #if !defined (__MINGW32__)
00302
00303 GdkGC *gc;
00304 GdkGCValues values;
00305 GdkGCValuesMask values_mask;
00306 #endif
00307 gint x1, y1, x2, y2;
00308 double dx, dy;
00309
00310 #if !defined (__MINGW32__)
00311 memset(&values, 0, sizeof(values));
00312 values.function = GDK_XOR;
00313 if (!screen.zoom_outline_color.pixel)
00314 gdk_colormap_alloc_color(gdk_colormap_get_system(), &screen.zoom_outline_color, FALSE, TRUE);
00315 values.foreground = screen.zoom_outline_color;
00316 values_mask = GDK_GC_FUNCTION | GDK_GC_FOREGROUND;
00317 gc = gdk_gc_new_with_values(screen.drawing_area->window, &values,
00318 values_mask);
00319 #endif
00320 x1 = MIN(screen.start_x, screen.last_x);
00321 y1 = MIN(screen.start_y, screen.last_y);
00322 x2 = MAX(screen.start_x, screen.last_x);
00323 y2 = MAX(screen.start_y, screen.last_y);
00324 dx = (x2 - x1)/ screenRenderInfo.scaleFactorX;
00325 dy = (y2 - y1)/ screenRenderInfo.scaleFactorY;
00326
00327 #if !defined (__MINGW32__)
00328 gdk_draw_line(screen.drawing_area->window, gc, screen.start_x,
00329 screen.start_y, screen.last_x, screen.last_y);
00330 #endif
00331 screen.win.lastMeasuredX = dx;
00332 screen.win.lastMeasuredY = dy;
00333 callbacks_update_statusbar_measured_distance (dx, dy);
00334 #if !defined (__MINGW32__)
00335 gdk_gc_unref(gc);
00336 #endif
00337 }
00338
00339
00340 void render_selection_layer (void){
00341 #ifndef RENDER_USING_GDK
00342 cairo_t *cr;
00343
00344 if (screen.selectionRenderData)
00345 cairo_surface_destroy ((cairo_surface_t *) screen.selectionRenderData);
00346 screen.selectionRenderData =
00347 (gpointer) cairo_surface_create_similar ((cairo_surface_t *)screen.windowSurface,
00348 CAIRO_CONTENT_COLOR_ALPHA, screenRenderInfo.displayWidth,
00349 screenRenderInfo.displayHeight);
00350 if (screen.selectionInfo.type != GERBV_SELECTION_EMPTY) {
00351 cr= cairo_create(screen.selectionRenderData);
00352 gerbv_render_cairo_set_scale_and_translation(cr, &screenRenderInfo);
00353 cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.85);
00354
00355 gerbv_image_t *matchImage;
00356 int j;
00357 if (screen.selectionInfo.selectedNodeArray->len > 0) {
00358 gerbv_selection_item_t sItem = g_array_index (screen.selectionInfo.selectedNodeArray,
00359 gerbv_selection_item_t, 0);
00360 matchImage = (gerbv_image_t *) sItem.image;
00361 dprintf(" .... calling render_image_to_cairo_target on selection layer...\n");
00362 for(j = mainProject->max_files-1; j >= 0; j--) {
00363 if ((mainProject->file[j]) && (mainProject->file[j]->image == matchImage)) {
00364 draw_image_to_cairo_target (cr, mainProject->file[j]->image,
00365 mainProject->file[j]->transform.inverted,
00366 1.0/MAX(screenRenderInfo.scaleFactorX,
00367 screenRenderInfo.scaleFactorY),
00368 DRAW_SELECTIONS, &screen.selectionInfo);
00369 }
00370 }
00371 }
00372 cairo_destroy (cr);
00373 }
00374 #endif
00375 }
00376
00377
00378 void render_refresh_rendered_image_on_screen (void) {
00379 GdkCursor *cursor;
00380
00381 dprintf("----> Entering redraw_pixmap...\n");
00382 cursor = gdk_cursor_new(GDK_WATCH);
00383 gdk_window_set_cursor(GDK_WINDOW(screen.drawing_area->window), cursor);
00384 gdk_cursor_destroy(cursor);
00385
00386 if (screenRenderInfo.renderType < 2){
00387 if (screen.pixmap)
00388 gdk_pixmap_unref(screen.pixmap);
00389 screen.pixmap = gdk_pixmap_new(screen.drawing_area->window, screenRenderInfo.displayWidth,
00390 screenRenderInfo.displayHeight, -1);
00391 gerbv_render_to_pixmap_using_gdk (mainProject, screen.pixmap, &screenRenderInfo, &screen.selectionInfo,
00392 &screen.selection_color);
00393 dprintf("<---- leaving redraw_pixmap.\n");
00394 }
00395 #ifndef RENDER_USING_GDK
00396 else{
00397 int i;
00398 dprintf(" .... Now try rendering the drawing using cairo .... \n");
00399
00400
00401
00402
00403 for(i = mainProject->max_files-1; i >= 0; i--) {
00404 if (mainProject->file[i]) {
00405 cairo_t *cr;
00406 if (mainProject->file[i]->privateRenderData)
00407 cairo_surface_destroy ((cairo_surface_t *) mainProject->file[i]->privateRenderData);
00408 mainProject->file[i]->privateRenderData =
00409 (gpointer) cairo_surface_create_similar ((cairo_surface_t *)screen.windowSurface,
00410 CAIRO_CONTENT_COLOR_ALPHA, screenRenderInfo.displayWidth,
00411 screenRenderInfo.displayHeight);
00412 cr= cairo_create(mainProject->file[i]->privateRenderData );
00413 gerbv_render_layer_to_cairo_target (cr, mainProject->file[i], &screenRenderInfo);
00414 dprintf(" .... calling render_image_to_cairo_target on layer %d...\n", i);
00415 cairo_destroy (cr);
00416 }
00417 }
00418
00419 render_selection_layer();
00420
00421 render_recreate_composite_surface ();
00422 }
00423 #endif
00424
00425 callbacks_switch_to_correct_cursor ();
00426 callbacks_force_expose_event_for_screen();
00427 }
00428
00429
00430 #ifndef RENDER_USING_GDK
00431 gint
00432 render_create_cairo_buffer_surface () {
00433 if (screen.bufferSurface) {
00434 cairo_surface_destroy (screen.bufferSurface);
00435 screen.bufferSurface = NULL;
00436 }
00437 if (!screen.windowSurface)
00438 return 0;
00439
00440 screen.bufferSurface= cairo_surface_create_similar ((cairo_surface_t *)screen.windowSurface,
00441 CAIRO_CONTENT_COLOR, screenRenderInfo.displayWidth,
00442 screenRenderInfo.displayHeight);
00443 return 1;
00444 }
00445
00446
00447 void
00448 render_clear_selection_buffer (void){
00449 if (screen.selectionInfo.type == GERBV_SELECTION_EMPTY)
00450 return;
00451
00452 g_array_remove_range (screen.selectionInfo.selectedNodeArray, 0,
00453 screen.selectionInfo.selectedNodeArray->len);
00454 screen.selectionInfo.type = GERBV_SELECTION_EMPTY;
00455 }
00456
00457
00458 void
00459 render_find_selected_objects_and_refresh_display (gint activeFileIndex, gboolean eraseOldSelection){
00460
00461 if ((eraseOldSelection)&&(screen.selectionInfo.selectedNodeArray->len))
00462 g_array_remove_range (screen.selectionInfo.selectedNodeArray, 0,
00463 screen.selectionInfo.selectedNodeArray->len);
00464
00465
00466
00467 if (!render_create_cairo_buffer_surface())
00468 return;
00469
00470
00471
00472 cairo_t *cr= cairo_create(screen.bufferSurface);
00473 gerbv_render_cairo_set_scale_and_translation(cr,&screenRenderInfo);
00474 draw_image_to_cairo_target (cr, mainProject->file[activeFileIndex]->image, mainProject->file[activeFileIndex]->transform.inverted,
00475 1.0/MAX(screenRenderInfo.scaleFactorX, screenRenderInfo.scaleFactorY),
00476 FIND_SELECTIONS, &screen.selectionInfo);
00477 cairo_destroy (cr);
00478
00479
00480 if (!screen.selectionInfo.selectedNodeArray->len)
00481 screen.selectionInfo.type = GERBV_SELECTION_EMPTY;
00482
00483 if (screenRenderInfo.renderType < 2){
00484 render_refresh_rendered_image_on_screen ();
00485 }
00486 else {
00487 render_selection_layer();
00488 render_recreate_composite_surface ();
00489 callbacks_force_expose_event_for_screen();
00490 }
00491 }
00492
00493
00494 void
00495 render_fill_selection_buffer_from_mouse_click (gint mouseX, gint mouseY, gint activeFileIndex,
00496 gboolean eraseOldSelection) {
00497 screen.selectionInfo.lowerLeftX = mouseX;
00498 screen.selectionInfo.lowerLeftY = mouseY;
00499
00500 screen.selectionInfo.type = GERBV_SELECTION_POINT_CLICK;
00501 render_find_selected_objects_and_refresh_display (activeFileIndex, eraseOldSelection);
00502 }
00503
00504
00505 void
00506 render_fill_selection_buffer_from_mouse_drag (gint corner1X, gint corner1Y,
00507 gint corner2X, gint corner2Y, gint activeFileIndex, gboolean eraseOldSelection) {
00508
00509 screen.selectionInfo.lowerLeftX = MIN(corner1X, corner2X);
00510 screen.selectionInfo.lowerLeftY = MIN(corner1Y, corner2Y);
00511
00512 screen.selectionInfo.upperRightX = MAX(corner1X, corner2X);
00513 screen.selectionInfo.upperRightY = MAX(corner1Y, corner2Y);
00514
00515 screen.selectionInfo.type = GERBV_SELECTION_DRAG_BOX;
00516 render_find_selected_objects_and_refresh_display (activeFileIndex, eraseOldSelection);
00517 }
00518
00519
00520 void render_recreate_composite_surface () {
00521 gint i;
00522
00523 if (!render_create_cairo_buffer_surface())
00524 return;
00525
00526 cairo_t *cr= cairo_create(screen.bufferSurface);
00527
00528 cairo_set_source_rgba (cr, (double) mainProject->background.red/G_MAXUINT16,
00529 (double) mainProject->background.green/G_MAXUINT16,
00530 (double) mainProject->background.blue/G_MAXUINT16, 1);
00531 cairo_paint (cr);
00532
00533 for(i = mainProject->max_files-1; i >= 0; i--) {
00534 if (mainProject->file[i] && mainProject->file[i]->isVisible) {
00535 cairo_set_source_surface (cr, (cairo_surface_t *) mainProject->file[i]->privateRenderData,
00536 0, 0);
00537
00538 if (((double) mainProject->file[i]->alpha < 65535)&&(screenRenderInfo.renderType != 1)) {
00539 cairo_paint_with_alpha(cr,(double) mainProject->file[i]->alpha/G_MAXUINT16);
00540 }
00541 else {
00542 cairo_paint (cr);
00543 }
00544 }
00545 }
00546
00547 if (screen.selectionInfo.type != GERBV_SELECTION_EMPTY) {
00548 cairo_set_source_surface (cr, (cairo_surface_t *) screen.selectionRenderData,
00549 0, 0);
00550 cairo_paint_with_alpha (cr,1.0);
00551 }
00552 cairo_destroy (cr);
00553 }
00554
00555
00556 void render_project_to_cairo_target (cairo_t *cr) {
00557
00558 cairo_set_source_rgba (cr, (double) mainProject->background.red/G_MAXUINT16,
00559 (double) mainProject->background.green/G_MAXUINT16,
00560 (double) mainProject->background.blue/G_MAXUINT16, 1);
00561 cairo_paint (cr);
00562
00563 cairo_set_source_surface (cr, (cairo_surface_t *) screen.bufferSurface, 0 , 0);
00564
00565 cairo_paint (cr);
00566 }
00567 #endif
00568
00569
00573 gerbv_stats_t *
00574 generate_gerber_analysis(void)
00575 {
00576 int i;
00577 gerbv_stats_t *stats;
00578 gerbv_stats_t *instats;
00579
00580
00581
00582 stats = gerbv_stats_new();
00583
00584
00585 for (i = 0; i <= mainProject->max_files-1; i++) {
00586 if (mainProject->file[i] && mainProject->file[i]->isVisible &&
00587 (mainProject->file[i]->image->layertype == GERBV_LAYERTYPE_RS274X) ) {
00588 instats = mainProject->file[i]->image->gerbv_stats;
00589 gerbv_stats_add_layer(stats, instats, i+1);
00590 }
00591 }
00592 return stats;
00593 }
00594
00595
00596
00600 gerbv_drill_stats_t *
00601 generate_drill_analysis(void)
00602 {
00603 int i;
00604 gerbv_drill_stats_t *stats;
00605 gerbv_drill_stats_t *instats;
00606
00607 stats = gerbv_drill_stats_new();
00608
00609
00610 for(i = mainProject->max_files-1; i >= 0; i--) {
00611 if (mainProject->file[i] &&
00612 mainProject->file[i]->isVisible &&
00613 (mainProject->file[i]->image->layertype == GERBV_LAYERTYPE_DRILL) ) {
00614 instats = mainProject->file[i]->image->drill_stats;
00615
00616
00617 gerbv_drill_stats_add_layer(stats, instats, i+1);
00618 }
00619 }
00620 return stats;
00621 }
00622