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.
30 #include "preferences.h"
32 /** Calculate the width (in cm) of the gap between grid lines in dynamic
36 calculate_dynamic_grid(DDisplay
*ddisp
, real
*width_x
, real
*width_y
)
38 real zoom
= ddisplay_untransform_length(ddisp
, 1.0);
40 /* Twiddle zoom to make change-over appropriate */
42 ret
= pow(10, ceil(log10(zoom
)));
43 /* dont' make it too small or huge (this is in pixels) */
44 tmp
= ddisplay_transform_length(ddisp
, ret
);
54 grid_draw_horizontal_lines(DDisplay
*ddisp
, Rectangle
*update
, real length
)
59 guint major_lines
= ddisp
->diagram
->grid
.major_lines
;
60 DiaRenderer
*renderer
= ddisp
->renderer
;
61 DiaInteractiveRendererInterface
*irenderer
;
64 irenderer
= DIA_GET_INTERACTIVE_RENDERER_INTERFACE (renderer
);
66 pos
= ceil( update
->top
/ length
) * length
;
67 ddisplay_transform_coords(ddisp
, update
->left
, pos
, &x
, &y
);
68 ddisplay_transform_coords(ddisp
, update
->right
, update
->bottom
, &width
, &height
);
71 Explanatory note from Lawrence Withers (lwithers@users.sf.net):
72 Think about it in terms of the maths and the modulo arithmetic; we
73 have a number P such that P < 0, and we want to find a number Q
74 such that Q >= 0, but (P % major_count) == (Q % major_count). To
75 do this, we say Q = P - (P * major_count), which is guaranteed to
76 give a correct answer if major_count > 0 (since the addition of
77 anf multiple of major_count won't alter the modulo).
81 major_count
= pos
/length
;
82 if(major_count
< 0) major_count
-= major_lines
* major_count
;
83 major_count
%= major_lines
;
89 DIA_RENDERER_GET_CLASS(renderer
)->set_linestyle(renderer
, LINESTYLE_SOLID
);
91 DIA_RENDERER_GET_CLASS(renderer
)->set_linestyle(renderer
, LINESTYLE_DOTTED
);
92 major_count
= (major_count
+1)%major_lines
;
94 irenderer
->draw_pixel_line(renderer
, x
, y
, width
, y
,
95 &ddisp
->diagram
->grid
.colour
);
97 ddisplay_transform_coords(ddisp
, update
->left
, pos
, &x
, &y
);
102 grid_draw_vertical_lines(DDisplay
*ddisp
, Rectangle
*update
, real length
)
107 guint major_lines
= ddisp
->diagram
->grid
.major_lines
;
108 DiaRenderer
*renderer
= ddisp
->renderer
;
109 DiaInteractiveRendererInterface
*irenderer
;
112 irenderer
= DIA_GET_INTERACTIVE_RENDERER_INTERFACE (renderer
);
114 pos
= ceil( update
->left
/ length
) * length
;
115 ddisplay_transform_coords(ddisp
, update
->right
, update
->bottom
, &width
, &height
);
118 major_count
= pos
/length
;
119 if(major_count
< 0) major_count
-= major_lines
* major_count
;
120 major_count
%= major_lines
;
124 ddisplay_transform_coords(ddisp
, pos
, update
->top
, &x
, &y
);
126 if (major_count
== 0)
127 DIA_RENDERER_GET_CLASS(renderer
)->set_linestyle(renderer
, LINESTYLE_SOLID
);
129 DIA_RENDERER_GET_CLASS(renderer
)->set_linestyle(renderer
, LINESTYLE_DOTTED
);
130 major_count
= (major_count
+1)%major_lines
;
132 irenderer
->draw_pixel_line(renderer
, x
, y
, x
, height
,
133 &ddisp
->diagram
->grid
.colour
);
139 grid_draw_hex(DDisplay
*ddisp
, Rectangle
*update
, real length
)
141 real horiz_pos
, vert_pos
;
142 int to_x
, to_y
, x
, y
;
143 DiaRenderer
*renderer
= ddisp
->renderer
;
144 DiaInteractiveRendererInterface
*irenderer
;
146 irenderer
= DIA_GET_INTERACTIVE_RENDERER_INTERFACE (renderer
);
148 /* First horizontal lines: */
149 vert_pos
= ceil( update
->top
/ (length
* sqrt(3)) ) * length
* sqrt(3);
150 while (vert_pos
<= update
->bottom
) {
151 horiz_pos
= ceil( (update
->left
) / (3 * length
) ) * length
* 3 - length
* 2.5;
152 while (horiz_pos
<= update
->right
) {
153 ddisplay_transform_coords(ddisp
, horiz_pos
, vert_pos
, &x
, &y
);
154 ddisplay_transform_coords(ddisp
, horiz_pos
+ length
, vert_pos
, &to_x
, &y
);
156 irenderer
->draw_pixel_line(renderer
,
158 &ddisp
->diagram
->grid
.colour
);
159 horiz_pos
+= 3 * length
;
162 vert_pos
+= sqrt(3) * length
;
165 /* Second horizontal lines: */
166 vert_pos
= ceil( update
->top
/ (length
* sqrt(3)) ) * length
* sqrt(3) - 0.5 * sqrt(3) * length
;
167 while (vert_pos
<= update
->bottom
) {
168 horiz_pos
= ceil( (update
->left
) / (3 * length
) ) * length
* 3 - length
;
169 while (horiz_pos
<= update
->right
) {
170 ddisplay_transform_coords(ddisp
, horiz_pos
, vert_pos
, &x
, &y
);
171 ddisplay_transform_coords(ddisp
, horiz_pos
+length
, vert_pos
, &to_x
, &y
);
173 irenderer
->draw_pixel_line(renderer
,
175 &ddisp
->diagram
->grid
.colour
);
176 horiz_pos
+= 3 * length
;
179 vert_pos
+= sqrt(3) * length
;
182 /* First \'s and /'s */
183 vert_pos
= ceil( update
->top
/ (length
* sqrt(3)) ) * length
* sqrt(3) - length
* sqrt(3);
184 while (vert_pos
<= update
->bottom
) {
185 horiz_pos
= ceil( (update
->left
) / (3 * length
) ) * length
* 3 - length
* 2.5;
186 while (horiz_pos
<= update
->right
) {
187 ddisplay_transform_coords(ddisp
, horiz_pos
+ length
, vert_pos
, &x
, &y
);
188 ddisplay_transform_coords(ddisp
, horiz_pos
+ 1.5 * length
, vert_pos
+ length
* sqrt(3) * 0.5, &to_x
, &to_y
);
190 irenderer
->draw_pixel_line(renderer
,
192 &ddisp
->diagram
->grid
.colour
);
194 ddisplay_transform_coords(ddisp
, horiz_pos
, vert_pos
, &x
, &y
);
195 ddisplay_transform_coords(ddisp
, horiz_pos
- 0.5 * length
, vert_pos
+ length
* sqrt(3) * 0.5, &to_x
, &to_y
);
197 irenderer
->draw_pixel_line(renderer
,
199 &ddisp
->diagram
->grid
.colour
);
200 horiz_pos
+= 3 * length
;
203 vert_pos
+= sqrt(3) * length
;
206 /* Second \'s and /'s */
207 vert_pos
= ceil( update
->top
/ (length
* sqrt(3)) ) * length
* sqrt(3) - 0.5 * sqrt(3) * length
;
208 while (vert_pos
<= update
->bottom
) {
209 horiz_pos
= ceil( (update
->left
) / (3 * length
) ) * length
* 3 - length
;
210 while (horiz_pos
<= update
->right
) {
211 ddisplay_transform_coords(ddisp
, horiz_pos
, vert_pos
, &x
, &y
);
212 ddisplay_transform_coords(ddisp
, horiz_pos
- 0.5 * length
, vert_pos
+ 0.5 * sqrt(3) * length
, &to_x
, &to_y
);
214 irenderer
->draw_pixel_line(renderer
,
216 &ddisp
->diagram
->grid
.colour
);
218 ddisplay_transform_coords(ddisp
, horiz_pos
+ length
, vert_pos
, &x
, &y
);
219 ddisplay_transform_coords(ddisp
, horiz_pos
+ 1.5 * length
, vert_pos
+ 0.5 * sqrt(3) * length
, &to_x
, &to_y
);
221 irenderer
->draw_pixel_line(renderer
,
223 &ddisp
->diagram
->grid
.colour
);
224 horiz_pos
+= 3 * length
;
227 vert_pos
+= sqrt(3) * length
;
233 grid_draw(DDisplay
*ddisp
, Rectangle
*update
)
235 Grid
*grid
= &ddisp
->grid
;
236 DiaRenderer
*renderer
= ddisp
->renderer
;
239 /* distance between visible grid lines */
240 real width_x
= ddisp
->diagram
->grid
.width_x
;
241 real width_y
= ddisp
->diagram
->grid
.width_y
;
242 real width_w
= ddisp
->diagram
->grid
.width_w
;
243 if (ddisp
->diagram
->grid
.dynamic
) {
244 calculate_dynamic_grid(ddisp
, &width_x
, &width_y
);
246 width_x
= ddisp
->diagram
->grid
.width_x
*
247 ddisp
->diagram
->grid
.visible_x
;
248 width_y
= ddisp
->diagram
->grid
.width_y
*
249 ddisp
->diagram
->grid
.visible_y
;
252 DIA_RENDERER_GET_CLASS(renderer
)->set_linewidth(renderer
, 0.0);
253 DIA_RENDERER_GET_CLASS(renderer
)->set_dashlength(renderer
,
254 ddisplay_untransform_length(ddisp
, 31));
256 if (ddisp
->diagram
->grid
.hex
) {
257 grid_draw_hex(ddisp
, update
, width_w
);
259 if (ddisplay_transform_length(ddisp
, width_y
) >= 2.0 &&
260 ddisplay_transform_length(ddisp
, width_x
) >= 2.0) {
261 /* Vertical lines: */
262 grid_draw_vertical_lines(ddisp
, update
, width_x
);
263 /* Horizontal lines: */
264 grid_draw_horizontal_lines(ddisp
, update
, width_y
);
271 pagebreak_draw(DDisplay
*ddisp
, Rectangle
*update
)
273 DiaRenderer
*renderer
= ddisp
->renderer
;
274 DiaInteractiveRendererInterface
*irenderer
;
276 int width
= dia_renderer_get_width_pixels(ddisp
->renderer
);
277 int height
= dia_renderer_get_height_pixels(ddisp
->renderer
);
279 irenderer
= DIA_GET_INTERACTIVE_RENDERER_INTERFACE (renderer
);
280 if (prefs
.pagebreak
.visible
) {
281 Diagram
*dia
= ddisp
->diagram
;
282 real origx
= 0, origy
= 0, pos
;
283 real pwidth
= dia
->data
->paper
.width
;
284 real pheight
= dia
->data
->paper
.height
;
287 DIA_RENDERER_GET_CLASS(renderer
)->set_linewidth(renderer
, 0.0);
288 DIA_RENDERER_GET_CLASS(renderer
)->set_dashlength(renderer
,
289 ddisplay_untransform_length(ddisp
, 31));
290 if (prefs
.pagebreak
.solid
)
291 DIA_RENDERER_GET_CLASS(renderer
)->set_linestyle(renderer
, LINESTYLE_SOLID
);
293 DIA_RENDERER_GET_CLASS(renderer
)->set_linestyle(renderer
, LINESTYLE_DOTTED
);
295 if (dia
->data
->paper
.fitto
) {
296 origx
= dia
->data
->extents
.left
;
297 origy
= dia
->data
->extents
.top
;
300 /* vertical lines ... */
301 pos
= origx
+ ceil((update
->left
- origx
) / pwidth
) * pwidth
;
302 while (pos
<= update
->right
) {
303 ddisplay_transform_coords(ddisp
, pos
,0,&x
,&y
);
304 irenderer
->draw_pixel_line(renderer
,
306 &dia
->pagebreak_color
);
309 /* Horizontal lines: */
310 pos
= origy
+ ceil((update
->top
- origy
) / pheight
) * pheight
;
311 while (pos
<= update
->bottom
) {
312 ddisplay_transform_coords(ddisp
, 0,pos
,&x
,&y
);
313 irenderer
->draw_pixel_line(renderer
,
315 &dia
->pagebreak_color
);
322 snap_to_grid(DDisplay
*ddisp
, coord
*x
, coord
*y
)
324 if (ddisp
->grid
.snap
) {
325 if (ddisp
->diagram
->grid
.hex
) {
326 real width_x
= ddisp
->diagram
->grid
.width_w
;
327 real x_mod
= (*x
- 1*width_x
) - floor((*x
- 1*width_x
) / (3*width_x
)) * 3 * width_x
;
328 real y_mod
= (*y
- 0.25*sqrt(3) * width_x
) -
329 floor((*y
- 0.25 * sqrt(3) * width_x
) / (sqrt(3)*width_x
)) * sqrt(3) * width_x
;
331 if ( x_mod
< (1.5 * width_x
) ) {
332 if ( y_mod
< 0.5 * sqrt(3) * width_x
) {
333 *x
= floor((*x
+ 0.5*width_x
) / (3*width_x
)) * 3 * width_x
+ 2 * width_x
;
334 *y
= floor((*y
- 0.25 * sqrt(3) * width_x
) / (sqrt(3)*width_x
)) * sqrt(3) * width_x
+ 0.5 * sqrt(3) * width_x
;
336 *x
= floor((*x
+ 0.5*width_x
) / (3*width_x
)) * 3 * width_x
+ 1.5 * width_x
;
337 *y
= floor((*y
- 0.25 * sqrt(3) * width_x
) / (sqrt(3)*width_x
)) * sqrt(3) * width_x
+ sqrt(3) * width_x
;
340 if ( y_mod
< 0.5 * sqrt(3) * width_x
) {
341 *x
= floor((*x
+ 0.5*width_x
) / (3*width_x
)) * 3 * width_x
;
342 *y
= floor((*y
- 0.25 * sqrt(3) * width_x
) / (sqrt(3)*width_x
)) * sqrt(3) * width_x
+ 0.5 * sqrt(3) * width_x
;
344 *x
= floor((*x
+ 0.5*width_x
) / (3*width_x
)) * 3 * width_x
+ 0.5 * width_x
;
345 *y
= floor((*y
- 0.25 * sqrt(3) * width_x
) / (sqrt(3)*width_x
)) * sqrt(3) * width_x
+ sqrt(3) * width_x
;
349 real width_x
= ddisp
->diagram
->grid
.width_x
;
350 real width_y
= ddisp
->diagram
->grid
.width_y
;
351 if (ddisp
->diagram
->grid
.dynamic
) {
352 calculate_dynamic_grid(ddisp
, &width_x
, &width_y
);
354 *x
= ROUND((*x
) / width_x
) * width_x
;
355 *y
= ROUND((*y
) / width_y
) * width_y
;