double ivar[] vs. float ivar[]
David Gobbi
dgobbi at irus.rri.on.ca
Sat Apr 29 13:31:12 EDT 2000
Hi All,
Just a quick rehash of the email that I've copied below: There is
a way to use proxy classes to allow you to (functionally, at least)
define both of the following methods:
float *GetIvar();
double *GetIvar();
This would allow us VTK developers to change existing float[] ivars
to double[] or vice versa without introducing compatibility problems
with existing VTK applications.
To demonstrate how this is done, I've attached a short test program.
To compile it, use "CC vtkdouble3.cpp -o vtkdouble3" i.e. linking
to VTK is not required.
The proxy classes in the test program, unlike the one in the email
below, should have zero CPU overhead unless a type conversion is
necessary.
- David
On Fri, 28 Apr 2000, David Gobbi wrote:
> Hi All,
>
> There is a marked lack of consistency in VTK whether floating-point
> ivars are double or float. Or rather, there is some consistency...
> new classes generally use double, older classes use float.
>
> My guess is that most people would prefer that all of the
> float[] ivars were converted to double[], but this hasn't been
> done because changing all of those 'float *GetIvar()' methods to
> 'double *GetIvar()' would break compatibility with many applications
> that use VTK.
>
>
> There is a way around this! By using proxy classes you can (as far
> as the users are concerned) define both of the following:
>
> float *GetIvar();
> double *GetIvar();
>
>
> Here's how to do it: first, we create a proxy class such as the
> following:
>
> class vtkdouble3
> {
> public:
> vtkdouble3(double *dp) {
> this->fdata[0] = this->ddata[0] = dp[0];
> this->fdata[1] = this->ddata[1] = dp[1];
> this->fdata[2] = this->ddata[2] = dp[2]; };
> operator double *() { return this->ddata; };
> operator float *() { return this->fdata; };
> double operator[](int i) { return this->ddata[i]; };
> double operator*() { return this->ddata[0]; };
>
> private:
> double ddata[3];
> float fdata[3];
> vtkdouble3();
> };
>
>
> Then, we define a VTK class that uses this proxy class:
>
> class vtkClass : public vtkObject
> {
> public:
> vtkdouble3 GetIvar() { return vtkdouble3(this->Ivar); };
>
> protected:
> double Ivar[3];
> }
>
>
> Now, in our VTK code we can do this:
>
> vtkClass *myClass = vtkClass::New();
>
> float *fp = myClass->GetIvar();
> double *dp = myClass->GetIvar();
>
>
> Here's how it works: the GetIvar() method creates a vtkdouble3
> object and returns it on the stack. The vtkdouble3 object consists
> of an array of 3 doubles and another array of 3 floats. The
> vtkdouble3 array class also has type-conversion methods that will
> allow it to be converted to either float * (i.e. return a pointer
> to its float array) or double * (i.e. return a pointer to its
> double array).
>
>
> There is an added advantage to using a proxy class. Because the
> use of the proxy class involves passing the contents of the Ivar
> array on the stack, instead of simply passing a pointer to the
> Ivar array, using a proxy class guarantees that the GetIvar() method
> is thread safe.
>
>
> There is a downside, when you use proxy classes the method
>
> double *dp = myClass->GetIvar();
>
> is slightly less efficient than
>
> double dp[3];
> myClass->GetIvar(dp);
>
> whereas it used to be more efficient. Of course, everybody should
> have been using myClass->GetIvar(dp) most of the time, anyway, because
> of thread safety and related issues.
>
>
> So, finally, here is my proposal:
>
> Most of those float Ivar[]'s really should be converted to
> double Ivar[], but we don't want to break people's VTK
> applications. So, we convert the Ivar[]'s to double
> but at the same time we write a special
> vtkGetVectorDoubleNMacro(Ivar) method that returns the
> proxy class instead of a pointer, and that also supports
> GetIvar(float a[N]) and GetIvar(float *a1, float *a2, float *a3).
> A special vtkSetVectorDoubleNMacro(Ivar) would be required, as well.
>
> Because the majority of the changes would occur within these
> Set and Get macros they could be achieved without an immense
> amount of effort. There are many classes that have float
> *GetIvar() methods that don't use the vtkGet macros, and these
> would have to be handled individually. Also, the tcl/python/java
> wrappers would have to be modified to recognize the new macros
> and the new proxy classes.
>
> - David
>
-------------- next part --------------
#include <stdio.h>
// proxy class for converting 'double *' into 'float *'
class vtkdouble3
{
public:
vtkdouble3(double *dp) {this->data = dp;};
operator double *() { return this->data; };
operator float *() {for (int i=0; i<3; i++) {this->fdata[i]=this->data[i];};
return this->fdata; };
double operator[](int i) {return this->data[i];};
double operator*() {return this->data[0];};
private:
vtkdouble3();
double *data;
float fdata[3];
};
// proxy class for converting 'float *' into 'double *'
class vtkfloat3
{
public:
vtkfloat3(float *fp) {this->data = fp;};
operator float *() {return this->data; };
operator double *() {for (int i=0; i<3; i++) {this->ddata[i]=this->data[i];};
return this->ddata; };
double operator[](int i) { return this->data[i]; };
double operator*() { return this->data[0]; };
private:
vtkfloat3();
float *data;
double ddata[3];
};
// an example VTK class that uses the above classes
class vtkTestClass
{
public:
static vtkTestClass *New() { return new vtkTestClass; };
void Delete() { delete this; };
void SetDoubleIvar(double x, double y, double z) {
this->DoubleIvar[0]=x; this->DoubleIvar[1]=y; this->DoubleIvar[2]=z; };
void SetFloatIvar(float x, float y, float z) {
this->FloatIvar[0]=x; this->FloatIvar[1]=y; this->FloatIvar[2]=z; };
vtkdouble3 GetDoubleIvar() { return vtkdouble3(this->DoubleIvar); };
vtkfloat3 GetFloatIvar() { return vtkfloat3(this->FloatIvar); };
protected:
vtkTestClass() {
this->DoubleIvar[0] = this->DoubleIvar[1] = this->DoubleIvar[2] = 0.0;
this->FloatIvar[0] = this->FloatIvar[1] = this->FloatIvar[2] = 0.0f; };
~vtkTestClass() {};
double DoubleIvar[3];
float FloatIvar[3];
};
// a short test program
int main(int argc, char *argv[])
{
double *dp;
float *fp;
vtkTestClass *testClass = vtkTestClass::New();
// test vtkdouble3
testClass->SetDoubleIvar(1.11111111111111111111,
2.22222222222222222222,
3.33333333333333333333);
dp = testClass->GetDoubleIvar();
fp = testClass->GetDoubleIvar();
fprintf(stderr,"float: %.16f %.16f %.16f\n",fp[0],fp[1],fp[2]);
fprintf(stderr,"double: %.16f %.16f %.16f\n\n",dp[0],dp[1],dp[2]);
// test vtkfloat3
testClass->SetFloatIvar(1.11111111111111111111,
2.22222222222222222222,
3.33333333333333333333);
dp = testClass->GetFloatIvar();
fp = testClass->GetFloatIvar();
fprintf(stderr,"float: %.16f %.16f %.16f\n",fp[0],fp[1],fp[2]);
fprintf(stderr,"double: %.16f %.16f %.16f\n\n",dp[0],dp[1],dp[2]);
testClass->Delete();
}
More information about the vtk-developers
mailing list