gfig-grid.c 14.8 KB
Newer Older
1 2 3
/*
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
4
 * This is a plug-in for GIMP.
5 6 7 8 9
 *
 * Generates images containing vector type drawings.
 *
 * Copyright (C) 1997 Andy Thomas  alt@picnic.demon.co.uk
 *
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 14 15 16 17 18 19 20
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * 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 25 26 27 28
 */

#include "config.h"

#include <stdlib.h>

#include <libgimp/gimp.h>
29
#include <libgimp/gimpui.h>
30 31 32 33 34 35

#include "gfig.h"
#include "gfig-grid.h"

#include "libgimp/stdplugins-intl.h"

36

37 38 39 40 41 42 43
/* For the isometric grid */
#define SQRT3 1.73205080756887729353   /* Square root of 3 */
#define SIN_1o6PI_RAD 0.5              /* Sine    1/6 Pi Radians */
#define COS_1o6PI_RAD SQRT3 / 2        /* Cosine  1/6 Pi Radians */
#define TAN_1o6PI_RAD 1 / SQRT3        /* Tangent 1/6 Pi Radians == SIN / COS */
#define RECIP_TAN_1o6PI_RAD SQRT3      /* Reciprocal of Tangent 1/6 Pi Radians */

44
gint           grid_gc_type           = GFIG_NORMAL_GC;
45

46 47 48
static void    draw_grid_polar     (cairo_t  *drawgc);
static void    draw_grid_sq        (cairo_t  *drawgc);
static void    draw_grid_iso       (cairo_t  *drawgc);
David Odin's avatar
David Odin committed
49

50 51
static cairo_t * gfig_get_grid_gc  (cairo_t   *cr,
                                    GtkWidget *widget,
52 53 54 55
                                    gint       gctype);

static void    find_grid_pos_polar (GdkPoint  *p,
                                    GdkPoint  *gp);
56 57 58 59 60 61


/********** PrimeFactors for Shaneyfelt-style Polar Grid **********
 * Quickly factor any number up to 17160
 * Correctly factors numbers up to 131 * 131 - 1
 */
62
typedef struct
63
{
64 65 66 67 68
  gint product;
  gint remaining;
  gint current;
  gint next;
  gint index;
69 70
} PrimeFactors;

71 72 73 74
static gchar primes[] = { 2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,
                          59,61,67,71,73,79,83,89,97,101,103,107,109,113,127 };

#define PRIMES_MAX_INDEX 30
75

76 77

static gint
78 79
prime_factors_get (PrimeFactors *this)
{
80 81
  this->current = this->next;
  while (this->index <= PRIMES_MAX_INDEX)
82
    {
83
      if (this->remaining % primes[this->index] == 0)   /* divisible */
84 85 86 87
        {
          this->remaining /= primes[this->index];
          this->next = primes[this->index];
          return this->current;
88
        }
89
      this->index++;
90
    }
91 92 93 94
  this->next = this->remaining;
  this->remaining = 1;

  return this->current;
95 96
}

97
static gint
98 99
prime_factors_lookahead (PrimeFactors *this)
{
100
  return this->next;
101 102
}

103
static void
104 105
prime_factors_reset (PrimeFactors *this)
{
106 107 108
  this->remaining = this->product;
  this->index = 0;
  prime_factors_get (this);
109 110
}

111 112 113 114 115 116 117 118 119
static PrimeFactors *
prime_factors_new (gint n)
{
  PrimeFactors *this = g_new (PrimeFactors, 1);

  this->product = n;
  prime_factors_reset (this);

  return this;
120 121
}

122 123 124 125
static void
prime_factors_delete (PrimeFactors* this)
{
  g_free (this);
126 127 128 129
}

/********** ********** **********/

