0

I have been searching high and low for a Delphi function or any info that can parse a space delimited TStringList(Loaded from *.asc file) to a dynamic 2D array of integer.

What I have is an ASCII grid file with elevations in a grid format. Firstly I read the file into a TStringlist, where I extract the header data to variables, then delete the header data from the TStringlist. What I'm left with is a TStringlist with only elevation data in a grid of 3601 x 3601, with each value separated by a space. With this Stringlist still in memory, I'd like to fill a 2D array of integer with the elevation data, then free the TStringList.

From my searches I stumbled upon a piece of code here that kind of worked, but not completely.

What I have is:

var sourceData, tmpGrid, tmpRow : TStringList;
    val : String;
    Pos, i, j, k, l : Integer;
    nCols, nRows, noData : Integer;
    xllCorner, yllCorner, cellSize : Extended;
    Dem : array of array of Integer;
begin
 val := '';
 sourceData := TStringList.Create;
 tmpGrid := TStringList.Create;
 tmpRow := TStringList.Create;
 tmpRow.StrictDelimiter := True;
 tmpRow.Delimiter := ' ';
 sourceData.LoadFromFile('D:\ZA_DEM_DATA\Bulk_Order_466486\ARCASCII\s30_e026_1arc_v3.asc');

nCols := StrToInt(StripNonConforming(sourceData.Strings[0], ['0'..'9', '+', '-', '.']));
nRows := StrToInt(StripNonConforming(sourceData.Strings[1], ['0'..'9', '+', '-', '.']));
xllCorner := StrToFloat(StripNonConforming(sourceData.Strings[2], ['0'..'9', '+', '-', '.']));
yllCorner := StrToFloat(StripNonConforming(sourceData.Strings[3], ['0'..'9', '+', '-', '.']));
cellSize := StrToFloat(StripNonConforming(sourceData.Strings[4], ['0'..'9', '+', '-', '.']));
noData := StrToInt(StripNonConforming(sourceData.Strings[5], ['0'..'9', '+', '-', '.']));

Edit1.Text := IntToStr(nCols);
Edit2.Text := IntToStr(nRows);
Edit3.Text := FloatToStr(xllCorner);
Edit4.Text := FloatToStr(yllCorner);
Edit5.Text := FloatToStr(cellSize);
Edit6.Text := IntToStr(noData);

for I := 0 to 5 do
 begin
  sourceData.Delete(0);
 end;
//This is where I start parsing my TStrinList
tmpGrid.DelimitedText := sourceData.Text;
SetLength(Dem, nCols, nRows);

Edit7.Text := IntToStr(sourceData.Count);

try
 for i := 0 to sourceData.Count -1 do
   for j := 0 to sourceData.Count -1 do
    begin
     Dem[i][j] := StrToInt(tmpGrid.Strings[i]);
    end;
finally
 sourceData.Free;
end;

StringGrid1.ColCount := nCols;
StringGrid1.RowCount := nRows;
//This is mainly to visualise the data while testing the code
for i := 0 to nCols -1 do
  for j := 0 to nRows -1 do
   begin
    StringGrid1.Cells[i, j] := IntToStr(dem[i, j]);
   end;
 end;

The result I get is the first "row" of data as displayed in the original file, but copied to all rows of the array. For example:

Original Data:

1. 1245 1268 1232 1258
2. 1354 1321 1578 1689
3. 1461 1423 1475 1427
4. 1598 1541 1562 1550

What I get is:

1. 1245 1268 1232 1258
2. 1245 1268 1232 1258
3. 1245 1268 1232 1258
4. 1245 1268 1232 1258

Any and all help will be greatly appreciated.

1
  • 1
    Well, looks like [debug-this-code-for-me] should be a major tag here. Commented Apr 2, 2015 at 12:23

2 Answers 2

2

This seems to be the cause of the wrong results

 for i := 0 to sourceData.Count -1 do
   for j := 0 to sourceData.Count -1 do
    begin
     Dem[i][j] := StrToInt(tmpGrid.Strings[i]);
    end;

You have moved the actual data from SourceData to tmpGrid, which is not needed. Instead, assign one line at a time from SourceData to tmpRow, then read the values one at a time from tmpRow, and assign to the value array:

for i := 0 to SourceData.Count-1 do
begin
  tmpRow.DelimitedText := SourceData[i];
  for j := 0 to tmpRow.Count-1 do
    Dem[i,j] := StrToInt(tmpRow[j]);
end;
Sign up to request clarification or add additional context in comments.

Comments

2

Just after this code line

//This is where I start parsing my TStrinList
tmpGrid.DelimitedText := sourceData.Text;

your sourceData contains 4 lines of text

1245 1268 1232 1258
1354 1321 1578 1689
1461 1423 1475 1427
1598 1541 1562 1550

and tmpGrid contains 16 lines of text

1245
1268
1232
1258
1354
1321
1578
1689
1461
1423
1475
1427
1598
1541
1562
1550

But you only access the tmpGrid lines from 0 to 3 for each row

 for i := 0 to sourceData.Count -1 do
   for j := 0 to sourceData.Count -1 do
    begin
     Dem[i][j] := StrToInt(tmpGrid.Strings[i]);
    end;

You should change your code to use the values from nCols and nRows and then calculate the line inside tmpGrid

 for i := 0 to nCols -1 do
   for j := 0 to nRows -1 do
    begin
     Dem[i][j] := StrToInt(tmpGrid.Strings[i + j*nCols]);
    end;
i = 0 // first column
j = 1 // second row
i + j * nCols => 0 + 4 => fifth line of tmpGrid (zero indexed)

6 Comments

Thanks Sir Rufo, your answer helped. At first I thought something caused an endless loop, since my application froze and stayed that way for over 10min. I decided to test again with a smaller block of data, 1/4 of the size to be exact, and it seem to have worked. I do however have a problem with the speed...it took 1min 09sec to complete the task with the test data which is 900x900. Is there any faster method I could try to explore, or should I rather approach the task differently?
@Martin Did you include writing to the StringGrid in your speed test? I found your timing report so unbelievable that I did a test (without the StringGrid) and reading a 900 x 900 value text file, converting values to integer and assigning to the array takes about a second. I used the method I suggested in my answer, without the tmpGrid StringList.
@ Tom, thanks for your comment, it got me on the right track. Apparrently the following line "Memo1.Lines.Assign(tmpGrid);" was the culprit. Also, just a side note, I had an issue with your answer at first as it returned with " '' is not a valid integer" error, but managed to fix it with Trim. Thanks for your help!
@Martin When you address comments with @, don't leave a space after, because then the notification of the adressee will not work. The issue with not valid integer was probably because of a space at the end of each line in SourceData, which creates an empty line in tmpRow. Good you found a fix.
@Tom, sorry about that, this is my first post here, so still learning the ropes. Yes, when assigning the data in it's delimited form to Memo, I noticed a leading and trailing space, but thought DelimitedText would sort it out. So I used your solution with the Trim function and it seems to be working great. I now have to create a bitmap from the values in the array to visualize the data as a Heightmap, once this is done i will be able to compare it with the original Heightmap and verify the results. Thanks for all the help. One last thing, how do I accept your answer?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.