static BezPoint *transform_spline(int npoints, Point *points, gboolean closed) { BezPoint *bezpoints = g_new(BezPoint, npoints); int i; Point vector; for (i = 0; i < npoints; i++) { bezpoints[i].p3 = points[i]; bezpoints[i].type = BEZ_CURVE_TO; } bezpoints[0].type = BEZ_MOVE_TO; bezpoints[0].p1 = points[0]; for (i = 1; i < npoints-1; i++) { bezpoints[i].p2 = points[i]; bezpoints[i+1].p1 = points[i]; vector = points[i-1]; point_sub(&vector, &points[i+1]); point_scale(&vector, -TENSION); point_sub(&bezpoints[i].p2, &vector); point_add(&bezpoints[i+1].p1, &vector); } if (closed) { bezpoints[npoints-1].p2 = points[i]; bezpoints[1].p1 = points[i]; vector = points[npoints-2]; point_sub(&vector, &points[1]); point_scale(&vector, -TENSION); point_sub(&bezpoints[npoints-1].p2, &vector); point_add(&bezpoints[1].p1, &vector); } else { bezpoints[1].p1 = points[0]; bezpoints[npoints-1].p2 = bezpoints[npoints-1].p3; } return bezpoints; }
static void draw_dot(DiaRenderer *renderer, Point *end, Point *vect, Color *col) { DiaRendererClass *renderer_ops = DIA_RENDERER_GET_CLASS (renderer); Point vv,vp,vt,pt; real vlen; vv = *end; point_sub(&vv,vect); vlen = distance_point_point(vect,end); if (vlen < 1E-7) return; point_scale(&vv,1/vlen); vp.y = vv.x; vp.x = -vv.y; pt = *end; vt = vp; point_scale(&vt,ARROW_DOT_WOFFSET); point_add(&pt,&vt); vt = vv; point_scale(&vt,-ARROW_DOT_LOFFSET); point_add(&pt,&vt); renderer_ops->set_fillstyle(renderer,FILLSTYLE_SOLID); renderer_ops->fill_ellipse(renderer,&pt, ARROW_DOT_RADIUS,ARROW_DOT_RADIUS, col); }
static void implements_update_data(Implements *implements) { Connection *conn = &implements->connection; Object *obj = (Object *) implements; Point delta; Point point; real len; Rectangle rect; obj->position = conn->endpoints[0]; implements->text_handle.pos = implements->text_pos; /* circle handle/center pos: */ delta = conn->endpoints[0]; point_sub(&delta, &conn->endpoints[1]); len = sqrt(point_dot(&delta, &delta)); delta.x /= len; delta.y /= len; point = delta; point_scale(&point, implements->circle_diameter); point_add(&point, &conn->endpoints[1]); implements->circle_handle.pos = point; point = delta; point_scale(&point, implements->circle_diameter/2.0); point_add(&point, &conn->endpoints[1]); implements->circle_center = point; connection_update_handles(conn); /* Boundingbox: */ connection_update_boundingbox(conn); /* Add boundingbox for circle: */ rect.left = implements->circle_center.x - implements->circle_diameter/2.0; rect.right = implements->circle_center.x + implements->circle_diameter/2.0; rect.top = implements->circle_center.y - implements->circle_diameter/2.0; rect.bottom = implements->circle_center.y + implements->circle_diameter/2.0; rectangle_union(&obj->bounding_box, &rect); /* Add boundingbox for text: */ rect.left = implements->text_pos.x; rect.right = rect.left + implements->text_width; rect.top = implements->text_pos.y - font_ascent(implements_font, IMPLEMENTS_FONTHEIGHT); rect.bottom = rect.top + IMPLEMENTS_FONTHEIGHT; rectangle_union(&obj->bounding_box, &rect); /* fix boundingbox for implements_width: */ obj->bounding_box.top -= IMPLEMENTS_WIDTH/2; obj->bounding_box.left -= IMPLEMENTS_WIDTH/2; obj->bounding_box.bottom += IMPLEMENTS_WIDTH/2; obj->bounding_box.right += IMPLEMENTS_WIDTH/2; }
static void rendobj_update_data(RenderObject *rend_obj) { Point p; const RenderObjectDescriptor *desc; Element *elem; Object *obj; int i; elem = &rend_obj->element; obj = &elem->object; desc = rend_obj->desc; rend_obj->magnify = elem->width / rend_obj->desc->width; /* Update connections: */ for (i=0;i<desc->num_connection_points;i++) { rend_obj->connections[i].pos = desc->connection_points[i]; point_scale(&rend_obj->connections[i].pos, rend_obj->magnify); point_add(&rend_obj->connections[i].pos, &elem->corner); } if (desc->use_text) { p = desc->text_pos; point_scale(&p, rend_obj->magnify); point_add(&p, &elem->corner); p.y += rend_obj->text->ascent; text_set_position(rend_obj->text, &p); } element_update_boundingbox(elem); /* fix boundingbox for extra_border: */ obj->bounding_box.top -= desc->extra_border; obj->bounding_box.left -= desc->extra_border; obj->bounding_box.bottom += desc->extra_border; obj->bounding_box.right += desc->extra_border; if (desc->use_text) { Rectangle text_box; text_calc_boundingbox(rend_obj->text, &text_box); rectangle_union(&obj->bounding_box, &text_box); } obj->position = elem->corner; p = desc->move_position; point_scale(&p, rend_obj->magnify); point_add(&obj->position, &p); element_update_handles(elem); }
static void annotation_draw(Annotation *annotation, DiaRenderer *renderer) { Point *endpoints; Point vect,rvect,v1,v2; Point pts[4]; real vlen; DiaRendererClass *renderer_ops = DIA_RENDERER_GET_CLASS (renderer); assert(annotation != NULL); assert(renderer != NULL); endpoints = &annotation->connection.endpoints[0]; renderer_ops->set_linewidth(renderer, ANNOTATION_LINE_WIDTH); renderer_ops->set_linestyle(renderer, LINESTYLE_SOLID); renderer_ops->set_linecaps(renderer, LINECAPS_BUTT); vect = annotation->connection.endpoints[1]; point_sub(&vect,&annotation->connection.endpoints[0]); vlen = distance_point_point(&annotation->connection.endpoints[0], &annotation->connection.endpoints[1]); if (vlen > 0.0) { /* draw the squiggle */ point_scale(&vect,1/vlen); rvect.y = vect.x; rvect.x = -vect.y; pts[0] = annotation->connection.endpoints[0]; pts[1] = annotation->connection.endpoints[0]; v1 = vect; point_scale(&v1,.5*vlen); point_add(&pts[1],&v1); pts[2] = pts[1]; /* pts[1] and pts[2] are currently both at the middle of (pts[0],pts[3]) */ v1 = vect; point_scale(&v1,ANNOTATION_ZLEN); v2 = rvect; point_scale(&v2,ANNOTATION_ZLEN); point_sub(&v1,&v2); point_add(&pts[1],&v1); point_sub(&pts[2],&v1); pts[3] = annotation->connection.endpoints[1]; renderer_ops->draw_polyline(renderer, pts, sizeof(pts) / sizeof(pts[0]), &color_black); } text_draw(annotation->text,renderer); }
static ObjectChange* bezierline_move_handle(Bezierline *bezierline, Handle *handle, Point *to, ConnectionPoint *cp, HandleMoveReason reason, ModifierKeys modifiers) { assert(bezierline!=NULL); assert(handle!=NULL); assert(to!=NULL); if (reason == HANDLE_MOVE_CREATE || reason == HANDLE_MOVE_CREATE_FINAL) { /* During creation, change the control points */ BezierConn *bez = &bezierline->bez; Point dist = bez->bezier.points[0].p1; point_sub(&dist, to); dist.y = 0; point_scale(&dist, 0.332); bezierconn_move_handle(bez, handle, to, cp, reason, modifiers); bez->bezier.points[1].p1 = bez->bezier.points[0].p1; point_sub(&bez->bezier.points[1].p1, &dist); bez->bezier.points[1].p2 = *to; point_add(&bez->bezier.points[1].p2, &dist); } else { bezierconn_move_handle(&bezierline->bez, handle, to, cp, reason, modifiers); } bezierline_update_data(bezierline); return NULL; }
static void draw_tunnel(DiaRenderer *renderer, Point *end, Point *vect, Color *col) { DiaRendererClass *renderer_ops = DIA_RENDERER_GET_CLASS (renderer); Point vv,vp,vt1,vt2; BezPoint curve1[2]; BezPoint curve2[2]; real vlen; vv = *end; point_sub(&vv,vect); vlen = distance_point_point(vect,end); if (vlen < 1E-7) return; point_scale(&vv,1/vlen); vp.y = vv.x; vp.x = -vv.y; curve1[0].type = curve2[0].type = BEZ_MOVE_TO; curve1[0].p1 = curve2[0].p1 = *end; vt1 = vv; point_scale(&vt1,-ARROW_PARENS_LOFFSET - (.5*ARROW_PARENS_LENGTH)); point_add(&curve1[0].p1,&vt1); point_add(&curve2[0].p1,&vt1); /* gcc, work for me, please. */ vt2 = vp; point_scale(&vt2,ARROW_PARENS_WOFFSET); point_add(&curve1[0].p1,&vt2); point_sub(&curve2[0].p1,&vt2); vt2 = vp; vt1 = vv; point_scale(&vt1,2.0*ARROW_PARENS_LENGTH / 6.0); point_scale(&vt2,ARROW_PARENS_LENGTH / 6.0); curve1[1].type = curve2[1].type = BEZ_CURVE_TO; curve1[1].p1 = curve1[0].p1; curve2[1].p1 = curve2[0].p1; point_add(&curve1[1].p1,&vt1); point_add(&curve2[1].p1,&vt1); point_add(&curve1[1].p1,&vt2); point_sub(&curve2[1].p1,&vt2); curve1[1].p2 = curve1[1].p1; curve2[1].p2 = curve2[1].p1; point_add(&curve1[1].p2,&vt1); point_add(&curve2[1].p2,&vt1); curve1[1].p3 = curve1[1].p2; curve2[1].p3 = curve2[1].p2; point_add(&curve1[1].p3,&vt1); point_add(&curve2[1].p3,&vt1); point_sub(&curve1[1].p3,&vt2); point_add(&curve2[1].p3,&vt2); renderer_ops->draw_bezier(renderer,curve1,2,col); renderer_ops->draw_bezier(renderer,curve2,2,col); }
void point_convex(Point *dst, const Point *src1, const Point *src2, real alpha) { /* Make convex combination of src1 and src2: dst = alpha * src1 + (1-alpha) * src2; */ point_copy(dst,src1); point_scale(dst,alpha); point_add_scaled(dst,src2,1.0 - alpha); }
static void scroll_motion(ScrollTool *tool, GdkEventMotion *event, DDisplay *ddisp) { Point to; Point delta; /* set the cursor appropriately, and change use_hand if needed */ if (!tool->scrolling) { /* try to minimise the number of cursor type changes */ if ((event->state & GDK_SHIFT_MASK) != 0) { if (!tool->use_hand) { tool->use_hand = TRUE; if (!open_hand_cursor) open_hand_cursor = create_cursor(ddisp->canvas->window, hand_open_data_bits, hand_open_data_width, hand_open_data_height, hand_open_mask_bits, hand_open_data_width/2, hand_open_data_height/2); ddisplay_set_all_cursor(open_hand_cursor); } } else if (tool->use_hand) { tool->use_hand = FALSE; ddisplay_set_all_cursor(scroll_cursor); } return; } ddisplay_untransform_coords(ddisp, event->x, event->y, &to.x, &to.y); if (tool->use_hand) { delta = tool->last_pos; point_sub(&delta, &to); tool->last_pos = to; point_add(&tool->last_pos, &delta); /* we use this so you can scroll past the edge of the image */ point_add(&delta, &ddisp->origo); ddisplay_set_origo(ddisp, delta.x, delta.y); ddisplay_update_scrollbars(ddisp); ddisplay_add_update_all(ddisp); } else { delta = to; point_sub(&delta, &tool->last_pos); point_scale(&delta, 0.5); ddisplay_scroll(ddisp, &delta); tool->last_pos = to; } ddisplay_flush(ddisp); }
/*! * \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 point center_of_mass(unsigned n, point o[]) { point com; unsigned i; unsigned long tn; com = point_zero; for (i = 0; i < n; ++i) com = point_add(com, o[i]); mpi_add_doubles(comm_mpi(), point_arr(&com), 3); tn = mpi_add_ulong(comm_mpi(), n); return point_scale(com, 1.0 / tn); }
static void rendobj_move(RenderObject *rend_obj, Point *to) { Point p; p = rend_obj->desc->move_position; rend_obj->element.corner = *to; point_scale(&p, rend_obj->magnify); point_sub(&rend_obj->element.corner, &p); rendobj_update_data(rend_obj); }
/* finds the point intersecting the full circle * on the vector defined by the center and Point *to * that point is returned in Point *best if 1 is returned */ static int arc_find_radial(const Arc *arc, const Point *to, Point *best) { Point tmp; tmp = *to; point_sub(&tmp, &arc->center); point_normalize(&tmp); point_scale(&tmp,arc->radius); point_add(&tmp, &arc->center); *best = tmp; return 1; }
/** 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); }
/* * This function estimates the distance from a point to a line segment * specified by two endpoints. * If the point is on the line segment, 0.0 is returned. Otherwise the * distance in the R^2 metric from the point to the nearest point * on the line segment is returned. Does one sqrt per call. * Philosophical bug: line_width is ignored iff point is beyond * end of line segment. */ real distance_line_point(Point *line_start, Point *line_end, real line_width, Point *point) { Point v1, v2; real v1_lensq; real projlen; real perp_dist; v1 = *line_end; point_sub(&v1,line_start); v2 = *point; point_sub(&v2, line_start); v1_lensq = point_dot(&v1,&v1); if (v1_lensq<0.000001) { return sqrt(point_dot(&v2,&v2)); } projlen = point_dot(&v1,&v2) / v1_lensq; if (projlen<0.0) { return sqrt(point_dot(&v2,&v2)); } if (projlen>1.0) { Point v3 = *point; point_sub(&v3,line_end); return sqrt(point_dot(&v3,&v3)); } point_scale(&v1, projlen); point_sub(&v1, &v2); perp_dist = sqrt(point_dot(&v1,&v1)); perp_dist -= line_width / 2.0; if (perp_dist < 0.0) { perp_dist = 0.0; } return perp_dist; }
/** Calculate the bounding box for a simple line. * @param p1 One end of the line. * @param p2 The other end of the line. * @param extra Extra information * @param rect The box that the line and extra stuff fits inside. */ void line_bbox(const Point *p1, const Point *p2, const LineBBExtras *extra, Rectangle *rect) { Point vl; rect->left = rect->right = p1->x; rect->top = rect->bottom = p1->y; rectangle_add_point(rect,p2); /* as a safety, so we don't need to care if it above or below p1 */ point_copy_add_scaled(&vl,p1,p2,-1); point_normalize(&vl); add_arrow_rectangle(rect,p1,&vl,extra->start_long,extra->start_trans); point_scale(&vl,-1); add_arrow_rectangle(rect,p2,&vl,extra->end_long,extra->end_trans); }
void line_bbox(const Point *p1, const Point *p2, const LineBBExtras *extra, Rectangle *rect) { Point vl; rect->setLeft(p1->x()); rect->setRight(p1->x()); rect->setTop(p1->y()); rect->setBottom(p1->y()); rectangle_add_point(rect,p2); point_copy_add_scaled(&vl,p1,p2,-1); point_normalize(&vl); add_arrow_rectangle(rect,p1,&vl,extra->startLong,extra->startTrans); point_scale(&vl,-1); add_arrow_rectangle(rect,p2,&vl,extra->endLong,extra->endTrans); }
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); } }
static void bezierline_move_handle(Bezierline *bezierline, Handle *handle, Point *to, HandleMoveReason reason, ModifierKeys modifiers) { assert(bezierline!=NULL); assert(handle!=NULL); assert(to!=NULL); bezierconn_move_handle(&bezierline->bez, handle, to, reason); if (reason == HANDLE_MOVE_CREATE || reason == HANDLE_MOVE_CREATE_FINAL) { BezierConn *bez = &bezierline->bez; Point delta = bez->points[1].p3; point_sub(&delta, &bez->points[0].p1); point_scale(&delta, 1.0/3); bez->points[1].p1 = bez->points[0].p1; point_add(&bez->points[1].p1, &delta); bez->points[1].p2 = bez->points[1].p1; point_add(&bez->points[1].p2, &delta); } bezierline_update_data(bezierline); }
static DiaObject * flow_create(Point *startpoint, void *user_data, Handle **handle1, Handle **handle2) { Flow *flow; Connection *conn; DiaObject *obj; LineBBExtras *extra; Point p ; Point n ; DiaFont *font; flow = g_malloc0(sizeof(Flow)); conn = &flow->connection; conn->endpoints[0] = *startpoint; conn->endpoints[1] = *startpoint; conn->endpoints[1].x += 1.5; obj = &conn->object; extra = &conn->extra_spacing; obj->type = &flow_type; obj->ops = &flow_ops; connection_init(conn, 3, 0); p = conn->endpoints[1] ; point_sub( &p, &conn->endpoints[0] ) ; point_scale( &p, 0.5 ) ; n.x = p.y ; n.y = -p.x ; if ( fabs(n.x) < 1.e-5 && fabs(n.y) < 1.e-5 ) { n.x = 0. ; n.y = -1. ; } else { point_normalize( &n ) ; } point_scale( &n, 0.5*FLOW_FONTHEIGHT ) ; point_add( &p, &n ) ; point_add( &p, &conn->endpoints[0] ) ; flow->textpos = p; font = dia_font_new_from_style(DIA_FONT_SANS, FLOW_FONTHEIGHT); flow->text = new_text("", font, FLOW_FONTHEIGHT, &p, &color_black, ALIGN_CENTER); dia_font_unref(font); flow->text_handle.id = HANDLE_MOVE_TEXT; flow->text_handle.type = HANDLE_MINOR_CONTROL; flow->text_handle.connect_type = HANDLE_NONCONNECTABLE; flow->text_handle.connected_to = NULL; flow->text_handle.pos = p; obj->handles[2] = &flow->text_handle; extra->start_long = extra->end_long = extra->start_trans = FLOW_WIDTH/2.0; extra->end_trans = MAX(FLOW_WIDTH, FLOW_ARROWLEN) / 2.0; flow_update_data(flow); *handle1 = obj->handles[0]; *handle2 = obj->handles[1]; return &flow->connection.object; }
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; 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; }
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 bus_update_data(Bus *bus) { Connection *conn = &bus->connection; DiaObject *obj = &conn->object; int i; Point u, v, vhat; Point *endpoints; real ulen; real min_par, max_par; /* * This seems to break stuff wildly. */ /* 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); min_par = 0.0; max_par = point_dot(&vhat, &v); for (i=0;i<bus->num_handles;i++) { u = bus->handles[i]->pos; point_sub(&u, &endpoints[0]); ulen = point_dot(&u, &vhat); min_par = MIN(min_par, ulen); max_par = MAX(max_par, ulen); bus->parallel_points[i] = vhat; point_scale(&bus->parallel_points[i], ulen); point_add(&bus->parallel_points[i], &endpoints[0]); } min_par -= LINE_WIDTH/2.0; max_par += LINE_WIDTH/2.0; bus->real_ends[0] = vhat; point_scale(&bus->real_ends[0], min_par); point_add(&bus->real_ends[0], &endpoints[0]); bus->real_ends[1] = vhat; point_scale(&bus->real_ends[1], max_par); point_add(&bus->real_ends[1], &endpoints[0]); connection_update_boundingbox(conn); rectangle_add_point(&obj->bounding_box, &bus->real_ends[0]); rectangle_add_point(&obj->bounding_box, &bus->real_ends[1]); for (i=0;i<bus->num_handles;i++) { rectangle_add_point(&obj->bounding_box, &bus->handles[i]->pos); } connection_update_handles(conn); }
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; }
/*! * \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; }
static void arc_draw(Arc *arc, Renderer *renderer) { Point *endpoints; real width; assert(arc != NULL); assert(renderer != NULL); endpoints = &arc->connection.endpoints[0]; renderer->ops->set_linewidth(renderer, arc->line_width); renderer->ops->set_linestyle(renderer, arc->line_style); renderer->ops->set_dashlength(renderer, arc->dashlength); renderer->ops->set_linecaps(renderer, LINECAPS_BUTT); /* Special case when almost line: */ if (fabs(arc->curve_distance) <= 0.0001) { renderer->ops->draw_line(renderer, &endpoints[0], &endpoints[1], &arc->arc_color); return; } width = 2*arc->radius; renderer->ops->draw_arc(renderer, &arc->center, width, width, arc->angle1, arc->angle2, &arc->arc_color); if (arc->start_arrow.type != ARROW_NONE || arc->end_arrow.type != ARROW_NONE) { Point reversepoint, centervec; Point controlpoint0, controlpoint1; real len, len2; centervec = endpoints[0]; point_sub(¢ervec, &endpoints[1]); point_scale(¢ervec, 0.5); len = centervec.x*centervec.x+centervec.y*centervec.y; point_add(¢ervec, &endpoints[1]); /* Centervec should now be the midpoint between [0] and [1] */ reversepoint = centervec; point_sub(¢ervec, &arc->center); len2 = centervec.x*centervec.x+centervec.y*centervec.y; if (len2 != 0) { point_scale(¢ervec, 1/len2); } point_scale(¢ervec, len); point_add(&reversepoint, ¢ervec); controlpoint0 = controlpoint1 = reversepoint; len = arc->angle2-arc->angle1; if (len > 180 || (len < 0.0 && len > -180)) { centervec = endpoints[0]; point_sub(¢ervec, &reversepoint); point_add(&controlpoint0, ¢ervec); point_add(&controlpoint0, ¢ervec); centervec = endpoints[1]; point_sub(¢ervec, &reversepoint); point_add(&controlpoint1, ¢ervec); point_add(&controlpoint1, ¢ervec); } if (arc->start_arrow.type != ARROW_NONE) { arrow_draw(renderer, arc->start_arrow.type, &endpoints[0],&controlpoint0, arc->start_arrow.length, arc->start_arrow.width, arc->line_width, &arc->arc_color, &color_white); } if (arc->end_arrow.type != ARROW_NONE) { arrow_draw(renderer, arc->end_arrow.type, &endpoints[1], &controlpoint1, arc->end_arrow.length, arc->end_arrow.width, arc->line_width, &arc->arc_color, &color_white); } } }