static void implements_move_handle(Implements *implements, Handle *handle, Point *to, HandleMoveReason reason, ModifierKeys modifiers) { Point v1, v2; assert(implements!=NULL); assert(handle!=NULL); assert(to!=NULL); if (handle->id == HANDLE_MOVE_TEXT) { implements->text_pos = *to; } else if (handle->id == HANDLE_CIRCLE_SIZE) { v1 = implements->connection.endpoints[0]; point_sub(&v1, &implements->connection.endpoints[1]); point_normalize(&v1); v2 = *to; point_sub(&v2, &implements->connection.endpoints[1]); implements->circle_diameter = point_dot(&v1, &v2); if (implements->circle_diameter<0.03) implements->circle_diameter = 0.03; } else { v1 = implements->connection.endpoints[1]; connection_move_handle(&implements->connection, handle->id, to, reason); point_sub(&v1, &implements->connection.endpoints[1]); point_sub(&implements->text_pos, &v1); } implements_update_data(implements); }
static ObjectChange* mbr_move_handle(Mbr *mbr, Handle *handle, Point *to, ConnectionPoint *cp, HandleMoveReason reason, ModifierKeys modifiers) { Point p1, p2; Point *endpoints; assert(mbr!=NULL); assert(handle!=NULL); assert(to!=NULL); if (handle->id == HANDLE_MOVE_MID_POINT) { mbr->pm = *to; } else { endpoints = &mbr->connection.endpoints[0]; p1.x = 0.5*(endpoints[0].x + endpoints[1].x); p1.y = 0.5*(endpoints[0].y + endpoints[1].y); connection_move_handle(&mbr->connection, handle->id, to, cp, reason, modifiers); p2.x = 0.5*(endpoints[0].x + endpoints[1].x); p2.y = 0.5*(endpoints[0].y + endpoints[1].y); point_sub(&p2, &p1); point_add(&mbr->pm, &p2); } mbr_update_data(mbr); return NULL; }
static void message_move_handle(Message *message, Handle *handle, Point *to, HandleMoveReason reason, ModifierKeys modifiers) { Point p1, p2; Point *endpoints; assert(message!=NULL); assert(handle!=NULL); assert(to!=NULL); if (handle->id == HANDLE_MOVE_TEXT) { message->text_pos = *to; } else { endpoints = &message->connection.endpoints[0]; p1.x = 0.5*(endpoints[0].x + endpoints[1].x); p1.y = 0.5*(endpoints[0].y + endpoints[1].y); connection_move_handle(&message->connection, handle->id, to, reason); p2.x = 0.5*(endpoints[0].x + endpoints[1].x); p2.y = 0.5*(endpoints[0].y + endpoints[1].y); point_sub(&p2, &p1); point_add(&message->text_pos, &p2); } message_update_data(message); }
static void arc_move_handle(Arc *arc, Handle *handle, Point *to, HandleMoveReason reason, ModifierKeys modifiers) { assert(arc!=NULL); assert(handle!=NULL); assert(to!=NULL); if (handle->id == HANDLE_MIDDLE) { Point a,b; real tmp; b = *to; point_sub(&b, &arc->connection.endpoints[0]); a = arc->connection.endpoints[1]; point_sub(&a, &arc->connection.endpoints[0]); tmp = point_dot(&a,&b); arc->curve_distance = sqrt(fabs(point_dot(&b,&b) - tmp*tmp/point_dot(&a,&a))); if (a.x*b.y - a.y*b.x < 0) arc->curve_distance = -arc->curve_distance; } else { connection_move_handle(&arc->connection, handle->id, to, reason); } arc_update_data(arc); }
static ObjectChange* constraint_move_handle(Constraint *constraint, Handle *handle, Point *to, ConnectionPoint *cp, HandleMoveReason reason, ModifierKeys modifiers) { Point p1, p2; Point *endpoints; assert(constraint!=NULL); assert(handle!=NULL); assert(to!=NULL); if (handle->id == HANDLE_MOVE_TEXT) { constraint->text_pos = *to; } else { endpoints = &constraint->connection.endpoints[0]; p1.x = 0.5*(endpoints[0].x + endpoints[1].x); p1.y = 0.5*(endpoints[0].y + endpoints[1].y); connection_move_handle(&constraint->connection, handle->id, to, cp, reason, modifiers); connection_adjust_for_autogap(&constraint->connection); p2.x = 0.5*(endpoints[0].x + endpoints[1].x); p2.y = 0.5*(endpoints[0].y + endpoints[1].y); point_sub(&p2, &p1); point_add(&constraint->text_pos, &p2); } constraint_update_data(constraint); return NULL; }
static ObjectChange* measure_move_handle (Measure *measure, Handle *handle, Point *to, ConnectionPoint *cp, HandleMoveReason reason, ModifierKeys modifiers) { connection_move_handle(&measure->connection, handle->id, to, cp, reason, modifiers); measure_update_data(measure); return NULL; }
static void line_move_handle(Line *line, Handle *handle, Point *to, HandleMoveReason reason, ModifierKeys modifiers) { assert(line!=NULL); assert(handle!=NULL); assert(to!=NULL); connection_move_handle(&line->connection, handle->id, to, reason); line_update_data(line); }
static ObjectChange* wanlink_move_handle(WanLink *wanlink, Handle *handle, Point *to, ConnectionPoint *cp, HandleMoveReason reason, ModifierKeys modifiers) { connection_move_handle(&wanlink->connection, handle->id, to, cp, reason, modifiers); connection_adjust_for_autogap(&wanlink->connection); wanlink_update_data(wanlink); return NULL; }
static ObjectChange* annotation_move_handle(Annotation *annotation, Handle *handle, Point *to, ConnectionPoint *cp, HandleMoveReason reason, ModifierKeys modifiers) { Point p1, p2; Point *endpoints; Connection *conn = (Connection *)annotation; g_assert(annotation!=NULL); g_assert(handle!=NULL); g_assert(to!=NULL); if (handle->id == HANDLE_MOVE_TEXT) { annotation->text->position = *to; } else { endpoints = &(conn->endpoints[0]); if (handle->id == HANDLE_MOVE_STARTPOINT) { p1 = endpoints[0]; connection_move_handle(conn, handle->id, to, cp, reason, modifiers); p2 = endpoints[0]; point_sub(&p2, &p1); point_add(&annotation->text->position, &p2); point_add(&p2,&(endpoints[1])); connection_move_handle(conn, HANDLE_MOVE_ENDPOINT, &p2, NULL, reason, 0); } else { p1 = endpoints[1]; connection_move_handle(conn, handle->id, to, cp, reason, modifiers); p2 = endpoints[1]; point_sub(&p2, &p1); point_add(&annotation->text->position, &p2); } } annotation_update_data(annotation); return NULL; }
static ObjectChange* line_move_handle(Line *line, Handle *handle, Point *to, ConnectionPoint *cp, HandleMoveReason reason, ModifierKeys modifiers) { assert(line!=NULL); assert(handle!=NULL); assert(to!=NULL); connection_move_handle(&line->connection, handle->id, to, cp, reason, modifiers); line_update_data(line); return NULL; }
static ObjectChange* flow_move_handle(Flow *flow, Handle *handle, Point *to, ConnectionPoint *cp, HandleMoveReason reason, ModifierKeys modifiers) { Point p1, p2; Point *endpoints; assert(flow!=NULL); assert(handle!=NULL); assert(to!=NULL); if (handle->id == HANDLE_MOVE_TEXT) { flow->textpos = *to; } else { real dest_length ; real orig_length2 ; real along_mag, norm_mag ; Point along ; endpoints = &flow->connection.endpoints[0]; p1 = flow->textpos ; point_sub( &p1, &endpoints[0] ) ; p2 = endpoints[1] ; point_sub( &p2, &endpoints[0] ) ; orig_length2= point_dot( &p2, &p2 ) ; along = p2 ; if ( orig_length2 > 1e-5 ) { along_mag = point_dot( &p2, &p1 )/sqrt(orig_length2) ; along_mag *= along_mag ; norm_mag = point_dot( &p1, &p1 ) ; norm_mag = (real)sqrt( (double)( norm_mag - along_mag ) ) ; along_mag = (real)sqrt( along_mag/orig_length2 ) ; if ( p1.x*p2.y - p1.y*p2.x > 0.0 ) norm_mag = -norm_mag ; } else { along_mag = 0.5 ; norm_mag = (real)sqrt( (double) point_dot( &p1, &p1 ) ) ; } connection_move_handle(&flow->connection, handle->id, to, cp, reason, modifiers); p2 = endpoints[1] ; point_sub( &p2, &endpoints[0] ) ; flow->textpos = endpoints[0] ; along = p2 ; p2.x = -along.y ; p2.y = along.x ; dest_length = point_dot( &p2, &p2 ) ; if ( dest_length > 1e-5 ) { point_normalize( &p2 ) ; } else { p2.x = 0.0 ; p2.y = -1.0 ; } point_scale( &p2, norm_mag ) ; point_scale( &along, along_mag ) ; point_add( &flow->textpos, &p2 ) ; point_add( &flow->textpos, &along ) ; } flow_update_data(flow); return NULL; }
static ObjectChange* bus_move_handle(Bus *bus, Handle *handle, Point *to, ConnectionPoint *cp, HandleMoveReason reason, ModifierKeys modifiers) { Connection *conn = &bus->connection; Point *endpoints; static real *parallel=NULL; static real *perp=NULL; static int max_num=0; Point vhat, vhatperp; Point u; real vlen, vlen2; real len_scale; int i; if (bus->num_handles>max_num) { if (parallel!=NULL) { g_free(parallel); g_free(perp); } parallel = g_malloc(sizeof(real)*bus->num_handles); perp = g_malloc(sizeof(real)*bus->num_handles); max_num = bus->num_handles; } if (handle->id == HANDLE_BUS) { handle->pos = *to; } else { endpoints = &conn->endpoints[0]; vhat = endpoints[1]; point_sub(&vhat, &endpoints[0]); if ((fabs(vhat.x) == 0.0) && (fabs(vhat.y)==0.0)) { vhat.x += 0.01; } vlen = sqrt(point_dot(&vhat, &vhat)); point_scale(&vhat, 1.0/vlen); vhatperp.x = -vhat.y; vhatperp.y = vhat.x; for (i=0;i<bus->num_handles;i++) { u = bus->handles[i]->pos; point_sub(&u, &endpoints[0]); parallel[i] = point_dot(&vhat, &u); perp[i] = point_dot(&vhatperp, &u); } connection_move_handle(&bus->connection, handle->id, to, cp, reason, modifiers); vhat = endpoints[1]; point_sub(&vhat, &endpoints[0]); if ((fabs(vhat.x) == 0.0) && (fabs(vhat.y)==0.0)) { vhat.x += 0.01; } vlen2 = sqrt(point_dot(&vhat, &vhat)); len_scale = vlen2 / vlen; point_normalize(&vhat); vhatperp.x = -vhat.y; vhatperp.y = vhat.x; for (i=0;i<bus->num_handles;i++) { if (bus->handles[i]->connected_to == NULL) { u = vhat; point_scale(&u, parallel[i]*len_scale); point_add(&u, &endpoints[0]); bus->parallel_points[i] = u; u = vhatperp; point_scale(&u, perp[i]); point_add(&u, &bus->parallel_points[i]); bus->handles[i]->pos = u; } } } bus_update_data(bus); return NULL; }
/*! * Moving handles of a lifeline * * - the top handle is usually connected to an object, when moved connected * the whole lifeline is moved horizontally (but may not any longer vertically). * - the top box handle is used to move the whole box vertically. * - the bottom box handle should maybe resize the box without changing the * connection point distance, i.e. adding/removing some (maybe limited * by connected points) * - the bottom handle just move itself, not beyond the lower box handle */ static ObjectChange* lifeline_move_handle(Lifeline *lifeline, Handle *handle, Point *to, ConnectionPoint *cp, HandleMoveReason reason, ModifierKeys modifiers) { real s, dy; Connection *conn; assert(lifeline!=NULL); assert(handle!=NULL); assert(to!=NULL); conn = &lifeline->connection; if (handle->id == HANDLE_BOXBOT) { /* distance between upper handle and boxtop must not be smaller than zero */ dy = to->y - conn->endpoints[0].y; if (dy > lifeline_rect_size(lifeline)) { real dist = dy - lifeline->rbot; real di; modf (dist, &di); /* the integer part gives the number of points to add or remove */ if (fabs (di) > 0) { int ni = (int)di; if (lifeline_point_above_mid (lifeline, to) ? lifeline->northeast->num_connections + ni > 0 : lifeline->southeast->num_connections + ni > 0) return lifeline_create_change (lifeline, ni > 0 ? LIFELINE_CHANGE_ADD : LIFELINE_CHANGE_DEL, to); else return NULL; } } } else if (handle->id == HANDLE_BOXMID) { /* the box can not move over the top - same logic, but old movement behavior as above */ real dist = (to->y - handle->pos.y); /* the potential movement */ if (dist > 0 || -dist < lifeline->rtop) { lifeline->rbot += dist; lifeline->rtop = lifeline->rbot - lifeline_rect_size(lifeline); } } else if (handle->id == HANDLE_BOXTOP) { /* Distance between upper handle and boxtop must not be smaller than zero, * Same for boxbot and lower handle */ dy = to->y - conn->endpoints[0].y; if (dy > 0 && dy + lifeline_rect_size(lifeline) < conn->endpoints[1].y) { lifeline->rtop = dy; } } else { /* move horizontally only if startpoint is moved */ if (handle->id==HANDLE_MOVE_STARTPOINT) { conn->endpoints[0].x = conn->endpoints[1].x = to->x; } else { to->x = conn->endpoints[0].x; } /* If connected don't change size */ dy = (reason==HANDLE_MOVE_CONNECTED) ? conn->endpoints[1].y - conn->endpoints[0].y : lifeline->rbot; connection_move_handle(conn, handle->id, to, cp, reason, modifiers); s = conn->endpoints[1].y - conn->endpoints[0].y; if (handle->id==HANDLE_MOVE_ENDPOINT && s < dy && s > lifeline->rtop + LIFELINE_BOXMINHEIGHT) lifeline->rbot = s; else if (reason==HANDLE_MOVE_CONNECTED || s < dy) conn->endpoints[1].y = conn->endpoints[0].y + dy; } lifeline_update_data(lifeline); return NULL; }
static ObjectChange* bus_move_handle(Bus *bus, Handle *handle, Point *to, ConnectionPoint *cp, HandleMoveReason reason, ModifierKeys modifiers) { Connection *conn = &bus->connection; Point *endpoints; real *parallel=NULL; real *perp=NULL; Point vhat, vhatperp; Point u; real vlen, vlen2; real len_scale; int i; const int num_handles = bus->num_handles; /* const to help scan-build */ /* code copied to Misc/tree.c */ parallel = (real *)g_alloca (num_handles * sizeof(real)); perp = (real *)g_alloca (num_handles * sizeof(real)); if (handle->id == HANDLE_BUS) { handle->pos = *to; } else { endpoints = &conn->endpoints[0]; vhat = endpoints[1]; point_sub(&vhat, &endpoints[0]); if ((fabs(vhat.x) == 0.0) && (fabs(vhat.y)==0.0)) { vhat.x += 0.01; } vlen = sqrt(point_dot(&vhat, &vhat)); point_scale(&vhat, 1.0/vlen); vhatperp.x = -vhat.y; vhatperp.y = vhat.x; for (i=0;i<num_handles;i++) { u = bus->handles[i]->pos; point_sub(&u, &endpoints[0]); parallel[i] = point_dot(&vhat, &u); perp[i] = point_dot(&vhatperp, &u); } connection_move_handle(&bus->connection, handle->id, to, cp, reason, modifiers); vhat = endpoints[1]; point_sub(&vhat, &endpoints[0]); if ((fabs(vhat.x) == 0.0) && (fabs(vhat.y)==0.0)) { vhat.x += 0.01; } vlen2 = sqrt(point_dot(&vhat, &vhat)); len_scale = vlen2 / vlen; point_normalize(&vhat); vhatperp.x = -vhat.y; vhatperp.y = vhat.x; for (i=0;i<num_handles;i++) { if (bus->handles[i]->connected_to == NULL) { u = vhat; point_scale(&u, parallel[i]*len_scale); point_add(&u, &endpoints[0]); bus->parallel_points[i] = u; u = vhatperp; point_scale(&u, perp[i]); point_add(&u, &bus->parallel_points[i]); bus->handles[i]->pos = u; } } } bus_update_data(bus); return NULL; }
static ObjectChange* arc_move_handle(Arc *arc, Handle *handle, Point *to, ConnectionPoint *cp, HandleMoveReason reason, ModifierKeys modifiers) { assert(arc!=NULL); assert(handle!=NULL); assert(to!=NULL); /* A minimum distance between our three points needs to be maintained * Otherwise our math will get unstable with unpredictable results. */ { const Point *p1, *p2; if (handle->id == HANDLE_MIDDLE) { p1 = &arc->connection.endpoints[0]; p2 = &arc->connection.endpoints[1]; } else if (handle->id == HANDLE_CENTER) { p1 = &arc->connection.endpoints[0]; p2 = &arc->connection.endpoints[1]; /* special movement, let the center point snap to grid */ } else { p1 = &arc->middle_handle.pos; p2 = &arc->connection.endpoints[(handle == (&arc->connection.endpoint_handles[0])) ? 1 : 0]; } if ( (distance_point_point (to, p1) < 0.01) || (distance_point_point (to, p2) < 0.01)) return NULL; } if (handle->id == HANDLE_MIDDLE) { TRACE(printf("curve_dist: %.2f \n",arc->curve_distance)); arc->curve_distance = arc_compute_curve_distance(arc, &arc->connection.endpoints[0], &arc->connection.endpoints[1], to); TRACE(printf("curve_dist: %.2f \n",arc->curve_distance)); } else if (handle->id == HANDLE_CENTER) { /* We can move the handle only on the line through center and middle * Intersecting chord theorem says a*a=b*c * with a = dist(p1,p2)/2 * b = curve_distance * c = 2*radius-b or c = r + d * with Pythagoras r^2 = d^2 + a^2 * d = sqrt(r^2-a^2) */ Point p0 = arc->connection.endpoints[0]; Point p1 = arc->connection.endpoints[1]; Point p2 = { (p0.x + p1.x) / 2.0, (p0.y + p1.y) / 2.0 }; real a = distance_point_point (&p0, &p1)/2.0; real r = ( distance_point_point (&p0, to) + distance_point_point (&p1, to)) / 2.0; real d = sqrt(r*r-a*a); real cd; /* If the new point lies between midpoint and the chords center the angles is >180, * so c is smaller than r */ if (point_projection_is_between (to, &arc->middle_handle.pos, &p2)) d = -d; cd = a*a / (r+d); /* the sign of curve_distance, i.e. if the arc angle is clockwise, does not change */ arc->curve_distance = (arc->curve_distance > 0) ? cd : -cd; } else { Point best; TRACE(printf("Modifiers: %d \n",modifiers)); if (modifiers & MODIFIER_SHIFT) /* if(arc->end_arrow.type == ARROW_NONE)*/ { TRACE(printf("SHIFT USED, to at %.2f %.2f ",to->x,to->y)); if (arc_find_radial(arc, to, &best)) { /* needs to move two handles at the same time * compute pos of middle handle */ Point midpoint; int ok; if (handle == (&arc->connection.endpoint_handles[0])) ok = arc_compute_midpoint(arc, &best , &arc->connection.endpoints[1], &midpoint); else ok = arc_compute_midpoint(arc, &arc->connection.endpoints[0], &best , &midpoint); if (!ok) return NULL; connection_move_handle(&arc->connection, handle->id, &best, cp, reason, modifiers); connection_adjust_for_autogap(&arc->connection); /* recompute curve distance equiv. move middle handle */ arc->curve_distance = arc_compute_curve_distance(arc, &arc->connection.endpoints[0], &arc->connection.endpoints[1], &midpoint); TRACE(printf("curve_dist: %.2f \n",arc->curve_distance)); } else { TRACE(printf("NO best\n")); } } else { connection_move_handle(&arc->connection, handle->id, to, cp, reason, modifiers); connection_adjust_for_autogap(&arc->connection); } } arc_update_data(arc); return NULL; }