5 /*----------------------------------------------------------------------
6 Copyright (c) 2004 Open Dynamics Framework Group
10 Redistribution and use in source and binary forms, with or without modification, are permitted provided
11 that the following conditions are met:
13 Redistributions of source code must retain the above copyright notice, this list of conditions
14 and the following disclaimer.
16 Redistributions in binary form must reproduce the above copyright notice,
17 this list of conditions and the following disclaimer in the documentation
18 and/or other materials provided with the distribution.
20 Neither the name of the Open Dynamics Framework Group nor the names of its contributors may
21 be used to endorse or promote products derived from this software without specific prior written permission.
23 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 DISCLAIMED. IN NO EVENT SHALL THE INTEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
28 IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 -----------------------------------------------------------------------*/
32 // http://codesuppository.blogspot.com
34 // mailto: jratcliff@infiniplex.net
36 // http://www.amillionpixels.us
40 #pragma warning(disable:4786)
46 namespace ConvexDecomposition
50 const float DEG_TO_RAD = ((2.0f * 3.14152654f) / 360.0f);
51 const float RAD_TO_DEG = (360.0f / (2.0f * 3.141592654f));
56 Vector3d(void) { }; // null constructor, does not inialize point.
58 Vector3d(const Vector3d &a) // constructor copies existing vector.
65 Vector3d(float a,float b,float c) // construct with initial point.
72 Vector3d(const float *t)
79 Vector3d(const int *t)
86 bool operator==(const Vector3d &a) const
88 return( a.x == x && a.y == y && a.z == z );
91 bool operator!=(const Vector3d &a) const
93 return( a.x != x || a.y != y || a.z != z );
97 Vector3d& operator = (const Vector3d& A) // ASSIGNMENT (=)
98 { x=A.x; y=A.y; z=A.z;
101 Vector3d operator + (const Vector3d& A) const // ADDITION (+)
102 { Vector3d Sum(x+A.x, y+A.y, z+A.z);
105 Vector3d operator - (const Vector3d& A) const // SUBTRACTION (-)
106 { Vector3d Diff(x-A.x, y-A.y, z-A.z);
109 Vector3d operator * (const float s) const // MULTIPLY BY SCALAR (*)
110 { Vector3d Scaled(x*s, y*s, z*s);
114 Vector3d operator + (const float s) const // ADD CONSTANT TO ALL 3 COMPONENTS (*)
115 { Vector3d Scaled(x+s, y+s, z+s);
121 Vector3d operator / (const float s) const // DIVIDE BY SCALAR (/)
124 Vector3d Scaled(x*r, y*r, z*r);
128 void operator /= (float A) // ACCUMULATED VECTOR ADDITION (/=)
129 { x/=A; y/=A; z/=A; };
131 void operator += (const Vector3d A) // ACCUMULATED VECTOR ADDITION (+=)
132 { x+=A.x; y+=A.y; z+=A.z; };
133 void operator -= (const Vector3d A) // ACCUMULATED VECTOR SUBTRACTION (+=)
134 { x-=A.x; y-=A.y; z-=A.z; };
135 void operator *= (const float s) // ACCUMULATED SCALAR MULTIPLICATION (*=) (bpc 4/24/2000)
138 void operator += (const float A) // ACCUMULATED VECTOR ADDITION (+=)
139 { x+=A; y+=A; z+=A; };
142 Vector3d operator - (void) const // NEGATION (-)
143 { Vector3d Negated(-x, -y, -z);
146 float operator [] (const int i) const // ALLOWS VECTOR ACCESS AS AN ARRAY.
147 { return( (i==0)?x:((i==1)?y:z) ); };
148 float & operator [] (const int i)
149 { return( (i==0)?x:((i==1)?y:z) ); };
153 float GetX(void) const { return x; };
154 float GetY(void) const { return y; };
155 float GetZ(void) const { return z; };
157 float X(void) const { return x; };
158 float Y(void) const { return y; };
159 float Z(void) const { return z; };
161 void SetX(float t) { x = t; };
162 void SetY(float t) { y = t; };
163 void SetZ(float t) { z = t; };
165 bool IsSame(const Vector3d &v,float epsilon) const
167 float dx = fabsf( x - v.x );
168 if ( dx > epsilon ) return false;
169 float dy = fabsf( y - v.y );
170 if ( dy > epsilon ) return false;
171 float dz = fabsf( z - v.z );
172 if ( dz > epsilon ) return false;
177 float ComputeNormal(const Vector3d &A,
181 float vx,vy,vz,wx,wy,wz,vw_x,vw_y,vw_z,mag;
191 vw_x = vy * wz - vz * wy;
192 vw_y = vz * wx - vx * wz;
193 vw_z = vx * wy - vy * wx;
195 mag = sqrtf((vw_x * vw_x) + (vw_y * vw_y) + (vw_z * vw_z));
197 if ( mag < 0.000001f )
214 void ScaleSumScale(float c0,float c1,const Vector3d &pos)
216 x = (x*c0) + (pos.x*c1);
217 y = (y*c0) + (pos.y*c1);
218 z = (z*c0) + (pos.z*c1);
228 void Get(float *v) const
235 void Set(const int *p)
242 void Set(const float *p)
250 void Set(float a,float b,float c)
262 const float* Ptr() const { return &x; }
263 float* Ptr() { return &x; }
267 Vector3d negative(void) const
276 float Magnitude(void) const
278 return float(sqrt(x * x + y * y + z * z));
281 float FastMagnitude(void) const
283 return float(sqrtf(x * x + y * y + z * z));
286 float FasterMagnitude(void) const
288 return float(sqrtf(x * x + y * y + z * z));
291 void Lerp(const Vector3d& from,const Vector3d& to,float slerp)
293 x = ((to.x - from.x) * slerp) + from.x;
294 y = ((to.y - from.y) * slerp) + from.y;
295 z = ((to.z - from.z) * slerp) + from.z;
298 // Highly specialized interpolate routine. Will compute the interpolated position
299 // shifted forward or backwards along the ray defined between (from) and (to).
300 // Reason for existance is so that when a bullet collides with a wall, for
301 // example, you can generate a graphic effect slightly *before* it hit the
302 // wall so that the effect doesn't sort into the wall itself.
303 void Interpolate(const Vector3d &from,const Vector3d &to,float offset)
308 float d = sqrtf( x*x + y*y + z*z );
309 float recip = 1.0f / d;
312 z*=recip; // normalize vector
313 d+=offset; // shift along ray
319 bool BinaryEqual(const Vector3d &p) const
321 const int *source = (const int *) &x;
322 const int *dest = (const int *) &p.x;
324 if ( source[0] == dest[0] &&
325 source[1] == dest[1] &&
326 source[2] == dest[2] ) return true;
331 /*bool BinaryEqual(const Vector3d<int> &p) const
333 if ( x == p.x && y == p.y && z == p.z ) return true;
340 /** Computes the reflection vector between two vectors.*/
341 void Reflection(const Vector3d &a,const Vector3d &b)// compute reflection vector.
346 float dot = a.Dot(b) * 2.0f;
357 void AngleAxis(float angle,const Vector3d& axis)
364 float Length(void) const // length of vector.
366 return float(sqrt( x*x + y*y + z*z ));
370 float ComputePlane(const Vector3d &A,
374 float vx,vy,vz,wx,wy,wz,vw_x,vw_y,vw_z,mag;
384 vw_x = vy * wz - vz * wy;
385 vw_y = vz * wx - vx * wz;
386 vw_z = vx * wy - vy * wx;
388 mag = sqrtf((vw_x * vw_x) + (vw_y * vw_y) + (vw_z * vw_z));
390 if ( mag < 0.000001f )
404 float D = 0.0f - ((x*A.x)+(y*A.y)+(z*A.z));
410 float FastLength(void) const // length of vector.
412 return float(sqrtf( x*x + y*y + z*z ));
416 float FasterLength(void) const // length of vector.
418 return float(sqrtf( x*x + y*y + z*z ));
421 float Length2(void) const // squared distance, prior to square root.
423 float l2 = x*x+y*y+z*z;
427 float Distance(const Vector3d &a) const // distance between two points.
429 Vector3d d(a.x-x,a.y-y,a.z-z);
433 float FastDistance(const Vector3d &a) const // distance between two points.
435 Vector3d d(a.x-x,a.y-y,a.z-z);
436 return d.FastLength();
439 float FasterDistance(const Vector3d &a) const // distance between two points.
441 Vector3d d(a.x-x,a.y-y,a.z-z);
442 return d.FasterLength();
446 float DistanceXY(const Vector3d &a) const
450 float dist = dx*dx + dy*dy;
454 float Distance2(const Vector3d &a) const // squared distance.
459 return dx*dx + dy*dy + dz*dz;
462 float Partial(const Vector3d &p) const
464 return (x*p.y) - (p.x*y);
467 float Area(const Vector3d &p1,const Vector3d &p2) const
469 float A = Partial(p1);
471 A+= p2.Partial(*this);
475 inline float Normalize(void) // normalize to a unit vector, returns distance.
477 float d = sqrtf( static_cast< float >( x*x + y*y + z*z ) );
492 inline float FastNormalize(void) // normalize to a unit vector, returns distance.
494 float d = sqrt( static_cast< float >( x*x + y*y + z*z ) );
509 inline float FasterNormalize(void) // normalize to a unit vector, returns distance.
511 float d = sqrtf( static_cast< float >( x*x + y*y + z*z ) );
529 float Dot(const Vector3d &a) const // computes dot product.
531 return (x * a.x + y * a.y + z * a.z );
535 Vector3d Cross( const Vector3d& other ) const
537 Vector3d result( y*other.z - z*other.y, z*other.x - x*other.z, x*other.y - y*other.x );
542 void Cross(const Vector3d &a,const Vector3d &b) // cross two vectors result in this one.
544 x = a.y*b.z - a.z*b.y;
545 y = a.z*b.x - a.x*b.z;
546 z = a.x*b.y - a.y*b.x;
549 /******************************************/
550 // Check if next edge (b to c) turns inward
552 // Edge from a to b is already in face
553 // Edge from b to c is being considered for addition to face
554 /******************************************/
555 bool Concave(const Vector3d& a,const Vector3d& b)
557 float vx,vy,vz,wx,wy,wz,vw_x,vw_y,vw_z,mag,nx,ny,nz,mag_a,mag_b;
563 mag_a = (float) sqrtf((wx * wx) + (wy * wy) + (wz * wz));
569 mag_b = (float) sqrtf((vx * vx) + (vy * vy) + (vz * vz));
571 vw_x = (vy * wz) - (vz * wy);
572 vw_y = (vz * wx) - (vx * wz);
573 vw_z = (vx * wy) - (vy * wx);
575 mag = (float) sqrtf((vw_x * vw_x) + (vw_y * vw_y) + (vw_z * vw_z));
577 // Check magnitude of cross product, which is a sine function
578 // i.e., mag (a x b) = mag (a) * mag (b) * sin (theta);
579 // If sin (theta) small, then angle between edges is very close to
580 // 180, which we may want to call a concavity. Setting the
581 // CONCAVITY_TOLERANCE value greater than about 0.01 MAY cause
582 // face consolidation to get stuck on particular face. Most meshes
583 // convert properly with a value of 0.0
585 if (mag/(mag_a*mag_b) <= 0.0f ) return true;
593 // Dot product of tri normal with cross product result will
594 // yield positive number if edges are convex (+1.0 if two tris
595 // are coplanar), negative number if edges are concave (-1.0 if
596 // two tris are coplanar.)
598 mag = ( x * nx) + ( y * ny) + ( z * nz);
600 if (mag > 0.0f ) return false;
605 bool PointTestXY(const Vector3d &i,const Vector3d &j) const
607 if (((( i.y <= y ) && ( y < j.y )) ||
608 (( j.y <= y ) && ( y < i.y ))) &&
609 ( x < (j.x - i.x) * (y - i.y) / (j.y - i.y) + i.x)) return true;
613 // test to see if this point is inside the triangle specified by
614 // these three points on the X/Y plane.
615 bool PointInTriXY(const Vector3d &p1,
617 const Vector3d &p3) const
619 float ax = p3.x - p2.x;
620 float ay = p3.y - p2.y;
621 float bx = p1.x - p3.x;
622 float by = p1.y - p3.y;
623 float cx = p2.x - p1.x;
624 float cy = p2.y - p1.y;
625 float apx = x - p1.x;
626 float apy = y - p1.y;
627 float bpx = x - p2.x;
628 float bpy = y - p2.y;
629 float cpx = x - p3.x;
630 float cpy = y - p3.y;
632 float aCROSSbp = ax*bpy - ay*bpx;
633 float cCROSSap = cx*apy - cy*apx;
634 float bCROSScp = bx*cpy - by*cpx;
636 return ((aCROSSbp >= 0.0f) && (bCROSScp >= 0.0f) && (cCROSSap >= 0.0f));
639 // test to see if this point is inside the triangle specified by
640 // these three points on the X/Y plane.
641 bool PointInTriYZ(const Vector3d &p1,
643 const Vector3d &p3) const
645 float ay = p3.y - p2.y;
646 float az = p3.z - p2.z;
647 float by = p1.y - p3.y;
648 float bz = p1.z - p3.z;
649 float cy = p2.y - p1.y;
650 float cz = p2.z - p1.z;
651 float apy = y - p1.y;
652 float apz = z - p1.z;
653 float bpy = y - p2.y;
654 float bpz = z - p2.z;
655 float cpy = y - p3.y;
656 float cpz = z - p3.z;
658 float aCROSSbp = ay*bpz - az*bpy;
659 float cCROSSap = cy*apz - cz*apy;
660 float bCROSScp = by*cpz - bz*cpy;
662 return ((aCROSSbp >= 0.0f) && (bCROSScp >= 0.0f) && (cCROSSap >= 0.0f));
666 // test to see if this point is inside the triangle specified by
667 // these three points on the X/Y plane.
668 bool PointInTriXZ(const Vector3d &p1,
670 const Vector3d &p3) const
672 float az = p3.z - p2.z;
673 float ax = p3.x - p2.x;
674 float bz = p1.z - p3.z;
675 float bx = p1.x - p3.x;
676 float cz = p2.z - p1.z;
677 float cx = p2.x - p1.x;
678 float apz = z - p1.z;
679 float apx = x - p1.x;
680 float bpz = z - p2.z;
681 float bpx = x - p2.x;
682 float cpz = z - p3.z;
683 float cpx = x - p3.x;
685 float aCROSSbp = az*bpx - ax*bpz;
686 float cCROSSap = cz*apx - cx*apz;
687 float bCROSScp = bz*cpx - bx*cpz;
689 return ((aCROSSbp >= 0.0f) && (bCROSScp >= 0.0f) && (cCROSSap >= 0.0f));
692 // Given a point and a line (defined by two points), compute the closest point
693 // in the line. (The line is treated as infinitely long.)
694 void NearestPointInLine(const Vector3d &point,
695 const Vector3d &line0,
696 const Vector3d &line1)
698 Vector3d &nearestPoint = *this;
699 Vector3d lineDelta = line1 - line0;
701 // Handle degenerate lines
702 if ( lineDelta == Vector3d(0, 0, 0) )
704 nearestPoint = line0;
708 float delta = (point-line0).Dot(lineDelta) / (lineDelta).Dot(lineDelta);
709 nearestPoint = line0 + lineDelta*delta;
713 // Given a point and a line segment (defined by two points), compute the closest point
714 // in the line. Cap the point at the endpoints of the line segment.
715 void NearestPointInLineSegment(const Vector3d &point,
716 const Vector3d &line0,
717 const Vector3d &line1)
719 Vector3d &nearestPoint = *this;
720 Vector3d lineDelta = line1 - line0;
722 // Handle degenerate lines
723 if ( lineDelta == Vector3d(0, 0, 0) )
725 nearestPoint = line0;
729 float delta = (point-line0).Dot(lineDelta) / (lineDelta).Dot(lineDelta);
731 // Clamp the point to conform to the segment's endpoints
734 else if ( delta > 1 )
737 nearestPoint = line0 + lineDelta*delta;
741 // Given a point and a plane (defined by three points), compute the closest point
742 // in the plane. (The plane is unbounded.)
743 void NearestPointInPlane(const Vector3d &point,
744 const Vector3d &triangle0,
745 const Vector3d &triangle1,
746 const Vector3d &triangle2)
748 Vector3d &nearestPoint = *this;
749 Vector3d lineDelta0 = triangle1 - triangle0;
750 Vector3d lineDelta1 = triangle2 - triangle0;
751 Vector3d pointDelta = point - triangle0;
754 // Get the normal of the polygon (doesn't have to be a unit vector)
755 normal.Cross(lineDelta0, lineDelta1);
757 float delta = normal.Dot(pointDelta) / normal.Dot(normal);
758 nearestPoint = point - normal*delta;
761 // Given a point and a plane (defined by a coplanar point and a normal), compute the closest point
762 // in the plane. (The plane is unbounded.)
763 void NearestPointInPlane(const Vector3d &point,
764 const Vector3d &planePoint,
765 const Vector3d &planeNormal)
767 Vector3d &nearestPoint = *this;
768 Vector3d pointDelta = point - planePoint;
770 float delta = planeNormal.Dot(pointDelta) / planeNormal.Dot(planeNormal);
771 nearestPoint = point - planeNormal*delta;
774 // Given a point and a triangle (defined by three points), compute the closest point
775 // in the triangle. Clamp the point so it's confined to the area of the triangle.
776 void NearestPointInTriangle(const Vector3d &point,
777 const Vector3d &triangle0,
778 const Vector3d &triangle1,
779 const Vector3d &triangle2)
781 static const Vector3d zeroVector(0, 0, 0);
783 Vector3d &nearestPoint = *this;
785 Vector3d lineDelta0 = triangle1 - triangle0;
786 Vector3d lineDelta1 = triangle2 - triangle0;
788 // Handle degenerate triangles
789 if ( (lineDelta0 == zeroVector) || (lineDelta1 == zeroVector) )
791 nearestPoint.NearestPointInLineSegment(point, triangle1, triangle2);
793 else if ( lineDelta0 == lineDelta1 )
795 nearestPoint.NearestPointInLineSegment(point, triangle0, triangle1);
801 axis[0].NearestPointInLine(triangle0, triangle1, triangle2);
802 axis[1].NearestPointInLine(triangle1, triangle0, triangle2);
803 axis[2].NearestPointInLine(triangle2, triangle0, triangle1);
806 axisDot[0] = (triangle0-axis[0]).Dot(point-axis[0]);
807 axisDot[1] = (triangle1-axis[1]).Dot(point-axis[1]);
808 axisDot[2] = (triangle2-axis[2]).Dot(point-axis[2]);
811 float bestMagnitude2 = 0;
812 float closeMagnitude2;
815 if ( axisDot[0] < 0 )
817 closePoint.NearestPointInLineSegment(point, triangle1, triangle2);
818 closeMagnitude2 = point.Distance2(closePoint);
819 if ( bForce || (bestMagnitude2 > closeMagnitude2) )
822 bestMagnitude2 = closeMagnitude2;
823 nearestPoint = closePoint;
826 if ( axisDot[1] < 0 )
828 closePoint.NearestPointInLineSegment(point, triangle0, triangle2);
829 closeMagnitude2 = point.Distance2(closePoint);
830 if ( bForce || (bestMagnitude2 > closeMagnitude2) )
833 bestMagnitude2 = closeMagnitude2;
834 nearestPoint = closePoint;
837 if ( axisDot[2] < 0 )
839 closePoint.NearestPointInLineSegment(point, triangle0, triangle1);
840 closeMagnitude2 = point.Distance2(closePoint);
841 if ( bForce || (bestMagnitude2 > closeMagnitude2) )
844 bestMagnitude2 = closeMagnitude2;
845 nearestPoint = closePoint;
849 // If bForce is true at this point, it means the nearest point lies
850 // inside the triangle; use the nearest-point-on-a-plane equation
855 // Get the normal of the polygon (doesn't have to be a unit vector)
856 normal.Cross(lineDelta0, lineDelta1);
858 Vector3d pointDelta = point - triangle0;
859 float delta = normal.Dot(pointDelta) / normal.Dot(normal);
861 nearestPoint = point - normal*delta;
878 Vector2d(void) { }; // null constructor, does not inialize point.
880 Vector2d(const Vector2d &a) // constructor copies existing vector.
886 Vector2d(const float *t)
893 Vector2d(float a,float b) // construct with initial point.
899 const float* Ptr() const { return &x; }
900 float* Ptr() { return &x; }
902 Vector2d & operator+=(const Vector2d &a) // += operator.
909 Vector2d & operator-=(const Vector2d &a)
916 Vector2d & operator*=(const Vector2d &a)
923 Vector2d & operator/=(const Vector2d &a)
930 bool operator==(const Vector2d &a) const
932 if ( a.x == x && a.y == y ) return true;
936 bool operator!=(const Vector2d &a) const
938 if ( a.x != x || a.y != y ) return true;
942 Vector2d operator+(Vector2d a) const
949 Vector2d operator-(Vector2d a) const
956 Vector2d operator - (void) const
961 Vector2d operator*(Vector2d a) const
968 Vector2d operator*(float c) const
978 Vector2d operator/(Vector2d a) const
986 float Dot(const Vector2d &a) const // computes dot product.
988 return (x * a.x + y * a.y );
991 float GetX(void) const { return x; };
992 float GetY(void) const { return y; };
994 void SetX(float t) { x = t; };
995 void SetY(float t) { y = t; };
997 void Set(float a,float b)
1008 Vector2d negative(void) const
1016 float magnitude(void) const
1018 return (float) sqrtf(x * x + y * y );
1021 float fastmagnitude(void) const
1023 return (float) sqrtf(x * x + y * y );
1026 float fastermagnitude(void) const
1028 return (float) sqrtf( x * x + y * y );
1031 void Reflection(Vector2d &a,Vector2d &b); // compute reflection vector.
1033 float Length(void) const // length of vector.
1035 return float(sqrtf( x*x + y*y ));
1038 float FastLength(void) const // length of vector.
1040 return float(sqrtf( x*x + y*y ));
1043 float FasterLength(void) const // length of vector.
1045 return float(sqrtf( x*x + y*y ));
1048 float Length2(void) // squared distance, prior to square root.
1053 float Distance(const Vector2d &a) const // distance between two points.
1057 float d = dx*dx+dy*dy;
1061 float FastDistance(const Vector2d &a) const // distance between two points.
1065 float d = dx*dx+dy*dy;
1069 float FasterDistance(const Vector2d &a) const // distance between two points.
1073 float d = dx*dx+dy*dy;
1077 float Distance2(Vector2d &a) // squared distance.
1081 return dx*dx + dy *dy;
1084 void Lerp(const Vector2d& from,const Vector2d& to,float slerp)
1086 x = ((to.x - from.x)*slerp) + from.x;
1087 y = ((to.y - from.y)*slerp) + from.y;
1091 void Cross(const Vector2d &a,const Vector2d &b) // cross two vectors result in this one.
1093 x = a.y*b.x - a.x*b.y;
1094 y = a.x*b.x - a.x*b.x;
1097 float Normalize(void) // normalize to a unit vector, returns distance.
1113 float FastNormalize(void) // normalize to a unit vector, returns distance.
1115 float l = FastLength();
1129 float FasterNormalize(void) // normalize to a unit vector, returns distance.
1131 float l = FasterLength();
1153 Line(const Vector3d &from,const Vector3d &to)
1158 // JWR Test for the intersection of two lines.
1160 bool Intersect(const Line& src,Vector3d §);
1168 typedef std::vector< Vector3d > Vector3dVector;
1169 typedef std::vector< Vector2d > Vector2dVector;
1171 inline Vector3d operator * (float s, const Vector3d &v )
1173 Vector3d Scaled(v.x*s, v.y*s, v.z*s);
1177 inline Vector2d operator * (float s, const Vector2d &v )
1179 Vector2d Scaled(v.x*s, v.y*s);