diff --git a/Base/CMakeLists.txt b/Base/CMakeLists.txt index 2acb5e21be9845f6427db8933eb2a281c50370cf..c2bff2d135a8a8ac772e3389adb6554518da5ad1 100644 --- a/Base/CMakeLists.txt +++ b/Base/CMakeLists.txt @@ -1,14 +1,27 @@ # Source files SET( HEADERS - Configure.h.in - TimeMeasurementBase.h - RunTimeTimer.h + binarySearch.h + Configure.h.in CPUTimeTimer.h + DateTools.h + FileFinder.h + FileTools.h + printList.h + quicksort.h + RunTimeTimer.h + StringTools.h + swap.h + TimeMeasurementBase.h + uniqueListInsert.h + wait.h ) SET( SOURCES - RunTimeTimer.cpp + binarySearch.cpp + DateTools.cpp CPUTimeTimer.cpp + RunTimeTimer.cpp + StringTools.cpp ) # Create the library @@ -16,3 +29,9 @@ ADD_LIBRARY( Base STATIC ${HEADERS} ${SOURCES} ) SET_TARGET_PROPERTIES(Base PROPERTIES LINKER_LANGUAGE CXX) +INCLUDE_DIRECTORIES( + ../GEOLib + ../MathLib + . +) + diff --git a/Base/Configure.h.in b/Base/Configure.h.in index aead27c31e567cdc1e141fa27ebce45f7e77f5a5..307759a4d601d1bb95d4b22d4498d1569fed827a 100644 --- a/Base/Configure.h.in +++ b/Base/Configure.h.in @@ -3,13 +3,19 @@ * * #defines which gets set through CMake */ -#ifndef CONFIGURE_H -#define CONFIGURE_H + #ifndef CONFIGURE_H + #define CONFIGURE_H +#define OGS_QT_VERSION ${QT_VERSION_MAJOR}${QT_VERSION_MINOR} #define SOURCEPATH "${CMAKE_SOURCE_DIR}" -#cmakedefine HAVE_PTHREADS -#cmakedefine PROCESSOR_COUNT "${PROCESSOR_COUNT}" +#cmakedefine OGS_VERSION "${OGS_VERSION}" +#cmakedefine OGS_DATE "${OGS_DATE}" -#endif // CONFIGURE_H +// for tests +#cmakedefine OGS_EXECUTABLE "${OGS_EXECUTABLE}" +#define PUT_TMP_DIR_IN "${PROJECT_BINARY_DIR}/tests/" + +#cmakedefine PROCESSOR_COUNT ${PROCESSOR_COUNT} +#endif // CONFIGURE_H diff --git a/Base/DateTools.cpp b/Base/DateTools.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4165c7c754f02cdf8a9c210117164c8a7c6467d5 --- /dev/null +++ b/Base/DateTools.cpp @@ -0,0 +1,77 @@ +/* + * DateTools.cpp + * + * Created on: Jun 16, 2010 + * Author: KR Initial implementation (in header file) + * TF moved implementation to source file + */ + +#include "DateTools.h" +#include <cmath> +#include <cstdlib> + +double date2double(int y, int m, int d) +{ + if ( (y<1000 || y>9999) || (m<1 || m>12) || (d<1 || d>31) ) + { + std::cout << "Error: date2double() -- input not in expected format." << std::endl; + return 0; + } + + int ddate=0; + if (y<1900) y+=1900; + ddate = y*10000; + ddate += (m*100); + ddate += d; + + return ddate; +} + +std::string date2string(double ddate) +{ + if (ddate<10000101 || ddate>99991231) + { + std::cout << "Error: date2String() -- input not in expected format." << std::endl; + return "0.0.0000"; + } + + int rest (static_cast<int>(ddate)); + int y = static_cast<int>(floor(rest/10000.0)); + rest = rest % (y*10000); + int m = static_cast<int>(floor(rest/100.0)); + if (m<1 || m>12) std::cout << "Warning: date2String() -- month not in [1:12]" << std::endl; + rest = rest % (m*100); + int d = rest; + if (d<1 || d>31) std::cout << "Warning: date2String() -- day not in [1:31]" << std::endl; + + std::string day = number2str(d); + if (d<10) day = "0" + day; + std::string month = number2str(m); + if (m<10) month = "0" + month; + std::string s = number2str(y) + "-" + month + "-" + day; + return s; +} + +double strDate2double(const std::string &s) +{ + size_t sep ( s.find(".",0) ); + int d ( atoi(s.substr(0, sep).c_str()) ); + size_t sep2 ( s.find(".", sep+1) ); + int m ( atoi(s.substr(sep+1,sep2-(sep+1)).c_str()) ); + int y ( atoi(s.substr(sep2+1, s.length()-(sep2+1)).c_str()) ); + return date2double(y, m, d); +} + +double xmlDate2double(const std::string &s) +{ + if (s.length() == 10) + { + int d = atoi(s.substr(8,2).c_str()); + if (d<1 || d>31) std::cout << "Warning: xmlDate2double() -- day not in [1:31]" << std::endl; + int m = atoi(s.substr(5,2).c_str()); + if (m<1 || m>12) std::cout << "Warning: xmlDate2double() -- month not in [1:12]" << std::endl; + int y = atoi(s.substr(0,4).c_str()); + return date2double(y, m, d); + } + return 0; +} diff --git a/Base/DateTools.h b/Base/DateTools.h new file mode 100644 index 0000000000000000000000000000000000000000..33e965852e5587e61cf3ba4734a59b9ba1c235ee --- /dev/null +++ b/Base/DateTools.h @@ -0,0 +1,42 @@ +/** + * \file DateTools.h + * 22/01/2010 KR Initial implementation + */ + +#ifndef DATETOOLS_H +#define DATETOOLS_H + +#include "StringTools.h" +#include <string> + +/** + * Converts three integers representing a date into a double. + * Note: It is not really checked if the date actually makes sense. + */ +double date2Double(int y, int m, int d); + +/** + * Converts a double representing a date into a string. + * Note: It is not really checked if the date actually makes sense. + * \param ddate Number containing date in double format yyyymmdd + * \return A string containing the date in format "dd.mm.yyyy". + */ +std::string date2string(double ddate); + +/** + * Converts a string containing a date into a double. + * Note: It is not really checked if the date actually makes sense. + * \param s String containing the date, the expected format is "dd.mm.yyyy". + * \return A number representing the date as dd.mm.yyyy. + */ +double strDate2double(const std::string &s); + +/** + * Converts a string containing a date into a double. + * Note: It is not really checked if the date actually makes sense. + * \param s String containing the date, the expected format is conform to the xml date type, i.e. "yyyy-mm-dd". + * \return A number representing the date as yyyymmdd. + */ +double xmlDate2double(const std::string &s); + +#endif //DATETOOLS_H diff --git a/Base/FileFinder.h b/Base/FileFinder.h new file mode 100644 index 0000000000000000000000000000000000000000..41ba7228a00270793b22c2bc2552651b14f6f788 --- /dev/null +++ b/Base/FileFinder.h @@ -0,0 +1,54 @@ +/** + * \file FileFinder.h + * 26/10/2010 KR Initial implementation + */ + +#ifndef FILEFINDER_H +#define FILEFINDER_H + +/** + * FileFinder stores a list of directories and will return the complete path + * for a given filename if the corresponding file is found in any of these + * directories. + */ +class FileFinder +{ +public: + /// Constructor + FileFinder() {}; + + /** + * \brief Adds another directory to the search-space. + * If the given directory does not end with a slash one will be appended. + */ + void addDirectory(std::string dir) + { + if (dir[dir.size()-1] != '/') dir.append("/"); + _directories.push_back(dir); + }; + + /** + * Given a filename, this method will return the complete path where this file can be found. + * If the file is located in more than one of the directories in the search list, only the + * first location will be returned. + */ + std::string getPath(std::string filename) + { + if (_directories.empty()) std::cout << "Error: FileFinder::getPath() -- directory list is empty." << std::endl; + for (std::list<std::string>::iterator it = _directories.begin(); it != _directories.end(); ++it) + { + std::string testDir(*it); + std::ifstream is(testDir.append(filename).c_str()); + if (is.good()) return testDir; + } + std::cout << "Error: FileFinder::getPath() -- file not found." << std::endl; + return filename; + }; + +private: + + std::list<std::string> _directories; + + +}; +#endif // FILEFINDER_H diff --git a/Base/FileTools.h b/Base/FileTools.h new file mode 100644 index 0000000000000000000000000000000000000000..ddf915b32b2c8f2bd759b7de9e8ac8f21270e25e --- /dev/null +++ b/Base/FileTools.h @@ -0,0 +1,46 @@ +/** + * \file FileTools.h + * 26/4/2010 LB Initial implementation + * + */ + + +#ifndef FILETOOLS_H +#define FILETOOLS_H + +// ** INCLUDES ** +#include <sys/stat.h> + +/** + * Returns true if given file exists. From http://www.techbytes.ca/techbyte103.html + */ +static bool IsFileExisting(std::string strFilename) +{ + struct stat stFileInfo; + bool blnReturn; + int intStat; + + // Attempt to get the file attributes + intStat = stat(strFilename.c_str(),&stFileInfo); + + if(intStat == 0) + { + // We were able to get the file attributes + // so the file obviously exists. + blnReturn = true; + } + else + { + // We were not able to get the file attributes. + // This may mean that we don't have permission to + // access the folder which contains this file. If you + // need to do that level of checking, lookup the + // return values of stat which will give you + // more details on why stat failed. + blnReturn = false; + } + + return(blnReturn); +} + +#endif // FILETOOLS_H diff --git a/Base/StringTools.cpp b/Base/StringTools.cpp new file mode 100644 index 0000000000000000000000000000000000000000..01fffcf4acc9a9817bab8918a1db808227e7694b --- /dev/null +++ b/Base/StringTools.cpp @@ -0,0 +1,109 @@ +/* + * StringTools.cpp + * + * Created on: Jun 16, 2010 + * Author: TF + */ + +#include "StringTools.h" + +std::list<std::string> splitString(const std::string &str, char delim) +{ + std::list<std::string> strList; + std::stringstream ss(str); + std::string item; + while(getline(ss, item, delim)) { + strList.push_back(item); + } + return strList; +} + +std::string replaceString(const std::string &searchString, const std::string &replaceString, std::string stringToReplace) + { + std::string::size_type pos = stringToReplace.find(searchString, 0); + int intLengthSearch = searchString.length(); + + while (std::string::npos != pos) { + stringToReplace.replace(pos, intLengthSearch, replaceString); + pos = stringToReplace.find(searchString, 0); + } + return stringToReplace; +} + +void trim(std::string &str, char ch) +{ + std::string::size_type pos = str.find_last_not_of(ch); + if(pos != std::string::npos) + { + str.erase(pos + 1); + pos = str.find_first_not_of(ch); + if(pos != std::string::npos) str.erase(0, pos); + } + else str.erase(str.begin(), str.end()); +} + + +#ifdef MSVC +void correctScientificNotation(std::string filename, size_t precision) +{ + std::ifstream stream; + std::ofstream outputStream; + + stream.open(filename.c_str()); + std::string tmpFilename = filename + ".tmp"; + outputStream.open(tmpFilename.c_str()); + + if (!stream) + { + std::cout << "correctScientificNotation: fstream is not open" << std::endl; + return; + } + + std::string line; + + // Iterate over lines in stream + while (getline(stream, line)) + { + std::string word; + std::istringstream iss(line); + // Iterate over all words in line + while (iss >> word) + { + // Search for e+0 + std::size_t exponentPosition = word.find("e+0", precision); + if (exponentPosition == std::string::npos) + // If not found search for e-0 + exponentPosition = word.find("e-0", precision); + if (exponentPosition != std::string::npos) + { + std::size_t wordSize = word.size(); + std::size_t exponentSize = wordSize - exponentPosition; + + if(exponentSize > 4) + { + // Erase the leading zero considering trailing characters + int i = wordSize - 1; + while (!isdigit(word[i])) + --i; + + size_t erasePos = wordSize - 3 - (wordSize - 1 - i); + std::string eraseString = word.substr(erasePos, 1); + if (eraseString.find("0") != std::string::npos) + word.erase(erasePos, 1); + } + } + + outputStream << word << " "; + } + outputStream << std::endl; + } + + stream.close(); + outputStream.close(); + + remove(filename.c_str()); + rename(tmpFilename.c_str(), filename.c_str()); +} +#endif + + diff --git a/Base/StringTools.h b/Base/StringTools.h new file mode 100644 index 0000000000000000000000000000000000000000..d63f537f4bcaae58a770513667a19821b294668e --- /dev/null +++ b/Base/StringTools.h @@ -0,0 +1,64 @@ +#ifndef STRINGTOOLS_H +#define STRINGTOOLS_H + +#include <string> +#include <list> +#include <sstream> +#include <fstream> +#include <iostream> +#include <ctype.h> + + +/** + * Splits a string into a list of strings. + * \param str String to be splitted + * \param delim Character indicating that the string should be splitted + * \return + */ +std::list<std::string> splitString(const std::string &str, char delim); + +/** + * Replaces a substring with another in a string + * \param searchString Search for this string + * \param replaceString Replace with this string + * \param stringToReplace Search and replace in this string + * \return The modified string + */ +std::string replaceString(const std::string &searchString, const std::string &replaceString, std::string stringToReplace); + +/** + * Converts a number (double, float, int, ...) into a string + * \param d The number to be converted + * \return The number as string + */ +template<typename T> std::string number2str(T d) +{ + std::stringstream out; + out << d; + return out.str(); +} + +/** + * Converts a string into a number (double, float, int, ...) + * Example: size_t number (str2number<size_t> (str)); + * \param str string to be converted + * \return the number + */ +template<typename T> T str2number (const std::string &str) +{ + std::stringstream strs (str, std::stringstream::in | std::stringstream::out); + T v; + strs >> v; + return v; +} + +/** + * Strip whitespace (or other characters) from the beginning and end of a string. + */ +void trim(std::string &str, char ch=' '); + +#ifdef MSVC +void correctScientificNotation(std::string filename, size_t precision = 0); +#endif + +#endif //STRINGTOOLS_H diff --git a/Base/binarySearch.cpp b/Base/binarySearch.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7ecd110b79c7dddec320de8e955ca1929a4fec8b --- /dev/null +++ b/Base/binarySearch.cpp @@ -0,0 +1,22 @@ +/* + * binarySearch.cpp + * + * Created on: Sep 7, 2010 + * Author: TF + */ + +#include "binarySearch.h" + +size_t searchElement (double const& val, size_t beg, size_t end, const std::vector<double>& array) +{ + if (beg >= end) return std::numeric_limits<size_t>::max(); + size_t m ((end+beg)/2); + + if (array[m] - val < 0 && array[m+1] - val > 0) { + return m; + } + if (val < array[m]) { + return searchElement (val, beg, m, array); + } + return searchElement (val, m+1, end, array); +} diff --git a/Base/binarySearch.h b/Base/binarySearch.h new file mode 100644 index 0000000000000000000000000000000000000000..92148b228a020f1714f71bcf8e21e0ad0b2573eb --- /dev/null +++ b/Base/binarySearch.h @@ -0,0 +1,43 @@ +/* + * binarySearch.h + * + * Created on: Jun 7, 2010 + * Author: TF + */ + +// STL +#include <limits> +#include <vector> +#include <cstddef> + +#ifndef BINARYSEARCH_H_ +#define BINARYSEARCH_H_ + +/** + * Binary search in a sorted vector of elements to get the + * id of an element according its key. + * @param key the key for the element + * @param beg beginning index in the sorted vector of elements + * @param end ending index in the sorted vector of elements + * @param array the vector of elements + * @return the id of the element in the vector or, if not found, + * the value std::numeric_limits<size_t>::max() + */ +template <class T> +size_t searchElement (const T& key, size_t beg, size_t end, const std::vector<T>& array) +{ + if (beg >= end) return std::numeric_limits<size_t>::max(); + size_t m ((end+beg)/2); + + if (key == array[m]) { + return m; + } + if (key < array[m]) { + return searchElement (key, beg, m, array); + } + return searchElement (key, m+1, end, array); +} + +size_t searchElement (double const& val, size_t beg, size_t end, const std::vector<double>& array); + +#endif /* BINARYSEARCH_H_ */ diff --git a/Base/printList.h b/Base/printList.h new file mode 100644 index 0000000000000000000000000000000000000000..bb0e7dd1c80af3ffa0b6cfbc8eb0cd2586e72bd4 --- /dev/null +++ b/Base/printList.h @@ -0,0 +1,30 @@ +/* + * printList.h + * + * Created on: Feb 23, 2011 + * Author: TF + */ + +#ifndef PRINTLIST_H_ +#define PRINTLIST_H_ + +// STL +#include <list> +#include <string> +#include <iostream> + +namespace BASELIB { + +void printList (std::list<size_t> const& mylist, std::string const& title) +{ + std::cout << title << std::endl; + for (std::list<size_t>::const_iterator my_it (mylist.begin()); + my_it != mylist.end(); my_it++) { + std::cout << *my_it << " "; + } + std::cout << std::endl; +} + +} // end namespace BASELIB + +#endif /* PRINTLIST_H_ */ diff --git a/Base/quicksort.h b/Base/quicksort.h new file mode 100644 index 0000000000000000000000000000000000000000..0650d485d43ba06777922311220462d1c333d710 --- /dev/null +++ b/Base/quicksort.h @@ -0,0 +1,182 @@ +/* + * quicksort.h + * + * Created on: May 26, 2010 + * Author: TF + */ + +#ifndef QUICKSORT_H_ +#define QUICKSORT_H_ + +// STL +#include <cstddef> + +// Base +#include "swap.h" + +/** + * version of partition_ that additional updates the permutation vector + * */ +template <class T> +size_t partition_(T* array, size_t beg, size_t end, size_t *perm) +{ + size_t i = beg + 1; + size_t j = end - 1; + T m = array[beg]; + + for (;;) { + while ((i < end) && (array[i] <= m)) + i++; + while ((j > beg) && !(array[j] <= m)) + j--; + + if (i >= j) + break; + BASELIB::swap(array[i], array[j]); + BASELIB::swap(perm[i], perm[j]); + } + + BASELIB::swap(array[beg], array[j]); + BASELIB::swap(perm[beg], perm[j]); + return j; +} + +/** + * version of quickSort that stores the permutation + * */ +template <class T> +void quicksort(T* array, size_t beg, size_t end, size_t* perm) +{ + if (beg < end) { + size_t p = partition_(array, beg, end, perm); + quicksort(array, beg, p, perm); + quicksort(array, p+1, end, perm); + } +} + +// STL +#include <vector> + +template <typename T> +class Quicksort { +public: + Quicksort (std::vector<T>& array, size_t beg, size_t end, std::vector<size_t>& perm) + { + quicksort (array, beg, end, perm); + } +private: + size_t partition_(std::vector<T>& array, size_t beg, size_t end, std::vector<size_t>& perm) + { + size_t i = beg + 1; + size_t j = end - 1; + T m = array[beg]; + + for (;;) { + while ((i < end) && (array[i] <= m)) + i++; + while ((j > beg) && !(array[j] <= m)) + j--; + + if (i >= j) + break; + BASELIB::swap(array[i], array[j]); + BASELIB::swap(perm[i], perm[j]); + } + + BASELIB::swap(array[beg], array[j]); + BASELIB::swap(perm[beg], perm[j]); + return j; + } + + void quicksort(std::vector<T>& array, size_t beg, size_t end, std::vector<size_t>& perm) + { + if (beg < end) { + size_t p = partition_(array, beg, end, perm); + quicksort(array, beg, p, perm); + quicksort(array, p+1, end, perm); + } + } +}; + +// specialization for pointer types +template <typename T> +class Quicksort <T *> { +public: + Quicksort (std::vector<T*>& array, size_t beg, size_t end, std::vector<size_t>& perm) + { + quicksort (array, beg, end, perm); + } + + Quicksort (std::vector<size_t>& perm, size_t beg, size_t end, std::vector<T*>& array) + { + quicksort (perm, beg, end, array); + } + +private: + size_t partition_(std::vector<T*>& array, size_t beg, size_t end, std::vector<size_t>& perm) + { + size_t i = beg + 1; + size_t j = end - 1; + T* m = array[beg]; + + for (;;) { + while ((i < end) && (*array[i] <= *m)) + i++; + while ((j > beg) && !(*array[j] <= *m)) + j--; + + if (i >= j) + break; + BASELIB::swap(array[i], array[j]); + BASELIB::swap(perm[i], perm[j]); + } + + BASELIB::swap(array[beg], array[j]); + BASELIB::swap(perm[beg], perm[j]); + return j; + } + + void quicksort(std::vector<T*>& array, size_t beg, size_t end, std::vector<size_t>& perm) + { + if (beg < end) { + size_t p = partition_(array, beg, end, perm); + quicksort(array, beg, p, perm); + quicksort(array, p+1, end, perm); + } + } + + size_t partition_(std::vector<size_t> &perm, size_t beg, size_t end, std::vector<T*>& array) + { + size_t i = beg + 1; + size_t j = end - 1; + size_t m = perm[beg]; + + for (;;) { + while ((i < end) && (perm[i] <= m)) + i++; + while ((j > beg) && !(perm[j] <= m)) + j--; + + if (i >= j) + break; + BASELIB::swap(perm[i], perm[j]); + BASELIB::swap(array[i], array[j]); + } + + BASELIB::swap(perm[beg], perm[j]); + BASELIB::swap(array[beg], array[j]); + return j; + } + + void quicksort(std::vector<size_t>& perm, size_t beg, size_t end, std::vector<T*>& array) + { + if (beg < end) { + size_t p = partition_(perm, beg, end, array); + quicksort(perm, beg, p, array); + quicksort(perm, p+1, end, array); + } + } + +}; + +#endif /* QUICKSORT_H_ */ diff --git a/Base/swap.h b/Base/swap.h new file mode 100644 index 0000000000000000000000000000000000000000..9915e9135c3aecbd70a69b9aa4b76e18791bb525 --- /dev/null +++ b/Base/swap.h @@ -0,0 +1,18 @@ +#ifndef SWAP_H_ +#define SWAP_H_ + +namespace BASELIB { + +/** + * swap the content of arg0 and arg1 + */ +template<class T> void swap(T& arg0, T& arg1) +{ + T temp(arg0); + arg0 = arg1; + arg1 = temp; +} + +} // end namespace BASELIB + +#endif //SWAP_H_ diff --git a/Base/uniqueListInsert.h b/Base/uniqueListInsert.h new file mode 100644 index 0000000000000000000000000000000000000000..779545a7ca4b097a517b222f541bdf862b58f156 --- /dev/null +++ b/Base/uniqueListInsert.h @@ -0,0 +1,28 @@ +/* + * uniqueListInsert.h + * + * Created on: Feb 23, 2011 + * Author: TF + */ + +#ifndef UNIQUELISTINSERT_H_ +#define UNIQUELISTINSERT_H_ + +#include <list> + +namespace BASELIB { + +void uniqueListInsert (std::list<size_t>& list, size_t element) +{ + // search element + std::list<size_t>::const_iterator it; + for (it = list.begin (); it != list.end(); it++) { + if (*it == element) return; + } + // element not found -> insert + list.push_back (element); +} + +} // end namespace BASELIB + +#endif /* UNIQUELISTINSERT_H_ */ diff --git a/Base/wait.h b/Base/wait.h new file mode 100644 index 0000000000000000000000000000000000000000..2973158740e78f9a94c09eb52d7386530d35c342 --- /dev/null +++ b/Base/wait.h @@ -0,0 +1,28 @@ +/** + * \file DateTools.h + * 2011/02/17 KR Initial implementation + */ + + +#ifndef WAIT_H +#define WAIT_H + +#include <ctime> + +namespace BASELIB { + +void wait(int seconds) +{ + time_t start_time, cur_time; + + time(&start_time); + do + { + time(&cur_time); + } + while((cur_time - start_time) < seconds); +} + +} // end namespace BASELIB + +#endif //WAIT_H diff --git a/CMakeLists.txt b/CMakeLists.txt index e1fe3728fbd8441e61335b9a658b5d16e7508dc5..b8b1a10d23c70e82386b9d22317b715c94786eb8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,6 +4,10 @@ cmake_minimum_required(VERSION 2.6) # Project name project( OGS-6 ) +# Set cmake module path +SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake") + + # Set cmake module path #SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/CMakeConfiguration") @@ -27,6 +31,7 @@ SET( LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib ) # Add subdirectories with the projects ADD_SUBDIRECTORY( Base ) +ADD_SUBDIRECTORY( GeoLib ) ADD_SUBDIRECTORY( MathLib ) ADD_SUBDIRECTORY( SimpleTests/MatrixTests ) ADD_SUBDIRECTORY( SimpleTests/SolverTests ) diff --git a/GeoLib/AxisAlignedBoundingBox.cpp b/GeoLib/AxisAlignedBoundingBox.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2049e77f0302188ee8d2273aee72e8c4a6f4ae44 --- /dev/null +++ b/GeoLib/AxisAlignedBoundingBox.cpp @@ -0,0 +1,74 @@ +/* + * \file AxisAlignedBoundingBox.cpp + * + * Created on: April 22, 2010 + * Author: TF + */ + +#include <limits> +#include <cstddef> +#include <cmath> +#include "AxisAlignedBoundingBox.h" + +namespace GEOLIB { + +AABB::AABB () +{ + for (std::size_t k(0); k<3; k++) { + _min_pnt[k] = std::numeric_limits<double>::max(); + _max_pnt[k] = std::numeric_limits<double>::min(); + } +} + +AABB::AABB ( const std::vector<GEOLIB::Point*> *points ) +{ + size_t nPoints (points->size()); + for (size_t i=0; i<nPoints; i++) + { + this->update((*(*points)[i])[0], (*(*points)[i])[1], (*(*points)[i])[2]); + } +} + +void AABB::update (GEOLIB::Point const & pnt) +{ + update (pnt[0], pnt[1], pnt[2]); +} + +void AABB::update (double x, double y, double z) +{ + if (x < _min_pnt[0]) _min_pnt[0] = x; + if (_max_pnt[0] < x) _max_pnt[0] = x; + if (y < _min_pnt[1]) _min_pnt[1] = y; + if (_max_pnt[1] < y) _max_pnt[1] = y; + if (z < _min_pnt[2]) _min_pnt[2] = z; + if (_max_pnt[2] < z) _max_pnt[2] = z; +} + +bool AABB::containsPoint (GEOLIB::Point const & pnt, double eps) const +{ + return containsPoint (pnt[0], pnt[1], pnt[2], eps); +} + +bool AABB::containsPoint (const double *pnt, double eps) const +{ + return containsPoint (pnt[0], pnt[1], pnt[2], eps); +} + +bool AABB::containsPoint (double x, double y, double z, double eps) const +{ + if ((_min_pnt[0] <= x && x <= _max_pnt[0]) + || std::fabs(_min_pnt[0]-x) < eps + || std::fabs(x - _max_pnt[0]) < eps) { + if ((_min_pnt[1] <= y && y <= _max_pnt[1]) + || std::fabs(_min_pnt[1]-y) < eps + || std::fabs(y-_max_pnt[1]) < eps) { + if ((_min_pnt[2] <= z && z <= _max_pnt[2]) + || std::fabs(_min_pnt[2]-z) < eps + || std::fabs(z-_max_pnt[2]) < eps) { + return true; + } else return false; + } else return false; + } else return false; +} + +} diff --git a/GeoLib/AxisAlignedBoundingBox.h b/GeoLib/AxisAlignedBoundingBox.h new file mode 100644 index 0000000000000000000000000000000000000000..8f457b3007bd308dd566e57541ea068789d238dd --- /dev/null +++ b/GeoLib/AxisAlignedBoundingBox.h @@ -0,0 +1,77 @@ +/* + * \file AxisAlignedBoundingBox.h + * + * Created on: April 22, 2010 + * Author: TF + */ + +#ifndef AXISALIGNEDBOUNDINGBOX_H_ +#define AXISALIGNEDBOUNDINGBOX_H_ + +#include "Point.h" +#include <vector> +#include <limits> + +namespace GEOLIB { + +/** + * + * \ingroup GEOLIB + * + * \brief Class AABB is a bounding box around a given geometric entity + * */ +class AABB +{ +public: + /** + * construction of object, initialization the axis aligned bounding box + * */ + AABB (); + + /** + * construction of object using vector of points + * */ + AABB ( const std::vector<GEOLIB::Point*> *points ); + + void update (GEOLIB::Point const & pnt); + /** + * update axis aligned bounding box + */ + void update (double x, double y, double z); + + /** + * update axis aligned bounding box + */ + void update (const double *pnt) + { + update (pnt[0], pnt[1], pnt[2]); + } + + /** + * check if point is in the axis aligned bounding box + * (employing containsPoint (double x, double y, double z)) + */ + bool containsPoint (GEOLIB::Point const & pnt, double eps = std::numeric_limits<double>::epsilon()) const; + + /** + * wrapper for GEOLIB::Point + */ + bool containsPoint (const double *pnt, double eps = std::numeric_limits<double>::epsilon()) const; + + /** + * check if point described by its coordinates x, y, z is in + * the axis aligned bounding box + */ + bool containsPoint (double x, double y, double z, double eps = std::numeric_limits<double>::epsilon()) const; + + GEOLIB::Point getMinPoint () const { return _min_pnt; } + GEOLIB::Point getMaxPoint () const { return _max_pnt; } + +private: + GEOLIB::Point _min_pnt; + GEOLIB::Point _max_pnt; +}; + +} // end namespace + +#endif /* AXISALIGNEDBOUNDINGBOX_H_ */ diff --git a/GeoLib/BruteForceClosestPair.cpp b/GeoLib/BruteForceClosestPair.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d047edf0e43200706348a65daa946675fca7fdcd --- /dev/null +++ b/GeoLib/BruteForceClosestPair.cpp @@ -0,0 +1,34 @@ +/* + * BruteForceClosestPair.cpp + * + * Created on: Jan 25, 2011 + * Author: TF + */ + +#include "BruteForceClosestPair.h" +#include "MathTools.h" + +namespace GEOLIB { + +BruteForceClosestPair::BruteForceClosestPair( + std::vector<GEOLIB::Point*> const & pnts, size_t& id0, size_t& id1) : + ClosestPair (pnts, id0, id1) +{ + double sqr_shortest_dist (MathLib::sqrDist (_pnts[0], _pnts[1])); + + const size_t n_pnts (_pnts.size()); + for (size_t i(0); i<n_pnts; i++) { + for (size_t j(i+1); j<n_pnts; j++) { + double sqr_dist (MathLib::sqrDist (_pnts[i], _pnts[j])); + if (sqr_dist < sqr_shortest_dist) { + sqr_shortest_dist = sqr_dist; + _id0 = i; + _id1 = j; + } + } + } + id0 = _id0; + id1 = _id1; +} + +} // end namespace GEOLIB diff --git a/GeoLib/BruteForceClosestPair.h b/GeoLib/BruteForceClosestPair.h new file mode 100644 index 0000000000000000000000000000000000000000..8de5d88ff42b581b3d9e668cf2a4dca28ed0a369 --- /dev/null +++ b/GeoLib/BruteForceClosestPair.h @@ -0,0 +1,22 @@ +/* + * BruteForceClosestPair.h + * + * Created on: Jan 25, 2011 + * Author: TF + */ + +#ifndef BRUTEFORCECLOSESTPAIR_H_ +#define BRUTEFORCECLOSESTPAIR_H_ + +#include "ClosestPair.h" + +namespace GEOLIB { + +class BruteForceClosestPair : public ClosestPair { +public: + BruteForceClosestPair(std::vector<GEOLIB::Point*> const & pnts, size_t& id0, size_t& id1); +}; + +} // end namespace GEOLIB + +#endif /* BRUTEFORCECLOSESTPAIR_H_ */ diff --git a/GeoLib/CMakeLists.txt b/GeoLib/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..c091c532b1448e9038cb5595f4825dffcf67af8d --- /dev/null +++ b/GeoLib/CMakeLists.txt @@ -0,0 +1,71 @@ +# Source files +set( SOURCES + AxisAlignedBoundingBox.cpp + BruteForceClosestPair.cpp + Color.cpp + GEOObjects.cpp + GeoType.cpp + Point.cpp + PointVec.cpp + Polygon.cpp + Polyline.cpp +# ProjectData.cpp # uses CFEMesh class +# SimplePolygonTree.cpp # uses FileIO/MeshIO + Station.cpp + Surface.cpp + Triangle.cpp + Raster.cpp +) + +# Header files +set( HEADERS + AxisAlignedBoundingBox.h + BruteForceClosestPair.h + ClosestPair.h + Color.h + GeoObject.h + GEOObjects.h + GeoType.h + Point.h + PointVec.h + PointWithID.h + Polygon.h + Polyline.h + PolylineVec.h +# ProjectData.h # uses CFEMesh class + PropertyBounds.h + QuadTree.h +# SimplePolygonTree.h # uses FileIO/MeshIO + Station.h + Surface.h + SurfaceVec.h + TemplatePoint.h + TemplateVec.h + Triangle.h + Raster.h +) + +# Create the library +add_library( GEO STATIC + ${SOURCES} + ${HEADERS} +) + + +include_directories( + . + ../Base + ../FEM + ../FileIO + ../MathLib + ../MSH +) + + +target_link_libraries ( + GEO + Base + FEM + MathLib +) + diff --git a/GeoLib/ClosestPair.h b/GeoLib/ClosestPair.h new file mode 100644 index 0000000000000000000000000000000000000000..d2b1d3af0f6fe6cc01bfd8e9c2947fbcd735d025 --- /dev/null +++ b/GeoLib/ClosestPair.h @@ -0,0 +1,34 @@ +/* + * ClosestPair.h + * + * Created on: Jan 25, 2011 + * Author: TF + */ + +#ifndef CLOSESTPAIR_H_ +#define CLOSESTPAIR_H_ + +// STL +#include <vector> + +// GEOLIB +#include "Point.h" + +namespace GEOLIB { + +class ClosestPair +{ +public: + ClosestPair (std::vector<GEOLIB::Point*> const & pnts, size_t id0, size_t id1) : + _pnts (pnts), _id0 (id0), _id1 (id1) + {} + +protected: + std::vector<GEOLIB::Point*> const & _pnts; + size_t _id0; + size_t _id1; +}; + +} // end namespace GEOLIB + +#endif /* CLOSESTPAIR_H_ */ diff --git a/GeoLib/Color.cpp b/GeoLib/Color.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fd54503680e14fb63add54c47b625b56c52a0284 --- /dev/null +++ b/GeoLib/Color.cpp @@ -0,0 +1,76 @@ +/* + * Color.cpp + * + * Created on: Jun 16, 2010 + * Author: KR initial implementation in header + * TF moved implementation to separate source file + */ + +#include <iostream> +#include <sstream> + +#include "Color.h" +#include "StringTools.h" + +namespace GEOLIB { + +Color* getRandomColor() +{ + return new Color((rand()%5)*50, (rand()%5)*50, (rand()%5)*50); +} + +int readColorLookupTable(std::map<std::string, Color*> &colors, const std::string &filename) +{ + std::string id = "", line = ""; + + std::ifstream in( filename.c_str() ); + + if (!in.is_open()) + { + std::cout << "Color::readLookupTable() - Could not open file..." << std::endl; + return 0; + } + + while ( getline(in, line) ) + { + std::list<std::string> fields = splitString(line, '\t'); + Color *c = new Color(); + + if (fields.size()>=4) + { + id = fields.front(); + fields.pop_front(); + (*c)[0] = atoi(fields.front().c_str()); + fields.pop_front(); + (*c)[1] = atoi(fields.front().c_str()); + fields.pop_front(); + (*c)[2] = atoi(fields.front().c_str()); + colors.insert(std::pair<std::string, Color*>(id, c)); + } + else delete c; + } + + return 1; +} + +const Color* getColor(const std::string &id, std::map<std::string, Color*> &colors) +{ + for (std::map<std::string, Color*>::const_iterator it=colors.begin(); it !=colors.end(); ++it) + { + if (id.compare(it->first) == 0) + return it->second; + } + std::cout << "Key \"" << id << "\" not found in color lookup table..." << std::endl; + Color* c = getRandomColor(); + colors.insert(std::pair<std::string, Color*>(id, c)); + return c; +} + +const Color* getColor(double id, std::map<std::string, GEOLIB::Color*> &colors) +{ + std::ostringstream stream; + stream << id; + return getColor(stream.str(), colors); +} + +} diff --git a/GeoLib/Color.h b/GeoLib/Color.h new file mode 100644 index 0000000000000000000000000000000000000000..f2843833f1162a92389051cf3b1abafff81db5da --- /dev/null +++ b/GeoLib/Color.h @@ -0,0 +1,38 @@ +/** + * \file Color.cpp + * 04/02/2010 KR Initial implementation + * + */ + + +#ifndef COLOR_H_ +#define COLOR_H_ + +#include "TemplatePoint.h" + +#include <fstream> +#include <cstdlib> +#include <map> +#include <list> + +namespace GEOLIB { + +typedef TemplatePoint<unsigned char> Color; + +/// Returns a random RGB colour. +Color* getRandomColor(); + +/// Reads a color-lookup-table from a file and writes it to a map. +int readColorLookupTable(std::map<std::string, GEOLIB::Color*> &colors, const std::string &filename); + +/// Uses a color-lookup-table (in form of a map) to return a colour for a specified name. If the name is not +/// in the colortable a new entry is created with the new name and a random colour. +const Color* getColor(const std::string &id, std::map<std::string, GEOLIB::Color*> &colors); + +/// Convenience function to use the getColor method with numbers as identifiers. +const Color* getColor(double id, std::map<std::string, GEOLIB::Color*> &colors); + + +} // namespace + +#endif /* COLOR_H_ */ diff --git a/GeoLib/GEOObjects.cpp b/GeoLib/GEOObjects.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6fd77f767680992e2de20c2f3adaf51589c8b859 --- /dev/null +++ b/GeoLib/GEOObjects.cpp @@ -0,0 +1,435 @@ +/* + * GEOObjects.cpp + * + * Created on: Jan 21, 2010 + * Author: TF / KR + */ + +#include "GEOObjects.h" +#include "StringTools.h" + +#include <fstream> + +namespace GEOLIB { + +GEOObjects::GEOObjects() +{ +} + +GEOObjects::~GEOObjects() +{ + // delete surfaces + for (size_t k(0); k < _sfc_vecs.size(); k++) { + delete _sfc_vecs[k]; + } + // delete polylines + for (size_t k(0); k < _ply_vecs.size(); k++) { + delete _ply_vecs[k]; + } + // delete points + for (size_t k(0); k < _pnt_vecs.size(); k++) { + delete _pnt_vecs[k]; + } +} + +void GEOObjects::addPointVec(std::vector<Point*> *points, std::string &name, std::map<std::string, size_t>* pnt_id_name_map) +{ + isUniquePointVecName(name); + _pnt_vecs.push_back(new PointVec(name, points, pnt_id_name_map)); +// std::cout << "minimal dist between points: " << (_pnt_vecs[_pnt_vecs.size()-1])->getShortestPointDistance () << std::endl; +} + +bool GEOObjects::appendPointVec(std::vector<Point*> const& new_points, + std::string const &name, std::vector<size_t>* ids) +{ + // search vector + size_t idx (0); + bool nfound (true); + for (idx=0; idx<_pnt_vecs.size() && nfound; idx++) { + if ( (_pnt_vecs[idx]->getName()).compare (name) == 0 ) + nfound = false; + } + + if (! nfound) { + idx--; + size_t n_new_pnts (new_points.size()); + // append points + if (ids) { + for (size_t k(0); k<n_new_pnts; k++) { + ids->push_back (_pnt_vecs[idx]->push_back (new_points[k])); + } + } else { + for (size_t k(0); k<n_new_pnts; k++) { + _pnt_vecs[idx]->push_back (new_points[k]); + } + } + return true; + } else return false; +} + +const std::vector<Point*>* GEOObjects::getPointVec(const std::string &name) const +{ + size_t size (_pnt_vecs.size()); + for (size_t i=0; i<size; i++) + { + if (_pnt_vecs[i]->getName().compare(name)==0) + return _pnt_vecs[i]->getVector(); + } + std::cout << "GEOObjects::getPointVec() - No entry found with name \"" << name << "\"." << std::endl; + return NULL; +} + +const PointVec* GEOObjects::getPointVecObj(const std::string &name) const +{ + size_t size (_pnt_vecs.size()); + for (size_t i=0; i<size; i++) { + if (_pnt_vecs[i]->getName().compare(name)==0) + return _pnt_vecs[i]; + } + std::cout << "GEOObjects::getPointVec() - No entry found with name \"" << name << "\"." << std::endl; + return NULL; +} + +bool GEOObjects::removePointVec(const std::string &name) +{ + if (isPntVecUsed (name)) { + std::cout << "GEOObjects::removePointVec() - There are still Polylines or Surfaces depending on these points." << std::endl; + return false; + } + + for (std::vector<PointVec*>::iterator it(_pnt_vecs.begin()); + it != _pnt_vecs.end(); it++) { + if ((*it)->getName().compare(name)==0) { + delete *it; + _pnt_vecs.erase(it); + return true; + } + } + std::cout << "GEOObjects::removePointVec() - No entry found with name \"" << name << "." << std::endl; + return false; +} + + +void GEOObjects::addStationVec(std::vector<Point*> *stations, std::string &name, const Color* const color) +{ + size_t size = stations->size(); + for (size_t i=0; i<size; i++) static_cast<Station*>((*stations)[i])->setColor(color); + isUniquePointVecName(name); + _pnt_vecs.push_back(new PointVec(name, stations, NULL, PointVec::STATION)); +} + + +std::vector<Point*> *GEOObjects::filterStationVec(const std::string &name, + const std::vector<PropertyBounds> &bounds) +{ + for (std::vector<PointVec*>::iterator it(_pnt_vecs.begin()); + it != _pnt_vecs.end(); it++) { + if ((*it)->getName().compare(name) == 0 && (*it)->getType() + == PointVec::STATION) { + return (*it)->filterStations(bounds); + } + } + std::cout << "GEOObjects:: filterStations() - No entry found with name \"" + << name << "." << std::endl; + return NULL; +} + +const std::vector<Point*> *GEOObjects::getStationVec(const std::string &name) const +{ + for (std::vector<PointVec*>::const_iterator it(_pnt_vecs.begin()); + it != _pnt_vecs.end(); it++) { + if ((*it)->getName().compare(name) == 0 && (*it)->getType() + == PointVec::STATION) + return (*it)->getVector(); + } + std::cout << "GEOObjects::getStationVec() - No entry found with name \"" + << name << "." << std::endl; + return NULL; +} + +void GEOObjects::addPolylineVec(std::vector<Polyline*> *lines, + const std::string &name, std::map<std::string, size_t>* ply_names) +{ + for (std::vector<Polyline*>::iterator it (lines->begin()); + it != lines->end(); ) { + if ((*it)->getNumberOfPoints() < 2) { + std::vector<Polyline*>::iterator it_erase (it); + it = lines->erase (it_erase); + } else it++; + } + + if (lines->empty()) return; + + _ply_vecs.push_back(new PolylineVec(name, lines, ply_names)); +} + +bool GEOObjects::appendPolylineVec(const std::vector<Polyline*> &polylines, const std::string &name) +{ + // search vector + size_t idx (0); + bool nfound (true); + for (idx=0; idx<_ply_vecs.size() && nfound; idx++) { + if ( (_ply_vecs[idx]->getName()).compare (name) == 0 ) nfound = false; + } + + if (! nfound) { + idx--; + size_t n_plys (polylines.size()); + // append lines + for (size_t k(0); k<n_plys; k++) + _ply_vecs[idx]->push_back (polylines[k]); + return true; + } else return false; +} + +const std::vector<Polyline*> *GEOObjects::getPolylineVec(const std::string &name) const +{ + size_t size (_ply_vecs.size()); + for (size_t i=0; i<size; i++) + { + if (_ply_vecs[i]->getName().compare(name)==0) + return _ply_vecs[i]->getVector(); + } +#ifndef NDEBUG + std::cout << "DEB: GEOObjects::getPolylineVec() - No entry found with name \"" << name << "." << std::endl; +#endif + return NULL; +} + +const PolylineVec* GEOObjects::getPolylineVecObj(const std::string &name) const +{ + size_t size (_ply_vecs.size()); + for (size_t i=0; i<size; i++) { + if (_ply_vecs[i]->getName().compare(name)==0) + return _ply_vecs[i]; + } +#ifndef NDEBUG + std::cout << "DEB: GEOObjects::getPolylineVec() - No entry found with name \"" << name << "\"." << std::endl; +#endif + return NULL; +} + +bool GEOObjects::removePolylineVec(const std::string &name) +{ + for (std::vector<PolylineVec*>::iterator it = _ply_vecs.begin(); + it != _ply_vecs.end(); ++it) + { + if ((*it)->getName().compare(name) == 0) { + delete *it; + _ply_vecs.erase(it); + return true; + } + } +#ifndef NDEBUG + std::cout << "GEOObjects::removePolylineVec() - No entry found with name \"" + << name << "\"." << std::endl; +#endif + return false; +} + +void GEOObjects::addSurfaceVec(std::vector<Surface*> *sfc, const std::string &name, + std::map<std::string, size_t>* sfc_names) +{ + _sfc_vecs.push_back(new SurfaceVec(name, sfc, sfc_names)); +} + +bool GEOObjects::appendSurfaceVec(const std::vector<Surface*> &surfaces, const std::string &name) +{ + // search vector + size_t idx (0); + bool nfound (true); + for (idx=0; idx<_sfc_vecs.size() && nfound; idx++) { + if ( (_sfc_vecs[idx]->getName()).compare (name) == 0 ) nfound = false; + } + + if (! nfound) { + idx--; + size_t n_sfcs (surfaces.size()); + // append surfaces + for (size_t k(0); k<n_sfcs; k++) + _sfc_vecs[idx]->push_back (surfaces[k]); + return true; + } else return false; +} + +const std::vector<Surface*>* GEOObjects::getSurfaceVec(const std::string &name) const +{ + size_t size (_sfc_vecs.size()); + for (size_t i=0; i<size; i++) + { + if (_sfc_vecs[i]->getName().compare(name)==0) + return _sfc_vecs[i]->getVector(); + } + std::cout << "GEOObjects::getSurfaceVec() - No entry found with name \"" << name << "." << std::endl; + return NULL; +} + +bool GEOObjects::removeSurfaceVec(const std::string &name) +{ + for (std::vector<SurfaceVec*>::iterator it (_sfc_vecs.begin()); + it != _sfc_vecs.end(); it++) { + if ((*it)->getName().compare (name) == 0) { + delete *it; + _sfc_vecs.erase (it); + return true; + } + } +#ifndef NDEBUG + std::cout << "GEOObjects::removeSurfaceVec() - No entry found with name \"" + << name << "\"." << std::endl; +#endif + return false; +} + +const SurfaceVec* GEOObjects::getSurfaceVecObj(const std::string &name) const +{ + size_t size (_sfc_vecs.size()); + for (size_t i=0; i<size; i++) { + if (_sfc_vecs[i]->getName().compare(name)==0) + return _sfc_vecs[i]; + } + std::cout << "GEOObjects::getSurfaceVec() - No entry found with name \"" << name << "\"." << std::endl; + return NULL; +} + +bool GEOObjects::isUniquePointVecName(std::string &name) +{ + int count=0; + bool isUnique = false; + std::string cpName; + + while (!isUnique) + { + isUnique = true; + cpName = name; + + count++; + // If the original name already exists we start to add numbers to name for + // as long as it takes to make the name unique. + if (count>1) cpName = cpName + "-" + number2str(count); + + for (size_t i=0; i<_pnt_vecs.size(); i++) + { + if ( cpName.compare(_pnt_vecs[i]->getName()) == 0 ) isUnique = false; + } + } + + // At this point cpName is a unique name and isUnique is true. + // If cpName is not the original name, "name" is changed and isUnique is set to false, + // indicating that a vector with the original name already exists. + if (count>1) + { + isUnique = false; + name = cpName; + } + return isUnique; +} + +bool GEOObjects::isPntVecUsed (const std::string &name) const +{ + // search dependent data structures (Polyline) + for (std::vector<PolylineVec*>::const_iterator it ( _ply_vecs.begin()); it != _ply_vecs.end(); it++) + { + std::string a = (*it)->getName(); + if (((*it)->getName()).compare(name) == 0) + return true; + } + for (std::vector<SurfaceVec*>::const_iterator it ( _sfc_vecs.begin()); it != _sfc_vecs.end(); it++) + { + std::string a = (*it)->getName(); + if (((*it)->getName()).compare(name) == 0) + return true; + } + + return false; + +} + +void GEOObjects::getStationNames(std::vector<std::string>& names) const +{ + for (std::vector<PointVec*>::const_iterator it(_pnt_vecs.begin()); it != _pnt_vecs.end(); it++) { + if ((*it)->getType() == PointVec::STATION) + names.push_back((*it)->getName()); + } +} + +void GEOObjects::getGeometryNames (std::vector<std::string>& names) const +{ + names.clear (); + for (std::vector<PointVec*>::const_iterator it(_pnt_vecs.begin()); it != _pnt_vecs.end(); it++) { + if ((*it)->getType() == PointVec::POINT) + names.push_back((*it)->getName()); + } +} + +void GEOObjects::mergeGeometries (std::vector<std::string> const & geo_names, std::string &merged_geo_name) +{ + std::vector<size_t> pnt_offsets(geo_names.size(), 0); + + // *** merge points + std::vector<GEOLIB::Point*>* merged_points (new std::vector<GEOLIB::Point*>); + for (size_t j(0); j<geo_names.size(); j++) { + const std::vector<GEOLIB::Point*>* pnts (this->getPointVec(geo_names[j])); + if (pnts) { + size_t nPoints(0); + // do not consider stations + if (dynamic_cast<GEOLIB::Station*>((*pnts)[0]) == NULL) { + nPoints = pnts->size(); + for (size_t k(0); k<nPoints; k++) { + merged_points->push_back (new GEOLIB::Point (((*pnts)[k])->getData())); + } + } + if (geo_names.size()-1 > j) + pnt_offsets[j+1] = nPoints + pnt_offsets[j]; + } + } + + this->addPointVec (merged_points, merged_geo_name); + std::vector<size_t> const& id_map (this->getPointVecObj(merged_geo_name)->getIDMap ()); + + // *** merge polylines + std::vector<GEOLIB::Polyline*> *merged_polylines (new std::vector<GEOLIB::Polyline*>); + for (size_t j(0); j<geo_names.size(); j++) { + const std::vector<GEOLIB::Polyline*>* plys (this->getPolylineVec(geo_names[j])); + if (plys) { + for (size_t k(0); k<plys->size(); k++) { + GEOLIB::Polyline* kth_ply_new(new GEOLIB::Polyline (*merged_points)); + GEOLIB::Polyline const*const kth_ply_old ((*plys)[k]); + const size_t size_of_kth_ply (kth_ply_old->getNumberOfPoints()); + // copy point ids from old ply to new ply (considering the offset) + for (size_t i(0); i<size_of_kth_ply; i++) { + kth_ply_new->addPoint (id_map[pnt_offsets[j]+kth_ply_old->getPointID(i)]); + } + merged_polylines->push_back (kth_ply_new); + } + } + } + this->addPolylineVec (merged_polylines, merged_geo_name); + + + // *** merge surfaces + std::vector<GEOLIB::Surface*> *merged_sfcs (new std::vector<GEOLIB::Surface*>); + for (size_t j(0); j<geo_names.size(); j++) { + const std::vector<GEOLIB::Surface*>* sfcs (this->getSurfaceVec(geo_names[j])); + if (sfcs) { + for (size_t k(0); k<sfcs->size(); k++) { + GEOLIB::Surface* kth_sfc_new(new GEOLIB::Surface (*merged_points)); + GEOLIB::Surface const*const kth_sfc_old ((*sfcs)[k]); + const size_t size_of_kth_sfc (kth_sfc_old->getNTriangles()); + // copy point ids from old ply to new ply (considering the offset) + for (size_t i(0); i<size_of_kth_sfc; i++) { + const GEOLIB::Triangle* tri ((*kth_sfc_old)[i]); + const size_t id0 (id_map[pnt_offsets[j]+(*tri)[0]]); + const size_t id1 (id_map[pnt_offsets[j]+(*tri)[1]]); + const size_t id2 (id_map[pnt_offsets[j]+(*tri)[2]]); + kth_sfc_new->addTriangle (id0, id1, id2); + } + merged_sfcs->push_back (kth_sfc_new); + } + } + } + this->addSurfaceVec (merged_sfcs, merged_geo_name); +} + + +} // namespace diff --git a/GeoLib/GEOObjects.h b/GeoLib/GEOObjects.h new file mode 100644 index 0000000000000000000000000000000000000000..9eae16b0e8771813cb7c88ff0a60f756c15bb30a --- /dev/null +++ b/GeoLib/GEOObjects.h @@ -0,0 +1,232 @@ +/* + * GEOObjects.h + * + * Created on: Jan 21, 2010 + * Author: TF / KR + */ + +#ifndef GEOOBJECTS_H_ +#define GEOOBJECTS_H_ + +#include <vector> +#include <string> +#include <map> + +#include "PointVec.h" +#include "Point.h" +#include "PolylineVec.h" +#include "Polyline.h" +#include "SurfaceVec.h" +#include "Surface.h" + +#include "Color.h" +#include "Station.h" + +namespace GEOLIB { + +/// +/** + * \defgroup GEOLIB This module consists of classes governing geometric objects + * and related algorithms. + */ + +/** + * \brief Container class for geometric objects. + * + * This class contains all the methods necessary for the I/O of geometric objects. + * Said objects are Points, polylines, Surfaces and Stations and they are stored in + * vectors (arrays) which are identified by a unique name. + * For a hierarchical definition, surfaces are bounded by polylines and polylines + * are defined by points. Therefore, a vector of surfaces references a vector polylines + * and a vector of polylines references a vector of points, respectively. For + * identification purposes, all of these vectors have the same name, i.e. the polyline- + * vector named "aaa" references a point vector "aaa". However, this name ("aaa") is + * unique among all the vectors of the same class, i.e. there exists only one point- + * vector with this name, etc. + * Note: The fact that vectors are uniquely named and the same name is assigned to + * related objects is automatically handled by this class. + * + * For each of these object-classes exists an "add", "remove" and "get"-method which + * allows for loading/unloading as well as accessing the data, respectively. + * E.g. for points these methods are "addPointVec(name)", "getPointVec(name)" and + * "removePointVec(name)". For some objects, additional methods might exist if + * necessary. + */ +class GEOObjects { +public: + /** + * Adds a vector of points with the given name to GEOObjects. + * @param points vector of pointers to points + * @param name the project name + * @param pnt_names vector of the names corresponding to the points + */ + virtual void addPointVec(std::vector<Point*> *points, std::string &name, std::map<std::string, size_t>* pnt_names = NULL); + + /** copies the pointers to the points in the vector to the PointVec with provided name. + * the pointers are managed by the GEOObjects, i.e. GEOObjects will delete the Points at the + * end of its scope + * \param points the vector with points + * \param name the name of the internal PointVec + * \param ids On return the vector holds the ids of the inserted points within the internal vector. + * In case the ids are not needed it is possible to give a NULL pointer (default value). + * \return true if the points are appended, false if the a PointVec with the + * corresponding name does not exist + * */ + virtual bool appendPointVec(const std::vector<Point*> &points, + std::string const &name, std::vector<size_t>* ids = NULL); + + /** + * Returns the point vector with the given name. + */ + const std::vector<Point*> *getPointVec(const std::string &name) const; + + /** + * search and returns the PointVec object with the given name. + * @param name the name of the PointVec object + * @return the PointVec object stored in GEOObjects + */ + const PointVec* getPointVecObj(const std::string &name) const; + + /** If there exists no dependencies the point vector with the given + * name from GEOObjects will be removed and the method returns true, + * else the return value is false. + */ + virtual bool removePointVec(const std::string &name); + + /// Adds a vector of stations with the given name and colour to GEOObjects. + virtual void addStationVec(std::vector<Point*> *stations, std::string &name, + const Color* const color); + /// Filters a list of stations with the given name based on the criteria in PropertyBounds. + /// (See property system in Station class for more information.) + std::vector<Point*> *filterStationVec(const std::string &name, + const std::vector<PropertyBounds> &bounds); + /// Returns the station vector with the given name. + const std::vector<Point*> *getStationVec(const std::string &name) const; + + /// Removes the station vector with the given name from GEOObjects + virtual bool removeStationVec(const std::string &name) { + return removePointVec(name); + } + + + /** + * Adds a vector of polylines with the given name to GEOObjects. + * @param lines The lines vector. + * @param name The given name. + * @param ply_names vector of the names corresponding to the polylines + */ + virtual void addPolylineVec(std::vector<Polyline*> *lines, + const std::string &name, std::map<std::string,size_t>* ply_names = NULL); + + /** copies the pointers to the polylines in the vector to the PolylineVec with provided name. + * the pointers are managed by the GEOObjects, i.e. GEOObjects will delete the Polylines at the + * end of its scope + * \param polylines the vector with polylines + * \param name the name of the internal PolylineVec + * \return true if the polylines are appended, false if the PolylineVec with the + * corresponding name does not exist + * */ + virtual bool appendPolylineVec(const std::vector<Polyline*> &polylines, + const std::string &name); + + /** + * Returns the polyline vector with the given name. + * */ + const std::vector<Polyline*> *getPolylineVec(const std::string &name) const; + + /** + * Returns a pointer to a PolylineVec object for the given name as a const. + * @param name the name of the vector of polylines + * @return PolylineVec object + */ + const PolylineVec* getPolylineVecObj(const std::string &name) const; + + /// Returns a pointer to a PolylineVec object for the given name. + PolylineVec* getPolylineVecObj(const std::string &name) { + return const_cast<PolylineVec*>(static_cast<const GEOObjects&>(*this).getPolylineVecObj(name)); + }; + + /** + * If no Surfaces depends on the vector of Polylines with the given + * name it will be removed and the method returns true, + * else the return value is false. + */ + virtual bool removePolylineVec(const std::string &name); + + /** Adds a vector of surfaces with the given name to GEOObjects. */ + virtual void addSurfaceVec(std::vector<Surface*> *surfaces, + const std::string &name, std::map<std::string, size_t>* sfc_names = NULL); + + /** + * Copies the surfaces in the vector to the SurfaceVec with the given name. + * \param surfaces the vector with surfaces + * \param name the name of the internal PolylineVec + * \return true if the surfaces are appended, false if the SurfaceVec with the + * corresponding name does not exist + * */ + virtual bool appendSurfaceVec(const std::vector<Surface*> &surfaces, + const std::string &name); + + /// Returns the surface vector with the given name as a const. + const std::vector<Surface*> *getSurfaceVec(const std::string &name) const; + + /// Returns the surface vector with the given name. + SurfaceVec* getSurfaceVecObj(const std::string &name) { + return const_cast<SurfaceVec*>(static_cast<const GEOObjects&>(*this).getSurfaceVecObj(name)); + }; + + /** removes the vector of Surfaces with the given name */ + virtual bool removeSurfaceVec(const std::string &name); + /** + * Returns a pointer to a SurfaceVec object for the given name. The class + * SurfaceVec stores the relation between surfaces and the names of the surfaces. + * @param name the name of the vector of surfaces (the project name) + * @return SurfaceVec object + */ + const SurfaceVec* getSurfaceVecObj(const std::string &name) const; + + /// Returns the names of all geometry vectors. + void getGeometryNames (std::vector<std::string>& names) const; + + /// Returns the names of all station vectors. + void getStationNames(std::vector<std::string>& names) const; + + /** + * merge geometries + * @param names the names of the geometries that are to be merged + * @param merged_geo_name the name of the resulting geometry + */ + void mergeGeometries (std::vector<std::string> const & names, std::string &merged_geo_name); + + /** constructor */ + GEOObjects(); + /** destructor */ + virtual ~GEOObjects(); + +protected: + /** + * Determines if the given name is unique among all the names in point vectors and creates a + * new name if this is not the case. The new name is then simply "name + x", where x>1 is + * the smallest number that creates a unique name (i.e. "name-2", "name-3", etc.) + * \param name Original name of the list, this name might be changed within this method if necessary. + * \return true if the name was unique, false if a new name has been generated + */ + bool isUniquePointVecName(std::string &name); + + /// Checks if the point vector with the given name is referenced in a polyline- or surface vector. + bool isPntVecUsed (const std::string &name) const; + + /** + * vector manages pointers to PointVec objects + */ + std::vector<PointVec*> _pnt_vecs; + + /** vector manages pointers to PolylineVec objects */ + std::vector<PolylineVec*> _ply_vecs; + /** vector manages pointers to SurfaceVec objects */ + std::vector<SurfaceVec*> _sfc_vecs; +}; + +} // end namespace + +#endif /* GEOOBJECTS_H_ */ diff --git a/GeoLib/GeoObject.h b/GeoLib/GeoObject.h new file mode 100644 index 0000000000000000000000000000000000000000..d3bc2fbb5273f9677f92f150c18875b85e23054e --- /dev/null +++ b/GeoLib/GeoObject.h @@ -0,0 +1,27 @@ +/* + * GeoObject.h + * + * Created on: Aug 27, 2010 + * Author: TF + */ + +#ifndef GEOOBJECT_H_ +#define GEOOBJECT_H_ + +namespace GEOLIB { + +/** + * \ingroup GEOLIB + * + * \brief Base class for classes Point, Polyline, Surface. + */ + +class GeoObject { +public: + GeoObject() {}; + virtual ~GeoObject() {}; +}; + +} // end namespace GEOLIB + +#endif /* GEOOBJECT_H_ */ diff --git a/GeoLib/GeoType.cpp b/GeoLib/GeoType.cpp new file mode 100644 index 0000000000000000000000000000000000000000..79a13cb251ef5f658723f4a4a84fac4ef1558534 --- /dev/null +++ b/GeoLib/GeoType.cpp @@ -0,0 +1,32 @@ +/* + * GeoType.cpp + * + * Created on: Dec 1, 2010 + * Author: TF + */ + +#include "GeoType.h" + +namespace GEOLIB { + +GEOTYPE convertGeoType (const std::string& geo_type_str) +{ + if (geo_type_str.compare ("POINT") == 0) return POINT; + if (geo_type_str.compare ("POLYLINE") == 0) return POLYLINE; + if (geo_type_str.compare ("SURFACE") == 0) return SURFACE; + if (geo_type_str.compare ("VOLUME") == 0) return VOLUME; + if (geo_type_str.compare ("GEODOMAIN") == 0) return GEODOMAIN; + return INVALID; +} + +std::string convertGeoTypeToString (GEOTYPE geo_type) +{ + if (geo_type == POINT) return "POINT"; + if (geo_type == POLYLINE) return "POLYLINE"; + if (geo_type == SURFACE) return "SURFACE"; + if (geo_type == VOLUME) return "VOLUME"; + if (geo_type == GEODOMAIN) return "GEODOMAIN"; + return "INVALID"; +} + +} // end namespace GEOLIB diff --git a/GeoLib/GeoType.h b/GeoLib/GeoType.h new file mode 100644 index 0000000000000000000000000000000000000000..6f7f2bb7cddfe08673367287dcc4da135ec3f2aa --- /dev/null +++ b/GeoLib/GeoType.h @@ -0,0 +1,35 @@ +/* + * GeoType.h + * + * Created on: Jun 17, 2010 + * Author: TF + */ + +#ifndef GEOTYPE_H_ +#define GEOTYPE_H_ + +#include <string> + +namespace GEOLIB { + +/** + * \ingroup GEOLIB + */ + +enum GEOTYPE { + INVALID = 0, + POINT, //!< POINT + POLYLINE, //!< POLYLINE + SURFACE, //!< SURFACE + VOLUME, //!< VOLUME + GEODOMAIN, //!< GEODOMAIN + COLUMN //!< COLUMN. //WW/JOD +}; + +GEOTYPE convertGeoType (const std::string& geo_type_str); + +std::string convertGeoTypeToString (GEOTYPE geo_type); + +} // end namespace GEOLIB + +#endif /* GEOTYPE_H_ */ diff --git a/GeoLib/Point.cpp b/GeoLib/Point.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4ebe2072d237066eb9cffee96ca55c0190d28675 --- /dev/null +++ b/GeoLib/Point.cpp @@ -0,0 +1,55 @@ +/* + * Point.cpp + * + * Created on: Jun 22, 2010 + * Author: TF + */ + + +#include <cmath> +#include <limits> + +#include "Point.h" + +bool operator<= (const GEOLIB::Point& p0, const GEOLIB::Point& p1) +{ + double tol (sqrt (std::numeric_limits<double>::min())); + + if (fabs (p0[0]-p1[0]) > tol * fabs(p0[0])) { + if (p0[0] < p1[0]) return true; + else return false; + } else { + // assume p0[0] == p1[0] + if (fabs (p0[1]-p1[1]) > tol * fabs(p0[1])) { + if (p0[1] < p1[1]) return true; + else return false; + } else { + // assume p0[1] == p1[1] and p0[0] == p1[0] + if (p0[2] < p1[2]) return true; + else return false; + } + } +} + +namespace GEOLIB { + +bool lessX (GEOLIB::Point const & p0, GEOLIB::Point const & p1) +{ + if (p0[0] <= p1[0]) return true; + return false; +} + +bool lessY (GEOLIB::Point const & p0, GEOLIB::Point const & p1) +{ + if (p0[1] <= p1[1]) return true; + return false; +} + +bool lessZ (GEOLIB::Point const & p0, GEOLIB::Point const & p1) +{ + if (p0[2] <= p1[2]) return true; + return false; +} + + +} // end namespace GEOLIB diff --git a/GeoLib/Point.h b/GeoLib/Point.h new file mode 100644 index 0000000000000000000000000000000000000000..a89a7e7d12be10c30f4687feecd25f70a27bf308 --- /dev/null +++ b/GeoLib/Point.h @@ -0,0 +1,51 @@ +/*************************************************************************** + * Point.h + * Created on: Jan 12, 2010 + * Author: TF +**************************************************************************/ + +#ifndef POINT_H_ +#define POINT_H_ + +#include "TemplatePoint.h" + +namespace GEOLIB { + +/** + * \ingroup GEOLIB + */ + +typedef TemplatePoint<double> Point; + +/** + * comparison based on the x coordinate + * @param p0 first point + * @param p1 second point + * @return true if the x coordinate of p0 is smaller equal the x coordinate of p1, else false + */ +bool lessX (Point const & p0, Point const & p1); + +/** + * comparison based on the y coordinate + * @param p0 first point + * @param p1 second point + * @return true if the y coordinate of p0 is smaller equal the y coordinate of p1, else false + */ +bool lessY (Point const & p0, Point const & p1); + +/** + * comparison based on the z coordinate + * @param p0 first point + * @param p1 second point + * @return true if the z coordinate of p0 is smaller equal the z coordinate of p1, else false + */ +bool lessZ (Point const & p0, Point const & p1); + +} + +/** + * lexicographic comparison of points + */ +bool operator<= (GEOLIB::Point const & p0, GEOLIB::Point const & p1); + +#endif /* POINT_H_ */ diff --git a/GeoLib/PointVec.cpp b/GeoLib/PointVec.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f59f637ccfbfe369018f1597a0658788b723d575 --- /dev/null +++ b/GeoLib/PointVec.cpp @@ -0,0 +1,258 @@ +/* + * PointVec.cpp + * + * Created on: Jun 11, 2010 + * Author: TF + */ + +#include "PointVec.h" +#include "BruteForceClosestPair.h" + +namespace GEOLIB { + +PointVec::PointVec (const std::string& name, std::vector<Point*>* points, + std::map<std::string, size_t>* name_id_map, PointType type) : + _pnt_vec (points), _name_id_map (name_id_map), _type(type), _name (name), + _sqr_shortest_dist (std::numeric_limits<double>::max()) +{ + assert (_pnt_vec); + size_t number_of_all_input_pnts (_pnt_vec->size()); + + makePntsUnique (_pnt_vec, _pnt_id_map); + + if (number_of_all_input_pnts - _pnt_vec->size() > 0) + std::cerr << "WARNING: there are " << number_of_all_input_pnts - _pnt_vec->size() << " double points" << std::endl; +// calculateShortestDistance (); + calculateAxisAlignedBoundingBox (); +} + +PointVec::~PointVec () +{ + for (size_t k(0); k<_pnt_vec->size(); k++) { + delete (*_pnt_vec)[k]; + (*_pnt_vec)[k] = NULL; + } + delete _pnt_vec; + delete _name_id_map; +} + +size_t PointVec::push_back (Point *pnt) +{ + _pnt_id_map.push_back (uniqueInsert(pnt)); + return _pnt_id_map[_pnt_id_map.size()-1]; +} + +void PointVec::push_back (Point *pnt, const std::string& name) +{ + std::map<std::string,size_t>::const_iterator it (_name_id_map->find (name)); + if (it != _name_id_map->end()) { + std::cerr << "ERROR: PointVec::push_back (): two points with the same name" << std::endl; + return; + } + + size_t id (uniqueInsert (pnt)); + _pnt_id_map.push_back (id); + (*_name_id_map)[name] = id; +} + +size_t PointVec::uniqueInsert (Point* pnt) +{ + size_t n (_pnt_vec->size()), k; + const double eps (std::numeric_limits<double>::epsilon()); + for (k=0; k<n; k++) { + if (fabs((*((*_pnt_vec)[k]))[0]-(*pnt)[0]) < eps + && fabs( (*((*_pnt_vec)[k]))[1]-(*pnt)[1]) < eps + && fabs( (*((*_pnt_vec)[k]))[2]-(*pnt)[2]) < eps) { + break; + } + } + + if(k==n) { + _pnt_vec->push_back (pnt); + // update shortest distance and bounding box + for (size_t i(0); i<n; i++) { + double sqr_dist (MathLib::sqrDist((*_pnt_vec)[i], (*_pnt_vec)[n])); + if (sqr_dist < _sqr_shortest_dist) + _sqr_shortest_dist = sqr_dist; + aabb.update (*((*_pnt_vec)[n])); + } + return n; + } + + delete pnt; + pnt = NULL; + return k; +} + +std::vector<Point*> * PointVec::filterStations(const std::vector<PropertyBounds> &bounds) const +{ + std::vector<Point*> *tmpStations (new std::vector<Point*>); + size_t size (_pnt_vec->size()); + for (size_t i=0; i<size; i++) { + if (static_cast<Station*>((*_pnt_vec)[i])->inSelection(bounds)) tmpStations->push_back((*_pnt_vec)[i]); + } + return tmpStations; +} + +bool PointVec::getElementIDByName (const std::string& name, size_t &id) const +{ + std::map<std::string,size_t>::const_iterator it (_name_id_map->find (name)); + + if (it != _name_id_map->end()) { + id = it->second; + return true; + } else return false; +} + +const Point* PointVec::getElementByName (const std::string& name) const +{ + size_t id; + bool ret (getElementIDByName (name, id)); + if (ret) { + return (*_pnt_vec)[id]; + } else { + return NULL; + } +} + +bool PointVec::getNameOfElement (const Point* data, std::string& name) const +{ + for (size_t k(0); k<_pnt_vec->size(); k++) { + if ((*_pnt_vec)[k] == data) { + return getNameOfElementByID (k, name); + } + } + return false; +} + +bool PointVec::getNameOfElementByID (size_t id, std::string& element_name) const +{ + if (! _name_id_map) return false; + // search in map for id + std::map<std::string,size_t>::const_iterator it (_name_id_map->begin()); + while (it != _name_id_map->end()) { + if (it->second == id) { + element_name = it->first; + return true; + } + it++; + } + return false; +} + +double PointVec::getShortestPointDistance () const +{ + return sqrt (_sqr_shortest_dist); +} + +void PointVec::makePntsUnique (std::vector<GEOLIB::Point*>* pnt_vec, std::vector<size_t> &pnt_id_map) +{ + size_t n_pnts_in_file (pnt_vec->size()); + std::vector<size_t> perm; + pnt_id_map.reserve (n_pnts_in_file); + for (size_t k(0); k<n_pnts_in_file; k++) { + perm.push_back (k); + pnt_id_map.push_back(k); + } + + // sort the points + Quicksort<GEOLIB::Point*> (*pnt_vec, 0, n_pnts_in_file, perm); + + // unfortunately quicksort is not stable - + // sort identical points by id - to make sorting stable + double eps (sqrt(std::numeric_limits<double>::min())); + // determine intervals with identical points to resort for stability of sorting + std::vector<size_t> identical_pnts_interval; + bool identical (false); + for (size_t k=0; k<n_pnts_in_file-1; k++) { + if ( fabs((*((*pnt_vec)[k+1]))[0]-(*((*pnt_vec)[k]))[0]) < eps + && fabs( (*((*pnt_vec)[k+1]))[1]-(*((*pnt_vec)[k]))[1]) < eps + && fabs( (*((*pnt_vec)[k+1]))[2]-(*((*pnt_vec)[k]))[2]) < eps) { + // points are identical, sort by id + if (!identical) identical_pnts_interval.push_back (k); + identical = true; + } else { + if (identical) identical_pnts_interval.push_back (k+1); + identical = false; + } + } + if (identical) identical_pnts_interval.push_back (n_pnts_in_file); + + for (size_t i(0); i<identical_pnts_interval.size()/2; i++) { + // bubble sort by id + size_t beg (identical_pnts_interval[2*i]); + size_t end (identical_pnts_interval[2*i+1]); + for (size_t j (beg); j<end; j++) { + for (size_t k (beg); k<end-1; k++) { + if (perm[k] > perm[k+1]) std::swap (perm[k], perm[k+1]); + } + } + } + + // check if there are identical points + for (size_t k=0; k<n_pnts_in_file-1; k++) { + if ( fabs((*((*pnt_vec)[k+1]))[0]-(*((*pnt_vec)[k]))[0]) < eps + && fabs( (*((*pnt_vec)[k+1]))[1]-(*((*pnt_vec)[k]))[1]) < eps + && fabs( (*((*pnt_vec)[k+1]))[2]-(*((*pnt_vec)[k]))[2]) < eps) { + pnt_id_map[perm[k+1]] = pnt_id_map[perm[k]]; + } + } + + // reverse permutation + Quicksort<GEOLIB::Point*> (perm, 0, n_pnts_in_file, *pnt_vec); + + // remove the second, third, ... occurrence from vector + for (size_t k(0); k<n_pnts_in_file; k++) { + if (pnt_id_map[k] < k) { + delete (*pnt_vec)[k]; + (*pnt_vec)[k] = NULL; + } + } + // remove NULL-ptr from vector + for (std::vector<GEOLIB::Point*>::iterator it(pnt_vec->begin()); it != pnt_vec->end(); ) { + if (*it == NULL) { + it = pnt_vec->erase (it); + } + else it++; + } + + // renumber id-mapping + size_t cnt (0); + for (size_t k(0); k<n_pnts_in_file; k++) { + if (pnt_id_map[k] == k) { // point not removed, if necessary: id change + pnt_id_map[k] = cnt; + cnt++; + } else { + pnt_id_map[k] = pnt_id_map[pnt_id_map[k]]; + } + } + + // KR correct renumbering of indices +// size_t cnt(0); +// std::map<size_t, size_t> reg_ids; +// for (size_t k(0); k < n_pnts_in_file; k++) { +// if (pnt_id_map[k] == k) { +// reg_ids.insert(std::pair<size_t, size_t>(k, cnt)); +// cnt++; +// } else reg_ids.insert(std::pair<size_t, size_t>(k, reg_ids[pnt_id_map[k]])); +// } +// for (size_t k(0); k < n_pnts_in_file; k++) +// pnt_id_map[k] = reg_ids[k]; +} + +void PointVec::calculateShortestDistance () +{ + size_t i, j; + BruteForceClosestPair (*_pnt_vec, i, j); + _sqr_shortest_dist = MathLib::sqrDist ((*_pnt_vec)[i], (*_pnt_vec)[j]); +} + +void PointVec::calculateAxisAlignedBoundingBox () +{ + const size_t n_pnts (_pnt_vec->size()); + for (size_t i(0); i<n_pnts; i++) { + aabb.update (*(*_pnt_vec)[i]); + } +} + +} // end namespace diff --git a/GeoLib/PointVec.h b/GeoLib/PointVec.h new file mode 100644 index 0000000000000000000000000000000000000000..fa54cd5bf3db505c6abd8fcfebc425c7b57de193 --- /dev/null +++ b/GeoLib/PointVec.h @@ -0,0 +1,200 @@ +/* + * \file PointVec.h + * + * Created on: Feb 2, 2010 + * Author: TF / KR + */ + + +// GEOLIB +#include "Point.h" +#include "Station.h" +#include "AxisAlignedBoundingBox.h" + +// Base +#include "quicksort.h" +#include "binarySearch.h" + +#include <vector> +#include <string> +#include <map> + +#ifndef POINTVEC_H_ +#define POINTVEC_H_ + +namespace GEOLIB { + +/** + * \ingroup GEOLIB + * + * \brief This class manages pointers to Points in a std::vector along with a name. + * It also handles the deleting of points. Additionally, each vector of points is identified by + * a unique name from class GEOObject. For this reason PointVec should have + * a name. + * */ +class PointVec +{ +public: + /// Signals if the vector contains object of type Point or Station + enum PointType + { + POINT = 0, + STATION = 1 + }; + + /** + * Constructor initializes the name of the PointVec object, + * the internal pointer _pnt_vec to the raw points and the internal + * pointer the vector of names of the points + * and sets the type of PointVec. + * @param name the name of the point group + * @param points pointer to a vector of GEOLIB::Pointers - + * PointVec will take the ownership of the vector, + * i.e. delete the points and the vector itself + * @param name_id_map the names to the points - + * PointVec will take the ownership of the vector, i.e. it + * deletes the names + * @param type the type of the point, \sa enum PointType + * @return an object of type PointVec + */ + PointVec (const std::string& name, std::vector<Point*>* points, std::map<std::string, size_t>* name_id_map = NULL, + PointType type = PointVec::POINT); + + /** Destructor deletes all Points of this PointVec. */ + ~PointVec (); + + /** + * Method adds a Point to the (internal) standard vector and takes the ownership. + * If the given point is already included in the vector, the point will be destroyed and + * the id of the existing point will be returned. + * @param pnt the pointer to the Point + * @return the id of the point within the internal vector + */ + size_t push_back (Point *pnt); + + /** + * push_back adds new elements at the end of the vector _pnt_vec. + * @param pnt a pointer to the point, PointVec takes ownership of the point + * @param name the name of the point + */ + void push_back (Point *pnt, const std::string& name); + + /** + * get the actual number of Points + */ + size_t size () const { return _pnt_vec->size(); } + /** + * get the type of Point, this can be either POINT or STATION + * + */ + PointType getType() const { return _type; } + + /** + * getVector returns the internal vector of Points, + * you are not able to change the Points or the address of the vector. + */ + const std::vector<Point*>* getVector () const { return _pnt_vec; } + + std::vector<Point*> *filterStations(const std::vector<PropertyBounds> &bounds) const; + + /** sets the name of the object + * \param n the name as standard string */ + void setName(const std::string & n) { _name = n; } + /** returns the name of the object */ + std::string getName () const { return _name; } + + /** + * search the vector of names for the ID of the point with the given name + * @param name the name of the point + * @param id the id of the point + * @return the id of the point + */ + bool getElementIDByName (const std::string& name, size_t &id) const; + + /** + * Method searchs for point with the given name. If it found a point with the name + * it returns a pointer to the point, else it returns the NULL pointer. + * @param name the name of the point + * @return the pointer to the point or NULL + */ + const Point* getElementByName (const std::string& name) const; + + /** + * The method returns true if the given element of type T + * can be found and the element has a name, else method returns false. + * @param data the data element, one wants to know the name + * @param name the name of the data element (if the data element is + * found and the data element has a name) + * @return if element is found and has a name: true, else false + */ + bool getNameOfElement (const Point* data, std::string& name) const; + + /** + * The method returns true if there is a name associated + * with the given id, else method returns false. + * @param id the id + * @param element_name if a name associated with the id + * is found name is assigned to element_name + * @return if there is name associated with the given id: + * true, else false + */ + bool getNameOfElementByID (size_t id, std::string& element_name) const; + + const std::vector<size_t>& getIDMap () const { return _pnt_id_map; } + + double getShortestPointDistance () const; + const GEOLIB::AABB& getAxisAlignedBoundingBox () const; + +private: + void makePntsUnique (std::vector<GEOLIB::Point*>* pnt_vec, std::vector<size_t> &pnt_id_map); + + /** copy constructor doesn't have an implementation */ + // compiler does not create a (possible unwanted) copy constructor + PointVec (const PointVec &); + /** standard constructor doesn't have an implementation */ + // compiler does not create a (possible unwanted) standard constructor + PointVec (); + + /** assignment operator doesn't have an implementation */ + // this way the compiler does not create a (possible unwanted) assignment operator + PointVec& operator= (const PointVec& rhs); + + size_t uniqueInsert (Point *pnt); + + /** + * pointer to a vector of pointers to Points + * + * The destructor of PointVec will delete all GEOLIB::Points + * inside the vector. + */ + std::vector<Point*> *_pnt_vec; + /** + * used to store the name associated with a point + */ + std::map<std::string, size_t>* _name_id_map; + /** the type of the point (\sa enum PointType) */ + PointType _type; + /** the name of the object */ + std::string _name; + /** + * permutation of the geometric elements according + * to their lexicographical order + */ + std::vector<size_t> _pnt_id_map; + + /** + * method calculates the shortest distance of points inside the _pnt_vec + */ + void calculateShortestDistance (); + /** + * squared shortest distance - calculated by calculateShortestAndLargestDistance, possible update by uniqueInsert + */ + double _sqr_shortest_dist; + + void calculateAxisAlignedBoundingBox (); + AABB aabb; +}; + +} // end namespace + +#endif /* POINTVEC_H_ */ diff --git a/GeoLib/PointWithID.h b/GeoLib/PointWithID.h new file mode 100644 index 0000000000000000000000000000000000000000..530830411f7b10e24b49c42c7af797b54cb8a5f7 --- /dev/null +++ b/GeoLib/PointWithID.h @@ -0,0 +1,37 @@ +/* + * PointWithID.h + * + * Created on: Jan 25, 2011 + * Author: TF + */ + +#ifndef POINTWITHID_H_ +#define POINTWITHID_H_ + +#include "Point.h" + +namespace GEOLIB { +/** + * class PointWithID is derived from class Point in + * order to extend the class Point with an ID. + */ +class PointWithID : public Point +{ +public: + PointWithID (double x0, double x1, double x2, size_t id) : + Point (x0, x1, x2), _id (id) + {} + + PointWithID (double const*const coords, size_t id) : + Point (coords), _id (id) + {} + + + size_t getID () const { return _id; } + +protected: + size_t _id; +}; +} // end namespace GEOLIB + +#endif /* POINTWITHID_H_ */ diff --git a/GeoLib/Polygon.cpp b/GeoLib/Polygon.cpp new file mode 100644 index 0000000000000000000000000000000000000000..90e79664ba1ad33ad82171b0100a26eda0ba581c --- /dev/null +++ b/GeoLib/Polygon.cpp @@ -0,0 +1,400 @@ +/* + * Polygon.cpp + * + * Created on: Jun 21, 2010 + * Author: TF + */ + +#include <cstdlib> // for exit +#include <cmath> + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +#include "Polygon.h" + +// MathLib +#include "AnalyticalGeometry.h" +#include "MathTools.h" +#include "Vector3.h" + +// Base +#include "quicksort.h" +#include "swap.h" + +namespace GEOLIB { + +Polygon::Polygon(const Polyline &ply, bool init) : + Polyline (ply) +{ + if (init) { + initialise (); + } +} + +Polygon::Polygon (const std::vector<Point*>& pnt_vec) : + Polyline (pnt_vec) +{} + +Polygon::~Polygon() +{ + // remove polygons from list + for (std::list<Polygon*>::iterator it (_simple_polygon_list.begin()); it != _simple_polygon_list.end(); it++) { + // the first entry of the list can be a pointer the object itself + if (*it != this) + delete *it; + } +} + +bool Polygon::initialise () +{ + if (this->isClosed()) { + calculateAxisAlignedBoundingBox(); + ensureCWOrientation(); + return true; + } else { + std::cerr << "ERROR in Polygon::initialise() - base polyline is not closed" << std::endl; + return false; + } +} + +bool Polygon::isPntInPolygon (GEOLIB::Point const & pnt) const +{ + GEOLIB::Point min_aabb_pnt (_aabb.getMinPoint()); + GEOLIB::Point max_aabb_pnt (_aabb.getMaxPoint()); + + if (pnt[0] < min_aabb_pnt[0] || max_aabb_pnt[0] < pnt[0] || pnt[1] < min_aabb_pnt[1] || max_aabb_pnt[1] < pnt[1]) + return false; + + size_t n_intersections (0); + GEOLIB::Point s; + + if (_simple_polygon_list.empty ()) { + const size_t n_nodes (getNumberOfPoints()-1); + for (size_t k(0); k<n_nodes; k++) { + if (((*(getPoint(k)))[1] <= pnt[1] && pnt[1] <= (*(getPoint(k+1)))[1]) || + ((*(getPoint(k+1)))[1] <= pnt[1] && pnt[1] <= (*(getPoint(k)))[1])) { + switch (getEdgeType(k, pnt)) { + case EdgeType::TOUCHING: + return true; + case EdgeType::CROSSING: + n_intersections++; + break; + case EdgeType::INESSENTIAL: + break; + default: + // do nothing + ; + } + } + } + if (n_intersections%2 == 1) return true; + } else { + for (std::list<Polygon*>::const_iterator it (_simple_polygon_list.begin()); + it != _simple_polygon_list.end(); ++it) { + if ((*it)->isPntInPolygon (pnt)) return true; + } + return false; + } + return false; +} + +bool Polygon::isPntInPolygon (double x, double y, double z) const +{ + const GEOLIB::Point pnt(x,y,z); + return isPntInPolygon (pnt); +} + +bool Polygon::isPolylineInPolygon (const Polyline& ply) const +{ + size_t ply_size (ply.getNumberOfPoints()), cnt (0); + for (size_t k(0); k<ply_size; k++) { + if (isPntInPolygon (*(ply[k]))) { + cnt++; + } + } + if (cnt == ply_size) + return true; + return false; +} + +GEOLIB::Point* Polygon::getIntersectionPointPolygonLine (GEOLIB::Point const & a, GEOLIB::Point const & b) const +{ + GEOLIB::Point* s (new GEOLIB::Point (0,0,0)); + + if (_simple_polygon_list.empty ()) { + const size_t n_nodes (getNumberOfPoints()-1); + for (size_t k(0); k<n_nodes; k++) { + if (MathLib::lineSegmentIntersect (*(getPoint(k)), *(getPoint(k+1)), a, b, *s)) { + return s; + } + } + } else { + for (std::list<Polygon*>::const_iterator it (_simple_polygon_list.begin()); + it != _simple_polygon_list.end(); ++it) { + const Polygon* polygon (*it); + const size_t n_nodes_simple_polygon (polygon->getNumberOfPoints()-1); + for (size_t k(0); k<n_nodes_simple_polygon; k++) { + if (MathLib::lineSegmentIntersect (*(polygon->getPoint(k)), *(polygon->getPoint(k+1)), a, b, *s)) { + return s; + } + } + } + } + delete s; + return NULL; +} + +const std::list<Polygon*>& Polygon::getListOfSimplePolygons() +{ + if (_simple_polygon_list.empty()) + _simple_polygon_list.push_back (this); + return _simple_polygon_list; +} + +void Polygon::computeListOfSimplePolygons () +{ + if (! _simple_polygon_list.empty()) + return; + + _simple_polygon_list.push_back (this); + splitPolygonAtPoint (_simple_polygon_list.begin()); + splitPolygonAtIntersection (_simple_polygon_list.begin()); + + for (std::list<Polygon*>::iterator it (_simple_polygon_list.begin()); + it != _simple_polygon_list.end(); it++) { + (*it)->initialise (); + } +} + +EdgeType::value Polygon::getEdgeType (size_t k, GEOLIB::Point const & pnt) const +{ + switch (getLocationOfPoint(k, pnt)) { + case Location::LEFT: { + const GEOLIB::Point & v (*(getPoint(k))); + const GEOLIB::Point & w (*(getPoint(k+1))); + if (v[1] < pnt[1] && pnt[1] <= w[1]) return EdgeType::CROSSING; + else return EdgeType::INESSENTIAL; + break; + } + case Location::RIGHT: { + const GEOLIB::Point & v (*(getPoint(k))); + const GEOLIB::Point & w (*(getPoint(k+1))); + if (w[1] < pnt[1] && pnt[1] <= v[1]) return EdgeType::CROSSING; + else return EdgeType::INESSENTIAL; + break; + } + case Location::BETWEEN: + case Location::SOURCE: + case Location::DESTINATION: + return EdgeType::TOUCHING; + default: + return EdgeType::INESSENTIAL; + } +} + +void Polygon::calculateAxisAlignedBoundingBox () +{ + size_t n_nodes (getNumberOfPoints()); + for (size_t k(0); k<n_nodes; k++) { + _aabb.update ((*(getPoint(k)))); + } +} + +void Polygon::ensureCWOrientation () +{ + // *** pre processing: rotate points to xy-plan + // *** copy points to vector - last point is identical to the first + size_t n_pnts (this->getNumberOfPoints()-1); + std::vector<GEOLIB::Point*> tmp_polygon_pnts; + for (size_t k(0); k < n_pnts; k++) { + tmp_polygon_pnts.push_back (new GEOLIB::Point (*(this->getPoint(k)))); + } + + // *** calculate supporting plane (plane normal and + MathLib::Vector plane_normal; + double d; + MathLib::getNewellPlane(tmp_polygon_pnts, plane_normal, d); + + // *** rotate if necessary + double tol (sqrt(std::numeric_limits<double>::min())); + if (fabs(plane_normal[0]) > tol || fabs(plane_normal[1]) > tol) { + // rotate copied points into x-y-plane + MathLib::rotatePointsToXY(plane_normal, tmp_polygon_pnts); + } + + for (size_t k(0); k<tmp_polygon_pnts.size(); k++) { + (*(tmp_polygon_pnts[k]))[2] = 0.0; // should be -= d but there are numerical errors + } + + // *** get the left most upper point + size_t min_x_max_y_idx (0); // for orientation check + for (size_t k(0); k<n_pnts; k++) { + if ((*(tmp_polygon_pnts[k]))[0] <= (*(tmp_polygon_pnts[min_x_max_y_idx]))[0]) { + if ((*(tmp_polygon_pnts[k]))[0] < (*(tmp_polygon_pnts[min_x_max_y_idx]))[0]) { + min_x_max_y_idx = k; + } else { + if ((*(tmp_polygon_pnts[k]))[1] > (*(tmp_polygon_pnts[min_x_max_y_idx]))[1]) { + min_x_max_y_idx = k; + } + } + } + } + // *** determine orientation + MathLib::Orientation orient; + if (0 < min_x_max_y_idx && min_x_max_y_idx < n_pnts-2) { + orient = MathLib::getOrientation ( + tmp_polygon_pnts[min_x_max_y_idx-1], + tmp_polygon_pnts[min_x_max_y_idx], + tmp_polygon_pnts[min_x_max_y_idx+1]); + } else { + if (0 == min_x_max_y_idx) { + orient = MathLib::getOrientation ( + tmp_polygon_pnts[n_pnts-1], + tmp_polygon_pnts[0], + tmp_polygon_pnts[1]); + } else { + orient = MathLib::getOrientation ( + tmp_polygon_pnts[n_pnts-2], + tmp_polygon_pnts[n_pnts-1], + tmp_polygon_pnts[0]); + } + } + + if (orient == MathLib::CCW) { + // switch orientation + size_t tmp_n_pnts (n_pnts); + tmp_n_pnts++; // include last point of polygon (which is identical to the first) + for (size_t k(0); k<tmp_n_pnts/2; k++) { + BASELIB::swap (_ply_pnt_ids[k], _ply_pnt_ids[tmp_n_pnts-1-k]); + } + } + + for (size_t k(0); k<n_pnts; k++) { + delete tmp_polygon_pnts[k]; + } +} + +void Polygon::splitPolygonAtIntersection (std::list<Polygon*>::iterator polygon_it) +{ + size_t idx0 (0), idx1 (0); + while (polygon_it != _simple_polygon_list.end()) { + GEOLIB::Point *intersection_pnt (new GEOLIB::Point); + bool is_simple (!MathLib::lineSegmentsIntersect (*polygon_it, idx0, idx1, *intersection_pnt)); + if (!is_simple) { + // adding intersection point to pnt_vec + size_t intersection_pnt_id (_ply_pnts.size()); + const_cast<std::vector<Point*>& >(_ply_pnts).push_back (intersection_pnt); + + // split Polygon + if (idx0 > idx1) BASELIB::swap (idx0, idx1); + + GEOLIB::Polygon* polygon0 (new GEOLIB::Polygon((*polygon_it)->getPointsVec(), false)); + for (size_t k(0); k<=idx0; k++) polygon0->addPoint ((*polygon_it)->getPointID (k)); + polygon0->addPoint (intersection_pnt_id); + for (size_t k(idx1+1); k<(*polygon_it)->getNumberOfPoints(); k++) + polygon0->addPoint ((*polygon_it)->getPointID (k)); + if (! polygon0->initialise()) { + std::cerr << "ERROR in Polygon::splitPolygonAtIntersection polygon0" << std::endl; + exit (1); + } + + GEOLIB::Polygon* polygon1 (new GEOLIB::Polygon((*polygon_it)->getPointsVec(), false)); + polygon1->addPoint (intersection_pnt_id); + for (size_t k(idx0+1); k<=idx1; k++) + polygon1->addPoint ((*polygon_it)->getPointID (k)); + polygon1->addPoint (intersection_pnt_id); + if (! polygon1->initialise()) { + std::cerr << "ERROR in Polygon::splitPolygonAtIntersection polygon1" << std::endl; + exit (1); + } + + // remove original polyline and add two new polylines + std::list<GEOLIB::Polygon*>::iterator polygon0_it, polygon1_it; + polygon_it = _simple_polygon_list.erase (polygon_it); + polygon1_it = _simple_polygon_list.insert (polygon_it, polygon1); + polygon0_it = _simple_polygon_list.insert (polygon1_it, polygon0); + + splitPolygonAtIntersection (polygon0_it); + splitPolygonAtIntersection (polygon1_it); + } else { + delete intersection_pnt; + } + ++polygon_it; + } +} + +void Polygon::splitPolygonAtPoint (std::list<GEOLIB::Polygon*>::iterator polygon_it) +{ + size_t n ((*polygon_it)->getNumberOfPoints()-1), idx0 (0), idx1(0); + size_t *id_vec (new size_t[n]), *perm (new size_t[n]); + for (size_t k(0); k<n; k++) { + id_vec[k] = (*polygon_it)->getPointID (k); + perm[k] = k; + } + + quicksort (id_vec, 0, n, perm); + + for (size_t k(0); k<n-1; k++) { + if (id_vec[k] == id_vec[k+1]) { + idx0 = perm[k]; + idx1 = perm[k+1]; + delete [] perm; + delete [] id_vec; + + if (idx0 > idx1) BASELIB::swap (idx0, idx1); + + // create two closed polylines + GEOLIB::Polygon* polygon0 (new GEOLIB::Polygon((*polygon_it)->getPointsVec())); + for (size_t k(0); k<=idx0; k++) + polygon0->addPoint ((*polygon_it)->getPointID (k)); + for (size_t k(idx1+1); k<(*polygon_it)->getNumberOfPoints(); k++) + polygon0->addPoint ((*polygon_it)->getPointID (k)); + polygon0->initialise(); + + GEOLIB::Polygon* polygon1 (new GEOLIB::Polygon((*polygon_it)->getPointsVec())); + for (size_t k(idx0); k<=idx1; k++) + polygon1->addPoint ((*polygon_it)->getPointID (k)); + polygon1->initialise(); + + // remove original polygon and add two new polygons + std::list<GEOLIB::Polygon*>::iterator polygon0_it, polygon1_it; + polygon1_it = _simple_polygon_list.insert (_simple_polygon_list.erase (polygon_it), polygon1); + polygon0_it = _simple_polygon_list.insert (polygon1_it, polygon0); + + splitPolygonAtPoint (polygon0_it); + splitPolygonAtPoint (polygon1_it); + + return; + } + } + delete [] perm; + delete [] id_vec; +} + +GEOLIB::Polygon* createPolygonFromCircle (GEOLIB::Point const& middle_pnt, double radius, + std::vector<GEOLIB::Point*> & pnts, size_t resolution) +{ + const size_t off_set (pnts.size()); + // create points + double angle (2.0 * M_PI / resolution); + for (size_t k(0); k<resolution; k++) { + GEOLIB::Point *pnt (new GEOLIB::Point(middle_pnt.getData())); + (*pnt)[0] += radius * cos (k*angle); + (*pnt)[1] += radius * sin (k*angle); + pnts.push_back (pnt); + } + + // create polygon + GEOLIB::Polygon* polygon (new GEOLIB::Polygon (pnts, false)); + for (size_t k(0); k<resolution; k++) { + polygon->addPoint (k+off_set); + } + polygon->addPoint (off_set); + + return polygon; +} + + +} // end namespace GEOLIB diff --git a/GeoLib/Polygon.h b/GeoLib/Polygon.h new file mode 100644 index 0000000000000000000000000000000000000000..f341407183972c50bc478a83118f722b3972af64 --- /dev/null +++ b/GeoLib/Polygon.h @@ -0,0 +1,104 @@ +/* + * Polygon.h + * + * Created on: Jun 21, 2010 + * Author: TF + */ + +#ifndef POLYGON_H_ +#define POLYGON_H_ + +// STL +#include <list> + +// GEOLIB +#include "AxisAlignedBoundingBox.h" +#include "Polyline.h" + +namespace GEOLIB { + +/** + * \ingroup GEOLIB + */ + +/** + * edge classification + */ +class EdgeType { + public: + enum value { + TOUCHING, //!< TOUCHING + CROSSING, //!< CROSSING + INESSENTIAL//!< INESSENTIAL + }; +}; + +/** + * + */ +class Polygon : public Polyline +{ +public: + /** + * constructor checks if the given polyline is closed, + * and assures that the orientation is clock wise. + * @param ply closed Polyline + * @param init if true, check if polyline is closed, calculate bounding box + * @return + */ + Polygon(const Polyline &ply, bool init = true); + + Polygon (const std::vector<Point*>& pnt_vec); + + virtual ~Polygon(); + + /** + * + * @return + */ + bool initialise (); + + /** + * Method checks if the given point is inside the polygon. + * The method requires that the polygon has clock wise orientation. + * @param pnt the Point + * @return if point is inside the polygon true, else false + */ + bool isPntInPolygon (const GEOLIB::Point& pnt) const; + /** + * wrapper for method isPntInPolygon (const GEOLIB::Point&) + * @param x x coordinate of point + * @param y y coordinate of point + * @param z z coordinate of point + * @return if point is inside the polygon true, else false + */ + bool isPntInPolygon (double x, double y, double z) const; + bool isPolylineInPolygon (const Polyline& ply) const; + GEOLIB::Point* getIntersectionPointPolygonLine (GEOLIB::Point const & a, GEOLIB::Point const & b) const; + void computeListOfSimplePolygons (); + const std::list<Polygon*>& getListOfSimplePolygons (); + +private: + /** + * get the type of edge with respect to the given point (2d method!) + * @param k number of line segment + * @param pnt point that is edge type computed for + * @return a value of enum EdgeType + */ + EdgeType::value getEdgeType (size_t k, GEOLIB::Point const & pnt) const; + + void calculateAxisAlignedBoundingBox (); + void ensureCWOrientation (); + + void splitPolygonAtIntersection (std::list<Polygon*>::iterator polygon_it); + void splitPolygonAtPoint (std::list<Polygon*>::iterator polygon_it); + std::list<Polygon*> _simple_polygon_list; + AABB _aabb; +}; + +GEOLIB::Polygon* createPolygonFromCircle (GEOLIB::Point const& middle_pnt, double radius, + std::vector<GEOLIB::Point*> & pnts, size_t resolution = 12); + +} // end namespace GEOLIB + +#endif /* POLYGON_H_ */ diff --git a/GeoLib/Polyline.cpp b/GeoLib/Polyline.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0176824553cd42d1fea7c1e14682472db9b72687 --- /dev/null +++ b/GeoLib/Polyline.cpp @@ -0,0 +1,261 @@ +/* + * Polyline.cpp + * + * Created on: Jun 21, 2010 + * Author: TF + */ + +// Base +#include "swap.h" + +#include "Polyline.h" + +namespace GEOLIB { + +Polyline::Polyline(const std::vector<Point*>& pnt_vec) : + GeoObject(), _ply_pnts(pnt_vec) +{ + _length.push_back (0.0); +} + +Polyline::Polyline(const Polyline& ply) : + GeoObject(), _ply_pnts (ply._ply_pnts) +{ + for (size_t k(0); k<ply.getNumberOfPoints(); ++k) { + _ply_pnt_ids.push_back (ply.getPointID (k)); + } + + if (ply.getNumberOfPoints() > 0) { + for (size_t k(0); k<ply.getNumberOfPoints(); ++k) { + _length.push_back (ply.getLength (k)); + } + } +} + +void Polyline::write(std::ostream &os) const +{ + size_t size(_ply_pnt_ids.size()); + for (size_t k(0); k < size; k++) { + os << *(_ply_pnts[_ply_pnt_ids[k]]) << std::endl; + } +} + +void Polyline::addPoint(size_t point_id) +{ + assert(point_id < _ply_pnts.size()); + size_t n_pnts (_ply_pnt_ids.size()); + _ply_pnt_ids.push_back(point_id); + + if (n_pnts > 0) { + double act_dist (sqrt(MathLib::sqrDist (_ply_pnts[_ply_pnt_ids[n_pnts-1]], _ply_pnts[point_id]))); + double dist_until_now (0.0); + if (n_pnts > 1) + dist_until_now = _length[n_pnts - 1]; + + _length.push_back (dist_until_now + act_dist); + } +} + +size_t Polyline::getNumberOfPoints() const +{ + return _ply_pnt_ids.size(); +} + +bool Polyline::isClosed() const +{ + if (_ply_pnt_ids.front() == _ply_pnt_ids.back()) + return true; + else + return false; +} + +size_t Polyline::getPointID(size_t i) const +{ + assert(i < _ply_pnt_ids.size()); + return _ply_pnt_ids[i]; +} + +void Polyline::setPointID(size_t idx, size_t id) +{ + assert(idx < _ply_pnt_ids.size()); + _ply_pnt_ids[idx] = id; +} + +const Point* Polyline::operator[](size_t i) const +{ + assert(i < _ply_pnt_ids.size()); + return _ply_pnts[_ply_pnt_ids[i]]; +} + +const Point* Polyline::getPoint(size_t i) const +{ + assert(i < _ply_pnt_ids.size()); + return _ply_pnts[_ply_pnt_ids[i]]; +} + +std::vector<Point*> const& Polyline::getPointsVec () const +{ + return _ply_pnts; +} + +double Polyline::getLength (size_t k) const +{ + assert(k < _length.size()); + return _length[k]; +} + +const std::vector<double>& Polyline::getLengthVec () const +{ + return _length; +} + + +Polyline* Polyline::constructPolylineFromSegments(const std::vector<Polyline*> &ply_vec, double prox) +{ + size_t nLines = ply_vec.size(); + + Polyline* new_ply = new Polyline(*ply_vec[0]); + std::vector<GEOLIB::Point*> pnt_vec(new_ply->getPointsVec()); + + std::vector<Polyline*> local_ply_vec; + for (size_t i = 1; i < nLines; i++) { + local_ply_vec.push_back(ply_vec[i]); + } + + while (!local_ply_vec.empty()) { + bool ply_found(false); + prox *= prox; // square distance once to save time later + for (std::vector<Polyline*>::iterator it=local_ply_vec.begin(); it!=local_ply_vec.end(); ++it) + { + if (pnt_vec == (*it)->getPointsVec()) + { + size_t nPoints((*it)->getNumberOfPoints()); + + //if (new_ply->getPointID(0) == (*it)->getPointID(0)) + if (pointsAreIdentical(pnt_vec, new_ply->getPointID(0), (*it)->getPointID(0), prox)) + { + Polyline* tmp = new Polyline((*it)->getPointsVec()); + for (size_t k = 0; k < nPoints; k++) + tmp->addPoint((*it)->getPointID(nPoints - k - 1)); + + size_t new_ply_size(new_ply->getNumberOfPoints()); + for (size_t k = 1; k < new_ply_size; k++) + tmp->addPoint(new_ply->getPointID(k)); + delete new_ply; + new_ply = tmp; + ply_found = true; + } + //else if (new_ply->getPointID(0) == (*it)->getPointID(nPoints-1)) + else if (pointsAreIdentical(pnt_vec, new_ply->getPointID(0), (*it)->getPointID(nPoints-1), prox)) + { + Polyline* tmp = new Polyline(**it); + size_t new_ply_size(new_ply->getNumberOfPoints()); + for (size_t k = 1; k < new_ply_size; k++) + tmp->addPoint(new_ply->getPointID(k)); + delete new_ply; + new_ply = tmp; + ply_found = true; + } + //else if (new_ply->getPointID(new_ply->getNumberOfPoints()-1) == (*it)->getPointID(0)) + else if (pointsAreIdentical(pnt_vec, new_ply->getPointID(new_ply->getNumberOfPoints()-1), (*it)->getPointID(0), prox)) + { + for (size_t k=1; k<nPoints; k++) + new_ply->addPoint((*it)->getPointID(k)); + ply_found = true; + } + //else if (new_ply->getPointID(new_ply->getNumberOfPoints()-1) == (*it)->getPointID(nPoints-1)) + else if (pointsAreIdentical(pnt_vec, new_ply->getPointID(new_ply->getNumberOfPoints()-1), (*it)->getPointID(nPoints-1), prox)) + { + for (size_t k=1; k<nPoints; k++) + new_ply->addPoint((*it)->getPointID(nPoints-k-1)); + ply_found = true; + } + if (ply_found) { + local_ply_vec.erase(it); + break; + } + } else + std::cout + << "Error in Polyline::contructPolylineFromSegments() - Line segments use different point vectors..." + << std::endl; + } + + if (!ply_found) { + std::cout + << "Error in Polyline::contructPolylineFromSegments() - Not all segments are connected..." + << std::endl; + new_ply = NULL; + break; + } + } + return new_ply; +} + +bool Polyline::pointsAreIdentical(const std::vector<Point*> &pnt_vec, size_t i, size_t j, double prox) +{ + if (i==j) return true; + return (MathLib::checkDistance( *pnt_vec[i], *pnt_vec[j], prox )); +} + +Polyline* Polyline::closePolyline(const Polyline& ply) +{ + if (ply.getNumberOfPoints()>2) + { + Polyline* new_ply = new Polyline(ply); + if (ply.isClosed()) return new_ply; + new_ply->addPoint(new_ply->getPointID(0)); + return new_ply; + } + std::cout << "Error in Polyline::closePolyline() - Input polyline needs to be composed of at least three points..." << std::endl; + return NULL; +} + +Location::type Polyline::getLocationOfPoint (size_t k, GEOLIB::Point const & pnt) const +{ + assert (k<_ply_pnt_ids.size()-1); + + GEOLIB::Point const& source (*(_ply_pnts[_ply_pnt_ids[k]])); + GEOLIB::Point const& dest (*(_ply_pnts[_ply_pnt_ids[k+1]])); + GEOLIB::Point a (dest[0]-source[0], dest[1]-source[1], dest[2]-source[2]); // vector + GEOLIB::Point b (pnt[0]-source[0], pnt[1]-source[1], pnt[2]-source[2]); // vector + + double det_2x2 (a[0]*b[1] - a[1]*b[0]); + + if (det_2x2 > std::numeric_limits<double>::epsilon()) return Location::LEFT; + if (std::numeric_limits<double>::epsilon() < fabs(det_2x2)) return Location::RIGHT; + if (a[0]*b[0] < 0.0 || a[1]*b[1] < 0.0) return Location::BEHIND; + if (MathLib::sqrNrm2(&a) < MathLib::sqrNrm2(&b)) return Location::BEYOND; + if (MathLib::sqrDist (&pnt, _ply_pnts[_ply_pnt_ids[k]]) < sqrt(std::numeric_limits<double>::min())) + return Location::SOURCE; + if (MathLib::sqrDist (&pnt, _ply_pnts[_ply_pnt_ids[k+1]]) < sqrt(std::numeric_limits<double>::min())) + return Location::DESTINATION; + return Location::BETWEEN; +} + +std::ostream& operator<< (std::ostream &os, const Polyline &pl) +{ + pl.write (os); + return os; +} + +bool containsEdge (const Polyline& ply, size_t id0, size_t id1) +{ + if (id0 == id1) { + std::cerr << "no valid edge id0 == id1 == " << id0 << std::endl; + return false; + } + if (id0 > id1) BASELIB::swap (id0,id1); + const size_t n (ply.getNumberOfPoints() - 1); + for (size_t k(0); k<n; k++) { + size_t ply_pnt0 (ply.getPointID (k)); + size_t ply_pnt1 (ply.getPointID (k+1)); + if (ply_pnt0 > ply_pnt1) + BASELIB::swap (ply_pnt0, ply_pnt1); + if (ply_pnt0 == id0 && ply_pnt1 == id1) + return true; + } + return false; +} + + +} // end namespace GEOLIB diff --git a/GeoLib/Polyline.h b/GeoLib/Polyline.h new file mode 100644 index 0000000000000000000000000000000000000000..6862c22ff7b30fa5e8ad87d8501e163f6c3b9d67 --- /dev/null +++ b/GeoLib/Polyline.h @@ -0,0 +1,155 @@ +/* + * PolyLine.h + * + * Created on: Jan 14, 2010 + * Author: TF + */ + +#ifndef POLYLINE_H_ +#define POLYLINE_H_ + +// GEOLIB +#include "GeoObject.h" +#include "Point.h" + +// MathLib +#include "MathTools.h" + +#include <vector> +#include <cmath> + +namespace GEOLIB { + +class Location { +public: + enum type { + LEFT, + RIGHT, + BEYOND, + BEHIND, + BETWEEN, + SOURCE, + DESTINATION + }; +}; + +/** + * \ingroup GEOLIB + * + * \brief Class Polyline consists mainly of a reference to a point vector and + * a vector that stores the indices in the point vector. + * A polyline consists of at least one line segment. The polyline is specified by the points + * of the line segments. The class Polyline stores the position of pointers to the points in the + * m_ply_pnt_ids vector. + * */ +class Polyline : public GeoObject +{ +public: + /** constructor + * \param pnt_vec a reference to the point vector + */ + Polyline(const std::vector<Point*>& pnt_vec); + /** + * Copy constructor + * @param ply Polyline + */ + Polyline (const Polyline& ply); + + virtual ~Polyline() {} + + /** write the points to the stream */ + void write(std::ostream &os) const; + + /** adds a new pointer to a point to the polyline */ + void addPoint(size_t pos); + + /** + * Closes a polyline by adding a line sement that connects start- and end-point. + * \param ply A Polyline containing at least three points. + * \result A polygon. + */ + static Polyline* closePolyline(const Polyline& ply); + + /// Constructs one polyline from a vector of connected polylines. + /// All polylines in this vector need to reference the same point vector. + static Polyline* constructPolylineFromSegments(const std::vector<Polyline*> &ply_vec, double prox = 0.0); + + /** + * returns the number of points, + * the number of segments is about one smaller + * */ + size_t getNumberOfPoints() const; + + /** returns true if the polyline is closed */ + bool isClosed() const; + + /** + * returns the index of the i-th polyline point + * in the point vector + */ + size_t getPointID(size_t i) const; + + /** + * Changes a point index for one point in a line + * @param idx Index of point in line + * @param id ID of point in PointVec object + */ + void setPointID(size_t idx, size_t id); + + /** \brief const access operator for the access to the i-th point of the polyline. + */ + const Point* operator[](size_t i) const; + + /** + * \brief returns the i-th point contained in the polyline + * */ + const Point* getPoint(size_t i) const; + + std::vector<Point*> const& getPointsVec () const; + + /** + * returns the length of the polyline until the k-th line segment + * @param k the k-th line segment + * @return the length of the polyline until the k-th line segment + */ + double getLength (size_t k) const; + + /** + * get the complete length vector + * @return the length vector of the polyline + */ + const std::vector<double>& getLengthVec () const; + +protected: + /** + * 2D method - ignores z coordinate. It calculates the location + * of the point relative to the k-th line segment of the polyline. + * (literatur reference: + * Computational Geometry and Computer Graphics in C++; Michael J. Laszlo) + * @param k the number of line segment + * @param pnt the point + * @return a value of enum LOCATION + */ + Location::type getLocationOfPoint (size_t k, GEOLIB::Point const & pnt) const; + + static bool pointsAreIdentical(const std::vector<Point*> &pnt_vec, size_t i, size_t j, double prox); + + + /** a reference to the vector of pointers to the geometric points */ + const std::vector<Point*> &_ply_pnts; + /** position of pointers to the geometric points */ + std::vector<size_t> _ply_pnt_ids; + /** + * the k-th element of the vector contains the length of the polyline until the k-th segment + */ + std::vector<double> _length; +}; + +/** overload the output operator for class Polyline */ +std::ostream& operator<< (std::ostream &os, const Polyline &pl); + +bool containsEdge (const Polyline& ply, size_t id0, size_t id1); + +} // end namespace + +#endif /* POLYLINE_H_ */ diff --git a/GeoLib/PolylineVec.h b/GeoLib/PolylineVec.h new file mode 100644 index 0000000000000000000000000000000000000000..bb97c68c5ca583c55f7ad24d61546e9aa985e6c9 --- /dev/null +++ b/GeoLib/PolylineVec.h @@ -0,0 +1,27 @@ +/* + * PolylineVec.h + * + * Created on: Feb 9, 2010 + * Author: TF + */ + +#ifndef POLYLINEVEC_H_ +#define POLYLINEVEC_H_ + +#include "TemplateVec.h" +#include "Polyline.h" + +namespace GEOLIB { + +/** + * \ingroup GEOLIB + * + * \brief class PolylineVec encapsulate a std::vector of Polylines + * additional one can give the vector of polylines a name + * */ + +typedef TemplateVec<Polyline> PolylineVec; + +} // end namespace + +#endif /* POLYLINEVEC_H_ */ diff --git a/GeoLib/ProjectData.cpp b/GeoLib/ProjectData.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d668fd46726fe7e7a47b207316b2689c28113143 --- /dev/null +++ b/GeoLib/ProjectData.cpp @@ -0,0 +1,148 @@ +/** + * \file ProjectData.cpp + * 25/08/2010 KR Initial implementation + */ + +#include "ProjectData.h" +#include "StringTools.h" + + +ProjectData::ProjectData() +//: _geoObjects () +{} + +ProjectData::~ProjectData() +{ + delete _geoObjects; + for (std::map<std::string, MeshLib::CFEMesh*>::iterator it = _msh_vec.begin(); it != _msh_vec.end(); ++it) + { + delete it->second; + } + size_t nCond (_cond_vec.size()); + for (size_t i=0; i<nCond; i++) + { + delete _cond_vec[i]; + } +} + +void ProjectData::addMesh(MeshLib::CFEMesh* mesh, std::string &name) +{ + isUniqueMeshName(name); + _msh_vec[name] = mesh; +}; + +const MeshLib::CFEMesh* ProjectData::getMesh(const std::string &name) const +{ + return _msh_vec.find(name)->second; +} + +bool ProjectData::removeMesh(const std::string &name) +{ + delete _msh_vec[name]; + size_t result = _msh_vec.erase(name); + return (result>0); +} + +void ProjectData::addCondition(FEMCondition* cond) +{ + _cond_vec.push_back(cond); +}; + +void ProjectData::addConditions(std::vector<FEMCondition*> conds) +{ + for (size_t i=0; i<conds.size(); i++) + _cond_vec.push_back(conds[i]); +}; + +const FEMCondition* ProjectData::getCondition(const std::string &geo_name, GEOLIB::GEOTYPE type, const std::string &cond_name) const +{ + for (std::vector<FEMCondition*>::const_iterator it = _cond_vec.begin(); it != _cond_vec.end(); ++it) + { + if ((*it)->getAssociatedGeometryName().compare(geo_name) == 0) + { + if ( ((*it)->getGeoName().compare(cond_name)==0) && ((*it)->getGeoType()==type) ) + return *it; + } + } + std::cout << "Error in ProjectData::getCondition() - No condition found with name \"" << cond_name << "\"..." << std::endl; + return NULL; +} + +const std::vector<FEMCondition*> ProjectData::getConditions(const std::string &geo_name, FEMCondition::CondType type) const +{ + std::vector<FEMCondition*> conds; + for (std::vector<FEMCondition*>::const_iterator it = _cond_vec.begin(); it != _cond_vec.end(); ++it) + { + if ((*it)->getAssociatedGeometryName().compare(geo_name) == 0) + { + if ( (type == FEMCondition::UNSPECIFIED) || ((*it)->getCondType() == type) ) + conds.push_back(*it); + } + } + return conds; +} + +bool ProjectData::removeCondition(const std::string &geo_name, GEOLIB::GEOTYPE type, const std::string &cond_name) +{ + for (std::vector<FEMCondition*>::iterator it = _cond_vec.begin(); it != _cond_vec.end(); ++it) + { + if ((*it)->getAssociatedGeometryName().compare(geo_name) == 0) + { + if ( ((*it)->getGeoName().compare(cond_name)==0) && ((*it)->getGeoType()==type) ) + { + delete *it; + _cond_vec.erase(it); + return true; + } + } + } + std::cout << "Error in ProjectData::getCondition() - No condition found with name \"" << cond_name << "\"..." << std::endl; + return false; +} + +void ProjectData::removeConditions(const std::string &geo_name, FEMCondition::CondType type) +{ + for (std::vector<FEMCondition*>::iterator it = _cond_vec.begin(); it != _cond_vec.end();) + { + if ( ((*it)->getAssociatedGeometryName().compare(geo_name) == 0) + && ( (type == FEMCondition::UNSPECIFIED) || ((*it)->getCondType() == type) )) + { + delete *it; + it = _cond_vec.erase(it); + } + else ++it; + } +} + +bool ProjectData::isUniqueMeshName(std::string &name) +{ + int count(0); + bool isUnique(false); + std::string cpName; + + while (!isUnique) + { + isUnique = true; + cpName = name; + + count++; + // If the original name already exists we start to add numbers to name for + // as long as it takes to make the name unique. + if (count>1) cpName = cpName + "-" + number2str(count); + + for (std::map<std::string, MeshLib::CFEMesh*>::iterator it = _msh_vec.begin(); it != _msh_vec.end(); ++it) + { + if ( cpName.compare(it->first) == 0 ) isUnique = false; + } + } + + // At this point cpName is a unique name and isUnique is true. + // If cpName is not the original name, "name" is changed and isUnique is set to false, + // indicating that a vector with the original name already exists. + if (count>1) + { + isUnique = false; + name = cpName; + } + return isUnique; +} diff --git a/GeoLib/ProjectData.h b/GeoLib/ProjectData.h new file mode 100644 index 0000000000000000000000000000000000000000..f3887909200f6ca320836a75266be93538602e6b --- /dev/null +++ b/GeoLib/ProjectData.h @@ -0,0 +1,75 @@ +/** + * \file ProjectData.h + * 25/08/2010 KR Initial implementation + */ + +#ifndef PROJECTDATA_H_ +#define PROJECTDATA_H_ + +#include "GEOObjects.h" +#include "msh_mesh.h" +#include "FEMCondition.h" + + +/** + * The ProjectData Object contains all the data needed for a certain project, i.e. all + * geometric data (stored in a GEOObjects-object), all the meshes, FEM Conditions (i.e. + * Boundary Conditions, Source Terms and Initial Conditions), etc. + * ProjectData does not administrate any of the objects, it is just a "container class" + * to store them all in one place. + * For each class of object stored in this container exists an add-, get- and remove-method. + * + * \sa GEOModels, FEMCondition + */ +class ProjectData +{ +public: + ProjectData(); + virtual ~ProjectData(); + + // Returns the GEOObjects containing all points, polylines and surfaces + GEOLIB::GEOObjects* getGEOObjects() { return _geoObjects; }; + + // Returns the GEOObjects containing all points, polylines and surfaces + void setGEOObjects(GEOLIB::GEOObjects* geo_objects) { _geoObjects = geo_objects; }; + + /// Adds a new mesh + virtual void addMesh(MeshLib::CFEMesh* mesh, std::string &name); + + /// Returns the mesh with the given name. + const MeshLib::CFEMesh* getMesh(const std::string &name) const; + + /// Returns all the meshes with their respective names + const std::map<std::string, MeshLib::CFEMesh*>& getMeshObjects() const { return _msh_vec; }; + + /// Removes the mesh with the given name. + virtual bool removeMesh(const std::string &name); + + /// Adds a new FEM Condition + virtual void addCondition(FEMCondition* cond); + + /// Adds a new FEM Condition + virtual void addConditions(std::vector<FEMCondition*> conds); + + /// Returns the FEM Condition set on a GeoObject with the given name and type from a certain geometry. + const FEMCondition* getCondition(const std::string &geo_name, GEOLIB::GEOTYPE type, const std::string &cond_name) const; + + /// Returns all FEM Conditions with the given type from a certain geometry. + const std::vector<FEMCondition*> getConditions(const std::string &geo_name, FEMCondition::CondType type = FEMCondition::UNSPECIFIED) const; + + /// Removes the FEM Condition set on a GeoObject with the given name and type from a certain geometry. + virtual bool removeCondition(const std::string &geo_name, GEOLIB::GEOTYPE type, const std::string &cond_name); + + /// Removes all FEM Conditions with the given type from a certain geometry + virtual void removeConditions(const std::string &geo_name, FEMCondition::CondType type = FEMCondition::UNSPECIFIED); + + /// Checks if the name of the mesh is already exists, if so it generates a unique name. + bool isUniqueMeshName(std::string &name); + +private: + GEOLIB::GEOObjects* _geoObjects; + std::map<std::string, MeshLib::CFEMesh*> _msh_vec; + std::vector<FEMCondition*> _cond_vec; +}; + +#endif //PROJECTDATA_H_ diff --git a/GeoLib/PropertyBounds.h b/GeoLib/PropertyBounds.h new file mode 100644 index 0000000000000000000000000000000000000000..9615d0c7df9c968dacf36aa2a9abea6fc0101e06 --- /dev/null +++ b/GeoLib/PropertyBounds.h @@ -0,0 +1,29 @@ +/** + * \file PropertyBounds.h + * 18/01/2010 KR Initial implementation + */ + +#ifndef PROPERTYBOUNDS_H +#define PROPERTYBOUNDS_H + +#include <string> + +class PropertyBounds +{ +public: + PropertyBounds(std::string pname, double minVal, double maxVal ) : _name(pname), _minVal(minVal), _maxVal(maxVal) {} + + std::string getName() const { return _name; } + double getMin() const { return _minVal; } + double getMax() const { return _maxVal; } + + void setMin(double val) { _minVal = val; } + void setMax(double val) { _maxVal = val; } + +private: + std::string _name; + double _minVal; + double _maxVal; +}; + +#endif //PROPERTYBOUNDS_H diff --git a/GeoLib/QuadTree.h b/GeoLib/QuadTree.h new file mode 100644 index 0000000000000000000000000000000000000000..b13af3d4a7207bb661ed100348541605c418a1b2 --- /dev/null +++ b/GeoLib/QuadTree.h @@ -0,0 +1,508 @@ +/* + * QuadTree.h + * + * Created on: Nov 9, 2010 + * Author: TF + */ + +#ifndef QUADTREE_H_ +#define QUADTREE_H_ + +namespace GEOLIB { + +/** + * A quadtree is a rooted tree in which every internal + * node has four children. Every node corresponds to a square. + * (see Computational Geometry - Algorithms and Applications [Mark de Berg, + * Otfried Cheong, Marc van Kreveld, Mark Overmars] - Chapter 14) + * + * One can instantiate the class template with a point type and a value for + * the maximal number of points per node. The point-type have to provide + * the access to its coordinates via operator[] and for debugging + * purposes operator<<) + */ +template <typename POINT> class QuadTree { +public: + enum Quadrant { + NE = 0, //!< north east + NW, //!< north west + SW, //!< south west + SE //!< south east + }; + /** + * This is the constructor for class QuadTree. It takes two points + * (lower left and the upper right points). + * @param ll lower left point of the square + * @param ur upper right point of the square + */ + QuadTree(POINT const& ll, POINT const& ur, size_t max_points_per_node) : + _father (NULL), _ll (ll), _ur (ur), _depth (0), _is_leaf (true), + _max_points_per_node (max_points_per_node) + { + assert (_max_points_per_node > 0); + + // init childs + for (size_t k(0); k<4; k++) { + _childs[k] = NULL; + } + + if ((_ur[0] - _ll[0]) > (_ur[1] - _ll[1])) { + _ur[1] = _ll[1] + _ur[0] - _ll[0]; + } else { + _ur[0] = _ll[0] + _ur[1] - _ll[1]; + } +//#ifndef NDEBUG +// std::cerr << "lower left: " << _ll << ", upper right: " << _ur << ", depth " << _depth << std::endl; +//#endif + } + + /** + * destructor + */ + ~QuadTree() + { + if (_is_leaf) { + for (size_t k(0); k<4; k++) { + delete _childs[k]; + } + } + } + + /** + * This method adds the given point to the quadtree. If necessary, + * the quadtree will be extended. + * @param pnt the point + * @return If the point can be inserted the method returns true, else false. + */ + bool addPoint (POINT * pnt) + { + if ((*pnt)[0] < _ll[0]) return false; + if ((*pnt)[0] > _ur[0]) return false; + if ((*pnt)[1] < _ll[1]) return false; + if ((*pnt)[1] > _ur[1]) return false; + + if (!_is_leaf) { + for (size_t k(0); k<4; k++) { + if (_childs[k]->addPoint (pnt)) + return true; + } + } + + // check if point is already in quadtree + bool pnt_in_quadtree (false); + double equal_pnt_dist (MathLib::fastpow(2, _depth) * fabs(_ll[0] - _ur[0]) * 1e-6); + for (size_t k(0); k<_pnts.size() && !pnt_in_quadtree; k++) { + const double sqr_dist (MathLib::sqrDist(_pnts[k]->getData(), pnt->getData())); + if (sqr_dist < equal_pnt_dist) { + pnt_in_quadtree = true; + } + } + if (!pnt_in_quadtree) { + _pnts.push_back (pnt); + } else { + return false; + } + + if (_pnts.size () > _max_points_per_node) { + splitNode (); + } + return true; + } + + /** + * This method balances the quadtree, i.e., it will be inserted nodes + * such that the depth between neighbored leafs is at most one. If you want + * to create a mesh (for instance with GMSH) you can use this method to + * improve the mesh quality. The balance method should be used after + * inserting all points. + */ + void balance () + { + std::list<QuadTree<POINT>*> leaf_list; + getLeafs (leaf_list); + + while (!leaf_list.empty()) { + QuadTree<POINT>* node (leaf_list.front()); + leaf_list.pop_front (); + + if (node->isLeaf()) { + if (needToRefine (node)) { + node->splitNode (); + leaf_list.push_back (node->getChild(NE)); + leaf_list.push_back (node->getChild(NW)); + leaf_list.push_back (node->getChild(SW)); + leaf_list.push_back (node->getChild(SE)); + + // check if north neighbor has to be refined + QuadTree<POINT>* north_neighbor (node->getNorthNeighbor()); + if (north_neighbor != NULL) { + if (north_neighbor->getDepth() < node->getDepth ()) { + if (north_neighbor->isLeaf()) { + leaf_list.push_back (north_neighbor); + } + } + } + + // check if west neighbor has to be refined + QuadTree<POINT>* west_neighbor (node->getWestNeighbor()); + if (west_neighbor != NULL) { + if (west_neighbor->getDepth() < node->getDepth ()) { + if (west_neighbor->isLeaf()) { + leaf_list.push_back (west_neighbor); + } + } + } + + // check if south neighbor has to be refined + QuadTree<POINT>* south_neighbor (node->getSouthNeighbor()); + if (south_neighbor != NULL) { + if (south_neighbor->getDepth() < node->getDepth ()) { + if (south_neighbor->isLeaf()) { + leaf_list.push_back (south_neighbor); + } + } + } + + // check if east neighbor has to be refined + QuadTree<POINT>* east_neighbor (node->getEastNeighbor()); + if (east_neighbor != NULL) { + if (east_neighbor->getDepth() < node->getDepth ()) { + if (east_neighbor->isLeaf()) { + leaf_list.push_back (east_neighbor); + } + } + } + } + } + } + } + + /** + * add all leafs of the quadtree to the list + * @param leaf_list list of leafs + */ + void getLeafs (std::list<QuadTree<POINT>*>& leaf_list) + { + if (_is_leaf) { + leaf_list.push_back (this); + } else { + for (size_t k(0); k<4; k++) { + _childs[k]->getLeafs (leaf_list); + } + } + } + + const std::vector<POINT*>& getPoints () const { return _pnts; } + + void getSquarePoints (POINT& ll, POINT& ur) const + { + ll = _ll; + ur = _ur; + } + + void getLeaf (const POINT& pnt, POINT& ll, POINT& ur) + { + if (this->isLeaf()) { + ll = _ll; + ur = _ur; + } else { + if (pnt[0] <= 0.5*(_ur[0]+_ll[0])) { // WEST + if (pnt[1] <= 0.5*(_ur[1]+_ll[1])) { // SOUTH + _childs[SW]->getLeaf (pnt, ll, ur); + } else { // NORTH + _childs[NW]->getLeaf (pnt, ll, ur); + } + } else { // EAST + if (pnt[1] <= 0.5*(_ur[1]+_ll[1])) { // SOUTH + _childs[SE]->getLeaf (pnt, ll, ur); + } else { // NORTH + _childs[NE]->getLeaf (pnt, ll, ur); + } + } + } + } + + void getQuadTree (std::vector<POINT*>& pnts, std::vector<GEOLIB::Polyline*>& plys) const + { + size_t pnt_pos (pnts.size()); + pnts.push_back (new POINT (_ll)); + pnts.push_back (new POINT (_ur[0], _ll[1], _ll[2])); + pnts.push_back (new POINT (_ur)); + pnts.push_back (new POINT (_ll[0], _ur[1], _ll[2])); + + if (_father == NULL) { + size_t ply_pos (plys.size()); + plys.push_back (new Polyline (pnts)); + for (size_t i(0); i<4; i++) + plys[ply_pos]->addPoint (pnt_pos+i); + plys[ply_pos]->addPoint (pnt_pos); + } + + if (! _is_leaf) { + for (size_t i(0); i<4; i++) { + _childs[i]->getQuadTree (pnts, plys); + } + } + } + + QuadTree<POINT> const * getFather () + { + return _father; + } + + QuadTree<POINT> const * getChild (Quadrant quadrant) const + { + return _childs[quadrant]; + } + + +private: + QuadTree<POINT> * getChild (Quadrant quadrant) + { + return _childs[quadrant]; + } + + bool isLeaf () const { return _is_leaf; } + + bool isChild (QuadTree<POINT> const * const tree, Quadrant quadrant) const + { + if (_childs[quadrant] == tree) return true; + return false; + } + + QuadTree<POINT>* getNorthNeighbor () const + { + if (this->_father == NULL) { // root of QuadTree + return NULL; + } + + if (this->_father->isChild (this, SW)) + return this->_father->getChild (NW); + if (this->_father->isChild (this, SE)) + return this->_father->getChild (NE); + + QuadTree<POINT>* north_neighbor (this->_father->getNorthNeighbor ()); + if (north_neighbor == NULL) + return NULL; + if (north_neighbor->isLeaf()) + return north_neighbor; + + if (this->_father->isChild (this, NW)) + return north_neighbor->getChild (SW); + else + return north_neighbor->getChild (SE); + } + + QuadTree<POINT>* getSouthNeighbor () const + { + if (this->_father == NULL) { // root of QuadTree + return NULL; + } + + if (this->_father->isChild (this, NW)) + return this->_father->getChild (SW); + if (this->_father->isChild (this, NE)) + return this->_father->getChild (SE); + + QuadTree<POINT>* south_neighbor (this->_father->getSouthNeighbor ()); + if (south_neighbor == NULL) + return NULL; + if (south_neighbor->isLeaf()) + return south_neighbor; + + if (this->_father->isChild (this, SW)) + return south_neighbor->getChild (NW); + else + return south_neighbor->getChild (NE); + } + + QuadTree<POINT>* getEastNeighbor () const + { + if (this->_father == NULL) { // root of QuadTree + return NULL; + } + + if (this->_father->isChild (this, NW)) + return this->_father->getChild (NE); + if (this->_father->isChild (this, SW)) + return this->_father->getChild (SE); + + QuadTree<POINT>* east_neighbor (this->_father->getEastNeighbor ()); + if (east_neighbor == NULL) + return NULL; + if (east_neighbor->isLeaf()) + return east_neighbor; + + if (this->_father->isChild (this, SE)) + return east_neighbor->getChild (SW); + else + return east_neighbor->getChild (NW); + } + + QuadTree<POINT>* getWestNeighbor () const + { + if (this->_father == NULL) { // root of QuadTree + return NULL; + } + + if (this->_father->isChild (this, NE)) + return this->_father->getChild (NW); + if (this->_father->isChild (this, SE)) + return this->_father->getChild (SW); + + QuadTree<POINT>* west_neighbor (this->_father->getWestNeighbor ()); + if (west_neighbor == NULL) + return NULL; + if (west_neighbor->isLeaf()) + return west_neighbor; + + if (this->_father->isChild (this, SW)) + return west_neighbor->getChild (SE); + else + return west_neighbor->getChild (NE); + } + + size_t getDepth () const { return _depth; } + + /** + * private constructor + * @param ll lower left point + * @param ur upper right point + * @param father father in the tree + * @param depth depth of the node + * @return + */ + QuadTree (POINT const& ll, POINT const& ur, QuadTree* father, size_t depth, size_t max_points_per_node) : + _father (father), _ll (ll), _ur (ur), _depth (depth), _is_leaf (true), + _max_points_per_node (max_points_per_node) + { + // init childs + for (size_t k(0); k<4; k++) { + _childs[k] = NULL; + } + +//#ifndef NDEBUG +// std::cerr << "lower left: " << _ll << ", upper right: " << _ur << ", depth: " << _depth << std::endl; +//#endif + } + + void splitNode () + { + // create childs + POINT mid_point(_ll); + mid_point[0] += (_ur[0] - _ll[0]) / 2.0; + mid_point[1] += (_ur[1] - _ll[1]) / 2.0; + _childs[0] = new QuadTree<POINT> (mid_point, _ur, this, _depth + 1, _max_points_per_node); // north east + POINT h_ll(mid_point), h_ur(mid_point); + h_ll[0] = _ll[0]; + h_ur[1] = _ur[1]; + _childs[1] = new QuadTree<POINT> (h_ll, h_ur, this, _depth + 1, _max_points_per_node); // north west + _childs[2] = new QuadTree<POINT> (_ll, mid_point, this, _depth + 1, _max_points_per_node); // south west + h_ll = _ll; + h_ll[0] = mid_point[0]; + h_ur = _ur; + h_ur[1] = mid_point[1]; + _childs[3] = new QuadTree<POINT> (h_ll, h_ur, this, _depth + 1, _max_points_per_node); // south east + + // distribute points to sub quadtrees + for (size_t j(0); j < _pnts.size(); j++) { + bool nfound(true); + for (size_t k(0); k < 4 && nfound; k++) { + if (_childs[k]->addPoint(_pnts[j])) { + nfound = false; + } + } + } + _pnts.clear(); + _is_leaf = false; + } + + bool needToRefine (QuadTree<POINT>* node) + { + QuadTree<POINT>* north_neighbor (node->getNorthNeighbor ()); + if (north_neighbor != NULL) { + if (north_neighbor->getDepth() == node->getDepth()) { + if (! north_neighbor->isLeaf ()) { + if (! (north_neighbor->getChild(SW))->isLeaf()) { + return true; + } + if (! (north_neighbor->getChild(SE))->isLeaf()) { + return true; + } + } + } + } + + QuadTree<POINT>* west_neighbor (node->getWestNeighbor ()); + if (west_neighbor != NULL) { + if (west_neighbor->getDepth() == node->getDepth()) { + if (! west_neighbor->isLeaf ()) { + if (! (west_neighbor->getChild(SE))->isLeaf()) { + return true; + } + if (! (west_neighbor->getChild(NE))->isLeaf()) { + return true; + } + } + } + } + + QuadTree<POINT>* south_neighbor (node->getSouthNeighbor ()); + if (south_neighbor != NULL) { + if (south_neighbor->getDepth() == node->getDepth()) { + if (!south_neighbor->isLeaf()) { + if (!(south_neighbor->getChild(NE))->isLeaf()) { + return true; + } + if (!(south_neighbor->getChild(NW))->isLeaf()) { + return true; + } + } + } + } + + QuadTree<POINT>* east_neighbor (node->getEastNeighbor ()); + if (east_neighbor != NULL) { + if (east_neighbor->getDepth() == node->getDepth()) { + if (! east_neighbor->isLeaf ()) { + if (! (east_neighbor->getChild(NW))->isLeaf()) { + return true; + } + if (! (east_neighbor->getChild(SW))->isLeaf()) { + return true; + } + } + } + } + return false; + } + + QuadTree<POINT>* _father; + /** + * childs are sorted: + * _childs[0] is north east child + * _childs[1] is north west child + * _childs[2] is south west child + * _childs[3] is south east child + */ + QuadTree<POINT>* _childs[4]; + /** + * lower left point of the square + */ + POINT _ll; + /** + * upper right point of the square + */ + POINT _ur; + size_t _depth; + std::vector<POINT *> _pnts; + bool _is_leaf; + /** + * maximum number of points per leaf + */ + const size_t _max_points_per_node; +}; + +} + +#endif /* QUADTREE_H_ */ diff --git a/GeoLib/Raster.cpp b/GeoLib/Raster.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ddf5005444ee498329fa5a94ac30bd66b9c45e6e --- /dev/null +++ b/GeoLib/Raster.cpp @@ -0,0 +1,66 @@ +/* + * Raster.cpp + * + * Created on: Sep 7, 2011 + * Author: TF + */ + +#include "Raster.h" + +namespace GEOLIB { + +Raster::Raster(double cell_size, double no_data_val) : + _cell_size(cell_size), _no_data_val(no_data_val) +{ +} + +void Raster::setCellSize(double cell_size) +{ + _cell_size = cell_size; +} + +void Raster::setNoDataVal (double no_data_val) +{ + _no_data_val = no_data_val; +} + +double* Raster::getRasterFromSurface(Surface const& sfc, size_t &n_x_pnts, size_t &n_y_pnts) const +{ + Point const& ll (sfc.getAABB().getMinPoint()); + Point const& ur (sfc.getAABB().getMaxPoint()); + + n_x_pnts = static_cast<size_t>(fabs(ur[0]-ll[0]) / _cell_size)+1; + n_y_pnts = static_cast<size_t>(fabs(ur[1]-ll[1]) / _cell_size)+1; + const size_t n_triangles (sfc.getNTriangles()); + double *z_vals (new double[n_x_pnts*n_y_pnts]); + if (!z_vals) { + std::cout << "DEBUG: CreateRaster::getRaster " << n_x_pnts << " x " << n_y_pnts << " to big" << std::endl; + } + size_t k(0); + + for (size_t r(0); r < n_x_pnts; r++) { + for (size_t c(0); c < n_y_pnts; c++) { + const double test_pnt[3] = { ll[0] + r*_cell_size, ll[1] + c*_cell_size, 0}; + for (k=0; k<n_triangles; k++) { + if (sfc[k]->containsPoint2D(test_pnt)) { + Triangle const * const tri (sfc[k]); + // compute coefficients c0, c1, c2 for the plane f(x,y) = c0 x + c1 y + c2 + double coeff[3] = {0.0, 0.0, 0.0}; + GEOLIB::getPlaneCoefficients(*tri, coeff); + z_vals[r*n_y_pnts+c] = coeff[0] * test_pnt[0] + coeff[1] * test_pnt[1] + coeff[2]; + break; + } + } + if (k==n_triangles) { + z_vals[r*n_y_pnts+c] = _no_data_val; + } + } + } + + return z_vals; +} + +Raster::~Raster() +{} + +} diff --git a/GeoLib/Raster.h b/GeoLib/Raster.h new file mode 100644 index 0000000000000000000000000000000000000000..a330638ca4a22c2ab0d023fcd5a569ab1ca4f7d7 --- /dev/null +++ b/GeoLib/Raster.h @@ -0,0 +1,29 @@ +/* + * Raster.h + * + * Created on: Sep 7, 2011 + * Author: TF + */ + +#ifndef RASTER_H_ +#define RASTER_H_ + +#include "Surface.h" + +namespace GEOLIB { + +class Raster { +public: + Raster(double cell_size=1, double no_data_val=9999); + void setCellSize(double cell_size); + void setNoDataVal (double no_data_val); + double* getRasterFromSurface (Surface const& sfc, size_t &n_x_pnts, size_t &n_y_pnts) const; + virtual ~Raster(); +private: + double _cell_size; + double _no_data_val; +}; + +} + +#endif /* RASTER_H_ */ diff --git a/GeoLib/SimplePolygonTree.cpp b/GeoLib/SimplePolygonTree.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c3454ac9a29ad31f7cf2ce87d5c3f8cefb366ddc --- /dev/null +++ b/GeoLib/SimplePolygonTree.cpp @@ -0,0 +1,183 @@ +/* + * SimplePolygonTree.cpp + * + * Created on: Jun 22, 2010 + * Author: TF + */ + +#include "SimplePolygonTree.h" + +namespace GEOLIB { + +SimplePolygonTree::SimplePolygonTree(const Polygon* polygon, SimplePolygonTree* parent) : + _node (polygon), _parent (parent) +{} + +SimplePolygonTree::~SimplePolygonTree() +{} + +const Polygon* SimplePolygonTree::getPolygon () const +{ + return _node; +} + +bool SimplePolygonTree::isPolygonInside (const SimplePolygonTree* polygon_hierarchy) const +{ + const Polygon* polygon (polygon_hierarchy->getPolygon()); + // check *all* points of polygon + size_t n_pnts_polygon (polygon->getNumberOfPoints() - 1), cnt(0); + for (size_t k(0); k<n_pnts_polygon && cnt == k; k++) { + if (_node->isPntInPolygon (*(polygon->getPoint(k)))) { + cnt++; + } + } + // all points of the given polygon are contained in the + if (cnt == n_pnts_polygon) return true; + else { + return false; + } +} + +void SimplePolygonTree::insertSimplePolygonTree (SimplePolygonTree* polygon_hierarchy) +{ + const Polygon* polygon (polygon_hierarchy->getPolygon()); + bool nfound (true); + for (std::list<SimplePolygonTree*>::const_iterator it (_childs.begin()); + it != _childs.end() && nfound; it++) + { + // check all points of polygon + size_t n_pnts_polygon (polygon->getNumberOfPoints()), cnt(0); + for (size_t k(0); k<n_pnts_polygon && cnt == k; k++) { + if (((*it)->getPolygon())->isPntInPolygon (*(polygon->getPoint(k)))) + cnt++; + } + // all points of the given polygon are contained in the current polygon + if (cnt == n_pnts_polygon) { + (*it)->insertSimplePolygonTree (polygon_hierarchy); + nfound = false; + } + } + if (nfound) + _childs.push_back (polygon_hierarchy); +} + +bool SimplePolygonTree::isGeoObjInside (const GeoObject* geo_obj) const +{ + if (dynamic_cast<const Point*>(geo_obj)) + return _node->isPntInPolygon (*(dynamic_cast<const Point*>(geo_obj))); + + if (dynamic_cast<const Polyline*>(geo_obj)) + return isPolylineInside (dynamic_cast<const Polyline*>(geo_obj)); + + return false; +} + +bool SimplePolygonTree::isPolylineInside (const Polyline* ply) const +{ + // check *all* points of polyline + size_t n_pnts_polyline (ply->getNumberOfPoints() - 1), cnt(0); + for (size_t k(0); k<n_pnts_polyline && cnt == k; k++) { + if (_node->isPntInPolygon (*(ply->getPoint(k)))) { + cnt++; + } + } + // all points of the given polyline are contained in the polygon + if (cnt == n_pnts_polyline) return true; + + return false; +} + +void SimplePolygonTree::insertGeoObj (const GeoObject* geo_obj) +{ + // check if the geo object is contained in a child of this node + bool nfound (true); + for (std::list<SimplePolygonTree*>::const_iterator it (_childs.begin()); + it != _childs.end() && nfound; it++) + { + // check Point + if (dynamic_cast<const Point*>(geo_obj)) { + if (((*it)->getPolygon())->isPntInPolygon (*(dynamic_cast<const Point*>(geo_obj)))) { + (*it)->insertGeoObj (geo_obj); + nfound = false; + } + } + // check Polyline + if (nfound && dynamic_cast<const Polyline*>(geo_obj)) { + const Polyline* ply (dynamic_cast<const Polyline*>(geo_obj)); + size_t n_pnts_polyline (ply->getNumberOfPoints()), cnt(0); + // check all points of Polyline + for (size_t k(0); k<n_pnts_polyline && cnt == k; k++) { + if (((*it)->getPolygon())->isPntInPolygon (*(ply->getPoint(k)))) + cnt++; + } + // all points of the given polygon are contained in the current polygon + if (cnt == n_pnts_polyline) { + (*it)->insertGeoObj (geo_obj); + nfound = false; + } + } + } + + if (nfound) { + _geo_objs.push_back (geo_obj); + } + +} + +//void SimplePolygonTree::visitAndProcessNodes (FileIO::GMSHInterface& gmsh_io) +//{ +// if (getLevel() == 0) { +// gmsh_io.writeGMSHPolygon (*_node); +// +// std::list<SimplePolygonTree*>::iterator it (_childs.begin()); +// while (it != _childs.end()) { +// (*it)->_visitAndProcessNodes (gmsh_io); +// it++; +// } +// gmsh_io.writePlaneSurface (); +// } +//} + +//void SimplePolygonTree::_visitAndProcessNodes (FileIO::GMSHInterface& gmsh_io) +//{ +// gmsh_io.writeGMSHPolygon (*_node); +// +// std::list<SimplePolygonTree*>::iterator it (_childs.begin()); +// while (it != _childs.end()) { +// (*it)->_visitAndProcessNodes (gmsh_io); +// it++; +// } +//} + +size_t SimplePolygonTree::getLevel () const +{ + if (_parent == NULL) return 0; + else return 1+_parent->getLevel (); +} + +void createPolygonTree (std::list<SimplePolygonTree*>& list_of_simple_polygon_hierarchies) +{ + std::list<SimplePolygonTree*>::iterator it0 (list_of_simple_polygon_hierarchies.begin()), it1; + while (it0 != list_of_simple_polygon_hierarchies.end()) { + it1 = it0; + it1++; + while (it1 != list_of_simple_polygon_hierarchies.end()) { + if ((*it0)->isPolygonInside (*it1)) { + (*it0)->insertSimplePolygonTree (*it1); + it1 = list_of_simple_polygon_hierarchies.erase (it1); + } else { + if ((*it1)->isPolygonInside (*it0)) { + (*it1)->insertSimplePolygonTree (*it0); + (*it1)->insertSimplePolygonTree (*it0); + it0 = list_of_simple_polygon_hierarchies.erase (it0); + } + + it1++; + } + } + it0++; + } +} + + +} // end namespace GEOLIB diff --git a/GeoLib/SimplePolygonTree.h b/GeoLib/SimplePolygonTree.h new file mode 100644 index 0000000000000000000000000000000000000000..688364df5f75f1753d988cdb7370a95ae20f2c35 --- /dev/null +++ b/GeoLib/SimplePolygonTree.h @@ -0,0 +1,57 @@ +/* + * SimplePolygonTree.h + * + * Created on: Jun 22, 2010 + * Author: TF + */ + +#ifndef SIMPLEPOLYGONTREE_H_ +#define SIMPLEPOLYGONTREE_H_ + +#include "Polygon.h" +// FileIO +#include "MeshIO/GMSHInterface.h" + +namespace GEOLIB { + +/** + * \brief This class computes and stores the topological relations between + * polygons and geometric objects like Point and Polyline. + * + * It is used to generate a proper input file for gmsh. + */ +class SimplePolygonTree { +public: + SimplePolygonTree(const Polygon* polygon, SimplePolygonTree* parent = NULL); + virtual ~SimplePolygonTree(); + + const Polygon* getPolygon () const; + const std::list<SimplePolygonTree*>& getChilds() const; + const std::list<GeoObject*>& getGeoObjects () const; + size_t getLevel () const; + + bool isPolygonInside (const SimplePolygonTree* polygon_tree) const; + void insertSimplePolygonTree (SimplePolygonTree* polygon_tree); +// void visitAndProcessNodes (FileIO::GMSHInterface& gmsh_io); + + bool isGeoObjInside (const GeoObject* geo_obj) const; + void insertGeoObj (const GeoObject* geo_obj); + +private: + bool isPolylineInside (const Polyline* ply) const; +// void _visitAndProcessNodes (FileIO::GMSHInterface& gmsh_io); + const Polygon* _node; + SimplePolygonTree* _parent; + std::list<SimplePolygonTree*> _childs; + std::list<const GeoObject*> _geo_objs; +}; + +/** + * creates from a list of simple polygons a list + * @param list_of_simple_polygon_trees + */ +void createPolygonTree (std::list<SimplePolygonTree*>& list_of_simple_polygon_trees); + +} + +#endif /* SIMPLEPOLYGONTREE_H_ */ diff --git a/GeoLib/Station.cpp b/GeoLib/Station.cpp new file mode 100644 index 0000000000000000000000000000000000000000..81a67b624b815be342c2307f0f16a84fddb984ff --- /dev/null +++ b/GeoLib/Station.cpp @@ -0,0 +1,380 @@ +/** + * \file Station.cpp + * KR Initial implementation + */ + +#include <cstdlib> +#include <fstream> +#include <iomanip> +#include <cmath> +// Base +#include "StringTools.h" +#include "DateTools.h" +// GEOLIB +#include "Station.h" + + +namespace GEOLIB { + +Station::Station(double x, double y, double z, std::string name, Color* const color) : + Point (x,y,z), _name(name), _type(Station::STATION), _color(color) +{ + addProperty("x", &getX, &Station::setX); + addProperty("y", &getY, &Station::setY); + addProperty("z", &getZ, &Station::setZ); +} + +Station::Station(Point* coords, std::string name, Color* const color) : + Point (*coords), _name(name), _type(Station::STATION), _color(color) +{ + addProperty("x", &getX, &Station::setX); + addProperty("y", &getY, &Station::setY); + addProperty("z", &getZ, &Station::setZ); +} + +void Station::addProperty(std::string pname, double (*getFct)(void*), void (*set)(void*, double)) +{ + STNProperty p; + p.name = pname; + p.get = getFct; + p.set = set; + _properties.push_back(p); +} + + +Station::~Station() +{ + delete _color; +} + +void Station::setColor(unsigned char r, unsigned char g, unsigned char b) +{ + (*_color)[0]=r; + (*_color)[1]=g; + (*_color)[2]=b; +} + +void Station::setColor(const Color* const color) +{ + (*_color)[0]=(*color)[0]; + (*_color)[1]=(*color)[1]; + (*_color)[2]=(*color)[2]; +} + +Station* Station::createStation(const std::string & line) +{ + std::list<std::string>::const_iterator it; + Station* station = new Station(); + std::list<std::string> fields = splitString(line, '\t'); + + if (fields.size() >= 3) { + + it = fields.begin(); + station->_name = *it; + (*station)[0] = strtod((replaceString(",", ".", *(++it))).c_str(), NULL); + (*station)[1] = strtod((replaceString(",", ".", *(++it))).c_str(), NULL); + if (++it != fields.end()) + { + (*station)[2] = strtod((replaceString(",", ".", *it)).c_str(), NULL); + } + } + else + { + std::cout << "Station::createStation() - Unexpected file format..." << std::endl; + delete station; + return NULL; + } + return station; + +} + +Station* Station::createStation(const std::string &name, double x, double y, double z) +{ + Station* station = new Station(); + station->_name = name; + (*station)[0] = x; + (*station)[1] = y; + (*station)[2] = z; + return station; +} + +const std::map<std::string, double> Station::getProperties() +{ + std::map<std::string, double> propertyMap; + + for (int i=0; i<static_cast<int>(_properties.size()); i++) + { + double (*getFct)(void*) = _properties[i].get; + //setFct set = _properties[i].set; + propertyMap[_properties[i].name] = (*getFct)((void*)this); + } + + return propertyMap; +} + +bool Station::inSelection(const std::vector<PropertyBounds> &bounds) +{ + double value; + for (size_t i=0; i<bounds.size(); i++) + { + for (size_t j=0; j<_properties.size(); j++) + { + if (_properties[j].name.compare(bounds[i].getName())==0) + { + double (*get)(void*) = _properties[j].get; + value = (*get)((void*)this); + if (!(value >= bounds[i].getMin() && value <= bounds[i].getMax())) return false; + } + } + } + return true; +} + + + +//////////////////////// +// The Borehole class // +//////////////////////// + +StationBorehole::StationBorehole(double x, double y, double z) : + Station (x,y,z), _zCoord(0), _depth(0), _date(0) +{ + _type = Station::BOREHOLE; + addProperty("date", &StationBorehole::getDate, &StationBorehole::setDate); + addProperty("depth", &StationBorehole::getDepth, &StationBorehole::setDepth); + + // add first point of borehole + _profilePntVec.push_back(this); + _soilName.push_back(""); +} + +StationBorehole::~StationBorehole(void) +{ + // deletes profile vector of borehole, starting at layer 1 + // the first point is NOT deleted as it points to the station object itself + for (size_t k(1); k<_profilePntVec.size(); k++) delete _profilePntVec[k]; +} + +int StationBorehole::find(const std::string &str) +{ + size_t size = _soilName.size(); + for (size_t i=0; i<size; i++) + { + if (_soilName[i].find(str)==0) return 1; + } + return 0; +} + +int StationBorehole::readStratigraphyFile(const std::string &path, std::vector<std::list<std::string> > &data) +{ + std::string line; + std::ifstream in( path.c_str() ); + + if (!in.is_open()) + { + std::cout << "StationBorehole::readStratigraphyFile() - Could not open file..." << std::endl; + return 0; + } + + while ( getline(in, line) ) + { + std::list<std::string> fields = splitString(line, '\t'); + data.push_back(fields); + } + + in.close(); + + return 1; +} + +int StationBorehole::addStratigraphy(const std::string &path, StationBorehole* borehole) +{ + std::vector<std::list<std::string> > data; + if (readStratigraphyFile(path, data)) + { + size_t size = data.size(); + for (size_t i=0; i<size; i++) + addLayer(data[i], borehole); + + // check if a layer is missing + size = borehole->_soilName.size(); + std::cout << "StationBorehole::addStratigraphy ToDo" << std::endl; + // for (size_t i=0; i<size; i++) + // { + // if ((borehole->_soilLayerThickness[i] == -1) ||(borehole->_soilName[i].compare("") == 0)) + // { + // borehole->_soilLayerThickness.clear(); + // borehole->_soilName.clear(); + // + // cout << "StationBorehole::addStratigraphy() - Profile incomplete (Borehole " << borehole->_name << ", Layer " << (i+1) << " missing).\n"; + // + // return 0; + // } + // } + } + else + { + borehole->addSoilLayer(borehole->getDepth(), "depth"); + } + + return 1; +} + +int StationBorehole::addLayer(std::list<std::string> fields, StationBorehole* borehole) +{ + if (fields.size() >= 4) /* check if there are enough fields to create a borehole object */ + { + if (fields.front().compare(borehole->_name) == 0) /* check if the name of the borehole matches the name in the data */ + { + fields.pop_front(); + + // int layer = atoi(fields.front().c_str()); + fields.pop_front(); + + std::cerr << "StationBorehole::addLayer - assuming correct order" << std::endl; + double thickness(strtod(replaceString(",", ".", fields.front()).c_str(), 0)); + fields.pop_front(); + borehole->addSoilLayer(thickness, fields.front()); + } + } else { + std::cout + << "StationBorehole::addLayer() - Unexpected file format (Borehole " + << borehole->_name << ")..." << std::endl; + return 0; + } + return 1; +} + +int StationBorehole::addStratigraphies(const std::string &path, std::vector<Point*> *boreholes) +{ + std::vector<std::list<std::string> > data; + + if (readStratigraphyFile(path, data)) + { + std::string name; + + size_t it=0; + size_t nBoreholes = data.size(); + for (size_t i=0; i<nBoreholes; i++) { + std::list<std::string> fields = data[i]; + + if (fields.size() >= 4) { + name = static_cast<StationBorehole*>((*boreholes)[it])->_name; + if ( fields.front().compare(name) != 0 ) { + if (it < boreholes->size()-1) it++; + } + + fields.pop_front(); + //the method just assumes that layers are read in correct order + fields.pop_front(); + double thickness (strtod(replaceString(",", ".", fields.front()).c_str(), 0)); + fields.pop_front(); + std::string soil_name (fields.front()); + fields.pop_front(); + static_cast<StationBorehole*>((*boreholes)[it])->addSoilLayer(thickness, soil_name); + } else + { + std::cout << "StationBorehole::addStratigraphies() - Unexpected file format..." << std::endl; + //return 0; + } + } + } + else + { + createSurrogateStratigraphies(boreholes); + } + + return 1; +} + + +StationBorehole* StationBorehole::createStation(const std::string &line) +{ + StationBorehole* borehole = new StationBorehole(); + std::list<std::string> fields = splitString(line, '\t'); + + if (fields.size() >= 5) { + borehole->_name = fields.front(); + fields.pop_front(); + (*borehole)[0] = strtod((replaceString(",", ".", fields.front())).c_str(), NULL); + fields.pop_front(); + (*borehole)[1] = strtod((replaceString(",", ".", fields.front())).c_str(), NULL); + fields.pop_front(); + (*borehole)[2] = strtod((replaceString(",", ".", fields.front())).c_str(), NULL); + fields.pop_front(); + borehole->_depth = strtod((replaceString(",", ".", fields.front())).c_str(), NULL); + fields.pop_front(); + if (fields.empty()) + borehole->_date = 0; + else + { + borehole->_date = strDate2double(fields.front()); + fields.pop_front(); + } + } + else + { + std::cout << "Station::createStation() - Unexpected file format..." << std::endl; + delete borehole; + return NULL; + } + return borehole; +} + +StationBorehole* StationBorehole::createStation(const std::string &name, double x, double y, double z, double depth, std::string date) +{ + StationBorehole* station = new StationBorehole(); + station->_name = name; + (*station)[0] = x; + (*station)[1] = y; + (*station)[2] = z; + station->_depth = depth; + if (date.compare("0000-00-00")) station->_date = xmlDate2double(date); + return station; +} + +void StationBorehole::createSurrogateStratigraphies(std::vector<Point*> *boreholes) +{ + size_t nBoreholes = boreholes->size(); + for (size_t i=0; i<nBoreholes; i++) + { + StationBorehole* bore = static_cast<StationBorehole*>((*boreholes)[i]); + bore->addSoilLayer(bore->getDepth(), "depth"); + } +} + +void StationBorehole::addSoilLayer ( double thickness, const std::string &soil_name) +{ + /* + // TF - Altmark + if (_profilePntVec.empty()) + addSoilLayer ((*this)[0], (*this)[1], (*this)[2]-thickness, soil_name); + else { + size_t idx (_profilePntVec.size()); + // read coordinates from last above + double x((*_profilePntVec[idx-1])[0]); + double y((*_profilePntVec[idx-1])[1]); + double z((*_profilePntVec[idx-1])[2]-thickness); + addSoilLayer (x, y, z, soil_name); + } + */ + + // KR - Bode + if (_profilePntVec.empty()) + addSoilLayer ((*this)[0], (*this)[1], (*this)[2], ""); + + size_t idx (_profilePntVec.size()); + double x((*_profilePntVec[idx-1])[0]); + double y((*_profilePntVec[idx-1])[1]); + double z((*_profilePntVec[0])[2]-thickness); + addSoilLayer (x, y, z, soil_name); + +} + +void StationBorehole::addSoilLayer ( double x, double y, double z, const std::string &soil_name) +{ + _profilePntVec.push_back (new Point (x, y, z)); + _soilName.push_back(soil_name); +} + +} // namespace diff --git a/GeoLib/Station.h b/GeoLib/Station.h new file mode 100644 index 0000000000000000000000000000000000000000..5a6943398eeb90699f37bc83d7cac77f4903652d --- /dev/null +++ b/GeoLib/Station.h @@ -0,0 +1,276 @@ +/** + * \file Station.h + * KR Initial implementation + */ + +#ifndef GEO_STATION_H +#define GEO_STATION_H + +#include <string> +#include <list> +#include <vector> +#include <map> + +#include "Polyline.h" +#include "Point.h" +#include "Color.h" +#include "PropertyBounds.h" + + +namespace GEOLIB { + +/** + * \ingroup GEOLIB + * + * \brief An observation station as a geometric object (i.e. basically a Point with some additional information. + * + * An observation station as a geometric object. Such a station is basically a point object + * with some additional information such as colour, a name, etc. + * + * Notes concerning the property-system used in this class: + * Variables of Station and derived classes can be defined to be "properties" of this class. + * Certain functions in the GUI allow you to modify aspects of the visualisation based on these + * properties (e.g. filtering operations such as "display only boreholes drilled after 1990 with a + * depth between 400-800m"). + * To make use of this functionality you need to define properties using the "Station::addProperty()"-method. + * Parameters for this function include the name of the property as well as a method to read and write the + * value of the associated variable (see documentation for "addProperty" for details). Furthermore, these read + * and write-functions need to be actually implemented as static functions to avoid casting problems with the + * function pointers used to dynamically connect the GUI functionality to the variables defined within the + * station-classes. Please refer to the documentation of the properties defined below for details. + */ +class Station : public Point +{ + +protected: + + //typedef double (Station::*getFct)(); + //typedef void (Station::*setFct)(double); + + /** + * \brief Container for station-properties. + * Each property consists of a name, a get- and a set-function. + * Please refer to Station::addProperty for details. + */ + struct STNProperty + { + std::string name; + double (*get)(void*); + void (*set)(void*, double); + }; + +public: + /// Signals if the object is a "simple" Station or a Borehole (i.e. containing borehole-specific information). + enum StationType + { + STATION = 1, + BOREHOLE = 2 + }; + + /** + * \brief Constructor + * + * Constructor initialising a Station object + * \param x The x-coordinate of the station. + * \param y The y-coordinate of the station. + * \param z The z-coordinate of the station. + * \param name The name of the station. + * \param color The color of the station in visualisation. + */ + Station(double x = 0.0, double y = 0.0, double z = 0.0, std::string name = "", Color* const color = new Color(0,128,0)); + + Station(Point* coords, std::string name = "", Color* const color = new Color(0,128,0)); + + + virtual ~Station(); + + /** + * \brief Defines a property for this class. + * + * Variables in Station and its derived classes can be defined to be properties of this station. + * This definition consists of a name for the property as well as a function pointer to a method to + * read and to write this variable. + * Due to inheritance these function pointers only work correctly if the read and write functions are + * implemented as static functions, i.e. both the read and the write functin get a void-pointer to the + * actual station-object. This pointer is then casted to the correct class and the respective value can + * then be read or written dynamically from that object. It is highly recommended to define both the + * read and write function as protected because it does not actually make sense for these functions to be + * static except in the context of function pointers. Please refer to the examples below, i.e. the getX + * and setX methods. + * \param pname The name of the property. + * \param get A function pointer to a static read function for the variable referred to by pname + * \param set A function pointer to a static write function for the variable referred to by pname + * \return + */ + void addProperty(std::string pname, double (*get)(void*), void (*set)(void*, double)); + + /// Sets colour for this station + void setColor(unsigned char r, unsigned char g, unsigned char b); + + /// Sets colour for this station + void setColor(const Color* color); + + /// returns the colour for this station + Color* getColor () { return _color; } + + /// Returns a map containing all the properties of that station type. + const std::map<std::string, double> getProperties(); + + /// Determines if the station's parameters are within the the bounds of the current selection (see property system for details) + bool inSelection(const std::vector<PropertyBounds> &bounds); + + /// Returns true if all properties of this stations are within the boundaries given by \param bounds and false otherwise + bool inSelection(std::map<std::string, double> properties) const; + + /// Returns the name of the station. + std::string getName() const { return _name; } + + /// Returns the GeoSys-station-type for the station. + int type() const { return _type; } + + /// Creates a Station-object from information contained in a string (assuming the string has the right format) + static Station* createStation(const std::string &line); + + /// Creates a new station object based on the given parameters. + static Station* createStation(const std::string &name, double x, double y, double z); + + +protected: + /** + * \brief Returns the x-coordinate of this station. See the detailed documentation for getX() concerning the syntax. + * + * Returns the x-coordinate of this station. + * This function belongs to the property system of Station and return the value for property "x" + * (i.e. the x-coordinate of the station). It is implemented as a static method to avoid casting issues + * related to the function pointer associated with this function. Therefore, this function needs to be + * called "getX((void*)this);". It is highly recommended to define this function as protected because it + * does not actually make sense for these functions to be static except in the context of function pointers. + * \param stnObject A pointer to the station object for which the x-coordinate should be returned, usually (void*)this will work fine. + * \return The x-coordinate for this station. + */ + static double getX(void* stnObject) { Station* stn = (Station*)stnObject; return (*stn)[0]; } + /// Returns the y-coordinate of this station. See the detailed documentation for getX concerning the syntax. + static double getY(void* stnObject) { Station* stn = (Station*)stnObject; return (*stn)[1]; } + /// Returns the z-coordinate of this station. See the detailed documentation for getX concerning the syntax. + static double getZ(void* stnObject) { Station* stn = (Station*)stnObject; return (*stn)[2]; } + /// Sets the x-coordinate for this station. See the detailed documentation for getX concerning the syntax. + static void setX(void* stnObject, double val) { Station* stn = (Station*)stnObject; (*stn)[0]=val; } + /// Sets the y-coordinate for this station. See the detailed documentation for getX concerning the syntax. + static void setY(void* stnObject, double val) { Station* stn = (Station*)stnObject; (*stn)[1]=val; } + /// Sets the z-coordinate for this station. See the detailed documentation for getX concerning the syntax. + static void setZ(void* stnObject, double val) { Station* stn = (Station*)stnObject; (*stn)[2]=val; } + + + std::string _name; + StationType _type; // GeoSys Station Type + std::vector<STNProperty> _properties; + + +private: + Color* _color; +}; + + +/********* Boreholes *********/ + + +/** + * \brief A borehole as a geometric object. + * + * A borehole inherits Station but has some additional information such as a date, a borehole profile, etc. + */ +class StationBorehole : public Station +{ + +public: + /** constructor initialises the borehole with the given coordinates */ + StationBorehole(double x = 0.0, double y = 0.0, double z = 0.0); + ~StationBorehole(void); + + /// Creates a StationBorehole-object from a string (assuming the string has the right format) + static StationBorehole* createStation(const std::string &line); + + /// Creates a new borehole object based on the given parameters. + static StationBorehole* createStation(const std::string &name, double x, double y, double z, double depth, std::string date = ""); + + /// Reads the stratigraphy for a specified station from a file + static int addStratigraphy(const std::string &path, StationBorehole* borehole); + + /** + * \brief Reads all stratigraphy information from a file in one go. + * + * Reads all stratigraphy information from a file in one go. + * Be very careful when using this method -- it is pretty fast but it checks nothing and just + * assumes that everything is in right order and will work out fine! + */ + static int addStratigraphies(const std::string &path, std::vector<Point*> *boreholes); + + /// Finds the given string in the vector of soil-names + int find(const std::string &str); + + // Returns the depth of the borehole + double getDepth() const { return _depth; } + + /// Returns the date entry for the borehole + double getDate() const { return _date; } + + /// Returns a reference to a vector of Points representing the stratigraphy of the borehole (incl. the station-point itself) + const std::vector<Point*> &getProfile() const { return _profilePntVec; } + + /// Returns a reference to a vector of soil names for the stratigraphy of the borehole + const std::vector<std::string> &getSoilNames() const { return _soilName; } + + /// Sets the depth of the borehole + void setDepth( double depth ) { _depth = depth; } + + /// Add a soil layer to the boreholes stratigraphy. + void addSoilLayer ( double thickness, const std::string &soil_name); + + /** + * Add a soil layer to the boreholes stratigraphy. + * Note: The given coordinates always mark THE END of the soil layer. The reason behind this is + * that the beginning of the first layer is identical with the position of the borehole. For each + * layer following the beginning is already given by the end of the last layer. This also saves + * a seperate entry in the profile vector for the end of the borehole which in the given notation + * is just the coordinate given for the last soil layer (i.e. the end of that layer). + */ + void addSoilLayer ( double x, double y, double z, const std::string &soil_name); + + + +protected: + /// Returns the depth of this borehole. Please see the documentation for Station::getX for details concerning the syntax. + static double getDepth(void* stnObject) { StationBorehole* stn = (StationBorehole*)stnObject; return stn->_depth; } + /// Returns the date this borehole has been drilled. Please see the documentation for Station::getX for details concerning the syntax. + static double getDate(void* stnObject) { StationBorehole* stn = (StationBorehole*)stnObject; return stn->_date; } + /// Sets the depth of this borehole. Please see the documentation for Station::getX for details concerning the syntax. + static void setDepth(void* stnObject, double val) { StationBorehole* stn = (StationBorehole*)stnObject; stn->_depth = val; } + /// Sets the date when this borehole has been drilled. Please see the documentation for Station::getX for details concerning the syntax. + static void setDate(void* stnObject, double val) { StationBorehole* stn = (StationBorehole*)stnObject; stn->_date = val; } + +private: + /// Adds a layer for the specified borehole profile based on the information given in the stringlist + static int addLayer(std::list<std::string> fields, StationBorehole* borehole); + + /// Creates fake stratigraphies of only one layer with a thickness equal to the borehole depth + static void createSurrogateStratigraphies(std::vector<Point*> *boreholes); + + /// Reads the specified file containing borehole stratigraphies into an vector of stringlists + static int readStratigraphyFile(const std::string &path, std::vector<std::list<std::string> > &data); + + //long profile_type; + //std::vector<long> _soilType; + double _zCoord; // height at which the borehole officially begins (this might _not_ be the actual elevation) + double _depth; // depth of the borehole + double _date; // date when the borehole has been drilled + + /// Contains the names for all the soil layers + std::vector<std::string> _soilName; + + /// Contains the points for the lower boundaries of all layers + std::vector<Point*> _profilePntVec; +}; + +} // namespace + +#endif // GEO_STATION_H diff --git a/GeoLib/Surface.cpp b/GeoLib/Surface.cpp new file mode 100644 index 0000000000000000000000000000000000000000..066df2a2d572aa5fa8305dfd3d7162c84831d793 --- /dev/null +++ b/GeoLib/Surface.cpp @@ -0,0 +1,107 @@ +/* + * Surface.cpp + * + * Created on: Apr 22, 2010 + * Author: TF + */ + +#include <list> + +// GEOLIB +#include "Surface.h" +#include "AxisAlignedBoundingBox.h" +#include "Polygon.h" + +// MathLib +#include "AnalyticalGeometry.h" +#include "EarClippingTriangulation.h" + +namespace GEOLIB { + +Surface::Surface (const std::vector<Point*> &pnt_vec) : + GeoObject(), _sfc_pnts(pnt_vec), _bv() +{} + +Surface::~Surface () +{ + for (size_t k(0); k<_sfc_triangles.size(); k++) + delete _sfc_triangles[k]; +} + +void Surface::addTriangle (size_t pnt_a, size_t pnt_b, size_t pnt_c) +{ + assert (pnt_a < _sfc_pnts.size() && pnt_b < _sfc_pnts.size() && pnt_c < _sfc_pnts.size()); + _sfc_triangles.push_back (new Triangle(_sfc_pnts, pnt_a, pnt_b, pnt_c)); + _bv.update (*_sfc_pnts[pnt_a]); + _bv.update (*_sfc_pnts[pnt_b]); + _bv.update (*_sfc_pnts[pnt_c]); +} + +Surface* Surface::createSurface(const Polyline &ply) +{ + if (!ply.isClosed()) { + std::cout << "Error in Surface::createSurface() - Polyline is not closed..." << std::cout; + return NULL; + } + + if (ply.getNumberOfPoints() > 2) { + // create empty surface + Surface *sfc(new Surface(ply.getPointsVec())); + + Polygon* polygon (new Polygon (ply)); + polygon->computeListOfSimplePolygons (); + + // create surfaces from simple polygons + const std::list<GEOLIB::Polygon*>& list_of_simple_polygons (polygon->getListOfSimplePolygons()); + for (std::list<GEOLIB::Polygon*>::const_iterator simple_polygon_it (list_of_simple_polygons.begin()); + simple_polygon_it != list_of_simple_polygons.end(); ++simple_polygon_it) { + + std::list<GEOLIB::Triangle> triangles; + std::cout << "triangulation of surface: ... " << std::flush; + MathLib::EarClippingTriangulation(*simple_polygon_it, triangles); + std::cout << "done - " << triangles.size () << " triangles " << std::endl; + + // add Triangles to Surface + std::list<GEOLIB::Triangle>::const_iterator it (triangles.begin()); + while (it != triangles.end()) { + sfc->addTriangle ((*it)[0], (*it)[1], (*it)[2]); + it++; + } + } + delete polygon; + return sfc; + } else { + std::cout << "Error in Surface::createSurface() - Polyline consists of less than three points and therefore cannot be triangulated..." << std::cout; + return NULL; + } + +} + +size_t Surface::getNTriangles () const +{ + return _sfc_triangles.size(); +} + +const Triangle* Surface::operator[] (size_t i) const +{ + assert (i < _sfc_triangles.size()); + return _sfc_triangles[i]; +} + +bool Surface::isPntInBV (const double *pnt, double eps) const +{ + return _bv.containsPoint (pnt, eps); +} + +bool Surface::isPntInSfc (const double *pnt) const +{ + bool nfound (true); + for (size_t k(0); k<_sfc_triangles.size() && nfound; k++) { + if (_sfc_triangles[k]->containsPoint (pnt)) { + nfound = false; + } + } + return !nfound; +} + +} // end namespace diff --git a/GeoLib/Surface.h b/GeoLib/Surface.h new file mode 100644 index 0000000000000000000000000000000000000000..7bf36f273bd77f716dd5d50e82a15da4ae27f9c9 --- /dev/null +++ b/GeoLib/Surface.h @@ -0,0 +1,82 @@ +/* + * Surface.h + * + * Created on: Jan 22, 2010 + * Author: TF + */ + +#ifndef SURFACE_H_ +#define SURFACE_H_ + +#include <vector> + +#include "GeoObject.h" +#include "Point.h" +#include "Polyline.h" +#include "Triangle.h" +#include "AxisAlignedBoundingBox.h" + +namespace GEOLIB { + +/** + * \ingroup GEOLIB + * + * \brief A Surface is represented by Triangles. It consists of a reference + * to a vector of (pointers to) points (m_sfc_pnts) and a vector that stores + * the Triangles consisting of points from m_sfc_pnts. + * */ +class Surface : public GeoObject +{ +public: + Surface (const std::vector<Point*> &pnt_vec); + virtual ~Surface (); + + /** + * adds three indices describing a triangle and updates the bounding box + * */ + void addTriangle (size_t pnt_a, size_t pnt_b, size_t pnt_c); + + /// Triangulates a new surface based on closed polyline. + static Surface* createSurface(const Polyline &ply); + + /** + * returns the number of triangles describing the Surface + * */ + size_t getNTriangles () const; + + /** \brief const access operator for the access to the i-th Triangle of the surface. + */ + const Triangle* operator[] (size_t i) const; + + /** + * is the given point in the bounding volume of the surface + */ + bool isPntInBV (const double *pnt, double eps = std::numeric_limits<double>::epsilon()) const; + + /** + * is the given point pnt located in the surface + * @param pnt the point + * @return true if the point is contained in the surface + */ + bool isPntInSfc (const double *pnt) const; + + const std::vector<Point*> *getPointVec() const { return &_sfc_pnts; }; + + /** + * method allows access to the internal axis aligned bounding box + * @return axis aligned bounding box + */ + AABB const & getAABB () const { return _bv; } + +protected: + /** a vector of pointers to Points */ + const std::vector<Point*> &_sfc_pnts; + /** position of pointers to the geometric points */ + std::vector<Triangle*> _sfc_triangles; + /** bounding volume is an axis aligned bounding box */ + AABB _bv; +}; + +} + +#endif /* SURFACE_H_ */ diff --git a/GeoLib/SurfaceVec.h b/GeoLib/SurfaceVec.h new file mode 100644 index 0000000000000000000000000000000000000000..7554f27d593253614e88614c1cd8d789bb151086 --- /dev/null +++ b/GeoLib/SurfaceVec.h @@ -0,0 +1,26 @@ +/* + * \file SurfaceVec.h + * + * Created on: Feb 9, 2010 + * Author: fischeth + */ + + +#ifndef SURFACEVEC_H_ +#define SURFACEVEC_H_ + +#include "TemplateVec.h" +#include "Surface.h" + +namespace GEOLIB { + +/** + * Class SurfaceVec encapsulate a std::vector of Surfaces + * and a name. + * */ + +typedef TemplateVec<Surface> SurfaceVec; + +} // end namespace + +#endif /* SURFACEVEC_H_ */ diff --git a/GeoLib/TemplatePoint.h b/GeoLib/TemplatePoint.h new file mode 100644 index 0000000000000000000000000000000000000000..41667d8d26e4136d3512bf16ce36978e66bae1f2 --- /dev/null +++ b/GeoLib/TemplatePoint.h @@ -0,0 +1,133 @@ +/* + * TemplatePoint.h + * + * Created on: Jan 28, 2010 + * Author: fischeth + */ + +#ifndef TEMPLATEPOINT_H_ +#define TEMPLATEPOINT_H_ + +#include <cassert> +#include <iostream> +#include <string> +#include <sstream> + +#include "GeoObject.h" + +namespace GEOLIB { + +/** + * \ingroup GEOLIB + * + * \brief class-template for points can be instantiated by a numeric type. + * \param T the coordinate type + */ +template <class T> class TemplatePoint : public GeoObject +{ +public: + /** default constructor */ + TemplatePoint (); + + /** constructor - constructs a TemplatePoint object + \param x1 value for the first coordinate + \param x2 value for the second coordinate + \param x3 value for the third coordinate + */ + TemplatePoint (T x1, T x2, T x3); + + /** constructor - constructs a TemplatePoint object + \param x values for three coordinates + */ + TemplatePoint (T const* x); + + /** virtual destructor */ + virtual ~TemplatePoint() {}; + + /** \brief const access operator + * The access to the point coordinates is like the access to a field. Code example: + * \code + * Point<double> point (1.0, 2.0, 3.0); + * double sqrNrm2 = point[0] * point[0] + point[1] * point[1] + point[2] + point[2]; + * \endcode + */ + const T& operator[] (size_t idx) const { + assert (idx <= 2); + return _x[idx]; + } + /** \brief access operator (see book Effektiv C++ programmieren - subsection 1.3.2 ). + * \sa const T& operator[] (size_t idx) const + */ + T& operator[] (size_t idx) { + return const_cast<T&> (static_cast<const TemplatePoint&> (*this)[idx]); + } + + /** returns an array containing the coordinates of the point */ + const T* getData () const { return _x; } + + /** write point coordinates into stream (used from operator<<) + * \param os a standard output stream + */ + virtual void write (std::ostream &os) const { + os << _x[0] << " " << _x[1] << " " << _x[2] << std::flush; + } + + /** + * write point coordinates into string + */ + virtual std::string write () const { + std::ostringstream strStream; + strStream << _x[0] << " " << _x[1] << " " << _x[2]; + return strStream.str(); + } + + /** read point coordinates into stream (used from operator>>) */ + virtual void read (std::istream &is) { + is >> _x[0] >> _x[1] >> _x[2]; + } + +protected: + T _x[3]; +}; + +template <class T> TemplatePoint<T>::TemplatePoint() : + GeoObject() +{ + _x[0] = static_cast<T>(0); + _x[1] = static_cast<T>(0); + _x[2] = static_cast<T>(0); +} + +template <class T> TemplatePoint<T>::TemplatePoint(T x1, T x2, T x3) : + GeoObject() +{ + _x[0] = x1; + _x[1] = x2; + _x[2] = x3; +} + +template <class T> TemplatePoint<T>::TemplatePoint (T const* x) : + GeoObject() +{ + for (size_t k(0); k<3; k++) _x[k] = x[k]; +} + +/** overload the output operator for class Point */ +template <class T> +std::ostream& operator<< (std::ostream &os, const TemplatePoint<T> &p) +{ + p.write (os); + return os; +} + +/** overload the input operator for class Point */ +template <class T> +std::istream& operator>> (std::istream &is, TemplatePoint<T> &p) +{ + p.read (is); + return is; +} + +} // end namespace GEO + +#endif /* TEMPLATEPOINT_H_ */ diff --git a/GeoLib/TemplateVec.h b/GeoLib/TemplateVec.h new file mode 100644 index 0000000000000000000000000000000000000000..878539a4ea3034383f133bc7fff701bc1470d4c6 --- /dev/null +++ b/GeoLib/TemplateVec.h @@ -0,0 +1,181 @@ +/* + * TemplateVec.h + * + * Created on: Feb 26, 2010 + * Author: TF + */ + +#ifndef TEMPLATEVEC_H_ +#define TEMPLATEVEC_H_ + +namespace GEOLIB { + +/** + * \ingroup GEOLIB + * + * \brief The class TemplateVec takes a unique name and manages + * a std::vector of pointers to data elements of type T. + * + * Instances are classes PolylineVec and SurfaceVec. + * */ +template <class T> class TemplateVec +{ +public: + /** + * Constructor of class TemlateVec. + * @param name unique name of the project the elements belonging to. + * In order to access the data elements a unique name is required. + * @param data_vec vector of data elements + * @param elem_name_map Names of data elements can be given by a + * std::map<std::string, size_t>. Here the std::string is the name + * of the element and the value for size_t stands for an index in + * the data_vec. + + */ + TemplateVec (const std::string &name, std::vector<T*> *data_vec, std::map<std::string, size_t>* elem_name_map = NULL) : + _name(name), _data_vec(data_vec), _name_id_map (elem_name_map) + {} + + /** + * destructor, deletes all data elements + */ + virtual ~TemplateVec () + { + for (size_t k(0); k<size(); k++) delete (*_data_vec)[k]; + delete _data_vec; + delete _name_id_map; + } + + /** sets the name of the vector of geometric objects + * the data elements belonging to + * \param n the name as standard string */ + void setName (const std::string & n) { _name = n; } + /** + * the name, the data element belonging to + * @return the name of the object + */ + std::string getName () const { return _name; } + + /** + * @return the number of data elements + */ + size_t size () const { return _data_vec->size(); } + + /** + * get a pointer to a standard vector containing the data elements + * @return the data elements + */ + const std::vector<T*>* getVector () const { return _data_vec; } + + /** + * search the vector of names for the ID of the geometric element with the given name + * @param name the name of the geometric element + * @param id the id of the geometric element + * @return + */ + bool getElementIDByName (const std::string& name, size_t &id) const + { + std::map<std::string,size_t>::const_iterator it (_name_id_map->find (name)); + + if (it != _name_id_map->end()) { + id = it->second; + return true; + } else return false; + } + + const T* getElementByName (const std::string& name) const + { + size_t id; + bool ret (getElementIDByName (name, id)); + if (ret) { + return (*_data_vec)[id]; + } else { + return NULL; + } + } + + /** + * The method returns true if there is a name associated + * with the given id, else method returns false. + * @param id the id + * @param element_name if a name associated with the id + * is found name is assigned to element_name + * @return if there is name associated with the given id: + * true, else false + */ + bool getNameOfElementByID (size_t id, std::string& element_name) const + { + if (! _name_id_map) return false; + // search in map for id + std::map<std::string,size_t>::const_iterator it (_name_id_map->begin()); + while (it != _name_id_map->end()) { + if (it->second == id) { + element_name = it->first; + return true; + } + it++; + } + return false; + } + + void setNameOfElementByID (size_t id, std::string& element_name) + { + if (! _name_id_map) return; + _name_id_map->insert( std::pair<std::string, size_t>(element_name, id) ); + } + + /** + * The method returns true if the given element of type T + * can be found and the element has a name, else method returns false. + * @param data the data element, one wants to know the name + * @param name the name of the data element (if the data element is + * found and the data element has a name) + * @return if element is found and has a name: true, else false + */ + bool getNameOfElement (const T* data, std::string& name) const + { + for (size_t k(0); k<_data_vec->size(); k++) { + if ((*_data_vec)[k] == data) { + return getNameOfElementByID (k, name); + } + } + return false; + } + + void push_back (T* data_element, std::string const * const name = NULL) + { + _data_vec->push_back (data_element); + if (name == NULL) return; + if (! name->empty()) { + if (_name_id_map == NULL) { + _name_id_map = new std::map <std::string, size_t>; + } + _name_id_map->insert (std::pair<std::string,size_t>(*name, _data_vec->size()-1)); + } + } + + +private: + /** copy constructor doesn't have an implementation */ + // compiler does not create a (possible unwanted) copy constructor + TemplateVec (const TemplateVec &); + /** assignment operator doesn't have an implementation */ + // this way the compiler does not create a (possible unwanted) assignment operator + TemplateVec& operator= (const TemplateVec& rhs); + + /** the name of the object */ + std::string _name; + + /** + * pointer to a vector of data elements + */ + std::vector <T*> *_data_vec; + /** + * store names associated with the element ids + */ + std::map<std::string, size_t>* _name_id_map; +}; + +} // end namespace GEOLIB + +#endif /* TEMPLATEVEC_H_ */ diff --git a/GeoLib/Triangle.cpp b/GeoLib/Triangle.cpp new file mode 100644 index 0000000000000000000000000000000000000000..06df2b4c28720ce481c661c2abaa61fb93d1851a --- /dev/null +++ b/GeoLib/Triangle.cpp @@ -0,0 +1,207 @@ +/* + * \file Triangle.cpp + * + * Created on: Jun 6, 2011 + * Author: TF + */ + +#include "Triangle.h" + +// MathLib +#include "LinAlg/Solvers/GaussAlgorithm.h" +#include "MathTools.h" +#include "LinAlg/Dense/Matrix.h" +#include "Vector3.h" + +namespace GEOLIB { + +Triangle::Triangle (std::vector<Point *> const &pnt_vec) : + _pnts(pnt_vec), _initialized (false), _longest_edge (0.0) +{ + _pnt_ids[0] = std::numeric_limits<size_t>::max(); + _pnt_ids[1] = std::numeric_limits<size_t>::max(); + _pnt_ids[2] = std::numeric_limits<size_t>::max(); +} + +Triangle::Triangle (std::vector<Point *> const &pnt_vec, size_t pnt_a, size_t pnt_b, size_t pnt_c) : + _pnts(pnt_vec), _initialized (true), _longest_edge (0.0) +{ + _pnt_ids[0] = pnt_a; + _pnt_ids[1] = pnt_b; + _pnt_ids[2] = pnt_c; + _longest_edge = MathLib::sqrDist (_pnts[_pnt_ids[0]], _pnts[_pnt_ids[1]]); + double tmp (MathLib::sqrDist (_pnts[_pnt_ids[1]], _pnts[_pnt_ids[2]])); + if (tmp > _longest_edge) _longest_edge = tmp; + tmp = MathLib::sqrDist (_pnts[_pnt_ids[0]], _pnts[_pnt_ids[2]]); + if (tmp > _longest_edge) _longest_edge = tmp; + _longest_edge = sqrt (_longest_edge); +} + +void Triangle::setTriangle (size_t pnt_a, size_t pnt_b, size_t pnt_c) +{ + assert (pnt_a < _pnts.size() && pnt_b < _pnts.size() && pnt_c < _pnts.size()); + _pnt_ids[0] = pnt_a; + _pnt_ids[1] = pnt_b; + _pnt_ids[2] = pnt_c; + + _longest_edge = MathLib::sqrDist (_pnts[_pnt_ids[0]], _pnts[_pnt_ids[1]]); + double tmp (MathLib::sqrDist (_pnts[_pnt_ids[1]], _pnts[_pnt_ids[2]])); + if (tmp > _longest_edge) _longest_edge = tmp; + tmp = MathLib::sqrDist (_pnts[_pnt_ids[0]], _pnts[_pnt_ids[2]]); + if (tmp > _longest_edge) _longest_edge = tmp; + _longest_edge = sqrt (_longest_edge); +} + +bool Triangle::containsPoint (const double *pnt) const +{ + GEOLIB::Point const& a_tmp (*(_pnts[_pnt_ids[0]])); + GEOLIB::Point const& b_tmp (*(_pnts[_pnt_ids[1]])); + GEOLIB::Point const& c_tmp (*(_pnts[_pnt_ids[2]])); + + GEOLIB::Point s(a_tmp); + for (size_t k(0); k<3; k++) { + s[k] += b_tmp[k] + c_tmp[k]; + s[k] /= 3.0; + } + + double eps (1e-2); + GEOLIB::Point const a (a_tmp[0] + eps *(a_tmp[0]-s[0]), + a_tmp[1] + eps *(a_tmp[1]-s[1]), + a_tmp[2] + eps *(a_tmp[2]-s[2])); + GEOLIB::Point const b (b_tmp[0] + eps *(b_tmp[0]-s[0]), + b_tmp[1] + eps *(b_tmp[1]-s[1]), + b_tmp[2] + eps *(b_tmp[2]-s[2])); + GEOLIB::Point const c (c_tmp[0] + eps *(c_tmp[0]-s[0]), + c_tmp[1] + eps *(c_tmp[1]-s[1]), + c_tmp[2] + eps *(c_tmp[2]-s[2])); + + const double delta (std::numeric_limits<double>::epsilon()); + const double upper (1+delta); + + // check special case where points of triangle have the same x-coordinate + if (fabs(b[0]-a[0]) <= std::numeric_limits<double>::epsilon() && + fabs(c[0]-a[0]) <= std::numeric_limits<double>::epsilon()) { + // all points of triangle have same x-coordinate + if (fabs(pnt[0]-a[0]) / _longest_edge <= 1e-3) { + // criterion: p-a = u0 * (b-a) + u1 * (c-a); 0 <= u0, u1 <= 1, u0+u1 <= 1 + MathLib::Matrix<double> mat (2,2); + mat(0,0) = b[1] - a[1]; + mat(0,1) = c[1] - a[1]; + mat(1,0) = b[2] - a[2]; + mat(1,1) = c[2] - a[2]; + double y[2] = {pnt[1]-a[1], pnt[2]-a[2]}; + + MathLib::GaussAlgorithm gauss (mat); + gauss.execute (y); + + if (-delta <= y[0] && y[0] <= upper && -delta <= y[1] && y[1] <= upper + && y[0] + y[1] <= upper) { + return true; + } else { + return false; + } + } else { + return false; + } + } + + // check special case where points of triangle have the same y-coordinate + if (fabs(b[1]-a[1]) <= std::numeric_limits<double>::epsilon() && + fabs(c[1]-a[1]) <= std::numeric_limits<double>::epsilon()) { + // all points of triangle have same y-coordinate + if (fabs(pnt[1]-a[1]) / _longest_edge <= 1e-3) { + // criterion: p-a = u0 * (b-a) + u1 * (c-a); 0 <= u0, u1 <= 1, u0+u1 <= 1 + MathLib::Matrix<double> mat (2,2); + mat(0,0) = b[0] - a[0]; + mat(0,1) = c[0] - a[0]; + mat(1,0) = b[2] - a[2]; + mat(1,1) = c[2] - a[2]; + double y[2] = {pnt[0]-a[0], pnt[2]-a[2]}; + + MathLib::GaussAlgorithm gauss (mat); + gauss.execute (y); + + if (-delta <= y[0] && y[0] <= upper && -delta <= y[1] && y[1] <= upper && y[0] + y[1] <= upper) { + return true; + } else { + return false; + } + } else { + return false; + } + } + + // criterion: p-a = u0 * (b-a) + u1 * (c-a); 0 <= u0, u1 <= 1, u0+u1 <= 1 + MathLib::Matrix<double> mat (2,2); + mat(0,0) = b[0] - a[0]; + mat(0,1) = c[0] - a[0]; + mat(1,0) = b[1] - a[1]; + mat(1,1) = c[1] - a[1]; + double y[2] = {pnt[0]-a[0], pnt[1]-a[1]}; + + MathLib::GaussAlgorithm gauss (mat); + gauss.execute (y); + + // check if the solution fulfills the third equation + if (fabs((b[2]-a[2]) * y[0] + (c[2]-a[2]) * y[1] - (pnt[2] - a[2])) < 1e-3) { + if (-delta <= y[0] && y[0] <= upper && -delta <= y[1] && y[1] <= upper && + y[0] + y[1] <= upper) { + return true; + } + return false; + } else { + return false; + } +} + +bool Triangle::containsPoint2D (const double *pnt) const +{ + GEOLIB::Point const& a (*(_pnts[_pnt_ids[0]])); + GEOLIB::Point const& b (*(_pnts[_pnt_ids[1]])); + GEOLIB::Point const& c (*(_pnts[_pnt_ids[2]])); + + // criterion: p-a = u0 * (b-a) + u1 * (c-a); 0 <= u0, u1 <= 1, u0+u1 <= 1 + MathLib::Matrix<double> mat (2,2); + mat(0,0) = b[0] - a[0]; + mat(0,1) = c[0] - a[0]; + mat(1,0) = b[1] - a[1]; + mat(1,1) = c[1] - a[1]; + double y[2] = {pnt[0]-a[0], pnt[1]-a[1]}; + + MathLib::GaussAlgorithm gauss (mat); + gauss.execute (y); + + const double delta (std::numeric_limits<double>::epsilon()); + const double upper (1+delta); + + // check if u0 and u1 fulfills the condition (with some delta) + if (-delta <= y[0] && y[0] <= upper && -delta <= y[1] && y[1] <= upper && y[0] + y[1] <= upper) { + return true; + } + return false; +} + +void getPlaneCoefficients(Triangle const& tri, double c[3]) +{ + GEOLIB::Point const& p0 (*(tri.getPoint(0))); + GEOLIB::Point const& p1 (*(tri.getPoint(1))); + GEOLIB::Point const& p2 (*(tri.getPoint(2))); + MathLib::Matrix<double> mat (3,3); + mat(0,0) = p0[0]; + mat(0,1) = p0[1]; + mat(0,2) = 1.0; + mat(1,0) = p1[0]; + mat(1,1) = p1[1]; + mat(1,2) = 1.0; + mat(2,0) = p2[0]; + mat(2,1) = p2[1]; + mat(2,2) = 1.0; + c[0] = p0[2]; + c[1] = p1[2]; + c[2] = p2[2]; + + MathLib::GaussAlgorithm gauss (mat); + gauss.execute (c); +} + +} // end namespace GEOLIB diff --git a/GeoLib/Triangle.h b/GeoLib/Triangle.h new file mode 100644 index 0000000000000000000000000000000000000000..48a1028ac34c221e588d88aa05a7fa11444003de --- /dev/null +++ b/GeoLib/Triangle.h @@ -0,0 +1,99 @@ +/* + * \file Triangle.h + * + * Created on: Mar 23, 2010 + * Author: TF + */ + +#ifndef TRIANGLE_H_ +#define TRIANGLE_H_ + +#include <vector> + +// GeoLib +#include "Point.h" + +namespace GEOLIB { + +/** \brief Class Triangle consists of a reference to a point vector and + * a vector that stores the indices in the point vector. + * A surface is composed by triangles. The class Surface stores the position + * of pointers to the points of triangles in the m_sfc_pnt_ids vector. + * */ +class Triangle +{ +public: + /** + * construction of object, initialization of reference to point vector + */ + Triangle (std::vector<Point *> const &pnt_vec); + + /** + * construction of object, initialization of reference to point vector, + * saves the three indices describing a triangle + */ + Triangle (std::vector<Point *> const &pnt_vec, size_t pnt_a, size_t pnt_b, size_t pnt_c); + + /** + * saves three indices describing a triangle + * */ + void setTriangle (size_t pnt_a, size_t pnt_b, size_t pnt_c); + + /** \brief const access operator to access the index + * of the i-th triangle point + */ + const size_t& operator[] (size_t i) const { + assert (i < 3); + return _pnt_ids[i]; + } + +// /** \brief access operator to access the index +// * of the i-th triangle point +// * */ +// size_t& operator[] (size_t i) { +// assert (i < 3); +// return _pnt_ids[i]; +// } + + /** + * \brief const access operator to access the i-th triangle Point + */ + const Point* getPoint (size_t i) const { + assert (i < 3); + return _pnts[_pnt_ids[i]]; + } + + /** + * checks if point is in triangle + * @param pnt + * @return true, if point is in triangle, else false + */ + bool containsPoint (const double *pnt) const; + + bool containsPoint (const Point &pnt) const + { + return containsPoint (pnt.getData()); + } + + /** + * projects the triangle points to the x-y-plane and + * checks if point pnt is contained into the triangle + * @param pnt the point to test for + * @return true, if the point is into the projected triangle + */ + bool containsPoint2D (const double *pnt) const; + +protected: + /** a vector of pointers to points */ + const std::vector<Point*> &_pnts; + /** position of pointers to the geometric points */ + size_t _pnt_ids[3]; + bool _initialized; + double _longest_edge; +}; + +void getPlaneCoefficients(Triangle const& tri, double c[3]); + +} // end namespace GEOLIB + +#endif /* TRIANGLE_H_ */ diff --git a/MathLib/AnalyticalGeometry.cpp b/MathLib/AnalyticalGeometry.cpp new file mode 100644 index 0000000000000000000000000000000000000000..efcf96bf5de5dd517031f67e47501c83488052bb --- /dev/null +++ b/MathLib/AnalyticalGeometry.cpp @@ -0,0 +1,215 @@ +/* + * \file AnalyticalGeometry.cpp + * + * Created on: Mar 17, 2010 + * Author: TF + */ + +#include <cmath> +#include <cstdlib> // for exit +#include <list> +#include <limits> +#include <fstream> + +// Base +#include "swap.h" +#include "quicksort.h" + +// GEO +#include "Polyline.h" +#include "Triangle.h" + +// MathLib +#include "MathTools.h" +#include "AnalyticalGeometry.h" +#include "LinAlg/Solvers/GaussAlgorithm.h" +#include "LinAlg/Dense/Matrix.h" // for transformation matrix +#include "max.h" + +namespace MathLib { + +Orientation getOrientation (const double& p0_x, const double& p0_y, + const double& p1_x, const double& p1_y, + const double& p2_x, const double& p2_y) +{ + double h1 ((p1_x-p0_x)*(p2_y-p0_y)); + double h2 ((p2_x-p0_x)*(p1_y-p0_y)); + + double tol (sqrt(std::numeric_limits<double>::min())); + if (fabs (h1-h2) <= tol * max (fabs(h1), fabs(h2))) + return COLLINEAR; + if (h1-h2 > 0.0) return CCW; + + return CW; +} + +Orientation getOrientation (const GEOLIB::Point* p0, const GEOLIB::Point* p1, const GEOLIB::Point* p2) +{ + return getOrientation ((*p0)[0], (*p0)[1], (*p1)[0], (*p1)[1], (*p2)[0], (*p2)[1]); +} + +bool lineSegmentIntersect (const GEOLIB::Point& a, const GEOLIB::Point& b, + const GEOLIB::Point& c, const GEOLIB::Point& d, + GEOLIB::Point& s) +{ + Matrix<double> mat(2,2); + mat(0,0) = b[0] - a[0]; + mat(1,0) = b[1] - a[1]; + mat(0,1) = c[0] - d[0]; + mat(1,1) = c[1] - d[1]; + + // check if vectors are parallel + double eps (sqrt(std::numeric_limits<double>::min())); + if (fabs(mat(1,1)) < eps) { + // vector (D-C) is parallel to x-axis + if (fabs(mat(0,1)) < eps) { + // vector (B-A) is parallel to x-axis + return false; + } + } else { + // vector (D-C) is not parallel to x-axis + if (fabs(mat(0,1)) >= eps) { + // vector (B-A) is not parallel to x-axis + // \f$(B-A)\f$ and \f$(D-C)\f$ are parallel iff there exists + // a constant \f$c\f$ such that \f$(B-A) = c (D-C)\f$ + if (fabs (mat(0,0) / mat(0,1) - mat(1,0) / mat(1,1)) < eps * fabs (mat(0,0) / mat(0,1))) + return false; + } + } + + double *rhs (new double[2]); + rhs[0] = c[0] - a[0]; + rhs[1] = c[1] - a[1]; + + GaussAlgorithm lu_solver (mat); + lu_solver.execute (rhs); + if (0 <= rhs[0] && rhs[0] <= 1.0 && 0 <= rhs[1] && rhs[1] <= 1.0) { + s[0] = a[0] + rhs[0] * (b[0] - a[0]); + s[1] = a[1] + rhs[0] * (b[1] - a[1]); + s[2] = a[2] + rhs[0] * (b[2] - a[2]); + // check z component + double z0 (a[2] - d[2]), z1(rhs[0]*(b[2]-a[2]) + rhs[1]*(d[2]-c[2])); + delete [] rhs; + if (std::fabs (z0-z1) < eps) + return true; + else + return false; + } else delete [] rhs; + return false; +} + +bool lineSegmentsIntersect (const GEOLIB::Polyline* ply, size_t &idx0, size_t &idx1, GEOLIB::Point& intersection_pnt) +{ + size_t n_segs (ply->getNumberOfPoints() - 1); + /** + * computing the intersections of all possible pairs of line segments of the given polyline + * as follows: + * let the segment \f$s_1 = (A,B)\f$ defined by \f$k\f$-th and \f$k+1\f$-st point + * of the polyline and segment \f$s_2 = (C,B)\f$ defined by \f$j\f$-th and + * \f$j+1\f$-st point of the polyline, \f$j>k+1\f$ + */ + for (size_t k(0); k<n_segs-2; k++) { + for (size_t j(k+2); j<n_segs; j++) { + if (k!=0 || j<n_segs-1) { + if (lineSegmentIntersect (*(*ply)[k], *(*ply)[k+1], *(*ply)[j], *(*ply)[j+1], intersection_pnt)) { + idx0 = k; + idx1 = j; + return true; + } + } + } + } + return false; +} + +bool isPointInTriangle (const double p[3], const double a[3], const double b[3], const double c[3]) +{ + // criterion: p-b = u0 * (b - a) + u1 * (b - c); 0 <= u0, u1 <= 1, u0+u1 <= 1 + MathLib::Matrix<double> mat (2,2); + mat(0,0) = a[0] - b[0]; + mat(0,1) = c[0] - b[0]; + mat(1,0) = a[1] - b[1]; + mat(1,1) = c[1] - b[1]; + double rhs[2] = {p[0]-b[0], p[1]-b[1]}; + + MathLib::GaussAlgorithm gauss (mat); + gauss.execute (rhs); + + if (0 <= rhs[0] && rhs[0] <= 1 && 0 <= rhs[1] && rhs[1] <= 1 && rhs[0] + rhs[1] <= 1) return true; + return false; +} + +bool isPointInTriangle (const GEOLIB::Point* p, + const GEOLIB::Point* a, const GEOLIB::Point* b, const GEOLIB::Point* c) +{ + return isPointInTriangle (p->getData(), a->getData(), b->getData(), c->getData()); +} + +// NewellPlane from book Real-Time Collision detection p. 494 +void getNewellPlane(const std::vector<GEOLIB::Point*>& pnts, Vector &plane_normal, + double& d) +{ + d = 0; + Vector centroid; + size_t n_pnts (pnts.size()); + for (size_t i(n_pnts - 1), j(0); j < n_pnts; i = j, j++) { + plane_normal[0] += ((*(pnts[i]))[1] - (*(pnts[j]))[1]) + * ((*(pnts[i]))[2] + (*(pnts[j]))[2]); // projection on yz + plane_normal[1] += ((*(pnts[i]))[2] - (*(pnts[j]))[2]) + * ((*(pnts[i]))[0] + (*(pnts[j]))[0]); // projection on xz + plane_normal[2] += ((*(pnts[i]))[0] - (*(pnts[j]))[0]) + * ((*(pnts[i]))[1] + (*(pnts[j]))[1]); // projection on xy + + centroid += *(pnts[j]); + } + + plane_normal *= 1.0 / plane_normal.Length(); + d = centroid.Dot(plane_normal) / n_pnts; +} + + +void rotatePointsToXY(Vector &plane_normal, + std::vector<GEOLIB::Point*> &pnts) +{ + double small_value (sqrt (std::numeric_limits<double>::min())); + if (fabs(plane_normal[0]) < small_value && fabs(plane_normal[1]) < small_value) + return; + + // *** some frequently used terms *** + // sqrt (v_1^2 + v_2^2) + double h0(sqrt(plane_normal[0] * plane_normal[0] + plane_normal[1] + * plane_normal[1])); + // 1 / sqrt (v_1^2 + v_2^2) + double h1(1 / h0); + // 1 / sqrt (h0 + v_3^2) + double h2(1.0 / sqrt(h0 + plane_normal[2] * plane_normal[2])); + + Matrix<double> rot_mat(3, 3); + // calc rotation matrix + rot_mat(0, 0) = plane_normal[2] * plane_normal[0] * h2 * h1; + rot_mat(0, 1) = plane_normal[2] * plane_normal[1] * h2 * h1; + rot_mat(0, 2) = - h0 * h2; + rot_mat(1, 0) = -plane_normal[1] * h1; + rot_mat(1, 1) = plane_normal[0] * h1;; + rot_mat(1, 2) = 0.0; + rot_mat(2, 0) = plane_normal[0] * h2; + rot_mat(2, 1) = plane_normal[1] * h2; + rot_mat(2, 2) = plane_normal[2] * h2; + + double *tmp (NULL); + size_t n_pnts(pnts.size()); + for (size_t k(0); k < n_pnts; k++) { + tmp = rot_mat * pnts[k]->getData(); + for (size_t j(0); j < 3; j++) + (*(pnts[k]))[j] = tmp[j]; + delete [] tmp; + } + + tmp = rot_mat * plane_normal.getData(); + for (size_t j(0); j < 3; j++) + plane_normal[j] = tmp[j]; + + delete [] tmp; +} + +} // end namespace MathLib diff --git a/MathLib/AnalyticalGeometry.h b/MathLib/AnalyticalGeometry.h new file mode 100644 index 0000000000000000000000000000000000000000..d982f10f3a0058f93caa2de82c48d61b8d98755b --- /dev/null +++ b/MathLib/AnalyticalGeometry.h @@ -0,0 +1,88 @@ +/* + * \file AnalyticalGeometry.h + * + * Created on: Mar 17, 2010 + * Author: TF + */ + +#ifndef ANALYTICAL_GEOMETRY_H_ +#define ANALYTICAL_GEOMETRY_H_ + +// MathLib +#include "Vector3.h" +// GEOLIB +#include "Triangle.h" + +namespace GEOLIB { + class Polyline; +} + +namespace MathLib { + +enum Orientation { + CW = 1, + CCW = 2, + COLLINEAR = 3 +}; + +/** + * computes the orientation of the three 2D-Points given by their coordinates + * p0_x, p0_y, p1_x, p1_y, p2_x and p2_y + * \returns CW (clockwise), CCW (counterclockwise) or COLLINEAR (points are on a line) + */ +Orientation getOrientation (const double& p0_x, const double& p0_y, + const double& p1_x, const double& p1_y, + const double& p2_x, const double& p2_y); + +/** + * wrapper for getOrientation () + */ +Orientation getOrientation (const GEOLIB::Point* p0, const GEOLIB::Point* p1, const GEOLIB::Point* p2); + +/** + * compute a supporting plane (represented by plane_normal and the value d) for the polygon + * Let \f$n\f$ be the plane normal and \f$d\f$ a parameter. Then for all points \f$p \in R^3\f$ of the plane + * it holds \f$ n \cdot p + d = 0\f$ + * @param pnts points of a closed polyline describing a polygon + * @param plane_normal the normal of the plane the polygon is located in + * @param d parameter from the plane equation + */ +void getNewellPlane (const std::vector<GEOLIB::Point*>& pnts, MathLib::Vector &plane_normal, double& d); + +/** + * + * @param plane_normal + * @param pnts + */ +void rotatePointsToXY(MathLib::Vector &plane_normal, std::vector<GEOLIB::Point*> &pnts); + +bool isPointInTriangle (const GEOLIB::Point* p, + const GEOLIB::Point* a, const GEOLIB::Point* b, const GEOLIB::Point* c); + +/** + * test for intersections of the line segments of the Polyline + * @param ply the polyline + * @param idx0 beginning index of the first line segment that has an intersection + * @param idx1 beginning index of the second line segment that has an intersection + * @param intersection_pnt the intersection point if the line segments intersect + * @return true, if the polyline contains intersections + */ +bool lineSegmentsIntersect (const GEOLIB::Polyline* ply, size_t &idx0, size_t &idx1, GEOLIB::Point& intersection_pnt); + +/** + * A line segment is given by its two end-points. The function checks, + * if the two line segments (ab) and (cd) intersects. Up to now only + * 2D line segments are handled! + * @param a first end-point of the first line segment + * @param b second end-point of the first line segment + * @param c first end-point of the second line segment + * @param d second end-point of the second line segment + * @param s the intersection point + * @return true, if the line segments intersect, else false + */ +bool lineSegmentIntersect (const GEOLIB::Point& a, const GEOLIB::Point& b, + const GEOLIB::Point& c, const GEOLIB::Point& d, GEOLIB::Point& s); + +} // end namespace MathLib + +#endif /* MATHTOOLS_H_ */ diff --git a/MathLib/CMakeLists.txt b/MathLib/CMakeLists.txt index fc1bdefbc3ea8368cf5108a0fbd84988f487c716..d36ba1f15b63244666ee1fdc9ae93a904dae4073 100644 --- a/MathLib/CMakeLists.txt +++ b/MathLib/CMakeLists.txt @@ -1,22 +1,50 @@ # Source files SET( HEADERS + AnalyticalGeometry.h + LinearInterpolation.h + MathTools.h + Vector3.h + EarClippingTriangulation.h + LinkedTriangle.h + max.h + sparse.h + vector_io.h LinAlg/MatrixBase.h + LinAlg/VectorNorms.h + LinAlg/Dense/Matrix.h + LinAlg/Preconditioner/generateDiagPrecond.h + LinAlg/Solvers/LinearSolver.h + LinAlg/Solvers/DirectLinearSolver.h + LinAlg/Solvers/DenseDirectLinearSolver.h + LinAlg/Solvers/GaussAlgorithm.h + LinAlg/Solvers/TriangularSolve.h + LinAlg/Solvers/IterativeLinearSolver.h + LinAlg/Solvers/solver.h LinAlg/Sparse/amuxCRS.h LinAlg/Sparse/CRSMatrix.h LinAlg/Sparse/CRSMatrixPThreads.h LinAlg/Sparse/CRSMatrixOpenMP.h LinAlg/Sparse/CRSSymMatrix.h - sparse.h LinAlg/Sparse/SparseMatrixBase.h ) SET( SOURCES + AnalyticalGeometry.cpp + LinearInterpolation.cpp + MathTools.cpp + EarClippingTriangulation.cpp + LinkedTriangle.cpp LinAlg/Sparse/amuxCRS.cpp + LinAlg/Solvers/CG.cpp + LinAlg/Solvers/GaussAlgorithm.cpp + LinAlg/Solvers/TriangularSolve.cpp + LinAlg/Preconditioner/generateDiagPrecond.cpp ) INCLUDE_DIRECTORIES ( . - ${PROJECT_BINARY_DIR}/Base + ../Base + ../GeoLib ) # Create the library diff --git a/MathLib/EarClippingTriangulation.cpp b/MathLib/EarClippingTriangulation.cpp new file mode 100644 index 0000000000000000000000000000000000000000..45eb1fa5235506c7d2240fd8f5d4c7d495260f89 --- /dev/null +++ b/MathLib/EarClippingTriangulation.cpp @@ -0,0 +1,302 @@ +/* + * EarClippingTriangulation.cpp + * + * Created on: Feb 23, 2011 + * Author: TF + */ + +// STL +#include <vector> + +// BASELIB +#include "swap.h" +#include "printList.h" +#include "uniqueListInsert.h" + +// MathLib +#include "EarClippingTriangulation.h" + +namespace MathLib { + +EarClippingTriangulation::EarClippingTriangulation(const GEOLIB::Polygon* polygon, + std::list<GEOLIB::Triangle> &triangles, bool rot) +{ + copyPolygonPoints (polygon); + + if (rot) { + rotate (); + ensureCWOrientation (); + } + + initVertexList (); + initLists (); + clipEars (); + + std::vector<GEOLIB::Point*> const& ref_pnts_vec (polygon->getPointsVec()); + std::list<GEOLIB::Triangle>::const_iterator it (_triangles.begin()); + if (_original_orient == MathLib::CW) { + while (it != _triangles.end()) { + const size_t i0 (polygon->getPointID ((*it)[0])); + const size_t i1 (polygon->getPointID ((*it)[1])); + const size_t i2 (polygon->getPointID ((*it)[2])); + triangles.push_back (GEOLIB::Triangle (ref_pnts_vec, i0, i1, i2)); + it++; + } + } else { + size_t n_pnts (_pnts.size()-1); + while (it != _triangles.end()) { + const size_t i0 (polygon->getPointID (n_pnts-(*it)[0])); + const size_t i1 (polygon->getPointID (n_pnts-(*it)[1])); + const size_t i2 (polygon->getPointID (n_pnts-(*it)[2])); + triangles.push_back (GEOLIB::Triangle (ref_pnts_vec, i0, i1, i2)); + it++; + } + } +} + +EarClippingTriangulation::~EarClippingTriangulation() +{ + const size_t n_pnts (_pnts.size()); + for (size_t k(0); k<n_pnts; k++) { + delete _pnts[k]; + } +} + +void EarClippingTriangulation::copyPolygonPoints (const GEOLIB::Polygon* polygon) +{ + // copy points - last point is identical to the first + size_t n_pnts (polygon->getNumberOfPoints()-1); + for (size_t k(0); k < n_pnts; k++) { + _pnts.push_back (new GEOLIB::Point (*(polygon->getPoint(k)))); + } +} + +void EarClippingTriangulation::rotate () +{ + // calculate supporting plane + Vector plane_normal; + double d; + // compute the plane normal + getNewellPlane(_pnts, plane_normal, d); + + double tol (sqrt(std::numeric_limits<double>::min())); + if (fabs(plane_normal[0]) > tol || fabs(plane_normal[1]) > tol) { + // rotate copied points into x-y-plane + rotatePointsToXY(plane_normal, _pnts); + } + + for (size_t k(0); k<_pnts.size(); k++) + (*(_pnts[k]))[2] = 0.0; // should be -= d but there are numerical errors +} + +void EarClippingTriangulation::ensureCWOrientation () +{ + size_t n_pnts (_pnts.size()); + // get the left most upper point + size_t min_x_max_y_idx (0); // for orientation check + for (size_t k(0); k<n_pnts; k++) { + if ((*(_pnts[k]))[0] <= (*(_pnts[min_x_max_y_idx]))[0]) { + if ((*(_pnts[k]))[0] < (*(_pnts[min_x_max_y_idx]))[0]) { + min_x_max_y_idx = k; + } else { + if ((*(_pnts[k]))[1] > (*(_pnts[min_x_max_y_idx]))[1]) { + min_x_max_y_idx = k; + } + } + } + } + // determine orientation + if (0 < min_x_max_y_idx && min_x_max_y_idx < n_pnts-1) { + _original_orient = MathLib::getOrientation ( + _pnts[min_x_max_y_idx-1], _pnts[min_x_max_y_idx], _pnts[min_x_max_y_idx+1]); + } else { + if (0 == min_x_max_y_idx) { + _original_orient = MathLib::getOrientation (_pnts[n_pnts-1], _pnts[0], _pnts[1]); + } else { + _original_orient = MathLib::getOrientation (_pnts[n_pnts-2], _pnts[n_pnts-1], _pnts[0]); + } + } + if (_original_orient == MathLib::CCW) { + // switch orientation + for (size_t k(0); k<n_pnts/2; k++) { + BASELIB::swap (_pnts[k], _pnts[n_pnts-1-k]); + } + } +} + +bool EarClippingTriangulation::isEar(size_t v0, size_t v1, size_t v2) const +{ + for (std::list<size_t>::const_iterator it (_vertex_list.begin ()); + it != _vertex_list.end(); ++it) { + if (*it != v0 && *it != v1 && *it != v2) { + if (isPointInTriangle (_pnts[*it], _pnts[v0], _pnts[v1], _pnts[v2])) { + return false; + } + } + } + return true; +} + +void EarClippingTriangulation::initVertexList () +{ + size_t n_pnts (_pnts.size()); + for (size_t k(0); k<n_pnts; k++) _vertex_list.push_back (k); +} + +void EarClippingTriangulation::initLists () +{ + // go through points checking ccw, cw or collinear order and identifying ears + std::list<size_t>::iterator it (_vertex_list.begin()), prev(_vertex_list.end()), next; + prev--; + next = it; + next++; + MathLib::Orientation orientation; + while (next != _vertex_list.end()) { + orientation = getOrientation (_pnts[*prev], _pnts[*it], _pnts[*next]); + if (orientation == COLLINEAR) { + it = _vertex_list.erase (it); + next++; + } else { + if (orientation == CW) { + _convex_vertex_list.push_back (*it); + if (isEar (*prev, *it, *next)) + _ear_list.push_back (*it); + } + prev = it; + it = next; + next++; + } + } + + next = _vertex_list.begin(); + orientation = getOrientation (_pnts[*prev], _pnts[*it], _pnts[*next]); + if (orientation == COLLINEAR) { + it = _vertex_list.erase (it); + } + if (orientation == CW) { + _convex_vertex_list.push_back (*it); + if (isEar (*prev, *it, *next)) + _ear_list.push_back (*it); + } +} + +void EarClippingTriangulation::clipEars() +{ + std::list<size_t>::iterator it, prev, next; + // *** clip an ear + while (_vertex_list.size() > 3) { + // pop ear from list + size_t ear = _ear_list.front(); + _ear_list.pop_front(); + // remove ear tip from _convex_vertex_list + _convex_vertex_list.remove(ear); + + // remove ear from vertex_list, apply changes to _ear_list, _convex_vertex_list + bool nfound(true); + it = _vertex_list.begin(); + prev = _vertex_list.end(); + prev--; + while (nfound && it != _vertex_list.end()) { + if (*it == ear) { + nfound = false; + it = _vertex_list.erase(it); // remove ear tip + next = it; + if (next == _vertex_list.end()) { + next = _vertex_list.begin(); + prev = _vertex_list.end(); + prev--; + } + // add triangle + _triangles.push_back(GEOLIB::Triangle(_pnts, *prev, ear, *next)); + + // check the orientation of prevprev, prev, next + std::list<size_t>::iterator prevprev; + if (prev == _vertex_list.begin()) { + prevprev = _vertex_list.end(); + } else { + prevprev = prev; + } + prevprev--; + + // apply changes to _convex_vertex_list and _ear_list looking "backward" + MathLib::Orientation orientation = getOrientation(_pnts[*prevprev], _pnts[*prev], + _pnts[*next]); + if (orientation == CW) { + BASELIB::uniqueListInsert(_convex_vertex_list, *prev); + // prev is convex + if (isEar(*prevprev, *prev, *next)) { + // prev is an ear tip + BASELIB::uniqueListInsert(_ear_list, *prev); + } else { + // if necessary remove prev + _ear_list.remove(*prev); + } + } else { + // prev is not convex => reflex or collinear + _convex_vertex_list.remove(*prev); + _ear_list.remove(*prev); + if (orientation == COLLINEAR) { + prev = _vertex_list.erase(prev); + if (prev == _vertex_list.begin()) { + prev = _vertex_list.end(); + prev--; + } else { + prev--; + } + } + } + + // check the orientation of prev, next, nextnext + std::list<size_t>::iterator nextnext, + help_it(_vertex_list.end()); + help_it--; + if (next == help_it) { + nextnext = _vertex_list.begin(); + } else { + nextnext = next; + nextnext++; + } + + // apply changes to _convex_vertex_list and _ear_list looking "forward" + orientation = getOrientation(_pnts[*prev], _pnts[*next], + _pnts[*nextnext]); + if (orientation == CW) { + BASELIB::uniqueListInsert(_convex_vertex_list, *next); + // next is convex + if (isEar(*prev, *next, *nextnext)) { + // next is an ear tip + BASELIB::uniqueListInsert(_ear_list, *next); + } else { + // if necessary remove *next + _ear_list.remove(*next); + } + } else { + // next is not convex => reflex or collinear + _convex_vertex_list.remove(*next); + _ear_list.remove(*next); + if (orientation == COLLINEAR) { + next = _vertex_list.erase(next); + if (next == _vertex_list.end()) + next = _vertex_list.begin(); + } + } + } else { + prev = it; + it++; + } + } + + } + // add last triangle + next = _vertex_list.begin(); + prev = next; + next++; + it = next; + next++; + if (getOrientation(_pnts[*prev], _pnts[*it], _pnts[*next]) == CCW) + _triangles.push_back(GEOLIB::Triangle(_pnts, *prev, *next, *it)); + else + _triangles.push_back(GEOLIB::Triangle(_pnts, *prev, *it, *next)); +} + +} // end namespace MathLib diff --git a/MathLib/EarClippingTriangulation.h b/MathLib/EarClippingTriangulation.h new file mode 100644 index 0000000000000000000000000000000000000000..77b8e6000fc17dbbadffd735d8e685324e63e07c --- /dev/null +++ b/MathLib/EarClippingTriangulation.h @@ -0,0 +1,59 @@ +/* + * EarClippingTriangulation.h + * + * Created on: Feb 23, 2011 + * Author: TF + */ + +#ifndef EARCLIPPINGTRIANGULATION_H_ +#define EARCLIPPINGTRIANGULATION_H_ + +// STL +#include <list> + +// GEOLIB +#include "Polygon.h" +#include "Triangle.h" + +// MathLib +#include "AnalyticalGeometry.h" + +namespace MathLib { + +class EarClippingTriangulation { +public: + EarClippingTriangulation(const GEOLIB::Polygon* ply, std::list<GEOLIB::Triangle> &triangles, bool rot = true); + virtual ~EarClippingTriangulation(); +private: + /** + * copies the points of the polygon to the vector _pnts + */ + inline void copyPolygonPoints (const GEOLIB::Polygon* polygon); + inline void rotate (); + inline void ensureCWOrientation (); + + inline bool isEar(size_t v0, size_t v1, size_t v2) const; + + inline void initVertexList (); + inline void initLists (); + inline void clipEars (); + + /** + * a copy of the polygon points + */ + std::vector<GEOLIB::Point*> _pnts; + std::list<size_t> _vertex_list; + std::list<size_t> _convex_vertex_list; + std::list<size_t> _ear_list; + + /** + * triangles of the triangulation (maybe in the wrong orientation) + */ + std::list<GEOLIB::Triangle> _triangles; + + MathLib::Orientation _original_orient; +}; + +} // end namespace MathLib + +#endif /* EARCLIPPINGTRIANGULATION_H_ */ diff --git a/MathLib/LinAlg/Dense/Matrix.h b/MathLib/LinAlg/Dense/Matrix.h new file mode 100644 index 0000000000000000000000000000000000000000..d0a97fb5e087667095f0ad33ef878c8337e09bd3 --- /dev/null +++ b/MathLib/LinAlg/Dense/Matrix.h @@ -0,0 +1,291 @@ +/* + * \file Matrix.h + * + * Created on: Mar 24, 2010 + * Author: TF + * modified on:Jul 13, 2010 + * HS & ZC + */ + +#ifndef MATRIX_H +#define MATRIX_H + +#include <new> +#include <exception> +#include <stdexcept> +#include <iostream> + +namespace MathLib { + +/** + * Matrix represents a dense matrix for a numeric data type. + */ +template <class T> class Matrix +{ +public: + Matrix (size_t rows, size_t cols); + Matrix (size_t rows, size_t cols, const T& val); + Matrix (const Matrix &src); + + ~Matrix (); + + size_t getNRows () const { return nrows; } + size_t getNCols () const { return ncols; } + /** + * \f$ y = \alpha \cdot A x + \beta y\f$ + */ + void axpy ( T alpha, const T* x, T beta, T* y) const; + + /** + * Matrix vector multiplication + * @param x + * @return + */ + T* operator* (const T *x) const; + /** + * Matrix matrix addition. + * @param mat + * @return + */ + Matrix<T>* operator+ (const Matrix<T>& mat) const throw (std::range_error); + /** + * Matrix matrix subtraction + * @param mat + * @return + */ + Matrix<T>* operator- (const Matrix<T>& mat) const throw (std::range_error); + + /** + * Matrix matrix multiplication \f$ C = A \cdot B\f$ + * @param mat the matrix \f$ B \f$ + * @return the matrix \f$ C \f$ + */ + Matrix<T>* operator* (const Matrix<T>& mat) const throw (std::range_error); + + /** + * matrix transpose + * @return the transpose of the matrix + */ + Matrix<T>* transpose() const; // HB & ZC + + Matrix<T>* getSubMatrix (size_t b_row, size_t b_col, size_t e_row, size_t e_col) const throw (std::range_error); + + /** + * overwrites values of the matrix with the given sub matrix + * @param b_row the first row + * @param b_col the first column + * @param sub_mat the sub matrix + */ + void setSubMatrix (size_t b_row, size_t b_col, const Matrix<T>& sub_mat) throw (std::range_error); + + inline T & operator() (size_t row, size_t col) throw (std::range_error); + inline T & operator() (size_t row, size_t col) const throw (std::range_error); + + /** + * writes the matrix entries into the output stream + * @param out the output stream + */ + void write (std::ostream& out) const; + + T const* getData () { return data; } + +private: + // zero based addressing, but Fortran storage layout + //inline size_t address(size_t i, size_t j) const { return j*rows+i; }; + // zero based addressing, C storage layout + inline size_t address(size_t i, size_t j) const { return i*ncols+j; }; + + size_t nrows; + size_t ncols; + T *data; +}; + +template<class T> Matrix<T>::Matrix (size_t rows, size_t cols) + : nrows (rows), ncols (cols), data (new T[nrows*ncols]) +{} + +template<class T> Matrix<T>::Matrix (const Matrix& src) : + nrows (src.getNRows ()), ncols (src.getNCols ()), data (new T[nrows * ncols]) +{ + for (size_t i = 0; i < nrows; i++) + for (size_t j = 0; j < ncols; j++) + data[address(i,j)] = src (i, j); +} + +template <class T> Matrix<T>::~Matrix () +{ + delete [] data; +} + +template<class T> void Matrix<T>::axpy ( T alpha, const T* x, T beta, T* y) const +{ + for (size_t i(0); i<nrows; i++) { + y[i] += beta * y[i]; + for (size_t j(0); j<ncols; j++) { + y[i] += alpha * data[address(i,j)] * x[j]; + } + } +} + +template<class T> T* Matrix<T>::operator* (const T *x) const +{ + T *y (new T[nrows]); + for (size_t i(0); i < nrows; i++) { + y[i] = 0.0; + for (size_t j(0); j < ncols; j++) { + y[i] += data[address(i, j)] * x[j]; + } + } + + return y; +} + +// HS initial implementation +template<class T> Matrix<T>* Matrix<T>::operator+ (const Matrix<T>& mat) const throw (std::range_error) +{ + // make sure the two matrices have the same dimension. + if (nrows != mat.getNRows() || ncols != mat.getNCols()) + throw std::range_error("Matrix::operator+, illegal matrix size!"); + + Matrix<T>* y(new Matrix<T> (nrows, ncols)); + for (size_t i = 0; i < nrows; i++) { + for (size_t j = 0; j < ncols; j++) { + (*y)(i, j) = data[address(i, j)] + mat(i, j); + } + } + + return y; +} + +// HS initial implementation +template<class T> Matrix<T>* Matrix<T>::operator- (const Matrix<T>& mat) const throw (std::range_error) +{ + // make sure the two matrices have the same dimension. + if (nrows != mat.getNRows() || ncols != mat.getNCols()) + throw std::range_error("Matrix::operator-, illegal matrix size!"); + + Matrix<T>* y(new Matrix<T> (nrows, ncols)); + for (size_t i = 0; i < nrows; i++) { + for (size_t j = 0; j < ncols; j++) { + (*y)(i, j) = data[address(i, j)] - mat(i, j); + } + } + + return y; +} + +// HS initial implementation +template<class T> Matrix<T>* Matrix<T>::operator* (const Matrix<T>& mat) const throw (std::range_error) +{ + // make sure the two matrices have the same dimension. + if (ncols != mat.getNRows()) + throw std::range_error( + "Matrix::operator*, number of rows and cols should be the same!"); + + size_t y_cols(mat.getNCols()); + Matrix<T>* y(new Matrix<T> (nrows, y_cols, T(0))); + + for (size_t i = 0; i < nrows; i++) { + for (size_t j = 0; j < y_cols; j++) { + for (size_t k = 0; k < ncols; k++) + (*y)(i, j) += data[address(i, k)] * mat(k, j); + } + } + + return y; +} + +// HS initial implementation +template<class T> Matrix<T>* Matrix<T>::transpose() const +{ + Matrix<T>* y(new Matrix<T> (ncols, nrows)); + + for (size_t i = 0; i < nrows; i++) { + for (size_t j = 0; j < ncols; j++) { +// y->data[y->address(j, i)] = data[address(i, j)]; + (*y)(j,i) = data[address(i, j)]; + } + } + return y; +} + +template<class T> Matrix<T>* Matrix<T>::getSubMatrix( + size_t b_row, size_t b_col, + size_t e_row, size_t e_col) const throw (std::range_error) +{ + if (b_row >= e_row | b_col >= e_col) + throw std::range_error ("Matrix::getSubMatrix() illegal sub matrix"); + if (e_row > nrows | e_col > ncols) + throw std::range_error ("Matrix::getSubMatrix() illegal sub matrix"); + + Matrix<T>* y(new Matrix<T> (e_row-b_row, e_col-b_col)); + for (size_t i=b_row; i<e_row; i++) { + for (size_t j=b_col; j<e_col; j++) { + (*y)(i-b_row, j-b_col) = data[address(i, j)]; + } + } + return y; +} + +template<class T> void Matrix<T>::setSubMatrix( + size_t b_row, size_t b_col, const Matrix<T>& sub_mat) throw (std::range_error) +{ + if (b_row + sub_mat.getNRows() > nrows | b_col + sub_mat.getNCols() > ncols) + throw std::range_error ("Matrix::setSubMatrix() sub matrix to big"); + + for (size_t i=0; i<sub_mat.getNRows(); i++) { + for (size_t j=0; j<sub_mat.getNCols(); j++) { + data[address(i+b_row, j+b_col)] = sub_mat(i,j); + } + } +} + +template<class T> T& Matrix<T>::operator() (size_t row, size_t col) + throw (std::range_error) +{ + if ( (row >= nrows) | ( col >= ncols) ) + throw std::range_error ("Matrix: op() const range error"); + return data [address(row,col)]; +} + + +template<class T> T& Matrix<T>::operator() (size_t row, size_t col) const + throw (std::range_error) +{ + if ( (row >= nrows) | ( col >= ncols) ) + throw std::range_error ("Matrix: op() const range error"); + return data [address(row,col)]; +} + +template <class T> void Matrix<T>::write (std::ostream &out) const +{ + for (size_t i = 0; i < nrows; i++) { + for (size_t j = 0; j < ncols; j++) { + out << data[address(i, j)] << "\t"; + } + out << std::endl; + } +} + +template <class T> T sqrFrobNrm (const Matrix<T> &mat) +{ + T nrm ((T)(0)); + size_t i,j; + for (j=0; j<mat.getNCols(); j++) + for (i=0; i<mat.getNRows(); i++) + nrm += mat(i,j) * mat(i,j); + + return nrm; +} + +/** overload the output operator for class Matrix */ +template <class T> +std::ostream& operator<< (std::ostream &os, const Matrix<T> &mat) +{ + mat.write (os); + return os; +} + +} // end namespace MathLib + +#endif diff --git a/MathLib/LinAlg/Preconditioner/generateDiagPrecond.cpp b/MathLib/LinAlg/Preconditioner/generateDiagPrecond.cpp index 4b52b83107b747b9cce5cd3bf43c64ff9bfd89c3..27ca8967a9d4839d8439913e34c9f1aa8d473d0a 100644 --- a/MathLib/LinAlg/Preconditioner/generateDiagPrecond.cpp +++ b/MathLib/LinAlg/Preconditioner/generateDiagPrecond.cpp @@ -1,6 +1,8 @@ #include "sparse.h" -bool generateDiagPrecond (unsigned n, double* A, unsigned* jA, unsigned* iA, +namespace MathLib { + +bool generateDiagPrecond (unsigned n, unsigned* iA, unsigned* jA, double* A, double* diag) { unsigned idx; // first idx of next row @@ -26,4 +28,4 @@ bool generateDiagPrecond (unsigned n, double* A, unsigned* jA, unsigned* iA, return true; } - +} // end namespace MathLib diff --git a/MathLib/LinAlg/Preconditioner/generateDiagPrecond.h b/MathLib/LinAlg/Preconditioner/generateDiagPrecond.h new file mode 100644 index 0000000000000000000000000000000000000000..66f7989650d4f24960fe4a60a975ffa53c7ae588 --- /dev/null +++ b/MathLib/LinAlg/Preconditioner/generateDiagPrecond.h @@ -0,0 +1,17 @@ +/* + * generateDiagPrecond.h + * + * Created on: Sep 28, 2011 + * Author: TF + */ + +#ifndef GENERATEDIAGPRECOND_H_ +#define GENERATEDIAGPRECOND_H_ + +namespace MathLib { + +bool generateDiagPrecond (unsigned n, unsigned* iA, unsigned* jA, double* A, double* diag); + +} // end namespace MathLib + +#endif /* PRECONDITIONER_H_ */ diff --git a/MathLib/LinAlg/Solvers/CG.cpp b/MathLib/LinAlg/Solvers/CG.cpp index 50cab766b9b6ea4c0cacb2620a3353b740bb155b..05c2f1d977f0943cf644b04b4473a172c4e55c39 100644 --- a/MathLib/LinAlg/Solvers/CG.cpp +++ b/MathLib/LinAlg/Solvers/CG.cpp @@ -12,10 +12,6 @@ #include "../Sparse/CRSMatrix.h" #include "../Sparse/CRSMatrixDiagPrecond.h" -#ifndef NDEBUG -#include <iostream> -#endif - // CG solves the symmetric positive definite linear // system Ax=b using the Conjugate Gradient method. // @@ -37,12 +33,12 @@ unsigned CG(CRSMatrix<double> const * mat, double const * const b, unsigned N = mat->getNRows(); double *p, *q, *r, *rhat, rho, rho1 = 0.0; - p = new double[4* N ]; + p = new double[4* N]; q = p + N; r = q + N; rhat = r + N; - double nrmb = sqrt(scpr(N, b, b, num_threads)); + double nrmb = sqrt(scpr(b, b, N)); if (nrmb < std::numeric_limits<double>::epsilon()) { blas::setzero(N, x); eps = 0.0; @@ -58,18 +54,15 @@ unsigned CG(CRSMatrix<double> const * mat, double const * const b, } double resid = blas::nrm2(N, r); - out << "0\t" << resid / nrmb << std::endl; if (resid <= eps * nrmb) { eps = resid / nrmb; nsteps = 0; delete[] p; - out.close(); return 0; } for (unsigned l = 1; l <= nsteps; ++l) { - out << l << "\t" << resid / nrmb << std::endl; #ifndef NDEBUG std::cout << "Step " << l << ", resid=" << resid / nrmb << std::endl; #endif @@ -97,7 +90,7 @@ unsigned CG(CRSMatrix<double> const * mat, double const * const b, mat->amux(D_ONE, p, q); // alpha = rho / p*q - double alpha = rho / scpr(N, p, q); + double alpha = rho / scpr(p, q, N); // x += alpha * p blas::axpy(N, alpha, p, x); @@ -105,7 +98,7 @@ unsigned CG(CRSMatrix<double> const * mat, double const * const b, // r -= alpha * q blas::axpy(N, -alpha, q, r); - resid = sqrt(scpr(N, r, r)); + resid = sqrt(scpr(r, r, N)); if (resid <= eps * nrmb) { eps = resid / nrmb; @@ -116,7 +109,6 @@ unsigned CG(CRSMatrix<double> const * mat, double const * const b, rho1 = rho; } - out.close(); eps = resid / nrmb; delete[] p; return 1; diff --git a/MathLib/LinAlg/Solvers/CG.h b/MathLib/LinAlg/Solvers/CG.h index 5cf6dbf38d1f4017647edb3964e9176de18acaf5..36cd6917402f478be69b95e0bc1f90878894dc9e 100644 --- a/MathLib/LinAlg/Solvers/CG.h +++ b/MathLib/LinAlg/Solvers/CG.h @@ -1,130 +1,21 @@ /* - * CG.h + * solver.h * * Created on: Sep 27, 2011 * Author: TF */ -#include "blas.h" -#include "CG.h" -#include <limits> -#include "CRSMatrix.h" -#include "CRSMatrixDiagPrecond.h" -#include "sparse.h" +#ifndef CG_H_ +#define CG_H_ -#include <fstream> - -#ifndef NDEBUG -#include <iostream> -#endif - -// CG solves the symmetric positive definite linear -// system Ax=b using the Conjugate Gradient method. -// -// The return value indicates convergence within max_iter (input) -// iterations (0), or no convergence within max_iter iterations (1). -// -// Upon successful return, output arguments have the following values: -// -// x -- approximate solution to Ax = b -// nsteps -- the number of iterations performed before the -// tolerance was reached -// eps -- the residual after the final iteration +namespace MathLib { +// forward declaration +template <typename T> class CRSMatrix; unsigned CG(CRSMatrix<double> const * mat, double const * const b, - double* const x, double& eps, unsigned& nsteps, unsigned num_threads) -{ - unsigned N = mat->getNRows(); - double *p, *q, *r, *rhat, rho, rho1 = 0.0; - - p = new double[4*N]; - q = p + N; - r = q + N; - rhat = r + N; - - double nrmb = sqrt(scpr(N, b, b, num_threads)); - if (nrmb < std::numeric_limits<double>::epsilon()) { - blas::setzero(N, x); - eps = 0.0; - nsteps = 0; - delete [] p; - return 0; - } - - // r0 = b - Ax0 - mat->amux (D_MONE, x, r); - for (unsigned k(0); k<N; k++) { - r[k] = b[k] - r[k]; - } - - std::ofstream out ("residuen.txt"); - - double resid = blas::nrm2(N, r); - out << "0\t" << resid/nrmb << std::endl; - if (resid <= eps*nrmb) { - eps = resid / nrmb; - nsteps = 0; - delete [] p; - out.close(); - return 0; - } - - for (unsigned l=1; l<=nsteps; ++l) { - - out << l << "\t" << resid/nrmb << std::endl; -#ifndef NDEBUG - std::cout << "Step " << l << ", resid=" << resid/nrmb << std::endl; -#endif - - // r^ = C r - blas::copy(N, r, rhat); - mat->precondApply(rhat); - - // rho = r * r^; - rho = scpr(N, r, rhat, num_threads); - - if (l>1) { - double beta = rho / rho1; - // p = r^ + beta * p - unsigned k; - omp_set_num_threads (num_threads); - #pragma omp parallel for - for(k=0; k<N; k++) { - p[k] = rhat[k] + beta * p[k]; - } - } - else - blas::copy(N, rhat, p); - - // q = Ap - blas::setzero(N, q); - mat->amux (D_ONE, p, q); - - // alpha = rho / p*q - double alpha = rho / scpr(N, p, q); - - // x += alpha * p - blas::axpy(N, alpha, p, x); - - // r -= alpha * q - blas::axpy(N, -alpha, q, r); - - resid = sqrt(scpr(N,r,r)); - - if (resid<=eps*nrmb) { - eps = resid/nrmb; - nsteps = l; - delete [] p; - return 0; - } - - rho1 = rho; - } - out.close(); - eps = resid / nrmb; - delete [] p; - return 1; -} + double* const x, double& eps, unsigned& nsteps, unsigned num_threads = 1); +} // end namespace MathLib +#endif /* SOLVER_H_ */ diff --git a/MathLib/LinAlg/Solvers/DenseDirectLinearSolver.h b/MathLib/LinAlg/Solvers/DenseDirectLinearSolver.h new file mode 100644 index 0000000000000000000000000000000000000000..3ef0205c502fc07d7b133515a933f7fe1c504493 --- /dev/null +++ b/MathLib/LinAlg/Solvers/DenseDirectLinearSolver.h @@ -0,0 +1,23 @@ +/* + * DenseDirectLinearSolver.h + * + * Created on: Jan 7, 2011 + * Author: TF + */ + +#ifndef DENSEDIRECTLINEARSOLVER_H_ +#define DENSEDIRECTLINEARSOLVER_H_ + +#include "DirectLinearSolver.h" + +namespace MathLib { + +class DenseDirectLinearSolver: public MathLib::DirectLinearSolver { +public: + DenseDirectLinearSolver() {}; + virtual ~DenseDirectLinearSolver() {}; +}; + +} + +#endif /* DENSEDIRECTLINEARSOLVER_H_ */ diff --git a/MathLib/LinAlg/Solvers/DirectLinearSolver.h b/MathLib/LinAlg/Solvers/DirectLinearSolver.h new file mode 100644 index 0000000000000000000000000000000000000000..46daf3b2f4f20eebe85b60c8d9821dde345f0e95 --- /dev/null +++ b/MathLib/LinAlg/Solvers/DirectLinearSolver.h @@ -0,0 +1,24 @@ +/* + * DirectLinearSolver.h + * + * Created on: Jan 7, 2011 + * Author: TF + */ + +#ifndef DIRECTLINEARSOLVER_H_ +#define DIRECTLINEARSOLVER_H_ + +#include "LinearSolver.h" + +namespace MathLib { + +class DirectLinearSolver : public MathLib::LinearSolver +{ +public: + DirectLinearSolver() {}; + virtual ~DirectLinearSolver() {}; +}; + +} + +#endif /* DIRECTLINEARSOLVER_H_ */ diff --git a/MathLib/LinAlg/Solvers/GaussAlgorithm.cpp b/MathLib/LinAlg/Solvers/GaussAlgorithm.cpp new file mode 100644 index 0000000000000000000000000000000000000000..98007abaf93e22fa66e300f39ee437970208353b --- /dev/null +++ b/MathLib/LinAlg/Solvers/GaussAlgorithm.cpp @@ -0,0 +1,66 @@ +/* + * GaussAlgorithm.cpp + * + * Created on: May 6, 2010 + * Author: TF + */ + +#include <cmath> +#include "GaussAlgorithm.h" +#include "swap.h" + +namespace MathLib { + +GaussAlgorithm::GaussAlgorithm (Matrix <double> &A) : + _mat (A), _n(_mat.getNRows()), _perm (new size_t [_n]) +{ + size_t k, i, j, nr (_mat.getNRows()), nc(_mat.getNCols()); + double l; + + for (k=0; k<nc; k++) { + // search pivot + double t = fabs(_mat(k, k)); + _perm[k] = k; + for (i=k+1; i<nr; i++) { + if (fabs(_mat(i,k)) > t) { + t = _mat(i,k); + _perm[k] = i; + } + } + + // exchange rows + if (_perm[k] != k) { + for (j=0; j<nc; j++) BASELIB::swap (_mat(_perm[k],j), _mat(k,j)); + } + + // eliminate + for (i=k+1; i<nr; i++) { + l=_mat(i,k)/_mat(k,k); + for (j=k; j<nc; j++) { + _mat(i,j) -= _mat(k,j) * l; + } + _mat(i,k) = l; + } + } +} + +GaussAlgorithm::~GaussAlgorithm() +{ + delete [] _perm; +} + +void GaussAlgorithm::execute (double *b) const +{ + permuteRHS (b); + forwardSolve (_mat, b); // L z = b, b will be overwritten by z + backwardSolve (_mat, b); // U x = z, b (z) will be overwritten by x +} + +void GaussAlgorithm::permuteRHS (double* b) const +{ + for (size_t i=0; i<_n; i++) { + if (_perm[i] != i) BASELIB::swap(b[i], b[_perm[i]]); + } +} + +} // end namespace MathLib diff --git a/MathLib/LinAlg/Solvers/GaussAlgorithm.h b/MathLib/LinAlg/Solvers/GaussAlgorithm.h new file mode 100644 index 0000000000000000000000000000000000000000..ad1422593965c248090086d97fd6717b0550a62c --- /dev/null +++ b/MathLib/LinAlg/Solvers/GaussAlgorithm.h @@ -0,0 +1,74 @@ +/* + * GaussAlgorithm.h + * + * Created on: May 6, 2010 + * Author: TF + */ + +#ifndef GAUSSALGORITHM_H_ +#define GAUSSALGORITHM_H_ + +#include <cstddef> +#include "../Dense/Matrix.h" +#include "DenseDirectLinearSolver.h" +#include "TriangularSolve.h" + +namespace MathLib { + +/** + * This is a class for the direct solution of (dense) systems of + * linear equations, \f$A x = b\f$. During the construction of + * the object the matrix A is factorized in matrices L and U using + * Gauss-Elimination with partial pivoting (rows are exchanged). In doing so + * the entries of A change! The solution for a specific + * right hand side is computed by the method execute(). + */ +class GaussAlgorithm : public MathLib::DenseDirectLinearSolver { +public: + /** + * A direct solver for the (dense) linear system \f$A x = b\f$. + * @param A at the beginning the matrix A, at the end of the construction + * of the object the matrix contains the factor L (without the diagonal) + * in the strictly lower part and the factor U in the upper part. + * The diagonal entries of L are all 1.0 and are not explicitly stored. + * Attention: the given matrix will be destroyed! + * @return a object of type GaussAlgorithm + */ + GaussAlgorithm(Matrix<double> &A); + /** + * destructor, deletes the permutation + */ + ~GaussAlgorithm(); + + /** + * Method solves the linear system \f$A x = b\f$ (based on the LU factorization) + * using forward solve and backward solve + * @param b at the beginning the right hand side, at the end the solution + */ + void execute (double *b) const; + +private: + /** + * permute the right hand side vector according to the + * row permutations of the LU factorization + * @param b the entries of the vector b are permuted + */ + void permuteRHS (double* b) const; + + /** + * a reference to the matrix + */ + Matrix<double>& _mat; + /** + * the size of the matrix + */ + size_t _n; + /** + * the permutation of the rows + */ + size_t* _perm; +}; + +} // end namespace MathLib + +#endif /* GAUSSALGORITHM_H_ */ diff --git a/MathLib/LinAlg/Solvers/IterativeLinearSolver.h b/MathLib/LinAlg/Solvers/IterativeLinearSolver.h new file mode 100644 index 0000000000000000000000000000000000000000..6e8b9e39202287f5d31da85591a23f45e2a89d11 --- /dev/null +++ b/MathLib/LinAlg/Solvers/IterativeLinearSolver.h @@ -0,0 +1,23 @@ +/* + * IterativeLinearSolver.h + * + * Created on: Jan 7, 2011 + * Author: TF + */ + +#ifndef ITERATIVELINEARSOLVER_H_ +#define ITERATIVELINEARSOLVER_H_ + +#include <LinearSolver.h> + +namespace MathLib { + +class IterativeLinearSolver: public MathLib::LinearSolver { +public: + IterativeLinearSolver() {}; + virtual ~IterativeLinearSolver() {}; +}; + +} + +#endif /* ITERATIVELINEARSOLVER_H_ */ diff --git a/MathLib/LinAlg/Solvers/LinearSolver.h b/MathLib/LinAlg/Solvers/LinearSolver.h new file mode 100644 index 0000000000000000000000000000000000000000..1264649dc08598cad631767856a48ad77fb05264 --- /dev/null +++ b/MathLib/LinAlg/Solvers/LinearSolver.h @@ -0,0 +1,24 @@ +/* + * LinearSolver.h + * + * Created on: Jan 7, 2011 + * Author: TF + */ + +#ifndef LINEARSOLVER_H_ +#define LINEARSOLVER_H_ + +namespace MathLib { + +/** + * Base class for all linear solver classes. + */ +class LinearSolver { +public: + LinearSolver() {}; + virtual ~LinearSolver() {}; +}; + +} + +#endif /* LINEARSOLVER_H_ */ diff --git a/MathLib/LinAlg/Solvers/TriangularSolve.cpp b/MathLib/LinAlg/Solvers/TriangularSolve.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8fbfb5e3306162eacb258cafb8f74a85576bdd6e --- /dev/null +++ b/MathLib/LinAlg/Solvers/TriangularSolve.cpp @@ -0,0 +1,53 @@ +/* + * TriangularSolve.cpp + * + * Created on: May 5, 2010 + * Author: TF + */ + +#include "../Dense/Matrix.h" + +namespace MathLib { + +void forwardSolve (const Matrix <double> &L, double* b) +{ + size_t m (L.getNRows()); + double t; + + for (size_t r=0; r<m; r++) { + t = 0.0; + for (size_t c=0; c<r; c++) { + t += L(r,c)*b[c]; + } + b[r] = b[r]-t; + } +} + +void backwardSolve (const Matrix <double> &mat, double* b) +{ + double t; + size_t m (mat.getNRows()), n(mat.getNCols()); + for (int r=m-1; r>=0; r--) { + t = 0.0; + for (size_t c=r+1; c<n; c++) { + t += mat(r,c)*b[c]; + } + b[r] = (b[r]-t) / mat(r,r); + } +} + +void backwardSolve ( Matrix<double> const& mat, double* x, double* b) +{ + size_t n_cols (mat.getNCols()); + for (int r = (n_cols - 1); r >= 0; r--) { + double t = 0.0; + + for (size_t c = r+1; c < n_cols; c++) { + t += mat(r,c) * b[c]; + } + x[r] = (b[r] - t) / mat(r, r); + } +} + + +} // end namespace MathLib diff --git a/MathLib/LinAlg/Solvers/TriangularSolve.h b/MathLib/LinAlg/Solvers/TriangularSolve.h new file mode 100644 index 0000000000000000000000000000000000000000..d7cd92664327f7e5246d905e3771da000c35d70b --- /dev/null +++ b/MathLib/LinAlg/Solvers/TriangularSolve.h @@ -0,0 +1,43 @@ +/* + * TriangularSolve.h + * + * Created on: May 6, 2010 + * Author: TF + */ + +#ifndef TRIANGULARSOLVE_H_ +#define TRIANGULARSOLVE_H_ + +#include "../Dense/Matrix.h" + +namespace MathLib { + +/** + * solves the \f$n \times n\f$ triangular linear system \f$L \cdot y = b\f$, + * assumes \f$L_{ii} = 1.0\f$, \f$i=1,...,n\f$, \f$b\f$ is destroyed + * @param L the lower triangular matrix + * @param b at beginning the right hand side vector, at the end the solution vector + */ +void forwardSolve (const Matrix <double> &L, double* b); + +/** + * solves the \f$n \times n\f$ triangular linear system \f$U \cdot x=y\f$, + * \f$U\f$, where \f$U\f$ is a upper triangular matrix. + * @param U upper triangular matrix + * @param y at beginning the right hand side, at the end the solution + */ +void backwardSolve (const Matrix <double> &U, double* y); + +// backwardSolve mat * x = y, mat ... upper triangular matrix +/** + * backward solve the system of linear equations \f$ U \cdot x = y\f$, + * where \f$U\f$ is a upper triangular matrix + * @param mat the upper triangular matrix + * @param x the solution of the system of linear equations + * @param b the right hand side + */ +void backwardSolve ( Matrix<double> const& mat, double* x, double* b); + +} // end namespace MathLib + +#endif /* TRIANGULARSOLVE_H_ */ diff --git a/MathLib/LinAlg/Solvers/blas.h b/MathLib/LinAlg/Solvers/blas.h index 231042bc9e3c2a26abd01a51777837ef7136740d..81513665b20ac717de6ea18beea5cee3423339fd 100644 --- a/MathLib/LinAlg/Solvers/blas.h +++ b/MathLib/LinAlg/Solvers/blas.h @@ -1,9 +1,8 @@ #ifndef BLAS_H #define BLAS_H -#include <assert.h> -#include <stdlib.h> - +#include <cassert> +#include <cstdlib> #include <cmath> #define SIGN(a) ((a) >= 0 ? 1.0 : -1.0) @@ -303,13 +302,13 @@ namespace blas // inline void conj(unsigned n, double* v) {} // inline void conj(unsigned n, float* v) {} - inline void swap(const unsigned n, double* x, const unsigned incx, + inline void swap(const unsigned n, double* x, const unsigned incx, double* y, const unsigned incy ) { dswap_(&n, x, &incx, y, &incy); } - inline void swap(const unsigned n, float* x, const unsigned incx, + inline void swap(const unsigned n, float* x, const unsigned incx, float* y, const unsigned incy ) { sswap_(&n, x, &incx, y, &incy); @@ -499,7 +498,7 @@ namespace blas // y = d Ax - inline void gemv(const unsigned m, const unsigned n, double d, + inline void gemv(const unsigned m, const unsigned n, double d, const double* A, double *x, double *y) { dgemv_(JOB_STR, &m, &n, &d, A, &m, x, &N_ONE, &D_ZERO, y, &N_ONE); @@ -582,16 +581,16 @@ namespace blas } // C = d A B, A is m x p, B is p x n - inline void gemm(const unsigned m, const unsigned p, const unsigned n, - const double d, const double* const A, const unsigned ldA, + inline void gemm(const unsigned m, const unsigned p, const unsigned n, + const double d, const double* const A, const unsigned ldA, const double* const B, const unsigned ldB, double* C, const unsigned ldC) { dgemm_(JOB_STR, JOB_STR, &m, &n, &p, &d, A, &ldA, B, &ldB, &D_ZERO, C, &ldC); } - inline void gemm(const unsigned m, const unsigned p, const unsigned n, - const float d, const float* const A, const unsigned ldA, + inline void gemm(const unsigned m, const unsigned p, const unsigned n, + const float d, const float* const A, const unsigned ldA, const float* const B, const unsigned ldB, float* C, const unsigned ldC) { @@ -600,16 +599,16 @@ namespace blas } // C += d A B, A is m x p, B is p x n - inline void gemma(const unsigned m, const unsigned p, const unsigned n, - const double d, const double* const A, const unsigned ldA, + inline void gemma(const unsigned m, const unsigned p, const unsigned n, + const double d, const double* const A, const unsigned ldA, const double* const B, const unsigned ldB, double* C, const unsigned ldC) { dgemm_(JOB_STR, JOB_STR, &m, &n, &p, &d, A, &ldA, B, &ldB, &D_ONE, C, &ldC); } - inline void gemma(const unsigned m, const unsigned p, const unsigned n, - const float d, const float* const A, const unsigned ldA, + inline void gemma(const unsigned m, const unsigned p, const unsigned n, + const float d, const float* const A, const unsigned ldA, const float* const B, const unsigned ldB, float* C, const unsigned ldC) { @@ -618,16 +617,16 @@ namespace blas } // C = d A^H B, A is m x p, B is m x n - inline void gemhm(const unsigned m, const unsigned p, const unsigned n, - const double d, const double* A, const unsigned ldA, + inline void gemhm(const unsigned m, const unsigned p, const unsigned n, + const double d, const double* A, const unsigned ldA, const double *B, const unsigned ldB, double* C, const unsigned ldC) { dgemm_(JOB_STR+1, JOB_STR, &p, &n, &m, &d, A, &ldA, B, &ldB, &D_ZERO, C, &ldC); } - inline void gemhm(const unsigned m, const unsigned p, const unsigned n, - const float d, const float* const A, const unsigned ldA, + inline void gemhm(const unsigned m, const unsigned p, const unsigned n, + const float d, const float* const A, const unsigned ldA, const float* const B, const unsigned ldB, float* C, const unsigned ldC) { @@ -637,14 +636,14 @@ namespace blas // C += d A^H B, A is m x p, B is m x n inline void gemhma(unsigned m, unsigned p, unsigned n, double d, - const double* const A, const unsigned ldA, const double* const B, + const double* const A, const unsigned ldA, const double* const B, const unsigned ldB, double* C, unsigned ldC) { dgemm_(JOB_STR+1, JOB_STR, &p, &n, &m, &d, A, &ldA, B, &ldB, &D_ONE, C, &ldC); } inline void gemhma(unsigned m, unsigned p, unsigned n, float d, - const float* const A, const unsigned ldA, const float* const B, + const float* const A, const unsigned ldA, const float* const B, const unsigned ldB, float* C, unsigned ldC) { sgemm_(JOB_STR+1, JOB_STR, &p, &n, &m, &d, A, &ldA, B, &ldB, @@ -652,16 +651,16 @@ namespace blas } // C = d A B^H, A is m x p, B is n x p - inline void gemmh(const unsigned m, const unsigned p, const unsigned n, - const double d, const double* const A, const unsigned ldA, + inline void gemmh(const unsigned m, const unsigned p, const unsigned n, + const double d, const double* const A, const unsigned ldA, const double* const B, const unsigned ldB, double* C, const unsigned ldC) { dgemm_(JOB_STR, JOB_STR+1, &m, &n, &p, &d, A, &ldA, B, &ldB, &D_ZERO, C, &ldC); } - inline void gemmh(const unsigned m, const unsigned p, const unsigned n, - const float d, const float* const A, const unsigned ldA, + inline void gemmh(const unsigned m, const unsigned p, const unsigned n, + const float d, const float* const A, const unsigned ldA, const float* const B, const unsigned ldB, float* C, const unsigned ldC) { @@ -670,16 +669,16 @@ namespace blas } // C += d A B^H, A is m x p, B is n x p - inline void gemmha(const unsigned m, const unsigned p, const unsigned n, - const double d, const double* const A, const unsigned ldA, + inline void gemmha(const unsigned m, const unsigned p, const unsigned n, + const double d, const double* const A, const unsigned ldA, const double* const B, const unsigned ldB, double* C, const unsigned ldC) { dgemm_(JOB_STR, JOB_STR+1, &m, &n, &p, &d, A, &ldA, B, &ldB, &D_ONE, C, &ldC); } - inline void gemmha(const unsigned m, const unsigned p, const unsigned n, - const float d, const float* const A, const unsigned ldA, + inline void gemmha(const unsigned m, const unsigned p, const unsigned n, + const float d, const float* const A, const unsigned ldA, const float* const B, const unsigned ldB, float* C, const unsigned ldC) { @@ -687,7 +686,7 @@ namespace blas &S_ONE, C, &ldC); } inline void gemmha(const unsigned m, const unsigned p, const unsigned n, - const double* const A, const unsigned ldA, + const double* const A, const unsigned ldA, const double* const B, const unsigned ldB, double* C, const unsigned ldC) { @@ -695,7 +694,7 @@ namespace blas &D_ONE, C, &ldC); } inline void gemmha(const unsigned m, const unsigned p, const unsigned n, - const float* const A, const unsigned ldA, + const float* const A, const unsigned ldA, const float* const B, const unsigned ldB, float* C, const unsigned ldC) { @@ -704,16 +703,16 @@ namespace blas } // C = d A^H B^H, A is p x m, B is n x p - inline void gemhmh(const unsigned m, const unsigned p, const unsigned n, - const double d, const double* const A, const unsigned ldA, + inline void gemhmh(const unsigned m, const unsigned p, const unsigned n, + const double d, const double* const A, const unsigned ldA, const double* const B, const unsigned ldB, double* C, const unsigned ldC) { dgemm_(JOB_STR+1, JOB_STR+1, &m, &n, &p, &d, A, &ldA, B, &ldB, &D_ZERO, C, &ldC); } - inline void gemhmh(const unsigned m, const unsigned p, const unsigned n, - const float d, const float* const A, const unsigned ldA, + inline void gemhmh(const unsigned m, const unsigned p, const unsigned n, + const float d, const float* const A, const unsigned ldA, const float* const B, const unsigned ldB, float* C, const unsigned ldC) { @@ -722,8 +721,8 @@ namespace blas } //C += d*AB, A is mxm (packed upper half is stored), B is mxn and regular matrix - inline void sygemma(const unsigned m, const unsigned n, - const double* const A, const double* const B, + inline void sygemma(const unsigned m, const unsigned n, + const double* const A, const double* const B, const double d, double* const C) { for(unsigned i=0;i<m;i++){ @@ -739,8 +738,8 @@ namespace blas } } } - inline void sygemma(const unsigned m, const unsigned n, - const float* const A, const float* const B, + inline void sygemma(const unsigned m, const unsigned n, + const float* const A, const float* const B, const float d, float* const C) { for(unsigned i=0;i<m;i++){ @@ -794,7 +793,7 @@ namespace blas } // C += d A^H A, C is a symm. matrix (packed upper half is stored), A is mxn - inline void symhm(const unsigned m, const unsigned n, const double* const A, + inline void symhm(const unsigned m, const unsigned n, const double* const A, const double d, double* C) { for (unsigned j=0; j<n; ++j) { @@ -805,7 +804,7 @@ namespace blas } } } - inline void symhm(const unsigned m, const unsigned n, const float* const A, + inline void symhm(const unsigned m, const unsigned n, const float* const A, const float d, float* C) { for (unsigned j=0; j<n; ++j) { @@ -1002,7 +1001,7 @@ namespace blas const unsigned ldC, unsigned nwk, double* wk) { int INF; - dormqr_(JOB_STR+6, JOB_STR, &m, &n, &p, A, &ldA, tau, C, &ldC, wk, &nwk, + dormqr_(JOB_STR+6, JOB_STR, &m, &n, &p, A, &ldA, tau, C, &ldC, wk, &nwk, &INF); return INF; } @@ -1011,7 +1010,7 @@ namespace blas const unsigned ldC, unsigned nwk, float* wk) { int INF; - sormqr_(JOB_STR+6, JOB_STR, &m, &n, &p, A, &ldA, tau, C, &ldC, wk, &nwk, + sormqr_(JOB_STR+6, JOB_STR, &m, &n, &p, A, &ldA, tau, C, &ldC, wk, &nwk, &INF); return INF; } @@ -1022,7 +1021,7 @@ namespace blas const unsigned ldC, unsigned nwk, double* wk) { int INF; - dormqr_(JOB_STR+6, JOB_STR+1, &m, &n, &p, A, &ldA, tau, C, &ldC, wk, &nwk, + dormqr_(JOB_STR+6, JOB_STR+1, &m, &n, &p, A, &ldA, tau, C, &ldC, wk, &nwk, &INF); return INF; } @@ -1031,7 +1030,7 @@ namespace blas const unsigned ldC, unsigned nwk, float* wk) { int INF; - sormqr_(JOB_STR+6, JOB_STR+1, &m, &n, &p, A, &ldA, tau, C, &ldC, wk, &nwk, + sormqr_(JOB_STR+6, JOB_STR+1, &m, &n, &p, A, &ldA, tau, C, &ldC, wk, &nwk, &INF); return INF; } @@ -1041,7 +1040,7 @@ namespace blas unsigned nwk, double* wk) { int INF; - dormqr_(JOB_STR+6, JOB_STR+1, &m, &n, &p, A, &ldA, tau, C, &m, wk, &nwk, + dormqr_(JOB_STR+6, JOB_STR+1, &m, &n, &p, A, &ldA, tau, C, &m, wk, &nwk, &INF); return INF; } @@ -1050,7 +1049,7 @@ namespace blas unsigned nwk, float* wk) { int INF; - sormqr_(JOB_STR+6, JOB_STR+1, &m, &n, &p, A, &ldA, tau, C, &m, wk, &nwk, + sormqr_(JOB_STR+6, JOB_STR+1, &m, &n, &p, A, &ldA, tau, C, &m, wk, &nwk, &INF); return INF; } @@ -1076,7 +1075,7 @@ namespace blas const unsigned ldC, unsigned nwk, double* wk) { int INF; - dormqr_(JOB_STR+8, JOB_STR, &m, &n, &p, A, &ldA, tau, C, &ldC, wk, &nwk, + dormqr_(JOB_STR+8, JOB_STR, &m, &n, &p, A, &ldA, tau, C, &ldC, wk, &nwk, &INF); return INF; } @@ -1085,7 +1084,7 @@ namespace blas const unsigned ldC, unsigned nwk, float* wk) { int INF; - sormqr_(JOB_STR+8, JOB_STR, &m, &n, &p, A, &ldA, tau, C, &ldC, wk, &nwk, + sormqr_(JOB_STR+8, JOB_STR, &m, &n, &p, A, &ldA, tau, C, &ldC, wk, &nwk, &INF); return INF; } @@ -1129,9 +1128,9 @@ namespace blas } // product of upper triangular and regular Matrix M = R A, R mxp, A nxp - inline void utrgemmh(const unsigned m, const unsigned p, const unsigned n, - const double* const R, const unsigned ldR, - const double* const A, const unsigned ldA, + inline void utrgemmh(const unsigned m, const unsigned p, const unsigned n, + const double* const R, const unsigned ldR, + const double* const A, const unsigned ldA, double* const M, const unsigned ldM) { for (unsigned i=0; i<m; ++i) { @@ -1143,8 +1142,8 @@ namespace blas } } } - inline void utrgemmh(const unsigned m, const unsigned p, const unsigned n, - const float* const R, const unsigned ldR, + inline void utrgemmh(const unsigned m, const unsigned p, const unsigned n, + const float* const R, const unsigned ldR, const float* const A, const unsigned ldA, float* const M, const unsigned ldM) { @@ -1160,14 +1159,14 @@ namespace blas // product of two upper triangular matrices M = R1 R2^T, R1 mxp, R2 nxp inline void utrmmh(const unsigned m, const unsigned p, const unsigned n, - const double* const R1, const unsigned ldR1, + const double* const R1, const unsigned ldR1, const double* const R2, const unsigned ldR2, double* const M) { for (unsigned j=0; j<n; ++j) { for (unsigned i=0; i<m; ++i) { double d = D_ZERO; - unsigned ij = MAX(i,j); + unsigned ij = MAX(i,j); for (unsigned l=ij; l<p; ++l) d += R1[i+l*ldR1]*R2[j+l*ldR2]; M[i+j*m] = d; @@ -1175,7 +1174,7 @@ namespace blas } } inline void utrmmh(const unsigned m, const unsigned p, const unsigned n, - const float* const R1, const unsigned ldR1, + const float* const R1, const unsigned ldR1, const float* const R2, const unsigned ldR2, float* const M) { @@ -1187,11 +1186,11 @@ namespace blas d += R1[i+l*ldR1]*R2[j+l*ldR2]; M[i+j*m] = d; } - } + } } // product of two upper triangular matrices M += R1 R2^T, R1 mxp, R2 nxp inline void utrmmha(const unsigned m, const unsigned p, const unsigned n, - const double* const R1, const unsigned ldR1, + const double* const R1, const unsigned ldR1, const double* const R2, const unsigned ldR2, double* const M) { @@ -1204,7 +1203,7 @@ namespace blas } } inline void utrmmha(const unsigned m, const unsigned p, const unsigned n, - const float* const R1, const unsigned ldR1, + const float* const R1, const unsigned ldR1, const float* const R2, const unsigned ldR2, float* const M) { @@ -1307,7 +1306,7 @@ namespace blas unsigned* ip = new unsigned[n]; for(unsigned i=0;i<n;i++) ip[i]=L[((2*n-i+1)*i)/2]; - + for(unsigned j=0;j<n;j++){ const unsigned ipj = ip[j]; const unsigned idUj = (ipj*(ipj+1))/2; @@ -1322,7 +1321,7 @@ namespace blas A[i]+=U[idUk+i]*t; } A+=n; - } + } delete [] ip; } @@ -1332,7 +1331,7 @@ namespace blas unsigned* ip = new unsigned[n]; for(unsigned i=0;i<n;i++) ip[i]=L[((2*n-i+1)*i)/2]; - + for(unsigned j=0;j<n;j++){ const unsigned ipj = ip[j]; const unsigned idUj = (ipj*(ipj+1))/2; @@ -1347,7 +1346,7 @@ namespace blas A[i]+=U[idUk+i]*t; } A+=n; - } + } delete [] ip; } @@ -1634,8 +1633,8 @@ namespace lapack dtrsm_(JOB_STR+8, JOB_STR+6, JOB_STR, JOB_STR+5, &n, &p, &D_ONE, LR, &ldLR, X, &ldX); } - - + + // unit lower triangular transposed solve (with L and R stored in one matrix) // XL^T=B, L is pxp, B is nxp inline void ltrhcs(const unsigned p, double* LR, const unsigned ldLR, diff --git a/MathLib/LinAlg/Solvers/solver.h b/MathLib/LinAlg/Solvers/solver.h index 79772ef87580ef1a84b8f90f26199a3223d7bd55..d89a01b897ba2a07e99a3539b26318241ef468d7 100644 --- a/MathLib/LinAlg/Solvers/solver.h +++ b/MathLib/LinAlg/Solvers/solver.h @@ -2,7 +2,7 @@ * solver.h * * Created on: Sep 27, 2011 - * Author: fischeth + * Author: TF */ #ifndef SOLVER_H_ diff --git a/MathLib/LinAlg/Sparse/CRSMatrix.h b/MathLib/LinAlg/Sparse/CRSMatrix.h index 977cc91b2bff7561125596e909b6caf0cd19fad6..a2c889cf3926acd1967fbdc0fadd95e299438283 100644 --- a/MathLib/LinAlg/Sparse/CRSMatrix.h +++ b/MathLib/LinAlg/Sparse/CRSMatrix.h @@ -14,6 +14,7 @@ #include "SparseMatrixBase.h" #include "sparse.h" #include "amuxCRS.h" +#include "../Preconditioner/generateDiagPrecond.h" namespace MathLib { @@ -54,6 +55,9 @@ public: amuxCRS(d, MatrixBase::_n_rows, _row_ptr, _col_idx, _data, x, y); } + virtual void precondApply(T* x) const + {} + protected: unsigned *_row_ptr; unsigned *_col_idx; diff --git a/MathLib/LinAlg/Sparse/CRSMatrixDiagPrecond.h b/MathLib/LinAlg/Sparse/CRSMatrixDiagPrecond.h index 2335eedf001f7cf4b6af353402fc9a9fd2fc2bf8..30c4f4b0cc301d4117751181dce255268e730614 100644 --- a/MathLib/LinAlg/Sparse/CRSMatrixDiagPrecond.h +++ b/MathLib/LinAlg/Sparse/CRSMatrixDiagPrecond.h @@ -5,12 +5,15 @@ #include "CRSMatrix.h" #include "sparse.h" +#include "../Preconditioner/generateDiagPrecond.h" + +namespace MathLib { class CRSMatrixDiagPrecond : public CRSMatrix<double> { public: - CRSMatrixDiagPrecond (std::string const &fname, unsigned num_of_threads=1) - : CRSMatrix<double>(fname, num_of_threads), _inv_diag(NULL) + CRSMatrixDiagPrecond (std::string const &fname) + : CRSMatrix<double>(fname), _inv_diag(NULL) { _inv_diag = new double[_n_rows]; if (!generateDiagPrecond (_n_rows, _row_ptr, _col_idx, _data, _inv_diag)) { @@ -19,7 +22,6 @@ public: } void precondApply(double* x) const { - omp_set_num_threads( _num_of_threads ); { unsigned k; #pragma omp parallel for @@ -36,5 +38,7 @@ private: double *_inv_diag; }; +} + #endif diff --git a/MathLib/LinAlg/Sparse/amuxCRS.cpp b/MathLib/LinAlg/Sparse/amuxCRS.cpp index 22e9aef84bdeddad579bcc320864ad62e6ad0929..a5f4e57f3924e5c74f9e88aa4f6d609dd5478fae 100644 --- a/MathLib/LinAlg/Sparse/amuxCRS.cpp +++ b/MathLib/LinAlg/Sparse/amuxCRS.cpp @@ -7,9 +7,10 @@ #include "amuxCRS.h" #include <omp.h> -#include <omp.h> #include <pthread.h> +namespace MathLib { + void amuxCRS (double a, unsigned n, unsigned const * const iA, unsigned const * const jA, double const * const A, double const * const x, double* y) @@ -153,3 +154,4 @@ void amuxCRSSym (double a, } } +} // end namespace MathLib diff --git a/MathLib/LinAlg/Sparse/amuxCRS.h b/MathLib/LinAlg/Sparse/amuxCRS.h index 24ec77d6fa41dac6530ab06821e5cf96a3213246..b1845218f8c5e8f3ad6f9a48c448b7e1eada5a67 100644 --- a/MathLib/LinAlg/Sparse/amuxCRS.h +++ b/MathLib/LinAlg/Sparse/amuxCRS.h @@ -1,16 +1,18 @@ #ifndef AMUXCRS_H #define AMUXCRS_H -void amuxCRS (double a, +namespace MathLib { + +void amuxCRS (double a, unsigned n, unsigned const * const iA, unsigned const * const jA, double const * const A, double const * const x, double* y); -void amuxCRSParallelPThreads (double a, +void amuxCRSParallelPThreads (double a, unsigned n, unsigned const * const iA, unsigned const * const jA, double const * const A, double const * const x, double* y, unsigned num_of_pthreads); -void amuxCRSParallelOpenMP (double a, +void amuxCRSParallelOpenMP (double a, unsigned n, unsigned const * const iA, unsigned const * const jA, double const * const A, double const * const x, double* y, unsigned num_of_omp_threads); @@ -19,4 +21,6 @@ void amuxCRSSym (double a, unsigned n, unsigned const * const iA, unsigned const * const jA, double const * const A, double const * const x, double* y); +} // end namespace MathLib + #endif diff --git a/MathLib/LinAlg/VectorNorms.h b/MathLib/LinAlg/VectorNorms.h new file mode 100644 index 0000000000000000000000000000000000000000..31bbf802f8cd969b12b14f6f4f12d7cb94d89d66 --- /dev/null +++ b/MathLib/LinAlg/VectorNorms.h @@ -0,0 +1,24 @@ +/* + * VectorNorms.h + * + * Created on: Jun 6, 2011 + * Author: TF + */ + +#ifndef VECTORNORMS_H_ +#define VECTORNORMS_H_ + +#include <cmath> + +#include "MathTools.h" + +namespace MathLib { + +double normEuklid (double const * const vec, size_t n) +{ + return sqrt (scpr (vec, vec, n)); +} + +} // end namespace MathLib + +#endif /* VECTORNORMS_H_ */ diff --git a/MathLib/LinearInterpolation.cpp b/MathLib/LinearInterpolation.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6853843b6a69800d2e8c44c54d2769c5b5860b4d --- /dev/null +++ b/MathLib/LinearInterpolation.cpp @@ -0,0 +1,55 @@ +/* + * LinearInterpolation.cpp + * + * Created on: Sep 7, 2010 + * Author: TF + */ + +#include "LinearInterpolation.h" +#include "binarySearch.h" +#include "swap.h" + +#include <iostream> + +namespace MathLib { + +LinearInterpolation::LinearInterpolation(const std::vector<double>& supporting_points, const std::vector<double>& values_at_supp_pnts) + : _supporting_points (supporting_points), _values_at_supp_pnts (values_at_supp_pnts) +{} + +LinearInterpolation::LinearInterpolation(const std::vector<double>& supporting_points, const std::vector<double>& values_at_supp_pnts, const std::vector<double>& points_to_interpolate, std::vector<double>& values_at_interpol_pnts) + : _supporting_points (supporting_points), _values_at_supp_pnts (values_at_supp_pnts) +{ +// std::cout << "LinearInterpolation::LinearInterpolation support_points, values_at_supp_pnts: " << std::endl; +// for (size_t k(0); k<supporting_points.size(); k++) { +// std::cout << supporting_points[k] << " " << values_at_supp_pnts[k] << std::endl; +// } +// std::cout << std::endl; + values_at_interpol_pnts.clear(); + for (size_t k(0); k<points_to_interpolate.size(); k++) + values_at_interpol_pnts.push_back (this->getValue (points_to_interpolate[k])); +} + +LinearInterpolation::~LinearInterpolation() +{} + +double LinearInterpolation::getValue ( double pnt_to_interpolate ) +{ + // search interval that has the point inside + size_t interval_idx (std::numeric_limits<size_t>::max()); + for (size_t k(1); k<_supporting_points.size() && interval_idx == std::numeric_limits<size_t>::max(); k++) { + if (_supporting_points[k-1] <= pnt_to_interpolate && pnt_to_interpolate <= _supporting_points[k]) { + interval_idx = k-1; + } + } + + // compute linear interpolation polynom: y = m * x + n + long double m ((_values_at_supp_pnts[interval_idx+1] - _values_at_supp_pnts[interval_idx]) / (_supporting_points[interval_idx+1] - _supporting_points[interval_idx])); +// double m ((_values_at_supp_pnts[interval_idx] - _values_at_supp_pnts[interval_idx+1]) / (_supporting_points[interval_idx] - _supporting_points[interval_idx+1])); +// double n (_values_at_supp_pnts[interval_idx+1] - m * _supporting_points[interval_idx+1]); + long double n (_values_at_supp_pnts[interval_idx] - m * _supporting_points[interval_idx]); + + return m * pnt_to_interpolate + n; +} + +} // end MathLib diff --git a/MathLib/LinearInterpolation.h b/MathLib/LinearInterpolation.h new file mode 100644 index 0000000000000000000000000000000000000000..7e5f746cd621fcdadc530b3264ae578f05c61dfc --- /dev/null +++ b/MathLib/LinearInterpolation.h @@ -0,0 +1,31 @@ +/* + * LinearInterpolation.h + * + * Created on: Sep 7, 2010 + * Author: TF + */ + +#ifndef LINEARINTERPOLATION_H_ +#define LINEARINTERPOLATION_H_ + +#include <vector> +#include <limits> + +namespace MathLib { + +class LinearInterpolation { +public: + LinearInterpolation(const std::vector<double>& supporting_points, const std::vector<double>& values_at_supp_pnts); + LinearInterpolation(const std::vector<double>& supporting_points, const std::vector<double>& values_at_supp_pnts, const std::vector<double>& points_to_interpolate, std::vector<double>& values_at_interpol_pnts); + virtual ~LinearInterpolation(); + + double getValue ( double pnt_to_interpolate ); + +private: + const std::vector<double>& _supporting_points; + const std::vector<double>& _values_at_supp_pnts; +}; + +} // end namespace MathLib + +#endif /* LINEARINTERPOLATION_H_ */ diff --git a/MathLib/LinkedTriangle.cpp b/MathLib/LinkedTriangle.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2207b967cff9f6b590ac39dd96d988809e360a2e --- /dev/null +++ b/MathLib/LinkedTriangle.cpp @@ -0,0 +1,83 @@ +/* + * LinkedTriangle.cpp + * + * Created on: Mar 25, 2010 + * Author: fischeth + */ + +#include "LinkedTriangle.h" + +namespace MathLib { + +LinkedTriangle::LinkedTriangle(std::vector<GEOLIB::Point*> const &pnt_vec, + size_t pnt_a, size_t pnt_b, size_t pnt_c, LinkedTriangle* tri_a, + LinkedTriangle* tri_b, LinkedTriangle* tri_c) : + GEOLIB::Triangle(pnt_vec, pnt_a, pnt_b, pnt_c) +{ + if (tri_a) _neighbor_triangles[0] = tri_a; + else _neighbor_triangles[0] = NULL; + if (tri_b) _neighbor_triangles[1] = tri_b; + else _neighbor_triangles[1] = NULL; + if (tri_c) _neighbor_triangles[2] = tri_c; + else _neighbor_triangles[2] = NULL; +} + +void LinkedTriangle::setNeighborTriangle(size_t idx, LinkedTriangle* tri) +{ + assert(idx < 3); + _neighbor_triangles[idx] = tri; +} + +void LinkedTriangle::setNeighborTriangleByPointIdx (size_t idx, LinkedTriangle* tri) +{ + if (idx == _pnt_ids[0]) setNeighborTriangle (0, tri); + else { + if (idx == _pnt_ids[1]) setNeighborTriangle (1, tri); + else setNeighborTriangle (2, tri); + } +} + +LinkedTriangle* LinkedTriangle::getNeighborTriangle(size_t idx) +{ + assert(idx < 3); + return _neighbor_triangles[idx]; +} + +size_t LinkedTriangle::getIdxOfNeighborTriangle(LinkedTriangle* tri) +{ + if (tri == _neighbor_triangles[0]) return 0; + if (tri == _neighbor_triangles[1]) return 1; + if (tri == _neighbor_triangles[2]) return 2; + return 3; +} + +size_t LinkedTriangle::getIdxOfPoint (size_t i) const +{ + if (_pnt_ids[0] == i) return 0; + if (_pnt_ids[1] == i) return 1; + if (_pnt_ids[2] == i) return 2; + return 3; +} + +void LinkedTriangle::writeNeighbor (std::ostream &os, size_t idx) const +{ + if (_neighbor_triangles[idx]) { + os << "["; + (_neighbor_triangles[idx])->write (os); + os << "]"; + } + else os << "NULL"; +} + +LinkedTriangle::~LinkedTriangle() +{ + // TODO Auto-generated destructor stub +} + +std::ostream& operator<< (std::ostream &os, const LinkedTriangle &tri) +{ + tri.write (os); + return os; +} + +} // end namespace MathLib diff --git a/MathLib/LinkedTriangle.h b/MathLib/LinkedTriangle.h new file mode 100644 index 0000000000000000000000000000000000000000..46cdf8321be7e48a6c6cf8ae5421616b6694428a --- /dev/null +++ b/MathLib/LinkedTriangle.h @@ -0,0 +1,54 @@ +/* + * LinkedTriangle.h + * + * Created on: Mar 25, 2010 + * Author: fischeth + */ + +#ifndef LINKEDTRIANGLE_H_ +#define LINKEDTRIANGLE_H_ + +#include <vector> +#include <iostream> + +// GEO +#include "Triangle.h" +#include "Point.h" + +namespace MathLib { + +class LinkedTriangle : public GEOLIB::Triangle { +public: + LinkedTriangle(std::vector<GEOLIB::Point*> const&pnt_vec, size_t pnt_a, + size_t pnt_b, size_t pnt_c, LinkedTriangle* tri_a, + LinkedTriangle* tri_b, LinkedTriangle* tri_c); + virtual ~LinkedTriangle(); + + void setNeighborTriangle (size_t idx, LinkedTriangle* tri); + void setNeighborTriangleByPointIdx (size_t idx, LinkedTriangle* tri); + + LinkedTriangle* getNeighborTriangle (size_t idx); + size_t getIdxOfNeighborTriangle(LinkedTriangle* tri); + + size_t getIdxOfPoint (size_t i) const; + + void write (std::ostream &os) const + { + os << _pnt_ids[0] << " " << _pnt_ids[1] << " " << _pnt_ids[2]; + } + + void writeNeighbor (std::ostream &os, size_t idx) const; + +private: + /** + * pointers to the neighbor triangles + */ + LinkedTriangle* _neighbor_triangles[3]; +}; + +/** overload the output operator for class LinkedTriangle */ +std::ostream& operator<< (std::ostream &os, const LinkedTriangle &tri); + +} // end namespace MathLib + +#endif /* LINKEDTRIANGLE_H_ */ diff --git a/MathLib/Vector3.h b/MathLib/Vector3.h new file mode 100644 index 0000000000000000000000000000000000000000..dd59d36f8567724555003068ecfb000f8ca0261f --- /dev/null +++ b/MathLib/Vector3.h @@ -0,0 +1,160 @@ +/** + * \file Vector3.h + * 27/10/2009 LB Initial implementation + * From: http://www.strout.net/info/coding/classlib/intro.html + * with modifications to derive from TemplatePoint + */ + +#ifndef VECTOR3_H +#define VECTOR3_H + +// GEO +#include "TemplatePoint.h" + +// MathLib +#include "MathTools.h" + +#include <iostream> +#include <cmath> + +namespace MathLib { + +/** + * The Vector class defines a three-dimensional vector, with appropriate + * operators. (* is cross product.) + */ +template <class T> +class TemplateVector : public GEOLIB::TemplatePoint<T> +{ +public: + TemplateVector() : GEOLIB::TemplatePoint<T>() {}; + TemplateVector(T x1, T x2, T x3) : GEOLIB::TemplatePoint<T>(x1, x2, x3) {}; + TemplateVector(const GEOLIB::TemplatePoint<T> & rhs) : + GEOLIB::TemplatePoint<T>(rhs[0], rhs[1], rhs[2]) + {} + /** constructs a vector from the gien points */ + TemplateVector(const GEOLIB::TemplatePoint<T> &a, const GEOLIB::TemplatePoint<T> &b) : + GEOLIB::TemplatePoint<T>(b[0]-a[0], b[1]-a[1], b[2]-a[2]) + {} + ~TemplateVector() {}; + + // vector arithmetic + + TemplateVector operator+(const TemplateVector & pV) const + { + return TemplateVector(this->x[0]+pV[0], this->x[1]+pV[1], this->x[2]+pV[2] ); + } + + TemplateVector operator-(const TemplateVector & pV) const { + TemplateVector out( this->x[0]-pV[0], this->x[1]-pV[1], this->x[2]-pV[2] ); + return out; + } + + TemplateVector operator-() const + { return TemplateVector (-this->x[0], -this->x[1], -this->x[2]); } + + TemplateVector& operator+=(const TemplateVector & pV) { + for (size_t i(0); i<3; i++) this->x[i]+=pV[i]; + return *this; + } + + TemplateVector& operator+=(const GEOLIB::TemplatePoint<T>& pnt) + { + for (size_t i(0); i<3; i++) this->_x[i] += pnt[i]; + return *this; + } + + TemplateVector& operator-=(const TemplateVector & pV) + { + for (size_t i(0); i<3; i++) this->_x[i] -= pV[i]; + return *this; + } + + // Accessors + T X() const { return this->_x[0]; } + T Y() const { return this->_x[1]; } + T Z() const { return this->_x[2]; } + void setX(T value) { this->_x[0] = value; } + void setY(T value) { this->_x[1] = value; } + void setZ(T value) { this->_x[2] = value; } + + /// Dot product with another vector + double Dot(const TemplateVector & pV) const + { + return this->_x[0]*pV[0] + this->_x[1]*pV[1] + this->_x[2]*pV[2]; + } + + /// Cross product as the multiplication operator + TemplateVector operator*(const TemplateVector & pV) const { + return TemplateVector ( + this->_x[1]*pV[2]-this->_x[2]*pV[1], + this->_x[2]*pV[0]-this->_x[0]*pV[2], + this->_x[0]*pV[1]-this->_x[1]*pV[0] ); + } + + /// Cross product with another vector + TemplateVector Cross( const TemplateVector & pV ) const + { return *this * pV; } + + friend double Dot( const TemplateVector & p1, const TemplateVector & p2 ) + { return p1.Dot(p2); } + + friend TemplateVector Cross( const TemplateVector & p1, const TemplateVector & p2 ) + { return p1 * p2; } + + TemplateVector operator*(double pR) const // * a scalar + { + return TemplateVector(this->x[0]*pR, this->x[1]*pR, this->x[2]*pR); + } + + friend TemplateVector operator*(double pR, const TemplateVector & pV) + { + return TemplateVector ( pV[0]*pR, pV[1]*pR, pV[2]*pR ); + } + + TemplateVector& operator*=(double pR) + { + for (size_t i(0); i<3; i++) this->_x[i]*=pR; + return *this; + } + + /// Returns the squared length + double LenSqr(void) const + { + return scpr (this->getData (), this->getData (), 3); + } + + /// Returns the length + double Length(void) const + { return sqrt(LenSqr()); } + + /// Projection (component of *this parallel to pV). + /// Note: component perpendicular to pV is: *this - Proj(pV) + TemplateVector Proj(const TemplateVector & pV) + { TemplateVector out( pV * (this->Dot(pV) / pV.LenSqr()) ); return out; } + + /// Cosine of the angle between two vectors: + double CosAng(const TemplateVector& pV) + { return this->Dot(pV) / (Length() * pV.Length()); } + + /// Comparison if equal + bool operator==( const TemplateVector & pV) const + { + return (std::fabs(this->_x[0] - pV[0]) < sqrt(std::numeric_limits<double>::min()) && + std::fabs(this->_x[1] - pV[1]) < sqrt(std::numeric_limits<double>::min()) && + std::fabs(this->_x[2] - pV[2]) < sqrt(std::numeric_limits<double>::min())); + } + + /// Comparison if not equal + bool operator!=( const TemplateVector & pV) const + { + return (! (pV == this)); +// this->_x[0]!=pV[0] || this->_x[1]!=pV[1] || this->_x[2]!=pV[2]; + } +}; + +typedef TemplateVector<double> Vector; + +} + +#endif // VECTOR3_H diff --git a/MathLib/max.h b/MathLib/max.h new file mode 100644 index 0000000000000000000000000000000000000000..f98c375dd6d23236ab91c2c088e50348c2dc3d2b --- /dev/null +++ b/MathLib/max.h @@ -0,0 +1,20 @@ +/* + * max.h + * + * Created on: Apr 20, 2010 + * Author: TF + */ + +#ifndef MAX_H_ +#define MAX_H_ + +/** + * max returns the maximum of its arguments + */ +template<class T> T max(const T& arg0, const T& arg1) +{ + if (arg0 < arg1) return arg1; + return arg0; +} + +#endif /* MAX_H_ */ diff --git a/MathLib/vector_io.h b/MathLib/vector_io.h new file mode 100644 index 0000000000000000000000000000000000000000..ab6ef2b935758c2c9af2ab43b1dfc27942c28722 --- /dev/null +++ b/MathLib/vector_io.h @@ -0,0 +1,95 @@ +#ifndef VECTOR_IO_H +#define VECTOR_IO_H + +#include <iostream> +#include <fstream> +#include <string> + +// von http://www.zfx.info/Display/Thread.php?TID=177779 +#include <sstream> + +#ifdef UNICODE +typedef std::wstringstream unistringstream; +typedef std::wstring unistring; +#else +typedef std::stringstream unistringstream; +typedef std::string unistring; +#endif + +template<typename A, typename T> inline const A lexical_cast(const T& source) +{ + unistringstream s; + + s << source; + + A destination; + s >> destination; + + return (destination); +} + +/** reads the number of lines of non-binary stream */ +unsigned readLines ( std::istream &in ) +{ + unsigned k = 0; + while (!in.eof()) { + std::string str; + getline (in, str); + k++; + } + + return k; +} + +/** reads N values of non-binary stream */ +template <class T> void read ( std::istream &in, unsigned N, T *a ) +{ + unsigned k = 0; + std::string ws (" \t"); + + while (!in.eof () and k <= N) { + std::string t; + getline (in, t); + size_t i1; + if (t.length () != 0) { + i1 = t.find_first_not_of (ws, 0); + if (i1 != std::string::npos) { + size_t i2 = t.find_first_of (ws, i1); + if (i2 != std::string::npos) { + a[k++] = lexical_cast<T> ( t.substr(i1, i2-i1) ); + } else { + a[k++] = lexical_cast<T> ( t.substr(i1, t.size()-i1)); + } + } + } + } +} + +template <class T> int readArrays ( const std::string &fname, size_t &s, + size_t n, T* &arr ) +{ + // open stream + std::ifstream in (fname.c_str()); + // read number of rows + if (in) { + s = readLines(in)-1; + in.close(); + } else { + std::cout << "could not open " << fname << std::endl; + return 1; + } + if (s > 0) { + arr = new T[s * n]; + size_t j(0), l(0); + // read values + in.open (fname.c_str(), std::ios::in); + for (j=0; j<s; ++j) { + for (l=0; l<n; l++) in >> arr[l*s+j]; + } + in.close (); + } + return 0; +} + +#endif + diff --git a/SimpleTests/SolverTests/CMakeLists.txt b/SimpleTests/SolverTests/CMakeLists.txt index 67123af78461ff0d22f9f63b1c480485bcfafedf..439de4a1d68c60c31c5d62213b7168bcf08e945f 100644 --- a/SimpleTests/SolverTests/CMakeLists.txt +++ b/SimpleTests/SolverTests/CMakeLists.txt @@ -27,7 +27,6 @@ ADD_EXECUTABLE( ConjugateGradientUnpreconditioned ADD_EXECUTABLE( ConjugateGradientDiagPrecond ConjugateGradientDiagonalPreconditioned.cpp - ../Preconditioner/generateDiagPrecond.cpp ${SOURCES} ${HEADERS} ) @@ -35,10 +34,14 @@ ADD_EXECUTABLE( ConjugateGradientDiagPrecond TARGET_LINK_LIBRARIES ( ConjugateGradientUnpreconditioned ${BLAS_LIBRARIES} ${LAPACK_LIBRARIES} + MathLib + Base ) TARGET_LINK_LIBRARIES ( ConjugateGradientDiagPrecond ${BLAS_LIBRARIES} ${LAPACK_LIBRARIES} + MathLib + Base ) diff --git a/SimpleTests/SolverTests/ConjugateGradientDiagonalPreconditioned.cpp b/SimpleTests/SolverTests/ConjugateGradientDiagonalPreconditioned.cpp index 263f9ffb57228140fe2f65b40fac052a33c0bb19..043afa1fce8f63f801f4860ed1d06bb5ec1d8204 100644 --- a/SimpleTests/SolverTests/ConjugateGradientDiagonalPreconditioned.cpp +++ b/SimpleTests/SolverTests/ConjugateGradientDiagonalPreconditioned.cpp @@ -1,12 +1,14 @@ #include <fstream> #include <iostream> #include <cmath> +#include <cstdlib> #include <omp.h> -#include "CG.h" -#include "CRSMatrixDiagPrecond.h" +#include "LinAlg/Solvers/CG.h" +#include "LinAlg/Sparse/CRSMatrixDiagPrecond.h" #include "sparse.h" #include "vector_io.h" -#include "timeMeasurement.h" +#include "RunTimeTimer.h" +#include "CPUTimeTimer.h" int main(int argc, char *argv[]) { @@ -15,13 +17,13 @@ int main(int argc, char *argv[]) return -1; } - // read number of threads + // read number of threads unsigned num_omp_threads (1); num_omp_threads = atoi (argv[3]); // *** reading matrix in crs format from file std::string fname(argv[1]); - CRSMatrixDiagPrecond *mat (new CRSMatrixDiagPrecond(fname, num_omp_threads)); + MathLib::CRSMatrixDiagPrecond *mat (new MathLib::CRSMatrixDiagPrecond(fname)); unsigned n (mat->getNRows()); bool verbose (true); @@ -48,22 +50,27 @@ int main(int argc, char *argv[]) } } - + if (verbose) std::cout << "solving system with PCG method (diagonal preconditioner) ... " << std::flush; - time_t start_time, end_time; - time(&start_time); - double cg_time (cputime(0.0)); + double eps (1.0e-6); unsigned steps (4000); - CG (mat, b, x, eps, steps, num_omp_threads); - cg_time = cputime(cg_time); - time(&end_time); + RunTimeTimer run_timer; + CPUTimeTimer cpu_timer; + run_timer.start(); + cpu_timer.start(); + + MathLib::CG (mat, b, x, eps, steps, num_omp_threads); + + cpu_timer.stop(); + run_timer.stop(); + if (verbose) { std::cout << " in " << steps << " iterations" << std::endl; - std::cout << "\t(residuum is " << eps << ") took " << cg_time << " sec time and " << (end_time-start_time) << " sec" << std::endl; + std::cout << "\t(residuum is " << eps << ") took " << cpu_timer.elapsed() << " sec time and " << run_timer.elapsed() << " sec" << std::endl; } else { - std::cout << end_time-start_time << std::endl; + std::cout << cpu_timer.elapsed() << std::endl; } delete mat; diff --git a/SimpleTests/SolverTests/ConjugateGradientUnpreconditioned.cpp b/SimpleTests/SolverTests/ConjugateGradientUnpreconditioned.cpp index d24ccac97ec13afbff538c7c90f67e20618014b6..2413a1502def9a6f29460fd0d8bf7edd2f33532c 100644 --- a/SimpleTests/SolverTests/ConjugateGradientUnpreconditioned.cpp +++ b/SimpleTests/SolverTests/ConjugateGradientUnpreconditioned.cpp @@ -1,18 +1,18 @@ #include <fstream> #include <iostream> #include <omp.h> -#include "CG.h" -#include "CRSMatrix.h" +#include "LinAlg/Solvers/CG.h" +#include "LinAlg/Sparse/CRSMatrix.h" #include "sparse.h" #include "vector_io.h" -#include "timeMeasurement.h" +//#include "timeMeasurement.h" int main(int argc, char *argv[]) { // *** reading matrix in crs format from file std::string fname("/work/fischeth/data/testmat.bin"); // std::ifstream in(fname.c_str(), std::ios::binary); - CRSMatrix<double> *mat (new CRSMatrix<double>(fname, 1)); + MathLib::CRSMatrix<double> *mat (new MathLib::CRSMatrix<double>(fname)); /* double *A(NULL); unsigned *iA(NULL), *jA(NULL), n; if (in) { @@ -49,13 +49,13 @@ int main(int argc, char *argv[]) std::cout << "solving system with CG method ... " << std::flush; time_t start_time, end_time; time(&start_time); - double cg_time (cputime(0.0)); +// double cg_time (cputime(0.0)); double eps (1.0e-6); unsigned steps (4000); CG (mat, b, x, eps, steps, 1); - cg_time = cputime(cg_time); +// cg_time = cputime(cg_time); time(&end_time); - std::cout << " in " << steps << " iterations (residuum is " << eps << ") took " << cg_time << " sec time and " << (end_time-start_time) << " sec" << std::endl; + std::cout << " in " << steps << " iterations (residuum is " << eps << ") took " << /*cg_time <<*/ " sec time and " << (end_time-start_time) << " sec" << std::endl; delete mat; delete [] x; diff --git a/cmake/FindBLAS.cmake b/cmake/FindBLAS.cmake new file mode 100644 index 0000000000000000000000000000000000000000..9827984332767385d8131fb9e1f4d1b6b3a0f06e --- /dev/null +++ b/cmake/FindBLAS.cmake @@ -0,0 +1,462 @@ +# - Find BLAS library +# This module finds an installed fortran library that implements the BLAS +# linear-algebra interface (see http://www.netlib.org/blas/). +# The list of libraries searched for is taken +# from the autoconf macro file, acx_blas.m4 (distributed at +# http://ac-archive.sourceforge.net/ac-archive/acx_blas.html). +# +# This module sets the following variables: +# BLAS_FOUND - set to true if a library implementing the BLAS interface +# is found +# BLAS_LINKER_FLAGS - uncached list of required linker flags (excluding -l +# and -L). +# BLAS_LIBRARIES - uncached list of libraries (using full path name) to +# link against to use BLAS +# BLAS95_LIBRARIES - uncached list of libraries (using full path name) +# to link against to use BLAS95 interface +# BLAS95_FOUND - set to true if a library implementing the BLAS f95 interface +# is found +# BLA_STATIC if set on this determines what kind of linkage we do (static) +# BLA_VENDOR if set checks only the specified vendor, if not set checks +# all the possibilities +# BLA_F95 if set on tries to find the f95 interfaces for BLAS/LAPACK +########## +### List of vendors (BLA_VENDOR) valid in this module +## ATLAS, PhiPACK,CXML,DXML,SunPerf,SCSL,SGIMATH,IBMESSL,Intel10_32 (intel mkl v10 32 bit),Intel10_64lp (intel mkl v10 64 bit,lp thread model, lp64 model), +## Intel( older versions of mkl 32 and 64 bit), ACML,Apple, NAS, Generic +# C/CXX should be enabled to use Intel mkl + +#============================================================================= +# Copyright 2007-2009 Kitware, Inc. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distributed this file outside of CMake, substitute the full +# License text for the above reference.) + +get_property(_LANGUAGES_ GLOBAL PROPERTY ENABLED_LANGUAGES) +include(CheckFunctionExists) + +macro(Check_Fortran_Libraries LIBRARIES _prefix _name _flags _list _threads) +# This macro checks for the existence of the combination of fortran libraries +# given by _list. If the combination is found, this macro checks (using the +# Check_Fortran_Function_Exists macro) whether can link against that library +# combination using the name of a routine given by _name using the linker +# flags given by _flags. If the combination of libraries is found and passes +# the link test, LIBRARIES is set to the list of complete library paths that +# have been found. Otherwise, LIBRARIES is set to FALSE. + +# N.B. _prefix is the prefix applied to the names of all cached variables that +# are generated internally and marked advanced by this macro. + +set(_libraries_work TRUE) +set(${LIBRARIES}) +set(_combined_name) +foreach(_library ${_list}) + set(_combined_name ${_combined_name}_${_library}) + + if(_libraries_work) + if ( WIN32 ) + if(BLA_STATIC) + set(CMAKE_FIND_LIBRARY_SUFFIXES ".lib;.dll") + endif(BLA_STATIC) + find_library(${_prefix}_${_library}_LIBRARY + NAMES ${_library} + PATHS ENV LIB + ) + endif ( WIN32 ) + + if ( APPLE ) + if(BLA_STATIC) + set(CMAKE_FIND_LIBRARY_SUFFIXES ".lib;.dll") + endif(BLA_STATIC) + find_library(${_prefix}_${_library}_LIBRARY + NAMES ${_library} + PATHS /usr/local/lib /usr/lib /usr/local/lib64 /usr/lib64 ENV DYLD_LIBRARY_PATH + ) + + else ( APPLE ) + if(BLA_STATIC) + set(CMAKE_FIND_LIBRARY_SUFFIXES ".a;.so") + endif(BLA_STATIC) + find_library(${_prefix}_${_library}_LIBRARY + NAMES ${_library} + PATHS /usr/local/lib /usr/lib /usr/local/lib64 /usr/lib64 ENV LD_LIBRARY_PATH + ) + endif( APPLE ) + mark_as_advanced(${_prefix}_${_library}_LIBRARY) + set(${LIBRARIES} ${${LIBRARIES}} ${${_prefix}_${_library}_LIBRARY}) + set(_libraries_work ${${_prefix}_${_library}_LIBRARY}) + endif(_libraries_work) +endforeach(_library ${_list}) +if(_libraries_work) + # Test this combination of libraries. + set(CMAKE_REQUIRED_LIBRARIES ${_flags} ${${LIBRARIES}} ${_threads}) + #message("DEBUG: CMAKE_REQUIRED_LIBRARIES = ${CMAKE_REQUIRED_LIBRARIES}") + check_function_exists("${_name}_" ${_prefix}${_combined_name}_WORKS) + set(CMAKE_REQUIRED_LIBRARIES) + mark_as_advanced(${_prefix}${_combined_name}_WORKS) + set(_libraries_work ${${_prefix}${_combined_name}_WORKS}) +endif(_libraries_work) +if(NOT _libraries_work) + set(${LIBRARIES} FALSE) +endif(NOT _libraries_work) +#message("DEBUG: ${LIBRARIES} = ${${LIBRARIES}}") +endmacro(Check_Fortran_Libraries) + +set(BLAS_LINKER_FLAGS) +set(BLAS_LIBRARIES) +set(BLAS95_LIBRARIES) +if ($ENV{BLA_VENDOR} MATCHES ".+") + set(BLA_VENDOR $ENV{BLA_VENDOR}) +else ($ENV{BLA_VENDOR} MATCHES ".+") + if(NOT BLA_VENDOR) + set(BLA_VENDOR "All") + endif(NOT BLA_VENDOR) +endif ($ENV{BLA_VENDOR} MATCHES ".+") + +if (BLA_VENDOR STREQUAL "ATLAS" OR BLA_VENDOR STREQUAL "All") + if(NOT BLAS_LIBRARIES) + # BLAS in ATLAS library? (http://math-atlas.sourceforge.net/) + check_fortran_libraries( + BLAS_LIBRARIES + BLAS + cblas_dgemm + "" + "cblas;f77blas;atlas" + "" + ) + endif(NOT BLAS_LIBRARIES) +endif (BLA_VENDOR STREQUAL "ATLAS" OR BLA_VENDOR STREQUAL "All") + +# BLAS in PhiPACK libraries? (requires generic BLAS lib, too) +if (BLA_VENDOR STREQUAL "PhiPACK" OR BLA_VENDOR STREQUAL "All") + if(NOT BLAS_LIBRARIES) + check_fortran_libraries( + BLAS_LIBRARIES + BLAS + sgemm + "" + "sgemm;dgemm;blas" + "" + ) + endif(NOT BLAS_LIBRARIES) +endif (BLA_VENDOR STREQUAL "PhiPACK" OR BLA_VENDOR STREQUAL "All") + +# BLAS in Alpha CXML library? +if (BLA_VENDOR STREQUAL "CXML" OR BLA_VENDOR STREQUAL "All") + if(NOT BLAS_LIBRARIES) + check_fortran_libraries( + BLAS_LIBRARIES + BLAS + sgemm + "" + "cxml" + "" + ) + endif(NOT BLAS_LIBRARIES) +endif (BLA_VENDOR STREQUAL "CXML" OR BLA_VENDOR STREQUAL "All") + +# BLAS in Alpha DXML library? (now called CXML, see above) +if (BLA_VENDOR STREQUAL "DXML" OR BLA_VENDOR STREQUAL "All") + if(NOT BLAS_LIBRARIES) + check_fortran_libraries( + BLAS_LIBRARIES + BLAS + sgemm + "" + "dxml" + "" + ) + endif(NOT BLAS_LIBRARIES) +endif (BLA_VENDOR STREQUAL "DXML" OR BLA_VENDOR STREQUAL "All") + +# BLAS in Sun Performance library? +if (BLA_VENDOR STREQUAL "SunPerf" OR BLA_VENDOR STREQUAL "All") + if(NOT BLAS_LIBRARIES) + check_fortran_libraries( + BLAS_LIBRARIES + BLAS + sgemm + "-xlic_lib=sunperf" + "sunperf;sunmath" + "" + ) + if(BLAS_LIBRARIES) + set(BLAS_LINKER_FLAGS "-xlic_lib=sunperf") + endif(BLAS_LIBRARIES) + endif(NOT BLAS_LIBRARIES) +endif (BLA_VENDOR STREQUAL "SunPerf" OR BLA_VENDOR STREQUAL "All") + +# BLAS in SCSL library? (SGI/Cray Scientific Library) +if (BLA_VENDOR STREQUAL "SCSL" OR BLA_VENDOR STREQUAL "All") + if(NOT BLAS_LIBRARIES) + check_fortran_libraries( + BLAS_LIBRARIES + BLAS + sgemm + "" + "scsl" + "" + ) + endif(NOT BLAS_LIBRARIES) +endif (BLA_VENDOR STREQUAL "SCSL" OR BLA_VENDOR STREQUAL "All") + +# BLAS in SGIMATH library? +if (BLA_VENDOR STREQUAL "SGIMATH" OR BLA_VENDOR STREQUAL "All") + if(NOT BLAS_LIBRARIES) + check_fortran_libraries( + BLAS_LIBRARIES + BLAS + sgemm + "" + "complib.sgimath" + "" + ) + endif(NOT BLAS_LIBRARIES) +endif (BLA_VENDOR STREQUAL "SGIMATH" OR BLA_VENDOR STREQUAL "All") + +# BLAS in IBM ESSL library? (requires generic BLAS lib, too) +if (BLA_VENDOR STREQUAL "IBMESSL" OR BLA_VENDOR STREQUAL "All") + if(NOT BLAS_LIBRARIES) + check_fortran_libraries( + BLAS_LIBRARIES + BLAS + sgemm + "" + "essl;blas" + "" + ) + endif(NOT BLAS_LIBRARIES) +endif (BLA_VENDOR STREQUAL "IBMESSL" OR BLA_VENDOR STREQUAL "All") + +#BLAS in acml library? +if (BLA_VENDOR STREQUAL "ACML" OR BLA_VENDOR STREQUAL "All") + if(NOT BLAS_LIBRARIES) + check_fortran_libraries( + BLAS_LIBRARIES + BLAS + sgemm + "" + "acml_mp;acml_mv" + "" + ) + endif(NOT BLAS_LIBRARIES) +endif (BLA_VENDOR STREQUAL "ACML" OR BLA_VENDOR STREQUAL "All") + +# Apple BLAS library? +if (BLA_VENDOR STREQUAL "Apple" OR BLA_VENDOR STREQUAL "All") +if(NOT BLAS_LIBRARIES) + check_fortran_libraries( + BLAS_LIBRARIES + BLAS + cblas_dgemm + "" + "Accelerate" + "" + ) + endif(NOT BLAS_LIBRARIES) +endif (BLA_VENDOR STREQUAL "Apple" OR BLA_VENDOR STREQUAL "All") + +if (BLA_VENDOR STREQUAL "NAS" OR BLA_VENDOR STREQUAL "All") + if ( NOT BLAS_LIBRARIES ) + check_fortran_libraries( + BLAS_LIBRARIES + BLAS + cblas_dgemm + "" + "vecLib" + "" + ) + endif ( NOT BLAS_LIBRARIES ) +endif (BLA_VENDOR STREQUAL "NAS" OR BLA_VENDOR STREQUAL "All") +# Generic BLAS library? +if (BLA_VENDOR STREQUAL "Generic" OR BLA_VENDOR STREQUAL "All") + if(NOT BLAS_LIBRARIES) + check_fortran_libraries( + BLAS_LIBRARIES + BLAS + sgemm + "" + "blas" + "" + ) + endif(NOT BLAS_LIBRARIES) +endif (BLA_VENDOR STREQUAL "Generic" OR BLA_VENDOR STREQUAL "All") + +#BLAS in intel mkl 10 library? (em64t 64bit) +if (BLA_VENDOR MATCHES "Intel*" OR BLA_VENDOR STREQUAL "All") + if (NOT WIN32) + set(LM "-lm") + endif () + if (_LANGUAGES_ MATCHES C OR _LANGUAGES_ MATCHES CXX) + if(BLAS_FIND_QUIETLY OR NOT BLAS_FIND_REQUIRED) + find_package(Threads) + else(BLAS_FIND_QUIETLY OR NOT BLAS_FIND_REQUIRED) + find_package(Threads REQUIRED) + endif(BLAS_FIND_QUIETLY OR NOT BLAS_FIND_REQUIRED) + if (WIN32) + if(BLA_F95) + if(NOT BLAS95_LIBRARIES) + check_fortran_libraries( + BLAS95_LIBRARIES + BLAS + sgemm + "" + "mkl_blas95;mkl_intel_c;mkl_intel_thread;mkl_core;libguide40" + "" + ) + endif(NOT BLAS95_LIBRARIES) + else(BLA_F95) + if(NOT BLAS_LIBRARIES) + check_fortran_libraries( + BLAS_LIBRARIES + BLAS + SGEMM + "" + "mkl_c_dll;mkl_intel_thread_dll;mkl_core_dll;libguide40" + "" + ) + endif(NOT BLAS_LIBRARIES) + endif(BLA_F95) + else(WIN32) + if (BLA_VENDOR STREQUAL "Intel10_32" OR BLA_VENDOR STREQUAL "All") + if(BLA_F95) + if(NOT BLAS95_LIBRARIES) + check_fortran_libraries( + BLAS95_LIBRARIES + BLAS + sgemm + "" + "mkl_blas95;mkl_intel;mkl_intel_thread;mkl_core;guide" + "${CMAKE_THREAD_LIBS_INIT};${LM}" + ) + endif(NOT BLAS95_LIBRARIES) + else(BLA_F95) + if(NOT BLAS_LIBRARIES) + check_fortran_libraries( + BLAS_LIBRARIES + BLAS + sgemm + "" + "mkl_intel;mkl_intel_thread;mkl_core;guide" + "${CMAKE_THREAD_LIBS_INIT}" + "${LM}" + ) + endif(NOT BLAS_LIBRARIES) + endif(BLA_F95) + endif (BLA_VENDOR STREQUAL "Intel10_32" OR BLA_VENDOR STREQUAL "All") + if (BLA_VENDOR STREQUAL "Intel10_64lp" OR BLA_VENDOR STREQUAL "All") + if(BLA_F95) + if(NOT BLAS95_LIBRARIES) + check_fortran_libraries( + BLAS95_LIBRARIES + BLAS + sgemm + "" + "mkl_blas95;mkl_intel_lp64;mkl_intel_thread;mkl_core;guide" + "${CMAKE_THREAD_LIBS_INIT};${LM}" + ) + endif(NOT BLAS95_LIBRARIES) + else(BLA_F95) + if(NOT BLAS_LIBRARIES) + check_fortran_libraries( + BLAS_LIBRARIES + BLAS + sgemm + "" + "mkl_intel_lp64;mkl_intel_thread;mkl_core;guide" + "${CMAKE_THREAD_LIBS_INIT};${LM}" + ) + endif(NOT BLAS_LIBRARIES) + endif(BLA_F95) + endif (BLA_VENDOR STREQUAL "Intel10_64lp" OR BLA_VENDOR STREQUAL "All") + endif (WIN32) + #older vesions of intel mkl libs + # BLAS in intel mkl library? (shared) + if(NOT BLAS_LIBRARIES) + check_fortran_libraries( + BLAS_LIBRARIES + BLAS + sgemm + "" + "mkl;guide" + "${CMAKE_THREAD_LIBS_INIT};${LM}" + ) + endif(NOT BLAS_LIBRARIES) + #BLAS in intel mkl library? (static, 32bit) + if(NOT BLAS_LIBRARIES) + check_fortran_libraries( + BLAS_LIBRARIES + BLAS + sgemm + "" + "mkl_ia32;guide" + "${CMAKE_THREAD_LIBS_INIT};${LM}" + ) + endif(NOT BLAS_LIBRARIES) + #BLAS in intel mkl library? (static, em64t 64bit) + if(NOT BLAS_LIBRARIES) + check_fortran_libraries( + BLAS_LIBRARIES + BLAS + sgemm + "" + "mkl_em64t;guide" + "${CMAKE_THREAD_LIBS_INIT};${LM}" + ) + endif(NOT BLAS_LIBRARIES) + endif (_LANGUAGES_ MATCHES C OR _LANGUAGES_ MATCHES CXX) +endif (BLA_VENDOR MATCHES "Intel*" OR BLA_VENDOR STREQUAL "All") + + +if(BLA_F95) + if(BLAS95_LIBRARIES) + set(BLAS95_FOUND TRUE) + else(BLAS95_LIBRARIES) + set(BLAS95_FOUND FALSE) + endif(BLAS95_LIBRARIES) + + if(NOT BLAS_FIND_QUIETLY) + if(BLAS95_FOUND) + message(STATUS "A library with BLAS95 API found.") + else(BLAS95_FOUND) + if(BLAS_FIND_REQUIRED) + message(FATAL_ERROR + "A required library with BLAS95 API not found. Please specify library location.") + else(BLAS_FIND_REQUIRED) + message(STATUS + "A library with BLAS95 API not found. Please specify library location.") + endif(BLAS_FIND_REQUIRED) + endif(BLAS95_FOUND) + endif(NOT BLAS_FIND_QUIETLY) + set(BLAS_FOUND TRUE) + set(BLAS_LIBRARIES "${BLAS95_LIBRARIES}") +else(BLA_F95) + if(BLAS_LIBRARIES) + set(BLAS_FOUND TRUE) + else(BLAS_LIBRARIES) + set(BLAS_FOUND FALSE) + endif(BLAS_LIBRARIES) + + if(NOT BLAS_FIND_QUIETLY) + if(BLAS_FOUND) + message(STATUS "A library with BLAS API found.") + else(BLAS_FOUND) + if(BLAS_FIND_REQUIRED) + message(FATAL_ERROR + "A required library with BLAS API not found. Please specify library location." + ) + else(BLAS_FIND_REQUIRED) + message(STATUS + "A library with BLAS API not found. Please specify library location." + ) + endif(BLAS_FIND_REQUIRED) + endif(BLAS_FOUND) + endif(NOT BLAS_FIND_QUIETLY) +endif(BLA_F95) diff --git a/cmake/FindLAPACK.cmake b/cmake/FindLAPACK.cmake new file mode 100644 index 0000000000000000000000000000000000000000..bf45406772253f858fd68b04a933f3da9d2af678 --- /dev/null +++ b/cmake/FindLAPACK.cmake @@ -0,0 +1,302 @@ +# - Find LAPACK library +# This module finds an installed fortran library that implements the LAPACK +# linear-algebra interface (see http://www.netlib.org/lapack/). +# +# The approach follows that taken for the autoconf macro file, acx_lapack.m4 +# (distributed at http://ac-archive.sourceforge.net/ac-archive/acx_lapack.html). +# +# This module sets the following variables: +# LAPACK_FOUND - set to true if a library implementing the LAPACK interface +# is found +# LAPACK_LINKER_FLAGS - uncached list of required linker flags (excluding -l +# and -L). +# LAPACK_LIBRARIES - uncached list of libraries (using full path name) to +# link against to use LAPACK +# LAPACK95_LIBRARIES - uncached list of libraries (using full path name) to +# link against to use LAPACK95 +# LAPACK95_FOUND - set to true if a library implementing the LAPACK f95 +# interface is found +# BLA_STATIC if set on this determines what kind of linkage we do (static) +# BLA_VENDOR if set checks only the specified vendor, if not set checks +# all the possibilities +# BLA_F95 if set on tries to find the f95 interfaces for BLAS/LAPACK +### List of vendors (BLA_VENDOR) valid in this module +## Intel(mkl), ACML,Apple, NAS, Generic + +#============================================================================= +# Copyright 2007-2009 Kitware, Inc. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +get_property(_LANGUAGES_ GLOBAL PROPERTY ENABLED_LANGUAGES) +if (NOT _LANGUAGES_ MATCHES Fortran) +include(CheckFunctionExists) +else (NOT _LANGUAGES_ MATCHES Fortran) +include(CheckFortranFunctionExists) +endif (NOT _LANGUAGES_ MATCHES Fortran) + +set(LAPACK_FOUND FALSE) +set(LAPACK95_FOUND FALSE) + +macro(Check_Lapack_Libraries LIBRARIES _prefix _name _flags _list _blas _threads) +# This macro checks for the existence of the combination of fortran libraries +# given by _list. If the combination is found, this macro checks (using the +# Check_Fortran_Function_Exists macro) whether can link against that library +# combination using the name of a routine given by _name using the linker +# flags given by _flags. If the combination of libraries is found and passes +# the link test, LIBRARIES is set to the list of complete library paths that +# have been found. Otherwise, LIBRARIES is set to FALSE. + +# N.B. _prefix is the prefix applied to the names of all cached variables that +# are generated internally and marked advanced by this macro. + +set(_libraries_work TRUE) +set(${LIBRARIES}) +set(_combined_name) +foreach(_library ${_list}) + set(_combined_name ${_combined_name}_${_library}) + + if(_libraries_work) + IF (WIN32) + if(BLA_STATIC) + set(CMAKE_FIND_LIBRARY_SUFFIXES ".lib;.dll") + endif(BLA_STATIC) + find_library(${_prefix}_${_library}_LIBRARY + NAMES ${_library} + PATHS ENV LIB + ) + ENDIF (WIN32) + + if(APPLE) + if(BLA_STATIC) + set(CMAKE_FIND_LIBRARY_SUFFIXES ".a;.so;.dylib") + endif(BLA_STATIC) + find_library(${_prefix}_${_library}_LIBRARY + NAMES ${_library} + PATHS /usr/local/lib /usr/lib /usr/local/lib64 /usr/lib64 ENV DYLD_LIBRARY_PATH + ) + else(APPLE) + if(BLA_STATIC) + set(CMAKE_FIND_LIBRARY_SUFFIXES ".a;.so") + endif(BLA_STATIC) + find_library(${_prefix}_${_library}_LIBRARY + NAMES ${_library} + PATHS /usr/local/lib /usr/lib /usr/local/lib64 /usr/lib64 ENV LD_LIBRARY_PATH + ) + endif(APPLE) + + mark_as_advanced(${_prefix}_${_library}_LIBRARY) + set(${LIBRARIES} ${${LIBRARIES}} ${${_prefix}_${_library}_LIBRARY}) + set(_libraries_work ${${_prefix}_${_library}_LIBRARY}) + endif(_libraries_work) +endforeach(_library ${_list}) + +if(_libraries_work) + # Test this combination of libraries. + if(UNIX AND BLA_STATIC) + set(CMAKE_REQUIRED_LIBRARIES ${_flags} "-Wl,--start-group ${${LIBRARIES}} ${_blas};-Wl,--end-group" ${_threads}) + else(UNIX AND BLA_STATIC) + set(CMAKE_REQUIRED_LIBRARIES ${_flags} ${${LIBRARIES}} ${_blas} ${_threads}) + endif(UNIX AND BLA_STATIC) +# message("DEBUG: CMAKE_REQUIRED_LIBRARIES = ${CMAKE_REQUIRED_LIBRARIES}") + if (NOT _LANGUAGES_ MATCHES Fortran) + check_function_exists("${_name}_" ${_prefix}${_combined_name}_WORKS) + else (NOT _LANGUAGES_ MATCHES Fortran) + check_fortran_function_exists(${_name} ${_prefix}${_combined_name}_WORKS) + endif (NOT _LANGUAGES_ MATCHES Fortran) + set(CMAKE_REQUIRED_LIBRARIES) + mark_as_advanced(${_prefix}${_combined_name}_WORKS) + set(_libraries_work ${${_prefix}${_combined_name}_WORKS}) + #message("DEBUG: ${LIBRARIES} = ${${LIBRARIES}}") +endif(_libraries_work) + + if(_libraries_work) + set(${LIBRARIES} ${${LIBRARIES}} ${_blas}) + else(_libraries_work) + set(${LIBRARIES} FALSE) + endif(_libraries_work) + +endmacro(Check_Lapack_Libraries) + + +set(LAPACK_LINKER_FLAGS) +set(LAPACK_LIBRARIES) +set(LAPACK95_LIBRARIES) + + +if(LAPACK_FIND_QUIETLY OR NOT LAPACK_FIND_REQUIRED) + find_package(BLAS) +else(LAPACK_FIND_QUIETLY OR NOT LAPACK_FIND_REQUIRED) + find_package(BLAS REQUIRED) +endif(LAPACK_FIND_QUIETLY OR NOT LAPACK_FIND_REQUIRED) + + +if(BLAS_FOUND) + set(LAPACK_LINKER_FLAGS ${BLAS_LINKER_FLAGS}) + if ($ENV{BLA_VENDOR} MATCHES ".+") + set(BLA_VENDOR $ENV{BLA_VENDOR}) + else ($ENV{BLA_VENDOR} MATCHES ".+") + if(NOT BLA_VENDOR) + set(BLA_VENDOR "All") + endif(NOT BLA_VENDOR) + endif ($ENV{BLA_VENDOR} MATCHES ".+") +#acml lapack + if (BLA_VENDOR STREQUAL "ACML" OR BLA_VENDOR STREQUAL "All") + if(NOT LAPACK_LIBRARIES) + check_lapack_libraries( + LAPACK_LIBRARIES + LAPACK + cheev + "" + "acml;acml_mv" + "" + "" + ) + endif(NOT LAPACK_LIBRARIES) + if(NOT LAPACK_LIBRARIES) + check_lapack_libraries( + LAPACK_LIBRARIES + LAPACK + cheev + "" + "acml_mp;acml_mv" + "" + "" + ) + endif(NOT LAPACK_LIBRARIES) + endif (BLA_VENDOR STREQUAL "ACML" OR BLA_VENDOR STREQUAL "All") + +# Apple LAPACK library? +if (BLA_VENDOR STREQUAL "Apple" OR BLA_VENDOR STREQUAL "All") + if(NOT LAPACK_LIBRARIES) + check_lapack_libraries( + LAPACK_LIBRARIES + LAPACK + cheev + "" + "Accelerate" + "${BLAS_LIBRARIES}" + "" + ) + endif(NOT LAPACK_LIBRARIES) +endif (BLA_VENDOR STREQUAL "Apple" OR BLA_VENDOR STREQUAL "All") +if (BLA_VENDOR STREQUAL "NAS" OR BLA_VENDOR STREQUAL "All") + if ( NOT LAPACK_LIBRARIES ) + check_lapack_libraries( + LAPACK_LIBRARIES + LAPACK + cheev + "" + "vecLib" + "${BLAS_LIBRARIES}" + "" + ) + endif ( NOT LAPACK_LIBRARIES ) +endif (BLA_VENDOR STREQUAL "NAS" OR BLA_VENDOR STREQUAL "All") +# Generic LAPACK library? +if (BLA_VENDOR STREQUAL "Generic" OR BLA_VENDOR STREQUAL "All") + if ( NOT LAPACK_LIBRARIES ) + check_lapack_libraries( + LAPACK_LIBRARIES + LAPACK + cheev + "" + "lapack" + "${BLAS_LIBRARIES}" + "" + ) + endif ( NOT LAPACK_LIBRARIES ) +endif (BLA_VENDOR STREQUAL "Generic" OR BLA_VENDOR STREQUAL "All") +#intel lapack + if (BLA_VENDOR MATCHES "Intel*" OR BLA_VENDOR STREQUAL "All") + if (_LANGUAGES_ MATCHES C OR _LANGUAGES_ MATCHES CXX) + if(LAPACK_FIND_QUIETLY OR NOT LAPACK_FIND_REQUIRED) + find_PACKAGE(Threads) + else(LAPACK_FIND_QUIETLY OR NOT LAPACK_FIND_REQUIRED) + find_package(Threads REQUIRED) + endif(LAPACK_FIND_QUIETLY OR NOT LAPACK_FIND_REQUIRED) + if (BLA_F95) + if(NOT LAPACK95_LIBRARIES) + check_lapack_libraries( + LAPACK95_LIBRARIES + LAPACK + cheev + "" + "mkl_lapack95" + "${BLAS95_LIBRARIES}" + "${CMAKE_THREAD_LIBS_INIT}" + ) + endif(NOT LAPACK95_LIBRARIES) + else(BLA_F95) + if(NOT LAPACK_LIBRARIES) + check_lapack_libraries( + LAPACK_LIBRARIES + LAPACK + cheev + "" + "mkl_lapack" + "${BLAS_LIBRARIES}" + "${CMAKE_THREAD_LIBS_INIT}" + ) + endif(NOT LAPACK_LIBRARIES) + endif(BLA_F95) + endif (_LANGUAGES_ MATCHES C OR _LANGUAGES_ MATCHES CXX) + endif(BLA_VENDOR MATCHES "Intel*" OR BLA_VENDOR STREQUAL "All") +else(BLAS_FOUND) + message(STATUS "LAPACK requires BLAS") +endif(BLAS_FOUND) + +if(BLA_F95) + if(LAPACK95_LIBRARIES) + set(LAPACK95_FOUND TRUE) + else(LAPACK95_LIBRARIES) + set(LAPACK95_FOUND FALSE) + endif(LAPACK95_LIBRARIES) + if(NOT LAPACK_FIND_QUIETLY) + if(LAPACK95_FOUND) + message(STATUS "A library with LAPACK95 API found.") + else(LAPACK95_FOUND) + if(LAPACK_FIND_REQUIRED) + message(FATAL_ERROR + "A required library with LAPACK95 API not found. Please specify library location." + ) + else(LAPACK_FIND_REQUIRED) + message(STATUS + "A library with LAPACK95 API not found. Please specify library location." + ) + endif(LAPACK_FIND_REQUIRED) + endif(LAPACK95_FOUND) + endif(NOT LAPACK_FIND_QUIETLY) + set(LAPACK_FOUND "${LAPACK95_FOUND}") + set(LAPACK_LIBRARIES "${LAPACK95_LIBRARIES}") +else(BLA_F95) + if(LAPACK_LIBRARIES) + set(LAPACK_FOUND TRUE) + else(LAPACK_LIBRARIES) + set(LAPACK_FOUND FALSE) + endif(LAPACK_LIBRARIES) + + if(NOT LAPACK_FIND_QUIETLY) + if(LAPACK_FOUND) + message(STATUS "A library with LAPACK API found.") + else(LAPACK_FOUND) + if(LAPACK_FIND_REQUIRED) + message(FATAL_ERROR + "A required library with LAPACK API not found. Please specify library location." + ) + else(LAPACK_FIND_REQUIRED) + message(STATUS + "A library with LAPACK API not found. Please specify library location." + ) + endif(LAPACK_FIND_REQUIRED) + endif(LAPACK_FOUND) + endif(NOT LAPACK_FIND_QUIETLY) +endif(BLA_F95)