www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - 3d vector struct

reply "Brenton" <bnrayner hotmail.com> writes:
Hi, I'm just getting to know D and so am hoping that someone more 
experienced with the language could review this 3d vector struct 
and my comments below.  I'm planning on building a little ray 
tracer in the next week or so :)

struct Vector3d {
	double x = 0, y = 0, z = 0;

	void normalize() {
		double scale = 1.0 / (x * x + y * y + z * z);
		x *= scale; y *= scale; z *= scale;
	}
	double dot(in Vector3d other) inout {
		return x * other.x + y * other.y + z * other.z;
	}
	Vector3d cross(in Vector3d other) inout {
		const Vector3d result = {
			y * other.z - z * other.y,
			z * other.x - x * other.z,
			x * other.y - y * other.x
		};
		return result;
	}
}

1) I initialize the vector to a null vector, not nans
2) The dot and cross are "inout" methods, i.e. available for 
mutable, const, and immutable objects.  There is no reason to 
declare "inout" methods as being "const".
3) The dot and cross methods take an input "in" argument.  This 
allows the compiler to choose between passing the parameter by 
const value or const reference.  I read somewhere that "in" and 
"scope" have not yet been implemented yet and that I should use 
"const ref" instead?
4) Is it advisable for the cross method to return by value?  In 
C++, I would declare this method as inline and in a header file.  
Can I trust D to inline away this inefficiency?  Perhaps I should 
pass in the result as a "ref" or "out" parameter (although I 
don't require the vector to be initialized here)?  Is there a 
more efficient way to do this?
5) I notice that a lot of other people online prefer using fixed 
arrays not structs for Vectors in D, why?
6) Any other comments or suggestions?
Feb 03 2014
next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Brenton:

 1) I initialize the vector to a null vector, not nans
Why?
 2) The dot and cross are "inout" methods, i.e. available for 
 mutable, const, and immutable objects.  There is no reason to 
 declare "inout" methods as being "const".
But I suggest to add pure/nothrow.
 3) The dot and cross methods take an input "in" argument.  This 
 allows the compiler to choose between passing the parameter by 
 const value or const reference.
This is not true. In means "const scope", so it's always passed by value. Bye, bearophile
Feb 03 2014
prev sibling next sibling parent "Craig Dillabaugh" <cdillaba cg.scs.carleton.ca> writes:
 5) I notice that a lot of other people online prefer using 
 fixed arrays not structs for Vectors in D, why?
It does make some calculations more straightforward. For example I have code that calculates distance between points as follows: double euclideanDistance( double[] pt1, double[] pt2 ) in { assert( pt1.length == pt2.length ); } body { return sqrt( 0.0.reduce!( (sum,pair) => sum + (pair[0]-pair[1])^^2)(zip(pt1, pt2)) ); } Now a point is not a vector, but they are similar in many respects. That fact that I use an array for my points makes such calculations possible. Furthermore you can always add methods to your struct that let users access the appropriate indices as x, y and z. If you use UFCS (I haven't yet) you could make these appear to user code just as if you had named your variables x, y, and z. Finally, maybe as some point you want to support vectors of varied dimension ... it then becomes easier to port your struct.
 6) Any other comments or suggestions?
Once you have your design more or less settled you should make it generic (if not for practical reasons just for fun and experience). You likely want your type to support only floating-point values, so you can see here how types can be restricted to FP (see line 50). https://github.com/craig-dillabaugh/phobos/blob/master/std/complex.d Thats my fork of the Phobos libraries, likely a bit out of date, but I was too lazy to look up the prope URL.
Feb 03 2014
prev sibling next sibling parent "Martijn Pot" <martijnpot52 gmail.com> writes:
On Monday, 3 February 2014 at 20:10:59 UTC, Brenton wrote:

 	double dot(in Vector3d other) inout {
 		return x * other.x + y * other.y + z * other.z;
 	}
 	Vector3d cross(in Vector3d other) inout {
 		const Vector3d result = {
 			y * other.z - z * other.y,
 			z * other.x - x * other.z,
 			x * other.y - y * other.x
 		};
 		return result;
 	}
 }
