1 /+ 2 The MIT License (MIT) 3 4 Copyright (c) <2013> <Oleg Butko (deviator), Anton Akzhigitov (Akzwar)> 5 6 Permission is hereby granted, free of charge, to any person obtaining a copy 7 of this software and associated documentation files (the "Software"), to deal 8 in the Software without restriction, including without limitation the rights 9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 copies of the Software, and to permit persons to whom the Software is 11 furnished to do so, subject to the following conditions: 12 13 The above copyright notice and this permission notice shall be included in 14 all copies or substantial portions of the Software. 15 16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 THE SOFTWARE. 23 +/ 24 25 module des.math.linear.vector; 26 27 import std.math; 28 import std.algorithm; 29 import std.array; 30 import std.traits; 31 import std.exception; 32 import std.string; 33 34 import des.util.testsuite; 35 36 import des.math.util; 37 38 version(unittest) import std.stdio; 39 40 private pure void isVectorImpl(size_t N,T,alias string AS)( in Vector!(N,T,AS) ) {} 41 pure bool isVector(E)() { return is( typeof(isVectorImpl(E.init)) ); } 42 43 pure bool isStaticVector(E)() 44 { 45 static if( !isVector!E ) return false; 46 else return E.isStatic; 47 } 48 49 pure bool isDynamicVector(E)() 50 { 51 static if( !isVector!E ) return false; 52 else return E.isDynamic; 53 } 54 55 unittest 56 { 57 static assert( !isStaticVector!float ); 58 static assert( !isDynamicVector!float ); 59 } 60 61 pure bool isCompatibleVector(size_t N,T,E)() 62 { 63 static if( !isVector!E ) return false; 64 else return E.init.length == N && is( E.datatype : T ); 65 } 66 67 pure bool isValidOp(string op,T,E,K=T)() 68 { mixin( `return is( typeof( T.init ` ~ op ~ ` E.init ) : K );` ); } 69 70 pure bool hasCompMltAndSum(T,E)() 71 { return is( typeof( T(T.init * E.init) ) ) && is( typeof( T.init + T.init ) == T ); } 72 73 private enum SEP = " "; 74 75 pure @property string spaceSep(string str) { return str.split("").join(SEP); } 76 77 private @property string zerosVectorData(size_t N)() 78 { 79 string[] ret; 80 foreach( j; 0 .. N ) 81 ret ~= format( "%d", 0 ); 82 return "[" ~ ret.join(",") ~ "]"; 83 } 84 85 struct Vector( size_t N, T, alias string AS="") 86 if( isCompatibleArrayAccessString(N,AS,SEP) || AS.length == 0 ) 87 { 88 enum isDynamic = N == 0; 89 enum isStatic = N != 0; 90 enum dims = N; 91 92 static if( isStatic ) 93 { 94 static if( isNumeric!T ) 95 T[N] data = mixin( zerosVectorData!N ); 96 else 97 T[N] data; 98 } 99 else T[] data; 100 101 alias data this; 102 103 alias T datatype; 104 alias AS access_string; 105 alias Vector!(N,T,AS) selftype; 106 107 pure: 108 static if( isDynamic ) 109 { 110 pure @property auto length() const { return data.length; } 111 112 pure @property auto length( size_t nl ) 113 { 114 data.length = nl; 115 return data.length; 116 } 117 } 118 else enum length = N; 119 120 this(E...)( in E vals ) 121 { 122 // not in limitation of signature because 123 // not work with dynamic vectors 124 static if( E.length == 0 ) 125 static assert( 0, "args length == 0" ); 126 static if( !is(typeof(flatData!T(vals))) ) 127 static assert( 0, "args not compatible" ); 128 129 auto buf = flatData!T(vals); 130 131 static if( isStatic ) 132 { 133 if( buf.length == length ) 134 data[] = buf[]; 135 else if( buf.length == 1 ) 136 data[] = buf[0]; 137 else enforce( false, "bad args length" ); 138 } 139 else 140 { 141 length = buf.length; 142 data[] = buf[]; 143 } 144 } 145 146 static if( isDynamic ) 147 this(this) { data = this.data.dup; } 148 149 auto opAssign( size_t K, E, alias string oas )( in Vector!(K,E,oas) b ) 150 if( (K==N||K==0||N==0) && is( typeof(T(E.init)) ) ) 151 { 152 static if( isDynamic ) length = b.length; 153 foreach( i; 0 .. length ) data[i] = T(b[i]); 154 return this; 155 } 156 157 auto opUnary(string op)() const 158 if( op == "-" && is( typeof( T.init * (-1) ) : T ) ) 159 { 160 selftype ret; 161 static if( isDynamic ) ret.length = length; 162 foreach( i; 0 .. length ) 163 ret[i] = this[i] * -1; 164 return ret; 165 } 166 167 auto opBinary(string op, size_t K, E, alias string oas ) 168 ( in Vector!(K,E,oas) b ) const 169 if( isValidOp!(op,T,E) && (K==N||K==0||N==0) ) 170 { 171 selftype ret; 172 static if( isDynamic || b.isDynamic ) 173 enforce( length == b.length, "wrong length" ); 174 static if( isDynamic ) ret.length = length; 175 foreach( i; 0 .. length ) 176 mixin( `ret[i] = this[i] ` ~ op ~ ` b[i];` ); 177 return ret; 178 } 179 180 auto opBinary(string op, E)( in E b ) const 181 if( isValidOp!(op,T,E) && op != "+" && op != "-" ) 182 { 183 selftype ret; 184 static if( isDynamic ) ret.length = length; 185 foreach( i; 0 .. length ) 186 mixin( `ret[i] = this[i] ` ~ op ~ ` b;` ); 187 return ret; 188 } 189 190 auto opOpAssign(string op, E)( in E b ) 191 if( mixin( `is( typeof( this ` ~ op ~ ` b ) )` ) ) 192 { mixin( `return this = this ` ~ op ~ ` b;` ); } 193 194 auto opBinaryRight(string op, E)( in E b ) const 195 if( isValidOp!(op,E,T,T) && op == "*" ) 196 { mixin( "return this " ~ op ~ " b;" ); } 197 198 bool opCast(E)() const if( is( E == bool ) ) 199 { 200 foreach( v; data ) if( !isFinite(v) ) return false; 201 return true; 202 } 203 204 const(T[]) opCast(E)() const if( is( E == T[] ) ) { return data; } 205 206 const @property 207 { 208 static if( is( typeof( dot(selftype.init,selftype.init) ) ) ) 209 { 210 auto len2() { return dot(this,this); } 211 212 static if( is( typeof( sqrt(CommonType!(T,float)(this.len2)) ) ) ) 213 auto len(E=CommonType!(T,float))() { return sqrt( E(len2) ); } 214 215 static if( is( typeof( this / len ) == typeof(this) ) ) 216 auto e() { return this / len; } 217 } 218 } 219 220 static if( N == 2 ) 221 { 222 auto rebase(I,J)( in I x, in J y ) const 223 if( isCompatibleVector!(2,T,I) && 224 isCompatibleVector!(2,T,J) ) 225 { 226 alias this m; 227 228 auto d = x[0] * y[1] - y[0] * x[1]; 229 auto rx = m[0] * y[1] - y[0] * m[1]; 230 auto ry = x[0] * m[1] - m[0] * x[1]; 231 232 return selftype( rx/d, ry/d ); 233 } 234 } 235 236 static if( N == 3 ) 237 { 238 auto rebase(I,J,K)( in I x, in J y, in K z ) const 239 if( isCompatibleVector!(3,T,I) && 240 isCompatibleVector!(3,T,J) && 241 isCompatibleVector!(3,T,K) ) 242 { 243 alias this m; 244 245 auto a1 = (y[1] * z[2] - z[1] * y[2]); 246 auto a2 = -(x[1] * z[2] - z[1] * x[2]); 247 auto a3 = (x[1] * y[2] - y[1] * x[2]); 248 249 auto x2 = -(m[1] * z[2] - z[1] * m[2]); 250 auto x3 = (m[1] * y[2] - y[1] * m[2]); 251 252 auto y1 = (m[1] * z[2] - z[1] * m[2]); 253 auto y3 = (x[1] * m[2] - m[1] * x[2]); 254 255 auto z1 = (y[1] * m[2] - m[1] * y[2]); 256 auto z2 = -(x[1] * m[2] - m[1] * x[2]); 257 258 auto ad1 = x[0] * a1; 259 auto ad2 = y[0] * a2; 260 auto ad3 = z[0] * a3; 261 262 auto d = x[0] * a1 + y[0] * a2 + z[0] * a3; 263 264 auto nxd = m[0] * a1 + y[0] * x2 + z[0] * x3; 265 auto nyd = x[0] * y1 + m[0] * a2 + z[0] * y3; 266 auto nzd = x[0] * z1 + y[0] * z2 + m[0] * a3; 267 268 return selftype( nxd/d, nyd/d, nzd/d ); 269 } 270 } 271 272 static if( AS.length > 0 ) 273 { 274 @property 275 { 276 ref T opDispatch(string v)() 277 if( oneOfAccess(AS,v,SEP) ) 278 { mixin( format( "return data[%d];", getIndex(AS,v,SEP) ) ); } 279 280 T opDispatch(string v)() const 281 if( oneOfAccess(AS,v,SEP) ) 282 { mixin( format( "return data[%d];", getIndex(AS,v,SEP) ) ); } 283 } 284 285 static if( isOneSymbolPerFieldAccessString(AS,SEP) ) 286 { 287 @property auto opDispatch(string v)() const 288 if( v.length > 1 && oneOfAccessAll(AS,v,SEP) ) 289 { 290 mixin( format( `return Vector!(v.length,T,"%s")(%s);`, 291 isCompatibleArrayAccessString(v.length,v)?v.split("").join(SEP):"", 292 array( map!(a=>format( `data[%d]`,getIndex(AS,a,SEP)))(v.split("")) ).join(",") 293 )); 294 } 295 296 @property auto opDispatch( string v, U )( in U b ) 297 if( v.length > 1 && oneOfAccessAll(AS,v,SEP) && isCompatibleArrayAccessString(v.length,v) && 298 ( isCompatibleVector!(v.length,T,U) || ( isDynamicVector!U && is(typeof(T(U.datatype.init))) ) ) ) 299 { 300 static if( b.isDynamic ) enforce( v.length == b.length ); 301 foreach( i; 0 .. v.length ) data[getIndex(AS,""~v[i],SEP)] = T( b[i] ); 302 return opDispatch!v; 303 } 304 } 305 } 306 307 /++ для кватернионов +/ 308 static if( AS == "i j k a" ) 309 { 310 static assert( isFloatingPoint!T, "quaterni must be floating point vector" ); 311 312 static selftype fromAngle(E,alias string bs)( T alpha, in Vector!(3,E,bs) axis ) 313 if( isFloatingPoint!E ) 314 { 315 T a = alpha / cast(T)(2.0); 316 return selftype( axis * sin(a), cos(a) ); 317 } 318 319 /++ quaterni mul +/ 320 auto quatMlt(E)( in Vector!(4,E,AS) b ) const 321 if( is( CommonType!(T,E) : T ) ) 322 { 323 alias this a; 324 auto aijk = a.ijk; 325 auto bijk = b.ijk; 326 return selftype( cross(aijk, bijk) + aijk * b.a + bijk * a.a, 327 a.a * b.a - dot(aijk, bijk) ); 328 } 329 330 auto rot(size_t K,E,alias string bs)( in Vector!(K,E,bs) b ) const 331 if( (K==0||K==3) && is( CommonType!(T,E) : T ) ) 332 { 333 static if( K==0 ) enforce( b.length == 3, "wrong length" ); 334 auto res = (this.quatMlt( selftype(b,0).quatMlt(inv) )); 335 return Vector!(K,T,bs)( res.ijk ); 336 } 337 338 const @property 339 { 340 T norm() { return dot(this,this); } 341 T mag() { return sqrt( norm ); } 342 auto con() { return selftype( -this.ijk, this.a ); } 343 auto inv() { return con / norm; } 344 } 345 } 346 } 347 348 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 ) 349 if( (N==K||K==0||N==0) && hasCompMltAndSum!(T,E) ) 350 { 351 static if( a.isDynamic || b.isDynamic ) 352 { 353 enforce( a.length == b.length, "wrong length" ); 354 enforce( a.length > 0, "zero length" ); 355 } 356 T ret = a[0] * b[0]; 357 foreach( i; 1 .. a.length ) 358 ret = ret + T( a[i] * b[i] ); 359 return ret; 360 } 361 362 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 ) 363 if( ((K==3||K==0)&&(N==3||N==0)) && hasCompMltAndSum!(T,E) ) 364 { 365 static if( a.isDynamic ) enforce( a.length == 3, "wrong length a" ); 366 static if( b.isDynamic ) enforce( b.length == 3, "wrong length b" ); 367 368 a.selftype ret; 369 static if( a.isDynamic ) ret.length = 3; 370 ret[0] = T(a[1] * b[2]) - T(a[2] * b[1]); 371 ret[1] = T(a[2] * b[0]) - T(a[0] * b[2]); 372 ret[2] = T(a[0] * b[1]) - T(a[1] * b[0]); 373 return ret; 374 } 375 376 alias Vector!(2,float,"x y") vec2; 377 alias Vector!(3,float,"x y z") vec3; 378 alias Vector!(4,float,"x y z w") vec4; 379 380 alias Vector!(4,float,"i j k a") quat; 381 alias Vector!(4,double,"i j k a") dquat; 382 383 alias Vector!(2,double,"x y") dvec2; 384 alias Vector!(3,double,"x y z") dvec3; 385 alias Vector!(4,double,"x y z w") dvec4; 386 387 alias Vector!(2,int,"x y") ivec2; 388 alias Vector!(3,int,"x y z") ivec3; 389 alias Vector!(4,int,"x y z w") ivec4; 390 391 alias Vector!(2,uint,"x y") uivec2; 392 alias Vector!(3,uint,"x y z") uivec3; 393 alias Vector!(4,uint,"x y z w") uivec4; 394 395 alias Vector!(3,float,"r g b") col3; 396 alias Vector!(4,float,"r g b a") col4; 397 398 alias Vector!(3,ubyte,"r g b") ubcol3; 399 alias Vector!(4,ubyte,"r g b a") ubcol4; 400 401 alias Vector!(0,byte) bvecD; 402 alias Vector!(0,ubyte) ubvecD; 403 alias Vector!(0,int) ivecD; 404 alias Vector!(0,uint) uivecD; 405 alias Vector!(0,long) lvecD; 406 alias Vector!(0,ulong) ulvecD; 407 alias Vector!(0,float) vecD; 408 alias Vector!(0,double) dvecD; 409 alias Vector!(0,real) rvecD; 410 411 unittest 412 { 413 static assert( isVector!vec2 ); 414 static assert( isVector!vec3 ); 415 static assert( isVector!vec4 ); 416 static assert( isVector!quat ); 417 static assert( isVector!dquat ); 418 static assert( isVector!dvec2 ); 419 static assert( isVector!dvec3 ); 420 static assert( isVector!dvec4 ); 421 static assert( isVector!ivec2 ); 422 static assert( isVector!ivec3 ); 423 static assert( isVector!ivec4 ); 424 static assert( isVector!col3 ); 425 static assert( isVector!col4 ); 426 static assert( isVector!ubcol3 ); 427 static assert( isVector!ubcol4 ); 428 static assert( isVector!vecD ); 429 static assert( isVector!ivecD ); 430 static assert( isVector!dvecD ); 431 } 432 433 unittest 434 { 435 static assert( Vector!(3,float).isStatic == true ); 436 static assert( Vector!(3,float).isDynamic == false ); 437 438 static assert( Vector!(0,float).isStatic == false ); 439 static assert( Vector!(0,float).isDynamic == true ); 440 441 static assert( isVector!(Vector!(3,float)) ); 442 static assert( isVector!(Vector!(0,float)) ); 443 444 static assert( !__traits(compiles,Vector!(3,float,"x y")) ); 445 static assert( !__traits(compiles,Vector!(3,float,"x y")) ); 446 static assert( __traits(compiles,Vector!(3,float,"x y z")) ); 447 448 static assert( Vector!(3,float,"x y z").sizeof == float.sizeof * 3 ); 449 static assert( Vector!(0,float).sizeof == (float[]).sizeof ); 450 451 static assert( Vector!(3,float,"x y z").length == 3 ); 452 } 453 454 unittest 455 { 456 assert( eq( Vector!(3,float)(1,2,3), [1,2,3] ) ); 457 458 auto a = Vector!(3,float)(1,2,3); 459 assert( eq( Vector!(5,int)(0,a,4), [0,1,2,3,4] ) ); 460 461 assert( mustExcept( { auto v = Vector!(2,int)(1,2,3); } ) ); 462 assert( !mustExcept( { auto v = Vector!(0,int)(1,2,3); } ) ); 463 assert( !mustExcept( { auto v = Vector!(3,int)(1); } ) ); 464 auto b = Vector!(0,float)(1,2,3); 465 assert( b.length == 3 ); 466 467 auto c = Vector!(3,float)(1); 468 assert( eq( c, [1,1,1] ) ); 469 auto d = c; 470 assert( eq( c, d ) ); 471 } 472 473 unittest 474 { 475 static struct Test1 { float x,y,z; } 476 static assert( !__traits(compiles,Vector!(3,float)(Test1.init)) ); 477 478 static struct Test2 { float[3] data; } 479 static assert( __traits(compiles,Vector!(3,float)(Test2.init)) ); 480 } 481 482 unittest 483 { 484 auto a = vec3(1,2,3); 485 486 auto a1 = const vec3(a); 487 auto a2 = const vec3(1,2,3); 488 auto a3 = const vec3(1); 489 490 auto a4 = shared vec3(a); 491 auto a5 = shared vec3(1,2,3); 492 auto a6 = shared vec3(1); 493 494 auto a7 = immutable vec3(a); 495 auto a8 = immutable vec3(1,2,3); 496 auto a9 = immutable vec3(1); 497 498 auto a10 = shared const vec3(a); 499 auto a11 = shared const vec3(1,2,3); 500 auto a12 = shared const vec3(1); 501 502 assert( eq( a, a1 ) ); 503 assert( eq( a, a4 ) ); 504 assert( eq( a, a7 ) ); 505 assert( eq( a, a10 ) ); 506 507 a = vec3(a4.data); 508 } 509 510 unittest 511 { 512 auto a = vec3(2); 513 assert( eq( -a, [-2,-2,-2] ) ); 514 } 515 516 unittest 517 { 518 auto a = vec3(1,2,3); 519 auto b = vecD(1,2,3); 520 auto c = a + b; 521 assert( is( typeof(c) == vec3 ) ); 522 auto d = b + a; 523 assert( is( typeof(d) == vecD ) ); 524 assert( eq(c,d) ); 525 auto f = ivec3(1,2,3); 526 auto c1 = a + f; 527 assert( is( typeof(c1) == vec3 ) ); 528 auto d1 = ivec3(f) + ivec3(a); 529 assert( is( typeof(d1) == ivec3 ) ); 530 assert( eq(c1,d) ); 531 assert( eq(c,d1) ); 532 533 a *= 2; 534 b *= 2; 535 auto e = b *= 2; 536 assert( eq(a,[2,4,6]) ); 537 assert( eq(b,a*2) ); 538 539 auto x = 2 * a; 540 assert( eq(x,[4,8,12]) ); 541 542 assert( !!x ); 543 x[0] = float.nan; 544 assert( !x ); 545 } 546 547 unittest 548 { 549 auto a = vecD(1,2,3); 550 551 auto b = vec3(a); 552 auto c = vecD(b); 553 554 assert( eq( a, b ) ); 555 assert( eq( a, c ) ); 556 } 557 558 unittest 559 { 560 auto a = vec3(1,2,3); 561 auto b = vecD(1,2,3); 562 563 assert( eq( dot(a,b), 1+4+9 ) ); 564 } 565 566 unittest 567 { 568 auto x = vec3(1,0,0); 569 auto y = vecD(0,1,0); 570 auto z = vecD(0,0,1); 571 572 assert( eq( cross(x,y), z ) ); 573 assert( eq( cross(y,z), x ) ); 574 assert( eq( cross(y,x), -z ) ); 575 assert( eq( cross(x,z), -y ) ); 576 assert( eq( cross(z,x), y ) ); 577 578 auto fy = vecD(0,1,0,0); 579 assert( mustExcept({ auto fz = x * fy; }) ); 580 auto cfy = vec4(0,1,0,0); 581 static assert( !__traits(compiles,x*cfy) ); 582 } 583 584 unittest 585 { 586 auto a = vec3(2,2,1); 587 assert( eq(a.rebase(vec3(2,0,0),vec3(0,2,0),vec3(0,0,2)), [1,1,.5] ) ); 588 } 589 590 unittest 591 { 592 auto a = vec3(1,2,3); 593 594 assert( a.opDispatch!"x" == 1 ); 595 assert( a.y == 2 ); 596 assert( a.z == 3 ); 597 598 a.x = 2; 599 assert( a.x == 2 ); 600 } 601 602 unittest 603 { 604 alias Vector!(4,float,"x y dx dy") vec2p; 605 606 auto a = vec2p(1,2,0,0); 607 608 assert( a.opDispatch!"x" == 1 ); 609 assert( a.dx == 0 ); 610 } 611 612 unittest 613 { 614 auto a = vec3(1,2,3); 615 616 auto b = a.opDispatch!"xy"; 617 auto c = a.xx; 618 auto d = a.xxxyyzyx; 619 620 static assert( is(typeof(b) == Vector!(2,float,"x y") ) ); 621 static assert( is(typeof(c) == Vector!(2,float) ) ); 622 static assert( is(typeof(d) == Vector!(8,float) ) ); 623 624 assert( eq( b, [1,2] ) ); 625 assert( eq( c, [1,1] ) ); 626 assert( eq( d, [1,1,1,2,2,3,2,1] ) ); 627 } 628 629 unittest 630 { 631 auto a = vec3(1,2,3); 632 auto b = dvec4(4,5,6,7); 633 auto c = vecD( 9, 10 ); 634 a.xz = b.yw; 635 assert( eq( a, [5,2,7] ) ); 636 a.zy = c; 637 assert( eq( a, [5,10,9] ) ); 638 static assert( !__traits(compiles, a.xy=vec3(1,2,3)) ); 639 static assert( !__traits(compiles, a.xx=vec2(1,2)) ); 640 auto d = a.zxy = b.wyx; 641 static assert( d.access_string == "z x y" ); 642 static assert( is( d.datatype == float ) ); 643 assert( eq( d, [ 7,5,4 ] ) ); 644 assert( eq( a, [ 5,4,7 ] ) ); 645 a.yzx = a.zxz; 646 assert( eq( a, [ 7,7,5 ] ) ); 647 } 648 649 unittest 650 { 651 auto r = quat.fromAngle( PI_2, vec3(0,0,1) ); 652 653 auto a = vec3( 1,0,0 ); 654 auto b = r.rot(a); 655 assert( is( typeof(b) == vec3 ) ); 656 assert( eq( b.data, [ 0, 1, 0 ] ) ); 657 } 658 659 unittest 660 { 661 auto a = vec3(1,2,3); 662 auto b = ivec3(1,2,3); 663 auto k = a.len2; 664 assert( is( typeof(k) == float ) ); 665 666 auto l = b.len2; 667 assert( is( typeof(l) == int ) ); 668 669 auto m = b.len; 670 assert( is( typeof(m) == float ) ); 671 672 auto n = b.len!real; 673 assert( is( typeof(n) == real ) ); 674 675 assert( is( typeof( vec3( 1, 2, 3 ).e ) == vec3 ) ); 676 assert( abs( a.e.len - 1 ) < float.epsilon ); 677 } 678 679 unittest 680 { 681 alias Vector!(3,cfloat) cvec3; 682 683 auto a = cvec3( 1-1i, 2, 3i ); 684 static assert( __traits(compiles, a.e) ); 685 assert( !mustExcept({ auto k = a.e; }) ); 686 } 687 688 unittest 689 { 690 alias Vector!(3,Vector!(3,float)) mat3; 691 auto a = mat3( vec3(1,0,0), vec3(0,1,0), vec3(0,0,1) ); 692 693 a *= 2; 694 a += a; 695 696 assert( a[0][0] == 4 ); 697 assert( a[1][1] == 4 ); 698 assert( a[2][2] == 4 ); 699 700 assert( a[0][1] == 0 ); 701 assert( a[1][2] == 0 ); 702 assert( a[2][1] == 0 ); 703 704 a ^^= 2; 705 706 assert( a[0][0] == 16 ); 707 assert( a[1][1] == 16 ); 708 assert( a[2][2] == 16 ); 709 710 auto b = -a; 711 712 assert( b[0][0] == -16 ); 713 assert( b[1][1] == -16 ); 714 assert( b[2][2] == -16 ); 715 } 716 717 unittest 718 { 719 auto a = vecD(1,2,3); 720 auto b = a; 721 assert( eq(a,b) ); 722 b[0] = 111; 723 assert( !eq(a,b) ); 724 725 vecD c; 726 c = b; 727 assert( eq(c,b) ); 728 b[0] = 222; 729 assert( !eq(c,b) ); 730 } 731 732 unittest 733 { 734 auto a = vec3(1,2,3); 735 auto b = a; 736 assert( eq(a,b) ); 737 b[0] = 111; 738 assert( !eq(a,b) ); 739 }