/*! * \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; } }
void transform_length (real *len, const DiaMatrix *m) { Point pt = { *len, 0 }; transform_point (&pt, m); /* not interested in the offset */ pt.x -= m->x0; pt.y -= m->y0; *len = point_len (&pt); }
/** rotates p around the center by an angle given in radians * a positive angle is ccw on the screen*/ static void rotate_point_around_point(Point *p, const Point *center, real angle) { real radius; real a; point_sub(p,center); radius = point_len(p); a = -atan2(p->y,p->x); /* y axis points down*/ a += angle; p->x = cos(a); p->y = -sin(a);/* y axis points down*/ point_scale(p,radius); point_add(p,center); }
static real approx_bez_length(BezierConn *bez) { /* Approximates the length of the bezier curve * by the length of the polyline joining its points */ Point *current, *last, vec; real length = .0; int i; current = &bez->bezier.points[0].p1; for (i=1; i < bez->bezier.num_points ; i++){ last = current; current = &bez->bezier.points[i].p3; point_copy(&vec,last); point_sub(&vec,current); length += point_len(&vec); } return length; }
void connpointline_putonaline(ConnPointLine *cpl,Point *start,Point *end, gint dirs) { Point se_vector; real se_len,pseudopoints; int i; GSList *elem; point_copy(&se_vector, end); point_sub(&se_vector, start); se_len = point_len(&se_vector); if (se_len > 0) point_normalize(&se_vector); cpl->start = *start; cpl->end = *end; if (dirs != DIR_NONE) /* use the oone givne by the caller */; else if (fabs(se_vector.x) > fabs(se_vector.y)) dirs = DIR_NORTH|DIR_SOUTH; else dirs = DIR_EAST|DIR_WEST; pseudopoints = cpl->num_connections + 1; /* here, we count the start and end points as eating real positions. */ for (i=0, elem=cpl->connections; i<cpl->num_connections; i++,elem=g_slist_next(elem)) { ConnectionPoint *cp = (ConnectionPoint *)(elem->data); cp->pos = se_vector; cp->directions = dirs; point_scale(&cp->pos,se_len * (i+1.0)/pseudopoints); point_add(&cp->pos,start); } }
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; }
static void wanlink_update_data(WanLink *wanlink) { Connection *conn = &wanlink->connection; DiaObject *obj = (DiaObject *) wanlink; Point v, vhat; Point *endpoints; real width, width_2; real len, angle; Point origin; int i; Matrix m; width = wanlink->width; width_2 = width / 2.0; if (connpoint_is_autogap(conn->endpoint_handles[0].connected_to) || connpoint_is_autogap(conn->endpoint_handles[1].connected_to)) { connection_adjust_for_autogap(conn); } endpoints = &conn->endpoints[0]; obj->position = endpoints[0]; v = endpoints[1]; point_sub(&v, &endpoints[0]); if ((fabs(v.x) == 0.0) && (fabs(v.y)==0.0)) { v.x += 0.01; } vhat = v; point_normalize(&vhat); connection_update_boundingbox(conn); /** compute the polygon **/ origin = wanlink->connection.endpoints [0]; len = point_len (&v); angle = atan2 (vhat.y, vhat.x) - M_PI_2; /* The case of the wanlink */ wanlink->poly[0].x = (width * 0.50) - width_2; wanlink->poly[0].y = (len * 0.00); wanlink->poly[1].x = (width * 0.50) - width_2; wanlink->poly[1].y = (len * 0.45); wanlink->poly[2].x = (width * 0.94) - width_2; wanlink->poly[2].y = (len * 0.45); wanlink->poly[3].x = (width * 0.50) - width_2; wanlink->poly[3].y = (len * 1.00); wanlink->poly[4].x = (width * 0.50) - width_2; wanlink->poly[4].y = (len * 0.55); wanlink->poly[5].x = (width * 0.06) - width_2; wanlink->poly[5].y = (len * 0.55); /* rotate */ _identity_matrix (m); _rotate_matrix (m, angle); obj->bounding_box.top = origin.y; obj->bounding_box.left = origin.x; obj->bounding_box.bottom = conn->endpoints[1].y; obj->bounding_box.right = conn->endpoints[1].x; for (i = 0; i < WANLINK_POLY_LEN; i++) { Point new_pt; _transform_point (m, &wanlink->poly[i], &new_pt); point_add (&new_pt, &origin); wanlink->poly[i] = new_pt; } /* calculate bounding box */ { PolyBBExtras bbex = {0, 0, wanlink->width/2, 0, 0 }; polyline_bbox (&wanlink->poly[0], WANLINK_POLY_LEN, &bbex, TRUE, &obj->bounding_box); } connection_update_handles(conn); }
/*! * \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; }