static void beziergon_update_data(Beziergon *beziergon) { BezierShape *bez = &beziergon->bezier; DiaObject *obj = &bez->object; ElementBBExtras *extra = &bez->extra_spacing; beziershape_update_data(bez); extra->border_trans = beziergon->line_width / 2.0; beziershape_update_boundingbox(bez); /* update the enclosing box using the control points */ { int i, num_points = bez->bezier.num_points; obj->enclosing_box = obj->bounding_box; for (i = 0; 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); } } obj->position = bez->bezier.points[0].p1; }
void bicubicbezier2D_bbox(const Point *p0,const Point *p1, const Point *p2,const Point *p3, const PolyBBExtras *extra, Rectangle *rect) { double x[4],y[4]; Point vl,vt,p,tt; double *xy; int i,extr; double u[2]; rect->setLeft(p0->x()); rect->setRight(p0->x()); rect->setTop(p0->y()); rect->setBottom(p0->y()); rectangle_add_point(rect,p3); point_copy_add_scaled(&vl,p0,p1,-1); point_normalize(&vl); add_arrow_rectangle(rect,p0,&vl,extra->startLong, qMax(extra->startTrans, extra->middleTrans)); point_copy_add_scaled(&vl,p3,p2,-1); point_normalize(&vl); add_arrow_rectangle(rect,p3,&vl,extra->endLong, qMax(extra->endTrans, extra->middleTrans)); x[0] = p0->x(); x[1] = p1->x(); x[2] = p2->x(); x[3] = p3->x(); y[0] = p0->y(); y[1] = p1->y(); y[2] = p2->y(); y[3] = p3->y(); for (xy = x; xy ; xy=(xy==x?y:NULL) ) { extr = bicubicbezier_extrema(xy,u); for (i=0;i<extr;i++) { if ((u[i]<0) || (u[i]>1)) continue; p.setX(bezier_eval(x,u[i])); vl.setX(bezier_eval_tangent(x,u[i])); p.setY(bezier_eval(y,u[i])); vl.setY(bezier_eval_tangent(y,u[i])); point_normalize(&vl); point_get_perp(&vt,&vl); point_copy_add_scaled(&tt,&p,&vt,extra->middleTrans); rectangle_add_point(rect,&tt); point_copy_add_scaled(&tt,&p,&vt,-extra->middleTrans); rectangle_add_point(rect,&tt); } } }
/** Calculate the boundingbox for a 2D bezier curve segment. * @param p0 start point * @param p1 1st control point * @param p2 2nd control point * @param p3 end point * @param extra information about extra space from linewidth and arrow to add to the bounding box * @param rect The rectangle that the segment fits inside. */ void bicubicbezier2D_bbox(const Point *p0,const Point *p1, const Point *p2,const Point *p3, const PolyBBExtras *extra, Rectangle *rect) { real x[4],y[4]; Point vl,vt,p,tt; real *xy; int i,extr; real u[2]; rect->left = rect->right = p0->x; rect->top = rect->bottom = p0->y; rectangle_add_point(rect,p3); /* start point */ point_copy_add_scaled(&vl,p0,p1,-1); point_normalize(&vl); add_arrow_rectangle(rect,p0,&vl,extra->start_long,MAX(extra->start_trans, extra->middle_trans)); /* end point */ point_copy_add_scaled(&vl,p3,p2,-1); point_normalize(&vl); add_arrow_rectangle(rect,p3,&vl,extra->end_long,MAX(extra->end_trans, extra->middle_trans)); /* middle part */ x[0] = p0->x; x[1] = p1->x; x[2] = p2->x; x[3] = p3->x; y[0] = p0->y; y[1] = p1->y; y[2] = p2->y; y[3] = p3->y; for (xy = x; xy ; xy=(xy==x?y:NULL) ) { /* sorry */ extr = bicubicbezier_extrema(xy,u); for (i=0;i<extr;i++) { if ((u[i]<0) || (u[i]>1)) continue; p.x = bezier_eval(x,u[i]); vl.x = bezier_eval_tangent(x,u[i]); p.y = bezier_eval(y,u[i]); vl.y = bezier_eval_tangent(y,u[i]); point_normalize(&vl); point_get_perp(&vt,&vl); point_copy_add_scaled(&tt,&p,&vt,extra->middle_trans); rectangle_add_point(rect,&tt); point_copy_add_scaled(&tt,&p,&vt,-extra->middle_trans); rectangle_add_point(rect,&tt); } } }
static void link_update_data(Link *link) { Connection *conn = &link->connection; DiaObject *obj = &conn->object; Rectangle rect; Point p1,p2,p3,p4,pa; /* Too complex to easily decide */ /* if (connpoint_is_autogap(conn->endpoint_handles[0].connected_to) || connpoint_is_autogap(conn->endpoint_handles[1].connected_to)) { connection_adjust_for_autogap(conn); } */ obj->position = conn->endpoints[0]; link->pm_handle.pos = link->pm; connection_update_handles(conn); connection_update_boundingbox(conn); /* endpoint */ p1 = conn->endpoints[0]; p2 = conn->endpoints[1]; /* bezier */ compute_line(&p1,&p2,&link->pm,link->line); /* connection point */ link->connector.pos.x=p1.x; link->connector.pos.y=p1.y; /* Update boundingbox for mid-point (TBD is this necessary ?) */ rectangle_add_point(&obj->bounding_box, &link->pm); /* Add boundingbox for annotation text (over-estimated) : */ pa=compute_annot(&p1,&p2,&link->pm,0.75,0.75); rect.left = pa.x-0.3; rect.right = rect.left+0.6; rect.top = pa.y - LINK_FONTHEIGHT; rect.bottom = rect.top + 2*LINK_FONTHEIGHT; rectangle_union(&obj->bounding_box, &rect); /* Add boundingbox for dependency decoration (with some overestimation toi be safe) */ pa=bezier_line_eval(link->line,2,0.25); p3.x=pa.x-LINK_DEP_WIDTH*1.5; p3.y=pa.y-LINK_DEP_HEIGHT*1.5; p4.x=p3.x+LINK_DEP_WIDTH*3; p4.y=p3.y+LINK_DEP_HEIGHT*3; rect.left=p3.x; rect.right=p4.x; rect.top=p3.y; rect.bottom=p4.y; rectangle_union(&obj->bounding_box, &rect); }
void add_arrow_rectangle(Rectangle *rect, const Point *vertex, const Point *normed_dir, double extra_long,double extra_trans) { Point vl,vt,pt; vl = *normed_dir; point_get_perp(&vt,&vl); point_copy_add_scaled(&pt,vertex,&vl,extra_long); point_add_scaled(&pt,&vt,extra_trans); rectangle_add_point(rect,&pt); point_add_scaled(&pt,&vt,-2.0 * extra_trans); rectangle_add_point(rect,&pt); point_add_scaled(&pt,&vl,-2.0 * extra_long); rectangle_add_point(rect,&pt); point_add_scaled(&pt,&vt,2.0 * extra_trans); rectangle_add_point(rect,&pt); }
static void textobj_update_data(Textobj *textobj) { Point to2; DiaObject *obj = &textobj->object; Rectangle tx_bb; text_set_position(textobj->text, &obj->position); text_calc_boundingbox(textobj->text, &obj->bounding_box); to2 = obj->position; textobj_valign_point(textobj, &to2); /* shift text position depending on text alignment */ if (VALIGN_TOP == textobj->vert_align) to2.y += textobj->margin; /* down */ else if (VALIGN_BOTTOM == textobj->vert_align) to2.y -= textobj->margin; /* up */ if (ALIGN_LEFT == textobj->text->alignment) to2.x += textobj->margin; /* right */ else if (ALIGN_RIGHT == textobj->text->alignment) to2.x -= textobj->margin; /* left */ text_set_position(textobj->text, &to2); /* always use the unrotated box ... */ text_calc_boundingbox(textobj->text, &tx_bb); /* grow the bounding box by 2x margin */ obj->bounding_box.top -= textobj->margin; obj->bounding_box.left -= textobj->margin; obj->bounding_box.bottom += textobj->margin; obj->bounding_box.right += textobj->margin; textobj->text_handle.pos = obj->position; if (textobj->text_angle == 0) { obj->bounding_box = tx_bb; g_return_if_fail (obj->enclosing_box != NULL); *obj->enclosing_box = tx_bb; } else { /* ... and grow it when necessary */ Point poly[4]; int i; _textobj_get_poly (textobj, poly); /* we don't want the joined box for boundingbox because * selection would become too greedy than. */ obj->bounding_box.left = obj->bounding_box.right = poly[0].x; obj->bounding_box.top = obj->bounding_box.bottom = poly[0].y; for (i = 1; i < 4; ++i) rectangle_add_point (&obj->bounding_box, &poly[i]); g_return_if_fail (obj->enclosing_box != NULL); *obj->enclosing_box = obj->bounding_box; /* join for editing/selection bbox */ rectangle_union (obj->enclosing_box, &tx_bb); } }
/** 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); }
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 void step_update_data(Step *step) { Element *elem = &step->element; DiaObject *obj = &elem->object; ElementBBExtras *extra = &elem->extra_spacing; Point *p,ulc; ulc = elem->corner; ulc.x += ((STEP_DECLAREDWIDTH - STEP_WIDTH) / 2.0); /* we cheat a little */ step->A.x = 0.0 + (STEP_WIDTH / 2.0); step->A.y = 0.0; step->D.x = 0.0 + (STEP_WIDTH / 2.0); step->D.y = 0.0 + STEP_HEIGHT; step->E.x = 0.0; step->E.y = 0.5; step->F.x = STEP_WIDTH; step->F.y = STEP_HEIGHT- 0.5; switch(step->type) { case STEP_INITIAL: step->I.x = step->E.x - 2 * STEP_LINE_WIDTH; step->I.y = step->E.y - 2 * STEP_LINE_WIDTH; step->J.x = step->F.x + 2 * STEP_LINE_WIDTH; step->J.y = step->F.y + 2 * STEP_LINE_WIDTH; step->B.x = step->A.x; step->B.y = step->I.y; step->C.x = step->D.x; step->C.y = step->J.y; step->Z.x = step->J.x; step->Z.y = STEP_HEIGHT / 2; break; case STEP_MACROCALL: step->I.x = step->E.x; step->I.y = step->E.y - 2 * STEP_LINE_WIDTH; step->J.x = step->F.x; step->J.y = step->F.y + 2 * STEP_LINE_WIDTH; step->B.x = step->A.x; step->B.y = step->I.y; step->C.x = step->D.x; step->C.y = step->J.y; step->Z.x = step->J.x; step->Z.y = STEP_HEIGHT / 2; break; case STEP_SUBPCALL: step->I.x = step->E.x - 2 * STEP_LINE_WIDTH; step->I.y = step->E.y; step->J.x = step->F.x + 2 * STEP_LINE_WIDTH; step->J.y = step->F.y; step->B.x = step->A.x; step->B.y = step->I.y; step->C.x = step->D.x; step->C.y = step->J.y; step->Z.x = step->J.x; step->Z.y = STEP_HEIGHT / 2; break; default: /* regular or macro end steps */ step->B.x = step->A.x; step->B.y = step->E.y; step->C.x = step->D.x; step->C.y = step->F.y; step->Z.x = step->F.x; step->Z.y = STEP_HEIGHT / 2; } step->G.x = step->A.x; step->G.y = (STEP_HEIGHT / 2) + (.3 * step->font_size); step->H.x = step->E.x + (1.2 * STEP_DOT_RADIUS); step->H.y = step->F.y - (1.2 * STEP_DOT_RADIUS); for (p=&(step->A); p<=&(step->Z) ; p++) point_add(p,&ulc); /* Update handles: */ if (step->north.pos.x == -65536.0) { step->north.pos = step->A; step->south.pos = step->D; } step->NU1.x = step->north.pos.x; step->NU2.x = step->A.x; step->NU1.y = step->NU2.y = (step->north.pos.y + step->A.y) / 2.0; step->SD1.x = step->D.x; step->SD2.x = step->south.pos.x; step->SD1.y = step->SD2.y = (step->south.pos.y + step->D.y) / 2.0; /* Update connections: */ step->connections[0].pos = step->A; step->connections[0].directions = DIR_NORTH; step->connections[1].pos = step->D; step->connections[1].directions = DIR_SOUTH; step->connections[2].pos = step->Z; step->connections[2].directions = DIR_EAST; step->connections[3].pos = step->H; step->connections[3].directions = DIR_WEST; /* recalc the bounding box : */ if ((step->type == STEP_INITIAL) || (step->type == STEP_SUBPCALL)) { extra->border_trans = 2.5 * STEP_LINE_WIDTH; } else { extra->border_trans = STEP_LINE_WIDTH / 2; } element_update_boundingbox(elem); rectangle_add_point(&obj->bounding_box,&step->north.pos); rectangle_add_point(&obj->bounding_box,&step->south.pos); obj->position = elem->corner; element_update_handles(elem); }
void polybezier_bbox(const BezPoint *pts, int numpoints, const PolyBBExtras *extra, bool closed, Rectangle *rect) { Point vx,vp,vn,vsc; int i,prev,next; Rectangle rt; PolyBBExtras bextra,start_bextra,end_bextra; LineBBExtras lextra,start_lextra,end_lextra,full_lextra; bool start,end; rect->setLeft(pts[0].p1.x()); rect->setRight(pts[0].p1.x()); rect->setTop(pts[0].p1.y()); rect->setBottom(pts[0].p1.y()); if (!closed) { start_lextra.startLong = extra->startLong; start_lextra.startTrans = qMax(extra->startTrans,extra->middleTrans); start_lextra.endLong = 0; start_lextra.endTrans = extra->middleTrans; end_lextra.startLong = 0; end_lextra.startTrans = extra->middleTrans; end_lextra.endLong = extra->endLong; end_lextra.endTrans = qMax(extra->endTrans,extra->middleTrans); } full_lextra.startLong = extra->startLong; full_lextra.startTrans = qMax(extra->startTrans,extra->middleTrans); full_lextra.endLong = extra->endLong; full_lextra.endTrans = qMax(extra->endTrans,extra->middleTrans); if (!closed) { lextra.startLong = 0; lextra.startTrans = extra->middleTrans; lextra.endLong = 0; lextra.endTrans = extra->middleTrans; start_bextra.startLong = extra->startLong; start_bextra.startTrans = extra->startTrans; start_bextra.middleTrans = extra->middleTrans; start_bextra.endLong = 0; start_bextra.endTrans = extra->middleTrans; end_bextra.startLong = 0; end_bextra.startTrans = extra->middleTrans; end_bextra.middleTrans = extra->middleTrans; end_bextra.endLong = extra->endLong; end_bextra.endTrans = extra->endTrans; } bextra.startLong = 0; bextra.startTrans = extra->middleTrans; bextra.middleTrans = extra->middleTrans; bextra.endLong = 0; bextra.endTrans = extra->middleTrans; for (i=1;i<numpoints;i++) { next = (i+1) % numpoints; prev = (i-1) % numpoints; if (closed && (next == 0)) next=1; if (closed && (prev == 0)) prev=numpoints-1; if (pts[i].type == BezPoint::BEZ_MOVE_TO) { continue; } switch(pts[i].type) { case BezPoint::BEZ_MOVE_TO: break; case BezPoint::BEZ_LINE_TO: vx = pts[i].p1; switch(pts[prev].type) { case BezPoint::BEZ_MOVE_TO: case BezPoint::BEZ_LINE_TO: vsc = pts[prev].p1; vp = pts[prev].p1; break; case BezPoint::BEZ_CURVE_TO: vsc = pts[prev].p3; vp = pts[prev].p3; break; } break; case BezPoint::BEZ_CURVE_TO: vx = pts[i].p3; vp = pts[i].p2; switch(pts[prev].type) { case BezPoint::BEZ_MOVE_TO: case BezPoint::BEZ_LINE_TO: vsc = pts[prev].p1; break; case BezPoint::BEZ_CURVE_TO: vsc = pts[prev].p3; break; } break; } start = (pts[prev].type == BezPoint::BEZ_MOVE_TO); end = (pts[next].type == BezPoint::BEZ_MOVE_TO); vn = pts[next].p1; if (closed) { if (pts[i].type == BezPoint::BEZ_LINE_TO) { line_bbox(&vsc,&vx,&full_lextra,&rt); } else { bicubicbezier2D_bbox(&vsc, &pts[i].p1,&pts[i].p2,&pts[i].p3, &bextra, &rt); } } else if (start) { if (pts[i].type == BezPoint::BEZ_LINE_TO) { if (end) { line_bbox(&vsc,&vx,&full_lextra,&rt); } else { line_bbox(&vsc,&vx,&start_lextra,&rt); } } else { if (end) { bicubicbezier2D_bbox(&vsc, &pts[i].p1,&pts[i].p2,&pts[i].p3, extra, &rt); } else { bicubicbezier2D_bbox(&vsc, &pts[i].p1,&pts[i].p2,&pts[i].p3, &start_bextra, &rt); } } } else if (end) { if (pts[i].type == BezPoint::BEZ_LINE_TO) { line_bbox(&vsc,&vx,&end_lextra,&rt); } else { bicubicbezier2D_bbox(&vsc, &pts[i].p1,&pts[i].p2,&pts[i].p3, &end_bextra, &rt); } } else { if (pts[i].type == BezPoint::BEZ_LINE_TO) { line_bbox(&vsc,&vx,&lextra,&rt); } else { bicubicbezier2D_bbox(&vsc, &pts[i].p1,&pts[i].p2,&pts[i].p3, &bextra, &rt); } } *rect = rect->united(rt); if ((!start) && (!end)) { Point vpx,vxn; double co,alpha; point_copy_add_scaled(&vpx,&vx,&vp,-1); point_normalize(&vpx); point_copy_add_scaled(&vxn,&vn,&vx,-1); point_normalize(&vxn); co = point_dot(&vpx,&vxn); alpha = acos(-co); if ((co > -0.9816) && (finite(alpha))) { double overshoot = extra->middleTrans / sin(alpha/2.0); Point vovs,pto; point_copy_add_scaled(&vovs,&vpx,&vxn,-1); point_normalize(&vovs); point_copy_add_scaled(&pto,&vx,&vovs,overshoot); rectangle_add_point(rect,&pto); } else { Point vpxt,vxnt,tmp; point_get_perp(&vpxt,&vpx); point_get_perp(&vxnt,&vxn); point_copy_add_scaled(&tmp,&vx,&vpxt,1); rectangle_add_point(rect,&tmp); point_copy_add_scaled(&tmp,&vx,&vpxt,-1); rectangle_add_point(rect,&tmp); point_copy_add_scaled(&tmp,&vx,&vxnt,1); rectangle_add_point(rect,&tmp); point_copy_add_scaled(&tmp,&vx,&vxnt,-1); rectangle_add_point(rect,&tmp); } } } }
static void association_update_data_end(Association *assoc, int endnum) { OrthConn *orth = &assoc->orth; DiaObject *obj = &orth->object; Point *points = orth->points; Rectangle rect; AssociationEnd *end; Orientation dir; int n = orth->numpoints - 1, fp, sp; Point dir_poly[3]; /* Find the first and second points depending on which end: */ if (endnum) { fp = n; sp = n-1; dir = assoc->orth.orientation[n-1]; } else { fp = 0; sp = 1; dir = assoc->orth.orientation[0]; } /* If the points are the same, find a better candidate: */ if (points[fp].x == points[sp].x && points[fp].y == points[sp].y) { sp += (endnum ? -1 : 1); if (sp < 0) sp = 0; if (sp > n) sp = n; if (points[fp].y != points[sp].y) dir = VERTICAL; else dir = HORIZONTAL; } /* Update the text-points of the ends: */ end = &assoc->end[endnum]; end->text_pos = points[fp]; switch (dir) { case HORIZONTAL: end->text_pos.y -= end->role_descent; if (points[fp].x < points[sp].x) { end->text_align = ALIGN_LEFT; end->text_pos.x += (get_aggregate_pos_diff(end) + ASSOCIATION_END_SPACE); } else { end->text_align = ALIGN_RIGHT; end->text_pos.x -= (get_aggregate_pos_diff(end) + ASSOCIATION_END_SPACE); } break; case VERTICAL: if (end->arrow || end->aggregate != AGGREGATE_NONE) end->text_pos.x += ASSOCIATION_DIAMONDWIDTH / 2; end->text_pos.x += ASSOCIATION_END_SPACE; end->text_pos.y += end->role_ascent; if (points[fp].y > points[sp].y) { if (end->role!=NULL && *end->role) end->text_pos.y -= ASSOCIATION_FONTHEIGHT; if (end->multiplicity!=NULL) end->text_pos.y -= ASSOCIATION_FONTHEIGHT; } end->text_align = ALIGN_LEFT; break; } /* Add the text recangle to the bounding box: */ rect.left = end->text_pos.x - (end->text_align == ALIGN_LEFT ? 0 : end->text_width); rect.right = rect.left + end->text_width; rect.top = end->text_pos.y - end->role_ascent; rect.bottom = rect.top + 2*ASSOCIATION_FONTHEIGHT; rectangle_union(&obj->bounding_box, &rect); if (assoc_get_direction_poly (assoc, dir_poly)) { int i; for (i = 0; i < 3; ++i) rectangle_add_point (&obj->bounding_box, &dir_poly[i]); } }
static void transition_update_data(Transition *transition) { Element *elem = &transition->element; DiaObject *obj = &elem->object; Point *p; transition->element.extra_spacing.border_trans = TRANSITION_LINE_WIDTH / 2.0; obj->position = elem->corner; elem->width = TRANSITION_DECLAREDWIDTH; elem->height = TRANSITION_DECLAREDWIDTH; /* compute the useful points' positions : */ transition->A.x = transition->B.x = (TRANSITION_DECLAREDWIDTH / 2.0); transition->A.y = (TRANSITION_DECLAREDHEIGHT / 2.0) - (TRANSITION_HEIGHT / 2.0); transition->B.y = transition->A.y + TRANSITION_HEIGHT; transition->C.y = transition->D.y = (TRANSITION_DECLAREDHEIGHT / 2.0); transition->C.x = (TRANSITION_DECLAREDWIDTH / 2.0) - (TRANSITION_WIDTH / 2.0); transition->D.x = transition->C.x + TRANSITION_WIDTH; transition->Z.y = (TRANSITION_DECLAREDHEIGHT / 2.0) + (.3 * transition->receptivity->fontheight); transition->Z.x = transition->D.x + dia_font_string_width("_",transition->receptivity->font, transition->receptivity->fontheight); for (p = &transition->A; p <= &transition->Z; p++) point_add(p,&elem->corner); transition->receptivity->pos = transition->Z; /* Update handles: */ if (transition->north.pos.x == -65536.0) { transition->north.pos = transition->A; transition->south.pos = transition->B; } transition->NU1.x = transition->north.pos.x; transition->NU2.x = transition->A.x; transition->NU1.y = transition->NU2.y = (transition->north.pos.y + transition->A.y) / 2.0; transition->SD1.x = transition->B.x; transition->SD2.x = transition->south.pos.x; transition->SD1.y = transition->SD2.y = (transition->south.pos.y + transition->B.y) / 2.0; obj->connections[0]->pos = transition->A; obj->connections[0]->directions = DIR_EAST|DIR_WEST; obj->connections[1]->pos = transition->B; obj->connections[1]->directions = DIR_EAST|DIR_WEST; element_update_boundingbox(elem); rectangle_add_point(&obj->bounding_box,&transition->north.pos); rectangle_add_point(&obj->bounding_box,&transition->south.pos); /* compute the rcept's width and bounding box, then merge. */ boolequation_calc_boundingbox(transition->receptivity,&transition->rceptbb); rectangle_union(&obj->bounding_box,&transition->rceptbb); element_update_handles(elem); }
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); } } }
/** Calculate a bounding box for a set of bezier points. * @param pts The bezier points * @param numpoints The number of elements in `pts' * @param extra Extra spacing information. * @param closed True if the bezier points form a closed line. * @param rect Return value: The enclosing rectangle will be stored here. * @bug This function is way too long (214 lines) and should be split. */ void polybezier_bbox(const BezPoint *pts, int numpoints, const PolyBBExtras *extra, gboolean closed, Rectangle *rect) { Point vx,vn,vsc,vp; int i,prev,next; Rectangle rt; PolyBBExtras bextra,start_bextra,end_bextra; LineBBExtras lextra,start_lextra,end_lextra,full_lextra; gboolean start,end; vp.x=0; vp.y=0; g_assert(pts[0].type == BEZ_MOVE_TO); rect->left = rect->right = pts[0].p1.x; rect->top = rect->bottom = pts[0].p1.y; /* First, we build derived BBExtras structures, so we have something to feed the primitives. */ if (!closed) { start_lextra.start_long = extra->start_long; start_lextra.start_trans = MAX(extra->start_trans,extra->middle_trans); start_lextra.end_long = 0; start_lextra.end_trans = extra->middle_trans; end_lextra.start_long = 0; end_lextra.start_trans = extra->middle_trans; end_lextra.end_long = extra->end_long; end_lextra.end_trans = MAX(extra->end_trans,extra->middle_trans); } full_lextra.start_long = extra->start_long; full_lextra.start_trans = MAX(extra->start_trans,extra->middle_trans); full_lextra.end_long = extra->end_long; full_lextra.end_trans = MAX(extra->end_trans,extra->middle_trans); if (!closed) { lextra.start_long = 0; lextra.start_trans = extra->middle_trans; lextra.end_long = 0; lextra.end_trans = extra->middle_trans; start_bextra.start_long = extra->start_long; start_bextra.start_trans = extra->start_trans; start_bextra.middle_trans = extra->middle_trans; start_bextra.end_long = 0; start_bextra.end_trans = extra->middle_trans; end_bextra.start_long = 0; end_bextra.start_trans = extra->middle_trans; end_bextra.middle_trans = extra->middle_trans; end_bextra.end_long = extra->end_long; end_bextra.end_trans = extra->end_trans; } bextra.start_long = 0; bextra.start_trans = extra->middle_trans; bextra.middle_trans = extra->middle_trans; bextra.end_long = 0; bextra.end_trans = extra->middle_trans; for (i=1;i<numpoints;i++) { next = (i+1) % numpoints; prev = (i-1) % numpoints; if (closed && (next == 0)) next=1; if (closed && (prev == 0)) prev=numpoints-1; /* We have now: i = index of current vertex. prev,next: index of previous/next vertices (of the control polygon) We want: vp, vx, vn: the previous, current and next vertices; start, end: TRUE if we're at an end of poly (then, vp and/or vn are not valid, respectively). Some values *will* be recomputed a few times across iterations (but stored in different boxes). Either gprof says it's a real problem, or gcc finally gets a clue. */ if (pts[i].type == BEZ_MOVE_TO) { continue; } switch(pts[i].type) { case BEZ_MOVE_TO: g_assert_not_reached(); break; case BEZ_LINE_TO: point_copy(&vx,&pts[i].p1); switch(pts[prev].type) { case BEZ_MOVE_TO: case BEZ_LINE_TO: point_copy(&vsc,&pts[prev].p1); point_copy(&vp,&pts[prev].p1); break; case BEZ_CURVE_TO: point_copy(&vsc,&pts[prev].p3); point_copy(&vp,&pts[prev].p3); break; } break; case BEZ_CURVE_TO: point_copy(&vx,&pts[i].p3); point_copy(&vp,&pts[i].p2); switch(pts[prev].type) { case BEZ_MOVE_TO: case BEZ_LINE_TO: point_copy(&vsc,&pts[prev].p1); break; case BEZ_CURVE_TO: point_copy(&vsc,&pts[prev].p3); break; } /* vsc is the start of the curve. */ break; } start = (pts[prev].type == BEZ_MOVE_TO); end = (pts[next].type == BEZ_MOVE_TO); point_copy(&vn,&pts[next].p1); /* whichever type pts[next] is. */ /* Now, we know about a few vertices around the one we're dealing with. Depending on the shape of the (previous,current) segment, and whether it's a middle or end segment, we'll be doing different stuff. */ if (closed) { if (pts[i].type == BEZ_LINE_TO) { line_bbox(&vsc,&vx,&full_lextra,&rt); } else { bicubicbezier2D_bbox(&vsc, &pts[i].p1,&pts[i].p2,&pts[i].p3, &bextra, &rt); } } else if (start) { if (pts[i].type == BEZ_LINE_TO) { if (end) { line_bbox(&vsc,&vx,&full_lextra,&rt); } else { line_bbox(&vsc,&vx,&start_lextra,&rt); } } else { /* BEZ_MOVE_TO */ if (end) { bicubicbezier2D_bbox(&vsc, &pts[i].p1,&pts[i].p2,&pts[i].p3, extra, &rt); } else { bicubicbezier2D_bbox(&vsc, &pts[i].p1,&pts[i].p2,&pts[i].p3, &start_bextra, &rt); } } } else if (end) { /* end but not start. Not closed anyway. */ if (pts[i].type == BEZ_LINE_TO) { line_bbox(&vsc,&vx,&end_lextra,&rt); } else { bicubicbezier2D_bbox(&vsc, &pts[i].p1,&pts[i].p2,&pts[i].p3, &end_bextra, &rt); } } else { /* normal case : middle segment (not closed shape). */ if (pts[i].type == BEZ_LINE_TO) { line_bbox(&vsc,&vx,&lextra,&rt); } else { bicubicbezier2D_bbox(&vsc, &pts[i].p1,&pts[i].p2,&pts[i].p3, &bextra, &rt); } } rectangle_union(rect,&rt); /* The following code enlarges a little the bounding box (if necessary) to account with the "pointy corners" X (and PS) add when LINEJOIN_MITER mode is in force. */ if ((!start) && (!end)) { /* We have a non-extremity vertex. */ Point vpx,vxn; real co,alpha; point_copy_add_scaled(&vpx,&vx,&vp,-1); point_normalize(&vpx); point_copy_add_scaled(&vxn,&vn,&vx,-1); point_normalize(&vxn); co = point_dot(&vpx,&vxn); alpha = acos(-co); if (co > -0.9816) { /* 0.9816 = cos(11deg) */ /* we have a pointy join. */ real overshoot; Point vovs,pto; if (finite(alpha)) overshoot = extra->middle_trans / sin(alpha/2.0); else /* prependicular? */ overshoot = extra->middle_trans; point_copy_add_scaled(&vovs,&vpx,&vxn,-1); point_normalize(&vovs); point_copy_add_scaled(&pto,&vx,&vovs,overshoot); rectangle_add_point(rect,&pto); } else { /* we don't have a pointy join. */ Point vpxt,vxnt,tmp; point_get_perp(&vpxt,&vpx); point_get_perp(&vxnt,&vxn); point_copy_add_scaled(&tmp,&vx,&vpxt,1); rectangle_add_point(rect,&tmp); point_copy_add_scaled(&tmp,&vx,&vpxt,-1); rectangle_add_point(rect,&tmp); point_copy_add_scaled(&tmp,&vx,&vxnt,1); rectangle_add_point(rect,&tmp); point_copy_add_scaled(&tmp,&vx,&vxnt,-1); rectangle_add_point(rect,&tmp); } } } }
static void arc_update_data(Arc *arc) { Connection *conn = &arc->connection; LineBBExtras *extra =&conn->extra_spacing; DiaObject *obj = &conn->object; Point *endpoints; real x1,y1,x2,y2,xc,yc; real lensq, alpha, radius; real angle1, angle2; gboolean righthand; endpoints = &arc->connection.endpoints[0]; x1 = endpoints[0].x; y1 = endpoints[0].y; x2 = endpoints[1].x; y2 = endpoints[1].y; lensq = (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1); if (fabs(arc->curve_distance) > 0.01) radius = lensq/(8*arc->curve_distance) + arc->curve_distance/2.0; else radius = 0.0; /* not really but used for bbox calculation below */ if (lensq == 0.0 || arc_is_line (arc)) alpha = 1.0; /* arbitrary, but /not/ 1/0 */ else alpha = (radius - arc->curve_distance) / sqrt(lensq); xc = (x1 + x2) / 2.0 + (y2 - y1)*alpha; yc = (y1 + y2) / 2.0 + (x1 - x2)*alpha; angle1 = -atan2(y1-yc, x1-xc)*180.0/M_PI; if (angle1<0) angle1+=360.0; angle2 = -atan2(y2-yc, x2-xc)*180.0/M_PI; if (angle2<0) angle2+=360.0; if (radius<0.0) { real tmp; tmp = angle1; angle1 = angle2; angle2 = tmp; radius = -radius; } arc->radius = radius; arc->center.x = xc; arc->center.y = yc; arc->angle1 = angle1; arc->angle2 = angle2; /* LineBBExtras not applicable to calculate the arrows bounding box */ extra->start_trans = extra->end_trans = extra->start_long = extra->end_long = (arc->line_width / 2.0); /* updates midpoint */ arc_update_handles(arc); /* startpoint, midpoint, endpoint */ righthand = is_right_hand (&endpoints[0], &arc->middle_handle.pos, &endpoints[1]); connection_update_boundingbox(conn); /* fix boundingbox for arc's special shape XXX find a more elegant way: */ if (in_angle(0, arc->angle1, arc->angle2)) { /* rigth side, y does not matter if included */ Point pt = { arc->center.x + arc->radius + (arc->line_width / 2.0), y1 }; rectangle_add_point (&obj->bounding_box, &pt); } if (in_angle(90, arc->angle1, arc->angle2)) { /* top side, x does not matter if included */ Point pt = {x1, arc->center.y - arc->radius - (arc->line_width / 2.0) }; rectangle_add_point (&obj->bounding_box, &pt); } if (in_angle(180, arc->angle1, arc->angle2)) { /* left side, y does not matter if included */ Point pt = { arc->center.x - arc->radius - (arc->line_width / 2.0), y1 }; rectangle_add_point (&obj->bounding_box, &pt); } if (in_angle(270, arc->angle1, arc->angle2)) { /* bootom side, x does not matter if included */ Point pt = { x1, arc->center.y + arc->radius + (arc->line_width / 2.0) }; rectangle_add_point (&obj->bounding_box, &pt); } if (arc->start_arrow.type != ARROW_NONE) { /* a good from-point would be the chord of arrow length, but draw_arc_with_arrows currently uses the tangent * For big arcs the difference is not huge and the minimum size of small arcs should be limited by the arror length. */ Rectangle bbox = {0,}; real tmp; Point move_arrow, move_line; Point to = arc->connection.endpoints[0]; Point from = to; point_sub (&from, &arc->center); tmp = from.x; if (righthand) from.x = -from.y, from.y = tmp; else from.x = from.y, from.y = -tmp; point_add (&from, &to); calculate_arrow_point(&arc->start_arrow, &to, &from, &move_arrow, &move_line, arc->line_width); /* move them */ point_sub(&to, &move_arrow); point_sub(&from, &move_line); arrow_bbox(&arc->start_arrow, arc->line_width, &to, &from, &bbox); rectangle_union(&obj->bounding_box, &bbox); } if (arc->end_arrow.type != ARROW_NONE) { Rectangle bbox = {0,}; real tmp; Point move_arrow, move_line; Point to = arc->connection.endpoints[1]; Point from = to; point_sub (&from, &arc->center); tmp = from.x; if (righthand) from.x = from.y, from.y = -tmp; else from.x = -from.y, from.y = tmp; point_add (&from, &to); calculate_arrow_point(&arc->end_arrow, &to, &from, &move_arrow, &move_line, arc->line_width); /* move them */ point_sub(&to, &move_arrow); point_sub(&from, &move_line); arrow_bbox(&arc->end_arrow, arc->line_width, &to, &from, &bbox); rectangle_union(&obj->bounding_box, &bbox); } /* if selected put the centerpoint in the box, too. */ obj->enclosing_box = obj->bounding_box; rectangle_add_point(&obj->enclosing_box, &arc->center); obj->position = conn->endpoints[0]; }