| Home | zeGraph lib | Lua lib | Custom lib | Tutorials | Notes | XML Script | C-Talk | Z-Script |
Lesson 1
Lesson 2
Lesson 3
Lesson 4
Lesson 5
Lesson 6
Lesson 7
Lesson 8
Lesson 9
Lesson 10
Lesson 11
Lesson 12
Lesson 13
Lesson 14
Lesson 15
Lesson 16
Lesson 17
Lesson 18
Lesson 19

Lesson 10 Array and Data Manipulation

The zeArray object of zeGraph offers an efficient way to handle a large number of data. It supports data types of signed and unsigned integers of 8-bits to 32-bits and of single and double floating numbers. While data in a zeArray object is expressed as a two-dimensional array, similar to data in a worksheet, the memory holding the data are contiguous. A one-dimensional array is just a two dimensional array with the second dimension size set to one. It is also possible to use zeArray to handle data array of three or more dimensions, as shown in lesson 12. You can use zeArray to initialize zeVertex, zeColor, and zeTexCoord directly.

As shown in the above figure, we call a column in an array a vector and a row a record. For a vector, a record is also called an element. The indexing of zeArray uses C convention, i.e., the first element or vector has index of zero. This is different from the convention of Lua. Let's examine the array and its memory layout through this example:

require("register")

--Create a 1 by 1 integer array.

arr = zeUtl.new("int")    

--Resize the array to 9 by 1 and fill it with numbers from 1 to 9

arr:range(1, 1, 9) 

--Reshape the array to 3 by 3 with touching the contents in the memry.

arr:reshape(3, 3)

--Print the contents
arr:print()

--[[Outputs:
1, 4, 7
2, 5, 8
3, 6, 9
]]

You can see from the outputs that data in the memory are arranged in column major. It is very important to remember this in order to properly import data from or export data to pointers of another library.

Rearranging data in the array takes only simple operations of shift, swap, flip, and transpose. First, let's shift all vectors to the left by one:

require("register")
arr = zeUtl.new("int")
arr:range(1, 1, 9)
arr:reshape(3, 3)
arr:shift(1)
arr:print()

--[[Outputs: 
 4, 7, 1
 5, 8, 2
 6, 9, 3
]]

If you change the argument of the shift(1) with -1, you will get these outputs:

 7, 1, 4
 8, 2, 5
 9, 3, 6

Most zeArray functions operate on vectors by default. With an additional argument of "r", they operate on records. For example,

require("register")
arr = zeUtl.new("int")
arr:range(1, 1, 9)
arr:reshape(3, 3)
arr:shift(1, "r")
arr:print()

--[[Outputs: 
2, 5, 8
3, 6 ,9
1, 4, 7
]]

The swap function exchanges data between two vectors. It works like this:

require("register")
arr = zeUtl.new("int")
arr:range(1, 1, 9)
arr:reshape(3, 3)
arr:swap(0, 1)
arr:print()

--[[Output: 
 4, 1, 7
 5, 2, 8
 6, 3, 9
]]

The flip function produces a mirror image of the original array. For example,

require("register")
arr = zeUtl.new("int")
arr:range(1, 1, 9)
arr:reshape(3, 3)
arr:flip("r")		-- flip records
arr:print()

--[[Output: 
 3, 6, 9
 2, 5, 8
 1, 4, 7
]]

The transpose function is very useful for data exchange between an array in column major and an array in row major:

require("register")
arr = zeUtl.new("int")
arr:range(1, 1, 9)
arr:reshape(3, 3)
arr:transpose()
arr:print()

--[[Outputs:
 1, 2, 3
 4, 5, 6
 7, 8, 9
]]

Another function to rearrange array elements is sort(). It sorts elements of a specified vector in ascending or descending order and arrange elements of other vectors according to the one being sorted. This example shows the behavior.

require("register")
arr = zeUtl.new("int")
arr:range(1, 1, 9)
arr:reshape(3, 3)
arr:flip("r")
arr:print()
--[[Outputs:
3, 6, 9
2, 5, 8
1, 4, 7
]]
arr:sort(0, 1)   --Sort by the first vector in assending order.
arr:print()
--[[Outputs:
1, 4, 7
2, 5, 8
3, 6, 9
]]

The insert and delete functions modify the number of row or column of an array. For a insertion operation, the array type of source and destination must be the same. For example:

require("register")
src, des = zeUtl.new("int", "int")
des:range(1, 1, 9)
des:reshape(3, 3)
src:range(10, 1, 9)
src:reshape(3, 3)
des:insert(1, src)
des:print()
--[[Outputs:
 1, 10, 13, 16, 4, 7
 2, 11, 14, 17, 5, 8
 3, 12, 15, 18, 6, 9
]]

