开发者

Conversion of pointers and arrays from C++ to Delphi

I am trying to use the ANN (approximate nearest neighbor) library (the .dll) within my Delphi code. The library is written in C++, and although the data types are fairly simple I am having some trouble.

I used h2pas to convert the C++ header file as far as I could get it. I ended up with the following data types (C++ on the left, Delphi on the right):

enum ANNbool {ANNfalse = 0, ANNtrue = 1}; --> ANNbool = longint;                
typedef double  ANNcoord;                 --> ANNcoord = double;                
typedef double  ANNdist;                  --> ANNdist = double;                 
typedef int     ANNidx;                   --> ANNidx = longint;                 

typedef ANNcoord* ANNpoint;               --> ANNpoint = ^ANNcoord;             
typedef ANNpoint* ANNpointArray;          --> ANNpointArray = ^ANNpoint;        
typedef ANNdist*  ANNdistArray;           --> ANNdistArray = ^ANNdist;          
typedef ANNidx*   ANNidxArray;            --> ANNidxArray = ^ANNidx;

For starters I want to sucessfully port the sample included with the ANN library. The C++ code for this sample is linked here without comments (if you want the comments, just download the library from ANN's webpage).

Even more specifically, here is the excerpt that I am having trouble with (C++ code..):

...
开发者_运维问答while (nPts < maxPts && readPt(*dataIn, dataPts[nPts]))  nPts++;
...
bool readPt(istream &in, ANNpoint p)
{
 for (int i = 0; i < dim; i++) {
 if(!(in >> p[i])) return false;
 }
 return true;
}

A member on stackoverflow helped me with a partial conversion of the readPt function - but I am not sure if it is completely correct (Delphi code..):

function readPt(inStr: TStream; p: ANNpoint): boolean;
var
  Size: longint; // number of bytes to read
begin
  inStr.Size := SizeOf(ANNcoord) * dim;
  Result := inStr.Read(p^, Size) = Size;
end; 

Here is my unsuccessful attempt at implementing that while loop in Delphi (irrelevant code omitted):

var
  dataPts: AnnPointArray;
  BinStream: TMemoryStream;    
  dim,maxPts,nPts: LongInt;


begin
  dim := 2; 
  maxPts := 1000;  
  dataPts := annAllocPts(maxPts, dim);      

  //GENERATE TStream data
  ///////////////////////////
  BinStream := TMemoryStream.Create;
  BinStream.SetSize(1001);
  for nPts := 0 to 1000 do
  begin
    BinStream.Write(nPts, 1);
  end;                       
  BinStream.Position := 0
  ///////////////////////////                     

  nPts:=0;
  while nPts < maxPts do
  begin
    readPt(BinStream, dataPts[nPts]);
    nPts:=nPts+1;
  end;  
end;   

When I attempt to run this I get a segmentation fault at readPt(BinStream, dataPts[nPts]);

I will be extremely grateful if someone would take the time to help me out here!

Edit: In case the C++ function for annAllocPts() is important.. here it is:

ANNpointArray annAllocPts(int n, int dim)       // allocate n pts in dim
{
    ANNpointArray pa = new ANNpoint[n];         // allocate points
    ANNpoint      p  = new ANNcoord[n*dim];     // allocate space for coords
    for (int i = 0; i < n; i++) {
        pa[i] = &(p[i*dim]);
    }
    return pa;
}

And here is how I implemented it:

function annAllocPts(n: longint; dim: longint): ANNpointArray cdecl;
  external 'ANN.dll' index 33;     

Edit 2: I am still having trouble properly filling the input stream (I think)...

var
 ThisDouble: Double;
begin
  binstream := TMemoryStream.Create;
  ThisDouble :=1.001;
  for nPts := 0 to maxPts*dim do
  begin
    binstream.Write(ThisDouble,SizeOf(ThisDouble));
  end;
  BinStream.Position := 0;

  nPts:=0;
  while nPts < maxPts do
  begin
   if not readPt(BinStream, dataPts[nPts]) then
    Break;
  nPts:=nPts+1;
end;                    


Your code calls the DLL function to allocate a array of 1000 2-element arrays of Double. Then you fill a stream with 1001 bytes. You're trying to populate 16000 bytes of storage with only 1001 bytes of data.

Furthermore, the data you're putting in the stream doesn't form meaningful Double values anyway.

Also, your version of readPt is wrong. You're assigning inStr.Size instead of the local Size variable. The compiler should have warned you that Size was used without being initialized. Your code has the effect to truncating the input stream to the length of one array segment and then attempting to read an unknown number of bytes from the stream. Use the version you got from your other question.


The code in readPt() is correct. But it reads more than one double in one go, just like the C++ example in the other question.

Your problem is that you write maxPts (=1000) doubles to the memory stream, but then, in a loop (of MaxPts = 1000 iterations), you read dim (= 2) doubles per iteration (readPt reads dim ANNcoords in one go), so you try to read 1000*2 ANNcoords and run out of data before you reach the end. You should check the return value of readPt() in the loop and break if it is false:

nPts:=0;
while nPts < maxPts do
begin
  if not readPt(BinStream, dataPts[nPts]) then
    Break;
  nPts:=nPts+1;
end;

Of course, you could also write dim * maxPts items into the memory stream.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