1 /+ 2 + License: 3 + The MIT License (MIT) 4 + 5 + Copyright (c) <2013> <Oleg Butko (deviator), Anton Akzhigitov (Akzwar)> 6 + 7 + Permission is hereby granted, free of charge, to any person obtaining a copy 8 + of this software and associated documentation files (the "Software"), to deal 9 + in the Software without restriction, including without limitation the rights 10 + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 + copies of the Software, and to permit persons to whom the Software is 12 + furnished to do so, subject to the following conditions: 13 + 14 + The above copyright notice and this permission notice shall be included in 15 + all copies or substantial portions of the Software. 16 + 17 + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 + THE SOFTWARE. 24 +/ 25 26 /++ 27 Provides work with vector and some aliases and functions. 28 +/ 29 30 module des.math.linear.vector; 31 32 import std.math; 33 import std.algorithm; 34 import std.array; 35 import std.traits; 36 import std.exception; 37 import std.string; 38 39 import des.util.testsuite; 40 41 import des.math.util; 42 43 version(unittest) import std.stdio; 44 45 /// checks type is vector 46 template isVector(E) 47 { 48 enum isVector = is( typeof(impl(E.init)) ); 49 void impl(size_t N,T,alias string AS)( in Vector!(N,T,AS) ) {} 50 } 51 52 /// checks type is static vector 53 template isStaticVector(E) 54 { 55 static if( !isVector!E ) 56 enum isStaticVector = false; 57 else enum isStaticVector = E.isStatic; 58 } 59 60 /// checks type is dynamic vector 61 template isDynamicVector(E) 62 { 63 static if( !isVector!E ) 64 enum isDynamicVector = false; 65 else enum isDynamicVector = E.isDynamic; 66 } 67 68 unittest 69 { 70 static assert( !isStaticVector!float ); 71 static assert( !isDynamicVector!float ); 72 } 73 74 /// сhecks type E is vector and E.dims == N and E.datatype can casted to T 75 template isCompatibleVector(size_t N,T,E) 76 { 77 static if( !isVector!E ) 78 enum isCompatibleVector = false; 79 else enum isCompatibleVector = E.dims == N && is( E.datatype : T ); 80 } 81 82 /++ 83 validate operation between types `T` and `E` 84 code: 85 mixin( `return is( typeof( T.init ` ~ op ~ ` E.init ) : K );` ); 86 +/ 87 bool isValidOp(string op,T,E,K=T)() pure 88 { mixin( `return is( typeof( T.init ` ~ op ~ ` E.init ) : K );` ); } 89 90 bool hasCompMltAndSum(T,E)() pure 91 { return is( typeof( T(T.init * E.init) ) ) && is( typeof( T.init + T.init ) == T ); } 92 93 /// vector value access string element separator = `" "` 94 enum VVASES = " "; 95 /// vector value access string variant separator = `"|"` 96 enum VVASVS = "|"; 97 98 private @property string zerosVectorData(size_t N)() 99 { 100 string[] ret; 101 foreach( j; 0 .. N ) 102 ret ~= format( "%d", 0 ); 103 return "[" ~ ret.join(",") ~ "]"; 104 } 105 106 /++ 107 Params: 108 N = Number of dimmensions. 109 Vector can be dynamic (`N==0`) or static (`N>0`). 110 T = Vector data type. 111 AS = Access string. 112 Must be valid access string ( see: [isCompatibleArrayAccessStrings](des/math/util/accessstring/isCompatibleArrayAccessStrings.html) ) 113 +/ 114 struct Vector( size_t N, T, alias string AS="") 115 if( isCompatibleArrayAccessStrings(N,AS,VVASES,VVASVS) || AS.length == 0 ) 116 { 117 /// `N == 0` 118 enum bool isDynamic = N == 0; 119 /// `N != 0` 120 enum bool isStatic = N != 0; 121 /// equals N 122 enum size_t dims = N; 123 124 /// 125 static if( isStatic ) 126 { 127 static if( !isNumeric!T ) 128 /// if `isStatic` ( fills by zeros if `isNumeric!T` ) 129 T[N] data; 130 else T[N] data = mixin( zerosVectorData!N ); 131 } 132 else T[] data; /// if `isDynamic` 133 134 /// 135 alias data this; 136 137 /// 138 alias datatype = T; 139 140 /// 141 alias access_string = AS; 142 143 /// 144 alias selftype = Vector!(N,T,AS); 145 146 pure: 147 148 static if( isDynamic ) 149 { 150 /++ 151 Length of elements. 152 Enum, if vector is static. 153 +/ 154 pure @property auto length() const { return data.length; } 155 156 ///ditto 157 pure @property auto length( size_t nl ) 158 { 159 data.length = nl; 160 return data.length; 161 } 162 } 163 else enum length = N; 164 165 /++ 166 + Vector can be constructed with different ways: 167 168 + * from single values 169 + * from arrays 170 + * from other vectors 171 +/ 172 this(E...)( in E vals ) 173 { 174 // not work with dynamic vectors 175 static assert( is(typeof(flatData!T(vals))), "args not compatible" ); 176 177 static if( isStatic ) 178 { 179 static if( hasNoDynamic!E && E.length > 1 ) 180 { 181 static assert( getElemCount!E == N * getElemCount!T, "wrong args count" ); 182 static assert( isConvertable!(T,E), "wrong args type" ); 183 mixin( vectorStaticFill!("T","data","vals",T,E) ); 184 } 185 else 186 { 187 auto buf = flatData!T(vals); 188 189 if( buf.length == length ) 190 data[] = buf[]; 191 else if( buf.length == 1 ) 192 data[] = buf[0]; 193 else enforce( false, "bad args length" ); 194 } 195 } 196 else data = flatData!T(vals); 197 } 198 199 static if( isDynamic ) this(this) { data = this.data.dup; } 200 201 /// 202 auto opAssign( size_t K, E, alias string oas )( in Vector!(K,E,oas) b ) 203 if( (K==N||K==0||N==0) && is( typeof(T(E.init)) ) ) 204 { 205 static if( isDynamic ) length = b.length; 206 foreach( i; 0 .. length ) data[i] = T(b[i]); 207 return this; 208 } 209 210 /// 211 auto opUnary(string op)() const 212 if( op == "-" && is( typeof( T.init * (-1) ) : T ) ) 213 { 214 selftype ret; 215 static if( isDynamic ) ret.length = length; 216 foreach( i; 0 .. length ) 217 ret[i] = this[i] * -1; 218 return ret; 219 } 220 221 /++ 222 + Any binary operations execs per element 223 + See_Also: 224 + [isValidOp](des/math/linear/vector/isValidOp.html) 225 +/ 226 auto opBinary(string op, size_t K, E, alias string oas ) 227 ( in Vector!(K,E,oas) b ) const 228 if( isValidOp!(op,T,E) && (K==N||K==0||N==0) ) 229 { 230 selftype ret; 231 static if( isDynamic || b.isDynamic ) 232 enforce( length == b.length, "wrong length" ); 233 static if( isDynamic ) ret.length = length; 234 foreach( i; 0 .. length ) 235 mixin( `ret[i] = this[i] ` ~ op ~ ` b[i];` ); 236 return ret; 237 } 238 239 /// ditto 240 auto opBinary(string op, E)( in E b ) const 241 if( isValidOp!(op,T,E) && op != "+" && op != "-" ) 242 { 243 selftype ret; 244 static if( isDynamic ) ret.length = length; 245 foreach( i; 0 .. length ) 246 mixin( `ret[i] = this[i] ` ~ op ~ ` b;` ); 247 return ret; 248 } 249 250 /// ditto 251 auto opOpAssign(string op, E)( in E b ) 252 if( mixin( `is( typeof( this ` ~ op ~ ` b ) )` ) ) 253 { mixin( `return this = this ` ~ op ~ ` b;` ); } 254 255 /// only mul allowed 256 auto opBinaryRight(string op, E)( in E b ) const 257 if( isValidOp!(op,E,T,T) && op == "*" ) 258 { mixin( "return this " ~ op ~ " b;" ); } 259 260 /// checks all elements is finite 261 bool opCast(E)() const if( is( E == bool ) ) 262 { return all!isFinite( data.dup ); } 263 264 const @property 265 { 266 static if( is( typeof( dot(selftype.init,selftype.init) ) ) ) 267 { 268 /++ Square of euclidean length of the vector. 269 270 only: 271 if( is( typeof( dot(selftype.init,selftype.init) ) ) ) 272 +/ 273 auto len2() { return dot(this,this); } 274 275 static if( is( typeof( sqrt(CommonType!(T,float)(this.len2)) ) ) ) 276 { 277 /++ Euclidean length of the vector 278 279 only: 280 if( is( typeof( sqrt(CommonType!(T,float)(this.len2)) ) ) ) 281 +/ 282 auto len(E=CommonType!(T,float))() { return sqrt( E(len2) ); } 283 } 284 285 static if( is( typeof( this / len ) == typeof(this) ) ) 286 { 287 /++ Unit length of the vector 288 289 only: 290 if( is( typeof( this / len ) == typeof(this) ) ) 291 +/ 292 auto e() { return this / len; } 293 } 294 } 295 } 296 297 version(todos) pragma(msg, __FILE__, "TODO: rework rebase for all dimension vectors" ); 298 299 static if( N == 2 ) 300 { 301 auto rebase(I,J)( in I x, in J y ) const 302 if( isCompatibleVector!(2,T,I) && 303 isCompatibleVector!(2,T,J) ) 304 { 305 alias this m; 306 307 auto d = x[0] * y[1] - y[0] * x[1]; 308 auto rx = m[0] * y[1] - y[0] * m[1]; 309 auto ry = x[0] * m[1] - m[0] * x[1]; 310 311 return selftype( rx/d, ry/d ); 312 } 313 } 314 315 static if( N == 3 ) 316 { 317 auto rebase(I,J,K)( in I x, in J y, in K z ) const 318 if( isCompatibleVector!(3,T,I) && 319 isCompatibleVector!(3,T,J) && 320 isCompatibleVector!(3,T,K) ) 321 { 322 alias this m; 323 324 auto a1 = (y[1] * z[2] - z[1] * y[2]); 325 auto a2 = -(x[1] * z[2] - z[1] * x[2]); 326 auto a3 = (x[1] * y[2] - y[1] * x[2]); 327 328 auto x2 = -(m[1] * z[2] - z[1] * m[2]); 329 auto x3 = (m[1] * y[2] - y[1] * m[2]); 330 331 auto y1 = (m[1] * z[2] - z[1] * m[2]); 332 auto y3 = (x[1] * m[2] - m[1] * x[2]); 333 334 auto z1 = (y[1] * m[2] - m[1] * y[2]); 335 auto z2 = -(x[1] * m[2] - m[1] * x[2]); 336 337 auto ad1 = x[0] * a1; 338 auto ad2 = y[0] * a2; 339 auto ad3 = z[0] * a3; 340 341 auto d = x[0] * a1 + y[0] * a2 + z[0] * a3; 342 343 auto nxd = m[0] * a1 + y[0] * x2 + z[0] * x3; 344 auto nyd = x[0] * y1 + m[0] * a2 + z[0] * y3; 345 auto nzd = x[0] * z1 + y[0] * z2 + m[0] * a3; 346 347 return selftype( nxd/d, nyd/d, nzd/d ); 348 } 349 } 350 351 static if( AS.length > 0 ) 352 { 353 @property 354 { 355 /++ 356 Get/set element data by access string. 357 358 only: 359 if( AS.length > 0 ) 360 +/ 361 ref T opDispatch(string v)() 362 if( getIndex(AS,v,VVASES,VVASVS) != -1 ) 363 { mixin( format( "return data[%d];", getIndex(AS,v,VVASES,VVASVS) ) ); } 364 365 ///ditto 366 T opDispatch(string v)() const 367 if( getIndex(AS,v,VVASES,VVASVS) != -1 ) 368 { mixin( format( "return data[%d];", getIndex(AS,v,VVASES,VVASVS) ) ); } 369 370 static if( isOneSymbolPerFieldForAnyAccessString(AS,VVASES,VVASVS) ) 371 { 372 /++ 373 Get/set vector by access string. 374 375 only: 376 if( AS.length > 0 && isOneSymbolPerFieldForAnyAccessString(AS,VVASES,VVASVS) ) 377 +/ 378 auto opDispatch(string v)() const 379 if( v.length > 1 && oneOfAnyAccessAll(AS,v,VVASES,VVASVS) ) 380 { 381 mixin( format( `return Vector!(v.length,T,"%s")(%s);`, 382 isCompatibleArrayAccessString(v.length,v)?v.split("").join(VVASES):"", 383 array( map!(a=>format( `data[%d]`,getIndex(AS,a,VVASES,VVASVS)))(v.split("")) ).join(",") 384 )); 385 } 386 387 ///ditto 388 auto opDispatch( string v, U )( in U b ) 389 if( v.length > 1 && oneOfAnyAccessAll(AS,v,VVASES,VVASVS) && isCompatibleArrayAccessString(v.length,v) && 390 ( isCompatibleVector!(v.length,T,U) || ( isDynamicVector!U && is(typeof(T(U.datatype.init))) ) ) ) 391 { 392 static if( b.isDynamic ) enforce( v.length == b.length ); 393 foreach( i; 0 .. v.length ) 394 data[getIndex(AS,""~v[i],VVASES,VVASVS)] = T( b[i] ); 395 return opDispatch!v; 396 } 397 } 398 } 399 } 400 } 401 402 /// `"x y|u v"` 403 private enum string AS2D = "x y|w h|u v"; 404 /// `"x y z|u v t|r g b"` 405 private enum string AS3D = "x y z|u v t|r g b"; 406 /// `"x y z w|r g b a"` 407 private enum string AS4D = "x y z w|r g b a"; 408 409 /// 410 alias Vector2(T) = Vector!(2,T,AS2D); 411 /// 412 alias Vector3(T) = Vector!(3,T,AS3D); 413 /// 414 alias Vector4(T) = Vector!(4,T,AS4D); 415 416 /// 417 alias Vector2!float vec2; 418 /// 419 alias Vector3!float vec3; 420 /// 421 alias Vector4!float vec4; 422 423 /// 424 alias Vector2!double dvec2; 425 /// 426 alias Vector3!double dvec3; 427 /// 428 alias Vector4!double dvec4; 429 430 /// 431 alias Vector2!real rvec2; 432 /// 433 alias Vector3!real rvec3; 434 /// 435 alias Vector4!real rvec4; 436 437 /// 438 alias Vector2!byte bvec2; 439 /// 440 alias Vector3!byte bvec3; 441 /// 442 alias Vector4!byte bvec4; 443 444 /// 445 alias Vector2!ubyte ubvec2; 446 /// 447 alias Vector3!ubyte ubvec3; 448 /// 449 alias Vector4!ubyte ubvec4; 450 451 /// 452 alias Vector2!int ivec2; 453 /// 454 alias Vector3!int ivec3; 455 /// 456 alias Vector4!int ivec4; 457 458 /// 459 alias Vector2!uint uivec2; 460 /// 461 alias Vector3!uint uivec3; 462 /// 463 alias Vector4!uint uivec4; 464 465 /// 466 alias Vector2!long lvec2; 467 /// 468 alias Vector3!long lvec3; 469 /// 470 alias Vector4!long lvec4; 471 472 /// 473 alias Vector2!ulong ulvec2; 474 /// 475 alias Vector3!ulong ulvec3; 476 /// 477 alias Vector4!ulong ulvec4; 478 479 /// 480 alias Vector!(3,float,"r g b") col3; 481 /// 482 alias Vector!(4,float,"r g b a") col4; 483 484 /// 485 alias Vector!(3,ubyte,"r g b") ubcol3; 486 /// 487 alias Vector!(4,ubyte,"r g b a") ubcol4; 488 489 unittest 490 { 491 static assert( is( Vector2!float == vec2 ) ); 492 static assert( is( Vector3!real == rvec3 ) ); 493 static assert( is( Vector4!float == vec4 ) ); 494 } 495 496 /// 497 alias Vector!(0,byte) bvecD; 498 /// 499 alias Vector!(0,ubyte) ubvecD; 500 /// 501 alias Vector!(0,int) ivecD; 502 /// 503 alias Vector!(0,uint) uivecD; 504 /// 505 alias Vector!(0,short) svecD; 506 /// 507 alias Vector!(0,ushort)usvecD; 508 /// 509 alias Vector!(0,long) lvecD; 510 /// 511 alias Vector!(0,ulong) ulvecD; 512 /// 513 alias Vector!(0,float) vecD; 514 /// 515 alias Vector!(0,double) dvecD; 516 /// 517 alias Vector!(0,real) rvecD; 518 519 unittest 520 { 521 static assert( isVector!vec2 ); 522 static assert( isVector!vec3 ); 523 static assert( isVector!vec4 ); 524 static assert( isVector!dvec2 ); 525 static assert( isVector!dvec3 ); 526 static assert( isVector!dvec4 ); 527 static assert( isVector!ivec2 ); 528 static assert( isVector!ivec3 ); 529 static assert( isVector!ivec4 ); 530 static assert( isVector!col3 ); 531 static assert( isVector!col4 ); 532 static assert( isVector!ubcol3 ); 533 static assert( isVector!ubcol4 ); 534 static assert( isVector!vecD ); 535 static assert( isVector!ivecD ); 536 static assert( isVector!dvecD ); 537 538 static assert( isCompatibleVector!(2,float,vec2) ); 539 static assert( isCompatibleVector!(3,float,vec3) ); 540 static assert( isCompatibleVector!(4,float,vec4) ); 541 static assert( isCompatibleVector!(2,double,dvec2) ); 542 static assert( isCompatibleVector!(3,double,dvec3) ); 543 static assert( isCompatibleVector!(4,double,dvec4) ); 544 static assert( isCompatibleVector!(2,int,ivec2) ); 545 static assert( isCompatibleVector!(3,int,ivec3) ); 546 static assert( isCompatibleVector!(4,int,ivec4) ); 547 static assert( isCompatibleVector!(3,float,col3) ); 548 static assert( isCompatibleVector!(4,float,col4) ); 549 static assert( isCompatibleVector!(3,ubyte,ubcol3) ); 550 static assert( isCompatibleVector!(4,ubyte,ubcol4) ); 551 static assert( !isCompatibleVector!(2,ubyte,ubcol3) ); 552 static assert( !isCompatibleVector!(3,ubyte,ubcol4) ); 553 } 554 555 /// 556 unittest 557 { 558 static assert( Vector!(3,float).isStatic == true ); 559 static assert( Vector!(3,float).isDynamic == false ); 560 561 static assert( Vector!(0,float).isStatic == false ); 562 static assert( Vector!(0,float).isDynamic == true ); 563 564 static assert( isVector!(Vector!(3,float)) ); 565 static assert( isVector!(Vector!(0,float)) ); 566 567 static assert( !__traits(compiles,Vector!(3,float,"x y")) ); 568 static assert( !__traits(compiles,Vector!(3,float,"x y")) ); 569 static assert( __traits(compiles,Vector!(3,float,"x y z")) ); 570 571 static assert( Vector!(3,float,"x y z").sizeof == float.sizeof * 3 ); 572 static assert( Vector!(0,float).sizeof == (float[]).sizeof ); 573 574 static assert( Vector!(3,float,"x y z").length == 3 ); 575 } 576 577 /// 578 unittest 579 { 580 assert( eq( Vector!(3,float)(1,2,3), [1,2,3] ) ); 581 582 auto a = Vector!(3,float)(1,2,3); 583 assert( eq( Vector!(5,int)(0,a,4), [0,1,2,3,4] ) ); 584 585 static assert( !__traits(compiles, { auto v = Vector!(2,int)(1,2,3); } ) ); 586 assert( !mustExcept( { auto v = Vector!(0,int)(1,2,3); } ) ); 587 assert( !mustExcept( { auto v = Vector!(3,int)(1); } ) ); 588 auto b = Vector!(0,float)(1,2,3); 589 assert( b.length == 3 ); 590 591 auto c = Vector!(3,float)(1); 592 assert( eq( c, [1,1,1] ) ); 593 auto d = c; 594 assert( eq( c, d ) ); 595 } 596 597 /// 598 unittest 599 { 600 static struct Test1 { float x,y,z; } 601 static assert( !__traits(compiles,Vector!(3,float)(Test1.init)) ); 602 603 static struct Test2 { float[3] data; } 604 static assert( __traits(compiles,Vector!(3,float)(Test2.init)) ); 605 } 606 607 unittest 608 { 609 auto a = vec3(1,2,3); 610 611 auto a1 = const vec3(a); 612 auto a2 = const vec3(1,2,3); 613 auto a3 = const vec3(1); 614 615 auto a4 = shared vec3(a); 616 auto a5 = shared vec3(1,2,3); 617 auto a6 = shared vec3(1); 618 619 auto a7 = immutable vec3(a); 620 auto a8 = immutable vec3(1,2,3); 621 auto a9 = immutable vec3(1); 622 623 auto a10 = shared const vec3(a); 624 auto a11 = shared const vec3(1,2,3); 625 auto a12 = shared const vec3(1); 626 627 assert( eq( a, a1 ) ); 628 assert( eq( a, a4 ) ); 629 assert( eq( a, a7 ) ); 630 assert( eq( a, a10 ) ); 631 632 a = vec3(a4.data); 633 } 634 635 /// convert vectors 636 unittest 637 { 638 auto a = ivec2(1,2); 639 auto b = vec2(a); 640 assert( eq( a, b ) ); 641 auto c = ivec2(b); 642 assert( eq( a, c ) ); 643 } 644 645 unittest 646 { 647 auto a = vec3(2); 648 assert( eq( -a, [-2,-2,-2] ) ); 649 } 650 651 /// 652 unittest 653 { 654 auto a = Vector!(3,int,"x y z|u v t|r g b")(1,2,3); 655 assert( a.x == a.r ); 656 assert( a.y == a.g ); 657 assert( a.z == a.b ); 658 assert( a.x == a.u ); 659 assert( a.y == a.v ); 660 assert( a.z == a.t ); 661 662 auto b = Vector!(2,int,"near far|n f")(1,100); 663 assert( b.near == b.n ); 664 assert( b.far == b.f ); 665 666 b.nf = ivec2( 10,20 ); 667 assert( b.near == 10 ); 668 assert( b.far == 20 ); 669 } 670 671 /// 672 unittest 673 { 674 auto a = vec3(1,2,3); 675 auto b = vecD(1,2,3); 676 auto c = a + b; 677 assert( is( typeof(c) == vec3 ) ); 678 auto d = b + a; 679 assert( is( typeof(d) == vecD ) ); 680 assert( eq(c,d) ); 681 auto f = ivec3(1,2,3); 682 auto c1 = a + f; 683 assert( is( typeof(c1) == vec3 ) ); 684 auto d1 = ivec3(f) + ivec3(a); 685 assert( is( typeof(d1) == ivec3 ) ); 686 assert( eq(c1,d) ); 687 assert( eq(c,d1) ); 688 689 a *= 2; 690 b *= 2; 691 auto e = b *= 2; 692 assert( eq(a,[2,4,6]) ); 693 assert( eq(b,a*2) ); 694 695 auto x = 2 * a; 696 assert( eq(x,[4,8,12]) ); 697 698 assert( !!x ); 699 x[0] = float.nan; 700 assert( !x ); 701 } 702 703 /// 704 unittest 705 { 706 auto a = vecD(1,2,3); 707 708 auto b = vec3(a); 709 auto c = vecD(b); 710 711 assert( eq( a, b ) ); 712 assert( eq( a, c ) ); 713 } 714 /// 715 unittest 716 { 717 auto a = vec3(2,2,1); 718 assert( eq(a.rebase(vec3(2,0,0),vec3(0,2,0),vec3(0,0,2)), [1,1,.5] ) ); 719 } 720 721 /// 722 unittest 723 { 724 auto a = vec3(1,2,3); 725 726 assert( a.opDispatch!"x" == 1 ); 727 assert( a.y == 2 ); 728 assert( a.z == 3 ); 729 730 a.x = 2; 731 assert( a.x == 2 ); 732 } 733 734 /// 735 unittest 736 { 737 alias Vector!(4,float,"x y dx dy") vec2p; 738 739 auto a = vec2p(1,2,0,0); 740 741 assert( a.opDispatch!"x" == 1 ); 742 assert( a.dx == 0 ); 743 } 744 745 /// 746 unittest 747 { 748 auto a = vec3(1,2,3); 749 750 auto b = a.opDispatch!"xy"; 751 auto c = a.xx; 752 auto d = a.xxxyyzyx; 753 754 static assert( is(typeof(b) == Vector!(2,float,"x y") ) ); 755 static assert( is(typeof(c) == Vector!(2,float) ) ); 756 static assert( is(typeof(d) == Vector!(8,float) ) ); 757 758 assert( eq( b, [1,2] ) ); 759 assert( eq( c, [1,1] ) ); 760 assert( eq( d, [1,1,1,2,2,3,2,1] ) ); 761 } 762 763 /// 764 unittest 765 { 766 auto a = vec3(1,2,3); 767 auto b = dvec4(4,5,6,7); 768 auto c = vecD( 9, 10 ); 769 a.xz = b.yw; 770 assert( eq( a, [5,2,7] ) ); 771 a.zy = c; 772 assert( eq( a, [5,10,9] ) ); 773 static assert( !__traits(compiles, a.xy=vec3(1,2,3)) ); 774 static assert( !__traits(compiles, a.xx=vec2(1,2)) ); 775 auto d = a.zxy = b.wyx; 776 static assert( d.access_string == "z x y" ); 777 static assert( is( d.datatype == float ) ); 778 assert( eq( d, [ 7,5,4 ] ) ); 779 assert( eq( a, [ 5,4,7 ] ) ); 780 a.yzx = a.zxz; 781 assert( eq( a, [ 7,7,5 ] ) ); 782 } 783 784 /// 785 unittest 786 { 787 auto a = vec3(1,2,3); 788 auto b = ivec3(1,2,3); 789 auto k = a.len2; 790 assert( is( typeof(k) == float ) ); 791 792 auto l = b.len2; 793 assert( is( typeof(l) == int ) ); 794 795 auto m = b.len; 796 assert( is( typeof(m) == float ) ); 797 798 auto n = b.len!real; 799 assert( is( typeof(n) == real ) ); 800 801 assert( is( typeof( vec3( 1, 2, 3 ).e ) == vec3 ) ); 802 assert( abs( a.e.len - 1 ) < float.epsilon ); 803 } 804 805 /// 806 unittest 807 { 808 alias Vector!(3,cfloat) cvec3; 809 810 auto a = cvec3( 1-1i, 2, 3i ); 811 static assert( __traits(compiles, a.e) ); 812 assert( !mustExcept({ auto k = a.e; }) ); 813 } 814 815 /// 816 unittest 817 { 818 alias Vector!(3,Vector!(3,float)) mat3; 819 auto a = mat3( vec3(1,0,0), vec3(0,1,0), vec3(0,0,1) ); 820 821 a *= 2; 822 a += a; 823 824 assert( a[0][0] == 4 ); 825 assert( a[1][1] == 4 ); 826 assert( a[2][2] == 4 ); 827 828 assert( a[0][1] == 0 ); 829 assert( a[1][2] == 0 ); 830 assert( a[2][1] == 0 ); 831 832 a ^^= 2; 833 834 assert( a[0][0] == 16 ); 835 assert( a[1][1] == 16 ); 836 assert( a[2][2] == 16 ); 837 838 auto b = -a; 839 840 assert( b[0][0] == -16 ); 841 assert( b[1][1] == -16 ); 842 assert( b[2][2] == -16 ); 843 } 844 845 unittest 846 { 847 auto a = vecD(1,2,3); 848 auto b = a; 849 assert( eq(a,b) ); 850 b[0] = 111; 851 assert( !eq(a,b) ); 852 853 vecD c; 854 c = b; 855 assert( eq(c,b) ); 856 b[0] = 222; 857 assert( !eq(c,b) ); 858 } 859 860 unittest 861 { 862 auto a = vec3(1,2,3); 863 auto b = a; 864 assert( eq(a,b) ); 865 b[0] = 111; 866 assert( !eq(a,b) ); 867 } 868 869 /// dot multiplication for compaitable vectors. 870 auto dot( size_t N, size_t K, T,E, alias string S1, alias string S2 )( in Vector!(N,T,S1) a, in Vector!(K,E,S2) b ) 871 if( (N==K||K==0||N==0) && hasCompMltAndSum!(T,E) ) 872 { 873 static if( a.isDynamic || b.isDynamic ) 874 { 875 enforce( a.length == b.length, "wrong length" ); 876 enforce( a.length > 0, "zero length" ); 877 } 878 T ret = a[0] * b[0]; 879 foreach( i; 1 .. a.length ) 880 ret = ret + T( a[i] * b[i] ); 881 return ret; 882 } 883 884 /// 885 unittest 886 { 887 auto a = vec3(1,2,3); 888 auto b = vecD(1,2,3); 889 890 assert( eq( dot(a,b), 1+4+9 ) ); 891 } 892 893 /// cross multiplication for compaitable vectors. 894 auto cross( size_t N, size_t K, T,E, alias string S1, alias string S2 )( in Vector!(N,T,S1) a, in Vector!(K,E,S2) b ) 895 if( ((K==3||K==0)&&(N==3||N==0)) && hasCompMltAndSum!(T,E) ) 896 { 897 static if( a.isDynamic ) enforce( a.length == 3, "wrong length a" ); 898 static if( b.isDynamic ) enforce( b.length == 3, "wrong length b" ); 899 900 a.selftype ret; 901 static if( a.isDynamic ) ret.length = 3; 902 ret[0] = T(a[1] * b[2]) - T(a[2] * b[1]); 903 ret[1] = T(a[2] * b[0]) - T(a[0] * b[2]); 904 ret[2] = T(a[0] * b[1]) - T(a[1] * b[0]); 905 return ret; 906 } 907 908 /// 909 unittest 910 { 911 auto x = vec3(1,0,0); 912 auto y = vecD(0,1,0); 913 auto z = vecD(0,0,1); 914 915 assert( eq( cross(x,y), z ) ); 916 assert( eq( cross(y,z), x ) ); 917 assert( eq( cross(y,x), -z ) ); 918 assert( eq( cross(x,z), -y ) ); 919 assert( eq( cross(z,x), y ) ); 920 921 auto fy = vecD(0,1,0,0); 922 assert( mustExcept({ auto fz = x * fy; }) ); 923 auto cfy = vec4(0,1,0,0); 924 static assert( !__traits(compiles,x*cfy) ); 925 }