Joan Venge
Joan Venge

Reputation: 331550

C++ code help for C#

I came across this code but not sure how I can write it in C#:

bool getBestFitPlane(unsigned int vcount,
                     const float *points,
                     unsigned int vstride,
                     const float *weights,
                     unsigned int wstride,
                     float *plane)
{
  bool ret = false;

  SinglePrecision::Vec3 kOrigin(0,0,0);

  float wtotal = 0;

  if ( 1 )
  {
    const char *source  = (const char *) points;
    const char *wsource = (const char *) weights;

    for (unsigned int i=0; i<vcount; i++)
    {

      const float *p = (const float *) source;

      float w = 1;

      if ( wsource )
      {
        const float *ws = (const float *) wsource;
        w = *ws; //
        wsource+=wstride;
      }

      kOrigin.x+=p[0]*w;
      kOrigin.y+=p[1]*w;
      kOrigin.z+=p[2]*w;

      wtotal+=w;

      source+=vstride;
    }
  }

  float recip = 1.0f / wtotal; // reciprocol of total weighting

  kOrigin.x*=recip;
  kOrigin.y*=recip;
  kOrigin.z*=recip;


  float fSumXX=0;
  float fSumXY=0;
  float fSumXZ=0;

  float fSumYY=0;
  float fSumYZ=0;
  float fSumZZ=0;


  if ( 1 )
  {
    const char *source  = (const char *) points;
    const char *wsource = (const char *) weights;

    for (unsigned int i=0; i<vcount; i++)
    {

      const float *p = (const float *) source;

      float w = 1;

      if ( wsource )
      {
        const float *ws = (const float *) wsource;
        w = *ws; //
        wsource+=wstride;
      }

      SinglePrecision::Vec3 kDiff;

      kDiff.x = w*(p[0] - kOrigin.x); // apply vertex weighting!
      kDiff.y = w*(p[1] - kOrigin.y);
      kDiff.z = w*(p[2] - kOrigin.z);

      fSumXX+= kDiff.x * kDiff.x; // sume of the squares of the differences.
      fSumXY+= kDiff.x * kDiff.y; // sume of the squares of the differences.
      fSumXZ+= kDiff.x * kDiff.z; // sume of the squares of the differences.

      fSumYY+= kDiff.y * kDiff.y;
      fSumYZ+= kDiff.y * kDiff.z;
      fSumZZ+= kDiff.z * kDiff.z;


      source+=vstride;
    }
  }

  fSumXX *= recip;
  fSumXY *= recip;
  fSumXZ *= recip;
  fSumYY *= recip;
  fSumYZ *= recip;
  fSumZZ *= recip;

  // setup the eigensolver
  SinglePrecision::Eigen kES;

  kES.mElement[0][0] = fSumXX;
  kES.mElement[0][1] = fSumXY;
  kES.mElement[0][2] = fSumXZ;

  kES.mElement[1][0] = fSumXY;
  kES.mElement[1][1] = fSumYY;
  kES.mElement[1][2] = fSumYZ;

  kES.mElement[2][0] = fSumXZ;
  kES.mElement[2][1] = fSumYZ;
  kES.mElement[2][2] = fSumZZ;

  // compute eigenstuff, smallest eigenvalue is in last position
  kES.DecrSortEigenStuff();

  SinglePrecision::Vec3 kNormal;

  kNormal.x = kES.mElement[0][2];
  kNormal.y = kES.mElement[1][2];
  kNormal.z = kES.mElement[2][2];

  // the minimum energy
  plane[0] = kNormal.x;
  plane[1] = kNormal.y;
  plane[2] = kNormal.z;

  plane[3] = 0 - kNormal.dot(kOrigin);

  return ret;
}

I mainly don't understand the const char line. Is it trying to get the first item of values array?

Upvotes: 1

Views: 229

Answers (2)

pickypg
pickypg

Reputation: 22342

I mainly don't understand the const char line. Is it trying to get the first item of values array?

The purpose of casting points to source is to get a constant byte array (effectively) version of the float array that

// use points as a byte array
const char *source  = (const char *) points;

for (unsigned int i=0; i<vcount; i++)
{
  // get a reference to the current position in the source array
  const float *p = (const float *) source;

  ...

  // iterate to the next series of points
  source+=vstride;
}

I assume that vstride is a value of 12 or more. vstride is being used to skip an arbitrary number of bytes for the current point in order to calculate the weighted value. As there are at least 3 float points per position, that is how I came up with at least 12 (3 times 4). It could be more if there is other data in the array along with the point, between the z coordinate and the start of the next point.

The reason that it is necessary to use the source pointer is because pointer arithmetic works based on the sizeof the pointed data. Thus (points + 12) is different from (source + 12), and clearly vstride is associated with the number of bytes to skip (sort of implying that the points reference may actually be a structure that is being used as float array out of convenience, which is not unusual in C/C++).

In C#, you would not be writing something like this. You are going to pass in an array/collection of Points, which is going to be an object that has an X, Y, and Z floating point coordinate. Similarly, there will be an optional (can be null, as noted by if (wsource)) array/collection of Weights, which contains a single float value in it representing the weight for the current coordinate. It may make sense to combine them together. The points and weights have the same number of elements, if weights is defined.

You will not need the vcount, vstride, or wstride variables in C#. You can loop through the Points array/collection and apply the weight if any Weights are supplied.

float weight = 1.0f;

for (int i = 0; i < points.Length; ++i)
{
    if (weights != null)
    {
        weight = weights[i].Weight;
    }

    x += points[i].X * weight;
    y += points[i].Y * weight;
    z += points[i].Z * weight;

    wtotal += weight;
}

Upvotes: 2

holtavolt
holtavolt

Reputation: 4468

Essentially, yes - although there's some strange type-casting going on here that seems unnecessary, at least given the code fragment you've posted.

The line is declaring a constant (i.e. unchangeable) pointer (*) to a char (signed byte) named 'source', and assigning it the address of the start of 'values'. This is odd, because as you can see from the argument list, values is a const float * type.

Pointer types are often used for handling arrays in older C/C++ programs, as they are somewhat interchangeable.

For C#, you would use the built-in array type instead.

[EDIT] Now that you've posted more source, it's clear that this was done so that they can use the 'source' variable to point into a block of floats, and increments it by a 'stride' amount of bytes (chars) when necessary to move to the float to be processed. You can certainly devise C# code to handle this memory layout if needed (System.IntPtr might be helpful to you.)

Upvotes: 3

Related Questions