130
static gdouble
131 132
sector_size_at_radius (gdouble inner_radius)
{
133 134 135 136 137 138 139 140 141 142 143
  PrimeFactors *factors = prime_factors_new (selvals.opts.grid_sectors_desired);
  gint          current_sectors = 1;
  gdouble       sector_size     = 2 * G_PI / current_sectors;

  while ((current_sectors < selvals.opts.grid_sectors_desired)
         && (inner_radius*sector_size
             > (prime_factors_lookahead (factors) *
                selvals.opts.grid_granularity)))
    {
      current_sectors *= prime_factors_get (factors);
      sector_size = 2 * G_PI / current_sectors;
144
    }
145 146 147 148

  prime_factors_delete(factors);

  return sector_size;
149 150 151 152 153 154
}

static void
find_grid_pos_polar (GdkPoint *p,
                     GdkPoint *gp)
{
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
  gdouble cx = preview_width / 2.0;
  gdouble cy = preview_height / 2.0;
  gdouble px = p->x - cx;
  gdouble py = p->y - cy;
  gdouble x  = 0;
  gdouble y  = 0;
  gdouble r  = sqrt (SQR (px) + SQR (py));

  if (r >= selvals.opts.grid_radius_min * 0.5)
    {
      gdouble t;
      gdouble sectorSize;

      r = selvals.opts.grid_radius_interval
        * (gint) (0.5 + ((r - selvals.opts.grid_radius_min) /
                         selvals.opts.grid_radius_interval))
        + selvals.opts.grid_radius_min;

      t = atan2 (py, px) + 2 * G_PI;
      sectorSize = sector_size_at_radius (r);
      t = selvals.opts.grid_rotation
        + (gint) (0.5 + ((t - selvals.opts.grid_rotation) / sectorSize))
        * sectorSize;
      x = r * cos (t);
      y = r * sin (t);
180
    }
181 182 183

  gp->x = x + cx;
  gp->y = y + cy;
184
}
185 186 187 188 189

/* find_grid_pos - Given an x, y point return the grid position of it */
/* return the new position in the passed point */

void
190
gfig_grid_colors (GtkWidget *widget)
191 192 193 194 195
{
}

void
find_grid_pos (GdkPoint *p,
196 197
               GdkPoint *gp,
               guint     is_butt3)
