【问题标题】:How to calculate the sizes of a rectangle that contains rotated image (potentially with transparent pixels)如何计算包含旋转图像的矩形的大小(可能带有透明像素)
【发布时间】:2021-01-03 19:55:21
【问题描述】:

给定旋转图像的theta 弧度角、widthheight,如何计算包含旋转图像的外部矩形的新宽度和高度?

换句话说,我如何计算新的绑定框宽度/高度? 请注意,图像实际上可能是圆形的,并且边缘有透明像素。

那就是:x1,y1。

我实际上正在使用cairo_rotate() 旋转一个以原点为中心的pixbuf,我需要知道新分配的区域。我尝试的是这样的:

double geo_rotated_rectangle_get_width (double a, double b, double theta)
{
    return abs(a*cos(theta)) + abs(b*sin(theta));
}

它总是返回足够的空间来容纳旋转的图像,但是当图像没有以 90o 的倍数旋转并且是完全不透明的图像(a方)。


编辑: 这是我正在旋转的图像:

有趣的是,我刚刚尝试使用相同大小的完全不透明图像,结果没问题。我使用gdk_pixbuf_get_width() 来获取宽度,无论如何它都会返回相同的值。所以我假设公式是正确的,问题是没有考虑透明度。当以对角线方向旋转时,旋转图像的矩形边缘是透明的。


我将保留以上内容,以便对其他人有所帮助:) 现在问题变成了如何计算边缘上的透明像素

【问题讨论】:

标签: c geometry rotation rectangles cairo


【解决方案1】:

要确定旋转矩形的bbox,可以计算4个顶点的坐标,取这4个点的bbox。

  • a 是未旋转矩形的宽度,b 是它的高度;

  • diag = sqrt(a * a + b * b) / 2这个矩形的中心到右上角的距离。您可以使用diag = hypot(a, b) / 2 以获得更好的精度;

  • 首先计算theta=0的第一条对角线的角度theta0theta0 = atan(b / a)或更好的theta0 = atan2(b, a)

  • 这4个顶点是:

    • { diag * cos(theta0 + theta), diag * sin(theta0 + theta) }
    • { diag * cos(pi - theta0 + theta), diag * sin(pi - theta0 + theta) }
    • { diag * cos(pi + theta0 + theta), diag * sin(pi + theta0 + theta) }
    • { diag * cos(-theta0 + theta), diag * sin(-theta0 + theta) }
  • 可以简化为:

    • { diag * cos(theta + theta0), diag * sin(theta + theta0) }
    • { -diag * cos(theta - theta0), -diag * sin(theta - theta0) }
    • { -diag * cos(theta + theta0), -diag * sin(theta + theta0) }
    • { diag * cos(theta - theta0), diag * sin(theta - theta0) }
  • 给出x1y1

    • x1 = diag * fmax(fabs(cos(theta + theta0)), fabs(cos(theta - theta0))
    • y1 = diag * fmax(fabs(sin(theta + theta0)), fabs(sin(theta - theta0))
  • 旋转矩形的widthheight 如下:

    • width = 2 * diag * fmax(fabs(cos(theta + theta0)), fabs(cos(theta - theta0))
    • height = 2 * diag * fmax(fabs(sin(theta + theta0)), fabs(sin(theta - theta0))

这是几何解决方案,但您必须考虑图形基元执行的舍入,因此最好使用图形 API 并使用 gdk_pixbuf_get_width()gdk_pixbuf_get_height() 检索 pixbuf 尺寸,这将允许用于精确放置。

【讨论】:

  • 赞成,有用的补充。但是,我担心我的编辑会使我的具体问题变得松散,但这没关系。我最初使用术语正方形,因为最终这就是 pixbuf 的含义,但是由于某些 pixbuf 实际上是复杂的图形并且具有透明度并且绑定框应该考虑到它们,所以出现了问题。
  • 试过了,它也有效(我不得不使用fabs)... :)
  • 如果您认为它有用并且您知道有一种方法可以解决此问题 - 添加如何考虑不应完全不透明矩形的图像边缘。
  • @Edenia:确实应该使用fabs(),也应该使用fmax()
  • @Edenia:对于部分透明的图像,没有灵丹妙药,你必须分析旋转的位图以确定实际图像的实际尺寸。对于问题中的示例,图像似乎接近圆盘,因此鸟头的尺寸不受旋转影响。
【解决方案2】:

我会说“让 cairo 计算这些坐标”。如果您有权访问cairo_t*,则可以执行以下操作(未经测试!):

double x1, y1, x2, y2;
cairo_save(cr);
cairo_rotate(cr, theta); // You can also do cairo_translate() and whatever your heart desires
cairo_new_path(cr);
cairo_rectangle(cr, x, y, width, height);
cairo_restore(cr); // Note: This preserved the path!
cairo_fill_extents(cr, &x1, &y1, &x2, &y2);
cairo_new_path(cr); // Clean up after ourselves
printf("Rectangle is inside of (%g,%g) to (%g,%g) (size %g,%g)\n",
    x1, y1, x2, y2, x2 - x1, y2 - y1);

上面的代码应用了一些转换,然后构造了一个路径。这使得 cairo 将变换应用于给定的坐标。之后,转换被cairo_restore()“抛弃”。接下来,我们向 cairo 询问当前路径所覆盖的区域,它在当前坐标系中提供,即没有变换。

【讨论】:

  • 这是否考虑了透明像素?
  • 没有。它只查看矩形的范围。我认为开罗没有任何东西可以为您提供有关透明像素的信息。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-23
  • 2011-08-12
  • 2011-02-03
  • 1970-01-01
相关资源
最近更新 更多