ObjectChange * beziershape_move_handle(BezierShape *bezier, Handle *handle, Point *to, ConnectionPoint *cp, HandleMoveReason reason, ModifierKeys modifiers) { int handle_nr, comp_nr, next_nr, prev_nr; Point delta, pt; delta = *to; point_sub(&delta, &handle->pos); handle_nr = get_handle_nr(bezier, handle); comp_nr = get_comp_nr(handle_nr); next_nr = comp_nr + 1; prev_nr = comp_nr - 1; if (comp_nr == bezier->numpoints - 1) next_nr = 1; if (comp_nr == 1) prev_nr = bezier->numpoints - 1; switch(handle->id) { case HANDLE_BEZMAJOR: if (comp_nr == bezier->numpoints - 1) { bezier->points[comp_nr].p3 = *to; bezier->points[0].p1 = bezier->points[0].p3 = *to; point_add(&bezier->points[comp_nr].p2, &delta); point_add(&bezier->points[1].p1, &delta); } else { bezier->points[comp_nr].p3 = *to; point_add(&bezier->points[comp_nr].p2, &delta); point_add(&bezier->points[comp_nr+1].p1, &delta); } break; case HANDLE_LEFTCTRL: bezier->points[comp_nr].p2 = *to; switch (bezier->corner_types[comp_nr]) { case BEZ_CORNER_SYMMETRIC: pt = bezier->points[comp_nr].p3; point_sub(&pt, &bezier->points[comp_nr].p2); point_add(&pt, &bezier->points[comp_nr].p3); bezier->points[next_nr].p1 = pt; break; case BEZ_CORNER_SMOOTH: { real len; pt = bezier->points[next_nr].p1; point_sub(&pt, &bezier->points[comp_nr].p3); len = point_len(&pt); pt = bezier->points[comp_nr].p3; point_sub(&pt, &bezier->points[comp_nr].p2); if (point_len(&pt) > 0) point_normalize(&pt); else { pt.x = 1.0; pt.y = 0.0; } point_scale(&pt, len); point_add(&pt, &bezier->points[comp_nr].p3); bezier->points[next_nr].p1 = pt; break; } case BEZ_CORNER_CUSP: /* no mirror point movement required */ break; } break; case HANDLE_RIGHTCTRL: bezier->points[comp_nr].p1 = *to; switch (bezier->corner_types[prev_nr]) { case BEZ_CORNER_SYMMETRIC: pt = bezier->points[prev_nr].p3; point_sub(&pt, &bezier->points[comp_nr].p1); point_add(&pt, &bezier->points[prev_nr].p3); bezier->points[prev_nr].p2 = pt; break; case BEZ_CORNER_SMOOTH: { real len; pt = bezier->points[prev_nr].p2; point_sub(&pt, &bezier->points[prev_nr].p3); len = point_len(&pt); pt = bezier->points[prev_nr].p3; point_sub(&pt, &bezier->points[comp_nr].p1); if (point_len(&pt) > 0) point_normalize(&pt); else { pt.x = 1.0; pt.y = 0.0; } point_scale(&pt, len); point_add(&pt, &bezier->points[prev_nr].p3); bezier->points[prev_nr].p2 = pt; break; } case BEZ_CORNER_CUSP: /* no mirror point movement required */ break; } break; default: message_error("Internal error in beziershape_move_handle."); break; } return NULL; }
/*! * \brief Move one of the handles associated with the * @param bezier The object whose handle is being moved. * @param handle The handle being moved. * @param to The position it has been moved to (corrected for * vertical/horizontal only movement). * @param cp If non-NULL, the connectionpoint found at this position. * If @a cp is NULL, there may or may not be a connectionpoint. * @param reason ignored * @param modifiers ignored * @return NULL * \memberof BezierConn */ ObjectChange* bezierconn_move_handle (BezierConn *bezier, Handle *handle, Point *to, ConnectionPoint *cp, HandleMoveReason reason, ModifierKeys modifiers) { int handle_nr, comp_nr; Point delta, pt; delta = *to; point_sub(&delta, &handle->pos); handle_nr = get_handle_nr(bezier, handle); comp_nr = get_comp_nr(handle_nr); switch(handle->id) { case HANDLE_MOVE_STARTPOINT: bezier->bezier.points[0].p1 = *to; /* shift adjacent point */ point_add(&bezier->bezier.points[1].p1, &delta); break; case HANDLE_MOVE_ENDPOINT: bezier->bezier.points[bezier->bezier.num_points-1].p3 = *to; /* shift adjacent point */ point_add(&bezier->bezier.points[bezier->bezier.num_points-1].p2, &delta); break; case HANDLE_BEZMAJOR: bezier->bezier.points[comp_nr].p3 = *to; /* shift adjacent point */ point_add(&bezier->bezier.points[comp_nr].p2, &delta); point_add(&bezier->bezier.points[comp_nr+1].p1, &delta); break; case HANDLE_LEFTCTRL: bezier->bezier.points[comp_nr].p2 = *to; if (comp_nr < bezier->bezier.num_points - 1) { switch (bezier->bezier.corner_types[comp_nr]) { case BEZ_CORNER_SYMMETRIC: pt = bezier->bezier.points[comp_nr].p3; point_sub(&pt, &bezier->bezier.points[comp_nr].p2); point_add(&pt, &bezier->bezier.points[comp_nr].p3); bezier->bezier.points[comp_nr+1].p1 = pt; break; case BEZ_CORNER_SMOOTH: { real len; pt = bezier->bezier.points[comp_nr+1].p1; point_sub(&pt, &bezier->bezier.points[comp_nr].p3); len = point_len(&pt); pt = bezier->bezier.points[comp_nr].p2; point_sub(&pt, &bezier->bezier.points[comp_nr].p3); if (point_len(&pt) > 0) point_normalize(&pt); else { pt.x = 1.0; pt.y = 0.0; } point_scale(&pt, -len); point_add(&pt, &bezier->bezier.points[comp_nr].p3); bezier->bezier.points[comp_nr+1].p1 = pt; break; } case BEZ_CORNER_CUSP: /* Do nothing to the other guy */ break; } } break; case HANDLE_RIGHTCTRL: bezier->bezier.points[comp_nr].p1 = *to; if (comp_nr > 1) { switch (bezier->bezier.corner_types[comp_nr-1]) { case BEZ_CORNER_SYMMETRIC: pt = bezier->bezier.points[comp_nr - 1].p3; point_sub(&pt, &bezier->bezier.points[comp_nr].p1); point_add(&pt, &bezier->bezier.points[comp_nr - 1].p3); bezier->bezier.points[comp_nr-1].p2 = pt; break; case BEZ_CORNER_SMOOTH: { real len; pt = bezier->bezier.points[comp_nr-1].p2; point_sub(&pt, &bezier->bezier.points[comp_nr-1].p3); len = point_len(&pt); pt = bezier->bezier.points[comp_nr].p1; point_sub(&pt, &bezier->bezier.points[comp_nr-1].p3); if (point_len(&pt) > 0) point_normalize(&pt); else { pt.x = 1.0; pt.y = 0.0; } point_scale(&pt, -len); point_add(&pt, &bezier->bezier.points[comp_nr-1].p3); bezier->bezier.points[comp_nr-1].p2 = pt; break; } case BEZ_CORNER_CUSP: /* Do nothing to the other guy */ break; } } break; default: g_warning("Internal error in bezierconn_move_handle.\n"); break; } return NULL; }