/*! * \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; } }
/* copied from lib/diarenderer.c, the one there should be removed */ static gboolean is_right_hand (const Point *a, const Point *b, const Point *c) { Point dot1, dot2; dot1 = *a; point_sub(&dot1, c); point_normalize(&dot1); dot2 = *b; point_sub(&dot2, c); point_normalize(&dot2); return point_cross(&dot1, &dot2) > 0; }
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); } } }
/*! * \brief Rotate path towards clicked point * * Rotate the given path around it's center with the angle given by * the top center handle and the clicked point. This function is * available with the context menu of the 'Standard - Path' object. * @return Undo information * * \relates _StdPath */ static ObjectChange * _path_rotate_callback (DiaObject *obj, Point *clicked, gpointer data) { StdPath *sp = (StdPath *)obj; real cx = (sp->object.bounding_box.left + sp->object.bounding_box.right) / 2; real cy = (sp->object.bounding_box.top + sp->object.bounding_box.bottom) / 2; DiaMatrix m = {1, 0, 0, 1, 0, 0 }; DiaMatrix translate = {1, 0, 0, 1, 0, 0 }; Point d; d.x = clicked->x - cx; d.y = clicked->y - cy; point_normalize (&d); /* to make the top, center handle clicked no rotation we subtract -PI/2 */ dia_matrix_set_angle_and_scales (&m, atan2 (d.y, d.x) + M_PI/2.0, 1.0, 1.0); /* rotate around center */ translate.x0 = cx; translate.y0 = cy; dia_matrix_multiply (&m, &m, &translate); translate.x0 = -cx; translate.y0 = -cy; dia_matrix_multiply (&m, &translate, &m); _path_transform (sp, &m); return _path_object_transform_change_create (obj, &m); }
/*! * \brief Move one of the objects handles * \memberof Outline */ static ObjectChange* outline_move_handle (Outline *outline, Handle *handle, Point *to, ConnectionPoint *cp, HandleMoveReason reason, ModifierKeys modifiers) { DiaObject *obj = &outline->object; Point start = obj->position; Point end = outline->ink_rect[2]; real dist, old_dist = distance_point_point (&start, &end); Point norm = end; point_sub (&norm, &start); point_normalize (&norm); /* we use this to modify angle and scale */ switch (handle->id) { case HANDLE_RESIZE_NW : start = *to; break; case HANDLE_RESIZE_SE : end = *to; break; default : g_warning ("Outline unknown handle"); } dist = distance_point_point (&start, &end); /* disallow everything below a certain level, otherwise the font-size could become invalid */ if (dist > 0.1) { obj->position = start; outline->font_height *= (dist / old_dist); outline_update_data (outline); } return NULL; }
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); }
/* 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; }
void polyline_calculate_gap_endpoints(Polyline *polyline, Point *gap_endpoints) { Point start_vec, end_vec; ConnectionPoint *start_cp, *end_cp; int n = polyline->poly.numpoints; gap_endpoints[0] = polyline->poly.points[0]; gap_endpoints[1] = polyline->poly.points[n-1]; start_cp = (polyline->poly.object.handles[0])->connected_to; end_cp = (polyline->poly.object.handles[polyline->poly.object.num_handles-1])->connected_to; if (connpoint_is_autogap(start_cp)) { gap_endpoints[0] = calculate_object_edge(&gap_endpoints[0], &polyline->poly.points[1], start_cp->object); } if (connpoint_is_autogap(end_cp)) { gap_endpoints[1] = calculate_object_edge(&gap_endpoints[1], &polyline->poly.points[n-2], end_cp->object); } start_vec = gap_endpoints[0]; point_sub(&start_vec, &polyline->poly.points[0]); point_normalize(&start_vec); end_vec = gap_endpoints[1]; point_sub(&end_vec, &polyline->poly.points[n-1]); point_normalize(&end_vec); /* add absolute gap */ point_add_scaled(&gap_endpoints[0], &start_vec, polyline->absolute_start_gap); point_add_scaled(&gap_endpoints[1], &end_vec, polyline->absolute_end_gap); }
/** 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); } }
/*! * \brief Set the other point of the pattern * * The meaning of the point depends on the type of the pattern. * For line gradient it is the second point giving the direction. * With a radial gradient it is the focal point. * * \ingroup DiaPattern */ void dia_pattern_set_point (DiaPattern *self, real x, real y) { self->other.x = x; self->other.y = y; /* with radial we have to ensure the point is in circle */ if (self->type == DIA_RADIAL_GRADIENT) { real dist = distance_ellipse_point (&self->start, self->radius*2, self->radius*2, 0.0, &self->other); if (dist > 0) { /* If the point defined by ‘fx’ and ‘fy’ lies outside the circle defined * by ‘cx’, ‘cy’ and ‘r’, then the user agent shall set the focal point to * the intersection of the line from (‘cx’, ‘cy’) to (‘fx’, ‘fy’) with the * circle defined by ‘cx’, ‘cy’ and ‘r’ */ Point p1 = self->start; Point p2 = self->other; point_sub (&p2, &p1); point_normalize (&p2); point_add_scaled (&p1, &p2, self->radius); self->other = p1; } } }
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; }
/** 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 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); }
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; }
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); } } } }
/*! * \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; }
/* * Draw the module into the image using the given view transformation matrix [VTM], * Lighting and DrawState by traversing the list of Elements. * (For now, Lighting can be an empty structure.) */ void module_draw(Module *md, Matrix *VTM, Matrix *GTM, DrawState *ds, Lighting *lighting, Image *src){ /* for antialiasing Module *thickLineMod = module_create(); Element *thickLineE; float dx, dy, dz, lineLength; Vector u, v, w;*/ // all locally needed variables Matrix LTM, tempGTM; Line tempLine; DrawState *tempds = drawstate_create(); Point tempPointLTM, tempPointGTM, tempPointVTM; Polyline *tempPolyline = polyline_create(); Polygon *tempPolygon = polygon_create(); Element *e = md->head; matrix_identity(<M); // loop until the end of the linked list is reached while(e){ //printf("Handling type %d\n", e->type); // draw based on type switch(e->type){ case ObjNone: break; case ObjPoint: //printf("drawing point "); // copy, xform, normalize, draw matrix_xformPoint(<M, &(e->obj.point), &tempPointLTM); matrix_xformPoint(GTM, &tempPointLTM, &tempPointGTM); matrix_xformPoint(VTM, &tempPointGTM, &tempPointVTM); point_normalize(&(tempPointVTM)); //point_print(&tempPointVTM, stdout); point_draw(&tempPointVTM, src, ds->color); break; case ObjLine: line_copy(&tempLine, &(e->obj.line)); //printf("drawing line "); // copy, xform, normalize, draw matrix_xformLine(<M, &tempLine); matrix_xformLine(GTM, &tempLine); matrix_xformLine(VTM, &tempLine); line_normalize(&tempLine); line_draw(&tempLine, src, ds->color); //line_print(&tempLine, stdout); /*if(antialias){ dx = tempLine.b.val[0]-tempLine.a.val[0]; dy = tempLine.b.val[1]-tempLine.a.val[1]; dz = tempLine.b.val[2]-tempLine.a.val[2]; lineLength = sqrt(dx*dx+dy*dy+dz*dz); module_scale( thickLineMod, 1, lineLength, 1 ); vector_set(&v, dx, dy, dz); vector_normalize(&v); vector_set(&u, -dz, dx, dy); vector_cross(&u, &v, &w); vector_cross(&v, &w, &u); vector_normalize(&u); vector_normalize(&w); module_rotateXYZ( thickLineMod, &u, &v, &w ); module_translate( thickLineMod, tempLine.a.val[0], tempLine.a.val[1], tempLine.a.val[2] ); module_cylinder( thickLineMod, 4, 1, 1, 0, 0, 0 ); thickLineE = element_init(ObjModule, thickLineMod); thickLineE->next = e->next; e->next = thickLineE; }*/ break; case ObjPolyline: //printf("drawing polyline "); // copy, xform, normalize, draw polyline_copy(tempPolyline, &(e->obj.polyline)); matrix_xformPolyline(<M, tempPolyline); matrix_xformPolyline(GTM, tempPolyline); matrix_xformPolyline(VTM, tempPolyline); polyline_normalize(tempPolyline); //polyline_print(tempPolyline, stdout); polyline_draw(tempPolyline, src, ds->color); break; case ObjPolygon: //printf("drawing polygon "); // copy, xform, normalize, draw polygon_copy(tempPolygon, &(e->obj.polygon)); matrix_xformPolygon(<M, tempPolygon); matrix_xformPolygon(GTM, tempPolygon); matrix_xformPolygon(VTM, tempPolygon); polygon_normalize(tempPolygon); //polygon_print(tempPolygon, stdout); polygon_draw(tempPolygon, src, ds); break; case ObjColor: drawstate_setColor(ds, e->obj.color); break; case ObjBodyColor: break; case ObjSurfaceColor: break; case ObjSurfaceCoeff: break; case ObjLight: break; case ObjIdentity: matrix_identity(<M); break; case ObjMatrix: matrix_multiply(&(e->obj.matrix), <M, <M); break; case ObjModule: matrix_multiply(GTM, <M, &tempGTM); drawstate_copy(tempds, ds); module_draw(e->obj.module, VTM, &tempGTM, tempds, lighting, src); break; default: printf("ObjectType %d is not handled in module_draw\n",e->type); } // advance traversal e = e->next; } // clean up polygon_free(tempPolygon); polyline_free(tempPolyline); free(tempds); }
static void compute_gap_points(Bezierline *bezierline, Point *gap_points) { real bez_length; BezierConn *bez = &bezierline->bez; Point vec_start, vec_end; gap_points[0] = bez->bezier.points[0].p1; gap_points[1] = bez->bezier.points[1].p1; gap_points[2] = bez->bezier.points[bez->bezier.num_points-1].p2; gap_points[3] = bez->bezier.points[bez->bezier.num_points-1].p3; point_copy(&vec_start, &gap_points[1]); point_sub(&vec_start, &gap_points[0]); point_normalize(&vec_start); /* unit vector pointing from first point */ point_copy(&vec_end, &gap_points[2]); point_sub(&vec_end, &gap_points[3]); point_normalize(&vec_end); /* unit vector pointing from last point */ bez_length = approx_bez_length(bez) ; if (connpoint_is_autogap(bez->object.handles[0]->connected_to) && (bez->object.handles[0])->connected_to != NULL && (bez->object.handles[0])->connected_to->object != NULL ) { Point end; point_copy(&end, &gap_points[0]); point_add_scaled(&end, &vec_start, bez_length); /* far away on the same slope */ end = calculate_object_edge(&gap_points[0], &end, (bez->object.handles[0])->connected_to->object); point_sub(&end, &gap_points[0]); /* vector from old start to new start */ /* move points */ point_add(&gap_points[0], &end); point_add(&gap_points[1], &end); } if (connpoint_is_autogap(bez->object.handles[3*(bez->bezier.num_points-1)]->connected_to) && (bez->object.handles[3*(bez->bezier.num_points-1)])->connected_to != NULL && (bez->object.handles[3*(bez->bezier.num_points-1)])->connected_to->object != NULL) { Point end; point_copy(&end, &gap_points[3]); point_add_scaled(&end, &vec_end, bez_length); /* far away on the same slope */ end = calculate_object_edge(&gap_points[3], &end, (bez->object.handles[3*(bez->bezier.num_points-1)])->connected_to->object); point_sub(&end, &gap_points[3]); /* vector from old end to new end */ /* move points */ point_add(&gap_points[3], &end); point_add(&gap_points[2], &end); } /* adds the absolute start gap according to the slope at the first point */ point_add_scaled(&gap_points[0], &vec_start, bezierline->absolute_start_gap); point_add_scaled(&gap_points[1], &vec_start, bezierline->absolute_start_gap); /* adds the absolute end gap according to the slope at the last point */ point_add_scaled(&gap_points[2], &vec_end, bezierline->absolute_end_gap); point_add_scaled(&gap_points[3], &vec_end, bezierline->absolute_end_gap); }
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* 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; }