1 /*
2 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3 *
4 * This is a plug-in for GIMP.
5 *
6 * Generates images containing vector type drawings.
7 *
8 * Copyright (C) 1997 Andy Thomas alt@picnic.demon.co.uk
9 *
10 * This program is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 3 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <https://www.gnu.org/licenses/>.
22 */
23
24 #include "config.h"
25
26 #include <math.h>
27 #include <stdlib.h>
28
29 #include <libgimp/gimp.h>
30 #include <libgimp/gimpui.h>
31
32 #include "gfig.h"
33 #include "gfig-grid.h"
34
35 #include "libgimp/stdplugins-intl.h"
36
37
38 /* For the isometric grid */
39 #define SQRT3 1.73205080756887729353 /* Square root of 3 */
40 #define SIN_1o6PI_RAD 0.5 /* Sine 1/6 Pi Radians */
41 #define COS_1o6PI_RAD SQRT3 / 2 /* Cosine 1/6 Pi Radians */
42 #define TAN_1o6PI_RAD 1 / SQRT3 /* Tangent 1/6 Pi Radians == SIN / COS */
43 #define RECIP_TAN_1o6PI_RAD SQRT3 /* Reciprocal of Tangent 1/6 Pi Radians */
44
45 gint grid_gc_type = GFIG_NORMAL_GC;
46
47 static void draw_grid_polar (cairo_t *drawgc);
48 static void draw_grid_sq (cairo_t *drawgc);
49 static void draw_grid_iso (cairo_t *drawgc);
50
51 static cairo_t * gfig_get_grid_gc (cairo_t *cr,
52 GtkWidget *widget,
53 gint gctype);
54
55 static void find_grid_pos_polar (GdkPoint *p,
56 GdkPoint *gp);
57
58
59 /********** PrimeFactors for Shaneyfelt-style Polar Grid **********
60 * Quickly factor any number up to 17160
61 * Correctly factors numbers up to 131 * 131 - 1
62 */
63 typedef struct
64 {
65 gint product;
66 gint remaining;
67 gint current;
68 gint next;
69 gint index;
70 } PrimeFactors;
71
72 static gchar primes[] = { 2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,
73 59,61,67,71,73,79,83,89,97,101,103,107,109,113,127 };
74
75 #define PRIMES_MAX_INDEX 30
76
77
78 static gint
prime_factors_get(PrimeFactors * this)79 prime_factors_get (PrimeFactors *this)
80 {
81 this->current = this->next;
82 while (this->index <= PRIMES_MAX_INDEX)
83 {
84 if (this->remaining % primes[this->index] == 0) /* divisible */
85 {
86 this->remaining /= primes[this->index];
87 this->next = primes[this->index];
88 return this->current;
89 }
90 this->index++;
91 }
92 this->next = this->remaining;
93 this->remaining = 1;
94
95 return this->current;
96 }
97
98 static gint
prime_factors_lookahead(PrimeFactors * this)99 prime_factors_lookahead (PrimeFactors *this)
100 {
101 return this->next;
102 }
103
104 static void
prime_factors_reset(PrimeFactors * this)105 prime_factors_reset (PrimeFactors *this)
106 {
107 this->remaining = this->product;
108 this->index = 0;
109 prime_factors_get (this);
110 }
111
112 static PrimeFactors *
prime_factors_new(gint n)113 prime_factors_new (gint n)
114 {
115 PrimeFactors *this = g_new (PrimeFactors, 1);
116
117 this->product = n;
118 prime_factors_reset (this);
119
120 return this;
121 }
122
123 static void
prime_factors_delete(PrimeFactors * this)124 prime_factors_delete (PrimeFactors* this)
125 {
126 g_free (this);
127 }
128
129 /********** ********** **********/
130
131 static gdouble
sector_size_at_radius(gdouble inner_radius)132 sector_size_at_radius (gdouble inner_radius)
133 {
134 PrimeFactors *factors = prime_factors_new (selvals.opts.grid_sectors_desired);
135 gint current_sectors = 1;
136 gdouble sector_size = 2 * G_PI / current_sectors;
137
138 while ((current_sectors < selvals.opts.grid_sectors_desired)
139 && (inner_radius*sector_size
140 > (prime_factors_lookahead (factors) *
141 selvals.opts.grid_granularity)))
142 {
143 current_sectors *= prime_factors_get (factors);
144 sector_size = 2 * G_PI / current_sectors;
145 }
146
147 prime_factors_delete(factors);
148
149 return sector_size;
150 }
151
152 static void
find_grid_pos_polar(GdkPoint * p,GdkPoint * gp)153 find_grid_pos_polar (GdkPoint *p,
154 GdkPoint *gp)
155 {
156 gdouble cx = preview_width / 2.0;
157 gdouble cy = preview_height / 2.0;
158 gdouble px = p->x - cx;
159 gdouble py = p->y - cy;
160 gdouble x = 0;
161 gdouble y = 0;
162 gdouble r = sqrt (SQR (px) + SQR (py));
163
164 if (r >= selvals.opts.grid_radius_min * 0.5)
165 {
166 gdouble t;
167 gdouble sectorSize;
168
169 r = selvals.opts.grid_radius_interval
170 * (gint) (0.5 + ((r - selvals.opts.grid_radius_min) /
171 selvals.opts.grid_radius_interval))
172 + selvals.opts.grid_radius_min;
173
174 t = atan2 (py, px) + 2 * G_PI;
175 sectorSize = sector_size_at_radius (r);
176 t = selvals.opts.grid_rotation
177 + (gint) (0.5 + ((t - selvals.opts.grid_rotation) / sectorSize))
178 * sectorSize;
179 x = r * cos (t);
180 y = r * sin (t);
181 }
182
183 gp->x = x + cx;
184 gp->y = y + cy;
185 }
186
187 /* find_grid_pos - Given an x, y point return the grid position of it */
188 /* return the new position in the passed point */
189
190 void
gfig_grid_colors(GtkWidget * widget)191 gfig_grid_colors (GtkWidget *widget)
192 {
193 }
194
195 void
find_grid_pos(GdkPoint * p,GdkPoint * gp,guint is_butt3)196 find_grid_pos (GdkPoint *p,
197 GdkPoint *gp,
198 guint is_butt3)
199 {
200 gint16 x = p->x;
201 gint16 y = p->y;
202 static GdkPoint cons_pnt;
203
204 if (selvals.opts.gridtype == RECT_GRID)
205 {
206 if (p->x % selvals.opts.gridspacing > selvals.opts.gridspacing/2)
207 x += selvals.opts.gridspacing;
208
209 if (p->y % selvals.opts.gridspacing > selvals.opts.gridspacing/2)
210 y += selvals.opts.gridspacing;
211
212 gp->x = (x/selvals.opts.gridspacing)*selvals.opts.gridspacing;
213 gp->y = (y/selvals.opts.gridspacing)*selvals.opts.gridspacing;
214
215 if (is_butt3)
216 {
217 if (abs (gp->x - cons_pnt.x) < abs (gp->y - cons_pnt.y))
218 gp->x = cons_pnt.x;
219 else
220 gp->y = cons_pnt.y;
221 }
222 else
223 {
224 /* Store the point since might be used later */
225 cons_pnt = *gp; /* Structure copy */
226 }
227 }
228 else if (selvals.opts.gridtype == POLAR_GRID)
229 {
230 find_grid_pos_polar (p,gp);
231 }
232 else if (selvals.opts.gridtype == ISO_GRID)
233 {
234 /*
235 * This really needs a picture to show the math...
236 *
237 * Consider an isometric grid with one of the sets of lines
238 * parallel to the y axis (vertical alignment). Further define
239 * that the origin of a Cartesian grid is at a isometric vertex.
240 * For simplicity consider the first quadrant only.
241 *
242 * - Let one line segment between vertices be r
243 * - Define the value of r as the grid spacing
244 * - Assign an integer n identifier to each vertical grid line
245 * along the x axis. with n=0 being the y axis. n can be any
246 * integer
247 * - Let m to be any integer
248
249 * - Let h be the spacing between vertical grid lines measured
250 * along the x axis. It follows from the isometric grid that
251 * h has a value of r * COS(1/6 Pi Rad)
252 *
253 * Consider a Vertex V at the Cartesian location [Xv, Yv]
254 *
255 * It follows that vertices belong to the set...
256 * V[Xv, Yv] = [ [ n * h ] ,
257 * [ m * r + ( 0.5 * r (n % 2) ) ] ]
258 * for all integers n and m
259 *
260 * Who cares? Me. It's useful in solving this problem:
261 * Consider an arbitrary point P[Xp,Yp], find the closest vertex
262 * in the set V.
263 *
264 * Restated this problem is "find values for m and n that are
265 * drive V closest to P"
266 *
267 * A Solution method (there may be a better one?):
268 *
269 * Step 1) bound n to the two closest values for Xp
270 * n_lo = (int) (Xp / h)
271 * n_hi = n_lo + 1
272 *
273 * Step 2) Consider the two closes vertices for each n_lo and
274 * n_hi. The further of the vertices in each pair can
275 * readily be discarded.
276 *
277 * m_lo_n_lo = (int) ( (Yp / r) - 0.5 (n_lo % 2) )
278 * m_hi_n_lo = m_lo_n_lo + 1
279 *
280 * m_lo_n_hi = (int) ( (Yp / r) - 0.5 (n_hi % 2) )
281 * m_hi_n_hi = m_hi_n_hi
282 *
283 * Step 3) compute the distance from P to V1 and V2. Snap to the
284 * closer point.
285 */
286
287 gint n_lo;
288 gint n_hi;
289 gint m_lo_n_lo;
290 gint m_hi_n_lo;
291 gint m_lo_n_hi;
292 gint m_hi_n_hi;
293 gint m_n_lo;
294 gint m_n_hi;
295 gdouble r;
296 gdouble h;
297 gint x1;
298 gint x2;
299 gint y1;
300 gint y2;
301
302 r = selvals.opts.gridspacing;
303 h = COS_1o6PI_RAD * r;
304
305 n_lo = (gint) x / h;
306 n_hi = n_lo + 1;
307
308 /* evaluate m candidates for n_lo */
309 m_lo_n_lo = (gint) ((y / r) - 0.5 * (n_lo % 2));
310 m_hi_n_lo = m_lo_n_lo + 1;
311
312 /* figure out which is the better candidate */
313 if (fabs ((m_lo_n_lo * r + (0.5 * r * (n_lo % 2))) - y) <
314 fabs ((m_hi_n_lo * r + (0.5 * r * (n_lo % 2))) - y))
315 {
316 m_n_lo = m_lo_n_lo;
317 }
318 else
319 {
320 m_n_lo = m_hi_n_lo;
321 }
322
323 /* evaluate m candidates for n_hi */
324 m_lo_n_hi = (gint) ( (y / r) - 0.5 * (n_hi % 2) );
325 m_hi_n_hi = m_lo_n_hi + 1;
326
327 /* figure out which is the better candidate */
328 if (fabs((m_lo_n_hi * r + (0.5 * r * (n_hi % 2))) - y) <
329 fabs((m_hi_n_hi * r + (0.5 * r * (n_hi % 2))) - y))
330 {
331 m_n_hi = m_lo_n_hi;
332 }
333 else
334 {
335 m_n_hi = m_hi_n_hi;
336 }
337
338 /* Now, which is closer to [x,y]? we can use a somewhat
339 * abbreviated form of the distance formula since we only care
340 * about relative values.
341 */
342
343 x1 = (gint) (n_lo * h);
344 y1 = (gint) (m_n_lo * r + (0.5 * r * (n_lo % 2)));
345 x2 = (gint) (n_hi * h);
346 y2 = (gint) (m_n_hi * r + (0.5 * r * (n_hi % 2)));
347
348 if (((x - x1) * (x - x1) + (y - y1) * (y - y1)) <
349 ((x - x2) * (x - x2) + (y - y2) * (y - y2)))
350 {
351 gp->x = x1;
352 gp->y = y1;
353 }
354 else
355 {
356 gp->x = x2;
357 gp->y = y2;
358 }
359 }
360 }
361
362 static void
draw_grid_polar(cairo_t * cr)363 draw_grid_polar (cairo_t *cr)
364 {
365 gdouble inner_radius;
366 gdouble outer_radius;
367 gdouble max_radius = sqrt (SQR (preview_width) + SQR (preview_height));
368 gint current_sectors = 1;
369 PrimeFactors *factors = prime_factors_new (selvals.opts.grid_sectors_desired);
370 for (inner_radius = 0, outer_radius = selvals.opts.grid_radius_min;
371 outer_radius <= max_radius;
372 inner_radius = outer_radius, outer_radius += selvals.opts.grid_radius_interval)
373 {
374 gdouble t;
375 gdouble sector_size = 2 * G_PI / current_sectors;
376 cairo_arc (cr,
377 0.5 + preview_width / 2.0,
378 0.5 + preview_height / 2.0,
379 outer_radius, 0, 2 * G_PI);
380 cairo_stroke (cr);
381
382 while ((current_sectors < selvals.opts.grid_sectors_desired)
383 && (inner_radius * sector_size
384 > prime_factors_lookahead (factors) * selvals.opts.grid_granularity ))
385 {
386 current_sectors *= prime_factors_get (factors);
387 sector_size = 2 * G_PI / current_sectors;
388 }
389
390 for (t = 0 ; t < 2 * G_PI ; t += sector_size)
391 {
392 gdouble normal_x = cos (selvals.opts.grid_rotation+t);
393 gdouble normal_y = sin (selvals.opts.grid_rotation+t);
394 cairo_move_to (cr,
395 0.5 + (preview_width / 2.0 + inner_radius * normal_x),
396 0.5 + (preview_height / 2.0 - inner_radius * normal_y));
397 cairo_line_to (cr,
398 0.5 + (preview_width / 2.0 + outer_radius * normal_x),
399 0.5 + (preview_height / 2.0 - outer_radius * normal_y));
400 cairo_stroke (cr);
401 }
402 }
403
404 prime_factors_delete (factors);
405 }
406
407
408 static void
draw_grid_sq(cairo_t * cr)409 draw_grid_sq (cairo_t *cr)
410 {
411 gint step;
412 gint loop;
413
414 /* Draw the horizontal lines */
415 step = selvals.opts.gridspacing;
416
417 for (loop = 0 ; loop < preview_height ; loop += step)
418 {
419 cairo_move_to (cr, 0 + .5, loop + .5);
420 cairo_line_to (cr, preview_width + .5, loop + .5);
421 }
422
423 /* Draw the vertical lines */
424
425 for (loop = 0 ; loop < preview_width ; loop += step)
426 {
427 cairo_move_to (cr, loop + .5, 0 + .5);
428 cairo_line_to (cr, loop + .5, preview_height + .5);
429 }
430 cairo_stroke (cr);
431 }
432
433 static void
draw_grid_iso(cairo_t * cr)434 draw_grid_iso (cairo_t *cr)
435 {
436 /* vstep is an int since it's defined from grid size */
437 gint vstep;
438 gdouble loop;
439 gdouble hstep;
440
441 gdouble diagonal_start;
442 gdouble diagonal_end;
443 gdouble diagonal_width;
444 gdouble diagonal_height;
445
446 vstep = selvals.opts.gridspacing;
447 hstep = selvals.opts.gridspacing * COS_1o6PI_RAD;
448
449 /* Draw the vertical lines - These are easy */
450 for (loop = 0 ; loop < preview_width ; loop += hstep)
451 {
452 cairo_move_to (cr, loop, 0);
453 cairo_line_to (cr, loop, preview_height);
454 }
455 cairo_stroke (cr);
456
457 /* draw diag lines at a Theta of +/- 1/6 Pi Rad */
458
459 diagonal_start = -(((int)preview_width * TAN_1o6PI_RAD) - (((int)(preview_width * TAN_1o6PI_RAD)) % vstep));
460
461 diagonal_end = preview_height + (preview_width * TAN_1o6PI_RAD);
462 diagonal_end -= ((int)diagonal_end) % vstep;
463
464 diagonal_width = preview_width;
465 diagonal_height = preview_width * TAN_1o6PI_RAD;
466
467 /* Draw diag lines */
468 for (loop = diagonal_start ; loop < diagonal_end ; loop += vstep)
469 {
470 cairo_move_to (cr, 0, loop);
471 cairo_line_to (cr, diagonal_width, loop + diagonal_height);
472
473 cairo_move_to (cr, 0, loop);
474 cairo_line_to (cr, diagonal_width, loop - diagonal_height);
475 }
476 cairo_stroke (cr);
477 }
478
479 static cairo_t *
gfig_get_grid_gc(cairo_t * cr,GtkWidget * w,gint gctype)480 gfig_get_grid_gc (cairo_t *cr, GtkWidget *w, gint gctype)
481 {
482 switch (gctype)
483 {
484 default:
485 case GFIG_NORMAL_GC:
486 cairo_set_source_rgb (cr, .92, .92, .92);
487 break;
488 case GFIG_BLACK_GC:
489 cairo_set_source_rgb (cr, 0., 0., 0.);
490 break;
491 case GFIG_WHITE_GC:
492 cairo_set_source_rgb (cr, 1., 1., 1.);
493 break;
494 case GFIG_GREY_GC:
495 cairo_set_source_rgb (cr, .5, .5, .5);
496 break;
497 case GFIG_DARKER_GC:
498 cairo_set_source_rgb (cr, .25, .25, .25);
499 break;
500 case GFIG_LIGHTER_GC:
501 cairo_set_source_rgb (cr, .75, .75, .75);
502 break;
503 case GFIG_VERY_DARK_GC:
504 cairo_set_source_rgb (cr, .125, .125, .125);
505 break;
506 }
507
508 return cr;
509 }
510
511 void
draw_grid(cairo_t * cr)512 draw_grid (cairo_t *cr)
513 {
514 /* Get the size of the preview and calc where the lines go */
515 /* Draw in prelight to start with... */
516 /* Always start in the upper left corner for rect.
517 */
518
519 if ((preview_width < selvals.opts.gridspacing &&
520 preview_height < selvals.opts.gridspacing))
521 {
522 /* Don't draw if they don't fit */
523 return;
524 }
525
526 if (selvals.opts.drawgrid)
527 gfig_get_grid_gc (cr, gfig_context->preview, grid_gc_type);
528 else
529 return;
530
531 cairo_set_line_width (cr, 1.);
532 if (selvals.opts.gridtype == RECT_GRID)
533 draw_grid_sq (cr);
534 else if (selvals.opts.gridtype == POLAR_GRID)
535 draw_grid_polar (cr);
536 else if (selvals.opts.gridtype == ISO_GRID)
537 draw_grid_iso (cr);
538 }
539
540
541