Rearranging data for quadtree/octree - algorithm

I am working on implementing a voxel octree raycaster, and the only thing left is rearranging the data to populate the leaf level of the octree, so that the data then can be averaged to build the lower levels of the tree.
I'm thinking in 2D (quadtree) initially for convenience. I have the data ordered like in the left in the drawing, and I am currently able to rearrange it like to the right. Example is 8x8.
However, I realized that I need to order the data in node order, like in the drawing below:
In other words, I want to go from an array where the data correspond to indices like this:
[0 1 2 3 4 5 6 7 8 9 ... 63]
to an array that would have the data in this order:
[0 1 4 5 16 17 20 21 2 3 ... 63]
for an 8x8 quadtree example.
I can't figure out how to do it. My main problem is dealing with an arbitrary tree size. I could probably hard-code a set of nested loops if I knew the size beforehand, but that it obviously not a great or elegant solution. I'm thinking there might be a recursive way achieve it.
This it what my quick and dirty sketch for sorting the data in the way described in picture one. It basically works by keeping track of four positions in the original data, and then stepping these forward as the new array gets filled. As far as I have been able to tell, this works fine but is not extendable to my needs:
int w = 8;
int[] before = new int[w*w*w];
int[] after = new int[w*w*w];
for (int i=0; i<w*w*w; i++) {
before[i] = i;
}
int toFill = 0;
int front = 0;
int back = w;
int frontZ = w*w;
int backZ = w*w + w;
do {
for (int i=0; i<w/2; i++) {
for (int j=0; j<w/2; j++) {
after[toFill++] = front++;
after[toFill++] = front++;
after[toFill++] = back++;
after[toFill++] = back++;
after[toFill++] = frontZ++;
after[toFill++] = frontZ++;
after[toFill++] = backZ++;
after[toFill++] = backZ++;
}
front += w;
back += w;
frontZ += w;
backZ += w;
}
front += w*w;
back += w*w;
frontZ += w*w;
backZ += w*w;
} while (toFill < w*w*w);
for (int i=0; i<w*w*w; i++) {
println("after " + i + " " + after[i]);
}

For the problem I stated, phs hinted me that it is called a Z-order curve. Thanks to that, I found this question: Z-order-curve coordinates where an algorithm for the 2D case is presented. I tried it, and it works.
Here are a few implementations of the 3D case as well: How to compute a 3D Morton number (interleave the bits of 3 ints)

Related

copy an one eigen matrix of vectors

I have
A(matrix of vectors with length = depth) is 5x5 (5 rows and 5 cols).
depth = 3 (it is the length of vector of any cell of matrix A).
B(matrix of single values) is 75 x Any (5*5*3 rows and Any cols).
x_size_kernel = 5.
block_idx is the index, here for example we have made it equal 0 (for one column of matrix B only)
The task of this simple and strict example is to copy all vectors of matrix A to one (first column) of matrix B.
Now I solve the problem like this (it is concrete example with precise data)
Eigen::MatrixXf B;
B = Eigen::MatrixXf(x_size_kernel * y_size_kernel * depth, 100).setZero();
Eigen::Matrix<Eigen::VectorXf, Eigen::Dynamic, Eigen::Dynamic> A;
A.resize(5, 5);
auto depth = 3;
for (auto yy = 0; yy < A.rows(); yy++) {
for (auto xx = 0; xx < A.cols(); xx++) {
A(yy, xx).resize(depth);
}
}
auto block_idx = 0;
// and here are all copy for one column of matrix B
for (auto my = 0; my < x_size_kernel; my++) {
for (auto mx = 0; mx < x_size_kernel; mx++) {
// add the next column of block data
B.col(block_idx).
segment(mx * depth + my * x_size_kernel * depth, depth).noalias() =
A(my, mx);
}
}
But the above code is very slow, so I need more fast code. Maybe somebody know how to copy data in such way using only Eigen one pass.
Thank you for helping.

Separate stream of numbers into groups of closer integers

I have a stream of numbers such as
[2872, 2997, 3121, 13055, 14178, 14302, 23134, 23382, 23507, 32832, 33677, 34017, 43415, 44246, 44374, 52866, 54035, 54158, 62835, 64243, 64936, 73110, 73890, 74014, 82809, 83771, 83899, 93436, 94765, 94891].
I would like to split it as follows:
[[2872, 2997, 3121], [13055, 14178, 14302], [23134, 23382, 23507], [32832, 33677, 34017], [43415, 44246, 44374], [52866, 54035, 54158], [62835, 64243, 64936], [73110, 73890, 74014], [82809, 83771, 83899], [93436, 94765, 94891]].
It is to be noted that the distance between the groups could be closer to each other, also the digits within a group could be farther away.
This is not an answer, but a way to look at your data, which should be insightful.
Original values:
Deltas:
Can't you just create a list of list of integers (or array of array) with size N/3 (N being the total of your numbers), and then just loop on this length and put the minimal number in it?
Something like this (I don't know what language you are using so I use c# as exemple):
int len = numbersStream.count();
List<List<int>> BigList = new List<List<int>>();
List<int> smallList = new List<int>();
for (int i = 0; i < len; ++i)
{
smallList = new List<int>();
for (int j = 0; j < 3; ++i)
{
int value = Math.Min(numbersStream);
smallList.Add(value);
numbersStream.remove(value);
}
BigList.Add(smallList);
}
BigList will be : (2872, 2997, 3121), (13055, 14178, 14302) etc...
*Assuming you always have exactly %3 numbers, otherwise you just tune the algorithm to avoid exceptions
The solution is in java but basically what this does is find the average delta and groups everything in a subset if the difference between the two elements is smaller then that average. You can fine tune this process by changing how the averageDelta operates
ps. this solution assumes your input is at least 1 large and called temp
int[] diffrence = new int[temp.length-1];
for (int i=1; i < temp.length; i++) {
diffrence[i-1] = temp[i]-temp[i-1];
}
int averageDelta = (int) Math.round(Arrays.stream(diffrence).average().orElse(1.0));
List<List<Integer>> resultList = new ArrayList<>();
List<Integer> currentList = new ArrayList<>();
currentList.add(temp[0]);
for (int i=1; i < temp.length; i++) {
if (temp[i]-temp[i-1] > averageDelta) {
resultList.add(currentList);
currentList = new ArrayList<>();
}
currentList.add(temp[i]);
}
resultList.add(currentList);
System.out.println(resultList.toString());

Remove object from 2D Array- Processing

I'm creating a simple space invaders game. I'm looking to delete one of the invaders once they are hit by a bullet. The invaders are made up of a 2D array of images and I've tested the collision between the image and the bullet (in an ArrayList) and that works fine. So the game detects a collision, the next step is to delete the correct object that has been hit. I'm a little confused as to how to correctly correspond where the bullet hits to which object it has hit in the 2D array, and then deleting it from the Array and carrying on with the game.
Below is how I created the invader array in setup()
for(int i=0; i<2; i++){
for(int j=0; j<4; j++){
invArray[j][i]= new Taxi(taxiX, taxiY);
taxiX= taxiX+ 100;
}
taxiX=20;
taxiY= taxiY+ 140;
}
I then filled the 2D Array with images in draw()
for(int i=0; i<2; i++){
for(int j=0; j<4; j++){
invArray[j][i].update();
if(invArray[j][i].y>=600){
invArray[j][i].y= 0;
invArray[j][i].render();
}
}
}
You're using arrays which are fixed size.
In theory you might be able to use array helper functions like shorten() and expand(), but you really got watch your counters and array structure.
In practice, for a beginner, I would say this is error prone.
It might be simpler(but hackier) to set the array element of the hit invader to null,
then simply check if the invader is not null before test collisions/rendering/etc.
e.g. in draw():
for(int i=0; i<2; i++){
for(int j=0; j<4; j++){
if(invArray[j][i] != null){
invArray[j][i].update();
if(invArray[j][i].y>=600){
invArray[j][i].y= 0;
invArray[j][i].render();
}
}
}
}
Another option is to use an ArrayList which has a dynamic size.
e.g.
ArrayList<Taxi> invaders = new ArrayList<Taxi>();
In setup you'd do something similar:
for(int i=0; i<2; i++){
for(int j=0; j<4; j++){
invaders.add(new Taxi(taxiX, taxiY));
taxiX= taxiX+ 100;
}
taxiX=20;
taxiY= taxiY+ 140;
}
then in draw():
for(int i = 0 ; i < invaders.size(); i++){
Taxi t = invaders.get(i);
t.update();
if(t.y>=600){
t.y= 0;
t.render();
}
/*
if(YOUR_HIT_CONDITION_HERE){
invaders.remove(t);
}
*/
}
It's a bit tricky to go back and forth between 1D and 2D arrays/indexing at the beginning, but it's not that bad once you get the hand of it.
To convert from 2D x,y to 1D index:
int index = x + y * width;
(where x,y are you counters and width is the width of your grid (number of columns)).
The other way around, 1D index to 2D x,y:
int x = index % width;
int y = index / width;
Try to decouple the hit detection from removing elements from the arraylist, maybe using a flag and removing at the end on the draw loop. Use arraylist.size() as limit of the loop in one part of the code. Maybe that can solve your problem with hit detection, maybe you need a counter.

Logic to randomly reorder remaining tile positions using a tile map array

The title explains most of the question.
I have a tile grid which is represented by a 2D array. Some tiles are marked as empty (but they exist in the array, for certain continued uses) while others are in normal state.
What I need to do is, to reorder the remaining (non-empty) tiles in the grid so that all (or most) are in a different non-empty position. If I just iterate all the non-empty positions and swap the tile with another random one, I might be already reordering many of them automatically (the swapped ones).
So I was wondering if there's some technique I can follow so as to reorder the grid satisfactorily with minimal looping. Any hints?
public void RandomizeGrid<T>(T[,] grid, Func<T,bool> isEmpty)
{
// Create a list of the indices of all non-empty cells.
var indices = new List<Point>();
int width = grid.GetLength(0);
int height = grid.GetLength(1);
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
if (!isEmpty(grid[x,y])) // function to check emptiness
{
indices.Add(new Point(x,y));
}
}
}
// Randomize the cells using the index-array as displacement.
int n = indices.Count;
var rnd = new Random();
for (int i = 0; i < n; i++)
{
int j = rnd.Next(i,n); // Random index i <= j < n
if (i != j)
{
// Swap the two cells
var p1 = indices[i];
var p2 = indices[j];
var tmp = grid[p1.X,p1.Y];
grid[p1.X,p1.Y] = grid[p2.X,p2.Y];
grid[p2.X,p2.Y] = tmp;
}
}
}
Would it meet your needs ("satisfactorily" is a bit vague) to ensure that every non empty tile was swapped with one other non-empty tile one time?
Say you have a list :
(1,4,7,3,8,10)
we can write down the indicies of the list
(0,1,2,3,4,5)
and perform N random swaps on the indices to shuffle it - maybe some numbers move, some don't.
(5,1,3,2,4,0)
Then take these pairwise as a sequence of swaps to perform on our original list.
(8,10,3,7,1,4)
if you have an odd number of elements, the leftover is swapped with any other element in the list.