Shouldn't these functions be non-member: double dot(in Vector3d one, in Vector3d other) {} Vector3d cross(in Vector3d one, in Vector3d other) {} No one Vector3d is more special in these functions, so treat them equal.
Feb 03 2014
prev sibling next sibling parent reply "Stanislav Blinov" <stanislav.blinov gmail.com> writes:
On Monday, 3 February 2014 at 20:10:59 UTC, Brenton wrote:

 4) Is it advisable for the cross method to return by value?  In 
 C++, I would declare this method as inline and in a header 
 file.  Can I trust D to inline away this inefficiency?  Perhaps 
 I should pass in the result as a "ref" or "out" parameter 
 (although I don't require the vector to be initialized here)?  
 Is there a more efficient way to do this?
Seeing as previous responses skipped over this point: Yes, return by value. The compiler will optimize that for you by moving (not copying) the result. Return-by-value (and optimizations involved) is one of the stronger things in D that IIRC was there even before e.g. C++11 with its move semantics. Performing a move means that it is absolutely possible for clever compiler to even construct the value in-place, but I'm not sure if any of existing D compilers do that as of yet. Return-by-value being optimized as a move might be one more reason why you would like to use slices instead of variables to store coordinates (since that would mean just moving a pointer and a size_t), but that might have to wait until custom allocators finally arrive.
Feb 03 2014
parent reply Marco Leise <Marco.Leise gmx.de> writes:
Am Mon, 03 Feb 2014 22:01:14 +0000
schrieb "Stanislav Blinov" <stanislav.blinov gmail.com>:

 Return-by-value being optimized as a move might be one more 
 reason why you would like to use slices instead of variables to 
 store coordinates (since that would mean just moving a pointer 
 and a size_t), but that might have to wait until custom 
 allocators finally arrive.
3 doubles is only one machine word more than an array slice and there are no indirections, allocations and length attribute to deal with (which is always 3 here). -- Marco
Feb 06 2014
parent reply "Stanislav Blinov" <stanislav.blinov gmail.com> writes:
On Friday, 7 February 2014 at 04:03:58 UTC, Marco Leise wrote:
 Am Mon, 03 Feb 2014 22:01:14 +0000
 schrieb "Stanislav Blinov" <stanislav.blinov gmail.com>:

 Return-by-value being optimized as a move might be one more 
 reason why you would like to use slices...
 3 doubles is only one machine word more than an array slice
 and there are no indirections, allocations and length
 attribute to deal with (which is always 3 here).
I know. I also know that people making games are obsessed with performance :) And, where there's 3d vector, there would also be 4d vector and matrices...
Feb 07 2014
parent reply "Casper =?UTF-8?B?RsOmcmdlbWFuZCI=?= <shorttail gmail.com> writes:
On Friday, 7 February 2014 at 10:50:49 UTC, Stanislav Blinov 
wrote:
 I know. I also know that people making games are obsessed with 
 performance :)

 And, where there's 3d vector, there would also be 4d vector and 
 matrices...
Wouldn't it make more sense to aim for a float SIMD implementation instead then? :P
Feb 07 2014
parent "Stanislav Blinov" <stanislav.blinov gmail.com> writes:
On Friday, 7 February 2014 at 21:37:26 UTC, Casper Færgemand 
wrote:
 On Friday, 7 February 2014 at 10:50:49 UTC, Stanislav Blinov 
 wrote:
 I know. I also know that people making games are obsessed with 
 performance :)

 And, where there's 3d vector, there would also be 4d vector 
 and matrices...
Wouldn't it make more sense to aim for a float SIMD implementation instead then? :P
It may well be :D
Feb 07 2014
prev sibling parent "Francesco Cattoglio" <francesco.cattoglio gmail.com> writes:
On Monday, 3 February 2014 at 20:10:59 UTC, Brenton wrote:
 6) Any other comments or suggestions?
I know that the "I'm learning the language" factor plays a huge role, but after you are done studying your vector implementation, I think you could forget about it and use the ones provided by other libraries :P If you didn't knew about it, DUB is a marvelous software that gives you quick access to lots of nice libraries. EG: one you might be interested in is http://code.dlang.org/packages/gl3n Another one *might* be gfm: http://code.dlang.org/packages/gfm I'm also wondering where the hell did I put my raytracer code I did ages ago...
Feb 04 2014