C language implements quaternary (quadtree) and decimal Morton codes

1. Foreword:
It was introduced by “Geographic Information Systems and Principles” and “Basics of Geographic Information Systems”. It seemed a bit interesting, so I wanted to implement it in C language and sort out the relevant content.
Prerequisite knowledge:

Leaf node: A node that has no child nodes.

The linear quadratic number only stores the last leaf node information, including the position, depth and grid value of the leaf node.

Address code (Morton code): Linear four-branch leaf nodes follow certain rules and imply the number of leaf node location information.

Expansion:

The 32-bit Morton code encoding method zyxzyx in the 3-dimensional space xyz, each dimension is represented by 10 bits (0~1023).

The node of the tree: contains a data element and several branches pointing to subtrees;

Child node: The root of the subtree of a node is called the child of the node;

Parent node: Node B is the child of node A, then node A is the parent of node B;

Brother nodes: nodes of children of the same parents; Cousin nodes: nodes on the same level;

Ancestor node: All nodes on the branches from the root to the node. Descendant nodes: Any node in the subtree rooted at a node is called a descendant of the node.

Node level: The level of the root node is defined as 1; the children of the root are the second level nodes, and so on;

Tree depth: the largest node level in the tree

Degree of node: the number of node subtrees

Degree of tree: The maximum node degree in the tree.

Leaf node: also called terminal node, it is a node with degree 0;

Branch node: a node whose degree is not 0;

Ordered tree: A tree with ordered subtrees, such as a family tree;

Unordered tree: the order of subtrees is not considered;

2. Basic principles:
Two methods:

There are two different solutions based on the generation of quaternary Morton codes and the establishment process of quaternary numbers.

1. The top-down splitting method gradually generates Morton codes in the process of establishing quadratic numbers;

2. First calculate the Morton code of each grid, and then merge it from bottom to top according to a certain scanning method to create a four-way number.

The quadratic numbers generated by bottom-up and top-down are the same, but the former is more efficient.

For the Morton code of the first method:

Step 1: Divide the sub-quadrants. The labels 0, 1, 2, and 3 represent the four sub-quadrants of the upper left, upper right, lower left, and lower right respectively.

Step 2: Perform testing and continue subdividing if necessary.

During the segmentation process, the number of digits of the label continues to increase, and this label is a Morton code.

And each digit of the Morton code is a quaternary number not greater than 3. Each time it is divided, one digit is added. The more divisions, the smaller the resulting sub-area, and the larger the corresponding Morton code value.

The Morton code value of the final node is the sum of the corresponding quadrant values of all bits, MQ=q1q2q3..qn=q1*10^(k-1) + q2*10^(k-2)… + qk

For the Morton code of the second method:

1. Convert decimal row and column numbers into binary representation

2. Based on MQ=2*Ib (binary row number) + Jb (binary column number)

3. Code implementation:
Try your skills:

Understand the quaternary Morton code:

#include<stdio.h>
#include<math.h>

//Calculate MQ value
int calculateMq(int Ib,int Jb)
{
return (2 * Ib + Jb);
}

