1 module armos.math.vector; 2 import armos.math; 3 import core.vararg; 4 import std.math; 5 import std.stdio; 6 7 version(D_SIMD) { 8 import core.simd; 9 enum SIMD_Enable = true; 10 } 11 else { 12 enum SIMD_Enable = false; 13 } 14 15 /++ 16 ベクトル計算を行うstructです 17 +/ 18 struct Vector(T, int Dimention)if(__traits(isArithmetic, T) && Dimention > 0){ 19 private alias Vector!(T, Dimention) VectorType; 20 21 enum XMMRegisterSize = 16; 22 enum PackSize = XMMRegisterSize / T.sizeof; 23 enum XMMsNum = Dimention % PackSize == 1 || Dimention % PackSize == 0 ? 24 Dimention / PackSize : 25 Dimention / PackSize + 1; 26 enum XMMsSize = XMMsNum * PackSize; 27 28 union PackedElements{ 29 T[Dimention] arr; 30 static if (!is(T == real) && Dimention > 1) { 31 static if (XMMsNum == 1){ 32 __vector(T[PackSize]) vec; 33 } 34 else { 35 __vector(T[PackSize])[XMMsNum] vec; 36 } 37 } 38 } 39 40 41 private template Compute (string Base) { 42 import std.format : format; 43 static if (Dimention > 1) { 44 enum XMMComputeBase = format("if(__ctfe){%s}else{%%s}",format(Base,"arr[]")); 45 static if (XMMsNum == 1) { 46 enum ComputeXMM = format(Base,"vec"); 47 } 48 else { 49 enum ComputeXMM = expandFor!(format(Base,"vec[%1$d]"),XMMsNum); 50 } 51 static if (Dimention <= XMMsSize) { 52 enum Compute = format(XMMComputeBase,ComputeXMM); 53 } 54 else static if (Dimention == XMMsSize + 1) { 55 enum Compute = format(XMMComputeBase,ComputeXMM ~ format(Base,"arr[$-1]")); 56 } 57 else { 58 static assert (false,"illegal PackedElements!"); 59 } 60 } 61 else { 62 enum Compute = format(Base,"arr[0]"); 63 } 64 } 65 unittest { 66 static assert(Vector!(int,3).Compute!("x.%1$s+y.%1$s;") == "if(__ctfe){x.arr[]+y.arr[];}else{x.vec+y.vec;}"); 67 static assert(Vector!(int,4).Compute!("x.%1$s+y.%1$s;") == "if(__ctfe){x.arr[]+y.arr[];}else{x.vec+y.vec;}"); 68 static assert(Vector!(int,5).Compute!("x.%1$s+y.%1$s;") == "if(__ctfe){x.arr[]+y.arr[];}else{x.vec+y.vec;x.arr[$-1]+y.arr[$-1];}"); 69 static assert(Vector!(int,6).Compute!("x.%1$s+y.%1$s;") == "if(__ctfe){x.arr[]+y.arr[];}else{x.vec[0]+y.vec[0];x.vec[1]+y.vec[1];}"); 70 static assert(Vector!(int,9).Compute!("x.%1$s+y.%1$s;") == "if(__ctfe){x.arr[]+y.arr[];}else{x.vec[0]+y.vec[0];x.vec[1]+y.vec[1];x.arr[$-1]+y.arr[$-1];}"); 71 } 72 unittest { 73 } 74 75 PackedElements packedElements; 76 77 // T[Dimention] elements = packedElements.arr[]; 78 ref T[Dimention] elements()const{ 79 return packedElements.arr[]; 80 } 81 82 //T[Dimention] packedElements = T.init; 83 /// 84 enum int dimention = Dimention; 85 unittest{ 86 static assert(Vector!(float, 3).dimention == 3); 87 } 88 89 alias elementType = T; 90 unittest{ 91 static assert(is(Vector!(float, 3).elementType == float)); 92 } 93 94 enum string coordNames = "xyzw"; 95 96 static if (Dimention <= coordNames.length){ 97 enum string coordName = coordNames[0..Dimention]; 98 }else{ 99 enum string coordName = ""; 100 } 101 unittest{ 102 static assert(Vector!(float,3).coordName == "xyz"); 103 } 104 105 /++ 106 Vectorのinitializerです.引数はDimentionと同じ個数の要素を取ります. 107 +/ 108 this(T[] arr ...)in{ 109 assert(arr.length == 0 || arr.length == Dimention); 110 }body{ 111 if(arr.length != 0){ 112 packedElements.arr = arr; 113 } 114 } 115 116 117 /++ 118 +/ 119 pure T opIndex(in size_t index)const{ 120 return packedElements.arr[index]; 121 } 122 123 /++ 124 +/ 125 ref T opIndex(in size_t index){ 126 return packedElements.arr[index]; 127 } 128 unittest{ 129 auto vec = Vector3d(1, 2, 3); 130 assert(vec[0] == 1.0); 131 assert(vec[1] == 2.0); 132 assert(vec[2] == 3.0); 133 } 134 135 // pure const bool opEquals(Object vec){ 136 // foreach (int index, T v; (cast(VectorType)vec).packedElements.arr) { 137 // if(v != this.packedElements.arr[index]){ 138 // return false; 139 // } 140 // } 141 // return true; 142 // } 143 unittest{ 144 auto vec1 = Vector3d(1, 2, 3); 145 auto vec2 = Vector3d(1, 2, 3); 146 assert(vec1 == vec2); 147 } 148 unittest{ 149 auto vec1 = Vector3d(1, 2, 3); 150 auto vec2 = Vector3d(2, 2, 1); 151 assert(vec1 != vec2); 152 } 153 154 /++ 155 +/ 156 enum VectorType zero = (){ 157 VectorType v; 158 v.packedElements.arr[] = T(0); 159 return v; 160 }(); 161 unittest{ 162 auto vec = Vector3d.zero; 163 assert(vec[0] == 0); 164 assert(vec[1] == 0); 165 assert(vec[2] == 0); 166 } 167 168 /++ 169 +/ 170 VectorType opNeg()const{ 171 auto result = VectorType(); 172 static if (SIMD_Enable && !is(T == real)) 173 mixin(Compute!("result.packedElements.%1$s = -packedElements.%1$s;")); 174 else 175 result.packedElements.arr[] = -packedElements.arr[]; 176 return result; 177 }; 178 unittest{ 179 auto vec1 = Vector3d(); 180 vec1[0] = 1.5; 181 assert(vec1[0] == 1.5); 182 assert((-vec1)[0] == -1.5); 183 } 184 185 /++ 186 +/ 187 VectorType opAdd(in VectorType r)const{ 188 auto result = VectorType(); 189 static if (SIMD_Enable && !is(T == real)) 190 mixin(Compute!("result.packedElements.%1$s = packedElements.%1$s + r.packedElements.%1$s;")); 191 else 192 result.packedElements.arr[] = packedElements.arr[] + r.packedElements.arr[]; 193 return result; 194 } 195 unittest{ 196 auto vec1 = Vector3d(); 197 vec1[0] = 1.5; 198 199 auto vec2 = Vector3d(); 200 vec2[1] = 0.2; 201 vec2[0] = 0.2; 202 assert((vec1+vec2)[0] == 1.7); 203 } 204 205 /++ 206 +/ 207 VectorType opSub(in VectorType r)const{ 208 auto result = VectorType(); 209 static if (SIMD_Enable && !is(T == real)) 210 mixin(Compute!("result.packedElements.%1$s = packedElements.%1$s - r.packedElements.%1$s;")); 211 else 212 result.packedElements.arr[] = packedElements.arr[] - r.packedElements.arr[]; 213 return result; 214 } 215 unittest{ 216 auto result = Vector3d(3, 2, 1) - Vector3d(1, 2, 3); 217 assert(result == Vector3d(2, 0, -2)); 218 } 219 220 /++ 221 +/ 222 VectorType opAdd(in T v)const{ 223 auto result = VectorType(); 224 static if (SIMD_Enable && !is(T == real)) { 225 PackedElements packedV; 226 packedV.arr[] = v; 227 mixin(Compute!("result.packedElements.%1$s = packedElements.%1$s + packedV.%1$s;")); 228 } 229 else 230 result.packedElements.arr[] = packedElements.arr[] + v; 231 return result; 232 } 233 unittest{ 234 auto result = Vector3d(3.0, 2.0, 1.0); 235 assert(result+2.0 == Vector3d(5.0, 4.0, 3.0)); 236 assert(2.0+result == Vector3d(5.0, 4.0, 3.0)); 237 } 238 239 /++ 240 +/ 241 VectorType opSub(in T v)const{ 242 auto result = VectorType(); 243 static if (SIMD_Enable && !is(T == real)) { 244 PackedElements packedV; 245 packedV.arr[] = v; 246 mixin(Compute!("result.packedElements.%1$s = packedElements.%1$s - packedV.%1$s;")); 247 } 248 else 249 result.packedElements.arr[] = packedElements.arr[] - v; 250 return result; 251 } 252 unittest{ 253 auto result = Vector3d(3.0, 2.0, 1.0); 254 assert(result-2.0 == Vector3d(1.0, 0.0, -1.0)); 255 } 256 257 /++ 258 +/ 259 VectorType opMul(in T v)const{ 260 auto result = VectorType(); 261 static if (SIMD_Enable && (is(T == float) || is(T == double) || is(T == short) || is(T == ushort))) { 262 PackedElements packedV; 263 packedV.arr[] = v; 264 mixin(Compute!("result.packedElements.%1$s = packedElements.%1$s * cast(const)packedV.%1$s;")); 265 } 266 else 267 result.packedElements.arr[] = packedElements.arr[] * v; 268 return result; 269 } 270 unittest{ 271 auto result = Vector3d(3.0, 2.0, 1.0); 272 assert(result*2.0 == Vector3d(6.0, 4.0, 2.0)); 273 assert(2.0*result == Vector3d(6.0, 4.0, 2.0)); 274 } 275 276 /++ 277 +/ 278 VectorType opDiv(in T v)const{ 279 auto result = VectorType(); 280 static if (SIMD_Enable && (is(T == float) || is(T == double))) { 281 PackedElements packedV; 282 packedV.arr[] = v; 283 mixin(Compute!("result.packedElements.%1$s = packedElements.%1$s / packedV.%1$s;")); 284 } 285 else 286 result.packedElements.arr[] = packedElements.arr[] / v; 287 return result; 288 } 289 unittest{ 290 auto result = Vector3d(3.0, 2.0, 1.0); 291 assert(result/2.0 == Vector3d(1.5, 1.0, 0.5)); 292 } 293 294 /++ 295 +/ 296 VectorType opMod(in T v)const{ 297 auto result = VectorType(); 298 result.packedElements.arr[] = packedElements.arr[] % v; 299 return result; 300 } 301 unittest{ 302 auto result = Vector3d(4.0, 2.0, 1.0); 303 assert(result%2.0 == Vector3d(0.0, 0.0, 1.0)); 304 } 305 306 /++ 307 +/ 308 VectorType opMul(in VectorType v)const{ 309 auto result = VectorType(); 310 static if (SIMD_Enable && (is(T == float) || is(T == double) || is(T == short) || is(T == ushort))) 311 mixin(Compute!("result.packedElements.%1$s = packedElements.%1$s * v.packedElements.%1$s;")); 312 else 313 result.packedElements.arr[] = packedElements.arr[] * v.packedElements.arr[]; 314 return result; 315 } 316 unittest{ 317 auto vec1 = Vector3d(3.0, 2.0, 1.0); 318 auto vec2 = Vector3d(2.0, 1.0, 0.0); 319 assert(vec1*vec2 == Vector3d(6.0, 2.0, 0.0)); 320 } 321 322 /++ 323 +/ 324 VectorType opDiv(in VectorType v)const{ 325 auto result = VectorType(); 326 static if (SIMD_Enable && (is(T == float) || is(T == double))) 327 mixin(Compute!("result.packedElements.%1$s = packedElements.%1$s / v.packedElements.%1$s;")); 328 else 329 result.packedElements.arr[] = packedElements.arr[] / v.packedElements.arr[]; 330 return result; 331 } 332 unittest{ 333 auto vec1 = Vector3d(4.0, 2.0, 1.0); 334 auto vec2 = Vector3d(2.0, 1.0, 1.0); 335 assert(vec1/vec2 == Vector3d(2.0, 2.0, 1.0)); 336 } 337 338 /++ 339 +/ 340 VectorType opMod(in VectorType v)const{ 341 auto result = VectorType(); 342 result.packedElements.arr[] = packedElements.arr[] % v.packedElements.arr[]; 343 return result; 344 } 345 unittest{ 346 auto vec1 = Vector3d(3.0, 2.0, 1.0); 347 auto vec2 = Vector3d(2.0, 1.0, 1.0); 348 assert(vec1%vec2 == Vector3d(1.0, 0.0, 0.0)); 349 } 350 351 /++ 352 +/ 353 void opAddAssign(in VectorType v){ 354 static if (SIMD_Enable && !is(T == real)) 355 mixin(Compute!("packedElements.%1$s += v.packedElements.%1$s;")); 356 else 357 packedElements.arr[] += v.packedElements.arr[]; 358 } 359 unittest{ 360 auto vec1 = Vector3d(1.0,2.0,3.0); 361 auto vec2 = Vector3d(1.0,1.0,2.0); 362 vec1 += vec2; 363 assert(vec1 == Vector3d(2.0,3.0,5.0)); 364 } 365 366 /++ 367 +/ 368 void opSubAssign(in VectorType v){ 369 static if (SIMD_Enable && !is(T == real)) 370 mixin(Compute!("packedElements.%1$s -= v.packedElements.%1$s;")); 371 else 372 packedElements.arr[] -= v.packedElements.arr[]; 373 } 374 unittest{ 375 auto vec1 = Vector3d(5.0,4.0,3.0); 376 auto vec2 = Vector3d(3.0,2.0,1.0); 377 vec1 -= vec2; 378 assert(vec1 == Vector3d(2.0,2.0,2.0)); 379 } 380 381 /++ 382 +/ 383 void opAddAssign(in T v){ 384 static if (SIMD_Enable && !is(T == real)) { 385 PackedElements packedV; 386 packedV.arr[] = v; 387 mixin(Compute!("packedElements.%1$s += packedV.%1$s;")); 388 } 389 else 390 packedElements.arr[] += v; 391 } 392 unittest{ 393 auto vec1 = Vector3d(1.0,2.0,3.0); 394 vec1 += 1.0; 395 assert(vec1 == Vector3d(2.0,3.0,4.0)); 396 } 397 398 /++ 399 +/ 400 void opSubAssign(in T v){ 401 static if (SIMD_Enable && !is(T == real)) { 402 PackedElements packedV; 403 packedV.arr[] = v; 404 mixin(Compute!("packedElements.%1$s -= packedV.%1$s;")); 405 } 406 else 407 packedElements.arr[] -= v; 408 } 409 unittest{ 410 auto vec1 = Vector3d(2.0,3.0,4.0); 411 vec1 -= 3.0; 412 assert(vec1 == Vector3d(-1.0,0.0,1.0)); 413 } 414 415 /++ 416 +/ 417 void opModAssign(in T v){ 418 packedElements.arr[] %= v; 419 } 420 unittest{ 421 auto vec1 = Vector3d(4.0,5.0,6.0); 422 vec1 %= 3.0; 423 assert(vec1 == Vector3d(1.0,2.0,0.0)); 424 } 425 426 /++ 427 +/ 428 void opDivAssign(in T v){ 429 static if (SIMD_Enable && (is(T == float) || is(T == double))) { 430 PackedElements packedV; 431 packedV.arr[] = v; 432 mixin(Compute!("packedElements.%1$s /= packedV.%1$s;")); 433 } 434 else 435 packedElements.arr[] /= v; 436 } 437 unittest{ 438 auto vec1 = Vector3d(3.0,4.0,5.0); 439 vec1 /= 2.0; 440 assert(vec1 == Vector3d(1.5,2.0,2.5)); 441 } 442 443 /++ 444 +/ 445 void opMulAssign(in T v){ 446 static if (SIMD_Enable && (is(T == float) && is(T == double) && is(T == short) && is(T == ushort))) { 447 PackedElements packedV; 448 packedV.arr[] = v; 449 mixin(Compute!("packedElements.%1$s *= packedV.%1$s;")); 450 } 451 else 452 packedElements.arr[] *= v; 453 } 454 unittest{ 455 auto vec1 = Vector3d(2.0,-1.0,1.0); 456 vec1 *= 3.0; 457 assert(vec1 == Vector3d(6.0,-3.0,3.0)); 458 } 459 460 /++ 461 +/ 462 void opModAssign(in VectorType v){ 463 packedElements.arr[] %= v.packedElements.arr[]; 464 } 465 unittest{ 466 auto vec1 = Vector3d(3.0,2.0,1.0); 467 auto vec2 = Vector3d(2.0,1.0,1.0); 468 vec1 %= vec2; 469 assert(vec1 == Vector3d(1.0,0.0,0.0)); 470 } 471 472 /++ 473 +/ 474 void opDivAssign(in VectorType v){ 475 static if (SIMD_Enable && (is(T == double) || is(T == float))) 476 mixin(Compute!("packedElements.%1$s /= v.packedElements.%1$s;")); 477 else 478 packedElements.arr[] /= v.packedElements.arr[]; 479 } 480 unittest{ 481 auto vec1 = Vector3d(4.0,2.0,1.0); 482 auto vec2 = Vector3d(2.0,1.0,1.0); 483 vec1 /= vec2; 484 assert(vec1 == Vector3d(2.0,2.0,1.0)); 485 } 486 487 /++ 488 +/ 489 void opMulAssign(in VectorType v){ 490 static if (SIMD_Enable && (is(T == float) || is(T == double) || is(T == short) || is(T == ushort))) 491 mixin(Compute!("packedElements.%1$s *= v.packedElements.%1$s;")); 492 else 493 packedElements.arr[] *= v.packedElements.arr[]; 494 } 495 unittest{ 496 auto vec1 = Vector3d(3.0,2.0,1.0); 497 auto vec2 = Vector3d(2.0,1.0,0.0); 498 vec1 *= vec2; 499 assert(vec1 == Vector3d(6.0,2.0,0.0)); 500 } 501 502 /++ 503 Vectorのノルムを返します. 504 +/ 505 T norm()const{ 506 import std.numeric : dotProduct; 507 immutable T sumsq = dotProduct(packedElements.arr, packedElements.arr); 508 509 static if(__traits(isFloating, T)){ 510 return sqrt(sumsq); 511 }else{ 512 return cast(T)sqrt(cast(float)sumsq); 513 } 514 } 515 unittest{ 516 auto result = Vector3d(3.0, 2.0, 1.0); 517 assert(result.norm() == ( 3.0^^2.0+2.0^^2.0+1.0^^2.0 )^^0.5); 518 } 519 520 /++ 521 Vectorのドット積を返します. 522 +/ 523 T dotProduct(in VectorType v)const{ 524 //v1 * v2 = v1.x * v2.x + v1.y * v2.y + v1.z * v2.z ... 525 //product = (v1.x * v2.x, v1.y * v2.y, v1.z * v2.z) 526 import std.algorithm.iteration : map; 527 import std.range : iota,join; 528 import std.format : format; 529 auto product = this * v; 530 //expand to "auto result = product.packedElements.arr[0] + product.packedElements.arr[1] + product.packedElements.arr[2] + ..." 531 mixin("return "~Dimention 532 .iota 533 .map!(idx => format("product.packedElements.arr[%d]",idx)) 534 .join('+') 535 ~ ";"); 536 } 537 unittest{ 538 auto vec1 = Vector3d(3.0, 2.0, 1.0); 539 auto vec2 = Vector3d(2.0, 1.0, 2.0); 540 assert(vec1.dotProduct(vec2) == 10.0); 541 } 542 543 unittest{ 544 auto vec1 = Vector3d(0.4, 0.1, 0.3); 545 auto vec2 = Vector3d(0.2, 0.5, 2.0); 546 assert(vec1.dotProduct(vec2) == 0.73); 547 } 548 549 /++ 550 Vectorのベクトル積(クロス積,外積)を返します. 551 Dimentionが3以上の場合のみ使用できます. 552 +/ 553 static if (Dimention == 3){ 554 VectorType vectorProduct(in VectorType v)const{ 555 return VectorType( 556 elements[1]*v[2] - elements[2]*v[1], 557 elements[2]*v[0] - elements[0]*v[2], 558 elements[0]*v[1] - elements[1]*v[0], 559 ); 560 } 561 } 562 563 static if (Dimention > 3){ 564 VectorType vectorProduct(in VectorType[] arg ...)const in{ 565 assert(arg.length == Dimention-2); 566 }body{ 567 auto return_vector = VectorType.zero; 568 foreach (int i, ref T v; return_vector.packedElements.arr) { 569 auto matrix = armos.math.Matrix!(T, Dimention, Dimention)(); 570 auto element_vector = VectorType.zero; 571 element_vector[i] = T(1); 572 matrix.setRowVector(0, element_vector); 573 matrix.setRowVector(1, this); 574 for (int j = 2; j < Dimention; j++) { 575 matrix.setRowVector(j, arg[j-2]); 576 } 577 // matrix.setColumnVector(i+1, this); 578 v = matrix.determinant; 579 } 580 return return_vector; 581 } 582 } 583 unittest{ 584 auto vector0 = Vector3f(1, 2, 3); 585 auto vector1 = Vector3f(4, 5, 6); 586 auto anser = Vector3f(-3, 6, -3); 587 assert(vector0.vectorProduct(vector1) == anser); 588 } 589 590 /++ 591 VectorとVectorの成す角を求めます 592 +/ 593 auto angle(in VectorType v)const{ 594 /+ 595 v1 * v2 = |v1| * |v2| * cosθ 596 θ = acos((v1 * v2) / (|v1| * |v2|)) 597 |v1| = √(v1.x^2 + v1.y^2 + v1.z^2 ...) = √(v1 * v1) 598 norm_product = |v1| * |v2| = √(v1*v1 * v2*v2) 599 dotProduct = v1 * v2 600 +/ 601 auto innerProduct = dotProduct(v); 602 auto normProduct = dotProduct(this) * v.dotProduct(v); 603 static if (__traits(isIntegral,T)) { 604 return acos(cast(float)innerProduct / sqrt(cast(float)normProduct)); 605 } 606 else { 607 return acos (innerProduct / sqrt(normProduct)); 608 } 609 } 610 unittest { 611 auto v1 = Vector2i(3,0); 612 auto v2 = Vector2i(0,5); 613 assert (approxEqual(v1.angle(v2),PI/2)); 614 615 auto v3 = Vector3d(1.0 * cos(PI*1/6), 1.0 * sin(PI*1/6),0.0); 616 auto v4 = Vector3d(2.0 * cos(PI*5/6), 2.0 * sin(PI*5/6),0.0); 617 assert (approxEqual(v3.angle(v4),PI*2/3)); 618 619 auto v5 = Vector2i(3,0); 620 auto v6 = Vector2i(0,-5); 621 assert (approxEqual(v5.angle(v6),PI/2)); 622 623 auto v7 = Vector2i(3,0); 624 auto v8 = Vector2i(-5,-5); 625 assert (approxEqual(v7.angle(v8),PI*3/4)); 626 } 627 628 /++ 629 正規化したVectorを返します. 630 +/ 631 VectorType normalized()const{ 632 return this/this.norm(); 633 } 634 unittest{ 635 auto vec1 = Vector3d(3.0, 2.0, 1.0); 636 assert(vec1.normalized().norm() == 1.0); 637 } 638 639 /++ 640 Vectorを正規化します. 641 +/ 642 void normalize(){ 643 static if (SIMD_Enable && (is(T == float) || is(T == double))) { 644 PackedElements packedNorm; 645 packedNorm.arr[] = this.norm(); 646 mixin(Compute!("this.packedElements.%1$s /= packedNorm.%1$s;")); 647 } 648 else 649 this.packedElements.arr[] /= this.norm(); 650 } 651 unittest{ 652 auto vec1 = Vector3d(3.0, 2.0, 1.0); 653 vec1.normalize(); 654 assert(vec1.norm() == 1.0); 655 } 656 657 /++ 658 Vectorの要素を一次元配列で返します. 659 +/ 660 T[Dimention] array()const{ 661 return packedElements.arr; 662 } 663 unittest{ 664 auto vector = Vector3f(1, 2, 3); 665 float[3] array = vector.array; 666 assert(array == [1, 2, 3]); 667 array[0] = 4; 668 assert(array == [4, 2, 3]); 669 assert(vector == Vector3f(1, 2, 3)); 670 } 671 672 /++ 673 +/ 674 string toString()const{ 675 import std.conv; 676 return typeid(this).to!string ~ "(" ~ packedElements.arr.to!string ~ ")"; 677 } 678 679 /++ 680 自身を別の型のVectorへキャストしたものを返します.キャスト後の型は元のVectorと同じ次元である必要があります. 681 +/ 682 CastType opCast(CastType)()const if(CastType.dimention == dimention){ 683 auto vec = CastType(); 684 foreach (int index, const T var; packedElements.arr) { 685 vec.packedElements.arr[index] = cast( typeof( vec.packedElements.arr[0] ) )packedElements.arr[index]; 686 } 687 return vec; 688 } 689 690 unittest{ 691 auto vec_f = Vector3f(2.5, 0, 0); 692 auto vec_i = Vector3i(0, 0, 0); 693 694 vec_i = cast(Vector3i)vec_f; 695 696 assert(vec_i[0] == 2); 697 698 //Invalid cast. Different size. 699 assert(!__traits(compiles, { 700 auto vec_f = Vector2f(2.5, 0); 701 auto vec_i = Vector3i(0, 0, 0); 702 vec_i = cast(Vector3i)vec_f; 703 })); 704 } 705 706 /++ 707 vec.x vec.xyのようにベクトルの一部を切り出すことが出来ます 708 +/ 709 @property auto opDispatch(string swizzle)()const if (swizzle.length > 0 && swizzle.length < coordName.length && coordName.length > 0) { 710 import std.string : indexOf,join; 711 import std.array : array; 712 import std.conv : to; 713 import std.algorithm.iteration : map; 714 715 static if (swizzle.length == 1) { 716 enum index = coordName.indexOf(swizzle[0]); 717 static if (index >= 0){ 718 return packedElements.arr[index]; 719 } 720 } else { 721 enum int[] indecies = swizzle.map!(axis => coordName.indexOf(axis)).array; 722 mixin("return Vector!(T,swizzle.length)("~indecies.map!(index => "packedElements.arr["~index.to!string~"]").array.join(',')~");"); 723 } 724 } 725 726 /++ 727 +/ 728 @property void opDispatch(string swizzle)(in T v) if (swizzle.length == 1 && coordName.length > 0) { 729 import std.string : indexOf; 730 enum index = coordName.indexOf(swizzle[0]); 731 static if (index >= 0) { 732 packedElements.arr[index] = v; 733 }else{ 734 static assert (false); 735 } 736 } 737 738 /++ 739 +/ 740 @property void opDispatch(string swizzle,V)(in V v) if (swizzle.length > 0 && swizzle.length < coordName.length && coordName.length > 0 && isVector!V) { 741 import std.string : indexOf; 742 import std.array : array; 743 import std.conv : to; 744 import std.range : iota,zip; 745 import std.algorithm.iteration : map,reduce; 746 import std.traits; 747 static if (is(T == Unqual!(typeof(v.packedElements.arr[0])))){ 748 enum indecies = swizzle.map!(charcter => coordName.indexOf(charcter)).array; 749 mixin(swizzle.length.iota 750 .zip(indecies) 751 .map!(pair => "packedElements.arr["~pair[1].to!string~"] = v.packedElements.arr["~pair[0].to!string~"];") 752 .reduce!"a~b" 753 ); 754 } 755 } 756 } 757 758 unittest{ 759 auto vec = Vector3f(1.0,2.0,3.0); 760 761 assert(vec.x == 1.0); 762 assert(vec.z == 3.0); 763 764 assert(vec.xy == Vector2f(1.0,2.0)); 765 assert(vec.zx == Vector2f(3.0,1.0)); 766 767 static assert (!__traits(compiles, vec.xw)); 768 } 769 770 unittest{ 771 const vec = Vector3f(1.0,2.0,3.0); 772 773 assert(vec.x == 1.0); 774 assert(vec.z == 3.0); 775 776 assert(vec.xy == Vector2f(1.0,2.0)); 777 assert(vec.zx == Vector2f(3.0,1.0)); 778 } 779 780 unittest{ 781 auto vec = Vector3f(1.0,2.0,3.0); 782 vec.x = 4.0; 783 assert (vec == Vector3f(4.0,2.0,3.0)); 784 785 static assert (!__traits(compiles,vec.w = 1.0)); 786 } 787 788 unittest{ 789 auto vec = Vector3f(2.0,4.0,6.0); 790 vec.yx = Vector2f(0.0,1.0); 791 assert (vec == Vector3f(1.0,0.0,6.0)); 792 793 static assert (!__traits(compiles,vec.xw = Vector2f(0.0,0.0))); 794 } 795 796 /// int型の2次元ベクトルです. 797 alias Vector!(int, 2) Vector2i; 798 /// int型の3次元ベクトルです. 799 alias Vector!(int, 3) Vector3i; 800 /// int型の4次元ベクトルです. 801 alias Vector!(int, 4) Vector4i; 802 /// float型の2次元ベクトルです. 803 alias Vector!(float, 2) Vector2f; 804 /// float型の3次元ベクトルです. 805 alias Vector!(float, 3) Vector3f; 806 /// float型の4次元ベクトルです. 807 alias Vector!(float, 4) Vector4f; 808 /// double型の2次元ベクトルです. 809 alias Vector!(double, 2) Vector2d; 810 /// double型の3次元ベクトルです. 811 alias Vector!(double, 3) Vector3d; 812 /// double型の4次元ベクトルです. 813 alias Vector!(double, 4) Vector4d; 814 815 /++ 816 +/ 817 template isVector(V) { 818 public{ 819 enum bool isVector = __traits(compiles, (){ 820 static assert(is(V == Vector!(typeof(V()[0]), V.dimention))); 821 }); 822 }//public 823 }//template isVector 824 unittest{ 825 static assert(isVector!(Vector!(float, 3))); 826 static assert(!isVector!(float)); 827 } 828 829 830 private template expandFor(string stmt,size_t Limit) { 831 import std.algorithm.iteration : map; 832 import std.range : iota,repeat,join,zip; 833 import std.format : format; 834 enum expandFor = Limit 835 .iota 836 .map!(idx => format(stmt,idx)) 837 .join; 838 } 839 unittest { 840 static assert (expandFor!("xs[%1$d] + ys[%1$d];",3) == "xs[0] + ys[0];xs[1] + ys[1];xs[2] + ys[2];"); 841 }