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