198
{
199 200
  gint16          x = p->x;
  gint16          y = p->y;
201
  static GdkPoint cons_pnt;
202

203 204 205
  if (selvals.opts.gridtype == RECT_GRID)
    {
      if (p->x % selvals.opts.gridspacing > selvals.opts.gridspacing/2)
206
        x += selvals.opts.gridspacing;
207

208
      if (p->y % selvals.opts.gridspacing > selvals.opts.gridspacing/2)
209
        y += selvals.opts.gridspacing;
210

211 212 213 214
      gp->x = (x/selvals.opts.gridspacing)*selvals.opts.gridspacing;
      gp->y = (y/selvals.opts.gridspacing)*selvals.opts.gridspacing;

      if (is_butt3)
215 216 217 218 219 220
        {
          if (abs (gp->x - cons_pnt.x) < abs (gp->y - cons_pnt.y))
            gp->x = cons_pnt.x;
          else
            gp->y = cons_pnt.y;
        }
221
      else
222 223 224 225
        {
          /* Store the point since might be used later */
          cons_pnt = *gp; /* Structure copy */
        }
226 227
    }
  else if (selvals.opts.gridtype == POLAR_GRID)
228
    {
229
      find_grid_pos_polar (p,gp);
230 231 232 233 234 235
    }
  else if (selvals.opts.gridtype == ISO_GRID)
    {
      /*
       * This really needs a picture to show the math...
       *
236 237 238 239
       * Consider an isometric grid with one of the sets of lines
       * parallel to the y axis (vertical alignment). Further define
       * that the origin of a Cartesian grid is at a isometric vertex.
       * For simplicity consider the first quadrant only.
240
       *
241 242
       *  - Let one line segment between vertices be r
       *  - Define the value of r as the grid spacing
243 244 245
       *  - Assign an integer n identifier to each vertical grid line
       *    along the x axis.  with n=0 being the y axis. n can be any
       *    integer
246
       *  - Let m to be any integer
247 248 249 250

       *  - Let h be the spacing between vertical grid lines measured
       *    along the x axis.  It follows from the isometric grid that
       *    h has a value of r * COS(1/6 Pi Rad)
251
       *
252 253 254 255 256 257 258 259
       *  Consider a Vertex V at the Cartesian location [Xv, Yv]
       *
       *   It follows that vertices belong to the set...
       *   V[Xv, Yv] = [ [ n * h ] ,
       *                 [ m * r + ( 0.5 * r (n % 2) ) ] ]
       *   for all integers n and m
       *
       * Who cares? Me. It's useful in solving this problem:
260 261
       * Consider an arbitrary point P[Xp,Yp], find the closest vertex
       * in the set V.
262
       *
263 264
       * Restated this problem is "find values for m and n that are
       * drive V closest to P"
265
       *
266
       * A Solution method (there may be a better one?):
267
       *
268
       * Step 1) bound n to the two closest values for Xp
269
       *         n_lo = (int) (Xp / h)
270
       *         n_hi = n_lo + 1
271
       *
272 273 274 275
       * Step 2) Consider the two closes vertices for each n_lo and
       *         n_hi. The further of the vertices in each pair can
       *         readily be discarded.
       *
276 277 278 279 280
       *         m_lo_n_lo = (int) ( (Yp / r) - 0.5 (n_lo % 2) )
       *         m_hi_n_lo = m_lo_n_lo + 1
       *
       *         m_lo_n_hi = (int) ( (Yp / r) - 0.5 (n_hi % 2) )
       *         m_hi_n_hi = m_hi_n_hi
281
       *
282 283
       * Step 3) compute the distance from P to V1 and V2. Snap to the
       *         closer point.
284
       */
285

286 287 288 289 290 291 292 293 294 295 296 297 298 299
      gint n_lo;
      gint n_hi;
      gint m_lo_n_lo;
      gint m_hi_n_lo;
      gint m_lo_n_hi;
      gint m_hi_n_hi;
      gint m_n_lo;
      gint m_n_hi;
      gdouble r;
      gdouble h;
      gint x1;
      gint x2;
      gint y1;
      gint y2;
300

301 302
      r = selvals.opts.gridspacing;
      h = COS_1o6PI_RAD * r;
303

304 305
      n_lo = (gint) x / h;
      n_hi = n_lo + 1;
306

307
      /* evaluate m candidates for n_lo */
308
      m_lo_n_lo = (gint) ((y / r) - 0.5 * (n_lo % 2));
309
      m_hi_n_lo = m_lo_n_lo + 1;
310 311 312 313 314 315 316 317 318 319 320

     /* figure out which is the better candidate */
      if (abs ((m_lo_n_lo * r + (0.5 * r * (n_lo % 2))) - y) <
          abs ((m_hi_n_lo * r + (0.5 * r * (n_lo % 2))) - y))
        {
          m_n_lo = m_lo_n_lo;
        }
      else
        {
          m_n_lo = m_hi_n_lo;
        }
321

322 323 324
      /* evaluate m candidates for n_hi */
      m_lo_n_hi = (gint) ( (y / r) - 0.5 * (n_hi % 2) );
      m_hi_n_hi = m_lo_n_hi + 1;
325

326 327
      /* figure out which is the better candidate */
      if (abs((m_lo_n_hi * r + (0.5 * r * (n_hi % 2))) - y) <
328 329 330 331 332 333 334 335
          abs((m_hi_n_hi * r + (0.5 * r * (n_hi % 2))) - y))
        {
          m_n_hi = m_lo_n_hi;
        }
      else
        {
          m_n_hi = m_hi_n_hi;
        }
336

337 338 339 340
      /* Now, which is closer to [x,y]? we can use a somewhat
       * abbreviated form of the distance formula since we only care
       * about relative values.
       */
341 342 343 344 345

      x1 = (gint) (n_lo * h);
      y1 = (gint) (m_n_lo * r + (0.5 * r * (n_lo % 2)));
      x2 = (gint) (n_hi * h);
      y2 = (gint) (m_n_hi * r + (0.5 * r * (n_hi % 2)));
346 347

      if (((x - x1) * (x - x1) + (y - y1) * (y - y1)) <
348 349 350 351 352 353 354 355 356 357
          ((x - x2) * (x - x2) + (y - y2) * (y - y2)))
        {
          gp->x =  x1;
          gp->y =  y1;
        }
      else
        {
          gp->x =  x2;
          gp->y =  y2;
        }
358 359 360 361
    }
}