Most efficient way to sort parallel arrays in a restricted-feature language

The environment: I am working in a proprietary scripting language where there is no such thing as a user-defined function. I have various loops and local variables of primitive types that I can create and use.
I have two related arrays, "times" and "values". They both contain floating point values. I want to numerically sort the "times" array but have to be sure that the same operations are applied on the "values" array. What's the most efficient way I can do this without the benefit of things like recursion?
You could maintain an index table and sort the index table instead.
This way you will not have to worry about times and values being consistent.
And whenever you need a sorted value, you can lookup on the sorted index.
And if in the future you decided there was going to be a third value, the sorting code will not need any changes.
Here's a sample in C#, but it shouldn't be hard to adapt to your scripting language:
static void Main() {
var r = new Random();
// initialize random data
var index = new int[10]; // the index table
var times = new double[10]; // times
var values = new double[10]; // values
for (int i = 0; i < 10; i++) {
index[i] = i;
times[i] = r.NextDouble();
values[i] = r.NextDouble();
}
// a naive bubble sort
for (int i = 0; i < 10; i++)
for (int j = 0; j < 10; j++)
// compare time value at current index
if (times[index[i]] < times[index[j]]) {
// swap index value (times and values remain unchanged)
var temp = index[i];
index[i] = index[j];
index[j] = temp;
}
// check if the result is correct
for (int i = 0; i < 10; i++)
Console.WriteLine(times[index[i]]);
Console.ReadKey();
}
Note: I used a naive bubble sort there, watchout. In your case, an insertion sort is probably a good candidate. Since you don't want complex recursions.
Just take your favourite sorting algorithm (e.g. Quicksort or Mergesort) and use it to sort the "values" array. Whenever two values are swapped in "values", also swap the values with the same indices in the "times" array.
So basically you can take any fast sorting algorithm and modify the swap() operation so that elements in both arrays are swapped.
Take a look at the Bottom-Up mergesort at Algorithmist. It's a non-recursive way of performing a mergesort. The version presented there uses function calls, but that can be inlined easily enough.
Like martinus said, every time you change a value in one array, do the exact same thing in the parallel array.
Here's a C-like version of a stable-non-recursive mergesort that makes no function calls, and uses no recursion.
const int arrayLength = 40;
float times_array[arrayLength];
float values_array[arrayLength];
// Fill the two arrays....
// Allocate two buffers
float times_buffer[arrayLength];
float values_buffer[arrayLength];
int blockSize = 1;
while (blockSize <= arrayLength)
{
int i = 0;
while (i < arrayLength-blockSize)
{
int begin1 = i;
int end1 = begin1 + blockSize;
int begin2 = end1;
int end2 = begin2 + blockSize;
int bufferIndex = begin1;
while (begin1 < end1 && begin2 < end2)
{
if ( values_array[begin1] > times_array[begin2] )
{
times_buffer[bufferIndex] = times_array[begin2];
values_buffer[bufferIndex++] = values_array[begin2++];
}
else
{
times_buffer[bufferIndex] = times_array[begin1];
values_buffer[bufferIndex++] = values_array[begin1++];
}
}
while ( begin1 < end1 )
{
times_buffer[bufferIndex] = times_array[begin1];
values_buffer[bufferIndex++] = values_array[begin1++];
}
while ( begin2 < end2 )
{
times_buffer[bufferIndex] = times_array[begin2];
values_buffer[bufferIndex++] = values_array[begin2++];
}
for (int k = i; k < i + 2 * blockSize; ++k)
{
times_array[k] = times_buffer[k];
values_array[k] = values_buffer[k];
}
i += 2 * blockSize;
}
blockSize *= 2;
}
I wouldn't suggest writing your own sorting routine, as the sorting routines provided as part of the Java language are well optimized.
The way I'd solve this is to copy the code in the java.util.Arrays class into your own class i.e. org.mydomain.util.Arrays. And add some comments telling yourself not to use the class except when you must have the additional functionality that you're going to add. The Arrays class is quite stable so this is less, less ideal than it would seem, but it's still less than ideal. However, the methods you need to change are private, so you've no real choice.
You then want to create an interface along the lines of:
public static interface SwapHook {
void swap(int a, int b);
}
You then need to add this to the sort method you're going to use, and to every subordinate method called in the sorting procedure, which swaps elements in your primary array. You arrange for the hook to get called by your modified sorting routine, and you can then implement the SortHook interface to achieve the behaviour you want in any secondary (e.g. parallel) arrays.
HTH.

Resources