//Calculate decimal numbers
int tenTransToTwo(int II)
{
int sum = 0;//used to store the converted binary
int n = 0;//Exponent used to convert the output form
while (II > 1)//Judge whether division by two and remainder is completed
{//Storage in reverse order
sum + = ((II % 2)*pow(10,n));
II = (II- II % 2)/2;
n + + ;
}
sum + = (II * pow(10, n));
return sum;
}
int main()
{
//Prompt user for input
printf("Please enter decimal II, JJ value\\
");
//Initialization and reading decimal numbers
int II=0;
int JJ=0;
scanf_s("%d", & amp;II);
scanf_s("%d", & amp;JJ);
//Implement binary conversion of rows and columns
printf("%d\\
", tenTransToTwo(II));
printf("%d\\
", tenTransToTwo(JJ));
//Output the quaternary Morton value (MQ value)
printf("%d\\
", calculateMq(tenTransToTwo(II), tenTransToTwo(JJ)));

return 0;
}
Output result:

Disadvantages of quaternary system:

1. The memory overhead inside and outside the code is large, and most languages do not support quaternary variables.

2. The computing efficiency is not high

Therefore, Mark et al. (1989) suggested using the decimal Morton code as the address code for linear quadratic numbers.

Experience it again:

Decimal Morton code:

Method 1:

Calculation method based on mathematical formulas

#include<stdio.h>
#include<math.h>

//Calculate MQ value
int calculateMq(int Ib, int Jb)
{
return (2 * Ib + Jb);
}

//Calculate decimal numbers
int tenTransToTwo(int II)
{
int sum = 0;//used to store the converted binary
int n = 0;//Exponent used to convert the output form
while (II > 1)//Judge whether division by two and remainder is completed
{//Storage in reverse order
sum + = ((II % 2)*pow(10, n));
II = (II - II % 2) / 2;
n + + ;
}
sum + = (II * pow(10, n));
return sum;
}

//Calculate binary numbers
int twoTransToFour(int transtedTwo)
{
int sum = 0;//used to store quaternary numbers
int n = 0;//Exponent used to convert the output form
int digit = 0;//used to temporarily store each digit;
//Follow the principle of output in reverse order and store in forward order
while(transtedTwo>0)
{
digit = transtedTwo % 2;
transtedTwo /= 2;
sum + = (digit*pow(4, n));
n + + ;
}
//return array i.e. return quaternary number

return sum;
}
int main()
{
//Prompt user for input
printf("Please enter decimal II, JJ value\\
");
//Initialization and reading decimal numbers
int II = 0;
int JJ = 0;
scanf_s("%d", & amp;II);
scanf_s("%d", & amp;JJ);
Implement binary conversion of rows and columns
//printf("Ib = %d\\
", tenTransToTwo(II));
//printf("Jb = %d\\
", tenTransToTwo(JJ));
Output the quaternary Morton value (MQ value)
//printf("The Morton code at the target is %d\\
", calculateMq(tenTransToTwo(II), tenTransToTwo(JJ)));
//Implement quaternary conversion of rows and columns
printf("Ib = %d\\
", twoTransToFour(II));
printf("Jb = %d\\
", twoTransToFour(JJ));
//Output the decimal Morton value (MQ value)
printf("The Morton code at the destination is %d\\
", calculateMq(twoTransToFour(II), twoTransToFour(JJ)));

return 0;
}
Method 2:

An algorithm based on bitwise operations. In order to simplify the use of bitwise operators, the author plans to use array simulation.

#include<stdio.h>
#include<math.h>

//Calculate decimal numbers
int tenTransToTwo(int II)
{
int sum = 0;//used to store the converted binary
int n = 0;//Exponent used to convert the output form
while (II > 1)//Judge whether division by two and remainder is completed
{//Storage in reverse order
sum + = ((II % 2)*pow(10,n));
II = (II- II % 2)/2;
n + + ;
}
sum + = (II * pow(10, n));
return sum;
}

//Calculate binary numbers
int MyBitOperator(int transtedTwo1, int transtedTwo2)
{
int sum = 0;//used to store quaternary numbers
int i=0;//Move array subscript
//Follow the principle of output in reverse order and store in forward order
int arr[8] = { 0 };//The bits used to store II and JJ, the even numbers (and 0) are the II bits, and the odd numbers are the JJ bits
while (transtedTwo1 > 0)
{
arr[0 + i] = transtedTwo1% 2;//0,2,4,6
transtedTwo1 /= 10;
i + = 2;
}
i = 0;
while (transtedTwo2 > 0)
{
arr[1 + i] = transtedTwo2 % 2;//1,3,5,7
transtedTwo2 /= 10;
i + = 2;
}
//Calculate Md
int n = 0;//Exponent used to convert the output form
for (int i = (sizeof(arr) / sizeof(arr[0]))-3; i >=0; i--)//The previous array is redundant
{
\t\t
if (arr[i] > 0) {
sum + = (arr[i] * pow(2, n));
printf("%d\\
", sum);
}
n + + ;
}
//return array i.e. return quaternary number

return sum;
}
int main() {
//Prompt user for input
printf("Please enter decimal II, JJ value\\
");
//Initialization and reading decimal numbers
int II = 0;
int JJ = 0;
scanf_s("%d", & amp;II);
scanf_s("%d", & amp;JJ);
printf("MD value is %d", MyBitOperator(tenTransToTwo(II), tenTransToTwo(JJ)));

return 0;
}

Output result:

Method 1:

Method 2:

Summary: Overall, the structure is simple, mainly about bit and base operations, which requires carefulness, so the author spent a long time debugging! !

If you think it’s good, you can like, collect and follow! Let’s make progress together!

I am a noob, everyone is welcome to criticize and correct me!

Like it