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
25 #include "config.h"
26
27 #include <libgimp/gimp.h>
28 #include <libgimp/gimpui.h>
29
30 #include "gfig.h"
31 #include "gfig-dobject.h"
32 #include "gfig-line.h"
33 #include "gfig-dialog.h"
34 #include "gfig-poly.h"
35
36 #include "libgimp/stdplugins-intl.h"
37
38 static gint poly_num_sides = 3; /* Default to three sided object */
39
40 static void d_draw_poly (GfigObject *obj,
41 cairo_t *cr);
42 static GfigObject *d_copy_poly (GfigObject *obj);
43
44 static void d_update_poly (GdkPoint *pnt);
45
46 void
tool_options_poly(GtkWidget * notebook)47 tool_options_poly (GtkWidget *notebook)
48 {
49 GtkWidget *sides;
50
51 sides = num_sides_widget (_("Regular Polygon Number of Sides"),
52 &poly_num_sides, NULL, 3, 200);
53 gtk_notebook_append_page (GTK_NOTEBOOK (notebook), sides, NULL);
54 }
55
56 static void
d_draw_poly(GfigObject * obj,cairo_t * cr)57 d_draw_poly (GfigObject *obj,
58 cairo_t *cr)
59 {
60 DobjPoints *center_pnt;
61 DobjPoints *radius_pnt;
62 gint16 shift_x;
63 gint16 shift_y;
64 gdouble ang_grid;
65 gdouble ang_loop;
66 gdouble radius;
67 gdouble offset_angle;
68 gint loop;
69 GdkPoint start_pnt = { 0, 0 };
70 GdkPoint first_pnt = { 0, 0 };
71 gboolean do_line = FALSE;
72
73 center_pnt = obj->points;
74
75 if (!center_pnt)
76 return; /* End-of-line */
77
78 /* First point is the center */
79 /* Just draw a control point around it */
80
81 draw_sqr (¢er_pnt->pnt, obj == gfig_context->selected_obj, cr);
82
83 /* Next point defines the radius */
84 radius_pnt = center_pnt->next; /* this defines the vertices */
85
86 if (!radius_pnt)
87 {
88 #ifdef DEBUG
89 g_warning ("Internal error in polygon - no vertice point \n");
90 #endif /* DEBUG */
91 return;
92 }
93
94 /* Other control point */
95 if (obj == obj_creating)
96 draw_circle (&radius_pnt->pnt, TRUE, cr);
97 else
98 draw_sqr (&radius_pnt->pnt, obj == gfig_context->selected_obj, cr);
99
100 /* Have center and radius - draw polygon */
101
102 shift_x = radius_pnt->pnt.x - center_pnt->pnt.x;
103 shift_y = radius_pnt->pnt.y - center_pnt->pnt.y;
104
105 radius = sqrt ((shift_x*shift_x) + (shift_y*shift_y));
106
107 /* Lines */
108 ang_grid = 2 * G_PI / (gdouble) obj->type_data;
109 offset_angle = atan2 (shift_y, shift_x);
110
111 for (loop = 0 ; loop < obj->type_data ; loop++)
112 {
113 gdouble lx, ly;
114 GdkPoint calc_pnt;
115
116 ang_loop = (gdouble)loop * ang_grid + offset_angle;
117
118 lx = radius * cos (ang_loop);
119 ly = radius * sin (ang_loop);
120
121 calc_pnt.x = RINT (lx + center_pnt->pnt.x);
122 calc_pnt.y = RINT (ly + center_pnt->pnt.y);
123
124 if (do_line)
125 {
126
127 /* Miss out points that come to the same location */
128 if (calc_pnt.x == start_pnt.x && calc_pnt.y == start_pnt.y)
129 continue;
130
131 gfig_draw_line (calc_pnt.x, calc_pnt.y, start_pnt.x, start_pnt.y, cr);
132 }
133 else
134 {
135 do_line = TRUE;
136 first_pnt = calc_pnt;
137 }
138 start_pnt = calc_pnt;
139 }
140
141 gfig_draw_line (first_pnt.x, first_pnt.y, start_pnt.x, start_pnt.y, cr);
142 }
143
144 void
d_paint_poly(GfigObject * obj)145 d_paint_poly (GfigObject *obj)
146 {
147 /* first point center */
148 /* Next point is radius */
149 gdouble *line_pnts;
150 gint seg_count;
151 gint i = 0;
152 DobjPoints *center_pnt;
153 DobjPoints *radius_pnt;
154 gint16 shift_x;
155 gint16 shift_y;
156 gdouble ang_grid;
157 gdouble ang_loop;
158 gdouble radius;
159 gdouble offset_angle;
160 gint loop;
161 GdkPoint first_pnt = { 0, 0 };
162 GdkPoint last_pnt = { 0, 0 };
163 gboolean first = TRUE;
164 gdouble *min_max;
165
166 g_assert (obj != NULL);
167
168 /* count - add one to close polygon */
169 seg_count = obj->type_data + 1;
170
171 center_pnt = obj->points;
172
173 if (!center_pnt || !seg_count || !center_pnt->next)
174 return; /* no-line */
175
176 line_pnts = g_new0 (gdouble, 2 * seg_count + 1);
177 min_max = g_new (gdouble, 4);
178
179 /* Go around all the points drawing a line from one to the next */
180
181 radius_pnt = center_pnt->next; /* this defines the vetices */
182
183 /* Have center and radius - get lines */
184 shift_x = radius_pnt->pnt.x - center_pnt->pnt.x;
185 shift_y = radius_pnt->pnt.y - center_pnt->pnt.y;
186
187 radius = sqrt ((shift_x*shift_x) + (shift_y*shift_y));
188
189 /* Lines */
190 ang_grid = 2.0 * G_PI/(gdouble) obj->type_data;
191 offset_angle = atan2 (shift_y, shift_x);
192
193 for (loop = 0 ; loop < obj->type_data ; loop++)
194 {
195 gdouble lx, ly;
196 GdkPoint calc_pnt;
197
198 ang_loop = (gdouble)loop * ang_grid + offset_angle;
199
200 lx = radius * cos (ang_loop);
201 ly = radius * sin (ang_loop);
202
203 calc_pnt.x = RINT (lx + center_pnt->pnt.x);
204 calc_pnt.y = RINT (ly + center_pnt->pnt.y);
205
206 /* Miss out duped pnts */
207 if (!first)
208 {
209 if (calc_pnt.x == last_pnt.x && calc_pnt.y == last_pnt.y)
210 {
211 continue;
212 }
213 }
214
215 line_pnts[i++] = calc_pnt.x;
216 line_pnts[i++] = calc_pnt.y;
217 last_pnt = calc_pnt;
218
219 if (first)
220 {
221 first_pnt = calc_pnt;
222 first = FALSE;
223 min_max[0] = min_max[2] = calc_pnt.x;
224 min_max[1] = min_max[3] = calc_pnt.y;
225 }
226 else
227 {
228 min_max[0] = MIN (min_max[0], calc_pnt.x);
229 min_max[1] = MIN (min_max[1], calc_pnt.y);
230 min_max[2] = MAX (min_max[2], calc_pnt.x);
231 min_max[3] = MAX (min_max[3], calc_pnt.y);
232 }
233 }
234
235 line_pnts[i++] = first_pnt.x;
236 line_pnts[i++] = first_pnt.y;
237
238 /* Scale before drawing */
239 if (selvals.scaletoimage)
240 {/* FIXME scale xmax and al. */
241 scale_to_original_xy (&line_pnts[0], i/2);
242 scale_to_original_xy (min_max, 2);
243 }
244 else
245 {
246 scale_to_xy (&line_pnts[0], i/2);
247 scale_to_xy (min_max, 2);
248 }
249
250
251 if (gfig_context_get_current_style ()->fill_type != FILL_NONE)
252 {
253 gimp_context_push ();
254 gimp_context_set_antialias (selopt.antia);
255 gimp_context_set_feather (selopt.feather);
256 gimp_context_set_feather_radius (selopt.feather_radius, selopt.feather_radius);
257 gimp_image_select_polygon (gfig_context->image_id,
258 selopt.type,
259 i, line_pnts);
260 gimp_context_pop ();
261
262 paint_layer_fill (min_max[0], min_max[1], min_max[2], min_max[3]);
263 gimp_selection_none (gfig_context->image_id);
264 }
265
266 if (obj->style.paint_type == PAINT_BRUSH_TYPE)
267 gfig_paint (selvals.brshtype, gfig_context->drawable_id, i, line_pnts);
268
269 g_free (line_pnts);
270 g_free (min_max);
271 }
272
273 void
d_poly2lines(GfigObject * obj)274 d_poly2lines (GfigObject *obj)
275 {
276 /* first point center */
277 /* Next point is radius */
278 DobjPoints *center_pnt;
279 DobjPoints *radius_pnt;
280 gint16 shift_x;
281 gint16 shift_y;
282 gdouble ang_grid;
283 gdouble ang_loop;
284 gdouble radius;
285 gdouble offset_angle;
286 gint loop;
287 GdkPoint first_pnt = { 0, 0 };
288 GdkPoint last_pnt = { 0, 0 };
289 gboolean first = TRUE;
290
291 g_assert (obj != NULL);
292
293 center_pnt = obj->points;
294
295 if (!center_pnt)
296 return; /* no-line */
297
298 /* NULL out these points free later */
299 obj->points = NULL;
300
301 /* Go around all the points creating line points */
302
303 radius_pnt = center_pnt->next; /* this defines the vertices */
304
305 /* Have center and radius - get lines */
306 shift_x = radius_pnt->pnt.x - center_pnt->pnt.x;
307 shift_y = radius_pnt->pnt.y - center_pnt->pnt.y;
308
309 radius = sqrt ((shift_x*shift_x) + (shift_y*shift_y));
310
311 /* Lines */
312 ang_grid = 2.0 * G_PI / (gdouble) obj->type_data;
313 offset_angle = atan2 (shift_y, shift_x);
314
315 for (loop = 0 ; loop < obj->type_data ; loop++)
316 {
317 gdouble lx, ly;
318 GdkPoint calc_pnt;
319
320 ang_loop = (gdouble)loop * ang_grid + offset_angle;
321
322 lx = radius * cos (ang_loop);
323 ly = radius * sin (ang_loop);
324
325 calc_pnt.x = RINT (lx + center_pnt->pnt.x);
326 calc_pnt.y = RINT (ly + center_pnt->pnt.y);
327
328 if (!first)
329 {
330 if (calc_pnt.x == last_pnt.x && calc_pnt.y == last_pnt.y)
331 {
332 continue;
333 }
334 }
335
336 d_pnt_add_line (obj, calc_pnt.x, calc_pnt.y, 0);
337
338 last_pnt = calc_pnt;
339
340 if (first)
341 {
342 first_pnt = calc_pnt;
343 first = FALSE;
344 }
345 }
346
347 d_pnt_add_line (obj, first_pnt.x, first_pnt.y, 0);
348 /* Free old pnts */
349 d_delete_dobjpoints (center_pnt);
350
351 /* hey we're a line now */
352 obj->type = LINE;
353 obj->class = &dobj_class[LINE];
354 }
355
356 void
d_star2lines(GfigObject * obj)357 d_star2lines (GfigObject *obj)
358 {
359 /* first point center */
360 /* Next point is radius */
361 DobjPoints *center_pnt;
362 DobjPoints *outer_radius_pnt;
363 DobjPoints *inner_radius_pnt;
364 gint16 shift_x;
365 gint16 shift_y;
366 gdouble ang_grid;
367 gdouble ang_loop;
368 gdouble outer_radius;
369 gdouble inner_radius;
370 gdouble offset_angle;
371 gint loop;
372 GdkPoint first_pnt = { 0, 0 };
373 GdkPoint last_pnt = { 0, 0 };
374 gboolean first = TRUE;
375
376 g_assert (obj != NULL);
377
378 center_pnt = obj->points;
379
380 if (!center_pnt)
381 return; /* no-line */
382
383 /* NULL out these points free later */
384 obj->points = NULL;
385
386 /* Go around all the points creating line points */
387 /* Next point defines the radius */
388 outer_radius_pnt = center_pnt->next; /* this defines the vetices */
389
390 if (!outer_radius_pnt)
391 {
392 #ifdef DEBUG
393 g_warning ("Internal error in star - no outer vertice point \n");
394 #endif /* DEBUG */
395 return;
396 }
397
398 inner_radius_pnt = outer_radius_pnt->next; /* this defines the vetices */
399
400 if (!inner_radius_pnt)
401 {
402 #ifdef DEBUG
403 g_warning ("Internal error in star - no inner vertice point \n");
404 #endif /* DEBUG */
405 return;
406 }
407
408 shift_x = outer_radius_pnt->pnt.x - center_pnt->pnt.x;
409 shift_y = outer_radius_pnt->pnt.y - center_pnt->pnt.y;
410
411 outer_radius = sqrt ((shift_x*shift_x) + (shift_y*shift_y));
412
413 /* Lines */
414 ang_grid = 2.0 * G_PI / (2.0 * (gdouble) obj->type_data);
415 offset_angle = atan2 (shift_y, shift_x);
416
417 shift_x = inner_radius_pnt->pnt.x - center_pnt->pnt.x;
418 shift_y = inner_radius_pnt->pnt.y - center_pnt->pnt.y;
419
420 inner_radius = sqrt ((shift_x * shift_x) + (shift_y * shift_y));
421
422 for (loop = 0 ; loop < 2 * obj->type_data ; loop++)
423 {
424 gdouble lx, ly;
425 GdkPoint calc_pnt;
426
427 ang_loop = (gdouble)loop * ang_grid + offset_angle;
428
429 if (loop % 2)
430 {
431 lx = inner_radius * cos (ang_loop);
432 ly = inner_radius * sin (ang_loop);
433 }
434 else
435 {
436 lx = outer_radius * cos (ang_loop);
437 ly = outer_radius * sin (ang_loop);
438 }
439
440 calc_pnt.x = RINT (lx + center_pnt->pnt.x);
441 calc_pnt.y = RINT (ly + center_pnt->pnt.y);
442
443 if (!first)
444 {
445 if (calc_pnt.x == last_pnt.x && calc_pnt.y == last_pnt.y)
446 {
447 continue;
448 }
449 }
450
451 d_pnt_add_line (obj, calc_pnt.x, calc_pnt.y, 0);
452
453 last_pnt = calc_pnt;
454
455 if (first)
456 {
457 first_pnt = calc_pnt;
458 first = FALSE;
459 }
460 }
461
462 d_pnt_add_line (obj, first_pnt.x, first_pnt.y, 0);
463 /* Free old pnts */
464 d_delete_dobjpoints (center_pnt);
465
466 /* hey we're a line now */
467 obj->type = LINE;
468 obj->class = &dobj_class[LINE];
469 }
470
471 static GfigObject *
d_copy_poly(GfigObject * obj)472 d_copy_poly (GfigObject *obj)
473 {
474 GfigObject *np;
475
476 g_assert (obj->type == POLY);
477
478 np = d_new_object (POLY, obj->points->pnt.x, obj->points->pnt.y);
479 np->points->next = d_copy_dobjpoints (obj->points->next);
480 np->type_data = obj->type_data;
481
482 return np;
483 }
484
485 void
d_poly_object_class_init(void)486 d_poly_object_class_init (void)
487 {
488 GfigObjectClass *class = &dobj_class[POLY];
489
490 class->type = POLY;
491 class->name = "POLY";
492 class->drawfunc = d_draw_poly;
493 class->paintfunc = d_paint_poly;
494 class->copyfunc = d_copy_poly;
495 class->update = d_update_poly;
496 }
497
498 static void
d_update_poly(GdkPoint * pnt)499 d_update_poly (GdkPoint *pnt)
500 {
501 DobjPoints *center_pnt;
502 DobjPoints *edge_pnt;
503
504 center_pnt = obj_creating->points;
505
506 if (!center_pnt)
507 return; /* No points */
508
509 if ((edge_pnt = center_pnt->next))
510 {
511 edge_pnt->pnt = *pnt;
512 }
513 else
514 {
515 d_pnt_add_line (obj_creating, pnt->x, pnt->y, -1);
516 }
517 }
518
519 void
d_poly_start(GdkPoint * pnt,gboolean shift_down)520 d_poly_start (GdkPoint *pnt,
521 gboolean shift_down)
522 {
523 obj_creating = d_new_object (POLY, pnt->x, pnt->y);
524 obj_creating->type_data = poly_num_sides;
525 }
526
527 void
d_poly_end(GdkPoint * pnt,gboolean shift_down)528 d_poly_end (GdkPoint *pnt,
529 gboolean shift_down)
530 {
531 add_to_all_obj (gfig_context->current_obj, obj_creating);
532 obj_creating = NULL;
533 }
534