mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-07 21:23:32 +00:00
renderer: revise the paint bounding box api
C++ API Modificaiton: - Result Paint::bounds(float* x, float* y, float* w, float* h, bool transform = false) const -> Result Paint::bounds(float* x, float* y, float* w, float* h) const C++ API Addition: - Result Paint::bounds(Point* pt4) const C API Modification: - Tvg_Result tvg_paint_get_bounds(const Tvg_Paint* paint, float* x, float* y, float* w, float* h, bool transformed); -> Tvg_Result tvg_paint_get_aabb(const Tvg_Paint* paint, float* x, float* y, float* w, float* h); C API Addition: - Tvg_Result tvg_paint_get_obb(const Tvg_Paint* paint, Tvg_Point* pt4); issue: https://github.com/thorvg/thorvg/issues/3290
This commit is contained in:
parent
259dbc9840
commit
67098793f0
14 changed files with 212 additions and 149 deletions
|
@ -97,13 +97,30 @@ struct UserExample : tvgexam::Example
|
|||
|
||||
bool clicked(tvg::Canvas* canvas, int32_t x, int32_t y) override
|
||||
{
|
||||
auto intersect = [&](float x, float y, tvg::Point* obb) -> bool {
|
||||
//compute edge vectors
|
||||
tvg::Point e1 = {obb[1].x - obb[0].x, obb[1].y - obb[0].y}; // Edge from obb[0] to obb[1]
|
||||
tvg::Point e2 = {obb[3].x - obb[0].x, obb[3].y - obb[0].y}; // Edge from obb[0] to obb[3]
|
||||
|
||||
//compute vectors from obb[0] to the test point
|
||||
tvg::Point o = {x - obb[0].x, y - obb[0].y};
|
||||
|
||||
/* compute dot products to express `o` in terms of edge1 and edge2
|
||||
and then compute barycentric coordinates (u, v) within the box space */
|
||||
auto u = (o.x * e1.x + o.y * e1.y) / (e1.x * e1.x + e1.y * e1.y);
|
||||
auto v = (o.x * e2.x + o.y * e2.y) / (e2.x * e2.x + e2.y * e2.y);
|
||||
|
||||
// Check if point is inside the OBB
|
||||
return (u >= 0.0f && u <= 1.0f && v >= 0.0f && v <= 1.0f);
|
||||
};
|
||||
|
||||
int i = 0;
|
||||
for (auto& state : states) {
|
||||
if (auto paint = lottie->picture()->paint(tvg::Accessor::id(state.name.c_str()))) {
|
||||
float px, py, pw, ph;
|
||||
paint->bounds(&px, &py, &pw, &ph, true);
|
||||
tvg::Point obb[4];
|
||||
paint->bounds(obb);
|
||||
//hit a emoji layer!
|
||||
if (x >= px && x <= px + pw && y >= py && y <= py + ph) {
|
||||
if (intersect(x, y, obb)) {
|
||||
tweening(i);
|
||||
return true;
|
||||
}
|
||||
|
|
42
inc/thorvg.h
42
inc/thorvg.h
|
@ -412,20 +412,42 @@ public:
|
|||
Result blend(BlendMethod method) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Gets the axis-aligned bounding box of the paint object.
|
||||
* @brief Retrieves the object-oriented bounding box (OBB) of the paint object in canvas space.
|
||||
*
|
||||
* This function returns the bounding box of the paint, as an oriented bounding box (OBB) after transformations are applied.
|
||||
*
|
||||
* @param[out] x The x-coordinate of the upper-left corner of the object.
|
||||
* @param[out] y The y-coordinate of the upper-left corner of the object.
|
||||
* @param[out] w The width of the object.
|
||||
* @param[out] h The height of the object.
|
||||
* @param[in] transformed If @c true, the paint's transformations are taken into account in the scene it belongs to. Otherwise they aren't.
|
||||
* @param[out] pt4 An array of four points representing the bounding box. The array size must be 4.
|
||||
*
|
||||
* @note This is useful when you need to figure out the bounding box of the paint in the canvas space.
|
||||
* @note The bounding box doesn't indicate the actual drawing region. It's the smallest rectangle that encloses the object.
|
||||
* @note If @p transformed is @c true, the paint needs to be pushed into a canvas and updated before this api is called.
|
||||
* @retval Result::InvalidArguments @p pt4 is @c nullptr.
|
||||
* @retval Result::InsufficientCondition If it failed to compute the bounding box (mostly due to invalid path information).
|
||||
*
|
||||
* @note The paint must be pushed into a canvas and updated before calling this function.
|
||||
*
|
||||
* @see Paint::bounds(float* x, float* y, folat* w, float* h)
|
||||
* @see Canvas::update()
|
||||
*
|
||||
* @since 1.0
|
||||
*/
|
||||
Result bounds(Point* pt4) const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Retrieves the axis-aligned bounding box (AABB) of the paint object in local space.
|
||||
*
|
||||
* This function returns the bounding box of the paint object relative to its local coordinate system, without applying any transformations.
|
||||
*
|
||||
* @param[out] x The x-coordinate of the upper-left corner of the bounding box.
|
||||
* @param[out] y The y-coordinate of the upper-left corner of the bounding box.
|
||||
* @param[out] w The width of the bounding box.
|
||||
* @param[out] h The height of the bounding box.
|
||||
*
|
||||
* @retval Result::InsufficientCondition If it failed to compute the bounding box (mostly due to invalid path information).
|
||||
*
|
||||
* @note The bounding box is calculated in the object's local space, meaning transformations such as scaling, rotation, or translation are not applied.
|
||||
*
|
||||
* @see Paint::bounds(Point* pt4)
|
||||
* @see Canvas::update()
|
||||
*/
|
||||
Result bounds(float* x, float* y, float* w, float* h, bool transformed = false) const noexcept;
|
||||
Result bounds(float* x, float* y, float* w, float* h) const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Duplicates the object.
|
||||
|
|
|
@ -912,25 +912,49 @@ TVG_API Tvg_Result tvg_paint_get_opacity(const Tvg_Paint* paint, uint8_t* opacit
|
|||
TVG_API Tvg_Paint* tvg_paint_duplicate(Tvg_Paint* paint);
|
||||
|
||||
|
||||
/*!
|
||||
* @brief Gets the axis-aligned bounding box of the Tvg_Paint object.
|
||||
*
|
||||
* @param[in] paint The Tvg_Paint object of which to get the bounds.
|
||||
* @param[out] x The x-coordinate of the upper-left corner of the object.
|
||||
* @param[out] y The y-coordinate of the upper-left corner of the object.
|
||||
* @param[out] w The width of the object.
|
||||
* @param[out] h The height of the object.
|
||||
* @param[in] transformed If @c true, the paint's transformations are taken into account in the scene it belongs to. Otherwise they aren't.
|
||||
*
|
||||
* @return Tvg_Result enumeration.
|
||||
* @retval TVG_RESULT_INVALID_ARGUMENT An invalid Tvg_Paint pointer.
|
||||
*
|
||||
* @note This is useful when you need to figure out the bounding box of the paint in the canvas space.
|
||||
* @note The bounding box doesn't indicate the actual drawing region. It's the smallest rectangle that encloses the object.
|
||||
* @note If @p transformed is @c true, the paint needs to be pushed into a canvas and updated before this api is called.
|
||||
* @see tvg_canvas_update_paint()
|
||||
*/
|
||||
TVG_API Tvg_Result tvg_paint_get_bounds(const Tvg_Paint* paint, float* x, float* y, float* w, float* h, bool transformed);
|
||||
/**
|
||||
* @brief Retrieves the axis-aligned bounding box (AABB) of the paint object in local space.
|
||||
*
|
||||
* This function returns the bounding box of the paint object relative to its local coordinate system, without applying any transformations.
|
||||
*
|
||||
* @param[in] paint The Tvg_Paint object of which to get the bounds.
|
||||
* @param[out] x The x-coordinate of the upper-left corner of the bounding box.
|
||||
* @param[out] y The y-coordinate of the upper-left corner of the bounding box.
|
||||
* @param[out] w The width of the bounding box.
|
||||
* @param[out] h The height of the bounding box.
|
||||
*
|
||||
* @return Tvg_Result enumeration.
|
||||
* @retval TVG_RESULT_INVALID_ARGUMENT An invalid @p paint.
|
||||
* @retval TVG_RESULT_INSUFFICIENT_CONDITION If it failed to compute the bounding box (mostly due to invalid path information).
|
||||
*
|
||||
* @note The bounding box is calculated in the object's local space, meaning transformations such as scaling, rotation, or translation are not applied.
|
||||
*
|
||||
* @see tvg_paint_get_obb()
|
||||
* @see tvg_canvas_update_paint()
|
||||
*/
|
||||
TVG_API Tvg_Result tvg_paint_get_aabb(const Tvg_Paint* paint, float* x, float* y, float* w, float* h);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Retrieves the object-oriented bounding box (OBB) of the paint object in canvas space.
|
||||
*
|
||||
* This function returns the bounding box of the paint, as an oriented bounding box (OBB) after transformations are applied.
|
||||
*
|
||||
* @param[in] paint The Tvg_Paint object of which to get the bounds.
|
||||
* @param[out] pt4 An array of four points representing the bounding box. The array size must be 4.
|
||||
*
|
||||
* @return Tvg_Result enumeration.
|
||||
* @retval TVG_RESULT_INVALID_ARGUMENT @p paint or @p pt4 is invalid.
|
||||
* @retval TVG_RESULT_INSUFFICIENT_CONDITION If it failed to compute the bounding box (mostly due to invalid path information).
|
||||
*
|
||||
* @note The paint must be pushed into a canvas and updated before calling this function.
|
||||
*
|
||||
* @see tvg_paint_get_aabb()
|
||||
* @see tvg_canvas_update_paint()
|
||||
*
|
||||
* @since 1.0
|
||||
*/
|
||||
TVG_API Tvg_Result tvg_paint_get_obb(const Tvg_Paint* paint, Tvg_Point* pt4);
|
||||
|
||||
|
||||
/*!
|
||||
|
@ -941,7 +965,7 @@ TVG_API Tvg_Result tvg_paint_get_bounds(const Tvg_Paint* paint, float* x, float*
|
|||
* @param[in] method The method used to mask the source object with the target.
|
||||
*
|
||||
* @return Tvg_Result enumeration.
|
||||
* @retval TVG_RESULT_INVALID_ARGUMENT An invalid @p paint or @p target object or the @p method equal to TVG_MASK_METHOD_NONE.
|
||||
|
||||
*/
|
||||
TVG_API Tvg_Result tvg_paint_set_mask_method(Tvg_Paint* paint, Tvg_Paint* target, Tvg_Mask_Method method);
|
||||
|
||||
|
|
|
@ -256,12 +256,17 @@ TVG_API Tvg_Result tvg_paint_get_opacity(const Tvg_Paint* paint, uint8_t* opacit
|
|||
}
|
||||
|
||||
|
||||
TVG_API Tvg_Result tvg_paint_get_bounds(const Tvg_Paint* paint, float* x, float* y, float* w, float* h, bool transformed)
|
||||
TVG_API Tvg_Result tvg_paint_get_aabb(const Tvg_Paint* paint, float* x, float* y, float* w, float* h)
|
||||
{
|
||||
if (!paint) return TVG_RESULT_INVALID_ARGUMENT;
|
||||
return (Tvg_Result) reinterpret_cast<const Paint*>(paint)->bounds(x, y, w, h, transformed);
|
||||
return (Tvg_Result) reinterpret_cast<const Paint*>(paint)->bounds(x, y, w, h);
|
||||
}
|
||||
|
||||
TVG_API Tvg_Result tvg_paint_get_obb(const Tvg_Paint* paint, Tvg_Point* pt4)
|
||||
{
|
||||
if (!paint) return TVG_RESULT_INVALID_ARGUMENT;
|
||||
return (Tvg_Result) reinterpret_cast<const Paint*>(paint)->bounds((Point*)pt4);
|
||||
}
|
||||
|
||||
TVG_API Tvg_Result tvg_paint_set_mask_method(Tvg_Paint* paint, Tvg_Paint* target, Tvg_Mask_Method method)
|
||||
{
|
||||
|
|
|
@ -927,7 +927,7 @@ static void _fontText(LottieText* text, Scene* scene, float frameNo, LottieExpre
|
|||
txt->fill(doc.color.rgb[0], doc.color.rgb[1], doc.color.rgb[2]);
|
||||
|
||||
float width;
|
||||
txt->bounds(nullptr, nullptr, &width, nullptr, false);
|
||||
txt->bounds(nullptr, nullptr, &width, nullptr);
|
||||
|
||||
auto cursorX = width * doc.justify;
|
||||
txt->translate(cursorX, -doc.size * 100.0f);
|
||||
|
|
|
@ -47,26 +47,10 @@ static inline bool _isGroupType(SvgNodeType type)
|
|||
|
||||
//According to: https://www.w3.org/TR/SVG11/coords.html#ObjectBoundingBoxUnits (the last paragraph)
|
||||
//a stroke width should be ignored for bounding box calculations
|
||||
static Box _boundingBox(const Shape* shape)
|
||||
static Box _boundingBox(Paint* shape)
|
||||
{
|
||||
float x, y, w, h;
|
||||
shape->bounds(&x, &y, &w, &h, false);
|
||||
|
||||
if (auto strokeW = shape->strokeWidth()) {
|
||||
x += 0.5f * strokeW;
|
||||
y += 0.5f * strokeW;
|
||||
w -= strokeW;
|
||||
h -= strokeW;
|
||||
}
|
||||
|
||||
return {x, y, w, h};
|
||||
}
|
||||
|
||||
|
||||
static Box _boundingBox(const Text* text)
|
||||
{
|
||||
float x, y, w, h;
|
||||
text->bounds(&x, &y, &w, &h, false);
|
||||
PAINT(shape)->bounds(&x, &y, &w, &h, false);
|
||||
return {x, y, w, h};
|
||||
}
|
||||
|
||||
|
@ -260,7 +244,7 @@ static Matrix _compositionTransform(Paint* paint, const SvgNode* node, const Svg
|
|||
}
|
||||
if (!compNode->node.clip.userSpace) {
|
||||
float x, y, w, h;
|
||||
PAINT(paint)->bounds(&x, &y, &w, &h, false, false);
|
||||
PAINT(paint)->bounds(&x, &y, &w, &h, false);
|
||||
m *= {w, 0, x, 0, h, y, 0, 0, 1};
|
||||
}
|
||||
return m;
|
||||
|
@ -346,7 +330,7 @@ static Paint* _applyFilter(SvgLoaderData& loaderData, Paint* paint, const SvgNod
|
|||
auto scene = Scene::gen();
|
||||
|
||||
Box bbox{};
|
||||
paint->bounds(&bbox.x, &bbox.y, &bbox.w, &bbox.h, false);
|
||||
paint->bounds(&bbox.x, &bbox.y, &bbox.w, &bbox.h);
|
||||
Box clipBox = filter.filterUserSpace ? filter.box : Box{bbox.x + filter.box.x * bbox.w, bbox.y + filter.box.y * bbox.h, filter.box.w * bbox.w, filter.box.h * bbox.h};
|
||||
auto primitiveUserSpace = filter.primitiveUserSpace;
|
||||
auto sx = paint->transform().e11;
|
||||
|
@ -943,13 +927,13 @@ static Scene* _sceneBuildHelper(SvgLoaderData& loaderData, const SvgNode* node,
|
|||
}
|
||||
|
||||
|
||||
static void _updateInvalidViewSize(const Scene* scene, Box& vBox, float& w, float& h, SvgViewFlag viewFlag)
|
||||
static void _updateInvalidViewSize(Scene* scene, Box& vBox, float& w, float& h, SvgViewFlag viewFlag)
|
||||
{
|
||||
bool validWidth = (viewFlag & SvgViewFlag::Width);
|
||||
bool validHeight = (viewFlag & SvgViewFlag::Height);
|
||||
|
||||
float x, y;
|
||||
scene->bounds(&x, &y, &vBox.w, &vBox.h, false);
|
||||
scene->bounds(&x, &y, &vBox.w, &vBox.h);
|
||||
if (!validWidth && !validHeight) {
|
||||
vBox.x = x;
|
||||
vBox.y = y;
|
||||
|
|
|
@ -277,48 +277,41 @@ RenderData Paint::Impl::update(RenderMethod* renderer, const Matrix& pm, Array<R
|
|||
}
|
||||
|
||||
|
||||
bool Paint::Impl::bounds(float* x, float* y, float* w, float* h, bool transformed, bool stroking, bool origin)
|
||||
bool Paint::Impl::bounds(float* x, float* y, float* w, float* h, bool stroking)
|
||||
{
|
||||
Point pts[4];
|
||||
if (!bounds(pts, false, stroking, false)) return false;
|
||||
|
||||
Point min = {FLT_MAX, FLT_MAX};
|
||||
Point max = {-FLT_MAX, -FLT_MAX};
|
||||
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
if (pts[i].x < min.x) min.x = pts[i].x;
|
||||
if (pts[i].x > max.x) max.x = pts[i].x;
|
||||
if (pts[i].y < min.y) min.y = pts[i].y;
|
||||
if (pts[i].y > max.y) max.y = pts[i].y;
|
||||
}
|
||||
|
||||
if (x) *x = min.x;
|
||||
if (y) *y = min.y;
|
||||
if (w) *w = max.x - min.x;
|
||||
if (h) *h = max.y - min.y;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool Paint::Impl::bounds(Point* pt4, bool transformed, bool stroking, bool origin)
|
||||
{
|
||||
bool ret;
|
||||
PAINT_METHOD(ret, bounds(pt4, stroking));
|
||||
|
||||
if (!ret || !transformed) return ret;
|
||||
|
||||
const auto& m = this->transform(origin);
|
||||
|
||||
//Case: No transformed, quick return!
|
||||
if (!transformed || identity(&m)) {
|
||||
PAINT_METHOD(ret, bounds(x, y, w, h, stroking));
|
||||
return ret;
|
||||
}
|
||||
|
||||
//Case: Transformed
|
||||
auto tx = 0.0f;
|
||||
auto ty = 0.0f;
|
||||
auto tw = 0.0f;
|
||||
auto th = 0.0f;
|
||||
|
||||
PAINT_METHOD(ret, bounds(&tx, &ty, &tw, &th, stroking));
|
||||
|
||||
//Get vertices
|
||||
Point pt[4] = {{tx, ty}, {tx + tw, ty}, {tx + tw, ty + th}, {tx, ty + th}};
|
||||
|
||||
//New bounding box
|
||||
auto x1 = FLT_MAX;
|
||||
auto y1 = FLT_MAX;
|
||||
auto x2 = -FLT_MAX;
|
||||
auto y2 = -FLT_MAX;
|
||||
|
||||
//Compute the AABB after transformation
|
||||
for (int i = 0; i < 4; i++) {
|
||||
pt[i] *= m;
|
||||
|
||||
if (pt[i].x < x1) x1 = pt[i].x;
|
||||
if (pt[i].x > x2) x2 = pt[i].x;
|
||||
if (pt[i].y < y1) y1 = pt[i].y;
|
||||
if (pt[i].y > y2) y2 = pt[i].y;
|
||||
}
|
||||
|
||||
if (x) *x = x1;
|
||||
if (y) *y = y1;
|
||||
if (w) *w = x2 - x1;
|
||||
if (h) *h = y2 - y1;
|
||||
pt4[0] *= m;
|
||||
pt4[1] *= m;
|
||||
pt4[2] *= m;
|
||||
pt4[3] *= m;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -373,9 +366,17 @@ Matrix& Paint::transform() noexcept
|
|||
}
|
||||
|
||||
|
||||
Result Paint::bounds(float* x, float* y, float* w, float* h, bool transformed) const noexcept
|
||||
Result Paint::bounds(float* x, float* y, float* w, float* h) const noexcept
|
||||
{
|
||||
if (pImpl->bounds(x, y, w, h, transformed, true, transformed)) return Result::Success;
|
||||
if (pImpl->bounds(x, y, w, h, true)) return Result::Success;
|
||||
return Result::InsufficientCondition;
|
||||
}
|
||||
|
||||
|
||||
Result Paint::bounds(Point* pt4) const noexcept
|
||||
{
|
||||
if (!pt4) return Result::InvalidArguments;
|
||||
if (pImpl->bounds(pt4, true, true, true)) return Result::Success;
|
||||
return Result::InsufficientCondition;
|
||||
}
|
||||
|
||||
|
|
|
@ -256,7 +256,8 @@ namespace tvg
|
|||
|
||||
RenderRegion bounds(RenderMethod* renderer) const;
|
||||
Iterator* iterator();
|
||||
bool bounds(float* x, float* y, float* w, float* h, bool transformed, bool stroking, bool origin = false);
|
||||
bool bounds(float* x, float* y, float* w, float* h, bool stroking);
|
||||
bool bounds(Point* pt4, bool transformed, bool stroking, bool origin = false);
|
||||
RenderData update(RenderMethod* renderer, const Matrix& pm, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag pFlag, bool clipper = false);
|
||||
bool render(RenderMethod* renderer);
|
||||
Paint* duplicate(Paint* ret = nullptr);
|
||||
|
|
|
@ -114,13 +114,12 @@ struct Picture::Impl : Paint::Impl
|
|||
return Result::Success;
|
||||
}
|
||||
|
||||
|
||||
bool bounds(float* x, float* y, float* w, float* h, bool stroking)
|
||||
bool bounds(Point* pt4, bool stroking)
|
||||
{
|
||||
if (x) *x = 0;
|
||||
if (y) *y = 0;
|
||||
if (w) *w = this->w;
|
||||
if (h) *h = this->h;
|
||||
pt4[0] = {0.0f, 0.0f};
|
||||
pt4[1] = {w, 0.0f};
|
||||
pt4[2] = {w, h};
|
||||
pt4[3] = {0.0f, h};
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -194,34 +194,28 @@ struct Scene::Impl : Paint::Impl
|
|||
return ret;
|
||||
}
|
||||
|
||||
bool bounds(float* px, float* py, float* pw, float* ph, bool stroking)
|
||||
bool bounds(Point* pt4, bool stroking)
|
||||
{
|
||||
if (paints.empty()) return false;
|
||||
|
||||
auto x1 = FLT_MAX;
|
||||
auto y1 = FLT_MAX;
|
||||
auto x2 = -FLT_MAX;
|
||||
auto y2 = -FLT_MAX;
|
||||
Point min = {FLT_MAX, FLT_MAX};
|
||||
Point max = {-FLT_MAX, -FLT_MAX};
|
||||
|
||||
for (auto paint : paints) {
|
||||
auto x = FLT_MAX;
|
||||
auto y = FLT_MAX;
|
||||
auto w = 0.0f;
|
||||
auto h = 0.0f;
|
||||
|
||||
if (!PAINT(paint)->bounds(&x, &y, &w, &h, true, stroking)) continue;
|
||||
|
||||
Point tmp[4];
|
||||
if (!PAINT(paint)->bounds(tmp, true, stroking)) continue;
|
||||
//Merge regions
|
||||
if (x < x1) x1 = x;
|
||||
if (x2 < x + w) x2 = (x + w);
|
||||
if (y < y1) y1 = y;
|
||||
if (y2 < y + h) y2 = (y + h);
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
if (tmp[i].x < min.x) min.x = tmp[i].x;
|
||||
if (tmp[i].x > max.x) max.x = tmp[i].x;
|
||||
if (tmp[i].y < min.y) min.y = tmp[i].y;
|
||||
if (tmp[i].y > max.y) max.y = tmp[i].y;
|
||||
}
|
||||
}
|
||||
|
||||
if (px) *px = x1;
|
||||
if (py) *py = y1;
|
||||
if (pw) *pw = (x2 - x1);
|
||||
if (ph) *ph = (y2 - y1);
|
||||
pt4[0] = min;
|
||||
pt4[1] = {max.x, min.y};
|
||||
pt4[2] = max;
|
||||
pt4[3] = {min.x, max.y};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -116,17 +116,24 @@ struct Shape::Impl : Paint::Impl
|
|||
return renderer->region(rd);
|
||||
}
|
||||
|
||||
bool bounds(float* x, float* y, float* w, float* h, bool stroking)
|
||||
bool bounds(Point* pt4, bool stroking)
|
||||
{
|
||||
if (!rs.path.bounds(x, y, w, h)) return false;
|
||||
float x, y, w, h;
|
||||
if (!rs.path.bounds(&x, &y, &w, &h)) return false;
|
||||
|
||||
//Stroke feathering
|
||||
if (stroking && rs.stroke) {
|
||||
if (x) *x -= rs.stroke->width * 0.5f;
|
||||
if (y) *y -= rs.stroke->width * 0.5f;
|
||||
if (w) *w += rs.stroke->width;
|
||||
if (h) *h += rs.stroke->width;
|
||||
x -= rs.stroke->width * 0.5f;
|
||||
y -= rs.stroke->width * 0.5f;
|
||||
w += rs.stroke->width;
|
||||
h += rs.stroke->width;
|
||||
}
|
||||
|
||||
pt4[0] = {x, y};
|
||||
pt4[1] = {x + w, y};
|
||||
pt4[2] = {x + w, y + h};
|
||||
pt4[3] = {x, y + h};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -134,10 +134,10 @@ struct Text::Impl : Paint::Impl
|
|||
return PAINT(shape)->update(renderer, transform, clips, opacity, pFlag, false);
|
||||
}
|
||||
|
||||
bool bounds(float* x, float* y, float* w, float* h, TVG_UNUSED bool stroking)
|
||||
bool bounds(Point* pt4, TVG_UNUSED bool stroking)
|
||||
{
|
||||
if (!load()) return false;
|
||||
PAINT(shape)->bounds(x, y, w, h, true, true, false);
|
||||
PAINT(shape)->bounds(pt4, true, true, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -124,7 +124,7 @@ bool GifSaver::save(Animation* animation, Paint* bg, const char* filename, TVG_U
|
|||
auto picture = animation->picture();
|
||||
float x, y;
|
||||
x = y = 0;
|
||||
picture->bounds(&x, &y, &vsize[0], &vsize[1], false);
|
||||
picture->bounds(&x, &y, &vsize[0], &vsize[1]);
|
||||
|
||||
//cut off the negative space
|
||||
if (x < 0) vsize[0] += x;
|
||||
|
|
|
@ -127,23 +127,28 @@ TEST_CASE("Bounding Box", "[tvgPaint]")
|
|||
|
||||
//Negative
|
||||
float x = 0, y = 0, w = 0, h = 0;
|
||||
REQUIRE(shape->bounds(&x, &y, &w, &h, false) == Result::InsufficientCondition);
|
||||
REQUIRE(shape->bounds(&x, &y, &w, &h) == Result::InsufficientCondition);
|
||||
|
||||
//Case 1
|
||||
REQUIRE(shape->appendRect(0.0f, 10.0f, 20.0f, 100.0f, 50.0f, 50.0f) == Result::Success);
|
||||
REQUIRE(shape->translate(100.0f, 111.0f) == Result::Success);
|
||||
REQUIRE(shape->bounds(&x, &y, &w, &h, false) == Result::Success);
|
||||
REQUIRE(shape->bounds(&x, &y, &w, &h) == Result::Success);
|
||||
REQUIRE(x == 0.0f);
|
||||
REQUIRE(y == 10.0f);
|
||||
REQUIRE(w == 20.0f);
|
||||
REQUIRE(h == 100.0f);
|
||||
|
||||
REQUIRE(canvas->update(shape) == Result::Success);
|
||||
REQUIRE(shape->bounds(&x, &y, &w, &h, true) == Result::Success);
|
||||
REQUIRE(x == 100.0f);
|
||||
REQUIRE(y == 121.0f);
|
||||
REQUIRE(w == 20.0f);
|
||||
REQUIRE(h == 100.0f);
|
||||
Point pts[4];
|
||||
REQUIRE(shape->bounds(pts) == Result::Success);
|
||||
REQUIRE(pts[0].x == 100.0f);
|
||||
REQUIRE(pts[3].x == 100.0f);
|
||||
REQUIRE(pts[0].y == 121.0f);
|
||||
REQUIRE(pts[1].y == 121.0f);
|
||||
REQUIRE(pts[1].x == 120.0f);
|
||||
REQUIRE(pts[2].x == 120.0f);
|
||||
REQUIRE(pts[2].y == 221.0f);
|
||||
REQUIRE(pts[3].y == 221.0f);
|
||||
|
||||
//Case 2
|
||||
REQUIRE(shape->reset() == Result::Success);
|
||||
|
@ -151,18 +156,22 @@ TEST_CASE("Bounding Box", "[tvgPaint]")
|
|||
REQUIRE(shape->lineTo(20.0f, 210.0f) == Result::Success);
|
||||
auto identity = Matrix{1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f};
|
||||
REQUIRE(shape->transform(identity) == Result::Success);
|
||||
REQUIRE(shape->bounds(&x, &y, &w, &h, false) == Result::Success);
|
||||
REQUIRE(shape->bounds(&x, &y, &w, &h) == Result::Success);
|
||||
REQUIRE(x == 0.0f);
|
||||
REQUIRE(y == 10.0f);
|
||||
REQUIRE(w == 20.0f);
|
||||
REQUIRE(h == 200.0f);
|
||||
|
||||
REQUIRE(canvas->update(shape) == Result::Success);
|
||||
REQUIRE(shape->bounds(&x, &y, &w, &h, true) == Result::Success);
|
||||
REQUIRE(x == 0.0f);
|
||||
REQUIRE(y == 10.0f);
|
||||
REQUIRE(w == 20.0f);
|
||||
REQUIRE(h == 200.0f);
|
||||
REQUIRE(shape->bounds(pts) == Result::Success);
|
||||
REQUIRE(pts[0].x == 0.0f);
|
||||
REQUIRE(pts[3].x == 0.0f);
|
||||
REQUIRE(pts[0].y == 10.0f);
|
||||
REQUIRE(pts[1].y == 10.0f);
|
||||
REQUIRE(pts[1].x == 20.0f);
|
||||
REQUIRE(pts[2].x == 20.0f);
|
||||
REQUIRE(pts[2].y == 210.0f);
|
||||
REQUIRE(pts[3].y == 210.0f);
|
||||
|
||||
Initializer::term();
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue