Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Constant object cannot be passed as var parameter

This is the trouble code..

multresult := mult(mult(temp, quatview), conjugate(temp));

Full procedure

procedure TForm2.RotateCamera(var angle: Single; x: Single; y: Single; z: Single);
var
    temp, QuatView, multResult : TQuaternion;
begin
    temp.x := x * sin(Angle/2);
    temp.y := y * sin(Angle/2);
    temp.z := z * sin(Angle/2);
    temp.w := cos(Angle/2);

    quatview.x := camera1.Position.x;
    quatview.y := camera1.Position.y;
    quatview.z := camera1.Position.z;
    quatview.w := 0;

    multresult := mult(mult(temp, quatview), conjugate(temp));

    camera1.Position.x := multresult.x;
    camera1.Position.y := multresult.y;
    camera1.Position.z := multresult.z;
end;

mult function

function TForm2.mult(var A: TQuaternion; B: TQuaternion) :TQuaternion;
 var
   c : TQuaternion;
begin
  C.x := A.w*B.x + A.x*B.w + A.y*B.z - A.z*B.y;
  C.y := A.w*B.y - A.x*B.z + A.y*B.w + A.z*B.x;
  C.z := A.w*B.z + A.x*B.y - A.y*B.x + A.z*B.w;
  C.w := A.w*B.w - A.x*B.x - A.y*B.y - A.z*B.z;
result := C;
End;

and conjugate

 function TForm2.conjugate( var quat:TQuaternion) :TQuaternion;
  begin
     quat.x := -quat.x;
     quat.y := -quat.y;
     quat.z := -quat.z;
     result := quat;
  end;

and if needed TQuaternion

type
  TQuaternion = class
    x: single;
    y: single;
    z: single;
    w: single;
  end;

any idea why i get this error and how to fix it?

like image 763
Glen Morse Avatar asked Aug 18 '13 03:08

Glen Morse


2 Answers

The answer to the question you asked is that the parameters to mult should be const. You don't modify them (and you should not), so make them const. Then your code compiles.

In a similar vein, it's bad form for Conjugate to modify its input parameter. That makes the function horrid to use. Don't do that.

Consider this line:

multresult := mult(mult(temp, quatview), conjugate(temp) );

Since conjugate modifies temp, you'd better hope that the call to conjugate is made after the other use of temp. The language makes no such guarantee. So, cross your fingers!

One of the principles worth following with arithmetic code is that input parameters/operands should never be modified, and that functions always return new values. Follow this principle and you'll never fall into trap highlighted above. See the second part of my answer for an illustration.

However the code won't work even with these changes because you are not instantiating any instances of the TQuaternion class. Are you sure that it's not a record?


The real forward progress will come when you create a good quaternion type. This should be a value type since arithmetic operations are better suited to value types for a number of reasons.

In modern Delphi you want to use a record with operators. Here's a flavour of what you need, ready to extend as you need.

type
  TQuaternion = record
    x: single;
    y: single;
    z: single;
    w: single;
    function Conjugate: TQuaternion;
    class operator Multiply(const A, B: TQuaternion): TQuaternion;
  end;

function TQuaternion.Conjugate: TQuaternion;
begin
  Result.x := -x;
  Result.y := -y;
  Result.z := -z;
  Result.w := w;
end;

class operator TQuaternion.Multiply(const A, B: TQuaternion): TQuaternion;
begin
  Result.x := A.w*B.x + A.x*B.w + A.y*B.z - A.z*B.y;
  Result.y := A.w*B.y - A.x*B.z + A.y*B.w + A.z*B.x;
  Result.z := A.w*B.z + A.x*B.y - A.y*B.x + A.z*B.w;
  Result.w := A.w*B.w - A.x*B.x - A.y*B.y - A.z*B.z;
end;

With this type your multiplication call becomes:

 multresult := temp*quatview*temp.Conjugate;

You'll surely want to write more operators and helper functions for this type.

It's really important to move the arithmetic functions into this type and out of your form. Don't use your high level GUI form class to implement low level arithmetic.

One final piece of advice. Your code has repeated mis-use of var parameters. I suggest you treat var parameters as things to be avoided. Try to write code without them if possible.

like image 187
David Heffernan Avatar answered Nov 02 '22 05:11

David Heffernan


The mult method declares the A parameter as a var so you must pass a variable to the method in order to work, like so.

 multresult := mult(temp, quatview);
 multresult := mult(multresult, conjugate(temp));
like image 31
RRUZ Avatar answered Nov 02 '22 04:11

RRUZ