linewidth is now working for PS_SOLID
[dia.git] / app / grid.c
blob7a0d0ed23b973de25ca4b29b696c42d1ec4d73c5
1 /* Dia -- an diagram creation/manipulation program
2 * Copyright (C) 1998 Alexander Larsson
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <math.h>
26 #include <glib.h>
28 #include "intl.h"
29 #include "grid.h"
30 #include "preferences.h"
32 /** Calculate the width (in cm) of the gap between grid lines in dynamic
33 * grid mode.
35 static real
36 calculate_dynamic_grid(DDisplay *ddisp, real *width_x, real *width_y)
38 real zoom = ddisplay_untransform_length(ddisp, 1.0);
39 /* Twiddle zoom to make change-over appropriate */
40 zoom *= 5;
41 return pow(10, ceil(log10(zoom)));
44 static void
45 grid_draw_horizontal_lines(DDisplay *ddisp, Rectangle *update, real length)
47 int x, y;
48 real pos;
49 int height, width;
50 guint major_lines = ddisp->diagram->data->grid.major_lines;
51 DiaRenderer *renderer = ddisp->renderer;
52 DiaInteractiveRendererInterface *irenderer;
53 int major_count = 0;
55 irenderer = DIA_GET_INTERACTIVE_RENDERER_INTERFACE (renderer);
57 pos = ceil( update->top / length ) * length;
58 ddisplay_transform_coords(ddisp, update->left, pos, &x, &y);
59 ddisplay_transform_coords(ddisp, update->right, update->bottom, &width, &height);
61 if (major_lines) {
62 major_count = pos/length;
63 major_count %= major_lines;
66 while (y < height) {
67 if (major_lines) {
68 if (major_count == 0)
69 DIA_RENDERER_GET_CLASS(renderer)->set_linestyle(renderer, LINESTYLE_SOLID);
70 else
71 DIA_RENDERER_GET_CLASS(renderer)->set_linestyle(renderer, LINESTYLE_DOTTED);
72 major_count = (major_count+1)%major_lines;
74 irenderer->draw_pixel_line(renderer, x, y, width, y,
75 &ddisp->diagram->data->grid.colour);
76 pos += length;
77 ddisplay_transform_coords(ddisp, update->left, pos, &x, &y);
81 static void
82 grid_draw_vertical_lines(DDisplay *ddisp, Rectangle *update, real length)
84 int x = 0, y = 0;
85 real pos;
86 int height, width;
87 guint major_lines = ddisp->diagram->data->grid.major_lines;
88 DiaRenderer *renderer = ddisp->renderer;
89 DiaInteractiveRendererInterface *irenderer;
90 int major_count = 0;
92 irenderer = DIA_GET_INTERACTIVE_RENDERER_INTERFACE (renderer);
94 pos = ceil( update->left / length ) * length;
95 ddisplay_transform_coords(ddisp, update->right, update->bottom, &width, &height);
97 if (major_lines) {
98 major_count = pos/length;
99 major_count %= major_lines;
102 while (x < width) {
103 ddisplay_transform_coords(ddisp, pos, update->top, &x, &y);
104 if (major_lines) {
105 if (major_count == 0)
106 DIA_RENDERER_GET_CLASS(renderer)->set_linestyle(renderer, LINESTYLE_SOLID);
107 else
108 DIA_RENDERER_GET_CLASS(renderer)->set_linestyle(renderer, LINESTYLE_DOTTED);
109 major_count = (major_count+1)%major_lines;
111 irenderer->draw_pixel_line(renderer, x, y, x, height,
112 &ddisp->diagram->data->grid.colour);
113 pos += length;
117 static void
118 grid_draw_hex(DDisplay *ddisp, Rectangle *update, real length)
120 real horiz_pos, vert_pos;
121 int to_x, to_y, x, y;
122 DiaRenderer *renderer = ddisp->renderer;
123 DiaInteractiveRendererInterface *irenderer;
125 irenderer = DIA_GET_INTERACTIVE_RENDERER_INTERFACE (renderer);
127 /* First horizontal lines: */
128 vert_pos = ceil( update->top / (length * sqrt(3)) ) * length * sqrt(3);
129 while (vert_pos <= update->bottom) {
130 horiz_pos = ceil( (update->left) / (3 * length) ) * length * 3 - length * 2.5;
131 while (horiz_pos <= update->right) {
132 ddisplay_transform_coords(ddisp, horiz_pos, vert_pos, &x, &y);
133 ddisplay_transform_coords(ddisp, horiz_pos + length, vert_pos, &to_x, &y);
135 irenderer->draw_pixel_line(renderer,
136 x, y, to_x, y,
137 &ddisp->diagram->data->grid.colour);
138 horiz_pos += 3 * length;
141 vert_pos += sqrt(3) * length;
144 /* Second horizontal lines: */
145 vert_pos = ceil( update->top / (length * sqrt(3)) ) * length * sqrt(3) - 0.5 * sqrt(3) * length;
146 while (vert_pos <= update->bottom) {
147 horiz_pos = ceil( (update->left) / (3 * length) ) * length * 3 - length;
148 while (horiz_pos <= update->right) {
149 ddisplay_transform_coords(ddisp, horiz_pos, vert_pos, &x, &y);
150 ddisplay_transform_coords(ddisp, horiz_pos+length, vert_pos, &to_x, &y);
152 irenderer->draw_pixel_line(renderer,
153 x, y, to_x, y,
154 &ddisp->diagram->data->grid.colour);
155 horiz_pos += 3 * length;
158 vert_pos += sqrt(3) * length;
161 /* First \'s and /'s */
162 vert_pos = ceil( update->top / (length * sqrt(3)) ) * length * sqrt(3) - length * sqrt(3);
163 while (vert_pos <= update->bottom) {
164 horiz_pos = ceil( (update->left) / (3 * length) ) * length * 3 - length * 2.5;
165 while (horiz_pos <= update->right) {
166 ddisplay_transform_coords(ddisp, horiz_pos + length, vert_pos, &x, &y);
167 ddisplay_transform_coords(ddisp, horiz_pos + 1.5 * length, vert_pos + length * sqrt(3) * 0.5, &to_x, &to_y);
169 irenderer->draw_pixel_line(renderer,
170 x, y, to_x, to_y,
171 &ddisp->diagram->data->grid.colour);
173 ddisplay_transform_coords(ddisp, horiz_pos, vert_pos, &x, &y);
174 ddisplay_transform_coords(ddisp, horiz_pos - 0.5 * length, vert_pos + length * sqrt(3) * 0.5, &to_x, &to_y);
176 irenderer->draw_pixel_line(renderer,
177 x, y, to_x, to_y,
178 &ddisp->diagram->data->grid.colour);
179 horiz_pos += 3 * length;
182 vert_pos += sqrt(3) * length;
185 /* Second \'s and /'s */
186 vert_pos = ceil( update->top / (length * sqrt(3)) ) * length * sqrt(3) - 0.5 * sqrt(3) * length;
187 while (vert_pos <= update->bottom) {
188 horiz_pos = ceil( (update->left) / (3 * length) ) * length * 3 - length;
189 while (horiz_pos <= update->right) {
190 ddisplay_transform_coords(ddisp, horiz_pos, vert_pos, &x, &y);
191 ddisplay_transform_coords(ddisp, horiz_pos - 0.5 * length, vert_pos + 0.5 * sqrt(3) * length, &to_x, &to_y);
193 irenderer->draw_pixel_line(renderer,
194 x, y, to_x, to_y,
195 &ddisp->diagram->data->grid.colour);
197 ddisplay_transform_coords(ddisp, horiz_pos + length, vert_pos, &x, &y);
198 ddisplay_transform_coords(ddisp, horiz_pos + 1.5 * length, vert_pos + 0.5 * sqrt(3) * length, &to_x, &to_y);
200 irenderer->draw_pixel_line(renderer,
201 x, y, to_x, to_y,
202 &ddisp->diagram->data->grid.colour);
203 horiz_pos += 3 * length;
206 vert_pos += sqrt(3) * length;
211 void
212 grid_draw(DDisplay *ddisp, Rectangle *update)
214 Grid *grid = &ddisp->grid;
215 DiaRenderer *renderer = ddisp->renderer;
216 int major_lines;
218 if (grid->visible) {
219 int width = dia_renderer_get_width_pixels(ddisp->renderer);
220 int height = dia_renderer_get_height_pixels(ddisp->renderer);
221 /* distance between visible grid lines */
222 real width_x = ddisp->diagram->data->grid.width_x;
223 real width_y = ddisp->diagram->data->grid.width_y;
224 real width_w = ddisp->diagram->data->grid.width_w;
225 if (ddisp->diagram->data->grid.dynamic) {
226 width_x = width_y = calculate_dynamic_grid(ddisp, &width_x, &width_y);
227 } else {
228 width_x = ddisp->diagram->data->grid.width_x *
229 ddisp->diagram->data->grid.visible_x;
230 width_y = ddisp->diagram->data->grid.width_y *
231 ddisp->diagram->data->grid.visible_y;
234 DIA_RENDERER_GET_CLASS(renderer)->set_linewidth(renderer, 0.0);
235 DIA_RENDERER_GET_CLASS(renderer)->set_dashlength(renderer,
236 ddisplay_untransform_length(ddisp, 31));
238 if (ddisp->diagram->data->grid.hex) {
239 grid_draw_hex(ddisp, update, width_w);
240 } else {
241 if (ddisplay_transform_length(ddisp, width_y) >= 2.0 &&
242 ddisplay_transform_length(ddisp, width_x) >= 2.0) {
243 /* Vertical lines: */
244 grid_draw_vertical_lines(ddisp, update, width_x);
245 /* Horizontal lines: */
246 grid_draw_horizontal_lines(ddisp, update, width_y);
252 void
253 pagebreak_draw(DDisplay *ddisp, Rectangle *update)
255 DiaRenderer *renderer = ddisp->renderer;
256 DiaInteractiveRendererInterface *irenderer;
258 int width = dia_renderer_get_width_pixels(ddisp->renderer);
259 int height = dia_renderer_get_height_pixels(ddisp->renderer);
261 irenderer = DIA_GET_INTERACTIVE_RENDERER_INTERFACE (renderer);
262 if (prefs.pagebreak.visible) {
263 Diagram *dia = ddisp->diagram;
264 real origx = 0, origy = 0, pos;
265 real pwidth = dia->data->paper.width;
266 real pheight = dia->data->paper.height;
267 int x,y;
269 DIA_RENDERER_GET_CLASS(renderer)->set_linewidth(renderer, 0.0);
270 DIA_RENDERER_GET_CLASS(renderer)->set_dashlength(renderer,
271 ddisplay_untransform_length(ddisp, 31));
272 if (prefs.pagebreak.solid)
273 DIA_RENDERER_GET_CLASS(renderer)->set_linestyle(renderer, LINESTYLE_SOLID);
274 else
275 DIA_RENDERER_GET_CLASS(renderer)->set_linestyle(renderer, LINESTYLE_DOTTED);
277 if (dia->data->paper.fitto) {
278 origx = dia->data->extents.left;
279 origy = dia->data->extents.top;
282 /* vertical lines ... */
283 pos = origx + ceil((update->left - origx) / pwidth) * pwidth;
284 while (pos <= update->right) {
285 ddisplay_transform_coords(ddisp, pos,0,&x,&y);
286 irenderer->draw_pixel_line(renderer,
287 x, 0, x, height,
288 &dia->data->pagebreak_color);
289 pos += pwidth;
291 /* Horizontal lines: */
292 pos = origy + ceil((update->top - origy) / pheight) * pheight;
293 while (pos <= update->bottom) {
294 ddisplay_transform_coords(ddisp, 0,pos,&x,&y);
295 irenderer->draw_pixel_line(renderer,
296 0, y, width, y,
297 &dia->data->pagebreak_color);
298 pos += pheight;
303 void
304 snap_to_grid(DDisplay *ddisp, coord *x, coord *y)
306 if (ddisp->grid.snap) {
307 if (prefs.grid.hex) {
308 real width_x = ddisp->diagram->data->grid.width_w;
309 real x_mod = (*x - 1*width_x) - floor((*x - 1*width_x) / (3*width_x)) * 3 * width_x;
310 real y_mod = (*y - 0.25*sqrt(3) * width_x) -
311 floor((*y - 0.25 * sqrt(3) * width_x) / (sqrt(3)*width_x)) * sqrt(3) * width_x;
313 if ( x_mod < (1.5 * width_x) ) {
314 if ( y_mod < 0.5 * sqrt(3) * width_x ) {
315 *x = floor((*x + 0.5*width_x) / (3*width_x)) * 3 * width_x + 2 * width_x;
316 *y = floor((*y - 0.25 * sqrt(3) * width_x) / (sqrt(3)*width_x)) * sqrt(3) * width_x + 0.5 * sqrt(3) * width_x;
317 } else {
318 *x = floor((*x + 0.5*width_x) / (3*width_x)) * 3 * width_x + 1.5 * width_x;
319 *y = floor((*y - 0.25 * sqrt(3) * width_x) / (sqrt(3)*width_x)) * sqrt(3) * width_x + sqrt(3) * width_x;
321 } else {
322 if ( y_mod < 0.5 * sqrt(3) * width_x ) {
323 *x = floor((*x + 0.5*width_x) / (3*width_x)) * 3 * width_x ;
324 *y = floor((*y - 0.25 * sqrt(3) * width_x) / (sqrt(3)*width_x)) * sqrt(3) * width_x + 0.5 * sqrt(3) * width_x;
325 } else {
326 *x = floor((*x + 0.5*width_x) / (3*width_x)) * 3 * width_x + 0.5 * width_x;
327 *y = floor((*y - 0.25 * sqrt(3) * width_x) / (sqrt(3)*width_x)) * sqrt(3) * width_x + sqrt(3) * width_x;
330 } else {
331 real width_x = ddisp->diagram->data->grid.width_x;
332 real width_y = ddisp->diagram->data->grid.width_y;
333 if (prefs.grid.dynamic) {
334 calculate_dynamic_grid(ddisp, &width_x, &width_y);
336 *x = ROUND((*x) / width_x) * width_x;
337 *y = ROUND((*y) / width_y) * width_y;