1 /************************************************************************/ 2 /* */ 3 /* Copyright 2010-2011 by Ullrich Koethe */ 4 /* */ 5 /* This file is part of the VIGRA computer vision library. */ 6 /* The VIGRA Website is */ 7 /* http://hci.iwr.uni-heidelberg.de/vigra/ */ 8 /* Please direct questions, bug reports, and contributions to */ 9 /* ullrich.koethe@iwr.uni-heidelberg.de or */ 10 /* vigra@informatik.uni-hamburg.de */ 11 /* */ 12 /* Permission is hereby granted, free of charge, to any person */ 13 /* obtaining a copy of this software and associated documentation */ 14 /* files (the "Software"), to deal in the Software without */ 15 /* restriction, including without limitation the rights to use, */ 16 /* copy, modify, merge, publish, distribute, sublicense, and/or */ 17 /* sell copies of the Software, and to permit persons to whom the */ 18 /* Software is furnished to do so, subject to the following */ 19 /* conditions: */ 20 /* */ 21 /* The above copyright notice and this permission notice shall be */ 22 /* included in all copies or substantial portions of the */ 23 /* Software. */ 24 /* */ 25 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND */ 26 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ 27 /* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */ 28 /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT */ 29 /* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ 30 /* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */ 31 /* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */ 32 /* OTHER DEALINGS IN THE SOFTWARE. */ 33 /* */ 34 /************************************************************************/ 35 36 #ifndef VIGRA_AXISTAGS_HXX 37 #define VIGRA_AXISTAGS_HXX 38 39 #include "utilities.hxx" 40 #include "array_vector.hxx" 41 #include "algorithm.hxx" 42 #include "error.hxx" 43 #include "functorexpression.hxx" 44 #include <string> 45 #include <sstream> 46 #include <iomanip> 47 48 namespace vigra { 49 50 class AxisInfo 51 { 52 public: 53 54 // this particular assignment of bits to types is crucial for 55 // canonical axis ordering 56 enum AxisType { Channels = 1, 57 Space = 2, 58 Angle = 4, 59 Time = 8, 60 Frequency = 16, 61 Edge = 32, 62 UnknownAxisType = 64, 63 NonChannel = Space | Angle | Time | Frequency | UnknownAxisType, 64 AllAxes = 2*UnknownAxisType-1 }; 65 AxisInfo(std::string key="?",AxisType typeFlags=UnknownAxisType,double resolution=0.0,std::string description="")66 AxisInfo(std::string key = "?", AxisType typeFlags = UnknownAxisType, 67 double resolution = 0.0, std::string description = "") 68 : key_(key), 69 description_(description), 70 resolution_(resolution), 71 flags_(typeFlags) 72 {} 73 key() const74 std::string key() const 75 { 76 return key_; 77 } 78 description() const79 std::string description() const 80 { 81 return description_; 82 } 83 setDescription(std::string const & description)84 void setDescription(std::string const & description) 85 { 86 description_ = description; 87 } 88 resolution() const89 double resolution() const 90 { 91 return resolution_; 92 } 93 setResolution(double resolution)94 void setResolution(double resolution) 95 { 96 resolution_ = resolution; 97 } 98 typeFlags() const99 AxisType typeFlags() const 100 { 101 return flags_ == 0 102 ? UnknownAxisType 103 : flags_; 104 } 105 isUnknown() const106 bool isUnknown() const 107 { 108 return isType(UnknownAxisType); 109 } 110 isSpatial() const111 bool isSpatial() const 112 { 113 return isType(Space); 114 } 115 isTemporal() const116 bool isTemporal() const 117 { 118 return isType(Time); 119 } 120 isChannel() const121 bool isChannel() const 122 { 123 return isType(Channels); 124 } 125 isFrequency() const126 bool isFrequency() const 127 { 128 return isType(Frequency); 129 } 130 isEdge() const131 bool isEdge() const 132 { 133 return isType(Edge); 134 } 135 isAngular() const136 bool isAngular() const 137 { 138 return isType(Angle); 139 } 140 isType(AxisType type) const141 bool isType(AxisType type) const 142 { 143 return (typeFlags() & type) != 0; 144 } 145 repr() const146 std::string repr() const 147 { 148 std::string res("AxisInfo: '"); 149 res += key_ + "' (type:"; 150 if(isUnknown()) 151 { 152 res += " none"; 153 } 154 else 155 { 156 if(isChannel()) 157 res += " Channels"; 158 if(isSpatial()) 159 res += " Space"; 160 if(isTemporal()) 161 res += " Time"; 162 if(isAngular()) 163 res += " Angle"; 164 if(isFrequency()) 165 res += " Frequency"; 166 } 167 if(resolution_ > 0.0) 168 { 169 res += ", resolution="; 170 res += asString(resolution_); 171 } 172 res += ")"; 173 if(description_ != "") 174 { 175 res += " "; 176 res += description_; 177 } 178 return res; 179 } 180 toFrequencyDomain(unsigned int size=0,int sign=1) const181 AxisInfo toFrequencyDomain(unsigned int size = 0, int sign = 1) const 182 { 183 AxisType type; 184 if(sign == 1) 185 { 186 vigra_precondition(!isFrequency(), 187 "AxisInfo::toFrequencyDomain(): axis is already in the Fourier domain."); 188 type = AxisType(Frequency | flags_); 189 } 190 else 191 { 192 vigra_precondition(isFrequency(), 193 "AxisInfo::fromFrequencyDomain(): axis is not in the Fourier domain."); 194 type = AxisType(~Frequency & flags_); 195 } 196 AxisInfo res(key(), type, 0.0, description_); 197 if(resolution_ > 0.0 && size > 0u) 198 res.resolution_ = 1.0 / (resolution_ * size); 199 return res; 200 } 201 fromFrequencyDomain(unsigned int size=0) const202 AxisInfo fromFrequencyDomain(unsigned int size = 0) const 203 { 204 return toFrequencyDomain(size, -1); 205 } 206 compatible(AxisInfo const & other) const207 bool compatible(AxisInfo const & other) const 208 { 209 return isUnknown() || other.isUnknown() || 210 ((typeFlags() & ~Frequency) == (other.typeFlags() & ~Frequency) && 211 key() == other.key()); 212 } 213 operator ==(AxisInfo const & other) const214 bool operator==(AxisInfo const & other) const 215 { 216 return typeFlags() == other.typeFlags() && key() == other.key(); 217 } 218 operator !=(AxisInfo const & other) const219 bool operator!=(AxisInfo const & other) const 220 { 221 return !operator==(other); 222 } 223 224 // the primary ordering is according to axis type: 225 // Channels < Space < Angle < Time < Frequency < Unknown 226 // the secondary ordering is the lexicographic ordering of the keys 227 // "x" < "y" < "z" operator <(AxisInfo const & other) const228 bool operator<(AxisInfo const & other) const 229 { 230 return (typeFlags() < other.typeFlags()) || 231 (typeFlags() == other.typeFlags() && key() < other.key()); 232 } 233 operator <=(AxisInfo const & other) const234 bool operator<=(AxisInfo const & other) const 235 { 236 return !(other < *this); 237 } 238 operator >(AxisInfo const & other) const239 bool operator>(AxisInfo const & other) const 240 { 241 return other < *this; 242 } 243 operator >=(AxisInfo const & other) const244 bool operator>=(AxisInfo const & other) const 245 { 246 return !(*this < other); 247 } 248 249 // factory functions for standard tags x(double resolution=0.0,std::string const & description="")250 static AxisInfo x(double resolution = 0.0, std::string const & description = "") 251 { 252 return AxisInfo("x", Space, resolution, description); 253 } 254 y(double resolution=0.0,std::string const & description="")255 static AxisInfo y(double resolution = 0.0, std::string const & description = "") 256 { 257 return AxisInfo("y", Space, resolution, description); 258 } 259 z(double resolution=0.0,std::string const & description="")260 static AxisInfo z(double resolution = 0.0, std::string const & description = "") 261 { 262 return AxisInfo("z", Space, resolution, description); 263 } 264 n(double resolution=0.0,std::string const & description="")265 static AxisInfo n(double resolution = 0.0, std::string const & description = "") 266 { 267 return AxisInfo("n", Space, resolution, description); 268 } 269 e(double resolution=0.0,std::string const & description="")270 static AxisInfo e(double resolution = 0.0, std::string const & description = "") 271 { 272 return AxisInfo("e", Edge, resolution, description); 273 } 274 t(double resolution=0.0,std::string const & description="")275 static AxisInfo t(double resolution = 0.0, std::string const & description = "") 276 { 277 return AxisInfo("t", Time, resolution, description); 278 } 279 fx(double resolution=0.0,std::string const & description="")280 static AxisInfo fx(double resolution = 0.0, std::string const & description = "") 281 { 282 return AxisInfo("x", AxisType(Space | Frequency), resolution, description); 283 } 284 fy(double resolution=0.0,std::string const & description="")285 static AxisInfo fy(double resolution = 0.0, std::string const & description = "") 286 { 287 return AxisInfo("y", AxisType(Space | Frequency), resolution, description); 288 } 289 fz(double resolution=0.0,std::string const & description="")290 static AxisInfo fz(double resolution = 0.0, std::string const & description = "") 291 { 292 return AxisInfo("z", AxisType(Space | Frequency), resolution, description); 293 } 294 ft(double resolution=0.0,std::string const & description="")295 static AxisInfo ft(double resolution = 0.0, std::string const & description = "") 296 { 297 return AxisInfo("t", AxisType(Time | Frequency), resolution, description); 298 } 299 c(std::string const & description="")300 static AxisInfo c(std::string const & description = "") 301 { 302 return AxisInfo("c", Channels, 0.0, description); 303 } 304 305 std::string key_, description_; 306 double resolution_; 307 AxisType flags_; 308 }; 309 310 class AxisTags 311 { 312 public: 313 AxisTags()314 AxisTags() 315 {} 316 AxisTags(int size)317 AxisTags(int size) 318 : axes_(size) 319 {} 320 AxisTags(AxisInfo const & i1)321 AxisTags(AxisInfo const & i1) 322 { 323 push_back(i1); 324 } 325 AxisTags(AxisInfo const & i1,AxisInfo const & i2)326 AxisTags(AxisInfo const & i1, AxisInfo const & i2) 327 { 328 push_back(i1); 329 push_back(i2); 330 } 331 AxisTags(AxisInfo const & i1,AxisInfo const & i2,AxisInfo const & i3)332 AxisTags(AxisInfo const & i1, AxisInfo const & i2, AxisInfo const & i3) 333 { 334 push_back(i1); 335 push_back(i2); 336 push_back(i3); 337 } 338 AxisTags(AxisInfo const & i1,AxisInfo const & i2,AxisInfo const & i3,AxisInfo const & i4)339 AxisTags(AxisInfo const & i1, AxisInfo const & i2, 340 AxisInfo const & i3, AxisInfo const & i4) 341 { 342 push_back(i1); 343 push_back(i2); 344 push_back(i3); 345 push_back(i4); 346 } 347 AxisTags(AxisInfo const & i1,AxisInfo const & i2,AxisInfo const & i3,AxisInfo const & i4,AxisInfo const & i5)348 AxisTags(AxisInfo const & i1, AxisInfo const & i2, 349 AxisInfo const & i3, AxisInfo const & i4, AxisInfo const & i5) 350 { 351 push_back(i1); 352 push_back(i2); 353 push_back(i3); 354 push_back(i4); 355 push_back(i5); 356 } 357 AxisTags(std::string const & tags)358 AxisTags(std::string const & tags) 359 { 360 for(std::string::size_type k=0; k<tags.size(); ++k) 361 { 362 switch(tags[k]) 363 { 364 case 'x': 365 push_back(AxisInfo::x()); 366 break; 367 case 'y': 368 push_back(AxisInfo::y()); 369 break; 370 case 'z': 371 push_back(AxisInfo::z()); 372 break; 373 case 't': 374 push_back(AxisInfo::t()); 375 break; 376 case 'c': 377 push_back(AxisInfo::c()); 378 break; 379 case 'f': 380 ++k; 381 vigra_precondition(k < tags.size(), 382 "AxisTags(string): invalid input"); 383 switch(tags[k]) 384 { 385 case 'x': 386 push_back(AxisInfo::fx()); 387 break; 388 case 'y': 389 push_back(AxisInfo::fy()); 390 break; 391 case 'z': 392 push_back(AxisInfo::fz()); 393 break; 394 case 't': 395 push_back(AxisInfo::ft()); 396 break; 397 default: 398 vigra_precondition(false, 399 "AxisTags(string): invalid input"); 400 } 401 break; 402 default: 403 vigra_precondition(false, 404 "AxisTags(string): invalid input"); 405 } 406 } 407 } 408 409 // static AxisTags fromJSON(std::string const & repr); 410 toJSON() const411 std::string toJSON() const 412 { 413 std::stringstream s; 414 s << "{\n \"axes\": ["; 415 for(unsigned int k=0; k<size(); ++k) 416 { 417 if(k > 0) 418 s << ","; 419 s << "\n"; 420 s << " {\n"; 421 s << " \"key\": \"" << axes_[k].key() << "\",\n"; 422 s << " \"typeFlags\": " << (unsigned int)axes_[k].typeFlags() << ",\n"; 423 s << " \"resolution\": " << std::setprecision(17) << axes_[k].resolution() << ",\n"; 424 s << " \"description\": \"" << axes_[k].description() << "\"\n"; 425 s << " }"; 426 } 427 s << "\n ]\n}"; 428 return s.str(); 429 } 430 size() const431 unsigned int size() const 432 { 433 return axes_.size(); 434 } 435 axisTypeCount(AxisInfo::AxisType type) const436 int axisTypeCount(AxisInfo::AxisType type) const 437 { 438 int res = 0; 439 for(unsigned int k=0; k<size(); ++k) 440 if(axes_[k].isType(type)) 441 ++res; 442 return res; 443 } 444 repr() const445 std::string repr() const 446 { 447 std::string res; 448 if(size() > 0) 449 res += axes_[0].key(); 450 for(unsigned int k=1; k<size(); ++k) 451 { 452 res += " "; 453 res += axes_[k].key(); 454 } 455 return res; 456 } 457 contains(std::string const & key) const458 bool contains(std::string const & key) const 459 { 460 return index(key) < (int)size(); 461 } 462 get(int k)463 AxisInfo & get(int k) 464 { 465 checkIndex(k); 466 if(k < 0) 467 k += size(); 468 return axes_[k]; 469 } 470 get(std::string const & key)471 AxisInfo & get(std::string const & key) 472 { 473 return get(index(key)); 474 } 475 get(int k) const476 AxisInfo const & get(int k) const 477 { 478 checkIndex(k); 479 if(k < 0) 480 k += size(); 481 return axes_[k]; 482 } 483 get(std::string const & key) const484 AxisInfo const & get(std::string const & key) const 485 { 486 return get(index(key)); 487 } 488 set(int k,AxisInfo const & info)489 void set(int k, AxisInfo const & info) 490 { 491 checkIndex(k); 492 if(k < 0) 493 k += size(); 494 checkDuplicates(k, info); 495 axes_[k] = info; 496 } 497 set(std::string const & key,AxisInfo const & info)498 void set(std::string const & key, AxisInfo const & info) 499 { 500 set(index(key), info); 501 } 502 insert(int k,AxisInfo const & i)503 void insert(int k, AxisInfo const & i) 504 { 505 if(k == (int)size()) 506 { 507 push_back(i); 508 } 509 else 510 { 511 checkIndex(k); 512 if(k < 0) 513 k += size(); 514 checkDuplicates(size(), i); 515 axes_.insert(axes_.begin()+k, i); 516 } 517 } 518 push_back(AxisInfo const & i)519 void push_back(AxisInfo const & i) 520 { 521 checkDuplicates(size(), i); 522 axes_.push_back(i); 523 } 524 dropAxis(int k)525 void dropAxis(int k) 526 { 527 checkIndex(k); 528 ArrayVector<AxisInfo>::iterator i = k < 0 529 ? axes_.end() + k 530 : axes_.begin() + k; 531 axes_.erase(i, i+1); 532 } 533 dropAxis(std::string const & key)534 void dropAxis(std::string const & key) 535 { 536 dropAxis(index(key)); 537 } 538 dropChannelAxis()539 void dropChannelAxis() 540 { 541 int k = channelIndex(); 542 if(k < (int)size()) 543 axes_.erase(axes_.begin() + k, axes_.begin() + k + 1); 544 } 545 index(std::string const & key) const546 int index(std::string const & key) const 547 { 548 for(unsigned int k=0; k<size(); ++k) 549 if(axes_[k].key() == key) 550 return k; 551 return (int)size(); 552 } 553 resolution(int k) const554 double resolution(int k) const 555 { 556 return get(k).resolution_; 557 } 558 resolution(std::string const & key) const559 double resolution(std::string const & key) const 560 { 561 return resolution(index(key)); 562 } 563 setResolution(int k,double r)564 void setResolution(int k, double r) 565 { 566 get(k).resolution_ = r; 567 } 568 setResolution(std::string const & key,double r)569 void setResolution(std::string const & key, double r) 570 { 571 setResolution(index(key), r); 572 } 573 scaleResolution(int k,double factor)574 void scaleResolution(int k, double factor) 575 { 576 get(k).resolution_ *= factor; 577 } 578 scaleResolution(std::string const & key,double factor)579 void scaleResolution(std::string const & key, double factor) 580 { 581 get(key).resolution_ *= factor; 582 } 583 description(int k) const584 std::string description(int k) const 585 { 586 return get(k).description_; 587 } 588 description(std::string const & key) const589 std::string description(std::string const & key) const 590 { 591 return description(index(key)); 592 } 593 setDescription(int k,std::string const & d)594 void setDescription(int k, std::string const & d) 595 { 596 get(k).setDescription(d); 597 } 598 setDescription(std::string const & key,std::string const & d)599 void setDescription(std::string const & key, std::string const & d) 600 { 601 setDescription(index(key), d); 602 } 603 setChannelDescription(std::string const & description)604 void setChannelDescription(std::string const & description) 605 { 606 int k = channelIndex(); 607 if(k < (int)size()) 608 axes_[k].setDescription(description); 609 } 610 toFrequencyDomain(int k,int size=0,int sign=1)611 void toFrequencyDomain(int k, int size = 0, int sign = 1) 612 { 613 get(k) = get(k).toFrequencyDomain(size, sign); 614 } 615 toFrequencyDomain(std::string const & key,int size=0,int sign=1)616 void toFrequencyDomain(std::string const & key, int size = 0, int sign = 1) 617 { 618 toFrequencyDomain(index(key), size, sign); 619 } 620 fromFrequencyDomain(int k,int size=0)621 void fromFrequencyDomain(int k, int size = 0) 622 { 623 toFrequencyDomain(k, size, -1); 624 } 625 fromFrequencyDomain(std::string const & key,int size=0)626 void fromFrequencyDomain(std::string const & key, int size = 0) 627 { 628 toFrequencyDomain(key, size, -1); 629 } 630 hasChannelAxis() const631 bool hasChannelAxis() const 632 { 633 return channelIndex() != (int)size(); 634 } 635 636 // FIXME: cache the results of these functions? channelIndex() const637 int channelIndex() const 638 { 639 for(unsigned int k=0; k<size(); ++k) 640 if(axes_[k].isChannel()) 641 return k; 642 return (int)size(); 643 } 644 innerNonchannelIndex() const645 int innerNonchannelIndex() const 646 { 647 int k = 0; 648 for(; k<(int)size(); ++k) 649 if(!axes_[k].isChannel()) 650 break; 651 for(int i=k+1; i<(int)size(); ++i) 652 { 653 if(axes_[i].isChannel()) 654 continue; 655 if(axes_[i] < axes_[k]) 656 k = i; 657 } 658 return k; 659 } 660 swapaxes(int i1,int i2)661 void swapaxes(int i1, int i2) 662 { 663 checkIndex(i1); 664 checkIndex(i2); 665 if(i1 < 0) 666 i1 += size(); 667 if(i2 < 0) 668 i2 += size(); 669 std::swap(axes_[i1], axes_[i2]); 670 } 671 672 template <class T> transpose(ArrayVector<T> const & permutation)673 void transpose(ArrayVector<T> const & permutation) 674 { 675 if(permutation.size() == 0) 676 { 677 transpose(); 678 } 679 else 680 { 681 vigra_precondition(permutation.size() == size(), 682 "AxisTags::transpose(): Permutation has wrong size."); 683 ArrayVector<AxisInfo> newAxes(size()); 684 applyPermutation(permutation.begin(), permutation.end(), axes_.begin(), newAxes.begin()); 685 axes_.swap(newAxes); 686 } 687 } 688 transpose()689 void transpose() 690 { 691 std::reverse(axes_.begin(), axes_.end()); 692 } 693 694 template <class T> 695 void permutationToNormalOrder(ArrayVector<T> & permutation) const696 permutationToNormalOrder(ArrayVector<T> & permutation) const 697 { 698 permutation.resize(size()); 699 indexSort(axes_.begin(), axes_.end(), permutation.begin()); 700 } 701 702 template <class T> 703 void permutationToNormalOrder(ArrayVector<T> & permutation,AxisInfo::AxisType types) const704 permutationToNormalOrder(ArrayVector<T> & permutation, AxisInfo::AxisType types) const 705 { 706 ArrayVector<AxisInfo> matchingAxes; 707 for(int k=0; k<(int)size(); ++k) 708 if(axes_[k].isType(types)) 709 matchingAxes.push_back(axes_[k]); 710 permutation.resize(matchingAxes.size()); 711 indexSort(matchingAxes.begin(), matchingAxes.end(), permutation.begin()); 712 } 713 714 template <class T> 715 void permutationFromNormalOrder(ArrayVector<T> & inverse_permutation) const716 permutationFromNormalOrder(ArrayVector<T> & inverse_permutation) const 717 { 718 ArrayVector<T> permutation; 719 permutationToNormalOrder(permutation); 720 inverse_permutation.resize(permutation.size()); 721 indexSort(permutation.begin(), permutation.end(), inverse_permutation.begin()); 722 } 723 724 template <class T> 725 void permutationFromNormalOrder(ArrayVector<T> & inverse_permutation,AxisInfo::AxisType types) const726 permutationFromNormalOrder(ArrayVector<T> & inverse_permutation, AxisInfo::AxisType types) const 727 { 728 ArrayVector<T> permutation; 729 permutationToNormalOrder(permutation, types); 730 inverse_permutation.resize(permutation.size()); 731 indexSort(permutation.begin(), permutation.end(), inverse_permutation.begin()); 732 } 733 734 template <class T> permutationToNumpyOrder(ArrayVector<T> & permutation) const735 void permutationToNumpyOrder(ArrayVector<T> & permutation) const 736 { 737 permutationToNormalOrder(permutation); 738 std::reverse(permutation.begin(), permutation.end()); 739 } 740 741 template <class T> permutationFromNumpyOrder(ArrayVector<T> & inverse_permutation) const742 void permutationFromNumpyOrder(ArrayVector<T> & inverse_permutation) const 743 { 744 ArrayVector<T> permutation; 745 permutationToNumpyOrder(permutation); 746 inverse_permutation.resize(permutation.size()); 747 indexSort(permutation.begin(), permutation.end(), inverse_permutation.begin()); 748 } 749 750 template <class T> permutationToVigraOrder(ArrayVector<T> & permutation) const751 void permutationToVigraOrder(ArrayVector<T> & permutation) const 752 { 753 permutation.resize(size()); 754 indexSort(axes_.begin(), axes_.end(), permutation.begin()); 755 int channel = channelIndex(); 756 if(channel < (int)size()) 757 { 758 for(int k=1; k<(int)size(); ++k) 759 permutation[k-1] = permutation[k]; 760 permutation.back() = channel; 761 } 762 } 763 764 template <class T> permutationFromVigraOrder(ArrayVector<T> & inverse_permutation) const765 void permutationFromVigraOrder(ArrayVector<T> & inverse_permutation) const 766 { 767 ArrayVector<T> permutation; 768 permutationToVigraOrder(permutation); 769 inverse_permutation.resize(permutation.size()); 770 indexSort(permutation.begin(), permutation.end(), inverse_permutation.begin()); 771 } 772 773 template <class T> permutationToOrder(ArrayVector<T> & permutation,std::string const & order) const774 void permutationToOrder(ArrayVector<T> & permutation, std::string const & order) const 775 { 776 if(order == "A") 777 { 778 permutation.resize(size()); 779 linearSequence(permutation.begin(), permutation.end()); 780 } 781 else if(order == "C") 782 { 783 permutationToNumpyOrder(permutation); 784 } 785 else if(order == "F") 786 { 787 permutationToNormalOrder(permutation); 788 } 789 else if(order == "V") 790 { 791 permutationToVigraOrder(permutation); 792 } 793 else 794 { 795 vigra_precondition(false, 796 "AxisTags::permutationToOrder(): unknown order '" + order + "'."); 797 } 798 } 799 800 #if 0 801 ArrayVector<UInt32> matchOrdering(AxisTags const & other) 802 { 803 vigra_precondition(size() == other.size(), 804 "AxisTags::matchOrdering(): size mismatch."); 805 806 ArrayVector<UInt32> permutation(size()); 807 for(unsigned int k = 0; k<size(); ++k) 808 { 809 std::string key = other.get(k).key(); 810 unsigned int l=0; 811 for(; l<size(); ++l) 812 { 813 if(key == get(l).key()) 814 break; 815 } 816 vigra_precondition(l < size(), 817 "AxisTags::matchOrdering(): key mismatch."); 818 permutation[k] = l; 819 } 820 return permutation; 821 } 822 #endif 823 compatible(AxisTags const & other) const824 bool compatible(AxisTags const & other) const 825 { 826 if(size() == 0 || other.size() == 0) 827 return true; 828 if(size() != other.size()) 829 return false; 830 for(unsigned int k=0; k<size(); ++k) 831 if(!axes_[k].compatible(other.axes_[k])) 832 return false; 833 return true; 834 } 835 operator ==(AxisTags const & other) const836 bool operator==(AxisTags const & other) const 837 { 838 if(size() != other.size()) 839 return false; 840 return std::equal(axes_.begin(), axes_.end(), other.axes_.begin()); 841 } 842 operator !=(AxisTags const & other) const843 bool operator!=(AxisTags const & other) const 844 { 845 return !operator==(other); 846 } 847 848 protected: 849 checkIndex(int k) const850 void checkIndex(int k) const 851 { 852 vigra_precondition(k < (int)size() && k >= -(int)size(), 853 "AxisTags::checkIndex(): index out of range."); 854 } 855 checkDuplicates(int i,AxisInfo const & info)856 void checkDuplicates(int i, AxisInfo const & info) 857 { 858 if(info.isChannel()) 859 { 860 for(int k=0; k<(int)size(); ++k) 861 { 862 vigra_precondition(k == i || !axes_[k].isChannel(), 863 "AxisTags::checkDuplicates(): can only have one channel axis."); 864 } 865 } 866 else if(!info.isUnknown()) 867 { 868 for(int k=0; k<(int)size(); ++k) 869 { 870 vigra_precondition(k == i || axes_[k].key() != info.key(), 871 std::string("AxisTags::checkDuplicates(): axis key '" + 872 info.key() + "' already exists.")); 873 } 874 } 875 } 876 877 ArrayVector<AxisInfo> axes_; 878 }; 879 880 // #if 0 881 // struct PyGetFunctor 882 // { 883 // AxisInfo const & operator()(python::object const & o) const 884 // { 885 // return python::extract<AxisInfo const &>(o)(); 886 // } 887 // }; 888 889 // class PyAxisTags 890 // : public AxisTags<python::object, PyGetFunctor> 891 // { 892 // typedef AxisTags<python::object, PyGetFunctor> BaseType; 893 // public: 894 // PyAxisTags() 895 // {} 896 897 // PyAxisTags(python::object i1, python::object i2, 898 // python::object i3, python::object i4, python::object i5) 899 // { 900 // if(PySequence_Check(i1.ptr())) 901 // { 902 // int size = len(i1); 903 // for(int k=0; k<size; ++k) 904 // if(python::extract<AxisInfo const &>(i1[k]).check()) 905 // push_back(i1[k]); 906 // } 907 // else if(PyInt_Check(i1.ptr())) 908 // { 909 // int size = python::extract<int>(i1)(); 910 // for(int k=0; k<size; ++k) 911 // push_back(python::object(AxisInfo())); 912 // } 913 // else 914 // { 915 // if(python::extract<AxisInfo const &>(i1).check()) 916 // push_back(i1); 917 // if(python::extract<AxisInfo const &>(i2).check()) 918 // push_back(i2); 919 // if(python::extract<AxisInfo const &>(i3).check()) 920 // push_back(i3); 921 // if(python::extract<AxisInfo const &>(i4).check()) 922 // push_back(i4); 923 // if(python::extract<AxisInfo const &>(i5).check()) 924 // push_back(i5); 925 // } 926 // } 927 928 // python::object getitem(int k) 929 // { 930 // if(!checkIndex(k)) 931 // { 932 // PyErr_SetString(PyExc_IndexError, "AxisInfo::getitem(): Invalid index or key."); 933 // python::throw_error_already_set(); 934 // } 935 // if(k < 0) 936 // k += this->size(); 937 // return this->axes_[k]; 938 // } 939 940 // python::object getitem(std::string const & key) 941 // { 942 // return getitem(this->findKey(key)); 943 // } 944 945 // void setitem(int k, python::object i) 946 // { 947 // if(!this->checkIndex(k)) 948 // { 949 // PyErr_SetString(PyExc_IndexError, "AxisInfo::setitem(): Invalid index or key."); 950 // python::throw_error_already_set(); 951 // } 952 // if(!python::extract<AxisInfo const &>(i).check()) 953 // { 954 // PyErr_SetString(PyExc_TypeError, "AxisInfo::setitem(): Item type must be AxisInfo."); 955 // python::throw_error_already_set(); 956 // } 957 958 // if(k < 0) 959 // k += this->size(); 960 // this->axes_[k] = i; 961 // } 962 963 // void setitem(std::string const & key, python::object i) 964 // { 965 // setitem(this->findKey(key), i); 966 // } 967 968 // void append(python::object i) 969 // { 970 // insert(size(), i); 971 // } 972 973 // void insert(int k, python::object i) 974 // { 975 // if(k < 0) 976 // k += this->size(); 977 // if(k < 0) 978 // k = 0; 979 // if(k > (int)this->size()) 980 // k = this->size(); 981 // if(!python::extract<AxisInfo const &>(i).check()) 982 // { 983 // PyErr_SetString(PyExc_TypeError, "AxisInfo::insert(): Item type must be AxisInfo."); 984 // python::throw_error_already_set(); 985 // } 986 // this->axes_.insert(this->axes_.begin()+k, i); 987 // } 988 989 // void insert(std::string const & key, python::object i) 990 // { 991 // insert(this->findKey(key), i); 992 // } 993 994 // python::list axesByFlag(AxisType typeFlags) const 995 // { 996 // python::list res; 997 // for(unsigned int k=0; k<this->size(); ++k) 998 // if(this->get(k).typeFlags() == typeFlags) 999 // res.append(k); 1000 // return res; 1001 // } 1002 1003 // python::list spatialAxes() const 1004 // { 1005 // python::list res; 1006 // for(unsigned int k=0; k<this->size(); ++k) 1007 // if(this->get(k).isSpatial()) 1008 // res.append(k); 1009 // return res; 1010 // } 1011 1012 // python::list temporalAxes() const 1013 // { 1014 // python::list res; 1015 // for(unsigned int k=0; k<this->size(); ++k) 1016 // if(this->get(k).isTemporal()) 1017 // res.append(k); 1018 // return res; 1019 // } 1020 1021 // python::list channelAxes() const 1022 // { 1023 // python::list res; 1024 // for(unsigned int k=0; k<this->size(); ++k) 1025 // if(this->get(k).isChannel()) 1026 // res.append(k); 1027 // return res; 1028 // } 1029 1030 // python::list frequencyAxes() const 1031 // { 1032 // python::list res; 1033 // for(unsigned int k=0; k<this->size(); ++k) 1034 // if(this->get(k).isFrequency()) 1035 // res.append(k); 1036 // return res; 1037 // } 1038 1039 // python::list angularAxes() const 1040 // { 1041 // python::list res; 1042 // for(unsigned int k=0; k<this->size(); ++k) 1043 // if(this->get(k).isAngular()) 1044 // res.append(k); 1045 // return res; 1046 // } 1047 1048 // python::list untaggedAxes() const 1049 // { 1050 // python::list res; 1051 // for(unsigned int k=0; k<this->size(); ++k) 1052 // if(this->get(k).isUnknown()) 1053 // res.append(k); 1054 // return res; 1055 // } 1056 1057 // template <class U> 1058 // python::list vectorToPython(ArrayVector<U> const & v) const 1059 // { 1060 // python::list res; 1061 // for(unsigned int k=0; k<v.size(); ++k) 1062 // res.append(v[k]); 1063 // return res; 1064 // } 1065 1066 // python::list canonicalOrdering() 1067 // { 1068 // return vectorToPython(BaseType::canonicalOrdering()); 1069 // } 1070 1071 // python::list matchOrdering(PyAxisTags const & other) 1072 // { 1073 // return vectorToPython(BaseType::matchOrdering(other)); 1074 // } 1075 1076 // void transpose(python::object const & o) 1077 // { 1078 // unsigned int osize = len(o); 1079 // ArrayVector<UInt32> permutation(osize); 1080 1081 // for(unsigned int k=0; k<this->size(); ++k) 1082 // permutation[k] = python::extract<UInt32>(o[k])(); 1083 1084 // BaseType::transpose(permutation); 1085 // } 1086 1087 // void transpose() 1088 // { 1089 // BaseType::transpose(); 1090 // } 1091 // }; 1092 1093 // class TaggedShape 1094 // { 1095 // public: 1096 1097 // ArrayVector<npy_intp> shape; 1098 // python_ptr axistags; 1099 // npy_intp channelCount; 1100 // std::string channelDescription; 1101 1102 // TaggedShape(MultiArrayIndex size) 1103 // : shape(size) 1104 // {} 1105 1106 // template <int N> 1107 // TaggedShape(typename MultiArrayShape<N>::type const & sh) 1108 // : shape(sh.begin(), sh.end()) 1109 // {} 1110 1111 // npy_intp & operator[](int i) 1112 // { 1113 // // rotate indices so that channels are located at index 0 1114 // return shape[(i+1) % shape.size()]; 1115 // } 1116 1117 // npy_intp operator[](int i) const 1118 // { 1119 // return shape[(i+1) % shape.size()]; 1120 // } 1121 1122 // unsigned int size() const 1123 // { 1124 // return shape.size(); 1125 // } 1126 1127 // // void setChannelDescription(std::string const & description) 1128 // // { 1129 // // if(axistags) 1130 // // { 1131 // // python_ptr func(PyString_FromString("setChannelDescription"), 1132 // // python_ptr::keep_count); 1133 // // pythonToCppException(res); 1134 1135 // // python_ptr d(PyString_FromString(d.c_str()), python_ptr::keep_count); 1136 // // pythonToCppException(d); 1137 1138 // // python_ptr res(PyObject_CallMethodObjArgs(axistags, func, d.get(), NULL), 1139 // // python_ptr::keep_count); 1140 // // pythonToCppException(res); 1141 // // } 1142 // // } 1143 1144 // // void setChannelCount(int channelCount) 1145 // // { 1146 // // shape[0] = channelCount; 1147 // // } 1148 1149 // void setChannelDescription(std::string const & description) 1150 // { 1151 // channelDescription = description; 1152 // } 1153 1154 // void setChannelCount(int count) 1155 // { 1156 // channelCount = count; 1157 // } 1158 1159 // void setChannelConfig(int channelCount, std::string const & description) 1160 // { 1161 // setChannelCount(channelCount); 1162 // setChannelDescription(description); 1163 // } 1164 // }; 1165 // #endif 1166 1167 } // namespace vigra 1168 1169 #endif /* VIGRA_AXISTAGS_HXX */ 1170