/*! * \brief Update handle positions to reflect the current object state * * The object bounding box needs to be calculated already. * \protected \memberof StdPath */ static void stdpath_update_handles(StdPath *stdpath) { DiaObject *obj = &stdpath->object; PolyBBExtras extra = { 0, }; Rectangle rect, *bb; g_return_if_fail (obj->handles != NULL); /* Using the zero-line-width boundingbox for handles */ bb = ▭ polybezier_bbox (stdpath->points, stdpath->num_points, &extra, FALSE /*(stdpath->stroke_or_fill & PDO_FILL)*/, bb); /* from left to right, from top to bottom */ obj->handles[0]->pos.x = bb->left; obj->handles[0]->pos.y = bb->top; obj->handles[1]->pos.x = (bb->left + bb->right) / 2.0; obj->handles[1]->pos.y = bb->top; /* adjust handle pos for runtime shear? */ obj->handles[2]->pos.x = bb->right; obj->handles[2]->pos.y = bb->top; obj->handles[3]->pos.x = bb->left; obj->handles[3]->pos.y = (bb->top + bb->bottom) / 2.0; obj->handles[4]->pos.x = bb->right; obj->handles[4]->pos.y = (bb->top + bb->bottom) / 2.0; /* adjust handle pos for runtime perspective? */ obj->handles[5]->pos.x = bb->left; obj->handles[5]->pos.y = bb->bottom; obj->handles[6]->pos.x = (bb->left + bb->right) / 2.0; obj->handles[6]->pos.y = bb->bottom; obj->handles[7]->pos.x = bb->right; obj->handles[7]->pos.y = bb->bottom; }
void polyline_bbox(const Point *pts, int numpoints, const PolyBBExtras *extra, bool closed, Rectangle *rect) { int i; BezPoint bpts[numpoints+1]; bpts[0].type = BezPoint::BEZ_MOVE_TO; bpts[0].p1 = pts[0]; for (i=1;i<numpoints;i++) { bpts[i].type = BezPoint::BEZ_LINE_TO; bpts[i].p1 = pts[i]; } polybezier_bbox(bpts,numpoints + (closed?1:0),extra,closed,rect); }
/*! * \brief Object update function called after property change * * Not in the object interface but very important anyway. * Used to recalculate the object data after a change * \protected \memberof StdPath */ static void stdpath_update_data (StdPath *stdpath) { DiaObject *obj = &stdpath->object; Rectangle *bb = &obj->bounding_box; PolyBBExtras extra = { 0 }; real lw = stdpath->stroke_or_fill & PDO_STROKE ? stdpath->line_width : 0.0; extra.start_trans = extra.end_trans = extra.start_long = extra.end_long = extra.middle_trans = lw/2.0; /* recalculate the bounding box */ polybezier_bbox (stdpath->points, stdpath->num_points, &extra, FALSE /*(stdpath->stroke_or_fill & PDO_FILL)*/, bb); /* adjust position from it */ obj->position.x = stdpath->points[0].p1.x; obj->position.y = stdpath->points[0].p1.y; /* adjust handles */ stdpath_update_handles (stdpath); }
/** Calculate the boundingbox for a polyline. * @param pts Array of points. * @param numpoints Number of elements in `pts'. * @param extra Extra space information * @param closed Whether the polyline is closed or not. * @param rect Return value: The bounding box that includes the points and * extra spacing. * @bug Surely doesn't need to use bezier code, but remember extra stuff. */ void polyline_bbox(const Point *pts, int numpoints, const PolyBBExtras *extra, gboolean closed, Rectangle *rect) { /* It's much easier to re-use the Bezier code... */ int i; BezPoint *bpts = alloc_polybezier_space(numpoints + 1); bpts[0].type = BEZ_MOVE_TO; bpts[0].p1 = pts[0]; for (i=1;i<numpoints;i++) { bpts[i].type = BEZ_LINE_TO; bpts[i].p1 = pts[i]; } /* This one will be used only when closed==TRUE... */ bpts[numpoints].type = BEZ_LINE_TO; bpts[numpoints].p1 = pts[0]; polybezier_bbox(bpts,numpoints + (closed?1:0),extra,closed,rect); free_polybezier_space(bpts); }
static void update_bounds(ShapeInfo *info) { GList *tmp; Point pt; for (tmp = info->display_list; tmp; tmp = tmp->next) { GraphicElement *el = tmp->data; int i; switch (el->type) { case GE_SUBSHAPE: /* subshapes are not supposed to have an influence on bounds */ break; case GE_LINE: check_point(info, &(el->line.p1)); check_point(info, &(el->line.p2)); break; case GE_POLYLINE: for (i = 0; i < el->polyline.npoints; i++) check_point(info, &(el->polyline.points[i])); break; case GE_POLYGON: for (i = 0; i < el->polygon.npoints; i++) check_point(info, &(el->polygon.points[i])); break; case GE_RECT: check_point(info, &(el->rect.corner1)); check_point(info, &(el->rect.corner2)); /* el->rect.corner_radius has no infulence on the bounding rectangle */ break; case GE_TEXT: check_point(info, &(el->text.anchor)); break; case GE_ELLIPSE: pt = el->ellipse.center; pt.x -= el->ellipse.width / 2.0; pt.y -= el->ellipse.height / 2.0; check_point(info, &pt); pt.x += el->ellipse.width; pt.y += el->ellipse.height; check_point(info, &pt); break; case GE_PATH: case GE_SHAPE: #if 1 { Rectangle bbox; PolyBBExtras extra = { 0, }; polybezier_bbox(&el->path.points[0],el->path.npoints, &extra,el->type == GE_SHAPE,&bbox); rectangle_union(&info->shape_bounds, &bbox); } #else for (i = 0; i < el->path.npoints; i++) switch (el->path.points[i].type) { case BEZ_CURVE_TO: check_point(info, &el->path.points[i].p3); check_point(info, &el->path.points[i].p2); case BEZ_MOVE_TO: case BEZ_LINE_TO: check_point(info, &el->path.points[i].p1); } #endif break; case GE_IMAGE: check_point(info, &(el->image.topleft)); pt.x = el->image.topleft.x + el->image.width; pt.y = el->image.topleft.y + el->image.height; check_point(info, &pt); break; } } { real width = info->shape_bounds.right-info->shape_bounds.left; real height = info->shape_bounds.bottom-info->shape_bounds.top; if (info->default_width > 0.0 && info->default_height == 0.0) { info->default_height = (info->default_width / width) * height; } else if (info->default_height > 0.0 && info->default_width == 0.0) { info->default_width = (info->default_height / height) * width; } } }