TDataset --> Pointer to rows cols matrix?

386 Views Asked by At

I am writing a windows application in Lazarus/FreePascal (like Delphi). I have a TDataset object that is populated by 5000 rows, 2 columns of numerical values. I need to pass this data to a C function that I am importing statically from a .dll library.

Here is an excerpt from the library's manual that explains what format its parameters should be in:

flan_index_t flann_build_index(float* dataset,
    int rows,
    int cols,
    float* speedup,
    struct FLANNParameters* flann_params);

This function builds an index and return a reference to it. The arguments expected by this function are as follows: dataset, rows and cols - are used to specify the input dataset of points: dataset is a pointer to a rows cols matrix stored in row-major order (one feature on each row)

Can I simply pass the TDataSet object? Do I have to do something to it first so that the pointer is in the right form?

3

There are 3 best solutions below

4
On BEST ANSWER

Obviously you can't pass the TDataSet object. It is a FreePascal object, and the function seems to expect a pointer to a float (which is probably a pointer to a Single in FreePascal). It probably expects a two-dimensional array of float's. You have to pass another pointer to float and a pointer to a FLANNParameters structure as well.

Move() won't work either. A TDataSet is not an array.

I guess you'll have to declare an array like Uwe said, populate it using your dataset and pass the array:

type
  PMyFloatArray = ^TFloatArray;
  TMyFloatArray = array[0..4999, 0..1] of Single;

var
  MyArray: PMyFloatArray;
  idx: flan_index_t;

begin
  New(MyArray);
  try

    // Fill array using your TDataSet...
    // set up other parameters... 

    idx := flann_build_index(MyArray, 5000, 2, &speedup, etc...);

    // ...

  finally
    Dispose(MyArray);
  end;
end;     

Shameless plug

Please read my Pitfalls of Conversion article about converting function declarations from C to Delphi (and probably FreePascal on Win32). Now I'm at it, you may want to read my article Addressing Pointers too.

0
On

Using Rudy's solution as a base (Thanks by the way!) I came up with this:

 with Datasource1.DataSet do
  begin
    Open;
    First;
    field_count := FieldCount;
    record_count := RecordCount;

    row := 0;
    while not EOF do
    begin
      for col := 0 to field_count - 1 do
        MyArray[row, col] := Fields.Fields[col].AsFloat;
      row := row + 1; //Shift to next row in array
      Next; //Shift to next row in dataset
    end;
  end; 

Seems to work great; and a lot faster than I expected.

5
On

No, you can't pass the dataset directly. The naming "dataset" might imply that, but the meaning is totally different. You have to pass a pointer to a float matrix to the function. To implement this you should declare an array[0..4999, 0..1] of float (probably double) and fill it from the dataset.