stage changes

This commit is contained in:
L-Nafaryus 2024-03-14 15:57:16 +05:00
parent 38d628d4ef
commit 39b2063889
Signed by: L-Nafaryus
GPG Key ID: 582F8B0866B294A1
27 changed files with 3393 additions and 2917 deletions

66
.clang-format Normal file
View File

@ -0,0 +1,66 @@
# Generated from CLion C/C++ Code Style settings
BasedOnStyle: LLVM
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: None
AlignOperands: Align
AllowAllArgumentsOnNextLine: false
AllowAllConstructorInitializersOnNextLine: false
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: Always
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: Always
AllowShortLambdasOnASingleLine: All
AllowShortLoopsOnASingleLine: true
AlwaysBreakAfterReturnType: None
AlwaysBreakTemplateDeclarations: Yes
BreakBeforeBraces: Custom
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: Never
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterUnion: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
SplitEmptyFunction: false
SplitEmptyRecord: true
BreakBeforeBinaryOperators: None
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: BeforeColon
BreakInheritanceList: BeforeColon
ColumnLimit: 0
CompactNamespaces: false
ContinuationIndentWidth: 8
IndentCaseLabels: true
IndentPPDirectives: None
IndentWidth: 4
KeepEmptyLinesAtTheStartOfBlocks: true
MaxEmptyLinesToKeep: 2
NamespaceIndentation: All
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PointerAlignment: Right
ReflowComments: false
SpaceAfterCStyleCast: true
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 0
SpacesInAngles: false
SpacesInCStyleCastParentheses: false
SpacesInContainerLiterals: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
TabWidth: 4
UseTab: Never

24
.gitignore vendored
View File

@ -1,13 +1,13 @@
# Xmake cache
.xmake/
build/
# MacOS Cache
.DS_Store/
# CMake
CMakeLists.txt
cmake-build-*/
# Idea
# Xmake cache
.xmake/
build/
# MacOS Cache
.DS_Store/
# CMake
CMakeLists.txt
cmake-build-*/
# Idea
.idea/

15
.vscode/c_cpp_properties.json vendored Normal file
View File

@ -0,0 +1,15 @@
{
"configurations": [
{
"name": "windows-gcc",
"compileCommands": ".vscode/compile_commands.json",
"intelliSenseMode": "windows-gcc-x64",
"compilerPath": "C:/Users/Administrator/scoop/apps/msys2/current/mingw64/bin/gcc.exe",
"includePath": [
"${workspaceFolder}/source"
],
"cppStandard": "gnu++20"
}
],
"version": 4
}

26
.vscode/compile_commands.json vendored Normal file
View File

@ -0,0 +1,26 @@
[
{
"directory": "c:\\Users\\Administrator\\Projects\\hpr",
"arguments": ["C:\\Users\\Administrator\\scoop\\apps\\msys2\\current\\mingw64\\bin\\x86_64-w64-mingw32-g++.exe", "-c", "-m64", "-O3", "-std=c++20", "-Isource", "-IC:\\Users\\Administrator\\AppData\\Local\\.xmake\\packages\\i\\imgui\\v1.90-docking\\600835732f214b96b5dbfaccf42f7a60\\include", "-IC:\\Users\\Administrator\\AppData\\Local\\.xmake\\packages\\i\\imgui\\v1.90-docking\\600835732f214b96b5dbfaccf42f7a60\\include\\imgui", "-IC:\\Users\\Administrator\\AppData\\Local\\.xmake\\packages\\i\\imgui\\v1.90-docking\\600835732f214b96b5dbfaccf42f7a60\\include\\backends", "-IC:\\Users\\Administrator\\AppData\\Local\\.xmake\\packages\\i\\imgui\\v1.90-docking\\600835732f214b96b5dbfaccf42f7a60\\include\\misc\\cpp", "-IC:\\Users\\Administrator\\AppData\\Local\\.xmake\\packages\\i\\implot\\v0.15\\6861f774eb2844d6a543372e119845e3\\include", "-IC:\\Users\\Administrator\\AppData\\Local\\.xmake\\packages\\i\\imgui\\v1.90\\853d785fcf03454094beebf60559d12f\\include", "-IC:\\Users\\Administrator\\AppData\\Local\\.xmake\\packages\\i\\imgui\\v1.90\\853d785fcf03454094beebf60559d12f\\include\\imgui", "-IC:\\Users\\Administrator\\AppData\\Local\\.xmake\\packages\\i\\imgui\\v1.90\\853d785fcf03454094beebf60559d12f\\include\\backends", "-IC:\\Users\\Administrator\\AppData\\Local\\.xmake\\packages\\i\\imgui\\v1.90\\853d785fcf03454094beebf60559d12f\\include\\misc\\cpp", "-IC:\\Users\\Administrator\\AppData\\Local\\.xmake\\packages\\g\\glfw\\3.3.8\\d31abc5641874d8fbdc13f33b5569420\\include", "-IC:\\Users\\Administrator\\scoop\\apps\\msys2\\2023-10-26\\mingw64\\include", "-IC:\\Users\\Administrator\\scoop\\apps\\msys2\\2023-10-26\\mingw64\\include\\opencascade", "-DHPR_SCALAR=float", "-DGLFW_INCLUDE_NONE", "-DNDEBUG", "-o", "build\\.objs\\hpr\\mingw\\x86_64\\release\\source\\hpr\\hpr.cpp.obj", "source\\hpr\\hpr.cpp"],
"file": "source\\hpr\\hpr.cpp"
},
{
"directory": "c:\\Users\\Administrator\\Projects\\hpr",
"arguments": ["C:\\Users\\Administrator\\scoop\\apps\\msys2\\current\\mingw64\\bin\\x86_64-w64-mingw32-g++.exe", "-c", "-m64", "-fvisibility=hidden", "-fvisibility-inlines-hidden", "-O3", "-std=c++20", "-Isource", "-IC:\\Users\\Administrator\\AppData\\Local\\.xmake\\packages\\g\\gtest\\1.12.1\\40112995bdf04048acde0ee5a34578c3\\include", "-DHPR_SCALAR=float", "-DNDEBUG", "-o", "build\\.objs\\tests\\mingw\\x86_64\\release\\source\\hpr\\tests\\main.cpp.obj", "source\\hpr\\tests\\main.cpp"],
"file": "source\\hpr\\tests\\main.cpp"
},
{
"directory": "c:\\Users\\Administrator\\Projects\\hpr",
"arguments": ["C:\\Users\\Administrator\\scoop\\apps\\msys2\\current\\mingw64\\bin\\x86_64-w64-mingw32-g++.exe", "-c", "-m64", "-fvisibility=hidden", "-fvisibility-inlines-hidden", "-O3", "-std=c++20", "-Isource", "-IC:\\Users\\Administrator\\AppData\\Local\\.xmake\\packages\\g\\gtest\\1.12.1\\40112995bdf04048acde0ee5a34578c3\\include", "-DHPR_SCALAR=float", "-DNDEBUG", "-o", "build\\.objs\\tests\\mingw\\x86_64\\release\\source\\hpr\\tests\\test_container.cpp.obj", "source\\hpr\\tests\\test_container.cpp"],
"file": "source\\hpr\\tests\\test_container.cpp"
},
{
"directory": "c:\\Users\\Administrator\\Projects\\hpr",
"arguments": ["C:\\Users\\Administrator\\scoop\\apps\\msys2\\current\\mingw64\\bin\\x86_64-w64-mingw32-g++.exe", "-c", "-m64", "-fvisibility=hidden", "-fvisibility-inlines-hidden", "-O3", "-std=c++20", "-Isource", "-IC:\\Users\\Administrator\\AppData\\Local\\.xmake\\packages\\g\\gtest\\1.12.1\\40112995bdf04048acde0ee5a34578c3\\include", "-DHPR_SCALAR=float", "-DNDEBUG", "-o", "build\\.objs\\tests\\mingw\\x86_64\\release\\source\\hpr\\tests\\test_math.cpp.obj", "source\\hpr\\tests\\test_math.cpp"],
"file": "source\\hpr\\tests\\test_math.cpp"
},
{
"directory": "c:\\Users\\Administrator\\Projects\\hpr",
"arguments": ["C:\\Users\\Administrator\\scoop\\apps\\msys2\\current\\mingw64\\bin\\x86_64-w64-mingw32-g++.exe", "-c", "-m64", "-fvisibility=hidden", "-fvisibility-inlines-hidden", "-O3", "-std=c++20", "-Isource", "-IC:\\Users\\Administrator\\AppData\\Local\\.xmake\\packages\\g\\gtest\\1.12.1\\40112995bdf04048acde0ee5a34578c3\\include", "-DHPR_SCALAR=float", "-DNDEBUG", "-o", "build\\.objs\\tests\\mingw\\x86_64\\release\\source\\hpr\\tests\\test_numeric.cpp.obj", "source\\hpr\\tests\\test_numeric.cpp"],
"file": "source\\hpr\\tests\\test_numeric.cpp"
}]

View File

@ -1,7 +1,7 @@
#pragma once
#include <hpr/container/iterator.hpp>
#include <hpr/container/sequence.hpp>
#include <hpr/container/static_array.hpp>
#include <hpr/container/dynamic_array.hpp>
#include <hpr/container/tree_node.hpp>
#pragma once
#include <hpr/container/iterator.hpp>
#include <hpr/container/sequence.hpp>
#include <hpr/container/static_array.hpp>
#include <hpr/container/dynamic_array.hpp>
#include <hpr/container/tree_node.hpp>

View File