static void
362
draw_grid_polar (cairo_t *cr)
363
{
364 365 366 367 368 369 370 371 372
    gdouble       inner_radius;
    gdouble       outer_radius;
    gdouble       max_radius = sqrt (SQR (preview_width) + SQR (preview_height));
    gint          current_sectors = 1;
    PrimeFactors *factors = prime_factors_new (selvals.opts.grid_sectors_desired);
    for (inner_radius = 0, outer_radius = selvals.opts.grid_radius_min;
         outer_radius <= max_radius;
         inner_radius = outer_radius, outer_radius += selvals.opts.grid_radius_interval)
      {
373
        gdouble t;
374
        gdouble sector_size = 2 * G_PI / current_sectors;
375
        cairo_arc (cr,
376 377
                   0.5 + preview_width / 2.0,
                   0.5 + preview_height / 2.0,
378 379
                   outer_radius, 0, 2 * G_PI);
        cairo_stroke (cr);
380 381 382 383 384 385 386 387 388 389 390

        while ((current_sectors < selvals.opts.grid_sectors_desired)
               && (inner_radius * sector_size
                   > prime_factors_lookahead (factors) * selvals.opts.grid_granularity ))
          {
            current_sectors *= prime_factors_get (factors);
            sector_size = 2 * G_PI / current_sectors;
          }

        for (t = 0 ; t < 2 * G_PI ; t += sector_size)
          {
391 392
            gdouble normal_x = cos (selvals.opts.grid_rotation+t);
            gdouble normal_y = sin (selvals.opts.grid_rotation+t);
393
            cairo_move_to (cr,
394 395
                           0.5 + (preview_width / 2.0 + inner_radius * normal_x),
                           0.5 + (preview_height / 2.0 - inner_radius * normal_y));
396
            cairo_line_to (cr,
397 398
                           0.5 + (preview_width / 2.0 + outer_radius * normal_x),
                           0.5 + (preview_height / 2.0 - outer_radius * normal_y));
399
            cairo_stroke (cr);
400 401 402
          }
      }

403
    prime_factors_delete (factors);
404 405
}

406

407
static void
408
draw_grid_sq (cairo_t *cr)
409 410 411 412 413 414 415 416 417
{
  gint step;
  gint loop;

  /* Draw the horizontal lines */
  step = selvals.opts.gridspacing;

  for (loop = 0 ; loop < preview_height ; loop += step)
    {
418 419
      cairo_move_to (cr, 0 + .5, loop + .5);
      cairo_line_to (cr, preview_width + .5, loop + .5);
420 421 422 423 424 425
    }

  /* Draw the vertical lines */

  for (loop = 0 ; loop < preview_width ; loop += step)
    {
426 427
      cairo_move_to (cr, loop + .5, 0 + .5);
      cairo_line_to (cr, loop + .5, preview_height + .5);
428
    }
429
  cairo_stroke (cr);
430 431 432
}

