0

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?

Community
  • 1
  • 1
Mike Furlender
  • 3,869
  • 5
  • 47
  • 75
  • Could this be the right way to do it? Move(DataSet, DataPointer[0], SizeOf(DataSet)); – Mike Furlender Aug 20 '11 at 14:46
  • No, a TDataSet is a class that encapsulates teh connection to a datafile or sql server. It doesn't point to the data expected by the function. – Uwe Raabe Aug 20 '11 at 14:52
  • No. The TDataset has a different structure than the required by the function. You don't specify which size has each item of the matrix, there are several types for numeric values. Sorry, I cannot add (+1) for using Object Pascal, even if I want to ;-) – umlcat Aug 20 '11 at 15:36

3 Answers3

1

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.

Uwe Raabe
  • 45,288
  • 3
  • 82
  • 130
1

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.

Rudy Velthuis
  • 28,387
  • 5
  • 46
  • 94
  • Would there happen to be a way to fill the array by reference instead of by duplicating the values in a loop? – Mike Furlender Aug 20 '11 at 18:14
  • Can I maybe convert it to a TMemoryStream, and then copy it to a pointer?.. Or is that a waste of time? – Mike Furlender Aug 20 '11 at 18:30
  • The data are somewhere, and you use the DataSet to get them from there. They don't have to be there in one block. – Rudy Velthuis Aug 20 '11 at 19:59
  • I have read parts of both of your articles many times over the past week or two. They are both extremely useful articles! Thank you very much for creating them; very impressive :) – Mike Furlender Aug 21 '11 at 01:08
0

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.

Mike Furlender
  • 3,869
  • 5
  • 47
  • 75