@ -1,307 +1,307 @@
#pragma once
#include <hpr/container/sequence.hpp>
#include <functional>
#include <limits>
namespace hpr
{
// forward declaration
template <typename T>
class DynamicArray;
// type traits
template <typename T>
struct is_sequence<DynamicArray<T>> : public std::true_type
{};
// aliases
template <typename T>
using darray = DynamicArray<T>;
// class definition
template <typename T>
class DynamicArray : public Sequence<T>
{
using base = Sequence<T>;
public:
using difference_type = std::ptrdiff_t;
using value_type = T;
using size_type = Size;
using pointer = T*;
using reference = T&;
using iterator = Iterator<T>;
using const_pointer = T const*;
using const_reference = T const&;
using const_iterator = Iterator<const T>;
public:
friend constexpr
void swap(DynamicArray& main, DynamicArray& other) noexcept
{
using std::swap;
swap(static_cast<base&>(main), static_cast<base&>(other));
}
constexpr
DynamicArray() noexcept :
base {}
{}
constexpr explicit
DynamicArray(const base& b) noexcept :
base {b}
{}
constexpr explicit
DynamicArray(base&& b) noexcept :
base {std::forward<base>(b)}
{}
constexpr
DynamicArray(const DynamicArray& arr) noexcept :
base {static_cast<base>(arr)}
{}
//! Move constructor
constexpr
DynamicArray(DynamicArray&& arr) noexcept :
base {std::forward<base>(static_cast<base>(arr))}
{}
template <typename Iter>
constexpr
DynamicArray(Iter start, Iter end) :
base {start, end}
{}
constexpr
DynamicArray(typename base::iterator start, typename base::iterator end) :
base {start, end}
{}
constexpr
DynamicArray(typename base::const_iterator start, typename base::const_iterator end) :
base {start, end}
{}
constexpr
DynamicArray(typename base::iterator start, typename base::iterator end, size_type capacity) :
base {start, end, capacity}
{}
constexpr
DynamicArray(typename base::const_iterator start, typename base::const_iterator end, size_type capacity) :
base {start, end, capacity}
{}
constexpr
DynamicArray(std::initializer_list<value_type> list) :
base {list.begin(), list.end()}
{}
constexpr
DynamicArray(size_type size, value_type value) noexcept :
base {size, value}
{}
constexpr
DynamicArray& operator=(base other) noexcept
{
swap(*this, other);
return *this;
}
constexpr
DynamicArray& operator=(DynamicArray other) noexcept
{
swap(*this, other);
return *this;
}
constexpr
DynamicArray& operator=(DynamicArray&& arr) noexcept
{
swap(*this, arr);
return *this;
}
virtual
~DynamicArray() = default;
// Member functions
[[nodiscard]] virtual constexpr
size_type capacity() const noexcept
{
return base::p_capacity;
}
[[nodiscard]] virtual constexpr
bool is_empty() const
{
return base::begin() == base::end();
}
virtual constexpr
iterator storage_end()
{
return iterator(base::p_start + base::p_capacity);
}
virtual constexpr
const_iterator storage_end() const
{
return const_iterator(base::p_start + base::p_capacity);
}
virtual constexpr
void resize(size_type newCapacity)
{
if (newCapacity == base::p_capacity)
return;
if (std::numeric_limits<size_type>::max() - base::size() < newCapacity)
throw hpr::LengthError("Invalid capacity value passed");
if (newCapacity > base::p_capacity)
{
DynamicArray tmp {base::begin(), base::end(), newCapacity};
swap(*this, tmp);
}
else
{
if (newCapacity >= base::p_size)
{
DynamicArray tmp {base::begin(), base::end()};
swap(*this, tmp);
}
else
{
DynamicArray tmp {base::begin(), base::begin() + newCapacity};
swap(*this, tmp);
}
}
}
virtual constexpr
void push(const value_type& val)
{
if (base::end() == storage_end())
resize(base::p_capacity * 2);
*base::end() = val;
++base::p_size;
}
virtual constexpr
void push(value_type&& val)
{
if (base::end() == storage_end())
resize(base::p_capacity * 2);
*base::end() = std::move(val);
++base::p_size;
}
virtual constexpr
void push(const DynamicArray<T>& arr)
{
for (const value_type& el : arr)
push(el);
}
virtual constexpr
value_type pop()
{
if (is_empty())
throw hpr::LengthError("Cannot pop element from empty array");
value_type val = base::back();
std::destroy_at(base::p_start + base::p_size);
--base::p_size;
return val;
}
virtual constexpr
void insert(size_type position, const value_type& val)
{
if (base::end() == storage_end())
resize(base::p_capacity * 2);
for (size_type n = base::p_size; n > position; --n)
*(base::p_start + n) = std::move(*(base::p_start + n - 1));
*(base::p_start + position) = val;
++base::p_size;
}
virtual constexpr
void insert(size_type position, value_type&& val)
{
if (base::end() == storage_end())
resize(base::p_capacity * 2);
for (size_type n = base::p_size; n > position; --n)
*(base::p_start + n) = std::move(*(base::p_start + n - 1));
*(base::p_start + position) = std::move(val);
++base::p_size;
}
virtual constexpr
void remove(size_type position)
{
for (size_type n = position; n < base::p_size - 1; ++n)
*(base::p_start + n) = std::move(*(base::p_start + n + 1));
std::destroy_at(base::p_start + base::p_size);
--base::p_size;
}
virtual constexpr
void remove(iterator position)
{
if (position + 1 != base::end())
std::copy(position + 1, base::end(), position);
std::destroy_at(base::p_start + base::p_size);
--base::p_size;
}
virtual constexpr
void remove(const std::function<bool(value_type)>& condition)
{
size_type newSize = base::p_size;
for (size_type offset = 0; offset < newSize; ++offset)
{
if (condition(*(base::p_start + offset)))
{
for (size_type n = offset; n < newSize; ++n)
*(base::p_start + n) = std::move(*(base::p_start + n + 1));
--newSize;
--offset;
}
}
base::p_size = newSize;
}
virtual constexpr
void clear()
{
delete[] base::p_start;
base::p_size = 0;
base::p_capacity = 1;
base::p_start = new value_type[base::p_capacity];
}
DynamicArray slice(iterator start, iterator end)
{
return DynamicArray {start, end};
}
};
#pragma once
#include <hpr/container/sequence.hpp>
#include <functional>
#include <limits>
namespace hpr
{
// forward declaration
template <typename T>
class DynamicArray;
// type traits
template <typename T>
struct is_sequence<DynamicArray<T>> : public std::true_type
{};
// aliases
template <typename T>
using darray = DynamicArray<T>;
// class definition
template <typename T>
class DynamicArray : public Sequence<T>
{
using base = Sequence<T>;
public:
using difference_type = std::ptrdiff_t;
using value_type = T;
using size_type = Size;
using pointer = T*;
using reference = T&;
using iterator = Iterator<T>;
using const_pointer = T const*;
using const_reference = T const&;
using const_iterator = Iterator<const T>;
public:
friend constexpr
void swap(DynamicArray& main, DynamicArray& other) noexcept
{
using std::swap;
swap(static_cast<base&>(main), static_cast<base&>(other));
}
constexpr
DynamicArray() noexcept :
base {}
{}
constexpr explicit
DynamicArray(const base& b) noexcept :
base {b}
{}
constexpr explicit
DynamicArray(base&& b) noexcept :
base {std::forward<base>(b)}
{}
constexpr
DynamicArray(const DynamicArray& arr) noexcept :
base {static_cast<base>(arr)}
{}
//! Move constructor
constexpr
DynamicArray(DynamicArray&& arr) noexcept :
base {std::forward<base>(static_cast<base>(arr))}
{}
template <typename Iter>
constexpr
DynamicArray(Iter start, Iter end) :
base {start, end}
{}
constexpr
DynamicArray(typename base::iterator start, typename base::iterator end) :
base {start, end}
{}
constexpr
DynamicArray(typename base::const_iterator start, typename base::const_iterator end) :
base {start, end}
{}
constexpr
DynamicArray(typename base::iterator start, typename base::iterator end, size_type capacity) :
base {start, end, capacity}
{}
constexpr
DynamicArray(typename base::const_iterator start, typename base::const_iterator end, size_type capacity) :
base {start, end, capacity}
{}
constexpr
DynamicArray(std::initializer_list<value_type> list) :
base {list.begin(), list.end()}
{}
constexpr
DynamicArray(size_type size, value_type value) noexcept :
base {size, value}
{}
constexpr
DynamicArray& operator=(base other) noexcept
{
swap(*this, other);
return *this;
}
constexpr
DynamicArray& operator=(DynamicArray other) noexcept
{
swap(*this, other);
return *this;
}
constexpr
DynamicArray& operator=(DynamicArray&& arr) noexcept
{
swap(*this, arr);
return *this;
}
virtual
~DynamicArray() = default;
// Member functions
[[nodiscard]] virtual constexpr
size_type capacity() const noexcept
{
return base::p_capacity;
}
[[nodiscard]] virtual constexpr
bool is_empty() const
{
return base::begin() == base::end();
}
virtual constexpr
iterator storage_end()
{
return iterator(base::p_start + base::p_capacity);
}
virtual constexpr
const_iterator storage_end() const
{
return const_iterator(base::p_start + base::p_capacity);
}
virtual constexpr
void resize(size_type newCapacity)
{
if (newCapacity == base::p_capacity)
return;
if (std::numeric_limits<size_type>::max() - base::size() < newCapacity)
throw hpr::LengthError("Invalid capacity value passed");
if (newCapacity > base::p_capacity)
{
DynamicArray tmp {base::begin(), base::end(), newCapacity};
swap(*this, tmp);
}
else
{
if (newCapacity >= base::p_size)
{
DynamicArray tmp {base::begin(), base::end()};
swap(*this, tmp);
}
else
{
DynamicArray tmp {base::begin(), base::begin() + newCapacity};
swap(*this, tmp);
}
}
}
virtual constexpr
void push(const value_type& val)
{
if (base::end() == storage_end())
resize(base::p_capacity * 2);
*base::end() = val;
++base::p_size;
}
virtual constexpr
void push(value_type&& val)
{
if (base::end() == storage_end())
resize(base::p_capacity * 2);
*base::end() = std::move(val);
++base::p_size;
}
virtual constexpr
void push(const DynamicArray<T>& arr)
{
for (const value_type& el : arr)
push(el);
}
virtual constexpr
value_type pop()
{
if (is_empty())
throw hpr::LengthError("Cannot pop element from empty array");
value_type val = base::back();
std::destroy_at(base::p_start + base::p_size);
--base::p_size;
return val;
}
virtual constexpr
void insert(size_type position, const value_type& val)
{
if (base::end() == storage_end())
resize(base::p_capacity * 2);
for (size_type n = base::p_size; n > position; --n)
*(base::p_start + n) = std::move(*(base::p_start + n - 1));
*(base::p_start + position) = val;
++base::p_size;
}
virtual constexpr
void insert(size_type position, value_type&& val)
{
if (base::end() == storage_end())
resize(base::p_capacity * 2);
for (size_type n = base::p_size; n > position; --n)
*(base::p_start + n) = std::move(*(base::p_start + n - 1));
*(base::p_start + position) = std::move(val);
++base::p_size;
}
virtual constexpr
void remove(size_type position)
{
for (size_type n = position; n < base::p_size - 1; ++n)
*(base::p_start + n) = std::move(*(base::p_start + n + 1));
std::destroy_at(base::p_start + base::p_size);
--base::p_size;
}
virtual constexpr
void remove(iterator position)
{
if (position + 1 != base::end())
std::copy(position + 1, base::end(), position);
std::destroy_at(base::p_start + base::p_size);
--base::p_size;
}
virtual constexpr
void remove(const std::function<bool(value_type)>& condition)
{
size_type newSize = base::p_size;
for (size_type offset = 0; offset < newSize; ++offset)
{
if (condition(*(base::p_start + offset)))
{
for (size_type n = offset; n < newSize; ++n)
*(base::p_start + n) = std::move(*(base::p_start + n + 1));
--newSize;
--offset;
}
}
base::p_size = newSize;
}
virtual constexpr
void clear()
{
delete[] base::p_start;
base::p_size = 0;
base::p_capacity = 1;
base::p_start = new value_type[base::p_capacity];
}
DynamicArray slice(iterator start, iterator end)
{
return DynamicArray {start, end};
}
};
} // end namespace hpr

View File

@ -1,98 +1,98 @@
#pragma once
#include <iterator>
namespace hpr
{
template <typename Type, typename Category = std::forward_iterator_tag>
class Iterator
{
public:
using iterator_category = Category;
using difference_type = std::ptrdiff_t;
using value_type = Type;
using pointer = Type*;
using reference = Type&;
using iterator = Iterator;
using const_pointer = Type const*;
using const_reference = Type const&;
using const_iterator = Iterator const;
protected:
pointer p_ptr;
public:
Iterator() :
p_ptr {nullptr}
{}
Iterator(pointer ptr) :
p_ptr {ptr}
{}
reference operator*()
{
return *p_ptr;
}
const_reference operator*() const
{
return *p_ptr;
}
pointer operator->()
{
return p_ptr;
}
const_pointer operator->() const
{
return p_ptr;
}
iterator& operator++()
{
p_ptr++;
return *this;
}
const_iterator& operator++() const
{
p_ptr++;
return *this;
}
iterator operator++(int)
{
iterator temp {*this};
++(*this);
return temp;
}
iterator operator+(int value)
{
iterator temp {*this};
temp.p_ptr += value;
return temp;
}
friend
bool operator==(const iterator& lhs, const iterator& rhs)
{
return lhs.p_ptr == rhs.p_ptr;
}
friend
bool operator!=(const iterator& lhs, const iterator& rhs)
{
return lhs.p_ptr != rhs.p_ptr;
}
};
} // end namespace hpr
#pragma once
#include <iterator>
namespace hpr
{
template <typename Type, typename Category = std::forward_iterator_tag>
class Iterator
{
public:
using iterator_category = Category;
using difference_type = std::ptrdiff_t;
using value_type = Type;
using pointer = Type*;
using reference = Type&;
using iterator = Iterator;
using const_pointer = Type const*;
using const_reference = Type const&;
using const_iterator = Iterator const;
protected:
pointer p_ptr;
public:
Iterator() :
p_ptr {nullptr}
{}
Iterator(pointer ptr) :
p_ptr {ptr}
{}
reference operator*()
{
return *p_ptr;
}
const_reference operator*() const
{
return *p_ptr;
}
pointer operator->()
{
return p_ptr;
}
const_pointer operator->() const
{
return p_ptr;
}
iterator& operator++()
{
p_ptr++;
return *this;
}
const_iterator& operator++() const
{
p_ptr++;
return *this;
}
iterator operator++(int)
{
iterator temp {*this};
++(*this);
return temp;
}
iterator operator+(int value)
{
iterator temp {*this};
temp.p_ptr += value;
return temp;
}
friend
bool operator==(const iterator& lhs, const iterator& rhs)
{
return lhs.p_ptr == rhs.p_ptr;
}
friend
bool operator!=(const iterator& lhs, const iterator& rhs)
{
return lhs.p_ptr != rhs.p_ptr;
}
};
} // end namespace hpr

View File

@ -1,319 +1,319 @@
#pragma once
#include <hpr/container/iterator.hpp>
#include <hpr/exception.hpp>
#include <hpr/numeric.hpp>
namespace hpr
{
// forward declaration
template <typename T>
class Sequence;
// type traits
template <typename T>
struct is_sequence : public std::false_type
{};
template <typename T>
struct is_sequence<Sequence<T>> : public std::true_type
{};
// concepts
template <typename Type>
concept IsSequence = is_sequence<Type>::value;
// class definition
template <typename T>
class Sequence
{
public:
using difference_type = std::ptrdiff_t;
using value_type = T;
using size_type = Size;
using pointer = T*;
using reference = T&;
using iterator = Iterator<T>;
using const_pointer = T const*;
using const_reference = T const&;
using const_iterator = Iterator<const T>;
protected:
size_type p_size;
size_type p_capacity;
pointer p_start;
protected:
constexpr
Sequence(size_type size, size_type capacity, pointer start) :
p_size {size},
p_capacity {capacity},
p_start {start}
{}
constexpr explicit
Sequence(size_type size, size_type capacity) :
p_size {size},
p_capacity {capacity},
p_start {p_capacity ? new value_type[p_capacity] : nullptr}
{}
public:
friend constexpr
void swap(Sequence& main, Sequence& other) noexcept
{
using std::swap;
swap(main.p_size, other.p_size);
swap(main.p_capacity, other.p_capacity);
swap(main.p_start, other.p_start);
}
constexpr
Sequence() noexcept :
p_size {0},
p_capacity {1},
p_start {new value_type[p_capacity]}
{}
constexpr
Sequence(const Sequence& seq) noexcept :
p_size {seq.p_size},
p_capacity {seq.p_capacity},
p_start {p_capacity ? new value_type[seq.p_capacity] : nullptr}
{
std::copy(seq.p_start, seq.p_start + seq.p_size, p_start);
}
//! Move constructor
constexpr
Sequence(Sequence&& seq) noexcept :
Sequence {}
{
swap(*this, seq);
}
template <typename Iter>
constexpr
Sequence(Iter start, Iter end) :
p_size {static_cast<size_type>(std::distance(start, end))},
p_capacity {p_size},
p_start {p_capacity ? new value_type[p_capacity] : nullptr}
{
std::copy(start, end, p_start);
}
constexpr
Sequence(iterator start, iterator end) :
p_size {static_cast<size_type>(std::distance(start, end))},
p_capacity {p_size},
p_start {p_capacity ? new value_type[p_capacity] : nullptr}
{
std::copy(start, end, p_start);
}
constexpr
Sequence(const_iterator start, const_iterator end) :
p_size {static_cast<size_type>(std::distance(start, end))},
p_capacity {p_size},
p_start {p_capacity ? new value_type[p_capacity] : nullptr}
{
std::copy(start, end, p_start);
}
constexpr
Sequence(iterator start, iterator end, size_type capacity) :
p_size {static_cast<size_type>(std::distance(start, end))},
p_capacity {capacity},
p_start {p_capacity ? new value_type[p_capacity] : nullptr}
{
std::copy(start, end, p_start);
}
constexpr
Sequence(const_iterator start, const_iterator end, size_type capacity) :
p_size {static_cast<size_type>(std::distance(start, end))},
p_capacity {capacity},
p_start {p_capacity ? new value_type[p_capacity] : nullptr}
{
std::copy(start, end, p_start);
}
/*constexpr
Sequence(std::initializer_list<value_type> list) :
Sequence {list.begin(), list.end()}
{}*/
constexpr
Sequence(size_type size, value_type value) noexcept:
p_size {size},
p_capacity {size},
p_start {p_capacity ? new value_type[p_capacity] : nullptr}
{
for (auto n = 0; n < size; ++n)
*(p_start + n) = value;
}
constexpr
Sequence& operator=(Sequence other) noexcept
{
swap(*this, other);
return *this;
}
constexpr
Sequence& operator=(Sequence&& seq) noexcept
{
swap(*this, seq);
return *this;
}
virtual
~Sequence()
{
delete[] p_start;
}
// Member functions
virtual constexpr
iterator begin()
{
return iterator(p_start);
}
[[nodiscard]] virtual constexpr
const_iterator begin() const
{
return const_iterator(p_start);
}
virtual constexpr
iterator end()
{
return iterator(p_start + p_size);
}
virtual constexpr
const_iterator end() const
{
return const_iterator(p_start + p_size);
}
virtual constexpr
iterator storage_end()
{
return iterator(p_start + p_capacity);
}
virtual constexpr
const_iterator storage_end() const
{
return const_iterator(p_start + p_capacity);
}
[[nodiscard]] virtual constexpr
size_type size() const noexcept
{
return p_size;
}
virtual constexpr
reference operator[](size_type n)
{
if (n >= size())
throw hpr::OutOfRange();
return *(p_start + n);
}
virtual constexpr
const_reference operator[](size_type n) const
{
if (n >= size())
throw hpr::OutOfRange();
return *(p_start + n);
}
virtual constexpr
reference at(size_type n)
{
return operator[](n);
}
virtual constexpr
const_reference at(size_type n) const
{
return operator[](n);
}
virtual constexpr
reference front()
{
return *begin();
}
virtual constexpr
const_reference front() const
{
return *begin();
}
virtual constexpr
reference back()
{
return *(p_start + p_size - 1);
}
virtual constexpr
const_reference back() const
{
return *(p_start + p_size - 1);
}
virtual constexpr
pointer data()
{
return p_start;
}
[[nodiscard]] virtual constexpr
const_pointer data() const
{
return p_start;
}
// Friend functions
friend
bool operator==(const Sequence& lhs, const Sequence& rhs)
{
for (auto n = 0; n < lhs.size(); ++n)
if (lhs[n] != rhs[n])
return false;
return true;
}
friend
Sequence operator+(const Sequence& lhs, const Sequence& rhs)
{
Sequence seq {rhs.size() + lhs.size(), {}};
for (auto n = 0; n < rhs.size(); ++n)
{
seq[n] = rhs[n];
seq[n + rhs.size()] = lhs[n];
}
return seq;
}
};
#pragma once
#include <hpr/container/iterator.hpp>
#include <hpr/exception.hpp>
#include <hpr/numeric.hpp>
namespace hpr
{
// forward declaration
template <typename T>
class Sequence;
// type traits
template <typename T>
struct is_sequence : public std::false_type
{};
template <typename T>
struct is_sequence<Sequence<T>> : public std::true_type
{};
// concepts
template <typename Type>
concept IsSequence = is_sequence<Type>::value;
// class definition
template <typename T>
class Sequence
{
public:
using difference_type = std::ptrdiff_t;
using value_type = T;
using size_type = Size;
using pointer = T*;
using reference = T&;
using iterator = Iterator<T>;
using const_pointer = T const*;
using const_reference = T const&;
using const_iterator = Iterator<const T>;
protected:
size_type p_size;
size_type p_capacity;
pointer p_start;
protected:
constexpr
Sequence(size_type size, size_type capacity, pointer start) :
p_size {size},
p_capacity {capacity},
p_start {start}
{}
constexpr explicit
Sequence(size_type size, size_type capacity) :
p_size {size},
p_capacity {capacity},
p_start {p_capacity ? new value_type[p_capacity] : nullptr}
{}
public:
friend constexpr
void swap(Sequence& main, Sequence& other) noexcept
{
using std::swap;
swap(main.p_size, other.p_size);
swap(main.p_capacity, other.p_capacity);
swap(main.p_start, other.p_start);
}
constexpr
Sequence() noexcept :
p_size {0},
p_capacity {1},
p_start {new value_type[p_capacity]}
{}
constexpr
Sequence(const Sequence& seq) noexcept :
p_size {seq.p_size},
p_capacity {seq.p_capacity},
p_start {p_capacity ? new value_type[seq.p_capacity] : nullptr}
{
std::copy(seq.p_start, seq.p_start + seq.p_size, p_start);
}
//! Move constructor
constexpr
Sequence(Sequence&& seq) noexcept :
Sequence {}
{
swap(*this, seq);
}
template <typename Iter>
constexpr
Sequence(Iter start, Iter end) :
p_size {static_cast<size_type>(std::distance(start, end))},
p_capacity {p_size},
p_start {p_capacity ? new value_type[p_capacity] : nullptr}
{
std::copy(start, end, p_start);
}
constexpr
Sequence(iterator start, iterator end) :
p_size {static_cast<size_type>(std::distance(start, end))},
p_capacity {p_size},
p_start {p_capacity ? new value_type[p_capacity] : nullptr}
{
std::copy(start, end, p_start);
}
constexpr
Sequence(const_iterator start, const_iterator end) :
p_size {static_cast<size_type>(std::distance(start, end))},
p_capacity {p_size},
p_start {p_capacity ? new value_type[p_capacity] : nullptr}
{
std::copy(start, end, p_start);
}
constexpr
Sequence(iterator start, iterator end, size_type capacity) :
p_size {static_cast<size_type>(std::distance(start, end))},
p_capacity {capacity},
p_start {p_capacity ? new value_type[p_capacity] : nullptr}
{
std::copy(start, end, p_start);
}
constexpr
Sequence(const_iterator start, const_iterator end, size_type capacity) :
p_size {static_cast<size_type>(std::distance(start, end))},
p_capacity {capacity},
p_start {p_capacity ? new value_type[p_capacity] : nullptr}
{
std::copy(start, end, p_start);
}
/*constexpr
Sequence(std::initializer_list<value_type> list) :
Sequence {list.begin(), list.end()}
{}*/
constexpr
Sequence(size_type size, value_type value) noexcept:
p_size {size},
p_capacity {size},
p_start {p_capacity ? new value_type[p_capacity] : nullptr}
{
for (auto n = 0; n < size; ++n)
*(p_start + n) = value;
}
constexpr
Sequence& operator=(Sequence other) noexcept
{
swap(*this, other);
return *this;
}
constexpr
Sequence& operator=(Sequence&& seq) noexcept
{
swap(*this, seq);
return *this;
}
virtual
~Sequence()
{
delete[] p_start;
}
// Member functions
virtual constexpr
iterator begin()
{
return iterator(p_start);
}
[[nodiscard]] virtual constexpr
const_iterator begin() const
{
return const_iterator(p_start);
}
virtual constexpr
iterator end()
{
return iterator(p_start + p_size);
}
virtual constexpr
const_iterator end() const
{
return const_iterator(p_start + p_size);
}
virtual constexpr
iterator storage_end()
{
return iterator(p_start + p_capacity);
}
virtual constexpr
const_iterator storage_end() const
{
return const_iterator(p_start + p_capacity);
}
[[nodiscard]] virtual constexpr
size_type size() const noexcept
{
return p_size;
}
virtual constexpr
reference operator[](size_type n)
{
if (n >= size())
throw hpr::OutOfRange();
return *(p_start + n);
}
virtual constexpr
const_reference operator[](size_type n) const
{
if (n >= size())
throw hpr::OutOfRange();
return *(p_start + n);
}
virtual constexpr
reference at(size_type n)
{
return operator[](n);
}
virtual constexpr
const_reference at(size_type n) const
{
return operator[](n);
}
virtual constexpr
reference front()
{
return *begin();
}
virtual constexpr
const_reference front() const
{
return *begin();
}
virtual constexpr
reference back()
{
return *(p_start + p_size - 1);
}
virtual constexpr
const_reference back() const
{
return *(p_start + p_size - 1);
}
virtual constexpr
pointer data()
{
return p_start;
}
[[nodiscard]] virtual constexpr
const_pointer data() const
{
return p_start;
}
// Friend functions
friend
bool operator==(const Sequence& lhs, const Sequence& rhs)
{
for (auto n = 0; n < lhs.size(); ++n)
if (lhs[n] != rhs[n])
return false;
return true;
}
friend
Sequence operator+(const Sequence& lhs, const Sequence& rhs)
{
Sequence seq {rhs.size() + lhs.size(), {}};
for (auto n = 0; n < rhs.size(); ++n)
{
seq[n] = rhs[n];
seq[n + rhs.size()] = lhs[n];
}
return seq;
}
};
} // end namespace hpr

View File

@ -1,146 +1,146 @@
#pragma once
#include <hpr/container/sequence.hpp>
namespace hpr
{
// forward declaration
template <typename T, Size S>
requires (S > 0)
class StaticArray;
// type traits
template <typename T, Size S>
struct is_sequence<StaticArray<T, S>> : public std::true_type
{};
// aliases
template <typename T, Size S>
using sarray = StaticArray<T, S>;
// class definition
template <typename T, Size S>
requires (S > 0)
class StaticArray : public Sequence<T>
{
using base = Sequence<T>;
public:
using difference_type = std::ptrdiff_t;
using value_type = T;
using size_type = Size;
using pointer = T*;
using reference = T&;
using iterator = Iterator<T>;
using const_pointer = T const*;
using const_reference = T const&;
using const_iterator = Iterator<const T>;
public:
friend constexpr
void swap(StaticArray& main, StaticArray& other) noexcept
{
using std::swap;
swap(static_cast<base&>(main), static_cast<base&>(other));
}
//! Default constructor
constexpr
StaticArray() noexcept :
base {S, S, new value_type[S] {}}
{}
constexpr explicit
StaticArray(const base& b) noexcept :
base {b}
{}
//! Copy constructor
constexpr
StaticArray(const StaticArray& arr) noexcept :
base {static_cast<base>(arr)}
{}
//! Move constructor
constexpr
StaticArray(StaticArray&& arr) noexcept :
base {std::forward<base>(static_cast<base>(arr))}
{}
constexpr
StaticArray(typename base::iterator start, typename base::iterator end) :
base {start, end}
{}
constexpr
StaticArray(typename base::const_iterator start, typename base::const_iterator end) :
base {start, end}
{}
constexpr
StaticArray(typename base::iterator start, typename base::iterator end, size_type capacity) :
base {start, end, capacity}
{}
constexpr
StaticArray(typename base::const_iterator start, typename base::const_iterator end, size_type capacity) :
base {start, end, capacity}
{}
constexpr
StaticArray(std::initializer_list<value_type> list) :
base {list.begin(), list.end()}
{}
template <std::convertible_to<value_type>... Args>
constexpr explicit
StaticArray(const value_type& v, const Args& ...args)
requires (1 + sizeof...(args) == S) :
StaticArray {std::initializer_list<value_type>({v, static_cast<value_type>(args)...})}
{}
template <std::convertible_to<value_type>... Args>
constexpr explicit
StaticArray(value_type&& v, Args&& ...args)
requires (1 + sizeof...(args) == S) :
StaticArray {std::initializer_list<value_type>({std::forward<value_type>(v), std::forward<value_type>(static_cast<value_type>(args))...})}
{}
template <size_type SS, std::convertible_to<value_type>... Args>
constexpr
StaticArray(const StaticArray<value_type, SS>& subArr, const value_type& v, const Args& ...args) noexcept
requires (SS + 1 + sizeof...(args) == S) :
base {S, S, new value_type[S] {}}
{
std::copy(subArr.begin(), subArr.end(), base::begin());
std::initializer_list<value_type> list {v, static_cast<value_type>(args)...};
std::copy(list.begin(), list.end(), base::begin() + subArr.size());
}
constexpr
StaticArray& operator=(StaticArray other)
{
swap(*this, other);
return *this;
}
constexpr
StaticArray& operator=(StaticArray&& other) noexcept
{
swap(*this, other);
return *this;
}
virtual
~StaticArray() = default;
};
} // end namespace hpr
#pragma once
#include <hpr/container/sequence.hpp>
namespace hpr
{
// forward declaration
template <typename T, Size S>
requires (S > 0)
class StaticArray;
// type traits
template <typename T, Size S>
struct is_sequence<StaticArray<T, S>> : public std::true_type
{};
// aliases
template <typename T, Size S>
using sarray = StaticArray<T, S>;
// class definition
template <typename T, Size S>
requires (S > 0)
class StaticArray : public Sequence<T>
{
using base = Sequence<T>;
public:
using difference_type = std::ptrdiff_t;
using value_type = T;
using size_type = Size;
using pointer = T*;
using reference = T&;
using iterator = Iterator<T>;
using const_pointer = T const*;
using const_reference = T const&;
using const_iterator = Iterator<const T>;
public:
friend constexpr
void swap(StaticArray& main, StaticArray& other) noexcept
{
using std::swap;
swap(static_cast<base&>(main), static_cast<base&>(other));
}
//! Default constructor
constexpr
StaticArray() noexcept :
base {S, S, new value_type[S] {}}
{}
constexpr explicit
StaticArray(const base& b) noexcept :
base {b}
{}
//! Copy constructor
constexpr
StaticArray(const StaticArray& arr) noexcept :
base {static_cast<base>(arr)}
{}
//! Move constructor
constexpr
StaticArray(StaticArray&& arr) noexcept :
base {std::forward<base>(static_cast<base>(arr))}
{}
constexpr
StaticArray(typename base::iterator start, typename base::iterator end) :
base {start, end}
{}
constexpr
StaticArray(typename base::const_iterator start, typename base::const_iterator end) :
base {start, end}
{}
constexpr
StaticArray(typename base::iterator start, typename base::iterator end, size_type capacity) :
base {start, end, capacity}
{}
constexpr
StaticArray(typename base::const_iterator start, typename base::const_iterator end, size_type capacity) :
base {start, end, capacity}
{}
constexpr
StaticArray(std::initializer_list<value_type> list) :
base {list.begin(), list.end()}
{}
template <std::convertible_to<value_type>... Args>
constexpr explicit
StaticArray(const value_type& v, const Args& ...args)
requires (1 + sizeof...(args) == S) :
StaticArray {std::initializer_list<value_type>({v, static_cast<value_type>(args)...})}
{}
template <std::convertible_to<value_type>... Args>
constexpr explicit
StaticArray(value_type&& v, Args&& ...args)
requires (1 + sizeof...(args) == S) :
StaticArray {std::initializer_list<value_type>({std::forward<value_type>(v), std::forward<value_type>(static_cast<value_type>(args))...})}
{}
template <size_type SS, std::convertible_to<value_type>... Args>
constexpr
StaticArray(const StaticArray<value_type, SS>& subArr, const value_type& v, const Args& ...args) noexcept
requires (SS + 1 + sizeof...(args) == S) :
base {S, S, new value_type[S] {}}
{
std::copy(subArr.begin(), subArr.end(), base::begin());
std::initializer_list<value_type> list {v, static_cast<value_type>(args)...};
std::copy(list.begin(), list.end(), base::begin() + subArr.size());
}
constexpr
StaticArray& operator=(StaticArray other)
{
swap(*this, other);
return *this;
}
constexpr
StaticArray& operator=(StaticArray&& other) noexcept
{
swap(*this, other);
return *this;
}
virtual
~StaticArray() = default;
};
} // end namespace hpr

View File

@ -1,181 +1,181 @@
#pragma once
#include <hpr/container/dynamic_array.hpp>
#include <memory>
namespace hpr
{
template <typename Type>
class TreeNode
{
public:
using value_type = Type;
using pointer = Type*;
using reference = Type&;
using const_pointer = Type const*;
using const_reference = Type const&;
protected:
pointer p_data;
darray<TreeNode*> p_descendants;
TreeNode* p_ancestor;
public:
friend constexpr
void swap(TreeNode& main, TreeNode& other) noexcept
{
using std::swap;
swap(main.p_data, other.p_data);
swap(main.p_descendants, other.p_descendants);
swap(main.p_ancestor, other.p_ancestor);
}
inline
TreeNode() :
p_data {new value_type {}},
p_descendants {},
p_ancestor {}
{}
inline
TreeNode(const TreeNode& node) :
p_data {new value_type {*node.p_data}},
p_descendants {},
p_ancestor {}
{}
inline
TreeNode(TreeNode&& node) noexcept :
p_data {},
p_descendants {},
p_ancestor {}
{
swap(*this, node);
/*std::swap(p_data, node.p_data);
std::swap(p_descendants, node.p_descendants);
std::swap(p_ancestor, node.p_ancestor);*/
}
inline
TreeNode& operator=(TreeNode other)
{
swap(*this, other);
return *this;
}
inline explicit
TreeNode(const value_type& data) :
p_data {new value_type {data}},
p_descendants {},
p_ancestor {}
{}
inline
TreeNode(const value_type& data, const darray<TreeNode*>& descendants, TreeNode* ancestor) :
p_data {new value_type {data}},
p_descendants {descendants},
p_ancestor {ancestor}
{
for (auto descendant : p_descendants)
descendant->ancestor(this);
}
inline
TreeNode(const value_type& data, const darray<TreeNode*>& descendants) :
p_data {new value_type {data}},
p_descendants {descendants},
p_ancestor {}
{
for (auto descendant : p_descendants)
descendant->ancestor(this);
}
virtual
~TreeNode()
{
delete p_data;
//delete p_ancestor;
}
// Member functions
inline
pointer data()
{
return p_data;
}
inline
void ancestor(TreeNode* node)
{
p_ancestor = node;
}
inline
TreeNode* ancestor()
{
return p_ancestor;
}
inline
void descendants(const darray<TreeNode*>& descendants)
{
p_descendants = descendants;
}
inline
darray<TreeNode*>& descendants()
{
return p_descendants;
}
darray<TreeNode*> traverse_descendants()
{
std::function<darray<TreeNode*>(TreeNode*)> collect = [&](TreeNode* node)
{
darray<TreeNode*> ds;
if (!node->descendants().is_empty())
{
for (TreeNode* dnode: node->descendants())
{
ds.push(dnode);
if (!dnode->descendants().is_empty())
ds.push(collect(dnode));
}
}
return ds;
};
return collect(this);
}
darray<TreeNode*> traverse_ancestors()
{
std::function<darray<TreeNode*>(TreeNode*)> collect = [&](TreeNode* node)
{
darray<TreeNode*> ds;
if (node->p_ancestor)
{
ds.push(node);
ds.push(collect(node->p_ancestor));
}
return ds;
};
return collect(this);
}
};
#pragma once
#include <hpr/container/dynamic_array.hpp>
#include <memory>
namespace hpr
{
template <typename Type>
class TreeNode
{
public:
using value_type = Type;
using pointer = Type*;
using reference = Type&;
using const_pointer = Type const*;
using const_reference = Type const&;
protected:
pointer p_data;
darray<TreeNode*> p_descendants;
TreeNode* p_ancestor;
public:
friend constexpr
void swap(TreeNode& main, TreeNode& other) noexcept
{
using std::swap;
swap(main.p_data, other.p_data);
swap(main.p_descendants, other.p_descendants);
swap(main.p_ancestor, other.p_ancestor);
}
inline
TreeNode() :
p_data {new value_type {}},
p_descendants {},
p_ancestor {}
{}
inline
TreeNode(const TreeNode& node) :
p_data {new value_type {*node.p_data}},
p_descendants {},
p_ancestor {}
{}
inline
TreeNode(TreeNode&& node) noexcept :
p_data {},
p_descendants {},
p_ancestor {}
{
swap(*this, node);
/*std::swap(p_data, node.p_data);
std::swap(p_descendants, node.p_descendants);
std::swap(p_ancestor, node.p_ancestor);*/
}
inline
TreeNode& operator=(TreeNode other)
{
swap(*this, other);
return *this;
}
inline explicit
TreeNode(const value_type& data) :
p_data {new value_type {data}},
p_descendants {},
p_ancestor {}
{}
inline
TreeNode(const value_type& data, const darray<TreeNode*>& descendants, TreeNode* ancestor) :
p_data {new value_type {data}},
p_descendants {descendants},
p_ancestor {ancestor}
{
for (auto descendant : p_descendants)
descendant->ancestor(this);
}
inline
TreeNode(const value_type& data, const darray<TreeNode*>& descendants) :
p_data {new value_type {data}},
p_descendants {descendants},
p_ancestor {}
{
for (auto descendant : p_descendants)
descendant->ancestor(this);
}
virtual
~TreeNode()
{
delete p_data;
//delete p_ancestor;
}
// Member functions
inline
pointer data()
{
return p_data;
}
inline
void ancestor(TreeNode* node)
{
p_ancestor = node;
}
inline
TreeNode* ancestor()
{
return p_ancestor;
}
inline
void descendants(const darray<TreeNode*>& descendants)
{
p_descendants = descendants;
}
inline
darray<TreeNode*>& descendants()
{
return p_descendants;
}
darray<TreeNode*> traverse_descendants()
{
std::function<darray<TreeNode*>(TreeNode*)> collect = [&](TreeNode* node)
{
darray<TreeNode*> ds;
if (!node->descendants().is_empty())
{
for (TreeNode* dnode: node->descendants())
{
ds.push(dnode);
if (!dnode->descendants().is_empty())
ds.push(collect(dnode));
}
}
return ds;
};
return collect(this);
}
darray<TreeNode*> traverse_ancestors()
{
std::function<darray<TreeNode*>(TreeNode*)> collect = [&](TreeNode* node)
{
darray<TreeNode*> ds;
if (node->p_ancestor)
{
ds.push(node);
ds.push(collect(node->p_ancestor));
}
return ds;
};
return collect(this);
}
};
} // end namespace hpr

View File

@ -1,63 +1,63 @@
#pragma once
#include <exception>
#include <string>
#include <source_location>
#include <sstream>
#include <utility>
#include <vector>
namespace hpr
{
class Exception : public std::exception
{
protected:
std::string p_message;
public:
inline explicit
Exception(std::source_location location = std::source_location::current()) :
p_message {}
{
std::stringstream _message;
_message << "\t" << p_message
<< "\n where:\t\t" << location.file_name() << ":" << location.line() << ":" << location.column()
<< "\n function:\t" << location.function_name();
p_message = _message.str();
}
inline explicit
Exception(const std::string& message, std::source_location location = std::source_location::current()) :
p_message {message}
{
std::stringstream _message;
_message << "\t" << p_message
<< "\n where:\t" << location.file_name() << ":" << location.line() << ":" << location.column()
<< "\n function:\t" << location.function_name();
p_message = _message.str();
}
[[nodiscard]]
const char* what() const noexcept override {
std::vector<float> vv;
return p_message.data();
}
};
struct OutOfRange : public Exception
{
inline explicit OutOfRange(std::source_location location = std::source_location::current()) : Exception {"Out of range", location} {}
inline explicit OutOfRange(const std::string& message, std::source_location location = std::source_location::current()) : Exception {message, location} {}
};
struct LengthError : public Exception
{
inline explicit LengthError(std::source_location location = std::source_location::current()) : Exception {"Length error", location} {}
inline explicit LengthError(const std::string& message, std::source_location location = std::source_location::current()) : Exception {message, location} {}
};
#pragma once
#include <exception>
#include <string>
#include <source_location>
#include <sstream>
#include <utility>
#include <vector>
namespace hpr
{
class Exception : public std::exception
{
protected:
std::string p_message;
public:
inline explicit
Exception(std::source_location location = std::source_location::current()) :
p_message {}
{
std::stringstream _message;
_message << "\t" << p_message
<< "\n where:\t\t" << location.file_name() << ":" << location.line() << ":" << location.column()
<< "\n function:\t" << location.function_name();
p_message = _message.str();
}
inline explicit
Exception(const std::string& message, std::source_location location = std::source_location::current()) :
p_message {message}
{
std::stringstream _message;
_message << "\t" << p_message
<< "\n where:\t" << location.file_name() << ":" << location.line() << ":" << location.column()
<< "\n function:\t" << location.function_name();
p_message = _message.str();
}
[[nodiscard]]
const char* what() const noexcept override {
std::vector<float> vv;
return p_message.data();
}
};
struct OutOfRange : public Exception
{
inline explicit OutOfRange(std::source_location location = std::source_location::current()) : Exception {"Out of range", location} {}
inline explicit OutOfRange(const std::string& message, std::source_location location = std::source_location::current()) : Exception {message, location} {}
};
struct LengthError : public Exception
{
inline explicit LengthError(std::source_location location = std::source_location::current()) : Exception {"Length error", location} {}
inline explicit LengthError(const std::string& message, std::source_location location = std::source_location::current()) : Exception {message, location} {}
};
} // end namespace hpr

View File

@ -1,5 +1,6 @@
#include <hpr/exception.hpp>
#include <hpr/numeric.hpp>
#include <hpr/container.hpp>
#include <hpr/math.hpp>
#include <hpr/exception.hpp>
#include <hpr/numeric.hpp>
#include <hpr/container.hpp>
#include <hpr/math.hpp>
#include <hpr/shape.hpp>

View File

@ -1,5 +1,5 @@
#pragma once
#include <hpr/math/vector.hpp>
#include <hpr/math/quaternion.hpp>
#include <hpr/math/matrix.hpp>
#pragma once
#include <hpr/math/vector.hpp>
#include <hpr/math/quaternion.hpp>
#include <hpr/math/matrix.hpp>

File diff suppressed because it is too large Load Diff

View File

@ -1,290 +1,290 @@
#pragma once
#include <hpr/math/vector.hpp>
#include <hpr/exception.hpp>
namespace hpr
{
// forward declarations
class Quaternion;
inline
Quaternion inverse(const Quaternion& q);
inline
Quaternion operator*(const Quaternion& lhs, const Quaternion& rhs);
// aliases
using quat = Quaternion;
// class declaration
class Quaternion
{
public:
enum RotationSequence
{
ZYX, ZYZ, ZXY, ZXZ, YXZ, YXY, YZX, YZY, XYZ, XYX, XZY, XZX
};
protected:
scalar p_real;
vec3 p_imag;
public:
inline
Quaternion() :
p_real{},
p_imag{}
{}
inline
Quaternion(const scalar real, const vec3& imag) :
p_real {real},
p_imag {imag}
{}
inline explicit
Quaternion(const scalar real) :
p_real {real},
p_imag {}
{}
inline explicit
Quaternion(const vec3& imag) :
p_real {},
p_imag {imag}
{}
inline
Quaternion(const vec3& vs, const scalar& theta) :
p_real {cos(0.5 * theta)},
p_imag {sin(0.5 * theta) * vs / mag(vs)}
{}
static inline
Quaternion unit(const vec3& vs)
{
return Quaternion(sqrt(1 - norm(vs)), vs);
}
inline
Quaternion(const RotationSequence rs, const vec3& angles)
{
switch (rs)
{
case XYZ:
*this = Quaternion(vec3(0, 1, 0), angles[0]) *
Quaternion(vec3(0, 1, 0), angles[1]) *
Quaternion(vec3(0, 0, 1), angles[2]);
break;
default:
throw std::runtime_error("Unknown rotation sequence");
}
}
inline
scalar real() const
{
return p_real;
}
inline
scalar& real()
{
return p_real;
}
inline
vec3 imag() const
{
return p_imag;
}
inline
vec3& imag()
{
return p_imag;
}
inline
scalar& operator[](Size n)
{
if (n > 3)
throw hpr::OutOfRange();
if (n == 0)
return p_real;
else
return p_imag[n - 1];
}
inline
scalar operator[](Size n) const
{
if (n > 3)
throw hpr::OutOfRange();
if (n == 0)
return p_real;
else
return p_imag[n - 1];
}
inline
void operator+=(const Quaternion& q)
{
p_real += q.p_real;
p_imag += q.p_imag;
}
inline
void operator-=(const Quaternion& q)
{
p_real -= q.p_real;
p_imag -= q.p_imag;
}
inline
void operator*=(const Quaternion& q)
{
scalar temp = p_real;
p_real = p_real * q.p_real - dot(p_imag, q.p_imag);
p_imag = temp * q.p_imag + q.p_real * p_imag + cross(p_imag, q.p_imag);
}
inline
void operator/=(const Quaternion& q)
{
operator*=(inverse(q));
}
inline
void operator*=(const scalar s)
{
p_real *= s;
p_imag *= s;
}
inline
void operator/=(const scalar s)
{
p_real /= s;
p_imag /= s;
}
};
inline
bool equal(const Quaternion& lhs, const Quaternion& rhs)
{
return lhs.real() == rhs.real() && lhs.imag() == rhs.imag();
}
inline
bool operator==(const Quaternion& lhs, const Quaternion& rhs)
{
return equal(lhs, rhs);
}
inline
bool operator!=(const Quaternion& lhs, const Quaternion& rhs)
{
return !equal(lhs, rhs);
}
inline
Quaternion operator+(const Quaternion& lhs, const Quaternion& rhs)
{
return {lhs.real() + rhs.real(), lhs.imag() + rhs.imag()};
}
inline
Quaternion operator-(const Quaternion& q)
{
return {q.real(), q.imag()};
}
inline
Quaternion operator-(const Quaternion& lhs, const Quaternion& rhs)
{
return {lhs.real() - rhs.real(), lhs.imag() - rhs.imag()};
}
inline
Quaternion operator*(const Quaternion& lhs, const Quaternion& rhs)
{
return {
lhs.real() * rhs.real() - dot(lhs.imag(), rhs.imag()),
lhs.real() * rhs.imag() + rhs.real() * lhs.imag() + cross(lhs.imag(), rhs.imag())
};
}
inline
Quaternion operator/(const Quaternion& lhs, const Quaternion& rhs)
{
return lhs * inverse(rhs);
}
inline
Quaternion operator*(const scalar s, const Quaternion& q)
{
return {s * q.real(), s * q.imag()};
}
inline
Quaternion operator*(const Quaternion& q, const scalar s)
{
return {q.real() * s, q.imag() * s};
}
inline
Quaternion operator/(const Quaternion& q, const scalar s)
{
return {q.real() / s, q.imag() / s};
}
inline
scalar norm(const Quaternion& q)
{
return sqrt(pow(q.real(), 2) + dot(q.imag(), q.imag()));
}
inline
Quaternion conjugate(const Quaternion& q)
{
return {q.real(), -q.imag()};
}
inline
Quaternion inverse(const Quaternion& q)
{
return conjugate(q) / pow(norm(q), 2);
}
inline
Quaternion normalize(const Quaternion& q)
{
return q / norm(q);
}
inline
vec3 rotate(const vec3& point, const vec3& axis, const scalar& angle)
{
Quaternion p {point};
Quaternion q {normalize(axis), angle};
return (q * p * inverse(q)).imag();
}
void decompose(const Quaternion& q, vec3& axis, scalar& angle)
{
const scalar qnorm = norm(q.imag());
axis = q.imag() / qnorm;
angle = 2 * atan2(qnorm, q.real());
}
#pragma once
#include <hpr/math/vector.hpp>
#include <hpr/exception.hpp>
namespace hpr
{
// forward declarations
class Quaternion;
inline
Quaternion inverse(const Quaternion& q);
inline
Quaternion operator*(const Quaternion& lhs, const Quaternion& rhs);
// aliases
using quat = Quaternion;
// class declaration
class Quaternion
{
public:
enum RotationSequence
{
ZYX, ZYZ, ZXY, ZXZ, YXZ, YXY, YZX, YZY, XYZ, XYX, XZY, XZX
};
protected:
scalar p_real;
vec3 p_imag;
public:
inline
Quaternion() :
p_real{},
p_imag{}
{}
inline
Quaternion(const scalar real, const vec3& imag) :
p_real {real},
p_imag {imag}
{}
inline explicit
Quaternion(const scalar real) :
p_real {real},
p_imag {}
{}
inline explicit
Quaternion(const vec3& imag) :
p_real {},
p_imag {imag}
{}
inline
Quaternion(const vec3& vs, const scalar& theta) :
p_real {cos(0.5 * theta)},
p_imag {sin(0.5 * theta) * vs / mag(vs)}
{}
static inline
Quaternion unit(const vec3& vs)
{
return Quaternion(sqrt(1 - norm(vs)), vs);
}
inline
Quaternion(const RotationSequence rs, const vec3& angles)
{
switch (rs)
{
case XYZ:
*this = Quaternion(vec3(0, 1, 0), angles[0]) *
Quaternion(vec3(0, 1, 0), angles[1]) *
Quaternion(vec3(0, 0, 1), angles[2]);
break;
default:
throw std::runtime_error("Unknown rotation sequence");
}
}
inline
scalar real() const
{
return p_real;
}
inline
scalar& real()
{
return p_real;
}
inline
vec3 imag() const
{
return p_imag;
}
inline
vec3& imag()
{
return p_imag;
}
inline
scalar& operator[](Size n)
{
if (n > 3)
throw hpr::OutOfRange();
if (n == 0)
return p_real;
else
return p_imag[n - 1];
}
inline
scalar operator[](Size n) const
{
if (n > 3)
throw hpr::OutOfRange();
if (n == 0)
return p_real;
else
return p_imag[n - 1];
}
inline
void operator+=(const Quaternion& q)
{
p_real += q.p_real;
p_imag += q.p_imag;
}
inline
void operator-=(const Quaternion& q)
{
p_real -= q.p_real;
p_imag -= q.p_imag;
}
inline
void operator*=(const Quaternion& q)
{
scalar temp = p_real;
p_real = p_real * q.p_real - dot(p_imag, q.p_imag);
p_imag = temp * q.p_imag + q.p_real * p_imag + cross(p_imag, q.p_imag);
}
inline
void operator/=(const Quaternion& q)
{
operator*=(inverse(q));
}
inline
void operator*=(const scalar s)
{
p_real *= s;
p_imag *= s;
}
inline
void operator/=(const scalar s)
{
p_real /= s;
p_imag /= s;
}
};
inline
bool equal(const Quaternion& lhs, const Quaternion& rhs)
{
return lhs.real() == rhs.real() && lhs.imag() == rhs.imag();
}
inline
bool operator==(const Quaternion& lhs, const Quaternion& rhs)
{
return equal(lhs, rhs);
}
inline
bool operator!=(const Quaternion& lhs, const Quaternion& rhs)
{
return !equal(lhs, rhs);
}
inline
Quaternion operator+(const Quaternion& lhs, const Quaternion& rhs)
{
return {lhs.real() + rhs.real(), lhs.imag() + rhs.imag()};
}
inline
Quaternion operator-(const Quaternion& q)
{
return {q.real(), q.imag()};
}
inline
Quaternion operator-(const Quaternion& lhs, const Quaternion& rhs)
{
return {lhs.real() - rhs.real(), lhs.imag() - rhs.imag()};
}
inline
Quaternion operator*(const Quaternion& lhs, const Quaternion& rhs)
{
return {
lhs.real() * rhs.real() - dot(lhs.imag(), rhs.imag()),
lhs.real() * rhs.imag() + rhs.real() * lhs.imag() + cross(lhs.imag(), rhs.imag())
};
}
inline
Quaternion operator/(const Quaternion& lhs, const Quaternion& rhs)
{
return lhs * inverse(rhs);
}
inline
Quaternion operator*(const scalar s, const Quaternion& q)
{
return {s * q.real(), s * q.imag()};
}
inline
Quaternion operator*(const Quaternion& q, const scalar s)
{
return {q.real() * s, q.imag() * s};
}
inline
Quaternion operator/(const Quaternion& q, const scalar s)
{
return {q.real() / s, q.imag() / s};
}
inline
scalar norm(const Quaternion& q)
{
return sqrt(pow(q.real(), 2) + dot(q.imag(), q.imag()));
}
inline
Quaternion conjugate(const Quaternion& q)
{
return {q.real(), -q.imag()};
}
inline
Quaternion inverse(const Quaternion& q)
{
return conjugate(q) / pow(norm(q), 2);
}
inline
Quaternion normalize(const Quaternion& q)
{
return q / norm(q);
}
inline
vec3 rotate(const vec3& point, const vec3& axis, const scalar& angle)
{
Quaternion p {point};
Quaternion q {normalize(axis), angle};
return (q * p * inverse(q)).imag();
}
void decompose(const Quaternion& q, vec3& axis, scalar& angle)
{
const scalar qnorm = norm(q.imag());
axis = q.imag() / qnorm;
angle = 2 * atan2(qnorm, q.real());
}
} // end namespace hpr

View File

@ -1,321 +1,321 @@
#pragma once
#include <hpr/numeric.hpp>
#include <hpr/container/static_array.hpp>
namespace hpr
{
// forward declarations
template <IsReal T, Size S> requires (S >= 0)
class Vector;
template <IsReal T, Size S>
using SubVector = typename std::conditional<S >= 2, Vector<T, S - 1>, Vector<T, 1>>::type;
// type traits
template <typename T>
struct is_vector : public std::false_type {};
template <typename T, Size S>
struct is_vector<Vector<T, S>> : public std::true_type {};
// concepts
template <typename T>
concept IsVector = is_vector<T>::value;
// aliases
template <typename Type, Size S>
using vec = Vector<Type, S>;
using vec2 = Vector<scalar, 2>;
using vec3 = Vector<scalar, 3>;
using vec4 = Vector<scalar, 4>;
template <IsReal Type, Size S> requires (S >= 0)
class Vector : public StaticArray<Type, S>
{
using base = StaticArray<Type, S>;
public:
using value_type = Type;
using size_type = Size;
using pointer = Type*;
using reference = Type&;
using iterator = Iterator<Type>;
using const_iterator = Iterator<const Type>;
public:
//! null constructor
constexpr
Vector() :
base {}
{}
//! copy constructor
constexpr
Vector(const Vector& vs) :
base {static_cast<base>(vs)}
{}
//! move constructor
constexpr
Vector(Vector&& vs) noexcept :
base {std::forward<base>(static_cast<base>(vs))}
{}
//! copy assignment operator
constexpr
Vector& operator=(const Vector& vs)
{
base::operator=(vs);
return *this;
}
//! move assignment operator
constexpr
Vector& operator=(Vector&& vs) noexcept
{
swap(*this, vs);
return *this;
}
//! destructor
virtual
~Vector() = default;
//! copy constructor from base
constexpr
Vector(const base& arr) :
base {arr}
{}
//! move constructor from base
constexpr
Vector(base&& arr) :
base {std::forward<base>(arr)}
{}
//! construct from iterators
constexpr
Vector(typename base::iterator start, typename base::iterator end) :
base {start, end}
{}
//! construct from constant iterators
constexpr
Vector(typename base::const_iterator start, typename base::const_iterator end) :
base {start, end}
{}
//! construct from initializer list
constexpr
Vector(std::initializer_list<value_type> list) :
base {list}
{}
//! copy constructor with variadic args
template <IsReal... Args>
constexpr
Vector(const value_type& v, const Args& ...args) requires (S == 1 + sizeof...(args)):
base {v, static_cast<value_type>(args)...}
{}
//! move constructor with variadic args
template <IsReal... Args>
constexpr
Vector(value_type&& v, Args&& ...args) requires (S == 1 + sizeof...(args)):
base {v, static_cast<value_type>(std::forward<Args>(args))...}
{}
//! copy constructor with sub vector and value
constexpr
Vector(const SubVector<Type, S>& svs, const value_type& v) requires (S >= 1):
base {}
{
for (auto n = 0; n < svs.size(); ++n)
(*this)[n] = svs[n];
(*this)[svs.size()] = v;
}
//! copy constructor from greater vector
template <Size GS> requires (GS > S)
constexpr explicit
Vector(const Vector<Type, GS>& vs) :
base {vs.begin(), vs.begin() + S}
{}
};
// global operators
template <IsReal T, Size S> inline Vector<T, S> operator+(const Vector<T, S>& lhs) { Vector<T, S> vs; for (Size n = 0; n < S; ++n) vs[n] = lhs[n]; return vs; }
template <IsReal T, Size S> inline Vector<T, S> operator-(const Vector<T, S>& lhs) { Vector<T, S> vs; for (Size n = 0; n < S; ++n) vs[n] = -lhs[n]; return vs; }
template <IsReal T, Size S> inline Vector<T, S>& operator+=(Vector<T, S>& lhs, const Vector<T, S>& rhs) { for (Size n = 0; n < S; ++n) lhs[n] += rhs[n]; return lhs; }
template <IsReal T, Size S> inline Vector<T, S>& operator-=(Vector<T, S>& lhs, const Vector<T, S>& rhs) { for (Size n = 0; n < S; ++n) lhs[n] -= rhs[n]; return lhs; }
template <IsReal T, Size S> inline Vector<T, S>& operator*=(Vector<T, S>& lhs, const Vector<T, S>& rhs) { for (Size n = 0; n < S; ++n) lhs[n] *= rhs[n]; return lhs; }
template <IsReal T, Size S> inline Vector<T, S>& operator/=(Vector<T, S>& lhs, const Vector<T, S>& rhs) { for (Size n = 0; n < S; ++n) lhs[n] /= rhs[n]; return lhs; }
template <IsReal T, Size S> inline Vector<T, S> operator+(const Vector<T, S>& lhs, const Vector<T, S>& rhs) { Vector<T, S> vs {lhs}; for (Size n = 0; n < S; ++n) vs[n] += rhs[n]; return vs; }
template <IsReal T, Size S> inline Vector<T, S> operator-(const Vector<T, S>& lhs, const Vector<T, S>& rhs) { Vector<T, S> vs {lhs}; for (Size n = 0; n < S; ++n) vs[n] -= rhs[n]; return vs; }
template <IsReal T, Size S> inline Vector<T, S> operator*(const Vector<T, S>& lhs, const Vector<T, S>& rhs) { Vector<T, S> vs {lhs}; for (Size n = 0; n < S; ++n) vs[n] *= rhs[n]; return vs; }
template <IsReal T, Size S> inline Vector<T, S> operator/(const Vector<T, S>& lhs, const Vector<T, S>& rhs) { Vector<T, S> vs {lhs}; for (Size n = 0; n < S; ++n) vs[n] /= rhs[n]; return vs; }
template <IsReal T, Size S> inline bool operator==(const Vector<T, S>& lhs, const Vector<T, S>& rhs) { for (Size n = 0; n < S; ++n) if (lhs[n] != rhs[n]) return false; return true; }
template <IsReal T, Size S> inline bool operator!=(const Vector<T, S>& lhs, const Vector<T, S>& rhs) { for (Size n = 0; n < S; ++n) if (lhs[n] == rhs[n]) return false; return true; }
template <IsReal T, Size S> inline Vector<T, S>& operator+=(Vector<T, S>& lhs, const T& rhs) { for (Size n = 0; n < S; ++n) lhs[n] += rhs; return lhs; }
template <IsReal T, Size S> inline Vector<T, S>& operator-=(Vector<T, S>& lhs, const T& rhs) { for (Size n = 0; n < S; ++n) lhs[n] -= rhs; return lhs; }
template <IsReal T, Size S> inline Vector<T, S>& operator*=(Vector<T, S>& lhs, const T& rhs) { for (Size n = 0; n < S; ++n) lhs[n] *= rhs; return lhs; }
template <IsReal T, Size S> inline Vector<T, S>& operator/=(Vector<T, S>& lhs, const T& rhs) { for (Size n = 0; n < S; ++n) lhs[n] /= rhs; return lhs; }
template <IsReal T, Size S> inline Vector<T, S> operator+(const Vector<T, S>& lhs, const T& rhs) { Vector<T, S> vs {lhs}; for (Size n = 0; n < S; ++n) vs[n] += rhs; return vs; }
template <IsReal T, Size S> inline Vector<T, S> operator-(const Vector<T, S>& lhs, const T& rhs) { Vector<T, S> vs {lhs}; for (Size n = 0; n < S; ++n) vs[n] -= rhs; return vs; }
template <IsReal T, IsReal T2, Size S> inline Vector<T, S> operator*(const Vector<T, S>& lhs, const T2& rhs) { Vector<T, S> vs {lhs}; for (Size n = 0; n < S; ++n) vs[n] *= static_cast<T>(rhs); return vs; }
template <IsReal T, IsReal T2, Size S> inline Vector<T, S> operator/(const Vector<T, S>& lhs, const T2& rhs) { Vector<T, S> vs {lhs}; for (Size n = 0; n < S; ++n) vs[n] /= static_cast<T>(rhs); return vs; }
template <IsReal T, Size S> inline Vector<T, S> operator+(const T& lhs, const Vector<T, S>& rhs) { Vector<T, S> vs {rhs}; for (Size n = 0; n < S; ++n) vs[n] += lhs; return vs; }
template <IsReal T, Size S> inline Vector<T, S> operator-(const T& lhs, const Vector<T, S>& rhs) { Vector<T, S> vs {rhs}; for (Size n = 0; n < S; ++n) vs[n] -= lhs; return vs; }
template <IsReal T, Size S> inline Vector<T, S> operator*(const T& lhs, const Vector<T, S>& rhs) { Vector<T, S> vs {rhs}; for (Size n = 0; n < S; ++n) vs[n] *= lhs; return vs; }
template <IsReal T, Size S> inline Vector<T, S> operator/(const T& lhs, const Vector<T, S>& rhs) { Vector<T, S> vs {rhs}; for (Size n = 0; n < S; ++n) vs[n] /= lhs; return vs; }
// boolean operations
template <typename Type, Size S>
inline
Vector<bool, S> equal(const Vector<Type, S>& lhs, const Vector<Type, S>& rhs, const scalar& precision = hpr::precision())
{
Vector<bool, S> vs;
for (auto n = 0; n < S; ++n)
vs[n] = equal(lhs[n], rhs[n], precision);
return vs;
}
template <Size S>
inline
bool any(const Vector<bool, S>& vs)
{
bool res = false;
for (auto e : vs)
res = res || e;
return res;
}
template <Size S>
inline
bool all(const Vector<bool, S>& vs)
{
bool res = true;
for (auto e : vs)
res = res && e;
return res;
}
// per element operations
template <typename Type, Size S>
inline
Vector<Type, S> abs(const Vector<Type, S>& vs)
{
Vector<Type, S> res;
for (auto n = 0; n < S; ++n)
res[n] = abs(vs[n]);
return res;
}
template <typename Type, Size S>
inline
Type sum(const Vector<Type, S>& vs)
{
Type sum {};
for (const Type& v : vs)
sum += v;
return sum;
}
template <typename Type, Size S>
inline
Vector<Type, S> pow(const Vector<Type, S>& vs, scalar degree)
{
Vector<Type, S> res;
for (auto n = 0; n < S; ++n)
res[n] = pow(vs[n], degree);
return res;
}
// vector operations
template <typename Type, Size S>
inline
Type norm(const Vector<Type, S>& vs)
{
return sqrt(sum(pow(abs(vs), 2)));
}
template <typename Type, Size S>
inline
Type dot(const Vector<Type, S>& lhs, const Vector<Type, S>& rhs)
{
return sum(lhs * rhs);
}
template <typename Type, Size S>
inline
Type length(const Vector<Type, S>& vs)
{
return sqrt(dot(vs, vs));
}
template <typename Type, Size S>
inline
Type mag(const Vector<Type, S>& vs)
{
return length(vs);
}
template <typename Type, Size S>
inline
Type distance(const Vector<Type, S>& vs1, const Vector<Type, S>& vs2)
{
return length(vs1 - vs2);
}
template <typename Type, Size S>
inline
Vector<Type, S> normalize(const Vector<Type, S>& vs)
{
return vs * isqrt(dot(vs, vs));
}
template <typename Type>
inline
Type angle(const Vector<Type, 3>& lhs, const Vector<Type, 3>& rhs)
{
scalar cos = dot(lhs, rhs) / (norm(lhs) * norm(rhs));
return acos(cos); //clip(cos, -1., 1.));
}
// vector 3 operations
template <typename Type>
inline
Vector<Type, 3> cross(const Vector<Type, 3>& lhs, const Vector<Type, 3>& rhs)
{
return Vector<Type, 3>(
lhs[1] * rhs[2] - lhs[2] * rhs[1],
lhs[2] * rhs[0] - lhs[0] * rhs[2],
lhs[0] * rhs[1] - lhs[1] * rhs[0]
);
}
#pragma once
#include <hpr/numeric.hpp>
#include <hpr/container/static_array.hpp>
namespace hpr
{
// forward declarations
template <IsReal T, Size S> requires (S >= 0)
class Vector;
template <IsReal T, Size S>
using SubVector = typename std::conditional<S >= 2, Vector<T, S - 1>, Vector<T, 1>>::type;
// type traits
template <typename T>
struct is_vector : public std::false_type {};
template <typename T, Size S>
struct is_vector<Vector<T, S>> : public std::true_type {};
// concepts
template <typename T>
concept IsVector = is_vector<T>::value;
// aliases
template <typename Type, Size S>
using vec = Vector<Type, S>;
using vec2 = Vector<scalar, 2>;
using vec3 = Vector<scalar, 3>;
using vec4 = Vector<scalar, 4>;
template <IsReal Type, Size S> requires (S >= 0)
class Vector : public StaticArray<Type, S>
{
using base = StaticArray<Type, S>;
public:
using value_type = Type;
using size_type = Size;
using pointer = Type*;
using reference = Type&;
using iterator = Iterator<Type>;
using const_iterator = Iterator<const Type>;
public:
//! null constructor
constexpr
Vector() :
base {}
{}
//! copy constructor
constexpr
Vector(const Vector& vs) :
base {static_cast<base>(vs)}
{}
//! move constructor
constexpr
Vector(Vector&& vs) noexcept :
base {std::forward<base>(static_cast<base>(vs))}
{}
//! copy assignment operator
constexpr
Vector& operator=(const Vector& vs)
{
base::operator=(vs);
return *this;
}
//! move assignment operator
constexpr
Vector& operator=(Vector&& vs) noexcept
{
swap(*this, vs);
return *this;
}
//! destructor
virtual
~Vector() = default;
//! copy constructor from base
constexpr
Vector(const base& arr) :
base {arr}
{}
//! move constructor from base
constexpr
Vector(base&& arr) :
base {std::forward<base>(arr)}
{}
//! construct from iterators
constexpr
Vector(typename base::iterator start, typename base::iterator end) :
base {start, end}
{}
//! construct from constant iterators
constexpr
Vector(typename base::const_iterator start, typename base::const_iterator end) :
base {start, end}
{}
//! construct from initializer list
constexpr
Vector(std::initializer_list<value_type> list) :
base {list}
{}
//! copy constructor with variadic args
template <IsReal... Args>
constexpr
Vector(const value_type& v, const Args& ...args) requires (S == 1 + sizeof...(args)):
base {v, static_cast<value_type>(args)...}
{}
//! move constructor with variadic args
template <IsReal... Args>
constexpr
Vector(value_type&& v, Args&& ...args) requires (S == 1 + sizeof...(args)):
base {v, static_cast<value_type>(std::forward<Args>(args))...}
{}
//! copy constructor with sub vector and value
constexpr
Vector(const SubVector<Type, S>& svs, const value_type& v) requires (S >= 1):
base {}
{
for (auto n = 0; n < svs.size(); ++n)
(*this)[n] = svs[n];
(*this)[svs.size()] = v;
}
//! copy constructor from greater vector
template <Size GS> requires (GS > S)
constexpr explicit
Vector(const Vector<Type, GS>& vs) :
base {vs.begin(), vs.begin() + S}
{}
};
// global operators
template <IsReal T, Size S> inline Vector<T, S> operator+(const Vector<T, S>& lhs) { Vector<T, S> vs; for (Size n = 0; n < S; ++n) vs[n] = lhs[n]; return vs; }
template <IsReal T, Size S> inline Vector<T, S> operator-(const Vector<T, S>& lhs) { Vector<T, S> vs; for (Size n = 0; n < S; ++n) vs[n] = -lhs[n]; return vs; }
template <IsReal T, Size S> inline Vector<T, S>& operator+=(Vector<T, S>& lhs, const Vector<T, S>& rhs) { for (Size n = 0; n < S; ++n) lhs[n] += rhs[n]; return lhs; }
template <IsReal T, Size S> inline Vector<T, S>& operator-=(Vector<T, S>& lhs, const Vector<T, S>& rhs) { for (Size n = 0; n < S; ++n) lhs[n] -= rhs[n]; return lhs; }
template <IsReal T, Size S> inline Vector<T, S>& operator*=(Vector<T, S>& lhs, const Vector<T, S>& rhs) { for (Size n = 0; n < S; ++n) lhs[n] *= rhs[n]; return lhs; }
template <IsReal T, Size S> inline Vector<T, S>& operator/=(Vector<T, S>& lhs, const Vector<T, S>& rhs) { for (Size n = 0; n < S; ++n) lhs[n] /= rhs[n]; return lhs; }
template <IsReal T, Size S> inline Vector<T, S> operator+(const Vector<T, S>& lhs, const Vector<T, S>& rhs) { Vector<T, S> vs {lhs}; for (Size n = 0; n < S; ++n) vs[n] += rhs[n]; return vs; }
template <IsReal T, Size S> inline Vector<T, S> operator-(const Vector<T, S>& lhs, const Vector<T, S>& rhs) { Vector<T, S> vs {lhs}; for (Size n = 0; n < S; ++n) vs[n] -= rhs[n]; return vs; }
template <IsReal T, Size S> inline Vector<T, S> operator*(const Vector<T, S>& lhs, const Vector<T, S>& rhs) { Vector<T, S> vs {lhs}; for (Size n = 0; n < S; ++n) vs[n] *= rhs[n]; return vs; }
template <IsReal T, Size S> inline Vector<T, S> operator/(const Vector<T, S>& lhs, const Vector<T, S>& rhs) { Vector<T, S> vs {lhs}; for (Size n = 0; n < S; ++n) vs[n] /= rhs[n]; return vs; }
template <IsReal T, Size S> inline bool operator==(const Vector<T, S>& lhs, const Vector<T, S>& rhs) { for (Size n = 0; n < S; ++n) if (lhs[n] != rhs[n]) return false; return true; }
template <IsReal T, Size S> inline bool operator!=(const Vector<T, S>& lhs, const Vector<T, S>& rhs) { for (Size n = 0; n < S; ++n) if (lhs[n] == rhs[n]) return false; return true; }
template <IsReal T, Size S> inline Vector<T, S>& operator+=(Vector<T, S>& lhs, const T& rhs) { for (Size n = 0; n < S; ++n) lhs[n] += rhs; return lhs; }
template <IsReal T, Size S> inline Vector<T, S>& operator-=(Vector<T, S>& lhs, const T& rhs) { for (Size n = 0; n < S; ++n) lhs[n] -= rhs; return lhs; }
template <IsReal T, Size S> inline Vector<T, S>& operator*=(Vector<T, S>& lhs, const T& rhs) { for (Size n = 0; n < S; ++n) lhs[n] *= rhs; return lhs; }
template <IsReal T, Size S> inline Vector<T, S>& operator/=(Vector<T, S>& lhs, const T& rhs) { for (Size n = 0; n < S; ++n) lhs[n] /= rhs; return lhs; }
template <IsReal T, Size S> inline Vector<T, S> operator+(const Vector<T, S>& lhs, const T& rhs) { Vector<T, S> vs {lhs}; for (Size n = 0; n < S; ++n) vs[n] += rhs; return vs; }
template <IsReal T, Size S> inline Vector<T, S> operator-(const Vector<T, S>& lhs, const T& rhs) { Vector<T, S> vs {lhs}; for (Size n = 0; n < S; ++n) vs[n] -= rhs; return vs; }
template <IsReal T, IsReal T2, Size S> inline Vector<T, S> operator*(const Vector<T, S>& lhs, const T2& rhs) { Vector<T, S> vs {lhs}; for (Size n = 0; n < S; ++n) vs[n] *= static_cast<T>(rhs); return vs; }
template <IsReal T, IsReal T2, Size S> inline Vector<T, S> operator/(const Vector<T, S>& lhs, const T2& rhs) { Vector<T, S> vs {lhs}; for (Size n = 0; n < S; ++n) vs[n] /= static_cast<T>(rhs); return vs; }
template <IsReal T, Size S> inline Vector<T, S> operator+(const T& lhs, const Vector<T, S>& rhs) { Vector<T, S> vs {rhs}; for (Size n = 0; n < S; ++n) vs[n] += lhs; return vs; }
template <IsReal T, Size S> inline Vector<T, S> operator-(const T& lhs, const Vector<T, S>& rhs) { Vector<T, S> vs {rhs}; for (Size n = 0; n < S; ++n) vs[n] -= lhs; return vs; }
template <IsReal T, Size S> inline Vector<T, S> operator*(const T& lhs, const Vector<T, S>& rhs) { Vector<T, S> vs {rhs}; for (Size n = 0; n < S; ++n) vs[n] *= lhs; return vs; }
template <IsReal T, Size S> inline Vector<T, S> operator/(const T& lhs, const Vector<T, S>& rhs) { Vector<T, S> vs {rhs}; for (Size n = 0; n < S; ++n) vs[n] /= lhs; return vs; }
// boolean operations
template <typename Type, Size S>
inline
Vector<bool, S> equal(const Vector<Type, S>& lhs, const Vector<Type, S>& rhs, const scalar& precision = hpr::precision())
{
Vector<bool, S> vs;
for (auto n = 0; n < S; ++n)
vs[n] = equal(lhs[n], rhs[n], precision);
return vs;
}
template <Size S>
inline
bool any(const Vector<bool, S>& vs)
{
bool res = false;
for (auto e : vs)
res = res || e;
return res;
}
template <Size S>
inline
bool all(const Vector<bool, S>& vs)
{
bool res = true;
for (auto e : vs)
res = res && e;
return res;
}
// per element operations
template <typename Type, Size S>
inline
Vector<Type, S> abs(const Vector<Type, S>& vs)
{
Vector<Type, S> res;
for (auto n = 0; n < S; ++n)
res[n] = abs(vs[n]);
return res;
}
template <typename Type, Size S>
inline
Type sum(const Vector<Type, S>& vs)
{
Type sum {};
for (const Type& v : vs)
sum += v;
return sum;
}
template <typename Type, Size S>
inline
Vector<Type, S> pow(const Vector<Type, S>& vs, scalar degree)
{
Vector<Type, S> res;
for (auto n = 0; n < S; ++n)
res[n] = pow(vs[n], degree);
return res;
}
// vector operations
template <typename Type, Size S>
inline
Type norm(const Vector<Type, S>& vs)
{
return sqrt(sum(pow(abs(vs), 2)));
}
template <typename Type, Size S>
inline
Type dot(const Vector<Type, S>& lhs, const Vector<Type, S>& rhs)
{
return sum(lhs * rhs);
}
template <typename Type, Size S>
inline
Type length(const Vector<Type, S>& vs)
{
return sqrt(dot(vs, vs));
}
template <typename Type, Size S>
inline
Type mag(const Vector<Type, S>& vs)
{
return length(vs);
}
template <typename Type, Size S>
inline
Type distance(const Vector<Type, S>& vs1, const Vector<Type, S>& vs2)
{
return length(vs1 - vs2);
}
template <typename Type, Size S>
inline
Vector<Type, S> normalize(const Vector<Type, S>& vs)
{
return vs * isqrt(dot(vs, vs));
}
template <typename Type>
inline
Type angle(const Vector<Type, 3>& lhs, const Vector<Type, 3>& rhs)
{
scalar cos = dot(lhs, rhs) / (norm(lhs) * norm(rhs));
return acos(cos); //clip(cos, -1., 1.));
}
// vector 3 operations
template <typename Type>
inline
Vector<Type, 3> cross(const Vector<Type, 3>& lhs, const Vector<Type, 3>& rhs)
{
return Vector<Type, 3>(
lhs[1] * rhs[2] - lhs[2] * rhs[1],
lhs[2] * rhs[0] - lhs[0] * rhs[2],
lhs[0] * rhs[1] - lhs[1] * rhs[0]
);
}
} // end namespace hpr

View File

@ -1,305 +1,305 @@
#pragma once
#include <type_traits>
#include <cmath>
#include <limits>
#include <numbers>
#ifdef __MSC_VER
#define HPR_CONSTEXPR
#else
#define HPR_CONSTEXPR constexpr
#endif
namespace hpr
{
using Size = std::size_t;
template <typename Type>
struct is_size : public std::integral_constant<bool, std::is_integral<Type>::value && std::is_unsigned<Type>::value> {};
template <typename Type>
concept IsSize = is_size<Type>::value || std::convertible_to<Type, Size>;
template <typename Type>
struct is_integer : public std::is_integral<Type> {};
template <typename Type>
concept IsInteger = is_integer<Type>::value;
template <typename Type>
struct is_scalar : public std::is_floating_point<Type> {};
template <typename Type>
concept IsScalar = is_scalar<Type>::value;
template <typename Type>
concept IsReal = is_integer<Type>::value || is_scalar<Type>::value;
#ifndef HPR_SCALAR
#define HPR_SCALAR float
#endif
#ifdef HPR_SCALAR_IMPLEMENTATION
template <IsScalar T>
class Scalar
{
public:
using type = Scalar<T>;
using value_type = T;
protected:
value_type p_value;
public:
// constructors
constexpr Scalar() : p_value {} {}
template <IsScalar X> constexpr Scalar(const Scalar<X>& value) : p_value {static_cast<value_type>(value.p_value)} {}
template <IsReal X> constexpr Scalar(const X& value) : p_value {static_cast<value_type>(value)} {}
template <IsScalar X> constexpr type& operator=(const Scalar<X>& value) { p_value = static_cast<value_type>(value.p_value); return *this; }
template <IsReal X> constexpr type& operator=(const X& value) { p_value = static_cast<value_type>(value); return *this; }
virtual constexpr ~Scalar() = default;
// conversion
constexpr operator double() const { return static_cast<double>(p_value); }
constexpr operator float() const { return static_cast<float>(p_value); }
constexpr operator long double() const { return static_cast<long double>(p_value); }
constexpr operator bool() const { return static_cast<bool>(p_value); }
// access
[[nodiscard]] constexpr value_type value() const { return p_value; }
constexpr value_type& value() { return p_value; }
};
using scalar_type = HPR_SCALAR;
using scalar = Scalar<HPR_SCALAR>;
// template<> scalar::value_type scalar::s_precision = static_cast<scalar::value_type>(1e-15);
/// scalar vs scalar
constexpr scalar operator+(const scalar& s) { return s; }
constexpr scalar operator-(const scalar& s) { return -s.value(); }
constexpr bool operator!(const scalar& s) { return !static_cast<bool>(s.value()); }
constexpr scalar& operator+=(scalar& lhs, const scalar& rhs) { lhs.value() += static_cast<scalar::value_type>(rhs.value()); return lhs; }
constexpr scalar& operator-=(scalar& lhs, const scalar& rhs) { lhs.value() -= static_cast<scalar::value_type>(rhs.value()); return lhs; }
constexpr scalar& operator*=(scalar& lhs, const scalar& rhs) { lhs.value() *= static_cast<scalar::value_type>(rhs.value()); return lhs; }
constexpr scalar& operator/=(scalar& lhs, const scalar& rhs) { lhs.value() /= static_cast<scalar::value_type>(rhs.value()); return lhs; }
constexpr scalar operator+(const scalar& lhs, const scalar& rhs) { return lhs.value() + rhs.value(); }
constexpr scalar operator-(const scalar& lhs, const scalar& rhs) { return lhs.value() - rhs.value(); }
constexpr scalar operator*(const scalar& lhs, const scalar& rhs) { return lhs.value() * rhs.value(); }
constexpr scalar operator/(const scalar& lhs, const scalar& rhs) { return lhs.value() / rhs.value(); }
constexpr bool operator==(const scalar& lhs, const scalar& rhs) { return lhs.value() == rhs.value(); }
constexpr bool operator!=(const scalar& lhs, const scalar& rhs) { return lhs.value() != rhs.value(); }
constexpr bool operator&&(const scalar& lhs, const scalar& rhs) { return static_cast<bool>(lhs) && static_cast<bool>(rhs); }
constexpr bool operator||(const scalar& lhs, const scalar& rhs) { return static_cast<bool>(lhs) || static_cast<bool>(rhs); }
constexpr bool operator>(const scalar& lhs, const scalar& rhs) { return lhs.value() > rhs.value(); }
constexpr bool operator<(const scalar& lhs, const scalar& rhs) { return lhs.value() < rhs.value(); }
constexpr bool operator>=(const scalar& lhs, const scalar& rhs) { return lhs.value() >= rhs.value(); }
constexpr bool operator<=(const scalar& lhs, const scalar& rhs) { return lhs.value() <= rhs.value(); }
// std::ostream& operator<<(std::ostream& stream, const scalar& s) { return stream << s.value(); }
/// scalar vs Scalar<T>
template <IsScalar T> constexpr scalar& operator+=(scalar& lhs, const Scalar<T>& rhs) { lhs.value() += static_cast<scalar::value_type>(rhs.value()); return lhs; }
template <IsScalar T> constexpr scalar& operator-=(scalar& lhs, const Scalar<T>& rhs) { lhs.value() -= static_cast<scalar::value_type>(rhs.value()); return lhs; }
template <IsScalar T> constexpr scalar& operator*=(scalar& lhs, const Scalar<T>& rhs) { lhs.value() *= static_cast<scalar::value_type>(rhs.value()); return lhs; }
template <IsScalar T> constexpr scalar& operator/=(scalar& lhs, const Scalar<T>& rhs) { lhs.value() /= static_cast<scalar::value_type>(rhs.value()); return lhs; }
template <IsScalar T> constexpr scalar operator+(const scalar& lhs, const Scalar<T>& rhs) { return lhs.value() + static_cast<scalar::value_type>(rhs.value()); }
template <IsScalar T> constexpr scalar operator+(const Scalar<T>& lhs, const scalar& rhs) { return static_cast<scalar::value_type>(lhs.value()) + rhs.value(); }
template <IsScalar T> constexpr scalar operator-(const scalar& lhs, const Scalar<T>& rhs) { return lhs.value() - static_cast<scalar::value_type>(rhs.value()); }
template <IsScalar T> constexpr scalar operator-(const Scalar<T>& lhs, const scalar& rhs) { return static_cast<scalar::value_type>(lhs.value()) - rhs.value(); }
template <IsScalar T> constexpr scalar operator*(const scalar& lhs, const Scalar<T>& rhs) { return lhs.value() * static_cast<scalar::value_type>(rhs.value()); }
template <IsScalar T> constexpr scalar operator*(const Scalar<T>& lhs, const scalar& rhs) { return static_cast<scalar::value_type>(lhs.value()) * rhs.value(); }
template <IsScalar T> constexpr scalar operator/(const scalar& lhs, const Scalar<T>& rhs) { return lhs.value() / static_cast<scalar::value_type>(rhs.value()); }
template <IsScalar T> constexpr scalar operator/(const Scalar<T>& lhs, const scalar& rhs) { return static_cast<scalar::value_type>(lhs.value()) / rhs.value(); }
template <IsScalar T> constexpr bool operator==(const scalar& lhs, const Scalar<T>& rhs) { return lhs.value() == static_cast<scalar::value_type>(rhs.value()); }
template <IsScalar T> constexpr bool operator==(const Scalar<T>& lhs, const scalar& rhs) { return static_cast<scalar::value_type>(lhs.value()) == rhs.value(); }
template <IsScalar T> constexpr bool operator!=(const scalar& lhs, const Scalar<T>& rhs) { return lhs.value() != static_cast<scalar::value_type>(rhs.value()); }
template <IsScalar T> constexpr bool operator!=(const Scalar<T>& lhs, const scalar& rhs) { return static_cast<scalar::value_type>(lhs.value()) != rhs.value(); }
template <IsScalar T> constexpr bool operator&&(const scalar& lhs, const Scalar<T>& rhs) { return static_cast<bool>(lhs) && static_cast<bool>(rhs); }
template <IsScalar T> constexpr bool operator&&(const Scalar<T>& lhs, const scalar& rhs) { return static_cast<bool>(lhs) && static_cast<bool>(rhs); }
template <IsScalar T> constexpr bool operator||(const scalar& lhs, const Scalar<T>& rhs) { return static_cast<bool>(lhs) || static_cast<bool>(rhs); }
template <IsScalar T> constexpr bool operator||(const Scalar<T>& lhs, const scalar& rhs) { return static_cast<bool>(lhs) || static_cast<bool>(rhs); }
template <IsScalar T> constexpr bool operator>(const scalar& lhs, const Scalar<T>& rhs) { return lhs.value() > static_cast<scalar::value_type>(rhs.value()); }
template <IsScalar T> constexpr bool operator>(const Scalar<T>& lhs, const scalar& rhs) { return static_cast<scalar::value_type>(lhs.value()) > rhs.value(); }
template <IsScalar T> constexpr bool operator<(const scalar& lhs, const Scalar<T>& rhs) { return lhs.value() < static_cast<scalar::value_type>(rhs.value()); }
template <IsScalar T> constexpr bool operator<(const Scalar<T>& lhs, const scalar& rhs) { return static_cast<scalar::value_type>(lhs.value()) < rhs.value(); }
template <IsScalar T> constexpr bool operator>=(const scalar& lhs, const Scalar<T>& rhs) { return lhs.value() >= static_cast<scalar::value_type>(rhs.value()); }
template <IsScalar T> constexpr bool operator>=(const Scalar<T>& lhs, const scalar& rhs) { return static_cast<scalar::value_type>(lhs.value()) >= rhs.value(); }
template <IsScalar T> constexpr bool operator<=(const scalar& lhs, const Scalar<T>& rhs) { return lhs.value() <= static_cast<scalar::value_type>(rhs.value()); }
template <IsScalar T> constexpr bool operator<=(const Scalar<T>& lhs, const scalar& rhs) { return static_cast<scalar::value_type>(lhs.value()) <= rhs.value(); }
template <IsScalar T> std::ostream& operator<<(std::ostream& stream, const Scalar<T>& s) { return stream << s.value(); }
template <IsScalar T> std::istream& operator>>(std::istream& stream, Scalar<T>& s) { return stream >> s.value(); }
/// scalar vs real
template <IsReal T> constexpr scalar& operator+=(scalar& lhs, const T& rhs) { lhs.value() += static_cast<scalar::value_type>(rhs); return lhs; }
template <IsReal T> constexpr scalar& operator-=(scalar& lhs, const T& rhs) { lhs.value() -= static_cast<scalar::value_type>(rhs); return lhs; }
template <IsReal T> constexpr scalar& operator*=(scalar& lhs, const T& rhs) { lhs.value() *= static_cast<scalar::value_type>(rhs); return lhs; }
template <IsReal T> constexpr scalar& operator/=(scalar& lhs, const T& rhs) { lhs.value() /= static_cast<scalar::value_type>(rhs); return lhs; }
template <IsReal T> constexpr T& operator+=(T& lhs, const scalar& rhs) { lhs += static_cast<T>(rhs); return lhs; }
template <IsReal T> constexpr T& operator-=(T& lhs, const scalar& rhs) { lhs -= static_cast<T>(rhs); return lhs; }
template <IsReal T> constexpr T& operator*=(T& lhs, const scalar& rhs) { lhs *= static_cast<T>(rhs); return lhs; }
template <IsReal T> constexpr T& operator/=(T& lhs, const scalar& rhs) { lhs /= static_cast<T>(rhs); return lhs; }
template <IsReal T> constexpr scalar operator+(const scalar& lhs, const T& rhs) { return lhs.value() + static_cast<scalar::value_type>(rhs); }
template <IsReal T> constexpr scalar operator+(const T& lhs, const scalar& rhs) { return static_cast<scalar::value_type>(lhs) + rhs.value(); }
template <IsReal T> constexpr scalar operator-(const scalar& lhs, const T& rhs) { return lhs.value() - static_cast<scalar::value_type>(rhs); }
template <IsReal T> constexpr scalar operator-(const T& lhs, const scalar& rhs) { return static_cast<scalar::value_type>(lhs) - rhs.value(); }
template <IsReal T> constexpr scalar operator*(const scalar& lhs, const T& rhs) { return lhs.value() * static_cast<scalar::value_type>(rhs); }
template <IsReal T> constexpr scalar operator*(const T& lhs, const scalar& rhs) { return static_cast<scalar::value_type>(lhs) * rhs.value(); }
template <IsReal T> constexpr scalar operator/(const scalar& lhs, const T& rhs) { return lhs.value() / static_cast<scalar::value_type>(rhs); }
template <IsReal T> constexpr scalar operator/(const T& lhs, const scalar& rhs) { return static_cast<scalar::value_type>(lhs) / rhs.value(); }
template <IsReal T> constexpr bool operator==(const scalar& lhs, const T& rhs) { return lhs.value() == static_cast<scalar::value_type>(rhs); }
template <IsReal T> constexpr bool operator==(const T& lhs, const scalar& rhs) { return static_cast<scalar::value_type>(lhs) == rhs.value(); }
template <IsReal T> constexpr bool operator!=(const scalar& lhs, const T& rhs) { return lhs.value() != static_cast<scalar::value_type>(rhs); }
template <IsReal T> constexpr bool operator!=(const T& lhs, const scalar& rhs) { return static_cast<scalar::value_type>(lhs) != rhs.value(); }
template <IsReal T> constexpr bool operator&&(const scalar& lhs, const T& rhs) { return static_cast<bool>(lhs) && static_cast<bool>(rhs); }
template <IsReal T> constexpr bool operator&&(const T& lhs, const scalar& rhs) { return static_cast<bool>(lhs) && static_cast<bool>(rhs); }
template <IsReal T> constexpr bool operator||(const scalar& lhs, const T& rhs) { return static_cast<bool>(lhs) || static_cast<bool>(rhs); }
template <IsReal T> constexpr bool operator||(const T& lhs, const scalar& rhs) { return static_cast<bool>(lhs) || static_cast<bool>(rhs); }
template <IsReal T> constexpr bool operator>(const scalar& lhs, const T& rhs) { return lhs.value() > static_cast<scalar::value_type>(rhs); }
template <IsReal T> constexpr bool operator>(const T& lhs, const scalar& rhs) { return static_cast<scalar::value_type>(lhs) > rhs.value(); }
template <IsReal T> constexpr bool operator<(const scalar& lhs, const T& rhs) { return lhs.value() < static_cast<scalar::value_type>(rhs); }
template <IsReal T> constexpr bool operator<(const T& lhs, const scalar& rhs) { return static_cast<scalar::value_type>(lhs) < rhs.value(); }
template <IsReal T> constexpr bool operator>=(const scalar& lhs, const T& rhs) { return lhs.value() >= static_cast<scalar::value_type>(rhs); }
template <IsReal T> constexpr bool operator>=(const T& lhs, const scalar& rhs) { return static_cast<scalar::value_type>(lhs) >= rhs.value(); }
template <IsReal T> constexpr bool operator<=(const scalar& lhs, const T& rhs) { return lhs.value() <= static_cast<scalar::value_type>(rhs); }
template <IsReal T> constexpr bool operator<=(const T& lhs, const scalar& rhs) { return static_cast<scalar::value_type>(lhs) <= rhs.value(); }
#else
using scalar_type = HPR_SCALAR;
using scalar = HPR_SCALAR;
#endif
// constants
HPR_CONSTEXPR scalar pi() { return std::numbers::pi_v<scalar_type>; }
HPR_CONSTEXPR scalar e() { return std::numbers::e_v<scalar_type>; }
// transcendentals
template <IsReal T> HPR_CONSTEXPR scalar cos(const T& s) { return std::cos(static_cast<scalar_type>(s));}
template <IsReal T> HPR_CONSTEXPR scalar acos(const T& s) { return std::acos(static_cast<scalar_type>(s)); }
template <IsReal T> HPR_CONSTEXPR scalar cosh(const T& s) { return std::cosh(static_cast<scalar_type>(s)); }
template <IsReal T> HPR_CONSTEXPR scalar acosh(const T& s) { return std::acosh(static_cast<scalar_type>(s)); }
template <IsReal T> HPR_CONSTEXPR scalar sin(const T& s) { return std::sin(static_cast<scalar_type>(s)); }
template <IsReal T> HPR_CONSTEXPR scalar asin(const T& s) { return std::asin(static_cast<scalar_type>(s)); }
template <IsReal T> HPR_CONSTEXPR scalar sinh(const T& s) { return std::sinh(static_cast<scalar_type>(s)); }
template <IsReal T> HPR_CONSTEXPR scalar asinh(const T& s) { return std::asinh(static_cast<scalar_type>(s)); }
template <IsReal T> HPR_CONSTEXPR scalar tan(const T& s) { return std::tan(static_cast<scalar_type>(s)); }
template <IsReal T> HPR_CONSTEXPR scalar atan(const T& s) { return std::atan(static_cast<scalar_type>(s)); }
template <IsReal T, IsReal X> HPR_CONSTEXPR scalar atan2(const T& s, const X& s2) { return std::atan2(static_cast<scalar_type>(s), static_cast<scalar_type>(s2)); }
template <IsReal T> HPR_CONSTEXPR scalar tanh(const T& s) { return std::tanh(static_cast<scalar_type>(s)); }
template <IsReal T> HPR_CONSTEXPR scalar atanh(const T& s) { return std::atanh(static_cast<scalar_type>(s)); }
template <IsReal T> HPR_CONSTEXPR scalar exp(const T& s) { return std::exp(static_cast<scalar_type>(s)); }
template <IsReal T> HPR_CONSTEXPR scalar log(const T& s) { return std::log(static_cast<scalar_type>(s)); }
template <IsReal T> HPR_CONSTEXPR scalar log10(const T& s) { return std::log10(static_cast<scalar_type>(s)); }
template <IsReal T, IsReal X> HPR_CONSTEXPR scalar pow(const T& s, const X& d) { return std::pow(static_cast<scalar_type>(s), static_cast<scalar_type>(d)); }
template <IsReal T> HPR_CONSTEXPR scalar sqrt(const T& s) { return std::sqrt(static_cast<scalar_type>(s)); }
template <IsReal T> HPR_CONSTEXPR scalar isqrt(const T& s) { return static_cast<T>(1) / sqrt(static_cast<scalar_type>(s)); }
//
static scalar_type scalar_precision = static_cast<scalar_type>(1e-15);
inline scalar_type precision()
{
return scalar_precision;
}
template <IsReal T> inline void precision(const T& precision)
{
scalar_precision = static_cast<scalar_type>(precision);
}
HPR_CONSTEXPR scalar inf() { return std::numeric_limits<scalar_type>::infinity(); }
HPR_CONSTEXPR scalar epsilon() { return std::numeric_limits<scalar_type>::epsilon(); }
HPR_CONSTEXPR scalar isnan(const scalar& s) { return std::isnan(static_cast<scalar_type>(s)); }
HPR_CONSTEXPR scalar abs(const scalar& s) { return std::abs(static_cast<scalar_type>(s)); }
HPR_CONSTEXPR scalar mag(const scalar& s) { return std::abs(static_cast<scalar_type>(s)); }
HPR_CONSTEXPR bool equal(const scalar& lhs, const scalar& rhs, const scalar& precision = hpr::precision()) { return abs(lhs - rhs) < precision; }
//! Convert degrees to radians
HPR_CONSTEXPR scalar rad(const scalar& s) { return s * pi() / static_cast<scalar_type>(180); }
//! Convert radians to degrees
HPR_CONSTEXPR scalar deg(const scalar& s) { return s * static_cast<scalar_type>(180) / pi(); }
HPR_CONSTEXPR scalar min(const scalar& s1, const scalar& s2) { return std::min(static_cast<scalar_type>(s1), static_cast<scalar_type>(s2));}
HPR_CONSTEXPR scalar max(const scalar& s1, const scalar& s2) { return std::max(static_cast<scalar_type>(s1), static_cast<scalar_type>(s2)); }
HPR_CONSTEXPR scalar clip(const scalar& s, const scalar& sMin, const scalar& sMax) { return min(sMax, max(s, sMin)); }
} // end namespace hpr
#ifdef HPR_SCALAR_IMPLEMENTATION
namespace std
{
template <class T> struct is_floating_point<hpr::scalar> : true_type {};
} // end namespace std
#pragma once
#include <type_traits>
#include <cmath>
#include <limits>
#include <numbers>
#ifdef __MSC_VER
#define HPR_CONSTEXPR
#else
#define HPR_CONSTEXPR constexpr
#endif
namespace hpr
{
using Size = std::size_t;
template <typename Type>
struct is_size : public std::integral_constant<bool, std::is_integral<Type>::value && std::is_unsigned<Type>::value> {};
template <typename Type>
concept IsSize = is_size<Type>::value || std::convertible_to<Type, Size>;
template <typename Type>
struct is_integer : public std::is_integral<Type> {};
template <typename Type>
concept IsInteger = is_integer<Type>::value;
template <typename Type>
struct is_scalar : public std::is_floating_point<Type> {};
template <typename Type>
concept IsScalar = is_scalar<Type>::value;
template <typename Type>
concept IsReal = is_integer<Type>::value || is_scalar<Type>::value;
#ifndef HPR_SCALAR
#define HPR_SCALAR float
#endif
#ifdef HPR_SCALAR_IMPLEMENTATION
template <IsScalar T>
class Scalar
{
public:
using type = Scalar<T>;
using value_type = T;
protected:
value_type p_value;
public:
// constructors
constexpr Scalar() : p_value {} {}
template <IsScalar X> constexpr Scalar(const Scalar<X>& value) : p_value {static_cast<value_type>(value.p_value)} {}
template <IsReal X> constexpr Scalar(const X& value) : p_value {static_cast<value_type>(value)} {}
template <IsScalar X> constexpr type& operator=(const Scalar<X>& value) { p_value = static_cast<value_type>(value.p_value); return *this; }
template <IsReal X> constexpr type& operator=(const X& value) { p_value = static_cast<value_type>(value); return *this; }
virtual constexpr ~Scalar() = default;
// conversion
constexpr operator double() const { return static_cast<double>(p_value); }
constexpr operator float() const { return static_cast<float>(p_value); }
constexpr operator long double() const { return static_cast<long double>(p_value); }
constexpr operator bool() const { return static_cast<bool>(p_value); }
// access
[[nodiscard]] constexpr value_type value() const { return p_value; }
constexpr value_type& value() { return p_value; }
};
using scalar_type = HPR_SCALAR;
using scalar = Scalar<HPR_SCALAR>;
// template<> scalar::value_type scalar::s_precision = static_cast<scalar::value_type>(1e-15);
/// scalar vs scalar
constexpr scalar operator+(const scalar& s) { return s; }
constexpr scalar operator-(const scalar& s) { return -s.value(); }
constexpr bool operator!(const scalar& s) { return !static_cast<bool>(s.value()); }
constexpr scalar& operator+=(scalar& lhs, const scalar& rhs) { lhs.value() += static_cast<scalar::value_type>(rhs.value()); return lhs; }
constexpr scalar& operator-=(scalar& lhs, const scalar& rhs) { lhs.value() -= static_cast<scalar::value_type>(rhs.value()); return lhs; }
constexpr scalar& operator*=(scalar& lhs, const scalar& rhs) { lhs.value() *= static_cast<scalar::value_type>(rhs.value()); return lhs; }
constexpr scalar& operator/=(scalar& lhs, const scalar& rhs) { lhs.value() /= static_cast<scalar::value_type>(rhs.value()); return lhs; }
constexpr scalar operator+(const scalar& lhs, const scalar& rhs) { return lhs.value() + rhs.value(); }
constexpr scalar operator-(const scalar& lhs, const scalar& rhs) { return lhs.value() - rhs.value(); }
constexpr scalar operator*(const scalar& lhs, const scalar& rhs) { return lhs.value() * rhs.value(); }
constexpr scalar operator/(const scalar& lhs, const scalar& rhs) { return lhs.value() / rhs.value(); }
constexpr bool operator==(const scalar& lhs, const scalar& rhs) { return lhs.value() == rhs.value(); }
constexpr bool operator!=(const scalar& lhs, const scalar& rhs) { return lhs.value() != rhs.value(); }
constexpr bool operator&&(const scalar& lhs, const scalar& rhs) { return static_cast<bool>(lhs) && static_cast<bool>(rhs); }
constexpr bool operator||(const scalar& lhs, const scalar& rhs) { return static_cast<bool>(lhs) || static_cast<bool>(rhs); }
constexpr bool operator>(const scalar& lhs, const scalar& rhs) { return lhs.value() > rhs.value(); }
constexpr bool operator<(const scalar& lhs, const scalar& rhs) { return lhs.value() < rhs.value(); }
constexpr bool operator>=(const scalar& lhs, const scalar& rhs) { return lhs.value() >= rhs.value(); }
constexpr bool operator<=(const scalar& lhs, const scalar& rhs) { return lhs.value() <= rhs.value(); }
// std::ostream& operator<<(std::ostream& stream, const scalar& s) { return stream << s.value(); }
/// scalar vs Scalar<T>
template <IsScalar T> constexpr scalar& operator+=(scalar& lhs, const Scalar<T>& rhs) { lhs.value() += static_cast<scalar::value_type>(rhs.value()); return lhs; }
template <IsScalar T> constexpr scalar& operator-=(scalar& lhs, const Scalar<T>& rhs) { lhs.value() -= static_cast<scalar::value_type>(rhs.value()); return lhs; }
template <IsScalar T> constexpr scalar& operator*=(scalar& lhs, const Scalar<T>& rhs) { lhs.value() *= static_cast<scalar::value_type>(rhs.value()); return lhs; }
template <IsScalar T> constexpr scalar& operator/=(scalar& lhs, const Scalar<T>& rhs) { lhs.value() /= static_cast<scalar::value_type>(rhs.value()); return lhs; }
template <IsScalar T> constexpr scalar operator+(const scalar& lhs, const Scalar<T>& rhs) { return lhs.value() + static_cast<scalar::value_type>(rhs.value()); }
template <IsScalar T> constexpr scalar operator+(const Scalar<T>& lhs, const scalar& rhs) { return static_cast<scalar::value_type>(lhs.value()) + rhs.value(); }
template <IsScalar T> constexpr scalar operator-(const scalar& lhs, const Scalar<T>& rhs) { return lhs.value() - static_cast<scalar::value_type>(rhs.value()); }
template <IsScalar T> constexpr scalar operator-(const Scalar<T>& lhs, const scalar& rhs) { return static_cast<scalar::value_type>(lhs.value()) - rhs.value(); }
template <IsScalar T> constexpr scalar operator*(const scalar& lhs, const Scalar<T>& rhs) { return lhs.value() * static_cast<scalar::value_type>(rhs.value()); }
template <IsScalar T> constexpr scalar operator*(const Scalar<T>& lhs, const scalar& rhs) { return static_cast<scalar::value_type>(lhs.value()) * rhs.value(); }
template <IsScalar T> constexpr scalar operator/(const scalar& lhs, const Scalar<T>& rhs) { return lhs.value() / static_cast<scalar::value_type>(rhs.value()); }
template <IsScalar T> constexpr scalar operator/(const Scalar<T>& lhs, const scalar& rhs) { return static_cast<scalar::value_type>(lhs.value()) / rhs.value(); }
template <IsScalar T> constexpr bool operator==(const scalar& lhs, const Scalar<T>& rhs) { return lhs.value() == static_cast<scalar::value_type>(rhs.value()); }
template <IsScalar T> constexpr bool operator==(const Scalar<T>& lhs, const scalar& rhs) { return static_cast<scalar::value_type>(lhs.value()) == rhs.value(); }
template <IsScalar T> constexpr bool operator!=(const scalar& lhs, const Scalar<T>& rhs) { return lhs.value() != static_cast<scalar::value_type>(rhs.value()); }
template <IsScalar T> constexpr bool operator!=(const Scalar<T>& lhs, const scalar& rhs) { return static_cast<scalar::value_type>(lhs.value()) != rhs.value(); }
template <IsScalar T> constexpr bool operator&&(const scalar& lhs, const Scalar<T>& rhs) { return static_cast<bool>(lhs) && static_cast<bool>(rhs); }
template <IsScalar T> constexpr bool operator&&(const Scalar<T>& lhs, const scalar& rhs) { return static_cast<bool>(lhs) && static_cast<bool>(rhs); }
template <IsScalar T> constexpr bool operator||(const scalar& lhs, const Scalar<T>& rhs) { return static_cast<bool>(lhs) || static_cast<bool>(rhs); }
template <IsScalar T> constexpr bool operator||(const Scalar<T>& lhs, const scalar& rhs) { return static_cast<bool>(lhs) || static_cast<bool>(rhs); }
template <IsScalar T> constexpr bool operator>(const scalar& lhs, const Scalar<T>& rhs) { return lhs.value() > static_cast<scalar::value_type>(rhs.value()); }
template <IsScalar T> constexpr bool operator>(const Scalar<T>& lhs, const scalar& rhs) { return static_cast<scalar::value_type>(lhs.value()) > rhs.value(); }
template <IsScalar T> constexpr bool operator<(const scalar& lhs, const Scalar<T>& rhs) { return lhs.value() < static_cast<scalar::value_type>(rhs.value()); }
template <IsScalar T> constexpr bool operator<(const Scalar<T>& lhs, const scalar& rhs) { return static_cast<scalar::value_type>(lhs.value()) < rhs.value(); }
template <IsScalar T> constexpr bool operator>=(const scalar& lhs, const Scalar<T>& rhs) { return lhs.value() >= static_cast<scalar::value_type>(rhs.value()); }
template <IsScalar T> constexpr bool operator>=(const Scalar<T>& lhs, const scalar& rhs) { return static_cast<scalar::value_type>(lhs.value()) >= rhs.value(); }
template <IsScalar T> constexpr bool operator<=(const scalar& lhs, const Scalar<T>& rhs) { return lhs.value() <= static_cast<scalar::value_type>(rhs.value()); }
template <IsScalar T> constexpr bool operator<=(const Scalar<T>& lhs, const scalar& rhs) { return static_cast<scalar::value_type>(lhs.value()) <= rhs.value(); }
template <IsScalar T> std::ostream& operator<<(std::ostream& stream, const Scalar<T>& s) { return stream << s.value(); }
template <IsScalar T> std::istream& operator>>(std::istream& stream, Scalar<T>& s) { return stream >> s.value(); }
/// scalar vs real
template <IsReal T> constexpr scalar& operator+=(scalar& lhs, const T& rhs) { lhs.value() += static_cast<scalar::value_type>(rhs); return lhs; }
template <IsReal T> constexpr scalar& operator-=(scalar& lhs, const T& rhs) { lhs.value() -= static_cast<scalar::value_type>(rhs); return lhs; }
template <IsReal T> constexpr scalar& operator*=(scalar& lhs, const T& rhs) { lhs.value() *= static_cast<scalar::value_type>(rhs); return lhs; }
template <IsReal T> constexpr scalar& operator/=(scalar& lhs, const T& rhs) { lhs.value() /= static_cast<scalar::value_type>(rhs); return lhs; }
template <IsReal T> constexpr T& operator+=(T& lhs, const scalar& rhs) { lhs += static_cast<T>(rhs); return lhs; }
template <IsReal T> constexpr T& operator-=(T& lhs, const scalar& rhs) { lhs -= static_cast<T>(rhs); return lhs; }
template <IsReal T> constexpr T& operator*=(T& lhs, const scalar& rhs) { lhs *= static_cast<T>(rhs); return lhs; }
template <IsReal T> constexpr T& operator/=(T& lhs, const scalar& rhs) { lhs /= static_cast<T>(rhs); return lhs; }
template <IsReal T> constexpr scalar operator+(const scalar& lhs, const T& rhs) { return lhs.value() + static_cast<scalar::value_type>(rhs); }
template <IsReal T> constexpr scalar operator+(const T& lhs, const scalar& rhs) { return static_cast<scalar::value_type>(lhs) + rhs.value(); }
template <IsReal T> constexpr scalar operator-(const scalar& lhs, const T& rhs) { return lhs.value() - static_cast<scalar::value_type>(rhs); }
template <IsReal T> constexpr scalar operator-(const T& lhs, const scalar& rhs) { return static_cast<scalar::value_type>(lhs) - rhs.value(); }
template <IsReal T> constexpr scalar operator*(const scalar& lhs, const T& rhs) { return lhs.value() * static_cast<scalar::value_type>(rhs); }
template <IsReal T> constexpr scalar operator*(const T& lhs, const scalar& rhs) { return static_cast<scalar::value_type>(lhs) * rhs.value(); }
template <IsReal T> constexpr scalar operator/(const scalar& lhs, const T& rhs) { return lhs.value() / static_cast<scalar::value_type>(rhs); }
template <IsReal T> constexpr scalar operator/(const T& lhs, const scalar& rhs) { return static_cast<scalar::value_type>(lhs) / rhs.value(); }
template <IsReal T> constexpr bool operator==(const scalar& lhs, const T& rhs) { return lhs.value() == static_cast<scalar::value_type>(rhs); }
template <IsReal T> constexpr bool operator==(const T& lhs, const scalar& rhs) { return static_cast<scalar::value_type>(lhs) == rhs.value(); }
template <IsReal T> constexpr bool operator!=(const scalar& lhs, const T& rhs) { return lhs.value() != static_cast<scalar::value_type>(rhs); }
template <IsReal T> constexpr bool operator!=(const T& lhs, const scalar& rhs) { return static_cast<scalar::value_type>(lhs) != rhs.value(); }
template <IsReal T> constexpr bool operator&&(const scalar& lhs, const T& rhs) { return static_cast<bool>(lhs) && static_cast<bool>(rhs); }
template <IsReal T> constexpr bool operator&&(const T& lhs, const scalar& rhs) { return static_cast<bool>(lhs) && static_cast<bool>(rhs); }
template <IsReal T> constexpr bool operator||(const scalar& lhs, const T& rhs) { return static_cast<bool>(lhs) || static_cast<bool>(rhs); }
template <IsReal T> constexpr bool operator||(const T& lhs, const scalar& rhs) { return static_cast<bool>(lhs) || static_cast<bool>(rhs); }
template <IsReal T> constexpr bool operator>(const scalar& lhs, const T& rhs) { return lhs.value() > static_cast<scalar::value_type>(rhs); }
template <IsReal T> constexpr bool operator>(const T& lhs, const scalar& rhs) { return static_cast<scalar::value_type>(lhs) > rhs.value(); }
template <IsReal T> constexpr bool operator<(const scalar& lhs, const T& rhs) { return lhs.value() < static_cast<scalar::value_type>(rhs); }
template <IsReal T> constexpr bool operator<(const T& lhs, const scalar& rhs) { return static_cast<scalar::value_type>(lhs) < rhs.value(); }
template <IsReal T> constexpr bool operator>=(const scalar& lhs, const T& rhs) { return lhs.value() >= static_cast<scalar::value_type>(rhs); }
template <IsReal T> constexpr bool operator>=(const T& lhs, const scalar& rhs) { return static_cast<scalar::value_type>(lhs) >= rhs.value(); }
template <IsReal T> constexpr bool operator<=(const scalar& lhs, const T& rhs) { return lhs.value() <= static_cast<scalar::value_type>(rhs); }
template <IsReal T> constexpr bool operator<=(const T& lhs, const scalar& rhs) { return static_cast<scalar::value_type>(lhs) <= rhs.value(); }
#else
using scalar_type = HPR_SCALAR;
using scalar = HPR_SCALAR;
#endif
// constants
HPR_CONSTEXPR scalar pi() { return std::numbers::pi_v<scalar_type>; }
HPR_CONSTEXPR scalar e() { return std::numbers::e_v<scalar_type>; }
// transcendentals
template <IsReal T> HPR_CONSTEXPR scalar cos(const T& s) { return std::cos(static_cast<scalar_type>(s));}
template <IsReal T> HPR_CONSTEXPR scalar acos(const T& s) { return std::acos(static_cast<scalar_type>(s)); }
template <IsReal T> HPR_CONSTEXPR scalar cosh(const T& s) { return std::cosh(static_cast<scalar_type>(s)); }
template <IsReal T> HPR_CONSTEXPR scalar acosh(const T& s) { return std::acosh(static_cast<scalar_type>(s)); }
template <IsReal T> HPR_CONSTEXPR scalar sin(const T& s) { return std::sin(static_cast<scalar_type>(s)); }
template <IsReal T> HPR_CONSTEXPR scalar asin(const T& s) { return std::asin(static_cast<scalar_type>(s)); }
template <IsReal T> HPR_CONSTEXPR scalar sinh(const T& s) { return std::sinh(static_cast<scalar_type>(s)); }
template <IsReal T> HPR_CONSTEXPR scalar asinh(const T& s) { return std::asinh(static_cast<scalar_type>(s)); }
template <IsReal T> HPR_CONSTEXPR scalar tan(const T& s) { return std::tan(static_cast<scalar_type>(s)); }
template <IsReal T> HPR_CONSTEXPR scalar atan(const T& s) { return std::atan(static_cast<scalar_type>(s)); }
template <IsReal T, IsReal X> HPR_CONSTEXPR scalar atan2(const T& s, const X& s2) { return std::atan2(static_cast<scalar_type>(s), static_cast<scalar_type>(s2)); }
template <IsReal T> HPR_CONSTEXPR scalar tanh(const T& s) { return std::tanh(static_cast<scalar_type>(s)); }
template <IsReal T> HPR_CONSTEXPR scalar atanh(const T& s) { return std::atanh(static_cast<scalar_type>(s)); }
template <IsReal T> HPR_CONSTEXPR scalar exp(const T& s) { return std::exp(static_cast<scalar_type>(s)); }
template <IsReal T> HPR_CONSTEXPR scalar log(const T& s) { return std::log(static_cast<scalar_type>(s)); }
template <IsReal T> HPR_CONSTEXPR scalar log10(const T& s) { return std::log10(static_cast<scalar_type>(s)); }
template <IsReal T, IsReal X> HPR_CONSTEXPR scalar pow(const T& s, const X& d) { return std::pow(static_cast<scalar_type>(s), static_cast<scalar_type>(d)); }
template <IsReal T> HPR_CONSTEXPR scalar sqrt(const T& s) { return std::sqrt(static_cast<scalar_type>(s)); }
template <IsReal T> HPR_CONSTEXPR scalar isqrt(const T& s) { return static_cast<T>(1) / sqrt(static_cast<scalar_type>(s)); }
//
static scalar_type scalar_precision = static_cast<scalar_type>(1e-15);
inline scalar_type precision()
{
return scalar_precision;
}
template <IsReal T> inline void precision(const T& precision)
{
scalar_precision = static_cast<scalar_type>(precision);
}
HPR_CONSTEXPR scalar inf() { return std::numeric_limits<scalar_type>::infinity(); }
HPR_CONSTEXPR scalar epsilon() { return std::numeric_limits<scalar_type>::epsilon(); }
HPR_CONSTEXPR scalar isnan(const scalar& s) { return std::isnan(static_cast<scalar_type>(s)); }
HPR_CONSTEXPR scalar abs(const scalar& s) { return std::abs(static_cast<scalar_type>(s)); }
HPR_CONSTEXPR scalar mag(const scalar& s) { return std::abs(static_cast<scalar_type>(s)); }
HPR_CONSTEXPR bool equal(const scalar& lhs, const scalar& rhs, const scalar& precision = hpr::precision()) { return abs(lhs - rhs) < precision; }
//! Convert degrees to radians
HPR_CONSTEXPR scalar rad(const scalar& s) { return s * pi() / static_cast<scalar_type>(180); }
//! Convert radians to degrees
HPR_CONSTEXPR scalar deg(const scalar& s) { return s * static_cast<scalar_type>(180) / pi(); }
HPR_CONSTEXPR scalar min(const scalar& s1, const scalar& s2) { return std::min(static_cast<scalar_type>(s1), static_cast<scalar_type>(s2));}
HPR_CONSTEXPR scalar max(const scalar& s1, const scalar& s2) { return std::max(static_cast<scalar_type>(s1), static_cast<scalar_type>(s2)); }
HPR_CONSTEXPR scalar clip(const scalar& s, const scalar& sMin, const scalar& sMax) { return min(sMax, max(s, sMin)); }
} // end namespace hpr
#ifdef HPR_SCALAR_IMPLEMENTATION
namespace std
{
template <class T> struct is_floating_point<hpr::scalar> : true_type {};
} // end namespace std
#endif

3
source/hpr/shape.hpp Normal file
View File

@ -0,0 +1,3 @@
#pragma once
#include <hpr/shape/shape.hpp>

360
source/hpr/shape/shape.hpp Normal file
View File

@ -0,0 +1,360 @@
#pragma once
#include <hpr/numeric.hpp>
#include <hpr/container/dynamic_array.hpp>
#include <map>
#include <string>
#include <Geom_Surface.hxx>
#include <GeomLProp_SLProps.hxx>
#include <Poly_Triangle.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Vertex.hxx>
#include <TopoDS_Edge.hxx>
#include <TopoDS_Wire.hxx>
#include <TopoDS_Face.hxx>
#include <TopoDS_Compound.hxx>
#include <TopoDS_CompSolid.hxx>
#include <TopoDS_Shell.hxx>
#include <TopoDS_Solid.hxx>
#include <TopExp_Explorer.hxx>
#include <BRepBuilderAPI_MakeVertex.hxx>
#include <BRepBuilderAPI_MakeEdge.hxx>
#include <BRepBuilderAPI_MakeWire.hxx>
#include <BRepBuilderAPI_MakeFace.hxx>
#include <BRepBuilderAPI_MakeShell.hxx>
#include <BRepBuilderAPI_MakeSolid.hxx>
#include <BRepBuilderAPI_Sewing.hxx>
#include <BRep_Builder.hxx>
#include <BRepBndLib.hxx>
#include <BRep_Tool.hxx>
#include <BRepTools.hxx>
#include <BRepGProp.hxx>
#include <GProp_GProps.hxx>
#include <ShapeUpgrade_UnifySameDomain.hxx>
#include <BRepExtrema_DistShapeShape.hxx>
#include <BRepBuilderAPI_Transform.hxx>
#include <BRepBuilderAPI_GTransform.hxx>
#include <BRepFilletAPI_MakeFillet.hxx>
#include <BRepAlgoAPI_Fuse.hxx>
#include <BRepAlgoAPI_Common.hxx>
#include <BRepAlgoAPI_Cut.hxx>
#include <BRepPrimAPI_MakeSphere.hxx>
#include <BRepPrimAPI_MakeBox.hxx>
#include <BRepPrimAPI_MakePrism.hxx>
#include <STEPControl_Writer.hxx>
#include <Interface_Static.hxx>
#include <BRepMesh_IncrementalMesh.hxx>
#include <Poly_PolygonOnTriangulation.hxx>
#include <Poly_Triangulation.hxx>
#include <TopAbs_ShapeEnum.hxx>
#include <TopLoc_Location.hxx>
#include <NCollection_List.hxx>
#include <ShapeFix_Solid.hxx>
#include <ShapeFix_Shell.hxx>
#include <ShapeFix_Face.hxx>
namespace hpr::csg
{
class Shape;
}
namespace std
{
template<>
struct less<hpr::csg::Shape>
{
bool operator() (const hpr::csg::Shape& s1, const hpr::csg::Shape& s2) const;
};
}
namespace hpr::csg
{
// Class declaration
class Shape
{
public:
enum class Type
{
Compound,
Compsolid,
Solid,
Shell,
Face,
Wire,
Edge,
Vertex,
Shape,
Unknown
};
enum class Format
{
Unknown,
STEP
};
class Metadata
{
public:
std::string label;
public:
Metadata() :
label {"default"}
{}
void merge(const Metadata& data)
{
if (label == "default" && data.label != "default")
label = data.label;
}
};
public:
// TODO: clean up map
static
std::map<Shape, Shape::Metadata> metadata;
protected:
TopoDS_Shape p_shape;
public:
[[nodiscard]]
TopoDS_Shape tshape() const { return p_shape; }
Shape(const TopoDS_Shape& s) :
p_shape {s}
{}
Shape(TopoDS_Shape&& s) noexcept:
p_shape {std::forward<TopoDS_Shape>(s)}
{}
public:
Shape() :
p_shape {}
{}
virtual
~Shape() = default;
//{
//if (metadata.contains(*this))
// metadata.erase(*this);
//}
[[nodiscard]]
Type type() const
{
switch (p_shape.ShapeType())
{
case TopAbs_VERTEX:
return Type::Vertex;
case TopAbs_EDGE:
return Type::Edge;
case TopAbs_FACE:
return Type::Face;
case TopAbs_WIRE:
return Type::Wire;
case TopAbs_SHELL:
return Type::Shell;
case TopAbs_SOLID:
return Type::Solid;
case TopAbs_COMPOUND:
return Type::Compound;
case TopAbs_COMPSOLID:
return Type::Compsolid;
case TopAbs_SHAPE:
return Type::Shape;
default:
return Type::Unknown;
}
}
[[nodiscard]]
vec3 center() const
{
GProp_GProps props;
switch (type())
{
case Type::Solid:
case Type::Compsolid:
case Type::Compound:
BRepGProp::VolumeProperties(p_shape, props);
case Type::Shell:
case Type::Face:
BRepGProp::SurfaceProperties(p_shape, props);
default:
BRepGProp::LinearProperties(p_shape, props);
}
gp_Pnt center {props.CentreOfMass()};
return vec3 {static_cast<scalar>(center.X()), static_cast<scalar>(center.Y()), static_cast<scalar>(center.Z())};
}
[[nodiscard]]
double length() const
{
GProp_GProps props;
switch (type())
{
case Type::Vertex:
return 0;
default:
BRepGProp::LinearProperties(p_shape, props);
return props.Mass();
}
}
[[nodiscard]]
double area() const
{
GProp_GProps props;
switch (type())
{
case Type::Vertex:
case Type::Edge:
case Type::Wire:
return 0;
default:
BRepGProp::SurfaceProperties(p_shape, props);
return props.Mass();
}
}
[[nodiscard]]
double volume() const
{
GProp_GProps props;
switch (type())
{
case Type::Compsolid:
case Type::Solid:
BRepGProp::VolumeProperties(p_shape, props);
return props.Mass();
default:
return 0;
}
}
void label(const std::string& label) const
{
metadata[*this].label = label;
}
[[nodiscard]]
std::string label() const
{
return metadata[*this].label;
}
void dump(const std::string& filename, Format format) const
{
if (p_shape.IsNull())
throw std::runtime_error("Trying to export null shape");
switch (format)
{
case Format::STEP:
{
STEPControl_Writer writer;
Interface_Static::SetCVal("xstep.cascade.unit", "MM");
Interface_Static::SetCVal("write.step.unit", "MM");
Interface_Static::SetIVal("write.step.nonmanifold", 1);
writer.Transfer(p_shape, STEPControl_AsIs);
writer.Write(filename.c_str());
break;
}
case Format::Unknown:
default:
throw std::invalid_argument("Unknown export format");
}
}
//
[[nodiscard]]
sarray<vec3, 2> boundingBox() const
{
Bnd_Box bbox;
BRepBndLib::Add(p_shape, bbox, true);
gp_Pnt p1 {bbox.CornerMin()};
gp_Pnt p2 {bbox.CornerMax()};
return sarray<vec3, 2> {
{static_cast<scalar>(p1.X()), static_cast<scalar>(p1.Y()), static_cast<scalar>(p1.Z())},
{static_cast<scalar>(p2.X()), static_cast<scalar>(p2.Y()), static_cast<scalar>(p2.Z())}
};
}
void incrementalMesh(double deflection)
{
BRepTools::Clean(p_shape);
BRepMesh_IncrementalMesh(p_shape, deflection, true);
}
darray<Shape> subShapes(Type type) const
{
darray<Shape> shapes;
for (TopExp_Explorer exp(p_shape, static_cast<TopAbs_ShapeEnum>(type)); exp.More(); exp.Next())
shapes.push(Shape(exp.Current()));
return shapes;
}
darray<Shape> edges() const
{
return subShapes(Type::Edge);
}
darray<Shape> faces() const
{
return subShapes(Type::Face);
}
darray<Shape> shells() const
{
return subShapes(Type::Shell);
}
};
double distance(const Shape& lhs, const Shape& rhs)
{
return BRepExtrema_DistShapeShape(lhs.tshape(), rhs.tshape()).Value();
}
}

View File

@ -0,0 +1,5 @@

View File

@ -1,7 +1,7 @@
#include <gtest/gtest.h>
int main(int argc, char **argv)
{
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
#include <gtest/gtest.h>
int main(int argc, char **argv)
{
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@ -1,94 +1,94 @@
#pragma once
#include <gtest/gtest.h>
#include <hpr/container/static_array.hpp>
#include <hpr/container/dynamic_array.hpp>
#include <hpr/container/tree_node.hpp>
TEST(containers, StaticArray)
{
hpr::StaticArray<float, 3> arr {7, 3, 2};
hpr::StaticArray<float, 4> sarr {arr, 5};
hpr::StaticArray<float, 4> sarr2 {7, 3, 2, 5};
//hpr::StaticArray<float, 0> sarr4;
EXPECT_EQ(sarr, sarr2);
//EXPECT_EQ(sarr4.data(), nullptr);
//EXPECT_EQ(sarr4.is_empty(), true);
EXPECT_EQ(sarr.size(), 4);
EXPECT_EQ(sarr2.size(), 4);
EXPECT_EQ(sarr[0], 7);
EXPECT_EQ(sarr[1], 3);
EXPECT_EQ(sarr[2], 2);
EXPECT_EQ(sarr[3], 5);
}
TEST(containers, DynamicArray)
{
hpr::DynamicArray<float> arr {1, 3, 2};
hpr::DynamicArray<float> arr2 {1, 3, 2};
EXPECT_EQ(arr, arr2);
EXPECT_TRUE(arr == arr2);
arr.remove(1);
EXPECT_EQ(arr, hpr::darray<float>({1, 2}));
auto iter = arr2.begin();
++iter;
arr2.remove(iter);
EXPECT_EQ(arr2, hpr::darray<float>({1, 2}));
hpr::DynamicArray<float> arr3 {1, 3, 0, 2, 9, 0, 5};
arr3.remove([](float num) { return num == 0; });
EXPECT_EQ(arr3, hpr::darray<float>({1, 3, 2, 9, 5}));
EXPECT_EQ(arr3.size(), 5);
arr3.insert(3, 19);
EXPECT_EQ(arr3.size(), 6);
EXPECT_EQ(arr3[3], 19);
EXPECT_EQ(arr3.pop(), 5);
EXPECT_EQ(arr3.size(), 5);
arr3.resize(3);
EXPECT_EQ(arr3.size(), 3);
EXPECT_EQ(arr3.capacity(), 3);
EXPECT_EQ(arr3.back(), 2);
arr3.resize(4);
EXPECT_EQ(arr3.back(), 2);
arr3.push(17);
arr3.push(14);
EXPECT_EQ(arr3.back(), 14);
EXPECT_EQ(arr3.size(), 5);
arr3.clear();
EXPECT_EQ(arr3.is_empty(), true);
hpr::DynamicArray<float*> arr4;
arr4.push(new float(5));
arr4.push(new float(7));
arr4.push(new float(9));
EXPECT_EQ(*arr4[0], 5.f);
EXPECT_EQ(*arr4[2], 9.f);
for (auto& v : arr4)
delete v;
}
TEST(containers, TreeNode)
{
hpr::TreeNode<float> node1 (5);
//std::shared_ptr<hpr::TreeNode<float>> ptr {node1};
hpr::TreeNode<float> node2 {7, {&node1}};
hpr::TreeNode<float> node3 {9, {&node2, &node1}};
hpr::TreeNode<float> node4 {11, {&node3}};
EXPECT_EQ(*node1.data(), 5);
//EXPECT_EQ(*node1->data(), *node2.ancestor()->data());
hpr::darray<hpr::TreeNode<float>*> tr = node1.traverse_descendants();
EXPECT_EQ(tr.size(), 0);
hpr::darray<hpr::TreeNode<float>*> tr2 = node4.traverse_descendants();
EXPECT_EQ(tr2.size(), 4);
hpr::darray<hpr::TreeNode<float>*> tr3 = node1.traverse_ancestors();
EXPECT_EQ(tr3.size(), 2); // node1 has changed ancestor
//
}
#pragma once
#include <gtest/gtest.h>
#include <hpr/container/static_array.hpp>
#include <hpr/container/dynamic_array.hpp>
#include <hpr/container/tree_node.hpp>
TEST(containers, StaticArray)
{
hpr::StaticArray<float, 3> arr {7, 3, 2};
hpr::StaticArray<float, 4> sarr {arr, 5};
hpr::StaticArray<float, 4> sarr2 {7, 3, 2, 5};
//hpr::StaticArray<float, 0> sarr4;
EXPECT_EQ(sarr, sarr2);
//EXPECT_EQ(sarr4.data(), nullptr);
//EXPECT_EQ(sarr4.is_empty(), true);
EXPECT_EQ(sarr.size(), 4);
EXPECT_EQ(sarr2.size(), 4);
EXPECT_EQ(sarr[0], 7);
EXPECT_EQ(sarr[1], 3);
EXPECT_EQ(sarr[2], 2);
EXPECT_EQ(sarr[3], 5);
}
TEST(containers, DynamicArray)
{
hpr::DynamicArray<float> arr {1, 3, 2};
hpr::DynamicArray<float> arr2 {1, 3, 2};
EXPECT_EQ(arr, arr2);
EXPECT_TRUE(arr == arr2);
arr.remove(1);
EXPECT_EQ(arr, hpr::darray<float>({1, 2}));
auto iter = arr2.begin();
++iter;
arr2.remove(iter);
EXPECT_EQ(arr2, hpr::darray<float>({1, 2}));
hpr::DynamicArray<float> arr3 {1, 3, 0, 2, 9, 0, 5};
arr3.remove([](float num) { return num == 0; });
EXPECT_EQ(arr3, hpr::darray<float>({1, 3, 2, 9, 5}));
EXPECT_EQ(arr3.size(), 5);
arr3.insert(3, 19);
EXPECT_EQ(arr3.size(), 6);
EXPECT_EQ(arr3[3], 19);
EXPECT_EQ(arr3.pop(), 5);
EXPECT_EQ(arr3.size(), 5);
arr3.resize(3);
EXPECT_EQ(arr3.size(), 3);
EXPECT_EQ(arr3.capacity(), 3);
EXPECT_EQ(arr3.back(), 2);
arr3.resize(4);
EXPECT_EQ(arr3.back(), 2);
arr3.push(17);
arr3.push(14);
EXPECT_EQ(arr3.back(), 14);
EXPECT_EQ(arr3.size(), 5);
arr3.clear();
EXPECT_EQ(arr3.is_empty(), true);
hpr::DynamicArray<float*> arr4;
arr4.push(new float(5));
arr4.push(new float(7));
arr4.push(new float(9));
EXPECT_EQ(*arr4[0], 5.f);
EXPECT_EQ(*arr4[2], 9.f);
for (auto& v : arr4)
delete v;
}
TEST(containers, TreeNode)
{
hpr::TreeNode<float> node1 (5);
//std::shared_ptr<hpr::TreeNode<float>> ptr {node1};
hpr::TreeNode<float> node2 {7, {&node1}};
hpr::TreeNode<float> node3 {9, {&node2, &node1}};
hpr::TreeNode<float> node4 {11, {&node3}};
EXPECT_EQ(*node1.data(), 5);
//EXPECT_EQ(*node1->data(), *node2.ancestor()->data());
hpr::darray<hpr::TreeNode<float>*> tr = node1.traverse_descendants();
EXPECT_EQ(tr.size(), 0);
hpr::darray<hpr::TreeNode<float>*> tr2 = node4.traverse_descendants();
EXPECT_EQ(tr2.size(), 4);
hpr::darray<hpr::TreeNode<float>*> tr3 = node1.traverse_ancestors();
EXPECT_EQ(tr3.size(), 2); // node1 has changed ancestor
//
}

View File

@ -1,63 +1,63 @@
#pragma once
#include <gtest/gtest.h>
#include <hpr/math/vector.hpp>
#include <hpr/math/matrix.hpp>
#include <hpr/math/quaternion.hpp>
TEST(math, Vector)
{
hpr::vec3 v1 {1, 3, 2};
hpr::vec3 v2 {5, 7, -1};
hpr::vec2 v31 {13, -2};
hpr::vec3 v32 (v31, 9);
EXPECT_EQ((hpr::vec3(v2.begin(), v2.end())), v2);
EXPECT_EQ(v32, hpr::vec3(13, -2, 9));
EXPECT_EQ(-v1, hpr::vec3(-1, -3, -2));
EXPECT_EQ(v1 + v2, hpr::vec3(6, 10, 1));
EXPECT_EQ(v1 - v2, hpr::vec3(-4, -4, 3));
EXPECT_EQ((hpr::dot(v1, v2) ), 24);
EXPECT_EQ((hpr::cross(hpr::vec3(1, 0, 0), hpr::vec3(0, 1, 0))), hpr::vec3(0, 0, 1));
EXPECT_EQ((hpr::angle(hpr::vec3(1, 0, 0), hpr::vec3(0, 0, 1))), hpr::pi() * 0.5);
EXPECT_EQ((hpr::normalize(hpr::vec3(1, 1, 1))), hpr::vec3(0.5773502691896258, 0.5773502691896258, 0.5773502691896258));
}
TEST(math, Matrix)
{
hpr::mat2 m1;
hpr::vec4 v1;
EXPECT_FALSE(v1 == m1);
EXPECT_FALSE(m1 == v1);
hpr::mat2 m2 {3, 2, 7, 4};
hpr::vec2 v2 {2, 4};
EXPECT_EQ(m2.col(1), v2);
hpr::vec2 v3 {13, 51};
m2.col(1, v3);
EXPECT_EQ(m2.col(1), v3);
hpr::mat3 m4 {1, 2, 3, 4, 5, 6, 7, 8, 9};
hpr::mat2 m41 {5, 6, 8, 9};
//EXPECT_EQ(minor(m41, 0, 0), 9);
hpr::mat2 m5 {1, 2, 3, 4};
EXPECT_EQ(det(m4), 0);
EXPECT_EQ(hpr::det(m4), 0);
EXPECT_EQ(det(hpr::mat3(-9, 23, 3, 5, 5, 6, 7, -3, 9)), -786);
hpr::mat2 m6 {2, 1, 7, 4};
EXPECT_EQ(det(m6), 1);
EXPECT_EQ(adj(m6), hpr::mat2(4, -1, -7, 2));
EXPECT_EQ(inv(m6), hpr::mat2(4, -1, -7, 2));
EXPECT_EQ(det(hpr::mat3(1, 0, 0, 0, 1, 0, 0, 0, 1)), 1.);
//EXPECT_EQ(m4.det(), 0);
}
TEST(math, Quaternion)
{
hpr::quat q;
hpr::vec3 np = hpr::rotate(hpr::vec3(0, 1, 0), {1, 0, 0}, hpr::pi() * 0.5);
EXPECT_TRUE(hpr::all(hpr::equal(np, hpr::vec3(0, 0, 1))));
EXPECT_EQ(hpr::norm(hpr::quat(np)), 1);
}
#pragma once
#include <gtest/gtest.h>
#include <hpr/math/vector.hpp>
#include <hpr/math/matrix.hpp>
#include <hpr/math/quaternion.hpp>
TEST(math, Vector)
{
hpr::vec3 v1 {1, 3, 2};
hpr::vec3 v2 {5, 7, -1};
hpr::vec2 v31 {13, -2};
hpr::vec3 v32 (v31, 9);
EXPECT_EQ((hpr::vec3(v2.begin(), v2.end())), v2);
EXPECT_EQ(v32, hpr::vec3(13, -2, 9));
EXPECT_EQ(-v1, hpr::vec3(-1, -3, -2));
EXPECT_EQ(v1 + v2, hpr::vec3(6, 10, 1));
EXPECT_EQ(v1 - v2, hpr::vec3(-4, -4, 3));
EXPECT_EQ((hpr::dot(v1, v2) ), 24);
EXPECT_EQ((hpr::cross(hpr::vec3(1, 0, 0), hpr::vec3(0, 1, 0))), hpr::vec3(0, 0, 1));
EXPECT_EQ((hpr::angle(hpr::vec3(1, 0, 0), hpr::vec3(0, 0, 1))), hpr::pi() * 0.5);
EXPECT_EQ((hpr::normalize(hpr::vec3(1, 1, 1))), hpr::vec3(0.5773502691896258, 0.5773502691896258, 0.5773502691896258));
}
TEST(math, Matrix)
{
hpr::mat2 m1;
hpr::vec4 v1;
EXPECT_FALSE(v1 == m1);
EXPECT_FALSE(m1 == v1);
hpr::mat2 m2 {3, 2, 7, 4};
hpr::vec2 v2 {2, 4};
EXPECT_EQ(m2.col(1), v2);
hpr::vec2 v3 {13, 51};
m2.col(1, v3);
EXPECT_EQ(m2.col(1), v3);
hpr::mat3 m4 {1, 2, 3, 4, 5, 6, 7, 8, 9};
hpr::mat2 m41 {5, 6, 8, 9};
//EXPECT_EQ(minor(m41, 0, 0), 9);
hpr::mat2 m5 {1, 2, 3, 4};
EXPECT_EQ(det(m4), 0);
EXPECT_EQ(hpr::det(m4), 0);
EXPECT_EQ(det(hpr::mat3(-9, 23, 3, 5, 5, 6, 7, -3, 9)), -786);
hpr::mat2 m6 {2, 1, 7, 4};
EXPECT_EQ(det(m6), 1);
EXPECT_EQ(adj(m6), hpr::mat2(4, -1, -7, 2));
EXPECT_EQ(inv(m6), hpr::mat2(4, -1, -7, 2));
EXPECT_EQ(det(hpr::mat3(1, 0, 0, 0, 1, 0, 0, 0, 1)), 1.);
//EXPECT_EQ(m4.det(), 0);
}
TEST(math, Quaternion)
{
hpr::quat q;
hpr::vec3 np = hpr::rotate(hpr::vec3(0, 1, 0), {1, 0, 0}, hpr::pi() * 0.5);
EXPECT_TRUE(hpr::all(hpr::equal(np, hpr::vec3(0, 0, 1))));
EXPECT_EQ(hpr::norm(hpr::quat(np)), 1);
}

View File

@ -1,41 +1,41 @@
#pragma once
#include <gtest/gtest.h>
#include <hpr/numeric.hpp>
#include <complex>
TEST(numeric, Scalar)
{
EXPECT_EQ(hpr::scalar(5) + hpr::scalar(7), hpr::scalar(12));
#ifdef HPR_SCALAR_IMPLEMENTATION
EXPECT_TRUE(std::is_floating_point_v<hpr::Scalar<double>>);
EXPECT_TRUE(std::is_arithmetic_v<hpr::Scalar<double>>);
#endif
//EXPECT_EQ(5.f, hpr::Scalar<double>(5));
EXPECT_EQ(hpr::rad(180), hpr::pi());
EXPECT_EQ(hpr::deg(hpr::pi()), 180);
EXPECT_EQ(hpr::cos(0), 1);
EXPECT_EQ(hpr::sin(0), 0);
EXPECT_EQ(hpr::abs(hpr::scalar(-1)), 1);
EXPECT_EQ(hpr::pow(2, 2), 4);
EXPECT_EQ(hpr::precision(), static_cast<hpr::scalar>(1e-15));
EXPECT_TRUE(typeid(static_cast<float>(hpr::scalar(5))) == typeid(float));
EXPECT_FALSE(!hpr::scalar(-1.));
std::stringstream oss;
oss << hpr::cos(0);
EXPECT_EQ(oss.str(), "1");
hpr::scalar s;
oss >> s;
EXPECT_EQ(s, 1);
EXPECT_TRUE(hpr::equal(5.5453535353535395818593, 5.5453535353535395817592, 1e-18));
EXPECT_EQ(hpr::min(7., 5), 5);
EXPECT_EQ(hpr::max(7., 5), 7);
EXPECT_EQ(hpr::clip(7., 5, 10), 7);
EXPECT_EQ(hpr::clip(1., 5, 10), 5);
EXPECT_EQ(hpr::clip(72., 5, 10), 10);
}
#pragma once
#include <gtest/gtest.h>
#include <hpr/numeric.hpp>
#include <complex>
TEST(numeric, Scalar)
{
EXPECT_EQ(hpr::scalar(5) + hpr::scalar(7), hpr::scalar(12));
#ifdef HPR_SCALAR_IMPLEMENTATION
EXPECT_TRUE(std::is_floating_point_v<hpr::Scalar<double>>);
EXPECT_TRUE(std::is_arithmetic_v<hpr::Scalar<double>>);
#endif
//EXPECT_EQ(5.f, hpr::Scalar<double>(5));
EXPECT_EQ(hpr::rad(180), hpr::pi());
EXPECT_EQ(hpr::deg(hpr::pi()), 180);
EXPECT_EQ(hpr::cos(0), 1);
EXPECT_EQ(hpr::sin(0), 0);
EXPECT_EQ(hpr::abs(hpr::scalar(-1)), 1);
EXPECT_EQ(hpr::pow(2, 2), 4);
EXPECT_EQ(hpr::precision(), static_cast<hpr::scalar>(1e-15));
EXPECT_TRUE(typeid(static_cast<float>(hpr::scalar(5))) == typeid(float));
EXPECT_FALSE(!hpr::scalar(-1.));
std::stringstream oss;
oss << hpr::cos(0);
EXPECT_EQ(oss.str(), "1");
hpr::scalar s;
oss >> s;
EXPECT_EQ(s, 1);
EXPECT_TRUE(hpr::equal(5.5453535353535395818593, 5.5453535353535395817592, 1e-18));
EXPECT_EQ(hpr::min(7., 5), 5);
EXPECT_EQ(hpr::max(7., 5), 7);
EXPECT_EQ(hpr::clip(7., 5, 10), 7);
EXPECT_EQ(hpr::clip(1., 5, 10), 5);
EXPECT_EQ(hpr::clip(72., 5, 10), 10);
}

View File

@ -1,72 +1,72 @@
target("hpr")
set_kind("shared")
set_languages("c++20")
set_policy("build.c++.modules", false)
add_options("scalar", "scalar_implementation")
add_includedirs("..", { public = true })
add_headerfiles("../(hpr/*.hpp)")
add_headerfiles("../(hpr/*/*.hpp)")
add_files("hpr.cpp")
-- export all symbols for windows/dll
if is_plat("windows") and is_kind("shared") then
if is_mode("release") then
set_optimize("fastest")
end
add_rules("utils.symbols.export_all")
end
-- install importfiles for pkg-config/cmake
add_rules("utils.install.cmake_importfiles")
add_rules("utils.install.pkgconfig_importfiles")
-- add packages
for _, name in ipairs({"imgui", "implot", "glfw", "opencascade"}) do
add_packages(name)
if has_package(name) then
set_configvar("HPR_HAVE_PACKAGE_" .. name:upper(), 1)
end
end
target_end()
target("tests")
set_kind("binary")
set_default(false)
set_languages("c++20")
if is_plat("mingw") or is_plat("windows") then
add_ldflags("-static", { force = true} )
end
set_policy("build.c++.modules", false)
add_options("scalar", "scalar_implementation")
add_packages("gtest")
add_includedirs("..", { public = true })
add_files("tests/main.cpp")
on_load(function (target)
for _, file in ipairs(os.files("source/hpr/tests/test_*.cpp")) do
target:add("files", file)
for line in io.lines(file) do
local group, name = string.match(line:gsub("%s+", ""), "TEST%a*%((%a+),(%a+)%)")
if group then
target:add("tests", group .. "/" .. name, { group = group, runargs = "--gtest_filter=" .. group .. "." .. name})
end
end
end
end)
target_end()
target("hpr")
set_kind("shared")
set_languages("c++20")
set_policy("build.c++.modules", false)
add_options("scalar", "scalar_implementation")
add_includedirs("..", { public = true })
add_headerfiles("../(hpr/*.hpp)")
add_headerfiles("../(hpr/*/*.hpp)")
add_files("hpr.cpp")
-- export all symbols for windows/dll
if is_plat("windows") and is_kind("shared") then
if is_mode("release") then
set_optimize("fastest")
end
add_rules("utils.symbols.export_all")
end
-- install importfiles for pkg-config/cmake
add_rules("utils.install.cmake_importfiles")
add_rules("utils.install.pkgconfig_importfiles")
-- add packages
for _, name in ipairs({"imgui", "implot", "glfw", "opencascade"}) do
add_packages(name)
if has_package(name) then
set_configvar("HPR_HAVE_PACKAGE_" .. name:upper(), 1)
end
end
target_end()
target("tests")
set_kind("binary")
set_default(false)
set_languages("c++20")
if is_plat("mingw") or is_plat("windows") then
add_ldflags("-static", { force = true} )
end
set_policy("build.c++.modules", false)
add_options("scalar", "scalar_implementation")
add_packages("gtest")
add_includedirs("..", { public = true })
add_files("tests/main.cpp")
on_load(function (target)
for _, file in ipairs(os.files("source/hpr/tests/test_*.cpp")) do
target:add("files", file)
for line in io.lines(file) do
local group, name = string.match(line:gsub("%s+", ""), "TEST%a*%((%a+),(%a+)%)")
if group then
target:add("tests", group .. "/" .. name, { group = group, runargs = "--gtest_filter=" .. group .. "." .. name})
end
end
end
end)
target_end()

View File

@ -1,65 +1,65 @@
-- options: general
option("creator")
set_category("General")
set_default(false)
set_showmenu(true)
set_description("Build creator application")
option_end()
option("tests")
set_category("General")
set_default(false)
set_showmenu(true)
set_description("Build tests")
option_end()
-- options: modules
for _, name in ipairs({"csg", "mesh"}) do
option(name)
set_category("Modules")
set_default(true)
set_showmenu(true)
set_description(format("Module %s", name))
set_configvar("HPR_HAVE_MODULE_" .. name:upper(), 1)
option_end()
end
-- packages
add_requires("imgui v1.90-docking")
add_requires("implot v0.15")
add_requires("glfw 3.3.8")
if has_config("csg") then
add_requires("conan::opencascade/7.6.2")
end
if has_config("tests") then
add_requires("gtest")
end
--
option("scalar_implementation")
set_category("Internal")
set_default(true)
set_description("Use internal scalar implementation")
add_defines("HPR_SCALAR_IMPLEMENTATION")
option_end()
option("scalar")
set_category("Internal")
set_values("float", "double", "long double")
set_default("float")
set_description("Internal scalar value type")
after_check(function(option)
option:add("defines", format("HPR_SCALAR=%s", option:value()))
end)
option_end()
-- includes project dirs
includes("hpr")
if has_config("creator") then
includes("creator")
-- options: general
option("creator")
set_category("General")
set_default(false)
set_showmenu(true)
set_description("Build creator application")
option_end()
option("tests")
set_category("General")
set_default(false)
set_showmenu(true)
set_description("Build tests")
option_end()
-- options: modules
for _, name in ipairs({"csg", "mesh"}) do
option(name)
set_category("Modules")
set_default(true)
set_showmenu(true)
set_description(format("Module %s", name))
set_configvar("HPR_HAVE_MODULE_" .. name:upper(), 1)
option_end()
end
-- packages
add_requires("imgui v1.90-docking")
add_requires("implot v0.15")
add_requires("glfw 3.3.8")
if has_config("csg") then
add_requires("pacman::opencascade 7.7.2", {alias = "opencascade"})
end
if has_config("tests") then
add_requires("gtest")
end
--
option("scalar_implementation")
set_category("Internal")
set_default(true)
set_description("Use internal scalar implementation")
add_defines("HPR_SCALAR_IMPLEMENTATION")
option_end()
option("scalar")
set_category("Internal")
set_values("float", "double", "long double")
set_default("float")
set_description("Internal scalar value type")
after_check(function(option)
option:add("defines", format("HPR_SCALAR=%s", option:value()))
end)
option_end()
-- includes project dirs
includes("hpr")
if has_config("creator") then
includes("creator")
end

View File

@ -1,17 +1,17 @@
set_project("hpr")
set_version("0.0.1")
add_rules("mode.debug", "mode.release")
if is_mode("debug") then
add_defines("HPR_DEBUG")
end
if is_plat("linux") and is_mode("debug") then
add_ldflags("-rdynamic")
end
set_optimize("fastest")
set_project("hpr")
set_version("0.0.1")
add_rules("mode.debug", "mode.release")
if is_mode("debug") then
add_defines("HPR_DEBUG")
end
if is_plat("linux") and is_mode("debug") then
add_ldflags("-rdynamic")
end
set_optimize("fastest")
includes("source")