diff --git a/CMakeLists.txt b/CMakeLists.txt index f490a59f7e4196e7c4e0803824c48a7b347b363c..f50cfe6196a3349bb98da27ff3a1305b44240199 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -200,6 +200,7 @@ list(APPEND NGP_INCLUDE_DIRECTORIES "dependencies/eigen" "dependencies/filesystem" "dependencies/nanovdb" + "dependencies/NaturalSort" "dependencies/tinylogger" ) diff --git a/dependencies/NaturalSort/LICENSE.md b/dependencies/NaturalSort/LICENSE.md new file mode 100644 index 0000000000000000000000000000000000000000..02b51c98732138c2f09f660cfe68e838009eeaa8 --- /dev/null +++ b/dependencies/NaturalSort/LICENSE.md @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 Gagan Kumar + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dependencies/NaturalSort/Makefile b/dependencies/NaturalSort/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..4a5e9c20fb652a91212c96e3b255da856d077818 --- /dev/null +++ b/dependencies/NaturalSort/Makefile @@ -0,0 +1,9 @@ +CC = g++ +CFLAGS = -Wall + +test: natural_sort_test.cpp natural_sort.hpp + $(CC) $(CFLAGS) -o $@ $< + ./$@ + +clean: + rm -f test diff --git a/dependencies/NaturalSort/README.md b/dependencies/NaturalSort/README.md new file mode 100644 index 0000000000000000000000000000000000000000..ba172f845d82ca16c24333bbbfc854c1c85da35d --- /dev/null +++ b/dependencies/NaturalSort/README.md @@ -0,0 +1,61 @@ +# NaturalSort  +C++ Header File for Natural Comparison and Natural Sort + + +##### Calling Methods + +* __For Natural Sorting__ + + void SI::natural::sort(Container<String>); + + void SI::natural::sort(IteratorBegin<String>,IteratorEnd<String>); + + void SI::natural::sort<String,CArraySize>(CArray<String>); + + +* __For Natural Comparision__ + + bool SI::natural::compare<String>(String lhs,String rhs); + bool SI::natural::compare<String>(char *const lhs,char *const rhs); + + Here we can have + + std::vector<std::string> as Container<String> + String as std::string + CArray<String> as std::string[CArraySize] + + + + + +##### Example + +* __Inputs__ + + Hello 100 + Hello 34 + Hello 9 + Hello 25 + Hello 10 + Hello 8 + +* __Normal Sort Output__ + + Hello 10 + Hello 100 + Hello 25 + Hello 34 + Hello 8 + Hello 9 + +* __Natural Sort Output__ + + Hello 8 + Hello 9 + Hello 10 + Hello 25 + Hello 34 + Hello 100 + + + diff --git a/dependencies/NaturalSort/natural_sort.hpp b/dependencies/NaturalSort/natural_sort.hpp new file mode 100644 index 0000000000000000000000000000000000000000..2a9856fd4dbdcce1b5800d2b0f96c1a222f31fc3 --- /dev/null +++ b/dependencies/NaturalSort/natural_sort.hpp @@ -0,0 +1,281 @@ +/* + The MIT License (MIT) + Copyright (c) 2016 Gagan Kumar(scopeInfinity) + Complete License at https://raw.githubusercontent.com/scopeInfinity/NaturalSort/master/LICENSE.md +*/ + +/********************************************************************** +Calling Methods : + + //For Natural Sorting + void SI::natural::sort(Container<String>); + void SI::natural::sort(IteratorBegin<String>,IteratorEnd<String>); + void SI::natural::sort<String,CArraySize>(CArray<String>); + + //For Natural Comparision + bool SI::natural::compare<String>(String lhs,String rhs); + bool SI::natural::compare<String>(char *const lhs,char *const rhs); + + Here we can have + std::vector<std::string> as Container<String> + String as std::string + CArray<String> as std::string[CArraySize] + +***********************************************************************/ +#ifndef SI_sort_HPP +#define SI_sort_HPP +#include <cctype> +#include <algorithm> +#include <vector> + + +namespace SI +{ +namespace natural +{ + namespace detail + { + /********** Compare Two Character CaseInsensitive ********/ + template<typename ElementType> + bool natural_less(const ElementType &lhs,const ElementType &rhs) + { + if(tolower(lhs)<tolower(rhs)) + return true; + return false; + } + + template<typename ElementType> + bool is_not_digit(const ElementType &x) + { + return !isdigit(x); + } + + /********** Compare Two Iterators CaseInsensitive ********/ + template<typename ElementType,typename Iterator> + struct comp_over_iterator + { + int operator()(const Iterator &lhs,const Iterator &rhs) const + { + if(natural_less<ElementType>(*lhs,*rhs)) + return -1; + if(natural_less<ElementType>(*rhs,*lhs)) + return +1; + return 0; + } + }; + + /**************************************************** + Comparing two SubString from (Begin,End Iterator each) + with only digits. + Usage : + int compare_number()(\ + FirstNumberBeginIterator,FirstNumberEndIterator,isFirstNumberFractionalPart\ + SecondNumberBeginIterator,SecondNumberEndIterator,isSecondNumberFractionalPart\ + ); + + Returns : + -1 - Number1 < Number2 + 0 - Number1 == Number2 + 1 - Number1 > Number2 + + ***************************************************/ + + + template<typename ValueType, typename Iterator> + struct compare_number + { + private: + //If Number is Itself fractional Part + int fractional(Iterator lhsBegin,Iterator lhsEnd, Iterator rhsBegin,Iterator rhsEnd) + { + while(lhsBegin<lhsEnd && rhsBegin<rhsEnd) + { + int local_compare = comp_over_iterator<ValueType, Iterator>()(lhsBegin,rhsBegin); + if(local_compare!=0) + return local_compare; + lhsBegin++; + rhsBegin++; + } + while(lhsBegin<lhsEnd && *lhsBegin=='0') lhsBegin++; + while(rhsBegin<rhsEnd && *rhsBegin=='0') rhsBegin++; + if(lhsBegin==lhsEnd && rhsBegin!=rhsEnd) + return -1; + else if(lhsBegin!=lhsEnd && rhsBegin==rhsEnd) + return +1; + else //lhsBegin==lhsEnd && rhsBegin==rhsEnd + return 0; + } + int non_fractional(Iterator lhsBegin,Iterator lhsEnd, Iterator rhsBegin,Iterator rhsEnd) + { + //Skip Inital Zero's + while(lhsBegin<lhsEnd && *lhsBegin=='0') lhsBegin++; + while(rhsBegin<rhsEnd && *rhsBegin=='0') rhsBegin++; + + //Comparing By Length of Both String + if(lhsEnd-lhsBegin<rhsEnd-rhsBegin) + return -1; + if(lhsEnd-lhsBegin>rhsEnd-rhsBegin) + return +1; + + //Equal In length + while(lhsBegin<lhsEnd) + { + int local_compare = comp_over_iterator<ValueType, Iterator>()(lhsBegin,rhsBegin); + if(local_compare!=0) + return local_compare; + lhsBegin++; + rhsBegin++; + } + return 0; + } + + + public: + int operator()(\ + Iterator lhsBegin,Iterator lhsEnd,bool isFractionalPart1,\ + Iterator rhsBegin,Iterator rhsEnd,bool isFractionalPart2) + { + if(isFractionalPart1 && !isFractionalPart2) + return true; //0<num1<1 && num2>=1 + if(!isFractionalPart1 && isFractionalPart2) + return false; //0<num2<1 && num1>=1 + + //isFractionPart1 == isFactionalPart2 + if(isFractionalPart1) + return fractional(lhsBegin,lhsEnd,rhsBegin,rhsEnd); + else + return non_fractional(lhsBegin,lhsEnd,rhsBegin,rhsEnd); + } + }; + + + + + + }// namespace detail + + /*********************************************************************** + Natural Comparision of Two String using both's (Begin and End Iterator) + + Returns : + -1 - String1 < String2 + 0 - String1 == String2 + 1 - String1 > String2 + + Suffix 1 represents for components of 1st String + Suffix 2 represents for components of 2nd String + ************************************************************************/ + + template<typename ElementType, typename Iterator> + bool _compare(\ + const Iterator &lhsBegin,const Iterator &lhsEnd,\ + const Iterator &rhsBegin,const Iterator &rhsEnd) + { + Iterator current1 = lhsBegin,current2 = rhsBegin; + + //Flag for Space Found Check + bool flag_found_space1 = false,flag_found_space2 = false; + + + while(current1!=lhsEnd && current2!=rhsEnd) + { + //Ignore More than One Continous Space + + /****************************************** + For HandlingComparision Like + Hello 9 + Hello 10 + Hello 123 + ******************************************/ + while(flag_found_space1 && current1!=lhsEnd && *current1==' ') current1++; + flag_found_space1=false; + if(*current1==' ') flag_found_space1 = true; + + while(flag_found_space2 && current2!=rhsEnd && *current2==' ') current2++; + flag_found_space2=false; + if(*current2==' ') flag_found_space2 = true; + + + if( !isdigit(*current1 ) || !isdigit(*current2)) + { + // Normal comparision if any of character is non digit character + if(detail::natural_less<ElementType>(*current1,*current2)) + return true; + if(detail::natural_less<ElementType>(*current2,*current1)) + return false; + current1++; + current2++; + } + else + { + /********************************* + Capture Numeric Part of Both String + and then using it to compare Both + + ***********************************/ + Iterator last_nondigit1 = std::find_if(current1,lhsEnd,detail::is_not_digit<ElementType>); + Iterator last_nondigit2 = std::find_if(current2,rhsEnd,detail::is_not_digit<ElementType>); + + int result = detail::compare_number<ElementType, Iterator>()(\ + current1,last_nondigit1,(current1>lhsBegin && *(current1-1)=='.'), \ + current2,last_nondigit2,(current2>rhsBegin && *(current2-1)=='.')); + if(result<0) + return true; + if(result>0) + return false; + current1 = last_nondigit1; + current2 = last_nondigit2; + } + } + + if (current1 == lhsEnd && current2 == rhsEnd) { + return false; + } else { + return current1 == lhsEnd; + } + } + + template<typename String> + inline bool compare(const String &first ,const String &second) + { + return _compare<typename String::value_type,typename String::const_iterator>(first.begin(),first.end(),second.begin(),second.end()); + } + template<> + inline bool compare(char *const &first ,char *const &second) + { + char* it1 = first; + while(*it1!='\0')it1++; + char* it2 = second; + while(*it2!='\0')it2++; + return _compare<char,char*>(first,it1,second,it2); + } + + + template<typename Container> + inline void sort(Container &container) + { + std::sort(container.begin(),container.end(),compare<typename Container::value_type>); + } + + template<typename Iterator> + inline void sort(const Iterator &first,const Iterator &end) + { + std::sort(first,end,compare<typename Iterator::value_type>); + } + + template<typename ValueType> + inline void sort(ValueType* const first,ValueType* const end) + { + std::sort(first,end,compare<ValueType>); + } + + template<typename ValueType,int N> + inline void sort(ValueType container[N]) + { + std::sort(&container[0],&container[0]+N,compare<ValueType>); + } + +}//namespace natural +}//namespace SI + +#endif diff --git a/dependencies/NaturalSort/natural_sort_test.cpp b/dependencies/NaturalSort/natural_sort_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cb31acac56654f1c56709dfb11e049add5185ffd --- /dev/null +++ b/dependencies/NaturalSort/natural_sort_test.cpp @@ -0,0 +1,95 @@ +#include <iostream> +#include <vector> +#include <string> +#include <assert.h> +#include "natural_sort.hpp" + +#define ADD_TEST(test_method) { \ + std::cout<<"Running test " #test_method "..."<<std::endl; \ + test_method(); \ + std::cout<<"Test " #test_method " is successful."<<std::endl; \ +} + +#define ASSERT_TRUE(x) { assert(x); } +#define ASSERT_FALSE(x) { assert(!(x)); } +#define ASSERT_EQ(x, y) { assert((x) == (y)); } + +void test_compare() { + ASSERT_FALSE(SI::natural::compare<std::string>("Hello 32", "Hello 023")); + ASSERT_FALSE(SI::natural::compare<std::string>("Hello 32a", "Hello 32")); + ASSERT_TRUE(SI::natural::compare<std::string>("Hello 32", "Hello 32a")); + ASSERT_FALSE(SI::natural::compare<std::string>("Hello 32.1", "Hello 32")); + ASSERT_TRUE(SI::natural::compare<std::string>("Hello 32", "Hello 32.1")); + ASSERT_FALSE(SI::natural::compare<std::string>("Hello 32", "Hello 32")); +} + +void test_sort_vector() { + std::vector<std::string> data = { + "Hello 100", + "Hello 34", + "Hello 9", + "Hello 25", + "Hello 10", + "Hello 8", + }; + std::vector<std::string> want = { + "Hello 8", + "Hello 9", + "Hello 10", + "Hello 25", + "Hello 34", + "Hello 100", + }; + SI::natural::sort(data); + ASSERT_EQ(data, want); +} + +void test_sort_array() { + const int SZ = 3; + std::string data[SZ] = { + "Hello 100", + "Hello 25", + "Hello 34", + }; + std::string want[SZ] = { + "Hello 25", + "Hello 34", + "Hello 100", + }; + + SI::natural::sort<std::string, SZ>(data); + for(int i=0; i<SZ; i++) { + ASSERT_EQ(data[i], want[i]); + } +} + +void test_sort_float() { + std::vector<std::string> data = { + "Hello 1", + "Hello 10", + "Hello 10.3", + "Hello 2", + "Hello 10.23", + "Hello 10.230", + }; + std::vector<std::string> want = { + "Hello 1", + "Hello 2", + "Hello 10", + "Hello 10.23", + "Hello 10.230", + "Hello 10.3", + }; + + SI::natural::sort(data); + ASSERT_EQ(data, want); +} + +int main() +{ + ADD_TEST(test_compare); + ADD_TEST(test_sort_vector); + ADD_TEST(test_sort_array); + ADD_TEST(test_sort_float); + return 0; +} \ No newline at end of file diff --git a/src/nerf_loader.cu b/src/nerf_loader.cu index 9b91a4215e5f274af8fb5d93b605c490102b2a4a..0b8376563dd703bd9b53e1460806091e0dc8657c 100644 --- a/src/nerf_loader.cu +++ b/src/nerf_loader.cu @@ -19,9 +19,11 @@ #include <neural-graphics-primitives/thread_pool.h> #include <neural-graphics-primitives/tinyexr_wrapper.h> +#include <filesystem/path.h> + #include <json/json.hpp> -#include <filesystem/path.h> +#include <natural_sort.hpp> #include <stb_image/stb_image.h> @@ -346,7 +348,7 @@ NerfDataset load_nerf(const std::vector<fs::path>& jsonpaths, float sharpen_amou float sharpness_discard_threshold = json.value("sharpness_discard_threshold", 0.0f); // Keep all by default std::sort(frames.begin(), frames.end(), [](const auto& frame1, const auto& frame2) { - return frame1["file_path"] < frame2["file_path"]; + return SI::natural::compare<std::string>(frame1["file_path"], frame2["file_path"]); }); for (auto&& frame : frames) {