static void arc_move_handle(Arc *arc, Handle *handle, Point *to, HandleMoveReason reason, ModifierKeys modifiers) { assert(arc!=NULL); assert(handle!=NULL); assert(to!=NULL); if (handle->id == HANDLE_MIDDLE) { Point a,b; real tmp; b = *to; point_sub(&b, &arc->connection.endpoints[0]); a = arc->connection.endpoints[1]; point_sub(&a, &arc->connection.endpoints[0]); tmp = point_dot(&a,&b); arc->curve_distance = sqrt(fabs(point_dot(&b,&b) - tmp*tmp/point_dot(&a,&a))); if (a.x*b.y - a.y*b.x < 0) arc->curve_distance = -arc->curve_distance; } else { connection_move_handle(&arc->connection, handle->id, to, reason); } arc_update_data(arc); }
static void implements_move_handle(Implements *implements, Handle *handle, Point *to, HandleMoveReason reason, ModifierKeys modifiers) { Point v1, v2; assert(implements!=NULL); assert(handle!=NULL); assert(to!=NULL); if (handle->id == HANDLE_MOVE_TEXT) { implements->text_pos = *to; } else if (handle->id == HANDLE_CIRCLE_SIZE) { v1 = implements->connection.endpoints[0]; point_sub(&v1, &implements->connection.endpoints[1]); point_normalize(&v1); v2 = *to; point_sub(&v2, &implements->connection.endpoints[1]); implements->circle_diameter = point_dot(&v1, &v2); if (implements->circle_diameter<0.03) implements->circle_diameter = 0.03; } else { v1 = implements->connection.endpoints[1]; connection_move_handle(&implements->connection, handle->id, to, reason); point_sub(&v1, &implements->connection.endpoints[1]); point_sub(&implements->text_pos, &v1); } implements_update_data(implements); }
static int find_median_radius(unsigned n, point o[], plane* pp) { double d, min, max; plane p; unsigned i; unsigned long nin; unsigned long tn; static unsigned const maxiter = 60; p = *pp; min = my_dbl_max; max = -my_dbl_max; for (i = 0; i < n; ++i) { d = point_dot(o[i], p.n); min = MIN(min, d); max = MAX(max, d); } mpi_min_doubles(comm_mpi(), &min, 1); mpi_max_doubles(comm_mpi(), &max, 1); d = (max - min) * (1.0 / 4.0 + epsilon); p.r = (max + min) / 2.0; tn = mpi_add_ulong(comm_mpi(), n); for (i = 0; i < maxiter; ++i) { nin = count_total_in(n, o, p); if (nin == tn / 2) { *pp = p; return 1; } if (nin < tn / 2) p.r -= d; else p.r += d; d /= 2.0; } return 0; }
static real arc_distance_from(Arc *arc, Point *point) { Point *endpoints; Point from_center; real angle; real d, d2; endpoints = &arc->connection.endpoints[0]; from_center = *point; point_sub(&from_center, &arc->center); angle = -atan2(from_center.y, from_center.x)*180.0/M_PI; if (angle<0) angle+=360.0; if (in_angle(angle, arc->angle1, arc->angle2)) { d = fabs(sqrt(point_dot(&from_center, &from_center)) - arc->radius); d -= arc->line_width/2.0; if (d<0) d = 0.0; return d; } else { d = distance_point_point(&endpoints[0], point); d2 = distance_point_point(&endpoints[1], point); return MIN(d,d2); } }
/*Reumann-Witkam algorithm * Returns number of points in the output line */ int reumann_witkam(struct line_pnts *Points, double thresh, int with_z) { int seg1, seg2; int i, count; POINT x0, x1, x2, sub, diff; double subd, diffd, sp, dist; int n; n = Points->n_points; if (n < 3) return n; thresh *= thresh; seg1 = 0; seg2 = 1; count = 1; point_assign(Points, 0, with_z, &x1); point_assign(Points, 1, with_z, &x2); point_subtract(x2, x1, &sub); subd = point_dist2(sub); for (i = 2; i < n; i++) { point_assign(Points, i, with_z, &x0); point_subtract(x1, x0, &diff); diffd = point_dist2(diff); sp = point_dot(diff, sub); dist = (diffd * subd - sp * sp) / subd; /* if the point is out of the threshlod-sausage, store it and calculate * all variables which do not change for each line-point calculation */ if (dist > thresh) { point_assign(Points, i - 1, with_z, &x1); point_assign(Points, i, with_z, &x2); point_subtract(x2, x1, &sub); subd = point_dist2(sub); Points->x[count] = x0.x; Points->y[count] = x0.y; Points->z[count] = x0.z; count++; } } Points->x[count] = Points->x[n - 1]; Points->y[count] = Points->y[n - 1]; Points->z[count] = Points->z[n - 1]; Points->n_points = count + 1; return Points->n_points; }
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 real arc_compute_curve_distance(const Arc *arc, const Point *start, const Point *end, const Point *mid) { Point a,b; real tmp,cd; b = *mid; point_sub(&b, start); a = *end; point_sub(&a, start); tmp = point_dot(&a,&b); cd = sqrt(fabs(point_dot(&b,&b) - tmp*tmp/point_dot(&a,&a))); if (a.x*b.y - a.y*b.x < 0) cd = - cd; return cd; }
/* * 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; }
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 _calc_grid_values( double *x, double *y, double *norms, int num_vert, long *volumes, int num_tri, double cell_size, int nrow, int ncol, double *vertex_val, double *grid_val ) { int i, j, k; int x_min, x_max, y_min, y_max, point_index; double x_dist, y_dist, x_base, y_base; double sigma0, sigma1, sigma2; double fraction, intpart; double triangle[6], point[2]; double v1[2], v2[2], v3[2]; double n1[2], n2[2], n3[2]; double val1, val2, res[2]; EXTENT extent[1]; x_dist = cell_size; y_dist = cell_size; x_base = 0.0; y_base = 0.0; /* printf("%d\n",num_tri); for ( i=0; i< num_tri; i++){ printf("volumes\n"); printf("%ld %ld %ld \n",volumes[3*i],volumes[3*i+1],volumes[3*i+2]); } printf("%d\n",num_vert); for ( i=0; i< num_vert; i++){ printf("vertices\n"); printf("%g %g \n",x[i],y[i]); } */ for ( i = 0; i < num_tri; i++ ) { get_tri_vertices( x,y, volumes, i, triangle, v1, v2, v3); get_tri_norms( norms, i, n1, n2, n3 ); get_tri_extent( triangle, extent ); /* printf("tri %g %g %g %g %g %g\n", triangle[0],triangle[1],triangle[2],triangle[3], triangle[4],triangle[5]); printf("v1 %g %g\n", v1[0], v1[1]); printf("v2 %g %g\n", v2[0], v2[1]); printf("v3 %g %g\n", v3[0], v3[1]); printf("e.xmin %g \n", extent->x_min); printf("e.xmax %g \n", extent->x_max); printf("e.ymin %g \n", extent->y_min); printf("e.ymax %g \n", extent->y_max); */ fraction = modf( (extent->x_min - x_base)/x_dist, &intpart ); x_min = intpart; x_min = (x_min < 0) ? 0 : x_min; fraction = modf( ABS(extent->x_max - x_base)/x_dist, &intpart ); x_max = intpart; x_max = (x_max > (ncol-1)) ? (ncol-1) : x_max; fraction = modf( (extent->y_min - y_base)/y_dist, &intpart ); y_min = intpart; y_min = (y_min < 0 ) ? 0 : y_min; fraction = modf( ABS(extent->y_max - y_base)/y_dist, &intpart ); y_max = intpart; y_max = (y_max > (nrow-1)) ? (nrow-1) : y_max; if ( x_max >= 0 && y_max >= 0 ) { for ( j = y_min; j <= y_max; j++ ) { for ( k = x_min; k <= x_max; k++ ) { // iterate through points within a small region point_index = j*ncol+k; //printf("point_index %d %d %d\n",point_index, j, k); point[0] = k*cell_size; point[1] = j*cell_size; if ( _is_inside_triangle( point, triangle, \ 1, 1.0e-12, 1.0e-12 ) ) { point_sub( point, v2, res); val1 = point_dot( res, n1 ); point_sub( v1, v2 , res); val2 = point_dot( res, n1 ); sigma0 = val2 ? val1/val2 : 0; point_sub( point, v3, res); val1 = point_dot( res, n2 ); point_sub( v2, v3, res); val2 = point_dot( res, n2 ); sigma1 = val2 ? val1/val2 : 0; point_sub( point, v1, res); val1 = point_dot( res, n3 ); point_sub( v3, v1, res); val2 = point_dot( res, n3 ); sigma2 = val2 ? val1/val2 : 0; grid_val[point_index] = sigma0*vertex_val[volumes[i*3]] + \ sigma1*vertex_val[volumes[i*3+1]] + \ sigma2*vertex_val[volumes[i*3+2]]; } } } } } }
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; }
inline double point_angle_between(POINT a, POINT b, POINT c) { point_subtract(b, a, &a); point_subtract(c, b, &b); return acos(point_dot(a, b) / sqrt(point_dist2(a) * point_dist2(b))); }
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); } } } }
/** 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 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; }