2
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
4
* This is a plug-in for the GIMP.
6
* Generates images containing vector type drawings.
8
* 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 2 of the License, or
13
* (at your option) any later version.
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.
20
* You should have received a copy of the GNU General Public License
21
* along with this program; if not, write to the Free Software
22
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
35
#include <libgimp/gimp.h>
38
#include "gfig-dobject.h"
40
#include "libgimp/stdplugins-intl.h"
42
static gdouble dist (gdouble x1,
47
static void mid_point (gdouble x1,
54
static gdouble line_grad (gdouble x1,
59
static gdouble line_cons (gdouble x,
63
static void line_definition (gdouble x1,
70
static void arc_details (GdkPoint *vert_a,
76
static gdouble arc_angle (GdkPoint *pnt,
79
static void arc_drawing_details (GfigObject *obj,
87
static void d_draw_arc (GfigObject *obj);
89
static void d_paint_arc (GfigObject *obj);
91
static GfigObject *d_copy_arc (GfigObject *obj);
93
static void d_update_arc_line (GdkPoint *pnt);
94
static void d_update_arc (GdkPoint *pnt);
95
static void d_arc_line_start (GdkPoint *pnt,
97
static void d_arc_line_end (GdkPoint *pnt,
100
/* Distance between two points. */
111
return sqrt (s1 * s1 + s2 * s2);
114
/* Mid point of line returned */
116
mid_point (gdouble x1,
123
*mx = (x1 + x2) / 2.0;
124
*my = (y1 + y2) / 2.0;
127
/* Careful about infinite grads */
129
line_grad (gdouble x1,
139
return (dx == 0.0) ? 0.0 : dy / dx;
142
/* Constant of line that goes through x, y with grad lgrad */
144
line_cons (gdouble x,
148
return y - lgrad * x;
151
/* Get grad & const for perpend. line to given points */
153
line_definition (gdouble x1,
163
grad1 = line_grad (x1, y1, x2, y2);
168
printf ("Infinite grad....\n");
173
mid_point (x1, y1, x2, y2, &midx, &midy);
175
/* Invert grad for perpen gradient */
177
*lgrad = -1.0 / grad1;
179
*lconst = line_cons (midx, midy,*lgrad);
183
* Given three points get arc radius and the co-ords
188
arc_details (GdkPoint *vert_a,
191
GdkPoint *center_pnt,
194
/* Only vertices are in whole numbers - everything else is in doubles */
199
double len_a, len_b, len_c;
202
double circumcircle_R;
203
double line1_grad, line1_const;
204
double line2_grad, line2_const;
205
double inter_x = 0.0, inter_y = 0.0;
206
int got_x = 0, got_y = 0;
208
ax = (double) (vert_a->x);
209
ay = (double) (vert_a->y);
210
bx = (double) (vert_b->x);
211
by = (double) (vert_b->y);
212
cx = (double) (vert_c->x);
213
cy = (double) (vert_c->y);
215
len_a = dist (ax, ay, bx, by);
216
len_b = dist (bx, by, cx, cy);
217
len_c = dist (cx, cy, ax, ay);
219
sum_sides2 = (fabs (len_a) + fabs (len_b) + fabs (len_c))/2;
222
area = sqrt (sum_sides2 * (sum_sides2 - len_a) *
223
(sum_sides2 - len_b) *
224
(sum_sides2 - len_c));
227
circumcircle_R = len_a * len_b * len_c / (4 * area);
228
*radius = circumcircle_R;
230
/* Deal with exceptions - I hate exceptions */
232
if (ax == bx || ax == cx || cx == bx)
234
/* vert line -> mid point gives inter_x */
235
if (ax == bx && bx == cx)
253
inter_y = (maxy - miny) / 2 + miny;
257
inter_y = (ay - by) / 2 + by;
261
inter_y = (by - cy) / 2 + cy;
265
inter_y = (cy - ay) / 2 + ay;
270
if (ay == by || by == cy || ay == cy)
272
/* Horz line -> midpoint gives inter_y */
273
if (ax == bx && bx == cx)
291
inter_x = (maxx - minx) / 2 + minx;
295
inter_x = (ax - bx) / 2 + bx;
299
inter_x = (bx - cx) / 2 + cx;
303
inter_x = (cx - ax) / 2 + ax;
308
if (!got_x || !got_y)
310
/* At least two of the lines are not parallel to the axis */
312
if (ax != bx && ay != by)
313
line_definition (ax, ay, bx, by, &line1_grad, &line1_const);
315
line_definition (ax, ay, cx, cy, &line1_grad, &line1_const);
317
if (bx != cx && by != cy)
318
line_definition (bx, by, cx, cy, &line2_grad, &line2_const);
320
line_definition (ax, ay, cx, cy, &line2_grad, &line2_const);
323
/* Intersection point */
326
inter_x = (line2_const - line1_const) / (line1_grad - line2_grad);
328
inter_y = line1_grad * inter_x + line1_const;
330
center_pnt->x = (gint) inter_x;
331
center_pnt->y = (gint) inter_y;
335
arc_angle (GdkPoint *pnt,
338
/* Get angle (in degress) of point given origin of center */
341
gdouble offset_angle;
343
shift_x = pnt->x - center->x;
344
shift_y = -pnt->y + center->y;
345
offset_angle = atan2 (shift_y, shift_x);
347
if (offset_angle < 0)
348
offset_angle += 2.0 * G_PI;
350
return offset_angle * 360 / (2.0 * G_PI);
354
arc_drawing_details (GfigObject *obj,
356
GdkPoint *center_pnt,
362
DobjPoints *pnt1 = NULL;
363
DobjPoints *pnt2 = NULL;
364
DobjPoints *pnt3 = NULL;
366
gdouble ang1, ang2, ang3;
372
return; /* Not fully drawn */
377
return; /* Not fully drawn */
382
return; /* Still not fully drawn */
386
draw_sqr (&pnt1->pnt, obj == gfig_context->selected_obj);
387
draw_sqr (&pnt2->pnt, obj == gfig_context->selected_obj);
388
draw_sqr (&pnt3->pnt, obj == gfig_context->selected_obj);
393
/* Adjust pnts for scaling */
394
/* Warning struct copies here! and casting to double <-> int */
395
/* Too complex fix me - to much hacking */
407
for (j = 0 ; j < 3; j++)
409
xy[0] = dpnts[j].pnt.x;
410
xy[1] = dpnts[j].pnt.y;
411
if (selvals.scaletoimage)
412
scale_to_original_xy (&xy[0], 1);
414
scale_to_xy (&xy[0], 1);
415
dpnts[j].pnt.x = xy[0];
416
dpnts[j].pnt.y = xy[1];
420
arc_details (&pnt1->pnt, &pnt2->pnt, &pnt3->pnt, center_pnt, radius);
422
ang1 = arc_angle (&pnt1->pnt, center_pnt);
423
ang2 = arc_angle (&pnt2->pnt, center_pnt);
424
ang3 = arc_angle (&pnt3->pnt, center_pnt);
426
/* Find min/max angle */
438
if (ang2 > *minang && ang2 < maxang)
439
*arcang = maxang - *minang;
441
*arcang = maxang - *minang - 360;
445
d_draw_arc (GfigObject *obj)
448
gdouble radius, minang, arcang;
450
g_assert (obj != NULL);
455
arc_drawing_details (obj, &minang, ¢er_pnt, &arcang, &radius,
457
gfig_draw_arc (center_pnt.x, center_pnt.y, radius, radius, minang, arcang);
461
d_paint_arc (GfigObject *obj)
463
/* first point center */
464
/* Next point is radius */
472
GdkPoint first_pnt, last_pnt;
473
gboolean first = TRUE;
475
gdouble minang, arcang;
477
g_assert (obj != NULL);
482
/* No cnt pnts & must scale */
483
arc_drawing_details (obj, &minang, ¢er_pnt, &arcang, &radius,
486
seg_count = 360; /* Should make a smoth-ish curve */
488
/* +3 because we MIGHT do pie selection */
489
line_pnts = g_new0 (gdouble, 2 * seg_count + 3);
492
ang_grid = 2.0 * G_PI / 360.0;
496
/* Swap - since we always draw anti-clock wise */
501
minang = minang * (2.0 * G_PI / 360.0); /* min ang is in degrees - need in rads */
503
for (loop = 0 ; loop < abs ((gint)arcang) ; loop++)
508
ang_loop = (gdouble)loop * ang_grid + minang;
510
lx = radius * cos (ang_loop);
511
ly = -radius * sin (ang_loop); /* y grows down screen and angs measured from x clockwise */
513
calc_pnt.x = RINT (lx + center_pnt.x);
514
calc_pnt.y = RINT (ly + center_pnt.y);
516
/* Miss out duped pnts */
519
if (calc_pnt.x == last_pnt.x && calc_pnt.y == last_pnt.y)
525
line_pnts[i++] = calc_pnt.x;
526
line_pnts[i++] = calc_pnt.y;
531
first_pnt = calc_pnt;
537
if (obj->style.paint_type == PAINT_BRUSH_TYPE)
539
gfig_paint (selvals.brshtype,
540
gfig_context->drawable_id,
548
d_copy_arc (GfigObject *obj)
552
g_assert (obj->type == ARC);
554
nc = d_new_object (ARC, obj->points->pnt.x, obj->points->pnt.y);
555
nc->points->next = d_copy_dobjpoints (obj->points->next);
561
d_arc_object_class_init (void)
563
GfigObjectClass *class = &dobj_class[ARC];
567
class->drawfunc = d_draw_arc;
568
class->paintfunc = d_paint_arc;
569
class->copyfunc = d_copy_arc;
570
class->update = d_update_arc;
573
/* Update end point of line */
575
d_update_arc_line (GdkPoint *pnt)
577
DobjPoints *spnt, *epnt;
578
/* Get last but one segment and undraw it -
579
* Then draw new segment in.
580
* always dealing with the static object.
583
/* Get start of segments */
584
spnt = obj_creating->points;
587
return; /* No points */
589
if ((epnt = spnt->next))
592
/* Draw square on point */
593
draw_circle (&epnt->pnt, TRUE);
595
gdk_draw_line (gfig_context->preview->window,
596
/*gfig_context->preview->style->bg_gc[GTK_STATE_NORMAL],*/
606
/* Draw circle on point */
607
draw_circle (pnt, TRUE);
609
epnt = new_dobjpoint (pnt->x, pnt->y);
611
gdk_draw_line (gfig_context->preview->window,
612
/*gfig_context->preview->style->bg_gc[GTK_STATE_NORMAL],*/
622
d_update_arc (GdkPoint *pnt)
624
DobjPoints *pnt1 = NULL;
625
DobjPoints *pnt2 = NULL;
626
DobjPoints *pnt3 = NULL;
628
/* First two points as line only become arch when third
629
* point is placed on canvas.
632
pnt1 = obj_creating->points;
635
!(pnt2 = pnt1->next) ||
636
!(pnt3 = pnt2->next))
638
d_update_arc_line (pnt);
639
return; /* Not fully drawn */
642
/* Update a real curve */
643
/* Nothing to be done ... */
647
d_arc_line_start (GdkPoint *pnt,
650
if (!obj_creating || !shift_down)
652
/* Draw square on point */
653
/* Must delete obj_creating if we have one */
654
obj_creating = d_new_object (LINE, pnt->x, pnt->y);
659
d_update_arc_line (pnt);
664
d_arc_start (GdkPoint *pnt,
667
/* Draw lines to start with -- then convert to an arc */
669
draw_sqr (pnt, TRUE);
670
d_arc_line_start (pnt, TRUE); /* TRUE means multiple pointed line */
674
d_arc_line_end (GdkPoint *pnt,
677
/* Undraw the last circle */
678
draw_circle (pnt, TRUE);
684
GdkPoint tmp_pnt = *pnt;
688
tmp_pnt.x = pnt->x * scale_x_factor;
689
tmp_pnt.y = pnt->y * scale_y_factor;
692
d_pnt_add_line (tmp_line, tmp_pnt.x, tmp_pnt.y, -1);
693
free_one_obj (obj_creating);
694
/* Must free obj_creating */
698
tmp_line = obj_creating;
699
add_to_all_obj (gfig_context->current_obj, obj_creating);
702
obj_creating = d_new_object (LINE, pnt->x, pnt->y);
708
GdkPoint tmp_pnt = *pnt;
712
tmp_pnt.x = pnt->x * scale_x_factor;
713
tmp_pnt.y = pnt->y * scale_y_factor;
716
d_pnt_add_line (tmp_line, tmp_pnt.x, tmp_pnt.y, -1);
717
free_one_obj (obj_creating);
718
/* Must free obj_creating */
722
add_to_all_obj (gfig_context->current_obj, obj_creating);
727
/*gtk_widget_queue_draw (gfig_context->preview);*/
731
d_arc_end (GdkPoint *pnt,
734
/* Under control point */
737
!tmp_line->points->next)
739
/* No arc created - yet. Must have three points */
740
d_arc_line_end (pnt, TRUE);
745
/* Convert to an arc ... */
746
tmp_line->type = ARC;
747
tmp_line->class = &dobj_class[ARC];
748
d_arc_line_end (pnt, FALSE);
751
selvals.scaletoimage = 0;
753
/*d_draw_arc (newarc);*/
754
gtk_widget_queue_draw (gfig_context->preview);
757
selvals.scaletoimage = 1;