confused with bytes, blocks, en-/decoding in c++ - c++

I have a 64-byte block and want to append a 64 Bit (8 Byte) Block of data at the end.
typedef unsigned char uint1; // 1 Byte
typedef unsigned int uint4; // 4 Byte
// The 64 Byte-Block:
int BLOCKSIZE=64;
static uint1 padding[BLOCKSIZE] = {
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
// [[10000000][00000000].........[00000000]]
// The 64 Bit (8 Byte-Block):
uint4 appendix[2] = {};
appendix[1] = 0x000000ff;
// [[00000000000000000000000000000000][00000000000000000000000011111111]]
after memcpy 8 bytes from appendix to the last 8 byte of padding
memcpy(&padding[56], &appendix, 8);
it looks like
static uint1 padding[BLOCKSIZE] = {
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0, 0, 0, 0
};
but shouldn't it look like this?
static uint1 padding[BLOCKSIZE] = {
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff
};
I don't know whats wrong here!?!?
Can you help me?

appendix[1] = 0x000000ff;
// [[00000000000000000000000000000000][00000000000000000000000011111111]]
You're making assumptions about the byte order (endianness). You can't make such assumptions. Depending on byte-order of the architechture, appendix could alternatively be represented like this:
// [[00000000000000000000000000000000][11111111000000000000000000000000]]
If you want to set the last byte specifically, then you need to operate on bytes, not multi-byte integers. Like this for example:
uint1 appendix[8] = {};
appendix[7] = 0xff;
If you indeed need the last 8 bytes to represent two 4 byte integers, your code is correct in that regard and only your assumption about what the memory should look like is wrong.
If the integer must be in a particular byte order for sending it over network, then you must convert it appropriately. POSIX provides htonl and it's sister functions for exactly that. The functions are also provided by msvc.
You're also making the assumption that unsigned int is 4 bytes. It's not guaranteed to be. Use int32_t instead if you need a 4 byte integer.
Update:
My Goal is to implement MD5 and I need to append a 64 bit representation of the length of a file.
According to rfc1321:
... a sequence of
bytes can be interpreted as a sequence of 32-bit words, where each
consecutive group of four bytes is interpreted as a word with the
low-order (least significant) byte given first.
MD5 is little endian. Therefore writing a 2*4 array without converting the byte order will work correctly only on a little endian processor.
I recommend using a 8*1 byte-array so that you can control the order of the bytes exactly as the specification requires. Alternatively, if you're on linux or another platform that provides them, you could use htole32 and le32toh functions to convert to the correct byte order. On another platform you may need to implement them yourself.

So, as far as I'm able to understand the RFC1321 I need a 64 Bit Integer representation of the original message (file) size. The file size is 64 Byte. In a 64 Bit Integer the value 64 is in binary either:
0000000000000000000000000000000000000000000000000000000001000000
or:
0000001000000000000000000000000000000000000000000000000000000000
I have decoding funcitons for both, but i don't know which is right for md5 ?

You should look at Endianless. Your option is big-endian here.

Related

Reverse an array with preprocessor

I want to use pre-processor to fill some arrays in some ways. I can use preprocessor only for newly declared arrays. However, I need to change the array p which I declared and used before. Time optimization is very important for my purpose.
#define Reverse(x) {x[63], x[62], x[61], x[60], x[59], x[58], x[57], x[56], x[55], x[54], x[53], x[52], x[51], x[50], x[49], x[48], x[47], x[46], x[45], x[44], x[43], x[42], x[41], x[40], x[39], x[38], x[37], x[36], x[35], x[34], x[33], x[32], x[31], x[30], x[29], x[28], x[27], x[26], x[25], x[24], x[23], x[22], x[21], x[20], x[19], x[18], x[17], x[16], x[15], x[14], x[13], x[12], x[11], x[10], x[9], x[8], x[7], x[6], x[5], x[4], x[3], x[2], x[1], x[0] }
int main()
{
int p[64] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
int q[64] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
//doThings
p= Reverse(q); // line A - Gives error
int s[64] = Reverse(q); // line B - Works properly
//doThings
}
I got this error:
Error 11 error C3079: an initializer-list cannot be used as the right operand of this assignment operator c:\users\ferda\documents\visual studio 2013\projects\consoleapplication3\consoleapplication3\consoleapplication3.cpp 39‌​3 1 ConsoleApplication3
Built in array type does not allow to assign to it another array or use aggregate initialization on already initialized array, you would have to use memcpy or for loop to update it with new values. Your code will compile if you use std::array instead. It provides operator=:
operator= (implicitly declared) overwrites every element of the
array with the corresponding element of another array (public member
function)
http://coliru.stacked-crooked.com/a/8e664210b7f7f73b
i am not sure if this will work as fast as you expect, gcc will generate lots of mov instructions : https://godbolt.org/g/tzUqC3. I suppose it might be faster to use a for loop which will require less cache memory. As always profile your code.

Use uniform buffer of uvec3[]

I have the following uniform buffer:
uniform EDGE_ID_TO_START_POS{
uint[12*3] pos;
} edgeIdToStartPos;
Writing to this buffer works perfectly fine:
#define EDGE_ID_TO_START_POS_SIZE (12*3)
const uint32_t edgeIdToStartPos_constBuffer[EDGE_ID_TO_START_POS_SIZE] = {
/* 0*/ 0, 0, 0, /* 1*/ 0, 1, 0, /* 2*/ 1, 0, 0, /* 3*/ 0, 0, 0,
/* 4*/ 0, 0, 1, /* 5*/ 0, 1, 1, /* 6*/ 1, 0, 1, /* 7*/ 0, 0, 1,
/* 8*/ 0, 0, 0, /* 9*/ 0, 1, 0, /*10*/ 1, 1, 0, /*11*/ 1, 0, 0
};
glBindBuffer(GL_UNIFORM_BUFFER, ubo);
glBufferData(GL_UNIFORM_BUFFER, EDGE_ID_TO_START_POS_SIZE * sizeof(uint32_t), edgeIdToStartPos_constBuffer, GL_STATIC_DRAW);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
Now I want to change the uniform buffer to the following structure:
uniform EDGE_ID_TO_START_POS{
uvec3[12] pos;
} edgeIdToStartPos;
This structure makes more sense and is easier to use. And it should have the same memory layout than the previous version (?).
However, when reading from this struct, only the vectors 0..3 contain data. All uvecs with an index of 4 or higher contain zeros.
Why does this happen and how can I initialise such a uniform buffer correctly?
(C/C++, glew, glfw)
A uvec3 has an alignment of 16 bytes, so you must add padding. See OpenGL 4.5 spec, section 7.6.22:
If the member is a three-component vector with components consuming N basic machine units, the base alignment is 4N.
Here is how it would look:
static const int EDGE_ID_TO_START_POS_SIZE = 12 * 4;
const uint32_t edgeIdToStartPos_constBuffer[EDGE_ID_TO_START_POS_SIZE] = {
/* 0*/ 0, 0, 0, 0, /* 1*/ 0, 1, 0, 0, /* 2*/ 1, 0, 0, 0, /* 3*/ 0, 0, 0, 0,
/* 4*/ 0, 0, 1, 0, /* 5*/ 0, 1, 1, 0, /* 6*/ 1, 0, 1, 0, /* 7*/ 0, 0, 1, 0,
/* 8*/ 0, 0, 0, 0, /* 9*/ 0, 1, 0, 0, /*10*/ 1, 1, 0, 0, /*11*/ 1, 0, 0, 0,
};

Translating array pointer access from C++ to Delphi

I'd like to know if I translated a piece of code correctly from C++ to Delphi.
It looks like it is working, but I have a feeling that I'm reading and writing into memory that I'm not supposed to using Delphi.
Given C++ code:
struct tile_map
{
int32 CountX;
int32 CountY;
uint32 *Tiles;
};
inline uint32
GetTileValueUnchecked(tile_map *TileMap, int32 TileX, int32 TileY)
{
uint32 TileMapValue = TileMap->Tiles[TileY*TileMap->CountX + TileX];
return(TileMapValue);
}
uint32 Tiles00[9][17] =
{
{1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
};
// More tile map declarations ...
// uint32 Tiles01[9][17] = ...
// uint32 Tiles10[9][17] = ...
// uint32 Tiles11[9][17] = ...
tile_map TileMaps[2][2];
TileMaps[0][0].CountX = 17;
TileMaps[0][0].CountY = 9;
TileMaps[0][0].Tiles = (uint32 *)Tiles00;
TileMaps[0][1] = TileMaps[0][0];
TileMaps[0][1].Tiles = (uint32 *)Tiles01;
TileMaps[1][0] = TileMaps[0][0];
TileMaps[1][0].Tiles = (uint32 *)Tiles10;
TileMaps[1][1] = TileMaps[0][0];
TileMaps[1][1].Tiles = (uint32 *)Tiles11;
// Usage
int32 PlayerTileX = 2;
int32 PlayerTileY = 2;
uint32 TileMapValue = GetTileValueUnchecked(&TileMap[1][1], PlayerTileX, PlayerTileY);
Delphi translation:
program Project1;
{$APPTYPE CONSOLE}
type
Puint32 = ^uint32;
tile_map = record
CountX : int32;
CountY : int32;
Tiles : Puint32;
end;
Ptile_map = ^tile_map;
{$POINTERMATH ON}
function GetTileValueUnchecked(TileMap : Ptile_map; TileX, TileY : int32) : uint32; inline;
begin
result := TileMap^.Tiles[TileY * TileMap^.CountX + TileX];
end;
const //in the future these will be read from file, so const for now
Tiles00: array [0..8, 0..16] of uint32 =
(
(1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1),
(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1),
(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1),
(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1),
(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1),
(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1),
(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1),
(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1),
(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)
);
// More tile map declarations ...
//Tiles01: array [0..8, 0..16] of uint32 = ...
//Tiles10: array [0..8, 0..16] of uint32 = ...
//Tiles11: array [0..8, 0..16] of uint32 = ...
var
TileMaps : array [0..1, 0..1] of tile_map;
PlayerTileX, PlayerTileY : int32;
TileMapValue : uint32;
begin
TileMaps[0][0].CountX := 17;
TileMaps[0][0].CountY := 9;
TileMaps[0][0].Tiles := Addr(Tiles00);
TileMaps[0][1] := TileMaps[0][0];
TileMaps[0][1].Tiles := Addr(Tiles01);
TileMaps[1][0] := TileMaps[0][0];
TileMaps[1][0].Tiles := Addr(Tiles10);
TileMaps[1][1] := TileMaps[0][0];
TileMaps[1][1].Tiles := Addr(Tiles11);
// Usage
PlayerTileX := 2;
PlayerTileY := 2;
TileMapValue = GetTileValueUnchecked(#TileMaps[1][1], PlayerTileX, PlayerTileY);
end.
David Heffernan's comments has been helpful and others seem to agree that the code is correct, so I will mark this as answered.

Why is the size and values of this OpenCV Matrix incorrect?

I use the following function to return a weight matrix of values between 0 and 1 depending on how close to the center a particular matrix position is. Also after a threshold the values are all 1 (it is like plateau with the points closer to center having value 1 and points away from center after a threshold of distance linearly fall from 1 to 0 at the edges)?
cv::Mat2f getWeightsMatrix(int N, int M, float r){
cv::Mat2f weights = cv::Mat2f(N,M);
int i,j;
for(i=0;i<N;i++){
for(j=0;j<M;j++){
if(i<=floor(N*(1-r)/2)){
if(j<=floor(M*(1-r)/2)){
weights[i][j]=((float)(i/N-j/M)/(1-r));
}
else{
weights[i][j]=(2*(float)(i/N)/(1-r));
}
}
else if (i>=floor(N*(1+r)/2)){
if(j>=floor(M*(1+r)/2)){
weights[i][j]=(((float)((N-i)/N))-((float)((M-j)/M)))/(1-r);
}
else{
weights[i][j]=(2*(float)((N-i)/N)/(1-r));
}
}
else{
if(j<=floor(M*(1-r)/2)){
weights[i][j]=(2*(float)(j/M)/(1-r));
}
else if(j>=floor(M*(1+r)/2)){
weights[i][j]=(2*(float)((M-j)/M)/(1-r));
}
else{
weights[i][j]=1;
}
}
}
}
cout << weights << endl;
return weights;
}
Now my problem is that I am having some casting issues and only values 0 and 1 are being returned (no floats). Also my matrix size displayed by the cout is 20x10 when I call the function with N=10, M=10 and r=0.5.
Please helP!
EDIT: This is the output
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
Your matrix consists only if integers because when you do basic operations on integers, the results gets rounded automatically.
For example: when you write
weights[i][j]=((float)(i/N-j/M)/(1-r));
The result of i/N is rounded to a integer, j/M is also rounded to an integer, and finally, the division by (1-r) is also rounded. Your (float) cast is a good idea but it's applied too late.
You can do several things:
Cast inside elementary operations, for instance, float(i)/N instead of i/N
Use float numbers instead of integers: write 1.0 instead of 1
Use floats inside your loops and statements
For example:
for(float i = 0; i < N-0.5; i++) {
for(float j = 0; j < M-0.5; j++) {
if(i <= floor(N*(1.0-r)/2.0)) {
// ...
It's important you understand that because of floating point precision, a test such as i < N might or might not pass when float i = N. This is why I did a little trick by substracting 0.5 from your loop bounds N and M.

How to scale down blocks without causing pixel overlapping

I have a bunch of blocks that needs to be drawn into a grid. Now displaying them unscaled everything is fine but when I try to scale them down to fit withing a window I get "scale-artifacts" because I use a normal scale-ratio formula and floats.
Is there a way to avoid these problems ?
Common example data:
Original length: 200000
Scaled down to a 25x25 pixel grid (it's this small for development and debugging)
The scaled down max length: 625 (25 * 25)
Scale-ratio: (625 / 200000) = 0,003125
Example data 1 - overlapping, scaled blocks overwrite each other
Start of block => end of block: [start, end)
1: 2100 => 2800
2: 2800 => 3600
3: 3600 => 4500
4: 4500 => 5500
Jumping over showing the output of this example because I think example 2 and 3 will get the point across. Left it in for completeness.
Example data 2 - incorrect space between 2 and 3
Start of block => end of block: [start, end)
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:
pixel start, end, length
1: 3, 0, 1
2: 4, 0, 1
3: 6, 0, 1
Displayed grid:
[ 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 ]
...
Example data 3 - 1 moved a step back incorrectly
Start of block => end of block: [start, end)
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:
pixel start, end, length
1: 2, 0, 1
2: 4, 0, 1
3: 5, 0, 1
Displayed grid:
[ 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 ]
...
What example data 2 and 3 should have looked like:
[ 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 ]
...
Remember the block values are [start, end)
Preemptive strike (down-voters / trollers) Remember: I'm not psychic or a mind-reader. If you want to give negative do it in a constrictive way or it is useless (i will not learn anything) and will just pollute the thread.
Update
#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;
}
Output:
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 ]
This code example demonstrates my problem more clearly.
Interesting fact: mingw-g++, which i used to write this example, shows slightly different values. I usually use visual studio 2010 but couldn't this time because I'm not at home.
I am not sure if I am getting the problem statement but I will take a stab at it. You have ranges of information that you are displaying contigously a range is usually [a,b). Everything is fine when a and b directly represent the pixels that you are trying to draw, but you are having problems when you want to scale the whole thing.
Not dealing with multiple rows of pixels, if you have two ranges R1=[a,b) and R2=[b,c) unscaled you just draw from a to b-1 and from b to c-1 and your ranges are drawn so what is the problem in the scaled case drawing from (int)(a*scale) to ((int)(b*scale)-1) and then from (int)(b*scale) to ((int)(c*scale)-1), you can use any float to int conversion, rounding, floor or ceiling and you should be ok.
The next problem area would be if your scale ranges amount to less than 1 pixel, in this case you might need to detect if the size of the scaled range is 0 and carry a correction factor (in pixels) that is added at the end of the calculation.
Pseudocode
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);
}
This will eventually fail if you have more Ranges than blocks in your scaled down grid, you would have to figure out how to drop ranges completely. In draw rang you map your index to an actual block coordinate.
Does this solve your problem ?
Yeah +1 to get you back up, the question is OK.
I don't know why people thing it is so fun to downvote without even leaving a comment.
Well, to the question :-)
Usually when drawing you have this overlapping issues and in 3D computer graphics with scanline renderers (DirectX & OpenGL for ex) they usually Skip exactly one pixel (say all on the right and down side).
Maybe this can help you out.
It is possible too that when the division is perfect, you don't have the artefacts so you must maybe deal with that (ie. if the value is a 'perfect integer', for example 185.000000 then don't remove the last pixel).
HTH