static void
433
draw_grid_iso (cairo_t *cr)
434 435
{
  /* vstep is an int since it's defined from grid size */
436
  gint    vstep;
437 438
  gdouble loop;
  gdouble hstep;
439

440 441 442 443
  gdouble diagonal_start;
  gdouble diagonal_end;
  gdouble diagonal_width;
  gdouble diagonal_height;
444

445 446
  vstep = selvals.opts.gridspacing;
  hstep = selvals.opts.gridspacing * COS_1o6PI_RAD;
447

448
  /* Draw the vertical lines - These are easy */
449 450
  for (loop = 0 ; loop < preview_width ; loop += hstep)
    {
451 452
      cairo_move_to (cr, loop, 0);
      cairo_line_to (cr, loop, preview_height);
453
    }
454
  cairo_stroke (cr);
455

456
  /* draw diag lines at a Theta of +/- 1/6 Pi Rad */
457

458
  diagonal_start = -(((int)preview_width * TAN_1o6PI_RAD) - (((int)(preview_width * TAN_1o6PI_RAD)) % vstep));
459

460 461
  diagonal_end = preview_height + (preview_width * TAN_1o6PI_RAD);
  diagonal_end -= ((int)diagonal_end) % vstep;
462

463 464
  diagonal_width = preview_width;
  diagonal_height = preview_width * TAN_1o6PI_RAD;
465

466 467 468
  /* Draw diag lines */
  for (loop = diagonal_start ; loop < diagonal_end ; loop += vstep)
    {
469 470 471 472 473
      cairo_move_to (cr, 0, loop);
      cairo_line_to (cr, diagonal_width, loop + diagonal_height);

      cairo_move_to (cr, 0, loop);
      cairo_line_to (cr, diagonal_width, loop - diagonal_height);
474
    }
475
  cairo_stroke (cr);
476 477
}

478 479
static cairo_t *
gfig_get_grid_gc (cairo_t *cr, GtkWidget *w, gint gctype)
480 481 482
{
  switch (gctype)
    {
483 484 485 486
    default:
    case GFIG_NORMAL_GC:
      cairo_set_source_rgb (cr, .92, .92, .92);
      break;
487
    case GFIG_BLACK_GC:
488 489
      cairo_set_source_rgb (cr, 0., 0., 0.);
      break;
490
    case GFIG_WHITE_GC:
491 492
      cairo_set_source_rgb (cr, 1., 1., 1.);
      break;
493
    case GFIG_GREY_GC:
494 495 496 497 498 499 500 501 502 503 504
      cairo_set_source_rgb (cr, .5, .5, .5);
      break;
    case GFIG_DARKER_GC:
      cairo_set_source_rgb (cr, .25, .25, .25);
      break;
    case GFIG_LIGHTER_GC:
      cairo_set_source_rgb (cr, .75, .75, .75);
      break;
    case GFIG_VERY_DARK_GC:
      cairo_set_source_rgb (cr, .125, .125, .125);
      break;
505
    }
506 507

  return cr;
508 509 510
}

void
511
draw_grid (cairo_t *cr)
512 513 514 515 516 517 518
{
  /* Get the size of the preview and calc where the lines go */
  /* Draw in prelight to start with... */
  /* Always start in the upper left corner for rect.
   */

  if ((preview_width < selvals.opts.gridspacing &&
519
       preview_height < selvals.opts.gridspacing))
520 521 522 523 524 525
    {
      /* Don't draw if they don't fit */
      return;
    }

  if (selvals.opts.drawgrid)
526
    gfig_get_grid_gc (cr, gfig_context->preview, grid_gc_type);
527 528 529
  else
    return;

530
  cairo_set_line_width (cr, 1.);
531
  if (selvals.opts.gridtype == RECT_GRID)
532
    draw_grid_sq (cr);
533
  else if (selvals.opts.gridtype == POLAR_GRID)
534
    draw_grid_polar (cr);
535
  else if (selvals.opts.gridtype == ISO_GRID)
536
    draw_grid_iso (cr);
537 538 539
}