1 /* Dia -- an diagram creation/manipulation program
2 * Copyright (C) 1999 Alexander Larsson
4 * BezierConn Copyright (C) 1999 James Henstridge
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 #include <string.h> /* memcpy() */
29 #include "bezier_conn.h"
33 #define HANDLE_BEZMAJOR (HANDLE_CUSTOM1)
34 #define HANDLE_LEFTCTRL (HANDLE_CUSTOM2)
35 #define HANDLE_RIGHTCTRL (HANDLE_CUSTOM3)
43 ObjectChange obj_change
;
45 enum change_type type
;
49 BezCornerType corner_type
;
51 /* owning ref when not applied for ADD_POINT
52 * owning ref when applied for REMOVE_POINT */
53 Handle
*handle1
, *handle2
, *handle3
;
54 /* NULL if not connected */
55 ConnectionPoint
*connected_to1
, *connected_to2
, *connected_to3
;
59 ObjectChange obj_change
;
60 /* Only one kind of corner_change */
64 /* Old places when SET_CORNER_TYPE is applied */
65 Point point_left
, point_right
;
66 BezCornerType old_type
, new_type
;
70 bezierconn_create_point_change(BezierConn
*bez
, enum change_type type
,
71 BezPoint
*point
, BezCornerType corner_type
,
73 Handle
*handle1
, ConnectionPoint
*connected_to1
,
74 Handle
*handle2
, ConnectionPoint
*connected_to2
,
75 Handle
*handle3
, ConnectionPoint
*connected_to3
);
77 bezierconn_create_corner_change(BezierConn
*bez
, Handle
*handle
,
78 Point
*point_left
, Point
*point_right
,
79 BezCornerType old_corner_type
,
80 BezCornerType new_corner_type
);
83 static void setup_corner_handle(Handle
*handle
, HandleId id
)
86 handle
->type
= HANDLE_MINOR_CONTROL
;
87 handle
->connect_type
= (id
== HANDLE_BEZMAJOR
) ?
88 HANDLE_CONNECTABLE
: HANDLE_NONCONNECTABLE
;
89 handle
->connected_to
= NULL
;
92 static int get_handle_nr(BezierConn
*bez
, Handle
*handle
)
95 for (i
=0;i
<bez
->object
.num_handles
;i
++) {
96 if (bez
->object
.handles
[i
] == handle
)
102 #define get_comp_nr(hnum) (((int)(hnum)+2)/3)
103 #define get_major_nr(hnum) (((int)(hnum)+1)/3)
106 bezierconn_move_handle(BezierConn
*bez
, Handle
*handle
,
107 Point
*to
, HandleMoveReason reason
)
109 int handle_nr
, comp_nr
;
113 point_sub(&delta
, &handle
->pos
);
115 handle_nr
= get_handle_nr(bez
, handle
);
116 comp_nr
= get_comp_nr(handle_nr
);
118 case HANDLE_MOVE_STARTPOINT
:
119 bez
->points
[0].p1
= *to
;
120 /* shift adjacent point */
121 point_add(&bez
->points
[1].p1
, &delta
);
123 case HANDLE_MOVE_ENDPOINT
:
124 bez
->points
[bez
->numpoints
-1].p3
= *to
;
125 /* shift adjacent point */
126 point_add(&bez
->points
[bez
->numpoints
-1].p2
, &delta
);
128 case HANDLE_BEZMAJOR
:
129 bez
->points
[comp_nr
].p3
= *to
;
130 /* shift adjacent point */
131 point_add(&bez
->points
[comp_nr
].p2
, &delta
);
132 point_add(&bez
->points
[comp_nr
+1].p1
, &delta
);
134 case HANDLE_LEFTCTRL
:
135 bez
->points
[comp_nr
].p2
= *to
;
136 if (comp_nr
< bez
->numpoints
- 1) {
137 switch (bez
->corner_types
[comp_nr
]) {
138 case BEZ_CORNER_SYMMETRIC
:
139 pt
= bez
->points
[comp_nr
].p3
;
140 point_sub(&pt
, &bez
->points
[comp_nr
].p2
);
141 point_add(&pt
, &bez
->points
[comp_nr
].p3
);
142 bez
->points
[comp_nr
+1].p1
= pt
;
144 case BEZ_CORNER_SMOOTH
: {
146 pt
= bez
->points
[comp_nr
+1].p1
;
147 point_sub(&pt
, &bez
->points
[comp_nr
].p3
);
148 len
= point_len(&pt
);
149 pt
= bez
->points
[comp_nr
].p2
;
150 point_sub(&pt
, &bez
->points
[comp_nr
].p3
);
151 if (point_len(&pt
) > 0)
152 point_normalize(&pt
);
153 else { pt
.x
= 1.0; pt
.y
= 0.0; }
154 point_scale(&pt
, -len
);
155 point_add(&pt
, &bez
->points
[comp_nr
].p3
);
156 bez
->points
[comp_nr
+1].p1
= pt
;
159 case BEZ_CORNER_CUSP
:
160 /* Do nothing to the other guy */
165 case HANDLE_RIGHTCTRL
:
166 bez
->points
[comp_nr
].p1
= *to
;
168 switch (bez
->corner_types
[comp_nr
-1]) {
169 case BEZ_CORNER_SYMMETRIC
:
170 pt
= bez
->points
[comp_nr
- 1].p3
;
171 point_sub(&pt
, &bez
->points
[comp_nr
].p1
);
172 point_add(&pt
, &bez
->points
[comp_nr
- 1].p3
);
173 bez
->points
[comp_nr
-1].p2
= pt
;
175 case BEZ_CORNER_SMOOTH
: {
177 pt
= bez
->points
[comp_nr
-1].p2
;
178 point_sub(&pt
, &bez
->points
[comp_nr
-1].p3
);
179 len
= point_len(&pt
);
180 pt
= bez
->points
[comp_nr
].p1
;
181 point_sub(&pt
, &bez
->points
[comp_nr
-1].p3
);
182 if (point_len(&pt
) > 0)
183 point_normalize(&pt
);
184 else { pt
.x
= 1.0; pt
.y
= 0.0; }
185 point_scale(&pt
, -len
);
186 point_add(&pt
, &bez
->points
[comp_nr
-1].p3
);
187 bez
->points
[comp_nr
-1].p2
= pt
;
190 case BEZ_CORNER_CUSP
:
191 /* Do nothing to the other guy */
197 message_error("Internal error in bezierconn_move_handle.\n");
203 bezierconn_move(BezierConn
*bez
, Point
*to
)
209 point_sub(&p
, &bez
->points
[0].p1
);
211 bez
->points
[0].p1
= *to
;
212 for (i
= 1; i
< bez
->numpoints
; i
++) {
213 point_add(&bez
->points
[i
].p1
, &p
);
214 point_add(&bez
->points
[i
].p2
, &p
);
215 point_add(&bez
->points
[i
].p3
, &p
);
220 bezierconn_closest_segment(BezierConn
*bez
, Point
*point
, real line_width
)
224 real dist
= G_MAXDOUBLE
;
228 last
= bez
->points
[0].p1
;
229 for (i
= 0; i
< bez
->numpoints
- 1; i
++) {
230 real new_dist
= distance_bez_seg_point(&last
, &bez
->points
[i
+1].p1
,
231 &bez
->points
[i
+1].p2
, &bez
->points
[i
+1].p3
,
233 if (new_dist
< dist
) {
237 last
= bez
->points
[i
+1].p3
;
243 bezierconn_closest_handle(BezierConn
*bez
, Point
*point
)
249 closest
= bez
->object
.handles
[0];
250 dist
= distance_point_point( point
, &closest
->pos
);
251 for (i
= 1, hn
= 1; i
< bez
->numpoints
; i
++, hn
++) {
254 new_dist
= distance_point_point(point
, &bez
->points
[i
].p1
);
255 if (new_dist
< dist
) {
257 closest
= bez
->object
.handles
[hn
];
261 new_dist
= distance_point_point(point
, &bez
->points
[i
].p2
);
262 if (new_dist
< dist
) {
264 closest
= bez
->object
.handles
[hn
];
268 new_dist
= distance_point_point(point
, &bez
->points
[i
].p3
);
269 if (new_dist
< dist
) {
271 closest
= bez
->object
.handles
[hn
];
278 bezierconn_closest_major_handle(BezierConn
*bez
, Point
*point
)
280 Handle
*closest
= bezierconn_closest_handle(bez
, point
);
282 return bez
->object
.handles
[3*get_major_nr(get_handle_nr(bez
, closest
))];
286 bezierconn_distance_from(BezierConn
*bez
, Point
*point
, real line_width
)
288 return distance_bez_line_point(bez
->points
, bez
->numpoints
,
293 add_handles(BezierConn
*bez
, int pos
, BezPoint
*point
,
294 BezCornerType corner_type
, Handle
*handle1
,
295 Handle
*handle2
, Handle
*handle3
)
304 bez
->points
= g_realloc(bez
->points
, bez
->numpoints
*sizeof(BezPoint
));
305 bez
->corner_types
= g_realloc(bez
->corner_types
,
306 bez
->numpoints
* sizeof(BezCornerType
));
308 for (i
= bez
->numpoints
-1; i
> pos
; i
--) {
309 bez
->points
[i
] = bez
->points
[i
-1];
310 bez
->corner_types
[i
] = bez
->corner_types
[i
-1];
312 bez
->points
[pos
] = *point
;
313 bez
->points
[pos
].p1
= bez
->points
[pos
+1].p1
;
314 bez
->points
[pos
+1].p1
= point
->p1
;
315 bez
->corner_types
[pos
] = corner_type
;
316 object_add_handle_at(obj
, handle1
, 3*pos
-2);
317 object_add_handle_at(obj
, handle2
, 3*pos
-1);
318 object_add_handle_at(obj
, handle3
, 3*pos
);
320 if (pos
==bez
->numpoints
-1) {
321 obj
->handles
[obj
->num_handles
-4]->type
= HANDLE_MINOR_CONTROL
;
322 obj
->handles
[obj
->num_handles
-4]->id
= HANDLE_BEZMAJOR
;
327 remove_handles(BezierConn
*bez
, int pos
)
331 Handle
*old_handle1
, *old_handle2
, *old_handle3
;
338 if (pos
==obj
->num_handles
-1) {
339 obj
->handles
[obj
->num_handles
-4]->type
= HANDLE_MAJOR_CONTROL
;
340 obj
->handles
[obj
->num_handles
-4]->id
= HANDLE_MOVE_ENDPOINT
;
343 /* delete the points */
345 tmppoint
= bez
->points
[pos
].p1
;
346 for (i
= pos
; i
< bez
->numpoints
; i
++) {
347 bez
->points
[i
] = bez
->points
[i
+1];
348 bez
->corner_types
[i
] = bez
->corner_types
[i
+1];
350 bez
->points
[pos
].p1
= tmppoint
;
351 bez
->points
= g_realloc(bez
->points
, bez
->numpoints
*sizeof(BezPoint
));
352 bez
->corner_types
= g_realloc(bez
->corner_types
,
353 bez
->numpoints
* sizeof(BezCornerType
));
355 old_handle1
= obj
->handles
[3*pos
-3];
356 old_handle2
= obj
->handles
[3*pos
-2];
357 old_handle3
= obj
->handles
[3*pos
-1];
358 object_remove_handle(&bez
->object
, old_handle1
);
359 object_remove_handle(&bez
->object
, old_handle2
);
360 object_remove_handle(&bez
->object
, old_handle3
);
364 /* Add a point by splitting segment into two, putting the new point at
365 'point' or, if NULL, in the middle */
367 bezierconn_add_segment(BezierConn
*bez
, int segment
, Point
*point
)
370 BezCornerType corner_type
= BEZ_CORNER_SYMMETRIC
;
371 Handle
*new_handle1
, *new_handle2
, *new_handle3
;
375 startpoint
= bez
->points
[0].p1
;
377 startpoint
= bez
->points
[segment
].p3
;
380 realpoint
.p1
.x
= (startpoint
.x
+ bez
->points
[segment
+1].p3
.x
) / 6;
381 realpoint
.p1
.y
= (startpoint
.y
+ bez
->points
[segment
+1].p3
.y
) / 6;
382 realpoint
.p2
.x
= (startpoint
.x
+ bez
->points
[segment
+1].p3
.x
) / 3;
383 realpoint
.p2
.y
= (startpoint
.y
+ bez
->points
[segment
+1].p3
.y
) / 3;
384 realpoint
.p3
.x
= (startpoint
.x
+ bez
->points
[segment
+1].p3
.x
) / 2;
385 realpoint
.p3
.y
= (startpoint
.y
+ bez
->points
[segment
+1].p3
.y
) / 2;
387 realpoint
.p2
.x
= point
->x
+(startpoint
.x
- bez
->points
[segment
+1].p3
.x
)/6;
388 realpoint
.p2
.y
= point
->y
+(startpoint
.y
- bez
->points
[segment
+1].p3
.y
)/6;
389 realpoint
.p3
= *point
;
390 /* this really goes into the next segment ... */
391 realpoint
.p1
.x
= point
->x
-(startpoint
.x
- bez
->points
[segment
+1].p3
.x
)/6;
392 realpoint
.p1
.y
= point
->y
-(startpoint
.y
- bez
->points
[segment
+1].p3
.y
)/6;
394 realpoint
.type
= BEZ_CURVE_TO
;
396 new_handle1
= g_malloc(sizeof(Handle
));
397 new_handle2
= g_malloc(sizeof(Handle
));
398 new_handle3
= g_malloc(sizeof(Handle
));
399 setup_corner_handle(new_handle1
, HANDLE_RIGHTCTRL
);
400 setup_corner_handle(new_handle2
, HANDLE_LEFTCTRL
);
401 setup_corner_handle(new_handle3
, HANDLE_BEZMAJOR
);
402 add_handles(bez
, segment
+1, &realpoint
, corner_type
,
403 new_handle1
, new_handle2
, new_handle3
);
404 return bezierconn_create_point_change(bez
, TYPE_ADD_POINT
,
405 &realpoint
, corner_type
, segment
+1,
412 bezierconn_remove_segment(BezierConn
*bez
, int pos
)
414 Handle
*old_handle1
, *old_handle2
, *old_handle3
;
415 ConnectionPoint
*cpt1
, *cpt2
, *cpt3
;
417 BezCornerType old_ctype
;
420 assert(bez
->numpoints
> 2);
422 if (pos
== bez
->numpoints
-1) pos
--;
424 old_handle1
= bez
->object
.handles
[3*pos
-2];
425 old_handle2
= bez
->object
.handles
[3*pos
-1];
426 old_handle3
= bez
->object
.handles
[3*pos
];
427 old_point
= bez
->points
[pos
];
428 old_ctype
= bez
->corner_types
[pos
];
430 cpt1
= old_handle1
->connected_to
;
431 cpt2
= old_handle2
->connected_to
;
432 cpt3
= old_handle3
->connected_to
;
434 object_unconnect((Object
*)bez
, old_handle1
);
435 object_unconnect((Object
*)bez
, old_handle2
);
436 object_unconnect((Object
*)bez
, old_handle3
);
438 remove_handles(bez
, pos
);
440 bezierconn_update_data(bez
);
442 return bezierconn_create_point_change(bez
, TYPE_REMOVE_POINT
,
443 &old_point
, old_ctype
, pos
,
450 bezierconn_straighten_corner(BezierConn
*bez
, int comp_nr
) {
451 /* Neat thing would be to have the kind of straigthening depend on
452 which handle was chosen: Mid-handle does average, other leaves that
453 handle where it is. */
454 switch (bez
->corner_types
[comp_nr
]) {
455 case BEZ_CORNER_SYMMETRIC
: {
457 pt1
= bez
->points
[comp_nr
].p3
;
458 point_sub(&pt1
, &bez
->points
[comp_nr
].p2
);
459 pt2
= bez
->points
[comp_nr
].p3
;
460 point_sub(&pt2
, &bez
->points
[comp_nr
+1].p1
);
461 point_scale(&pt2
, -1.0);
462 point_add(&pt1
, &pt2
);
463 point_scale(&pt1
, 0.5);
465 point_scale(&pt1
, -1.0);
466 point_add(&pt1
, &bez
->points
[comp_nr
].p3
);
467 point_add(&pt2
, &bez
->points
[comp_nr
].p3
);
468 bez
->points
[comp_nr
].p2
= pt1
;
469 bez
->points
[comp_nr
+1].p1
= pt2
;
470 bezierconn_update_data(bez
);
473 case BEZ_CORNER_SMOOTH
: {
476 pt1
= bez
->points
[comp_nr
].p3
;
477 point_sub(&pt1
, &bez
->points
[comp_nr
].p2
);
478 pt2
= bez
->points
[comp_nr
].p3
;
479 point_sub(&pt2
, &bez
->points
[comp_nr
+1].p1
);
480 len1
= point_len(&pt1
);
481 len2
= point_len(&pt2
);
482 point_scale(&pt2
, -1.0);
484 point_normalize(&pt1
);
486 point_normalize(&pt2
);
487 point_add(&pt1
, &pt2
);
488 point_scale(&pt1
, 0.5);
490 point_scale(&pt1
, -len1
);
491 point_add(&pt1
, &bez
->points
[comp_nr
].p3
);
492 point_scale(&pt2
, len2
);
493 point_add(&pt2
, &bez
->points
[comp_nr
].p3
);
494 bez
->points
[comp_nr
].p2
= pt1
;
495 bez
->points
[comp_nr
+1].p1
= pt2
;
496 bezierconn_update_data(bez
);
499 case BEZ_CORNER_CUSP
:
505 bezierconn_set_corner_type(BezierConn
*bez
, Handle
*handle
,
506 BezCornerType corner_type
)
509 Point old_left
, old_right
;
511 int handle_nr
, comp_nr
;
513 handle_nr
= get_handle_nr(bez
, handle
);
515 switch (handle
->id
) {
516 case HANDLE_BEZMAJOR
:
519 case HANDLE_LEFTCTRL
:
521 mid_handle
= bez
->object
.handles
[handle_nr
];
523 case HANDLE_RIGHTCTRL
:
525 mid_handle
= bez
->object
.handles
[handle_nr
];
528 message_warning(_("Internal error: Setting corner type of endpoint of bezier"));
532 comp_nr
= get_major_nr(handle_nr
);
534 old_type
= bez
->corner_types
[comp_nr
];
535 old_left
= bez
->points
[comp_nr
].p2
;
536 old_right
= bez
->points
[comp_nr
+1].p1
;
538 bez
->corner_types
[comp_nr
] = corner_type
;
540 bezierconn_straighten_corner(bez
, comp_nr
);
542 return bezierconn_create_corner_change(bez
, mid_handle
, &old_left
, &old_right
,
543 old_type
, corner_type
);
547 bezierconn_update_data(BezierConn
*bez
)
551 /* Update handles: */
552 bez
->object
.handles
[0]->pos
= bez
->points
[0].p1
;
553 for (i
= 1; i
< bez
->numpoints
; i
++) {
554 bez
->object
.handles
[3*i
-2]->pos
= bez
->points
[i
].p1
;
555 bez
->object
.handles
[3*i
-1]->pos
= bez
->points
[i
].p2
;
556 bez
->object
.handles
[3*i
]->pos
= bez
->points
[i
].p3
;
561 bezierconn_update_boundingbox(BezierConn
*bez
)
565 polybezier_bbox(&bez
->points
[0],
567 &bez
->extra_spacing
, FALSE
,
568 &bez
->object
.bounding_box
);
572 bezierconn_simple_draw(BezierConn
*bez
, Renderer
*renderer
, real width
)
577 assert(renderer
!= NULL
);
579 points
= &bez
->points
[0];
581 renderer
->ops
->set_linewidth(renderer
, width
);
582 renderer
->ops
->set_linestyle(renderer
, LINESTYLE_SOLID
);
583 renderer
->ops
->set_linejoin(renderer
, LINEJOIN_ROUND
);
584 renderer
->ops
->set_linecaps(renderer
, LINECAPS_BUTT
);
586 renderer
->ops
->draw_bezier(renderer
, points
, bez
->numpoints
, &color_black
);
590 bezierconn_draw_control_lines(BezierConn
*bez
, Renderer
*renderer
)
592 Color line_colour
= {0.0, 0.0, 0.6};
596 /* setup renderer ... */
597 renderer
->ops
->set_linewidth(renderer
, 0);
598 renderer
->ops
->set_linestyle(renderer
, LINESTYLE_DOTTED
);
599 renderer
->ops
->set_dashlength(renderer
, 1);
600 renderer
->ops
->set_linejoin(renderer
, LINEJOIN_MITER
);
601 renderer
->ops
->set_linecaps(renderer
, LINECAPS_BUTT
);
603 startpoint
= bez
->points
[0].p1
;
604 for (i
= 1; i
< bez
->numpoints
; i
++) {
605 renderer
->ops
->draw_line(renderer
, &startpoint
, &bez
->points
[i
].p1
,
607 renderer
->ops
->draw_line(renderer
, &bez
->points
[i
].p2
, &bez
->points
[i
].p3
,
609 startpoint
= bez
->points
[i
].p3
;
614 bezierconn_init(BezierConn
*bez
, int num_points
)
621 object_init(obj
, 3*num_points
-2, 0);
623 bez
->numpoints
= num_points
;
625 bez
->points
= g_new(BezPoint
, num_points
);
626 bez
->corner_types
= g_new(BezCornerType
, num_points
);
627 bez
->points
[0].type
= BEZ_MOVE_TO
;
628 bez
->corner_types
[0] = BEZ_CORNER_SYMMETRIC
;
629 for (i
= 1; i
< num_points
; i
++) {
630 bez
->points
[i
].type
= BEZ_CURVE_TO
;
631 bez
->corner_types
[i
] = BEZ_CORNER_SYMMETRIC
;
634 obj
->handles
[0] = g_new(Handle
,1);
635 obj
->handles
[0]->connect_type
= HANDLE_CONNECTABLE
;
636 obj
->handles
[0]->connected_to
= NULL
;
637 obj
->handles
[0]->type
= HANDLE_MAJOR_CONTROL
;
638 obj
->handles
[0]->id
= HANDLE_MOVE_STARTPOINT
;
640 for (i
= 1; i
< num_points
; i
++) {
641 obj
->handles
[3*i
-2] = g_new(Handle
, 1);
642 obj
->handles
[3*i
-1] = g_new(Handle
, 1);
643 obj
->handles
[3*i
] = g_new(Handle
, 1);
645 obj
->handles
[3*i
-2]->connect_type
= HANDLE_NONCONNECTABLE
;
646 obj
->handles
[3*i
-2]->connected_to
= NULL
;
647 obj
->handles
[3*i
-2]->type
= HANDLE_MINOR_CONTROL
;
648 obj
->handles
[3*i
-2]->id
= HANDLE_RIGHTCTRL
;
650 obj
->handles
[3*i
-1]->connect_type
= HANDLE_NONCONNECTABLE
;
651 obj
->handles
[3*i
-1]->connected_to
= NULL
;
652 obj
->handles
[3*i
-1]->type
= HANDLE_MINOR_CONTROL
;
653 obj
->handles
[3*i
-1]->id
= HANDLE_LEFTCTRL
;
655 obj
->handles
[3*i
]->connect_type
= HANDLE_CONNECTABLE
;
656 obj
->handles
[3*i
]->connected_to
= NULL
;
657 obj
->handles
[3*i
]->type
= HANDLE_MAJOR_CONTROL
;
658 obj
->handles
[3*i
]->id
= HANDLE_MOVE_ENDPOINT
;
660 bezierconn_update_data(bez
);
664 bezierconn_set_points(BezierConn
*bez
, int num_points
, BezPoint
*points
)
669 bezierconn_copy(BezierConn
*from
, BezierConn
*to
)
672 Object
*toobj
, *fromobj
;
675 fromobj
= &from
->object
;
677 object_copy(fromobj
, toobj
);
679 to
->numpoints
= from
->numpoints
;
681 to
->points
= g_new(BezPoint
, to
->numpoints
);
682 to
->corner_types
= g_new(BezCornerType
, to
->numpoints
);
684 for (i
= 0; i
< to
->numpoints
; i
++) {
685 to
->points
[i
] = from
->points
[i
];
686 to
->corner_types
[i
] = from
->corner_types
[i
];
689 to
->object
.handles
[0] = g_new(Handle
,1);
690 *to
->object
.handles
[0] = *from
->object
.handles
[0];
691 for (i
= 1; i
< to
->object
.num_handles
- 1; i
++) {
692 to
->object
.handles
[i
] = g_new(Handle
, 1);
693 setup_corner_handle(to
->object
.handles
[i
], from
->object
.handles
[i
]->id
);
695 to
->object
.handles
[to
->object
.num_handles
-1] = g_new(Handle
,1);
696 *to
->object
.handles
[to
->object
.num_handles
-1] =
697 *from
->object
.handles
[to
->object
.num_handles
-1];
699 memcpy(&to
->extra_spacing
,&from
->extra_spacing
,sizeof(to
->extra_spacing
));
700 bezierconn_update_data(to
);
704 bezierconn_destroy(BezierConn
*bez
)
707 Handle
**temp_handles
;
709 /* Need to store these temporary since object.handles is
710 freed by object_destroy() */
711 nh
= bez
->object
.num_handles
;
712 temp_handles
= g_new(Handle
*, nh
);
713 for (i
= 0; i
< nh
; i
++)
714 temp_handles
[i
] = bez
->object
.handles
[i
];
716 object_destroy(&bez
->object
);
718 for (i
= 0; i
< nh
; i
++)
719 g_free(temp_handles
[i
]);
720 g_free(temp_handles
);
723 g_free(bez
->corner_types
);
728 bezierconn_save(BezierConn
*bez
, ObjectNode obj_node
)
733 object_save(&bez
->object
, obj_node
);
735 attr
= new_attribute(obj_node
, "bez_points");
737 data_add_point(attr
, &bez
->points
[0].p1
);
738 for (i
= 1; i
< bez
->numpoints
; i
++) {
739 data_add_point(attr
, &bez
->points
[i
].p1
);
740 data_add_point(attr
, &bez
->points
[i
].p2
);
741 data_add_point(attr
, &bez
->points
[i
].p3
);
744 attr
= new_attribute(obj_node
, "corner_types");
745 for (i
= 0; i
< bez
->numpoints
; i
++)
746 data_add_enum(attr
, bez
->corner_types
[i
]);
750 bezierconn_load(BezierConn
*bez
, ObjectNode obj_node
) /* NOTE: Does object_init() */
756 Object
*obj
= &bez
->object
;
758 object_load(obj
, obj_node
);
760 attr
= object_find_attribute(obj_node
, "bez_points");
763 bez
->numpoints
= (attribute_num_data(attr
) + 2)/3;
767 object_init(obj
, 3 * bez
->numpoints
- 2, 0);
769 data
= attribute_first_data(attr
);
770 if (bez
->numpoints
!= 0) {
771 bez
->points
= g_new(BezPoint
, bez
->numpoints
);
772 bez
->points
[0].type
= BEZ_MOVE_TO
;
773 data_point(data
, &bez
->points
[0].p1
);
774 data
= data_next(data
);
776 for (i
= 1; i
< bez
->numpoints
; i
++) {
777 bez
->points
[i
].type
= BEZ_CURVE_TO
;
778 data_point(data
, &bez
->points
[i
].p1
);
779 data
= data_next(data
);
780 data_point(data
, &bez
->points
[i
].p2
);
781 data
= data_next(data
);
782 data_point(data
, &bez
->points
[i
].p3
);
783 data
= data_next(data
);
787 bez
->corner_types
= g_new(BezCornerType
, bez
->numpoints
);
789 attr
= object_find_attribute(obj_node
, "corner_types");
790 /* if corner_types is missing or corrupt */
791 if (!attr
|| attribute_num_data(attr
) != bez
->numpoints
) {
792 for (i
= 0; i
< bez
->numpoints
; i
++) {
793 bez
->corner_types
[i
] = BEZ_CORNER_SYMMETRIC
;
796 data
= attribute_first_data(attr
);
797 for (i
= 0; i
< bez
->numpoints
; i
++) {
798 bez
->corner_types
[i
] = data_enum(data
);
799 data
= data_next(data
);
803 obj
->handles
[0] = g_new(Handle
, 1);
804 obj
->handles
[0]->connect_type
= HANDLE_CONNECTABLE
;
805 obj
->handles
[0]->connected_to
= NULL
;
806 obj
->handles
[0]->type
= HANDLE_MAJOR_CONTROL
;
807 obj
->handles
[0]->id
= HANDLE_MOVE_STARTPOINT
;
809 for (i
= 1; i
< bez
->numpoints
; i
++) {
810 obj
->handles
[3*i
-2] = g_new(Handle
, 1);
811 setup_corner_handle(obj
->handles
[3*i
-2], HANDLE_RIGHTCTRL
);
812 obj
->handles
[3*i
-1] = g_new(Handle
, 1);
813 setup_corner_handle(obj
->handles
[3*i
-1], HANDLE_LEFTCTRL
);
814 obj
->handles
[3*i
] = g_new(Handle
, 1);
815 setup_corner_handle(obj
->handles
[3*i
], HANDLE_BEZMAJOR
);
818 obj
->handles
[obj
->num_handles
-1]->connect_type
= HANDLE_CONNECTABLE
;
819 obj
->handles
[obj
->num_handles
-1]->connected_to
= NULL
;
820 obj
->handles
[obj
->num_handles
-1]->type
= HANDLE_MAJOR_CONTROL
;
821 obj
->handles
[obj
->num_handles
-1]->id
= HANDLE_MOVE_ENDPOINT
;
823 bezierconn_update_data(bez
);
827 bezierconn_point_change_free(struct PointChange
*change
)
829 if ( (change
->type
==TYPE_ADD_POINT
&& !change
->applied
) ||
830 (change
->type
==TYPE_REMOVE_POINT
&& change
->applied
) ){
831 g_free(change
->handle1
);
832 g_free(change
->handle2
);
833 g_free(change
->handle3
);
834 change
->handle1
= NULL
;
835 change
->handle2
= NULL
;
836 change
->handle3
= NULL
;
841 bezierconn_point_change_apply(struct PointChange
*change
, Object
*obj
)
844 switch (change
->type
) {
846 add_handles((BezierConn
*)obj
, change
->pos
, &change
->point
,
848 change
->handle1
, change
->handle2
, change
->handle3
);
850 case TYPE_REMOVE_POINT
:
851 object_unconnect(obj
, change
->handle1
);
852 object_unconnect(obj
, change
->handle2
);
853 object_unconnect(obj
, change
->handle3
);
854 remove_handles((BezierConn
*)obj
, change
->pos
);
860 bezierconn_point_change_revert(struct PointChange
*change
, Object
*obj
)
862 switch (change
->type
) {
864 remove_handles((BezierConn
*)obj
, change
->pos
);
866 case TYPE_REMOVE_POINT
:
867 add_handles((BezierConn
*)obj
, change
->pos
, &change
->point
,
869 change
->handle1
, change
->handle2
, change
->handle3
);
871 if (change
->connected_to1
)
872 object_connect(obj
, change
->handle1
, change
->connected_to1
);
873 if (change
->connected_to2
)
874 object_connect(obj
, change
->handle2
, change
->connected_to2
);
875 if (change
->connected_to3
)
876 object_connect(obj
, change
->handle3
, change
->connected_to3
);
883 static ObjectChange
*
884 bezierconn_create_point_change(BezierConn
*bez
, enum change_type type
,
885 BezPoint
*point
, BezCornerType corner_type
,
887 Handle
*handle1
, ConnectionPoint
*connected_to1
,
888 Handle
*handle2
, ConnectionPoint
*connected_to2
,
889 Handle
*handle3
, ConnectionPoint
*connected_to3
)
891 struct PointChange
*change
;
893 change
= g_new(struct PointChange
, 1);
895 change
->obj_change
.apply
= (ObjectChangeApplyFunc
) bezierconn_point_change_apply
;
896 change
->obj_change
.revert
= (ObjectChangeRevertFunc
) bezierconn_point_change_revert
;
897 change
->obj_change
.free
= (ObjectChangeFreeFunc
) bezierconn_point_change_free
;
901 change
->point
= *point
;
902 change
->corner_type
= corner_type
;
904 change
->handle1
= handle1
;
905 change
->connected_to1
= connected_to1
;
906 change
->handle2
= handle2
;
907 change
->connected_to2
= connected_to2
;
908 change
->handle3
= handle3
;
909 change
->connected_to3
= connected_to3
;
911 return (ObjectChange
*)change
;
915 bezierconn_corner_change_apply(struct CornerChange
*change
,
917 BezierConn
*bez
= (BezierConn
*)obj
;
918 int handle_nr
= get_handle_nr(bez
, change
->handle
);
919 int comp_nr
= get_major_nr(handle_nr
);
921 bezierconn_straighten_corner(bez
, comp_nr
);
923 bez
->corner_types
[comp_nr
] = change
->new_type
;
929 bezierconn_corner_change_revert(struct CornerChange
*change
,
931 BezierConn
*bez
= (BezierConn
*)obj
;
932 int handle_nr
= get_handle_nr(bez
, change
->handle
);
933 int comp_nr
= get_major_nr(handle_nr
);
935 bez
->points
[comp_nr
].p2
= change
->point_left
;
936 bez
->points
[comp_nr
+1].p1
= change
->point_right
;
937 bez
->corner_types
[comp_nr
] = change
->old_type
;
942 static ObjectChange
*
943 bezierconn_create_corner_change(BezierConn
*bez
, Handle
*handle
,
944 Point
*point_left
, Point
*point_right
,
945 BezCornerType old_corner_type
,
946 BezCornerType new_corner_type
)
948 struct CornerChange
*change
;
950 change
= g_new(struct CornerChange
, 1);
952 change
->obj_change
.apply
= (ObjectChangeApplyFunc
) bezierconn_corner_change_apply
;
953 change
->obj_change
.revert
= (ObjectChangeRevertFunc
) bezierconn_corner_change_revert
;
954 change
->obj_change
.free
= (ObjectChangeFreeFunc
) NULL
;
956 change
->old_type
= old_corner_type
;
957 change
->new_type
= new_corner_type
;
960 change
->handle
= handle
;
961 change
->point_left
= *point_left
;
962 change
->point_right
= *point_right
;
964 return (ObjectChange
*)change
;