Reputation: 331550
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
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 struct
ure 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 float
ing 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
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