如何缩小块而不会导致像素重叠

时间:2011-09-23 16:19:26

标签: c++ math floating-point scale pixel

我有一堆需要绘制到网格中的块。现在显示它们未缩放的一切都很好但是当我尝试将它们缩小以适应窗口时,我得到“缩放伪像”,因为我使用了正常的缩放比例公式并浮动。

有没有办法避免这些问题?

常见示例数据:

Original length: 200000

缩小到25x25 pixel grid(这对于开发和调试而言很小) 按比例缩小的最大长度:625(25 * 25)

Scale-ratio: (625 / 200000) = 0,003125

示例数据1 - 重叠,缩放的块互相覆盖 阻止开始=>块结束:[开始,结束]

1: 2100 => 2800
2: 2800 => 3600
3: 3600 => 4500
4: 4500 => 5500

跳过显示此示例的输出,因为我认为示例2和3将得到重点。保持完整性。

示例数据2 - 2到3之间的空格不正确 阻止开始=>块结束:[开始,结束]

1: 960 => 1440
2: 1440 => 1920
3: 1920 => 2400

1: 960 => 1440, length: 480, scaled length: 1.5:
2: 1440 => 1920, length: 480, scaled length: 1.5:
3: 1920 => 2400, length: 480, scaled length: 1.5:

像素开始,结束,长度

1: 3, 0, 1
2: 4, 0, 1
3: 6, 0, 1

显示网格:

[ 0, 0, 0, 1, 2, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
...

示例数据3 - 1向后移动错误 阻止开始=>块结束:[开始,结束]

1: 896 => 1344
2: 1344 => 1792
3: 1792 => 2240

1: 896 => 1344, length: 448, scaled length: 1.4:
2: 1344 => 1792, length: 448, scaled length: 1.4:
3: 1792 => 2240, length: 448, scaled length: 1.4:

像素开始,结束,长度

1: 2, 0, 1
2: 4, 0, 1
3: 5, 0, 1

显示网格:

[ 0, 0, 1, 0, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
...

数据2和3的示例应如下所示:

[ 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
...

请记住,块值为[start,end)

抢先罢工(选民/控制者)记住:我不是通灵者或心灵读者。如果你想以一种紧缩的方式给予否定,或者它是无用的(我将不会学到任何东西)并且只会污染线程。

更新

#include <iostream>
#include <math.h>
#include <limits.h>
#include <assert.h>
#include <vector>
#include <array>
#include <utility> // pair
#include <algorithm> // for_each

using namespace std;

const size_t width_size = 25; // 25 pixels
const size_t height_size = 25; // 25 pixels
const size_t grid_length = width_size * height_size; // width * height
array<size_t, grid_length> grid;

const size_t original_length = 200000;

typedef pair<unsigned long, unsigned long> block;
vector<block> test_values;

void show_grid()
{
    for (size_t y = 0; y < height_size; ++y) {
        const size_t start_pos_for_current_heigth = y * width_size;
        const size_t end_pos_for_current_heigth = start_pos_for_current_heigth + width_size;

        cout << "[ ";
        for (size_t i = start_pos_for_current_heigth; i < end_pos_for_current_heigth; ++i) {
            if (i + 1 < end_pos_for_current_heigth)
                cout << grid[i] << ", ";
            else
                cout << grid[i];
        };
        cout << " ]" << endl;
    }
}

void scale_and_add(const float scale)
{
    size_t test_value_id = 1;

    for_each(test_values.cbegin(), test_values.cend(), [&](const block &p) {
        const float s_f = p.first * scale;
        const unsigned long s = round(s_f);
        const float e_f = p.second * scale;
        const unsigned long e = round(e_f);
        const unsigned long block_length = p.second - p.first;
        const float block_length_scaled = block_length * scale;
        assert(s <= grid_length);
        assert(e <= grid_length);

        cout << test_value_id << ":" << endl;
        cout << " " << p.first << " => " << p.second << " length: " << block_length << endl;
        cout << " " << s << " (" << s_f << ") => " << e << " (" << e_f << ") length: " << (e - s) << " (" << block_length_scaled << ")" << " (scaled)" << endl;

        for (size_t i = s; i < e; ++i) {
            if (grid[i] != 0) {
                cout << "overlapp detected !" << endl;
            }
            grid[i] = test_value_id;
        }

        ++test_value_id;
    });
}

void reset_common()
{
    grid.fill(0);
    test_values.clear();
}

int main()
{
    const float scale = ((float)grid_length / (float)original_length);
    cout << "scale: " << scale << " length per pixel: " << ((float)original_length / (float)grid_length) << endl;

    // Example data 1
/*    cout << "Example data 1" << endl;

    test_values.push_back(make_pair(2100, 2800));
    test_values.push_back(make_pair(2800, 3600));
    test_values.push_back(make_pair(3600, 4500));
    test_values.push_back(make_pair(4500, 5500));

    scale_and_add(scale);
    show_grid();

    reset_common();

    // Example data 2
    cout << "Example data 2" << endl;

    test_values.push_back(make_pair(960, 1440));
    test_values.push_back(make_pair(1440, 1920));
    test_values.push_back(make_pair(1920, 2400));

    scale_and_add(scale);
    show_grid();

    reset_common();

    // Example data 3
    cout << endl << "Example data 3" << endl;

    test_values.push_back(make_pair(896, 1344));
    test_values.push_back(make_pair(1344, 1792));
    test_values.push_back(make_pair(1792, 2240));

    scale_and_add(scale);
    show_grid();

    reset_common();*/

    // Generated data - to quickly find the problem
    cout << "Generated data" << endl;

    auto to_op = [&](const size_t v) {
        return v * (original_length / grid_length) * 1.3; // 1.4 and 1.5 are also good values to show the problem
    };
    size_t pos = 0;
    size_t psize = 1; // Note this value (length) and check it with the displayed one, you'll be surprised !
    for (size_t g = 0; g < 10; ++g) {
        test_values.push_back(make_pair(to_op(pos), to_op(pos + psize)));
        pos += psize;
    }

    scale_and_add(scale);
    show_grid();

    return 0;
}

输出:

scale: 0.003125 length per pixel: 320
    Generated data
1:
 0 => 416 length: 416
 0 (0) => 1 (1.3) length: 1 (1.3) (scaled)
2:
 416 => 832 length: 416
 1 (1.3) => 3 (2.6) length: 2 (1.3) (scaled)
3:
 832 => 1248 length: 416
 3 (2.6) => 4 (3.9) length: 1 (1.3) (scaled)
4:
 1248 => 1664 length: 416
 4 (3.9) => 5 (5.2) length: 1 (1.3) (scaled)
5:
 1664 => 2080 length: 416
 5 (5.2) => 7 (6.5) length: 2 (1.3) (scaled)
6:
 2080 => 2496 length: 416
 7 (6.5) => 8 (7.8) length: 1 (1.3) (scaled)
7:
 2496 => 2912 length: 416
 8 (7.8) => 9 (9.1) length: 1 (1.3) (scaled)
8:
 2912 => 3328 length: 416
 9 (9.1) => 10 (10.4) length: 1 (1.3) (scaled)
9:
 3328 => 3744 length: 416
 10 (10.4) => 12 (11.7) length: 2 (1.3) (scaled)
10:
 3744 => 4160 length: 416
 12 (11.7) => 13 (13) length: 1 (1.3) (scaled)
[ 1, 2, 2, 3, 4, 5, 5, 6, 7, 8, 9, 9, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]

此代码示例更清楚地演示了我的问题。

有趣的事实:我曾经写过这个例子的mingw-g ++显示了稍微不同的值。我通常使用visual studio 2010,但这次不能,因为我不在家。

2 个答案:

答案 0 :(得分:0)

是啊+1让你回来,问题还可以。 我不知道为什么人们甚至在没有发表评论的情况下进行投票也是如此有趣。

那么问题: - )

通常在绘图时你会遇到这些重叠的问题,并且在3D计算机图形学中使用扫描线渲染器(例如DirectX和OpenGL),它们通常只跳过一个像素(比如右侧和下侧)。 也许这可以帮到你。

当划分完美时,你也可能没有人工制品,所以你必须处理它(例如,如果值是一个完整的整数,例如, 185.000000然后不删除最后一个像素。)

HTH

答案 1 :(得分:0)

我不确定我是否收到了问题陈述,但我会抓住它。您有条件显示的信息范围通常是[a,b)。当a和b直接表示您想要绘制的像素时,一切都很好,但是当您想要缩放整个事物时,您遇到了问题。

不处理多行像素,如果你有两个范围R1 = [a,b)和R2 = [b,c)未缩放,你只需从a到b-1和从b到c-1和你的范围被绘制,因此在缩放的情况下从(int)(a * scale)到((int)(b * scale)-1)然后从(int)(b * scale)到((int)的问题是什么问题)(c * scale)-1),你可以使用任何浮动到int转换,圆角,地板或天花板,你应该没问题。

下一个问题区域是,如果您的比例范围小于1个像素,在这种情况下,您可能需要检测缩放范围的大小是否为0并且带有在时添加的校正因子(以像素为单位)计算结束。

伪代码

DrawRanges(List<Range> ranges, float scale)
  int carry = 0;
  foreach(Range range in ranges)
  {
      int newStart = ceiling(range.start*scale);
      int newEnd = ceiling(range.end*scale)-1;

      if (newStart <= newEnd)
      {
        newEnd = newStart;
        ++carry;
      }
      DrawRange(newStart+carry,newEnd+carry);
  }

如果缩小网格中的范围多于块,则最终会失败,您必须弄清楚如何完全放弃范围。在绘制范围内,您可以将索引映射到实际的块坐标。

这可以解决您的问题吗?