Adding the the statement des:delete(2) before des:print() yields:

 1, 10, 16, 4, 7
 2, 11, 17, 5, 8
 3, 12, 18, 6, 9

The argument of many functions can be either a constant or an array. For example, you may insert a number to an array:

require("register")
arr = zeUtl.new("int", "int")
arr:range(1, 1, 9)
arr:reshape(3, 3)
arr:insert(1, 33)
arr:print()
--[[Outputs:
 1,33,4,7
 2,33,5,8
 3,33,6,9
]]

The setptr() and getptr() functions are for import and export of data. You may also use them to convert one type of array to another. Be aware that the conversion does not care about the overflow. Here is an example:

require("register")

int, dbl = zeUtl.new("int", "double")
int:range(1, 1, 9)

-- Get the pointer to the data and their type.
ptr, type = int:getptr()

-- Get the number of elements in a vector
-- and the number of vectors in the array.
nele, nvec = int:size()

-- Resize dbl array and get values from ptr
dbl:setptr(ptr, type, nele * nvec)

dbl:reshape(3, 3)
dbl:print()

--[[Outputs:
 1.000000e+000, 4.000000e+000, 7.000000e+000
 2.000000e+000, 5.000000e+000, 8.000000e+000
 3.000000e+000, 6.000000e+000, 9.000000e+000
]]

Note that the setptr() function resize the array to the same as the source and copy data from the source element by element. If both arrays are the same type, it is better to use the copy function, e.g.,

require("register")
arr1, arr2 = zeUtl.new("int", "int")
arr1:range(1, 1, 9)
arr1:reshape(3, 3)
arr1:copy(arr2)
arr2:print()

--[[
 1, 4, 7
 2, 5, 8
 3, 6, 9
]]

The parse() function tries to parse numbers separated by blanks in the string and assign them to data of a record:

require("register")
arr = zeUtl.new("int")
arr:resize(1, 5);
arr:parse(0, "1 2 3 4 5")  -- assume the string comes from reading a file
arr:print()

--[[Outputs:
 1, 2, 3, 4, 5
]]

The setele() and getele() functions are for accessing individual elements in an array. They are inefficient. Try to use setarr() and getarr() to reset and access a whole vector or record:

require("register")
arr1, arr2 = zeUtl.new("int", "int")
arr1:range(1, 1, 9)
arr1:reshape(3, 3)
arr1:getarr(1, arr2)	-- get the second vector
arr2:fill(0)
arr1:setarr(1, arr2)	-- reset the second vector
arr1:print()
--[[Outputs:
1, 0, 7
2, 0, 8
3, 0, 9
]]

Functions of add(), subtract(), multiply(), divide(), and abs() are available for modifying data values in an array. For example,

require("register")
arr = zeUtl.new("int")
arr:resize(1, 5);
arr:parse(0, "1 2 3 4 5")
arr:mul(100)
arr:print()

--[[Outputs:
 100, 200, 300, 400, 500
]]

Functions for logical comparisons between two array produce an array of 8-bit integer whose elements are 1 at the index at which the two elements in the two arrays satisfies the logical condition and are zero otherwise. The integer array may then be use to selectively transfer elements from an array to another. You can use the find() function to get indexes of non-zero elements of an array (see its use in Lesson 12). This example demonstrates the basic concept:

require("register")
arr, p, idx = zeUtl.new("int", "int", "char")
arr:resize(1, 5);
arr:parse(0, "100 200 300 400 500")
arr:ge(300, idx)	-- find elements greater >= 300
arr:getidx(idx, p)	-- get those elements
p:print()

--[[Outputs:
 300
 400
 500
]]

The concatenation function is useful for such a purpose as performing rotation transformation. Of course, the transformation job should be left to the rendering system in most cases, but someimes it is necessary or much more efficient to have the job done on data directly. Although the example here does not make much sense, you will see the practical use later.

require("register")
arr, ar2 = zeUtl.new("int", "int")
arr:range(1, 1, 9)
arr:reshape(3, 3)
ar2:range(1, 1, 9)
ar2:reshape(3, 3)
arr:concat(ar2)
arr:print()

--[[Outputs:
 30, 66, 102
 36, 81, 126
 42, 96, 150
]]

Finally, there are functions to find the minimum and the maximum of all elements:

require("register")
arr = zeUtl.new("int")
arr:range(1, 1, 9)
print(arr:min(), arr:max())
--[[Outputs:
1	9
]]