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