/*! * \brief Limit movability of control handles * * Update a corner to have less freedom in its control handles, arranging * the control points at some reasonable places. * @param bezier A bezierconn to straighten a corner of * @param comp_nr The index into the corner_types array of the corner to * straighten. * \memberof _BezierConn */ static void bezierconn_straighten_corner (BezierConn *bezier, int comp_nr) { int next_nr = comp_nr+1; /* Neat thing would be to have the kind of straigthening depend on which handle was chosen: Mid-handle does average, other leaves that handle where it is. */ switch (bezier->bezier.corner_types[comp_nr]) { case BEZ_CORNER_SYMMETRIC: { Point pt1, pt2; pt1 = bezier->bezier.points[comp_nr].p3; point_sub(&pt1, &bezier->bezier.points[comp_nr].p2); pt2 = bezier->bezier.points[comp_nr].p3; point_sub(&pt2, &bezier->bezier.points[next_nr].p1); point_scale(&pt2, -1.0); point_add(&pt1, &pt2); point_scale(&pt1, 0.5); pt2 = pt1; point_scale(&pt1, -1.0); point_add(&pt1, &bezier->bezier.points[comp_nr].p3); point_add(&pt2, &bezier->bezier.points[comp_nr].p3); bezier->bezier.points[comp_nr].p2 = pt1; bezier->bezier.points[next_nr].p1 = pt2; bezierconn_update_data(bezier); } break; case BEZ_CORNER_SMOOTH: { Point pt1, pt2; real len1, len2; pt1 = bezier->bezier.points[comp_nr].p3; point_sub(&pt1, &bezier->bezier.points[comp_nr].p2); pt2 = bezier->bezier.points[comp_nr].p3; point_sub(&pt2, &bezier->bezier.points[next_nr].p1); len1 = point_len(&pt1); len2 = point_len(&pt2); point_scale(&pt2, -1.0); if (len1 > 0) point_normalize(&pt1); if (len2 > 0) point_normalize(&pt2); point_add(&pt1, &pt2); point_scale(&pt1, 0.5); pt2 = pt1; point_scale(&pt1, -len1); point_add(&pt1, &bezier->bezier.points[comp_nr].p3); point_scale(&pt2, len2); point_add(&pt2, &bezier->bezier.points[comp_nr].p3); bezier->bezier.points[comp_nr].p2 = pt1; bezier->bezier.points[next_nr].p1 = pt2; bezierconn_update_data(bezier); } break; case BEZ_CORNER_CUSP: break; } }
static void bezierline_update_data(Bezierline *bezierline) { BezierConn *bez = &bezierline->bez; Object *obj = (Object *) bezierline; bezierconn_update_data(bez); bezierconn_update_boundingbox(bez); /* fix boundingbox for line_width: */ obj->bounding_box.top -= bezierline->line_width/2; obj->bounding_box.left -= bezierline->line_width/2; obj->bounding_box.bottom += bezierline->line_width/2; obj->bounding_box.right += bezierline->line_width/2; /* Fix boundingbox for arrowheads */ if (bezierline->start_arrow.type != ARROW_NONE || bezierline->end_arrow.type != ARROW_NONE) { real arrow_width = 0.0; if (bezierline->start_arrow.type != ARROW_NONE) arrow_width = bezierline->start_arrow.width; if (bezierline->end_arrow.type != ARROW_NONE) arrow_width = MAX(arrow_width, bezierline->start_arrow.width); obj->bounding_box.top -= arrow_width; obj->bounding_box.left -= arrow_width; obj->bounding_box.bottom += arrow_width; obj->bounding_box.right += arrow_width; } obj->position = bez->points[0].p1; }
/*! * \brief Remove a segment from a bezier. * @param bezier The bezier to remove a segment from. * @param pos The index of the segment to remove. * @returns Undo information for the segment removal. * \memberof _BezierConn */ ObjectChange * bezierconn_remove_segment (BezierConn *bezier, int pos) { Handle *old_handle1, *old_handle2, *old_handle3; ConnectionPoint *cpt1, *cpt2, *cpt3; BezPoint old_point; BezCornerType old_ctype; int next; g_assert(pos > 0); g_assert(bezier->bezier.num_points > 2); if (pos == bezier->bezier.num_points-1) pos--; next = pos+1; old_handle1 = bezier->object.handles[3*pos-2]; old_handle2 = bezier->object.handles[3*pos-1]; old_handle3 = bezier->object.handles[3*pos]; old_point = bezier->bezier.points[pos]; /* remember the old control point of following bezpoint */ old_point.p1 = bezier->bezier.points[next].p1; old_ctype = bezier->bezier.corner_types[pos]; cpt1 = old_handle1->connected_to; cpt2 = old_handle2->connected_to; cpt3 = old_handle3->connected_to; object_unconnect((DiaObject *)bezier, old_handle1); object_unconnect((DiaObject *)bezier, old_handle2); object_unconnect((DiaObject *)bezier, old_handle3); remove_handles(bezier, pos); bezierconn_update_data(bezier); return bezierconn_create_point_change(bezier, TYPE_REMOVE_POINT, &old_point, old_ctype, pos, old_handle1, cpt1, old_handle2, cpt2, old_handle3, cpt3); }
static void bezierline_update_data(Bezierline *bezierline) { BezierConn *bez = &bezierline->bez; DiaObject *obj = &bez->object; PolyBBExtras *extra = &bez->extra_spacing; bezierconn_update_data(bez); extra->start_trans = extra->start_long = extra->middle_trans = extra->end_trans = extra->end_long = (bezierline->line_width / 2.0); obj->position = bez->bezier.points[0].p1; if (connpoint_is_autogap(bez->object.handles[0]->connected_to) || connpoint_is_autogap(bez->object.handles[3*(bez->bezier.num_points-1)]->connected_to) || bezierline->absolute_start_gap || bezierline->absolute_end_gap || bezierline->start_arrow.type != ARROW_NONE || bezierline->end_arrow.type != ARROW_NONE) { Point gap_points[4]; Rectangle bbox_union = {bez->bezier.points[0].p1.x, bez->bezier.points[0].p1.y, bez->bezier.points[0].p1.x, bez->bezier.points[0].p1.y}; compute_gap_points(bezierline, gap_points); exchange_bez_gap_points(bez,gap_points); /* further modifying the points data, accounts for corrcet arrow and bezier bounding box */ if (bezierline->start_arrow.type != ARROW_NONE) { Rectangle bbox; Point move_arrow, move_line; Point to = bez->bezier.points[0].p1, from = bez->bezier.points[1].p1; calculate_arrow_point(&bezierline->start_arrow, &to, &from, &move_arrow, &move_line, bezierline->line_width); point_sub(&to, &move_arrow); point_sub(&bez->bezier.points[0].p1, &move_line); arrow_bbox (&bezierline->start_arrow, bezierline->line_width, &to, &from, &bbox); rectangle_union (&bbox_union, &bbox); } if (bezierline->end_arrow.type != ARROW_NONE) { Rectangle bbox; Point move_arrow, move_line; int num_points = bez->bezier.num_points; Point to = bez->bezier.points[num_points-1].p3, from = bez->bezier.points[num_points-1].p2; calculate_arrow_point(&bezierline->end_arrow, &to, &from, &move_arrow, &move_line, bezierline->line_width); point_sub(&to, &move_arrow); point_sub(&bez->bezier.points[num_points-1].p3, &move_line); arrow_bbox (&bezierline->end_arrow, bezierline->line_width, &to, &from, &bbox); rectangle_union (&bbox_union, &bbox); } bezierconn_update_boundingbox(bez); rectangle_union (&obj->bounding_box, &bbox_union); exchange_bez_gap_points(bez,gap_points); } else { bezierconn_update_boundingbox(bez); } /* add control points to the bounding box, needed to make them visible when showing all * and to remove traces from them */ { int i, num_points = bez->bezier.num_points; g_assert (obj->enclosing_box != NULL); *obj->enclosing_box = obj->bounding_box; /* starting with the second point, the first one is MOVE_TO */ for (i = 1; i < num_points; ++i) { if (bez->bezier.points[i].type != BEZ_CURVE_TO) continue; rectangle_add_point(obj->enclosing_box, &bez->bezier.points[i].p1); rectangle_add_point(obj->enclosing_box, &bez->bezier.points[i].p2); } } }
static void bezierline_select(Bezierline *bezierline, Point *clicked_point, DiaRenderer *interactive_renderer) { bezierconn_update_data(&bezierline->bez); }