gschem

x_grid.c

Go to the documentation of this file.
00001 /* gEDA - GPL Electronic Design Automation
00002  * gschem - gEDA Schematic Capture
00003  * Copyright (C) 1998-2010 Ales Hvezda
00004  * Copyright (C) 1998-2010 gEDA Contributors (see ChangeLog for details)
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00019  */
00020 #include <config.h>
00021 
00022 #include <math.h>
00023 #ifdef HAVE_STRING_H
00024 #include <string.h>
00025 #endif
00026 
00027 #include "gschem.h"
00028 
00029 #ifdef HAVE_LIBDMALLOC
00030 #include <dmalloc.h>
00031 #endif
00032 
00033 #define DOTS_POINTS_ARRAY_SIZE       5000
00034 #define DOTS_VARIABLE_MODE_SPACING   30
00035 
00036 #define MESH_COARSE_GRID_MULTIPLIER  5
00037 
00038 
00050 static int query_dots_grid_spacing (GSCHEM_TOPLEVEL *w_current)
00051 {
00052   TOPLEVEL *toplevel = w_current->toplevel;
00053   int incr, screen_incr;
00054 
00055   if (w_current->dots_grid_mode == DOTS_GRID_VARIABLE_MODE) {
00056     /* In the variable mode around every (DOTS_VARIABLE_MODE_SPACING)'th
00057      * screenpixel will be grid-point. */
00058     /* adding 0.1 for correct cast*/
00059     incr = round_5_2_1 (toplevel->page_current->to_world_x_constant *
00060                         DOTS_VARIABLE_MODE_SPACING) + 0.1;
00061 
00062     /* limit minimum grid spacing to grid to snap_size */
00063     if (incr < w_current->snap_size) {
00064       incr = w_current->snap_size;
00065     }
00066   } else {
00067     /* Fixed size grid in world coorinates */
00068     incr = w_current->snap_size;
00069     screen_incr = SCREENabs (w_current, incr);
00070     if (screen_incr < w_current->dots_grid_fixed_threshold) {
00071       /* No grid drawn if the on-screen spacing is less than the threshold */
00072       incr = -1;
00073     }
00074   }
00075   return incr;
00076 }
00077 
00078 
00090 static void draw_dots_grid_region (GSCHEM_TOPLEVEL *w_current,
00091                                    int x, int y, int width, int height)
00092 {
00093   TOPLEVEL *toplevel = w_current->toplevel;
00094   int i, j;
00095   int dot_x, dot_y;
00096   int x_start, y_start, x_end, y_end;
00097   int count = 0;
00098   GdkPoint points[DOTS_POINTS_ARRAY_SIZE];
00099 
00100   int incr = query_dots_grid_spacing (w_current);
00101 
00102   if (incr == -1)
00103     return;
00104 
00105   gdk_gc_set_foreground (w_current->gc, x_get_color (DOTS_GRID_COLOR));
00106 
00107   SCREENtoWORLD (w_current, x - 1, y + height + 1, &x_start, &y_start);
00108   SCREENtoWORLD (w_current, x + width + 1, y - 1, &x_end, &y_end);
00109 
00110   /* figure starting grid coordinates, work by taking the start
00111    * and end coordinates and rounding down to the nearest
00112    * increment */
00113   x_start -= (x_start % incr);
00114   y_start -= (y_start % incr);
00115 
00116   for (i = x_start; i <= x_end; i = i + incr) {
00117     for(j = y_start; j <= y_end; j = j + incr) {
00118       WORLDtoSCREEN (w_current, i,j, &dot_x, &dot_y);
00119       if (inside_region (toplevel->page_current->left,
00120                          toplevel->page_current->top,
00121                          toplevel->page_current->right,
00122                          toplevel->page_current->bottom, i, j)) {
00123 
00124         if (w_current->dots_grid_dot_size == 1) {
00125           points[count].x = dot_x;
00126           points[count].y = dot_y;
00127           count++;
00128 
00129           /* get out of loop if we're hit the end of the array */
00130           if (count == DOTS_POINTS_ARRAY_SIZE) {
00131             gdk_draw_points (w_current->drawable,
00132                              w_current->gc, points, count);
00133             count = 0;
00134           }
00135         } else {
00136           gdk_draw_arc (w_current->drawable, w_current->gc,
00137                         TRUE, dot_x, dot_y,
00138                         w_current->dots_grid_dot_size,
00139                         w_current->dots_grid_dot_size, 0, FULL_CIRCLE);
00140         }
00141       }
00142     }
00143   }
00144 
00145   /* now draw all the points in one step */
00146   if(count != 0) {
00147     gdk_draw_points (w_current->drawable, w_current->gc, points, count);
00148   }
00149 }
00150 
00151 
00154 static void draw_mesh (GSCHEM_TOPLEVEL *w_current, int color,
00155                        int x_start, int y_start, int x_end, int y_end,
00156                        int incr, int coarse_mult)
00157 {
00158   int i, j;
00159   int x1, y1, x2, y2;
00160   int next_coarse_x, next_coarse_y;
00161   int coarse_incr = incr * coarse_mult;
00162 
00163   /* figure starting grid coordinates, work by taking the start
00164    * and end coordinates and rounding down to the nearest increment */
00165   x_start -= (x_start % incr);
00166   y_start -= (y_start % incr);
00167 
00168   if (coarse_incr == 0) {
00169     next_coarse_x = x_start - 1; /* Ensures we never hit this when looping */
00170     next_coarse_y = y_start - 1; /* Ensures we never hit this when looping */
00171   } else {
00172     next_coarse_x = x_start - (x_start % coarse_incr);
00173     next_coarse_y = y_start - (y_start % coarse_incr);
00174     if (next_coarse_x < x_start) next_coarse_x += coarse_incr;
00175     if (next_coarse_y < y_start) next_coarse_y += coarse_incr;
00176   }
00177 
00178   gschem_cairo_set_source_color (w_current, x_color_lookup (color));
00179   cairo_set_line_width (w_current->cr, 1.);
00180   cairo_set_line_cap (w_current->cr, CAIRO_LINE_CAP_SQUARE);
00181 
00182   cairo_translate (w_current->cr, 0.5, 0.5);
00183 
00184   for (j = y_start; j < y_end; j = j + incr) {
00185 
00186     /* Skip lines which will be drawn in the coarser grid */
00187     if (j == next_coarse_y) {
00188       next_coarse_y += coarse_incr;
00189       continue;
00190     }
00191     WORLDtoSCREEN (w_current, x_start, j, &x1, &y1);
00192     WORLDtoSCREEN (w_current, x_end,   j, &x2, &y2);
00193     cairo_move_to (w_current->cr, x1, y1);
00194     cairo_line_to (w_current->cr, x2, y2);
00195   }
00196   cairo_stroke (w_current->cr);
00197 
00198   for (i = x_start; i < x_end; i = i + incr) {
00199 
00200     /* Skip lines which will be drawn in the coarser grid */
00201     if (j == next_coarse_y) {
00202       next_coarse_y += coarse_incr;
00203       continue;
00204     }
00205     WORLDtoSCREEN (w_current, i, y_start, &x1, &y1);
00206     WORLDtoSCREEN (w_current, i, y_end,   &x2, &y2);
00207     cairo_move_to (w_current->cr, x1, y1);
00208     cairo_line_to (w_current->cr, x2, y2);
00209   }
00210   cairo_stroke (w_current->cr);
00211 
00212   cairo_translate (w_current->cr, -0.5, -0.5);
00213 }
00214 
00215 
00227 static int query_mesh_grid_spacing (GSCHEM_TOPLEVEL *w_current)
00228 {
00229   int incr, screen_incr;
00230 
00231   incr = w_current->snap_size;
00232   screen_incr = SCREENabs (w_current, incr);
00233 
00234   /* We draw a fine grid if its on-screen spacing is large enough */
00235   if (screen_incr >= w_current->mesh_grid_display_threshold) {
00236     return incr;
00237   }
00238 
00239   incr *= MESH_COARSE_GRID_MULTIPLIER;
00240   screen_incr = SCREENabs (w_current, incr);
00241 
00242   /* We draw a coarse grid if its on-screen spacing is large enough */
00243   if (screen_incr >= w_current->mesh_grid_display_threshold)
00244     return incr;
00245 
00246   return -1;
00247 }
00248 
00260 static void draw_mesh_grid_region (GSCHEM_TOPLEVEL *w_current,
00261                                    int x, int y, int width, int height)
00262 {
00263   int x_start, y_start, x_end, y_end;
00264   int incr;
00265   int screen_incr;
00266 
00267   incr = w_current->snap_size;
00268   screen_incr = SCREENabs (w_current, incr);
00269 
00270   SCREENtoWORLD (w_current, x - 1, y + height + 1, &x_start, &y_start);
00271   SCREENtoWORLD (w_current, x + width + 1, y - 1, &x_end, &y_end);
00272 
00273   /* Draw the fine grid if its on-screen spacing is large enough */
00274   if (screen_incr >= w_current->mesh_grid_display_threshold) {
00275     draw_mesh (w_current, MESH_GRID_MINOR_COLOR, x_start, y_start,
00276                x_end, y_end, incr, MESH_COARSE_GRID_MULTIPLIER);
00277   }
00278 
00279   incr *= MESH_COARSE_GRID_MULTIPLIER;
00280   screen_incr = SCREENabs (w_current, incr);
00281 
00282   /* Draw the coarse grid if its on-screen spacing is large enough */
00283   if (screen_incr >= w_current->mesh_grid_display_threshold) {
00284     draw_mesh (w_current, MESH_GRID_MAJOR_COLOR,
00285                x_start, y_start, x_end, y_end, incr, 0);
00286   }
00287 }
00288 
00289 
00301 void x_grid_draw_region (GSCHEM_TOPLEVEL *w_current,
00302                          int x, int y, int width, int height)
00303 {
00304   switch (w_current->grid) {
00305     case GRID_NONE:
00306       return;
00307 
00308     case GRID_DOTS:
00309       draw_dots_grid_region (w_current, x, y, width, height);
00310       break;
00311 
00312     case GRID_MESH:
00313       draw_mesh_grid_region (w_current, x, y, width, height);
00314       break;
00315   }
00316 
00317 #if DEBUG
00318   /* highly temp, just for diag purposes */
00319   x_draw_tiles(w_current);
00320 #endif
00321 }
00322 
00323 
00335 int x_grid_query_drawn_spacing (GSCHEM_TOPLEVEL *w_current)
00336 {
00337   switch (w_current->grid) {
00338     default:
00339     case GRID_NONE: return -1;
00340     case GRID_DOTS: return query_dots_grid_spacing (w_current);
00341     case GRID_MESH: return query_mesh_grid_spacing (w_current);
00342   }
00343 }
00344 
00345 
00351 void x_draw_tiles(GSCHEM_TOPLEVEL *w_current)
00352 {
00353   TOPLEVEL *toplevel = w_current->toplevel;
00354   TILE *t_current;
00355   GdkFont *font;
00356   int i,j;
00357   int x1, y1, x2, y2;
00358   int screen_x, screen_y;
00359   int width, height;
00360   char *tempstring;
00361 
00362   gdk_gc_set_foreground (w_current->gc, x_get_color (LOCK_COLOR));
00363 
00364   font = gdk_fontset_load ("fixed");
00365   for (j = 0; j < MAX_TILES_Y; j++) {
00366     for (i = 0; i < MAX_TILES_X; i++) {
00367       t_current = &toplevel->page_current->world_tiles[i][j];
00368       WORLDtoSCREEN (w_current, t_current->left, t_current->top, &x1, &y1);
00369       WORLDtoSCREEN (w_current, t_current->right, t_current->bottom, &x2, &y2);
00370 
00371       screen_x = min(x1, x2);
00372       screen_y = min(y1, y2);
00373 
00374       width = abs(x1 - x2);
00375       height = abs(y1 - y2);
00376 
00377 #if DEBUG
00378       printf("x, y: %d %d\n", screen_x, screen_y);
00379       printf("w x h: %d %d\n", width, height);
00380 #endif
00381       gdk_draw_rectangle (w_current->drawable,
00382                           w_current->gc,
00383                           FALSE, screen_x, screen_y,
00384                           width, height);
00385 
00386       tempstring = g_strdup_printf("%d %d", i, j);
00387 
00388       gdk_draw_text (w_current->drawable,
00389                      font,
00390                      w_current->gc,
00391                      screen_x+10, screen_y+10,
00392                      tempstring,
00393                      strlen(tempstring));
00394       g_free(tempstring);
00395     }
00396   }
00397 
00398   gdk_font_unref(font);
00399 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines