mirror of
https://github.com/slendidev/smath.git
synced 2026-03-17 02:26:50 +02:00
Compare commits
17 Commits
v1.0.0
...
e063b10af5
| Author | SHA1 | Date | |
|---|---|---|---|
| e063b10af5 | |||
| cf490494c3 | |||
| 2719e1d746 | |||
| d113c492c9 | |||
| 24c3769e22 | |||
| 6471d48d35 | |||
| 79dc2d43e6 | |||
| cc08dd190c | |||
| 87a12de2bf | |||
| 6079705bb6 | |||
| 48eff7d784 | |||
| 224b924772 | |||
| 2a161e36ab | |||
| 6f9e8814b1 | |||
| 4f71b3ac90 | |||
| 01538457a5 | |||
| c4109f0ce3 |
51
.clang-format
Normal file
51
.clang-format
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
---
|
||||||
|
Language: Cpp
|
||||||
|
BasedOnStyle: LLVM
|
||||||
|
|
||||||
|
IndentWidth: 4
|
||||||
|
TabWidth: 4
|
||||||
|
UseTab: ForIndentation
|
||||||
|
|
||||||
|
ColumnLimit: 80
|
||||||
|
AlignAfterOpenBracket: DontAlign
|
||||||
|
AlignOperands: false
|
||||||
|
BreakBeforeBinaryOperators: All
|
||||||
|
ContinuationIndentWidth: 4
|
||||||
|
BreakBeforeBraces: Custom
|
||||||
|
BraceWrapping:
|
||||||
|
AfterCaseLabel: false
|
||||||
|
AfterClass: true
|
||||||
|
AfterControlStatement: Never
|
||||||
|
AfterEnum: true
|
||||||
|
AfterFunction: true
|
||||||
|
AfterNamespace: true
|
||||||
|
AfterStruct: true
|
||||||
|
AfterUnion: true
|
||||||
|
BeforeCatch: false
|
||||||
|
BeforeElse: false
|
||||||
|
SplitEmptyFunction: false
|
||||||
|
SplitEmptyRecord: false
|
||||||
|
SplitEmptyNamespace: false
|
||||||
|
AllowShortIfStatementsOnASingleLine: false
|
||||||
|
AllowShortLoopsOnASingleLine: false
|
||||||
|
AllowShortFunctionsOnASingleLine: Inline
|
||||||
|
AllowShortBlocksOnASingleLine: Empty
|
||||||
|
SpaceInEmptyBlock: true
|
||||||
|
BinPackArguments: false
|
||||||
|
BinPackParameters: false
|
||||||
|
Cpp11BracedListStyle: false
|
||||||
|
SpaceBeforeCpp11BracedList: true
|
||||||
|
IndentRequiresClause: false
|
||||||
|
RequiresClausePosition: OwnLine
|
||||||
|
|
||||||
|
PointerAlignment: Right
|
||||||
|
ReferenceAlignment: Right
|
||||||
|
IndentAccessModifiers: false
|
||||||
|
AccessModifierOffset: -4
|
||||||
|
|
||||||
|
SortIncludes: CaseSensitive
|
||||||
|
SpaceAfterTemplateKeyword: false
|
||||||
|
AlignEscapedNewlines: DontAlign
|
||||||
|
AlignConsecutiveAssignments: false
|
||||||
|
AlignConsecutiveDeclarations: false
|
||||||
|
...
|
||||||
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@@ -21,7 +21,7 @@ jobs:
|
|||||||
- name: Install Nix
|
- name: Install Nix
|
||||||
uses: DeterminateSystems/nix-installer-action@main
|
uses: DeterminateSystems/nix-installer-action@main
|
||||||
- name: Building default package
|
- name: Building default package
|
||||||
run: nix build .#default
|
run: nix build .#default --print-build-logs
|
||||||
- name: Upload artifact
|
- name: Upload artifact
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
|
|||||||
50
.github/workflows/docs.yml
vendored
Normal file
50
.github/workflows/docs.yml
vendored
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
name: Deploy Doxygen docs
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [master]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pages: write
|
||||||
|
id-token: write
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: "pages"
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Install Doxygen
|
||||||
|
run: sudo apt-get update && sudo apt-get install -y doxygen graphviz perl
|
||||||
|
|
||||||
|
- name: Create output directory
|
||||||
|
run: mkdir -p build/docs
|
||||||
|
|
||||||
|
- name: Generate docs
|
||||||
|
run: ./docs/build_docs.sh
|
||||||
|
|
||||||
|
- name: Disable Jekyll
|
||||||
|
run: touch build/docs/html/.nojekyll
|
||||||
|
|
||||||
|
- name: Upload Pages artifact
|
||||||
|
uses: actions/upload-pages-artifact@v3
|
||||||
|
with:
|
||||||
|
path: build/docs/html
|
||||||
|
|
||||||
|
deploy:
|
||||||
|
environment:
|
||||||
|
name: github-pages
|
||||||
|
url: ${{ steps.deployment.outputs.page_url }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: build
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Deploy to GitHub Pages
|
||||||
|
id: deployment
|
||||||
|
uses: actions/deploy-pages@v4
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,4 +1,5 @@
|
|||||||
[Bb]uild*
|
[Bb]uild*
|
||||||
|
![Bb]uild*.*
|
||||||
.cache
|
.cache
|
||||||
result
|
result
|
||||||
.direnv
|
.direnv
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
cmake_minimum_required(VERSION 3.15)
|
cmake_minimum_required(VERSION 3.15)
|
||||||
project(SmathExamples LANGUAGES CXX VERSION 0.1.0)
|
project(SmathExamples LANGUAGES CXX VERSION 1.0.0)
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 23)
|
set(CMAKE_CXX_STANDARD 23)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
@@ -7,6 +7,8 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
|||||||
option(SMATH_BUILD_EXAMPLES "Build example programs" ON)
|
option(SMATH_BUILD_EXAMPLES "Build example programs" ON)
|
||||||
option(SMATH_BUILD_TESTS "Build unit tests" ON)
|
option(SMATH_BUILD_TESTS "Build unit tests" ON)
|
||||||
option(SMATH_BUILD_MODULES "Enable C++20 modules support" OFF)
|
option(SMATH_BUILD_MODULES "Enable C++20 modules support" OFF)
|
||||||
|
option(SMATH_ENABLE_LEGACY_HEADER "Install legacy include <smath.hpp> shim" OFF)
|
||||||
|
option(SMATH_INSTALL_INTEROP_HEADERS "Install interop headers" OFF)
|
||||||
|
|
||||||
if(SMATH_BUILD_MODULES)
|
if(SMATH_BUILD_MODULES)
|
||||||
message(STATUS "Building smath C++ module")
|
message(STATUS "Building smath C++ module")
|
||||||
@@ -17,6 +19,7 @@ add_library(smath INTERFACE)
|
|||||||
target_include_directories(smath
|
target_include_directories(smath
|
||||||
INTERFACE
|
INTERFACE
|
||||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
||||||
|
$<$<BOOL:${SMATH_ENABLE_LEGACY_HEADER}>:$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>>
|
||||||
$<INSTALL_INTERFACE:include>
|
$<INSTALL_INTERFACE:include>
|
||||||
)
|
)
|
||||||
add_library(smath::smath ALIAS smath)
|
add_library(smath::smath ALIAS smath)
|
||||||
@@ -25,7 +28,21 @@ include(CMakePackageConfigHelpers)
|
|||||||
install(TARGETS smath
|
install(TARGETS smath
|
||||||
EXPORT smathTargets
|
EXPORT smathTargets
|
||||||
)
|
)
|
||||||
install(DIRECTORY include/ DESTINATION include)
|
install(FILES include/smath/smath.hpp DESTINATION include/smath)
|
||||||
|
|
||||||
|
if(SMATH_INSTALL_INTEROP_HEADERS)
|
||||||
|
install(DIRECTORY include/smath/interop DESTINATION include/smath)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(SMATH_ENABLE_LEGACY_HEADER)
|
||||||
|
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/include")
|
||||||
|
configure_file(
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/smath_legacy_header.hpp.in"
|
||||||
|
"${CMAKE_CURRENT_BINARY_DIR}/include/smath.hpp"
|
||||||
|
@ONLY
|
||||||
|
)
|
||||||
|
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/include/smath.hpp" DESTINATION include)
|
||||||
|
endif()
|
||||||
|
|
||||||
install(EXPORT smathTargets
|
install(EXPORT smathTargets
|
||||||
NAMESPACE smath::
|
NAMESPACE smath::
|
||||||
@@ -96,4 +113,3 @@ if(SMATH_BUILD_TESTS)
|
|||||||
include(GoogleTest)
|
include(GoogleTest)
|
||||||
gtest_discover_tests(smath_tests)
|
gtest_discover_tests(smath_tests)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|||||||
42
README.md
42
README.md
@@ -1,6 +1,6 @@
|
|||||||
<p align="center">
|
<p align="center">
|
||||||
<img alt="smath logo" src="https://github.com/user-attachments/assets/d6f2ef4b-eca0-4004-9099-37423528bcba" />
|
<img alt="smath logo" width="100%" src="https://paste.slendi.dev/LcCPsJ.svg" />
|
||||||
<br><br>
|
<br><br>
|
||||||
<a href="https://github.com/slendidev/smath/actions/workflows/build.yml">
|
<a href="https://github.com/slendidev/smath/actions/workflows/build.yml">
|
||||||
<img src="https://github.com/slendidev/smath/actions/workflows/build.yml/badge.svg" alt="Build">
|
<img src="https://github.com/slendidev/smath/actions/workflows/build.yml/badge.svg" alt="Build">
|
||||||
</a>
|
</a>
|
||||||
@@ -12,13 +12,26 @@
|
|||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- Generic `Vec<N, T>` class with useful aliases `Vec2/Vec3/Vec4` and friendly accessors (`x/y/z/w`, `r/g/b/a`). They support approx-equal and tuple/structured bindings.
|
||||||
|
- `std::format` support.
|
||||||
|
- Compile-time swizzles via `swizzle<"...">`.
|
||||||
|
- Generic matrix `Mat` class with useful aliases `Mat2/Mat3/Mat4`.
|
||||||
|
- `Quaternion<T>` built on `Vec4`.
|
||||||
|
- Angle helpers `rad/deg/turns` respecting a configurable base unit via the macro `SMATH_ANGLE_UNIT`.
|
||||||
|
- Optional implicit conversions.
|
||||||
|
- Packing utilities for normalized RGBA (`pack_unorm4x8`, `unpack_snorm4x8`, etc.).
|
||||||
|
- C++20 modules support.
|
||||||
|
- Built-in interop adapter and optional interop headers for various libraries.
|
||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
||||||
Create `main.cpp`:
|
Create `main.cpp`:
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
#include <print>
|
#include <print>
|
||||||
#include <smath.hpp>
|
#include <smath/smath.hpp>
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
using namespace smath;
|
using namespace smath;
|
||||||
@@ -39,17 +52,20 @@ g++ -std=c++23 -Iinclude main.cpp -o quickstart
|
|||||||
./quickstart
|
./quickstart
|
||||||
```
|
```
|
||||||
|
|
||||||
## Features
|
## Interop Headers
|
||||||
|
|
||||||
- Generic `Vec<N, T>` class with useful aliases `Vec2/Vec3/Vec4` and friendly accessors (`x/y/z/w`, `r/g/b/a`). They support approx-equal and tuple/structured bindings.
|
smath ships optional interop adapters under `include/smath/interop/`.
|
||||||
- `std::format` support.
|
|
||||||
- Compile-time swizzles via `swizzle<"...">`.
|
When installing with CMake, interop headers are gated behind:
|
||||||
- Generic matrix `Mat` class with useful aliases `Mat2/Mat3/Mat4`.
|
|
||||||
- `Quaternion<T>` built on `Vec4`.
|
- `-DSMATH_INSTALL_INTEROP_HEADERS=ON`
|
||||||
- Angle helpers `rad/deg/turns` respecting a configurable base unit via the macro `SMATH_ANGLE_UNIT`.
|
|
||||||
- Optional implicit conversions.
|
All of them plug into the same generic API defined in `smath.hpp`:
|
||||||
- Packing utilities for normalized RGBA (`pack_unorm4x8`, `unpack_snorm4x8`, etc.).
|
|
||||||
- C++20 modules support.
|
```cpp
|
||||||
|
auto v = smath::from_external(external_value);
|
||||||
|
auto ext = smath::to_external<ExternalType>(smath_value);
|
||||||
|
```
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|||||||
3
cmake/smath_legacy_header.hpp.in
Normal file
3
cmake/smath_legacy_header.hpp.in
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <smath/smath.hpp>
|
||||||
30
docs/Doxyfile
Normal file
30
docs/Doxyfile
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
PROJECT_NAME = "smath"
|
||||||
|
OUTPUT_DIRECTORY = build/docs
|
||||||
|
CREATE_SUBDIRS = NO
|
||||||
|
|
||||||
|
INPUT = include README.md
|
||||||
|
USE_MDFILE_AS_MAINPAGE = README.md
|
||||||
|
TOC_INCLUDE_HEADINGS = 0
|
||||||
|
RECURSIVE = YES
|
||||||
|
FILE_PATTERNS = *.hpp *.h *.md
|
||||||
|
EXCLUDE = include/smath/interop
|
||||||
|
|
||||||
|
EXTRACT_ALL = YES
|
||||||
|
EXTRACT_PRIVATE = NO
|
||||||
|
EXTRACT_STATIC = NO
|
||||||
|
|
||||||
|
GENERATE_HTML = YES
|
||||||
|
GENERATE_LATEX = NO
|
||||||
|
GENERATE_MAN = YES
|
||||||
|
GENERATE_TREEVIEW = YES
|
||||||
|
DISABLE_INDEX = NO
|
||||||
|
FULL_SIDEBAR = NO
|
||||||
|
HTML_COLORSTYLE = LIGHT
|
||||||
|
PROJECT_LOGO = docs/smath_light.svg
|
||||||
|
HTML_EXTRA_STYLESHEET = docs/vendor/doxygen-awesome.css docs/custom.css
|
||||||
|
HTML_EXTRA_FILES = docs/smath_dark.svg docs/smath_big.svg
|
||||||
|
LAYOUT_FILE = docs/DoxygenLayout.xml
|
||||||
|
|
||||||
|
WARN_IF_UNDOCUMENTED = YES
|
||||||
|
QUIET = NO
|
||||||
|
EXCLUDE_SYMBOLS = std smath::detail smath::interop_adapter interop_adapter smath::from_external from_external smath::to_external to_external
|
||||||
270
docs/DoxygenLayout.xml
Normal file
270
docs/DoxygenLayout.xml
Normal file
@@ -0,0 +1,270 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<doxygenlayout version="2.0">
|
||||||
|
<!-- Generated by doxygen 1.14.0 -->
|
||||||
|
<!-- Navigation index tabs for HTML output -->
|
||||||
|
<navindex>
|
||||||
|
<tab type="mainpage" visible="yes" title=""/>
|
||||||
|
<tab type="pages" visible="yes" title="" intro=""/>
|
||||||
|
<tab type="topics" visible="yes" title="" intro=""/>
|
||||||
|
<tab type="modules" visible="yes" title="" intro="">
|
||||||
|
<tab type="modulelist" visible="yes" title="" intro=""/>
|
||||||
|
<tab type="modulemembers" visible="yes" title="" intro=""/>
|
||||||
|
</tab>
|
||||||
|
<tab type="namespaces" visible="yes" title="">
|
||||||
|
<tab type="namespacelist" visible="yes" title="" intro=""/>
|
||||||
|
<tab type="namespacemembers" visible="yes" title="" intro=""/>
|
||||||
|
</tab>
|
||||||
|
<tab type="concepts" visible="yes" title="">
|
||||||
|
</tab>
|
||||||
|
<tab type="interfaces" visible="yes" title="">
|
||||||
|
<tab type="interfacelist" visible="yes" title="" intro=""/>
|
||||||
|
<tab type="interfaceindex" visible="$ALPHABETICAL_INDEX" title=""/>
|
||||||
|
<tab type="interfacehierarchy" visible="yes" title="" intro=""/>
|
||||||
|
</tab>
|
||||||
|
<tab type="classes" visible="yes" title="">
|
||||||
|
<tab type="classlist" visible="yes" title="" intro=""/>
|
||||||
|
<tab type="classindex" visible="$ALPHABETICAL_INDEX" title=""/>
|
||||||
|
<tab type="hierarchy" visible="yes" title="" intro=""/>
|
||||||
|
<tab type="classmembers" visible="yes" title="" intro=""/>
|
||||||
|
</tab>
|
||||||
|
<tab type="structs" visible="yes" title="">
|
||||||
|
<tab type="structlist" visible="yes" title="" intro=""/>
|
||||||
|
<tab type="structindex" visible="$ALPHABETICAL_INDEX" title=""/>
|
||||||
|
</tab>
|
||||||
|
<tab type="exceptions" visible="yes" title="">
|
||||||
|
<tab type="exceptionlist" visible="yes" title="" intro=""/>
|
||||||
|
<tab type="exceptionindex" visible="$ALPHABETICAL_INDEX" title=""/>
|
||||||
|
<tab type="exceptionhierarchy" visible="yes" title="" intro=""/>
|
||||||
|
</tab>
|
||||||
|
<tab type="files" visible="yes" title="">
|
||||||
|
<tab type="filelist" visible="yes" title="" intro=""/>
|
||||||
|
<tab type="globals" visible="yes" title="" intro=""/>
|
||||||
|
</tab>
|
||||||
|
<tab type="user" url="https://github.com/slendidev/smath" title="GitHub"/>
|
||||||
|
<tab type="examples" visible="yes" title="" intro=""/>
|
||||||
|
</navindex>
|
||||||
|
|
||||||
|
<!-- Layout definition for a class page -->
|
||||||
|
<class>
|
||||||
|
<briefdescription visible="yes"/>
|
||||||
|
<includes visible="$SHOW_HEADERFILE"/>
|
||||||
|
<inheritancegraph visible="yes"/>
|
||||||
|
<collaborationgraph visible="yes"/>
|
||||||
|
<memberdecl>
|
||||||
|
<nestedclasses visible="yes" title=""/>
|
||||||
|
<publictypes visible="yes" title=""/>
|
||||||
|
<services visible="yes" title=""/>
|
||||||
|
<interfaces visible="yes" title=""/>
|
||||||
|
<publicslots visible="yes" title=""/>
|
||||||
|
<signals visible="yes" title=""/>
|
||||||
|
<publicmethods visible="yes" title=""/>
|
||||||
|
<publicstaticmethods visible="yes" title=""/>
|
||||||
|
<publicattributes visible="yes" title=""/>
|
||||||
|
<publicstaticattributes visible="yes" title=""/>
|
||||||
|
<protectedtypes visible="yes" title=""/>
|
||||||
|
<protectedslots visible="yes" title=""/>
|
||||||
|
<protectedmethods visible="yes" title=""/>
|
||||||
|
<protectedstaticmethods visible="yes" title=""/>
|
||||||
|
<protectedattributes visible="yes" title=""/>
|
||||||
|
<protectedstaticattributes visible="yes" title=""/>
|
||||||
|
<packagetypes visible="yes" title=""/>
|
||||||
|
<packagemethods visible="yes" title=""/>
|
||||||
|
<packagestaticmethods visible="yes" title=""/>
|
||||||
|
<packageattributes visible="yes" title=""/>
|
||||||
|
<packagestaticattributes visible="yes" title=""/>
|
||||||
|
<properties visible="yes" title=""/>
|
||||||
|
<events visible="yes" title=""/>
|
||||||
|
<privatetypes visible="yes" title=""/>
|
||||||
|
<privateslots visible="yes" title=""/>
|
||||||
|
<privatemethods visible="yes" title=""/>
|
||||||
|
<privatestaticmethods visible="yes" title=""/>
|
||||||
|
<privateattributes visible="yes" title=""/>
|
||||||
|
<privatestaticattributes visible="yes" title=""/>
|
||||||
|
<friends visible="yes" title=""/>
|
||||||
|
<related visible="yes" title="" subtitle=""/>
|
||||||
|
<membergroups visible="yes"/>
|
||||||
|
</memberdecl>
|
||||||
|
<detaileddescription visible="yes" title=""/>
|
||||||
|
<memberdef>
|
||||||
|
<inlineclasses visible="yes" title=""/>
|
||||||
|
<typedefs visible="yes" title=""/>
|
||||||
|
<enums visible="yes" title=""/>
|
||||||
|
<services visible="yes" title=""/>
|
||||||
|
<interfaces visible="yes" title=""/>
|
||||||
|
<constructors visible="yes" title=""/>
|
||||||
|
<functions visible="yes" title=""/>
|
||||||
|
<related visible="yes" title=""/>
|
||||||
|
<variables visible="yes" title=""/>
|
||||||
|
<properties visible="yes" title=""/>
|
||||||
|
<events visible="yes" title=""/>
|
||||||
|
</memberdef>
|
||||||
|
<allmemberslink visible="yes"/>
|
||||||
|
<usedfiles visible="$SHOW_USED_FILES"/>
|
||||||
|
<authorsection visible="yes"/>
|
||||||
|
</class>
|
||||||
|
|
||||||
|
<!-- Layout definition for a namespace page -->
|
||||||
|
<namespace>
|
||||||
|
<briefdescription visible="yes"/>
|
||||||
|
<memberdecl>
|
||||||
|
<nestednamespaces visible="yes" title=""/>
|
||||||
|
<constantgroups visible="yes" title=""/>
|
||||||
|
<interfaces visible="yes" title=""/>
|
||||||
|
<classes visible="yes" title=""/>
|
||||||
|
<concepts visible="yes" title=""/>
|
||||||
|
<structs visible="yes" title=""/>
|
||||||
|
<exceptions visible="yes" title=""/>
|
||||||
|
<typedefs visible="yes" title=""/>
|
||||||
|
<sequences visible="yes" title=""/>
|
||||||
|
<dictionaries visible="yes" title=""/>
|
||||||
|
<enums visible="yes" title=""/>
|
||||||
|
<functions visible="yes" title=""/>
|
||||||
|
<variables visible="yes" title=""/>
|
||||||
|
<properties visible="yes" title=""/>
|
||||||
|
<membergroups visible="yes"/>
|
||||||
|
</memberdecl>
|
||||||
|
<detaileddescription visible="yes" title=""/>
|
||||||
|
<memberdef>
|
||||||
|
<inlineclasses visible="yes" title=""/>
|
||||||
|
<typedefs visible="yes" title=""/>
|
||||||
|
<sequences visible="yes" title=""/>
|
||||||
|
<dictionaries visible="yes" title=""/>
|
||||||
|
<enums visible="yes" title=""/>
|
||||||
|
<functions visible="yes" title=""/>
|
||||||
|
<variables visible="yes" title=""/>
|
||||||
|
<properties visible="yes" title=""/>
|
||||||
|
</memberdef>
|
||||||
|
<authorsection visible="yes"/>
|
||||||
|
</namespace>
|
||||||
|
|
||||||
|
<!-- Layout definition for a concept page -->
|
||||||
|
<concept>
|
||||||
|
<briefdescription visible="yes"/>
|
||||||
|
<includes visible="$SHOW_HEADERFILE"/>
|
||||||
|
<definition visible="yes" title=""/>
|
||||||
|
<detaileddescription visible="yes" title=""/>
|
||||||
|
<authorsection visible="yes"/>
|
||||||
|
</concept>
|
||||||
|
|
||||||
|
<!-- Layout definition for a file page -->
|
||||||
|
<file>
|
||||||
|
<briefdescription visible="yes"/>
|
||||||
|
<includes visible="$SHOW_INCLUDE_FILES"/>
|
||||||
|
<includegraph visible="yes"/>
|
||||||
|
<includedbygraph visible="yes"/>
|
||||||
|
<sourcelink visible="yes"/>
|
||||||
|
<memberdecl>
|
||||||
|
<interfaces visible="yes" title=""/>
|
||||||
|
<classes visible="yes" title=""/>
|
||||||
|
<structs visible="yes" title=""/>
|
||||||
|
<exceptions visible="yes" title=""/>
|
||||||
|
<namespaces visible="yes" title=""/>
|
||||||
|
<concepts visible="yes" title=""/>
|
||||||
|
<constantgroups visible="yes" title=""/>
|
||||||
|
<defines visible="yes" title=""/>
|
||||||
|
<typedefs visible="yes" title=""/>
|
||||||
|
<sequences visible="yes" title=""/>
|
||||||
|
<dictionaries visible="yes" title=""/>
|
||||||
|
<enums visible="yes" title=""/>
|
||||||
|
<functions visible="yes" title=""/>
|
||||||
|
<variables visible="yes" title=""/>
|
||||||
|
<properties visible="yes" title=""/>
|
||||||
|
<membergroups visible="yes"/>
|
||||||
|
</memberdecl>
|
||||||
|
<detaileddescription visible="yes" title=""/>
|
||||||
|
<memberdef>
|
||||||
|
<inlineclasses visible="yes" title=""/>
|
||||||
|
<defines visible="yes" title=""/>
|
||||||
|
<typedefs visible="yes" title=""/>
|
||||||
|
<sequences visible="yes" title=""/>
|
||||||
|
<dictionaries visible="yes" title=""/>
|
||||||
|
<enums visible="yes" title=""/>
|
||||||
|
<functions visible="yes" title=""/>
|
||||||
|
<variables visible="yes" title=""/>
|
||||||
|
<properties visible="yes" title=""/>
|
||||||
|
</memberdef>
|
||||||
|
<authorsection/>
|
||||||
|
</file>
|
||||||
|
|
||||||
|
<!-- Layout definition for a group page -->
|
||||||
|
<group>
|
||||||
|
<briefdescription visible="yes"/>
|
||||||
|
<groupgraph visible="yes"/>
|
||||||
|
<memberdecl>
|
||||||
|
<nestedgroups visible="yes" title=""/>
|
||||||
|
<modules visible="yes" title=""/>
|
||||||
|
<dirs visible="yes" title=""/>
|
||||||
|
<files visible="yes" title=""/>
|
||||||
|
<namespaces visible="yes" title=""/>
|
||||||
|
<concepts visible="yes" title=""/>
|
||||||
|
<classes visible="yes" title=""/>
|
||||||
|
<defines visible="yes" title=""/>
|
||||||
|
<typedefs visible="yes" title=""/>
|
||||||
|
<sequences visible="yes" title=""/>
|
||||||
|
<dictionaries visible="yes" title=""/>
|
||||||
|
<enums visible="yes" title=""/>
|
||||||
|
<enumvalues visible="yes" title=""/>
|
||||||
|
<functions visible="yes" title=""/>
|
||||||
|
<variables visible="yes" title=""/>
|
||||||
|
<signals visible="yes" title=""/>
|
||||||
|
<publicslots visible="yes" title=""/>
|
||||||
|
<protectedslots visible="yes" title=""/>
|
||||||
|
<privateslots visible="yes" title=""/>
|
||||||
|
<events visible="yes" title=""/>
|
||||||
|
<properties visible="yes" title=""/>
|
||||||
|
<friends visible="yes" title=""/>
|
||||||
|
<membergroups visible="yes"/>
|
||||||
|
</memberdecl>
|
||||||
|
<detaileddescription visible="yes" title=""/>
|
||||||
|
<memberdef>
|
||||||
|
<pagedocs/>
|
||||||
|
<inlineclasses visible="yes" title=""/>
|
||||||
|
<defines visible="yes" title=""/>
|
||||||
|
<typedefs visible="yes" title=""/>
|
||||||
|
<sequences visible="yes" title=""/>
|
||||||
|
<dictionaries visible="yes" title=""/>
|
||||||
|
<enums visible="yes" title=""/>
|
||||||
|
<enumvalues visible="yes" title=""/>
|
||||||
|
<functions visible="yes" title=""/>
|
||||||
|
<variables visible="yes" title=""/>
|
||||||
|
<signals visible="yes" title=""/>
|
||||||
|
<publicslots visible="yes" title=""/>
|
||||||
|
<protectedslots visible="yes" title=""/>
|
||||||
|
<privateslots visible="yes" title=""/>
|
||||||
|
<events visible="yes" title=""/>
|
||||||
|
<properties visible="yes" title=""/>
|
||||||
|
<friends visible="yes" title=""/>
|
||||||
|
</memberdef>
|
||||||
|
<authorsection visible="yes"/>
|
||||||
|
</group>
|
||||||
|
|
||||||
|
<!-- Layout definition for a C++20 module page -->
|
||||||
|
<module>
|
||||||
|
<briefdescription visible="yes"/>
|
||||||
|
<exportedmodules visible="yes"/>
|
||||||
|
<memberdecl>
|
||||||
|
<concepts visible="yes" title=""/>
|
||||||
|
<classes visible="yes" title=""/>
|
||||||
|
<enums visible="yes" title=""/>
|
||||||
|
<typedefs visible="yes" title=""/>
|
||||||
|
<functions visible="yes" title=""/>
|
||||||
|
<variables visible="yes" title=""/>
|
||||||
|
<membergroups visible="yes" title=""/>
|
||||||
|
</memberdecl>
|
||||||
|
<detaileddescription visible="yes" title=""/>
|
||||||
|
<memberdecl>
|
||||||
|
<files visible="yes"/>
|
||||||
|
</memberdecl>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<!-- Layout definition for a directory page -->
|
||||||
|
<directory>
|
||||||
|
<briefdescription visible="yes"/>
|
||||||
|
<directorygraph visible="yes"/>
|
||||||
|
<memberdecl>
|
||||||
|
<dirs visible="yes"/>
|
||||||
|
<files visible="yes"/>
|
||||||
|
</memberdecl>
|
||||||
|
<detaileddescription visible="yes" title=""/>
|
||||||
|
</directory>
|
||||||
|
</doxygenlayout>
|
||||||
10
docs/build_docs.sh
Executable file
10
docs/build_docs.sh
Executable file
@@ -0,0 +1,10 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
|
||||||
|
doxygen "${repo_root}/docs/Doxyfile"
|
||||||
|
"${repo_root}/docs/postprocess-doxygen.sh" "${repo_root}/build/docs/html"
|
||||||
|
|
||||||
|
echo "Docs generated at ${repo_root}/build/docs/html"
|
||||||
17
docs/custom.css
Normal file
17
docs/custom.css
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
#titlearea {
|
||||||
|
padding-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#projectlogo img {
|
||||||
|
height: 40px;
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#projectname,
|
||||||
|
#projectbrief {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
html.dark-mode #projectlogo img {
|
||||||
|
content: url('smath_dark.svg');
|
||||||
|
}
|
||||||
13
docs/postprocess-doxygen.sh
Executable file
13
docs/postprocess-doxygen.sh
Executable file
@@ -0,0 +1,13 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
html_dir="${1:-build/docs/html}"
|
||||||
|
index_file="${html_dir%/}/index.html"
|
||||||
|
|
||||||
|
if [[ ! -f "${index_file}" ]]; then
|
||||||
|
echo "error: ${index_file} not found" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
perl -0pi -e 's{<div><div class="header">\s*<div class="headertitle"><div class="title">.*?</div></div>\s*</div><!--header-->\s*}{}s' "${index_file}"
|
||||||
190
docs/smath_big.svg
Normal file
190
docs/smath_big.svg
Normal file
@@ -0,0 +1,190 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
width="1280"
|
||||||
|
height="640"
|
||||||
|
viewBox="0 0 1280.0001 640.00006"
|
||||||
|
version="1.1"
|
||||||
|
id="svg1"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<defs
|
||||||
|
id="defs1">
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient13">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#25ff0c;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop12" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#16d800;stop-opacity:1;"
|
||||||
|
offset="1"
|
||||||
|
id="stop13" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient10">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#25ff0c;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop10" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#25ff0c;stop-opacity:1;"
|
||||||
|
offset="1"
|
||||||
|
id="stop11" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient8">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#c50000;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop8" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#ff0c0c;stop-opacity:1;"
|
||||||
|
offset="1"
|
||||||
|
id="stop9" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient5">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#000000;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop5" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#969696;stop-opacity:1;"
|
||||||
|
offset="1"
|
||||||
|
id="stop6" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
xlink:href="#linearGradient5"
|
||||||
|
id="linearGradient6-2"
|
||||||
|
x1="482.5849"
|
||||||
|
y1="589.83472"
|
||||||
|
x2="613.15253"
|
||||||
|
y2="-24.437733"
|
||||||
|
gradientUnits="userSpaceOnUse" />
|
||||||
|
<rect
|
||||||
|
x="227.90907"
|
||||||
|
y="175.81558"
|
||||||
|
width="659.85107"
|
||||||
|
height="227.90907"
|
||||||
|
id="rect1-5" />
|
||||||
|
<linearGradient
|
||||||
|
xlink:href="#linearGradient10"
|
||||||
|
id="linearGradient11-0"
|
||||||
|
x1="50.894115"
|
||||||
|
y1="80.727814"
|
||||||
|
x2="50.894115"
|
||||||
|
y2="68.866821"
|
||||||
|
gradientUnits="userSpaceOnUse" />
|
||||||
|
<marker
|
||||||
|
style="overflow:visible"
|
||||||
|
id="RoundedArrow-45"
|
||||||
|
refX="0"
|
||||||
|
refY="0"
|
||||||
|
orient="auto-start-reverse"
|
||||||
|
markerWidth="1"
|
||||||
|
markerHeight="1"
|
||||||
|
viewBox="0 0 1 1"
|
||||||
|
preserveAspectRatio="xMidYMid">
|
||||||
|
<path
|
||||||
|
transform="scale(0.7)"
|
||||||
|
d="m -0.21114562,-4.1055728 6.42229122,3.21114561 a 1,1 90 0 1 0,1.78885438 L -0.21114562,4.1055728 A 1.236068,1.236068 31.717474 0 1 -2,3 v -6 a 1.236068,1.236068 148.28253 0 1 1.78885438,-1.1055728 z"
|
||||||
|
style="fill:context-stroke;fill-rule:evenodd;stroke:none"
|
||||||
|
id="path8-2" />
|
||||||
|
</marker>
|
||||||
|
<linearGradient
|
||||||
|
xlink:href="#linearGradient8"
|
||||||
|
id="linearGradient9-6"
|
||||||
|
x1="107.55984"
|
||||||
|
y1="103.63171"
|
||||||
|
x2="51.891579"
|
||||||
|
y2="103.63171"
|
||||||
|
gradientUnits="userSpaceOnUse" />
|
||||||
|
<marker
|
||||||
|
style="overflow:visible"
|
||||||
|
id="RoundedArrow-4-1"
|
||||||
|
refX="0"
|
||||||
|
refY="0"
|
||||||
|
orient="auto-start-reverse"
|
||||||
|
markerWidth="1"
|
||||||
|
markerHeight="1"
|
||||||
|
viewBox="0 0 1 1"
|
||||||
|
preserveAspectRatio="xMidYMid">
|
||||||
|
<path
|
||||||
|
transform="scale(0.7)"
|
||||||
|
d="m -0.21114562,-4.1055728 6.42229122,3.21114561 a 1,1 90 0 1 0,1.78885438 L -0.21114562,4.1055728 A 1.236068,1.236068 31.717474 0 1 -2,3 v -6 a 1.236068,1.236068 148.28253 0 1 1.78885438,-1.1055728 z"
|
||||||
|
style="fill:context-stroke;fill-rule:evenodd;stroke:none"
|
||||||
|
id="path8-3-1" />
|
||||||
|
</marker>
|
||||||
|
<linearGradient
|
||||||
|
xlink:href="#linearGradient13"
|
||||||
|
id="linearGradient16"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(1,0,0,0.93927134,0,6.2326702)"
|
||||||
|
x1="50.894115"
|
||||||
|
y1="80.727814"
|
||||||
|
x2="50.894115"
|
||||||
|
y2="68.866821" />
|
||||||
|
</defs>
|
||||||
|
<rect
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
id="rect16"
|
||||||
|
width="1280.0001"
|
||||||
|
height="640"
|
||||||
|
x="1.1474608e-06"
|
||||||
|
y="2.8421709e-14" />
|
||||||
|
<g
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(-419.99999)">
|
||||||
|
<g
|
||||||
|
id="g13-2"
|
||||||
|
transform="matrix(4.6783888,0,0,4.6783888,411.42933,-46.143325)">
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
transform="matrix(0.26458333,0,0,0.26458333,2.4199432,-2.3937254)"
|
||||||
|
id="text1-0"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:192px;font-family:'Shree Devanagari 714';-inkscape-font-specification:'Shree Devanagari 714, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;writing-mode:lr-tb;direction:ltr;white-space:pre;shape-inside:url(#rect1-5);display:inline;fill:url(#linearGradient6-2);stroke-width:7.55906;stroke-dasharray:none"><tspan
|
||||||
|
x="227.9082"
|
||||||
|
y="353.41641"
|
||||||
|
id="tspan1">SMATH</tspan></text>
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:8.37934px;font-family:'Shree Devanagari 714';-inkscape-font-specification:'Shree Devanagari 714, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;writing-mode:lr-tb;direction:ltr;text-anchor:start;fill:#000000;stroke-width:2;stroke-dasharray:none"
|
||||||
|
x="110.62661"
|
||||||
|
y="105.75446"
|
||||||
|
id="text2-1"><tspan
|
||||||
|
id="tspan2-24"
|
||||||
|
style="font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:8.37934px;font-family:'Shree Devanagari 714';-inkscape-font-specification:'Shree Devanagari 714, Bold Italic';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:2;stroke-dasharray:none"
|
||||||
|
x="110.62661"
|
||||||
|
y="105.75446">Linear algebra library for C++23</tspan></text>
|
||||||
|
<path
|
||||||
|
style="fill:#000000;stroke:url(#linearGradient11-0);stroke-width:2;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#RoundedArrow-45)"
|
||||||
|
d="M 50.894116,102.63145 V 56.432683"
|
||||||
|
id="path4-5" />
|
||||||
|
<path
|
||||||
|
style="fill:#000000;stroke:url(#linearGradient16);stroke-width:1.93832;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="M 50.894116,102.63145 V 59.238272"
|
||||||
|
id="path4-0-5" />
|
||||||
|
<path
|
||||||
|
style="fill:none;stroke:url(#linearGradient9-6);stroke-width:2;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#RoundedArrow-4-1)"
|
||||||
|
d="m 51.891583,103.63172 h 46.19876"
|
||||||
|
id="path4-9-23" />
|
||||||
|
<path
|
||||||
|
style="fill:#ff0c0c;fill-opacity:1;stroke:none;stroke-width:2;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 51.891583,104.63115 v -1.9997 l -1.998196,1.99844 z"
|
||||||
|
id="path5-2" />
|
||||||
|
<path
|
||||||
|
style="fill:#25ff0c;fill-opacity:1;stroke:none;stroke-width:2;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 49.895018,102.63082 v 1.9997 l 1.998196,-1.99844 z"
|
||||||
|
id="path5-8-3" />
|
||||||
|
<circle
|
||||||
|
style="fill:#1162ff;fill-opacity:1;stroke:none;stroke-width:2;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
id="path13-1"
|
||||||
|
cx="50.894115"
|
||||||
|
cy="103.6313"
|
||||||
|
r="3.4155982" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 7.1 KiB |
186
docs/smath_big_dark.svg
Normal file
186
docs/smath_big_dark.svg
Normal file
@@ -0,0 +1,186 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
width="1280"
|
||||||
|
height="640"
|
||||||
|
viewBox="0 0 1280.0001 640.00006"
|
||||||
|
version="1.1"
|
||||||
|
id="svg1"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<defs
|
||||||
|
id="defs1">
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient15">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#666666;stop-opacity:1;"
|
||||||
|
offset="0.27173913"
|
||||||
|
id="stop14" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#ffffff;stop-opacity:1;"
|
||||||
|
offset="1"
|
||||||
|
id="stop15" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient13">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#25ff0c;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop12" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#16d800;stop-opacity:1;"
|
||||||
|
offset="1"
|
||||||
|
id="stop13" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient10">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#25ff0c;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop10" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#25ff0c;stop-opacity:1;"
|
||||||
|
offset="1"
|
||||||
|
id="stop11" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient8">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#c50000;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop8" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#ff0c0c;stop-opacity:1;"
|
||||||
|
offset="1"
|
||||||
|
id="stop9" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
xlink:href="#linearGradient15"
|
||||||
|
id="linearGradient6-4-9"
|
||||||
|
x1="482.5849"
|
||||||
|
y1="589.83472"
|
||||||
|
x2="613.15253"
|
||||||
|
y2="-24.437733"
|
||||||
|
gradientUnits="userSpaceOnUse" />
|
||||||
|
<rect
|
||||||
|
x="227.90907"
|
||||||
|
y="175.81558"
|
||||||
|
width="659.85107"
|
||||||
|
height="227.90907"
|
||||||
|
id="rect1-9-2" />
|
||||||
|
<linearGradient
|
||||||
|
xlink:href="#linearGradient10"
|
||||||
|
id="linearGradient11-6-9"
|
||||||
|
x1="50.894115"
|
||||||
|
y1="80.727814"
|
||||||
|
x2="50.894115"
|
||||||
|
y2="68.866821"
|
||||||
|
gradientUnits="userSpaceOnUse" />
|
||||||
|
<marker
|
||||||
|
style="overflow:visible"
|
||||||
|
id="RoundedArrow-7-9"
|
||||||
|
refX="0"
|
||||||
|
refY="0"
|
||||||
|
orient="auto-start-reverse"
|
||||||
|
markerWidth="1"
|
||||||
|
markerHeight="1"
|
||||||
|
viewBox="0 0 1 1"
|
||||||
|
preserveAspectRatio="xMidYMid">
|
||||||
|
<path
|
||||||
|
transform="scale(0.7)"
|
||||||
|
d="m -0.21114562,-4.1055728 6.42229122,3.21114561 a 1,1 90 0 1 0,1.78885438 L -0.21114562,4.1055728 A 1.236068,1.236068 31.717474 0 1 -2,3 v -6 a 1.236068,1.236068 148.28253 0 1 1.78885438,-1.1055728 z"
|
||||||
|
style="fill:context-stroke;fill-rule:evenodd;stroke:none"
|
||||||
|
id="path8-31-8" />
|
||||||
|
</marker>
|
||||||
|
<linearGradient
|
||||||
|
xlink:href="#linearGradient8"
|
||||||
|
id="linearGradient9-9-6"
|
||||||
|
x1="107.55984"
|
||||||
|
y1="103.63171"
|
||||||
|
x2="51.891579"
|
||||||
|
y2="103.63171"
|
||||||
|
gradientUnits="userSpaceOnUse" />
|
||||||
|
<marker
|
||||||
|
style="overflow:visible"
|
||||||
|
id="RoundedArrow-4-8-5"
|
||||||
|
refX="0"
|
||||||
|
refY="0"
|
||||||
|
orient="auto-start-reverse"
|
||||||
|
markerWidth="1"
|
||||||
|
markerHeight="1"
|
||||||
|
viewBox="0 0 1 1"
|
||||||
|
preserveAspectRatio="xMidYMid">
|
||||||
|
<path
|
||||||
|
transform="scale(0.7)"
|
||||||
|
d="m -0.21114562,-4.1055728 6.42229122,3.21114561 a 1,1 90 0 1 0,1.78885438 L -0.21114562,4.1055728 A 1.236068,1.236068 31.717474 0 1 -2,3 v -6 a 1.236068,1.236068 148.28253 0 1 1.78885438,-1.1055728 z"
|
||||||
|
style="fill:context-stroke;fill-rule:evenodd;stroke:none"
|
||||||
|
id="path8-3-0-8" />
|
||||||
|
</marker>
|
||||||
|
<linearGradient
|
||||||
|
xlink:href="#linearGradient13"
|
||||||
|
id="linearGradient18"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(1,0,0,0.93927134,0,6.2326702)"
|
||||||
|
x1="50.894115"
|
||||||
|
y1="80.727814"
|
||||||
|
x2="50.894115"
|
||||||
|
y2="68.866821" />
|
||||||
|
</defs>
|
||||||
|
<g
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(-1710.0001)">
|
||||||
|
<g
|
||||||
|
id="g13-6-1"
|
||||||
|
transform="matrix(4.678389,0,0,4.6783889,1701.4295,-46.143332)">
|
||||||
|
<g
|
||||||
|
id="g15-6">
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
transform="matrix(0.26458333,0,0,0.26458333,2.4199432,-2.3937254)"
|
||||||
|
id="text1-5-1"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:192px;font-family:'Shree Devanagari 714';-inkscape-font-specification:'Shree Devanagari 714, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;writing-mode:lr-tb;direction:ltr;white-space:pre;shape-inside:url(#rect1-9-2);display:inline;fill:url(#linearGradient6-4-9);stroke-width:7.55906;stroke-dasharray:none"><tspan
|
||||||
|
x="227.9082"
|
||||||
|
y="353.41641"
|
||||||
|
id="tspan1">SMATH</tspan></text>
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:8.37934px;font-family:'Shree Devanagari 714';-inkscape-font-specification:'Shree Devanagari 714, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;writing-mode:lr-tb;direction:ltr;text-anchor:start;fill:#d1d1d1;fill-opacity:1;stroke-width:2;stroke-dasharray:none"
|
||||||
|
x="110.62661"
|
||||||
|
y="105.75446"
|
||||||
|
id="text2-4-3"><tspan
|
||||||
|
id="tspan2-2-2"
|
||||||
|
style="font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:8.37934px;font-family:'Shree Devanagari 714';-inkscape-font-specification:'Shree Devanagari 714, Bold Italic';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#d1d1d1;fill-opacity:1;stroke-width:2;stroke-dasharray:none"
|
||||||
|
x="110.62661"
|
||||||
|
y="105.75446">Linear algebra library for C++23</tspan></text>
|
||||||
|
<path
|
||||||
|
style="fill:#000000;stroke:url(#linearGradient11-6-9);stroke-width:2;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#RoundedArrow-7-9)"
|
||||||
|
d="M 50.894116,102.63145 V 56.432683"
|
||||||
|
id="path4-3-2" />
|
||||||
|
<path
|
||||||
|
style="fill:#000000;stroke:url(#linearGradient18);stroke-width:1.93832;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="M 50.894116,102.63145 V 59.238272"
|
||||||
|
id="path4-0-1-1" />
|
||||||
|
<path
|
||||||
|
style="fill:none;stroke:url(#linearGradient9-9-6);stroke-width:2;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#RoundedArrow-4-8-5)"
|
||||||
|
d="m 51.891583,103.63172 h 46.19876"
|
||||||
|
id="path4-9-2-1" />
|
||||||
|
<path
|
||||||
|
style="fill:#ff0c0c;fill-opacity:1;stroke:none;stroke-width:2;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 51.891583,104.63115 v -1.9997 l -1.998196,1.99844 z"
|
||||||
|
id="path5-1-1" />
|
||||||
|
<path
|
||||||
|
style="fill:#25ff0c;fill-opacity:1;stroke:none;stroke-width:2;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 49.895018,102.63082 v 1.9997 l 1.998196,-1.99844 z"
|
||||||
|
id="path5-8-2-2" />
|
||||||
|
<circle
|
||||||
|
style="fill:#1162ff;fill-opacity:1;stroke:none;stroke-width:2;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
id="path13-5-3"
|
||||||
|
cx="50.894115"
|
||||||
|
cy="103.6313"
|
||||||
|
r="3.4155982" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 7.2 KiB |
193
docs/smath_dark.svg
Normal file
193
docs/smath_dark.svg
Normal file
@@ -0,0 +1,193 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
width="200"
|
||||||
|
height="80"
|
||||||
|
viewBox="0 0 200.00001 80.000008"
|
||||||
|
version="1.1"
|
||||||
|
id="svg1"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<defs
|
||||||
|
id="defs1">
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient15">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#666666;stop-opacity:1;"
|
||||||
|
offset="0.27173913"
|
||||||
|
id="stop14" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#ffffff;stop-opacity:1;"
|
||||||
|
offset="1"
|
||||||
|
id="stop15" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient13">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#25ff0c;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop12" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#16d800;stop-opacity:1;"
|
||||||
|
offset="1"
|
||||||
|
id="stop13" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient10">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#25ff0c;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop10" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#25ff0c;stop-opacity:1;"
|
||||||
|
offset="1"
|
||||||
|
id="stop11" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient8">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#c50000;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop8" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#ff0c0c;stop-opacity:1;"
|
||||||
|
offset="1"
|
||||||
|
id="stop9" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
xlink:href="#linearGradient15"
|
||||||
|
id="linearGradient6-4"
|
||||||
|
x1="482.5849"
|
||||||
|
y1="589.83472"
|
||||||
|
x2="613.15253"
|
||||||
|
y2="-24.437733"
|
||||||
|
gradientUnits="userSpaceOnUse" />
|
||||||
|
<rect
|
||||||
|
x="227.90907"
|
||||||
|
y="175.81558"
|
||||||
|
width="659.85107"
|
||||||
|
height="227.90907"
|
||||||
|
id="rect1-9" />
|
||||||
|
<linearGradient
|
||||||
|
xlink:href="#linearGradient10"
|
||||||
|
id="linearGradient11-6"
|
||||||
|
x1="50.894115"
|
||||||
|
y1="80.727814"
|
||||||
|
x2="50.894115"
|
||||||
|
y2="68.866821"
|
||||||
|
gradientUnits="userSpaceOnUse" />
|
||||||
|
<marker
|
||||||
|
style="overflow:visible"
|
||||||
|
id="RoundedArrow-7"
|
||||||
|
refX="0"
|
||||||
|
refY="0"
|
||||||
|
orient="auto-start-reverse"
|
||||||
|
markerWidth="1"
|
||||||
|
markerHeight="1"
|
||||||
|
viewBox="0 0 1 1"
|
||||||
|
preserveAspectRatio="xMidYMid">
|
||||||
|
<path
|
||||||
|
transform="scale(0.7)"
|
||||||
|
d="m -0.21114562,-4.1055728 6.42229122,3.21114561 a 1,1 90 0 1 0,1.78885438 L -0.21114562,4.1055728 A 1.236068,1.236068 31.717474 0 1 -2,3 v -6 a 1.236068,1.236068 148.28253 0 1 1.78885438,-1.1055728 z"
|
||||||
|
style="fill:context-stroke;fill-rule:evenodd;stroke:none"
|
||||||
|
id="path8-31" />
|
||||||
|
</marker>
|
||||||
|
<linearGradient
|
||||||
|
xlink:href="#linearGradient8"
|
||||||
|
id="linearGradient9-9"
|
||||||
|
x1="107.55984"
|
||||||
|
y1="103.63171"
|
||||||
|
x2="51.891579"
|
||||||
|
y2="103.63171"
|
||||||
|
gradientUnits="userSpaceOnUse" />
|
||||||
|
<marker
|
||||||
|
style="overflow:visible"
|
||||||
|
id="RoundedArrow-4-8"
|
||||||
|
refX="0"
|
||||||
|
refY="0"
|
||||||
|
orient="auto-start-reverse"
|
||||||
|
markerWidth="1"
|
||||||
|
markerHeight="1"
|
||||||
|
viewBox="0 0 1 1"
|
||||||
|
preserveAspectRatio="xMidYMid">
|
||||||
|
<path
|
||||||
|
transform="scale(0.7)"
|
||||||
|
d="m -0.21114562,-4.1055728 6.42229122,3.21114561 a 1,1 90 0 1 0,1.78885438 L -0.21114562,4.1055728 A 1.236068,1.236068 31.717474 0 1 -2,3 v -6 a 1.236068,1.236068 148.28253 0 1 1.78885438,-1.1055728 z"
|
||||||
|
style="fill:context-stroke;fill-rule:evenodd;stroke:none"
|
||||||
|
id="path8-3-0" />
|
||||||
|
</marker>
|
||||||
|
<linearGradient
|
||||||
|
xlink:href="#linearGradient13"
|
||||||
|
id="linearGradient14"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(1,0,0,0.93927134,0,6.2326702)"
|
||||||
|
x1="50.894115"
|
||||||
|
y1="80.727814"
|
||||||
|
x2="50.894115"
|
||||||
|
y2="68.866821" />
|
||||||
|
</defs>
|
||||||
|
<rect
|
||||||
|
style="display:none;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
id="rect14"
|
||||||
|
width="200"
|
||||||
|
height="80"
|
||||||
|
x="-4.7587887e-06"
|
||||||
|
y="0" />
|
||||||
|
<g
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(-210)">
|
||||||
|
<g
|
||||||
|
id="g13-6"
|
||||||
|
transform="translate(171.3688,-38.262697)">
|
||||||
|
<g
|
||||||
|
id="g15">
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
transform="matrix(0.26458333,0,0,0.26458333,2.4199432,-2.3937254)"
|
||||||
|
id="text1-5"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:192px;font-family:'Shree Devanagari 714';-inkscape-font-specification:'Shree Devanagari 714, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;writing-mode:lr-tb;direction:ltr;white-space:pre;shape-inside:url(#rect1-9);display:inline;fill:url(#linearGradient6-4);stroke-width:7.55906;stroke-dasharray:none"><tspan
|
||||||
|
x="227.9082"
|
||||||
|
y="353.41641"
|
||||||
|
id="tspan1">SMATH</tspan></text>
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:8.37934px;font-family:'Shree Devanagari 714';-inkscape-font-specification:'Shree Devanagari 714, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;writing-mode:lr-tb;direction:ltr;text-anchor:start;fill:#d1d1d1;fill-opacity:1;stroke-width:2;stroke-dasharray:none"
|
||||||
|
x="110.62661"
|
||||||
|
y="105.75446"
|
||||||
|
id="text2-4"><tspan
|
||||||
|
id="tspan2-2"
|
||||||
|
style="font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:8.37934px;font-family:'Shree Devanagari 714';-inkscape-font-specification:'Shree Devanagari 714, Bold Italic';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#d1d1d1;fill-opacity:1;stroke-width:2;stroke-dasharray:none"
|
||||||
|
x="110.62661"
|
||||||
|
y="105.75446">Linear algebra library for C++23</tspan></text>
|
||||||
|
<path
|
||||||
|
style="fill:#000000;stroke:url(#linearGradient11-6);stroke-width:2;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#RoundedArrow-7)"
|
||||||
|
d="M 50.894116,102.63145 V 56.432683"
|
||||||
|
id="path4-3" />
|
||||||
|
<path
|
||||||
|
style="fill:#000000;stroke:url(#linearGradient14);stroke-width:1.93832;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="M 50.894116,102.63145 V 59.238272"
|
||||||
|
id="path4-0-1" />
|
||||||
|
<path
|
||||||
|
style="fill:none;stroke:url(#linearGradient9-9);stroke-width:2;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#RoundedArrow-4-8)"
|
||||||
|
d="m 51.891583,103.63172 h 46.19876"
|
||||||
|
id="path4-9-2" />
|
||||||
|
<path
|
||||||
|
style="fill:#ff0c0c;fill-opacity:1;stroke:none;stroke-width:2;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 51.891583,104.63115 v -1.9997 l -1.998196,1.99844 z"
|
||||||
|
id="path5-1" />
|
||||||
|
<path
|
||||||
|
style="fill:#25ff0c;fill-opacity:1;stroke:none;stroke-width:2;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 49.895018,102.63082 v 1.9997 l 1.998196,-1.99844 z"
|
||||||
|
id="path5-8-2" />
|
||||||
|
<circle
|
||||||
|
style="fill:#1162ff;fill-opacity:1;stroke:none;stroke-width:2;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
id="path13-5"
|
||||||
|
cx="50.894115"
|
||||||
|
cy="103.6313"
|
||||||
|
r="3.4155982" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 7.3 KiB |
182
docs/smath_light.svg
Normal file
182
docs/smath_light.svg
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
width="200"
|
||||||
|
height="80"
|
||||||
|
viewBox="0 0 200.00001 80.000008"
|
||||||
|
version="1.1"
|
||||||
|
id="svg1"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<defs
|
||||||
|
id="defs1">
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient13">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#25ff0c;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop12" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#16d800;stop-opacity:1;"
|
||||||
|
offset="1"
|
||||||
|
id="stop13" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient10">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#25ff0c;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop10" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#25ff0c;stop-opacity:1;"
|
||||||
|
offset="1"
|
||||||
|
id="stop11" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient8">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#c50000;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop8" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#ff0c0c;stop-opacity:1;"
|
||||||
|
offset="1"
|
||||||
|
id="stop9" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient5">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#000000;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop5" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#969696;stop-opacity:1;"
|
||||||
|
offset="1"
|
||||||
|
id="stop6" />
|
||||||
|
</linearGradient>
|
||||||
|
<marker
|
||||||
|
style="overflow:visible"
|
||||||
|
id="RoundedArrow"
|
||||||
|
refX="0"
|
||||||
|
refY="0"
|
||||||
|
orient="auto-start-reverse"
|
||||||
|
markerWidth="1"
|
||||||
|
markerHeight="1"
|
||||||
|
viewBox="0 0 1 1"
|
||||||
|
preserveAspectRatio="xMidYMid">
|
||||||
|
<path
|
||||||
|
transform="scale(0.7)"
|
||||||
|
d="m -0.21114562,-4.1055728 6.42229122,3.21114561 a 1,1 90 0 1 0,1.78885438 L -0.21114562,4.1055728 A 1.236068,1.236068 31.717474 0 1 -2,3 v -6 a 1.236068,1.236068 148.28253 0 1 1.78885438,-1.1055728 z"
|
||||||
|
style="fill:context-stroke;fill-rule:evenodd;stroke:none"
|
||||||
|
id="path8" />
|
||||||
|
</marker>
|
||||||
|
<rect
|
||||||
|
x="227.90907"
|
||||||
|
y="175.81558"
|
||||||
|
width="659.85107"
|
||||||
|
height="227.90907"
|
||||||
|
id="rect1" />
|
||||||
|
<marker
|
||||||
|
style="overflow:visible"
|
||||||
|
id="RoundedArrow-4"
|
||||||
|
refX="0"
|
||||||
|
refY="0"
|
||||||
|
orient="auto-start-reverse"
|
||||||
|
markerWidth="1"
|
||||||
|
markerHeight="1"
|
||||||
|
viewBox="0 0 1 1"
|
||||||
|
preserveAspectRatio="xMidYMid">
|
||||||
|
<path
|
||||||
|
transform="scale(0.7)"
|
||||||
|
d="m -0.21114562,-4.1055728 6.42229122,3.21114561 a 1,1 90 0 1 0,1.78885438 L -0.21114562,4.1055728 A 1.236068,1.236068 31.717474 0 1 -2,3 v -6 a 1.236068,1.236068 148.28253 0 1 1.78885438,-1.1055728 z"
|
||||||
|
style="fill:context-stroke;fill-rule:evenodd;stroke:none"
|
||||||
|
id="path8-3" />
|
||||||
|
</marker>
|
||||||
|
<linearGradient
|
||||||
|
xlink:href="#linearGradient5"
|
||||||
|
id="linearGradient6"
|
||||||
|
x1="482.5849"
|
||||||
|
y1="589.83472"
|
||||||
|
x2="613.15253"
|
||||||
|
y2="-24.437733"
|
||||||
|
gradientUnits="userSpaceOnUse" />
|
||||||
|
<linearGradient
|
||||||
|
xlink:href="#linearGradient8"
|
||||||
|
id="linearGradient9"
|
||||||
|
x1="107.55984"
|
||||||
|
y1="103.63171"
|
||||||
|
x2="51.891579"
|
||||||
|
y2="103.63171"
|
||||||
|
gradientUnits="userSpaceOnUse" />
|
||||||
|
<linearGradient
|
||||||
|
xlink:href="#linearGradient10"
|
||||||
|
id="linearGradient11"
|
||||||
|
x1="50.894115"
|
||||||
|
y1="80.727814"
|
||||||
|
x2="50.894115"
|
||||||
|
y2="68.866821"
|
||||||
|
gradientUnits="userSpaceOnUse" />
|
||||||
|
<linearGradient
|
||||||
|
xlink:href="#linearGradient13"
|
||||||
|
id="linearGradient12"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
x1="50.894115"
|
||||||
|
y1="80.727814"
|
||||||
|
x2="50.894115"
|
||||||
|
y2="68.866821"
|
||||||
|
gradientTransform="matrix(1,0,0,0.93927134,0,6.2326702)" />
|
||||||
|
</defs>
|
||||||
|
<g
|
||||||
|
id="layer1">
|
||||||
|
<g
|
||||||
|
id="g13"
|
||||||
|
transform="translate(-38.631211,-38.262697)">
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
transform="matrix(0.26458333,0,0,0.26458333,2.4199432,-2.3937254)"
|
||||||
|
id="text1"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:192px;font-family:'Shree Devanagari 714';-inkscape-font-specification:'Shree Devanagari 714, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;writing-mode:lr-tb;direction:ltr;white-space:pre;shape-inside:url(#rect1);display:inline;fill:url(#linearGradient6);stroke-width:7.55906;stroke-dasharray:none"><tspan
|
||||||
|
x="227.9082"
|
||||||
|
y="353.41641"
|
||||||
|
id="tspan3">SMATH</tspan></text>
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:8.37934px;font-family:'Shree Devanagari 714';-inkscape-font-specification:'Shree Devanagari 714, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;writing-mode:lr-tb;direction:ltr;text-anchor:start;fill:#000000;stroke-width:2;stroke-dasharray:none"
|
||||||
|
x="110.62661"
|
||||||
|
y="105.75446"
|
||||||
|
id="text2"><tspan
|
||||||
|
id="tspan2"
|
||||||
|
style="font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:8.37934px;font-family:'Shree Devanagari 714';-inkscape-font-specification:'Shree Devanagari 714, Bold Italic';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:2;stroke-dasharray:none"
|
||||||
|
x="110.62661"
|
||||||
|
y="105.75446">Linear algebra library for C++23</tspan></text>
|
||||||
|
<path
|
||||||
|
style="fill:#000000;stroke:url(#linearGradient11);stroke-width:2;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#RoundedArrow)"
|
||||||
|
d="M 50.894116,102.63145 V 56.432683"
|
||||||
|
id="path4" />
|
||||||
|
<path
|
||||||
|
style="fill:#000000;stroke:url(#linearGradient12);stroke-width:1.93832;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="M 50.894116,102.63145 V 59.238272"
|
||||||
|
id="path4-0" />
|
||||||
|
<path
|
||||||
|
style="fill:none;stroke:url(#linearGradient9);stroke-width:2;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#RoundedArrow-4)"
|
||||||
|
d="m 51.891583,103.63172 h 46.19876"
|
||||||
|
id="path4-9" />
|
||||||
|
<path
|
||||||
|
style="fill:#ff0c0c;fill-opacity:1;stroke:none;stroke-width:2;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 51.891583,104.63115 v -1.9997 l -1.998196,1.99844 z"
|
||||||
|
id="path5" />
|
||||||
|
<path
|
||||||
|
style="fill:#25ff0c;fill-opacity:1;stroke:none;stroke-width:2;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 49.895018,102.63082 v 1.9997 l 1.998196,-1.99844 z"
|
||||||
|
id="path5-8" />
|
||||||
|
<circle
|
||||||
|
style="fill:#1162ff;fill-opacity:1;stroke:none;stroke-width:2;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
id="path13"
|
||||||
|
cx="50.894115"
|
||||||
|
cy="103.6313"
|
||||||
|
r="3.4155982" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 6.8 KiB |
3020
docs/vendor/doxygen-awesome.css
vendored
Normal file
3020
docs/vendor/doxygen-awesome.css
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@@ -10,10 +10,11 @@
|
|||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <smath.hpp>
|
#include <smath/smath.hpp>
|
||||||
using smath::Vec2;
|
using smath::Vec2;
|
||||||
|
|
||||||
enum Color : uint8_t {
|
enum Color : uint8_t
|
||||||
|
{
|
||||||
CLR_NONE = 0, // default
|
CLR_NONE = 0, // default
|
||||||
CLR_AXES = 90, // bright black (gray)
|
CLR_AXES = 90, // bright black (gray)
|
||||||
CLR_A = 32, // green
|
CLR_A = 32, // green
|
||||||
@@ -22,18 +23,21 @@ enum Color : uint8_t {
|
|||||||
CLR_DOT = 36 // cyan
|
CLR_DOT = 36 // cyan
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Cell {
|
struct Cell
|
||||||
char ch{' '};
|
{
|
||||||
uint8_t color{CLR_NONE};
|
char ch { ' ' };
|
||||||
int prio{0};
|
uint8_t color { CLR_NONE };
|
||||||
|
int prio { 0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Canvas {
|
struct Canvas
|
||||||
|
{
|
||||||
int w, h;
|
int w, h;
|
||||||
std::vector<Cell> pix;
|
std::vector<Cell> pix;
|
||||||
Canvas(int W, int H) : w(W), h(H), pix(W * H) {}
|
Canvas(int W, int H) : w(W), h(H), pix(W * H) { }
|
||||||
|
|
||||||
void put(int x, int y, char c, int prio, uint8_t color) {
|
void put(int x, int y, char c, int prio, uint8_t color)
|
||||||
|
{
|
||||||
if (x < 0 || x >= w || y < 0 || y >= h)
|
if (x < 0 || x >= w || y < 0 || y >= h)
|
||||||
return;
|
return;
|
||||||
Cell &cell = pix[y * w + x];
|
Cell &cell = pix[y * w + x];
|
||||||
@@ -43,16 +47,19 @@ struct Canvas {
|
|||||||
cell.color = color;
|
cell.color = color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void hline(int y, char c, int prio, uint8_t color) {
|
void hline(int y, char c, int prio, uint8_t color)
|
||||||
|
{
|
||||||
for (int x = 0; x < w; ++x)
|
for (int x = 0; x < w; ++x)
|
||||||
put(x, y, c, prio, color);
|
put(x, y, c, prio, color);
|
||||||
}
|
}
|
||||||
void vline(int x, char c, int prio, uint8_t color) {
|
void vline(int x, char c, int prio, uint8_t color)
|
||||||
|
{
|
||||||
for (int y = 0; y < h; ++y)
|
for (int y = 0; y < h; ++y)
|
||||||
put(x, y, c, prio, color);
|
put(x, y, c, prio, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
void line_dir(int x0, int y0, int x1, int y1, int prio, uint8_t color) {
|
void line_dir(int x0, int y0, int x1, int y1, int prio, uint8_t color)
|
||||||
|
{
|
||||||
int dx = std::abs(x1 - x0), sx = x0 < x1 ? 1 : -1;
|
int dx = std::abs(x1 - x0), sx = x0 < x1 ? 1 : -1;
|
||||||
int dy = -std::abs(y1 - y0), sy = y0 < y1 ? 1 : -1;
|
int dy = -std::abs(y1 - y0), sy = y0 < y1 ? 1 : -1;
|
||||||
int err = dx + dy;
|
int err = dx + dy;
|
||||||
@@ -92,7 +99,8 @@ struct Canvas {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void flush() const {
|
void flush() const
|
||||||
|
{
|
||||||
uint8_t cur = 255;
|
uint8_t cur = 255;
|
||||||
for (int y = 0; y < h; ++y) {
|
for (int y = 0; y < h; ++y) {
|
||||||
for (int x = 0; x < w; ++x) {
|
for (int x = 0; x < w; ++x) {
|
||||||
@@ -112,19 +120,23 @@ struct Canvas {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Mapper {
|
struct Mapper
|
||||||
|
{
|
||||||
int W, H;
|
int W, H;
|
||||||
double scale;
|
double scale;
|
||||||
int cx, cy;
|
int cx, cy;
|
||||||
Mapper(int w, int h, double s) : W(w), H(h), scale(s), cx(w / 2), cy(h / 2) {}
|
Mapper(int w, int h, double s) : W(w), H(h), scale(s), cx(w / 2), cy(h / 2)
|
||||||
std::pair<int, int> map(Vec2 v) const {
|
{ }
|
||||||
|
std::pair<int, int> map(Vec2 v) const
|
||||||
|
{
|
||||||
int x = cx + (int)std::llround(v.x() * scale);
|
int x = cx + (int)std::llround(v.x() * scale);
|
||||||
int y = cy - (int)std::llround(v.y() * scale);
|
int y = cy - (int)std::llround(v.y() * scale);
|
||||||
return {x, y};
|
return { x, y };
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
int main() {
|
int main()
|
||||||
|
{
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
|
HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
if (h != INVALID_HANDLE_VALUE) {
|
if (h != INVALID_HANDLE_VALUE) {
|
||||||
@@ -143,27 +155,29 @@ int main() {
|
|||||||
if (!(std::cin >> bx >> by))
|
if (!(std::cin >> bx >> by))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
Vec2 a{(float)ax, (float)ay};
|
Vec2 a { (float)ax, (float)ay };
|
||||||
Vec2 b{(float)bx, (float)by};
|
Vec2 b { (float)bx, (float)by };
|
||||||
Vec2 p = a.project_onto(b);
|
Vec2 p = a.project_onto(b);
|
||||||
|
|
||||||
std::println("\nResults:");
|
std::println("\nResults:");
|
||||||
std::println("a = {}", a);
|
std::println("a = {}", a);
|
||||||
std::println("b = {}", b);
|
std::println("b = {}", b);
|
||||||
std::println("proj_b(a) = p = {}", p);
|
std::println("proj_b(a) = p = {}", p);
|
||||||
std::println("|a|={} |b|={} |p|={}", a.magnitude(), b.magnitude(),
|
std::println(
|
||||||
p.magnitude());
|
"|a|={} |b|={} |p|={}", a.magnitude(), b.magnitude(), p.magnitude());
|
||||||
double dot = a.dot(b);
|
double dot = a.dot(b);
|
||||||
double ang = (a.magnitude() > 0 && b.magnitude() > 0)
|
double ang = (a.magnitude() > 0 && b.magnitude() > 0)
|
||||||
? std::acos(std::clamp(dot / (a.magnitude() * b.magnitude()),
|
? std::acos(
|
||||||
-1.0, 1.0)) *
|
std::clamp(dot / (a.magnitude() * b.magnitude()), -1.0, 1.0))
|
||||||
180.0 / M_PI
|
* 180.0 / M_PI
|
||||||
: 0.0;
|
: 0.0;
|
||||||
std::println("a·b={} angle(a,b)={} deg\n", dot, ang);
|
std::println("a·b={} angle(a,b)={} deg\n", dot, ang);
|
||||||
|
|
||||||
const int W = 73, H = 33;
|
const int W = 73, H = 33;
|
||||||
double maxr = std::max({(double)a.magnitude(), (double)b.magnitude(),
|
double maxr = std::max({ (double)a.magnitude(),
|
||||||
(double)p.magnitude(), 1.0});
|
(double)b.magnitude(),
|
||||||
|
(double)p.magnitude(),
|
||||||
|
1.0 });
|
||||||
double usable = 0.45 * std::min(W, H);
|
double usable = 0.45 * std::min(W, H);
|
||||||
double scale = usable / maxr;
|
double scale = usable / maxr;
|
||||||
|
|
||||||
@@ -171,12 +185,11 @@ int main() {
|
|||||||
Mapper mp(W, H, scale);
|
Mapper mp(W, H, scale);
|
||||||
|
|
||||||
int pr_axes = 1;
|
int pr_axes = 1;
|
||||||
auto [cx, cy] = mp.map({0, 0});
|
|
||||||
cvs.hline(H / 2, '-', pr_axes, CLR_AXES);
|
cvs.hline(H / 2, '-', pr_axes, CLR_AXES);
|
||||||
cvs.vline(W / 2, '|', pr_axes, CLR_AXES);
|
cvs.vline(W / 2, '|', pr_axes, CLR_AXES);
|
||||||
cvs.put(W / 2, H / 2, 'O', pr_axes + 1, CLR_AXES);
|
cvs.put(W / 2, H / 2, 'O', pr_axes + 1, CLR_AXES);
|
||||||
|
|
||||||
auto [ox, oy] = mp.map({0, 0});
|
auto [ox, oy] = mp.map({ 0, 0 });
|
||||||
auto [ax1, ay1] = mp.map(a);
|
auto [ax1, ay1] = mp.map(a);
|
||||||
auto [bx1, by1] = mp.map(b);
|
auto [bx1, by1] = mp.map(b);
|
||||||
auto [px1, py1] = mp.map(p);
|
auto [px1, py1] = mp.map(p);
|
||||||
|
|||||||
@@ -22,18 +22,19 @@
|
|||||||
#include <print>
|
#include <print>
|
||||||
#include <random>
|
#include <random>
|
||||||
|
|
||||||
#include <smath.hpp>
|
#include <smath/smath.hpp>
|
||||||
|
|
||||||
auto main() -> int {
|
auto main() -> int
|
||||||
|
{
|
||||||
using namespace smath;
|
using namespace smath;
|
||||||
|
|
||||||
Vec2d point;
|
Vec2d point;
|
||||||
std::random_device rd;
|
std::random_device rd;
|
||||||
std::mt19937 rng{rd()};
|
std::mt19937 rng { rd() };
|
||||||
std::uniform_real_distribution<> dis(-5, 5);
|
std::uniform_real_distribution<> dis(-5, 5);
|
||||||
int i = 0;
|
int i = 0;
|
||||||
do {
|
do {
|
||||||
Vec2d add{dis(rng), dis(rng)};
|
Vec2d add { dis(rng), dis(rng) };
|
||||||
auto const n = point + add;
|
auto const n = point + add;
|
||||||
std::println("{}: {:.2f} + {:.2f} -> {:.2f}", i, point, add, n);
|
std::println("{}: {:.2f} + {:.2f} -> {:.2f}", i, point, add, n);
|
||||||
point = n;
|
point = n;
|
||||||
|
|||||||
@@ -17,11 +17,12 @@
|
|||||||
|
|
||||||
// #define SMATH_IMPLICIT_CONVERSIONS
|
// #define SMATH_IMPLICIT_CONVERSIONS
|
||||||
|
|
||||||
#include <smath.hpp>
|
#include <smath/smath.hpp>
|
||||||
|
|
||||||
int main() {
|
int main()
|
||||||
|
{
|
||||||
using namespace smath;
|
using namespace smath;
|
||||||
Vec3 v{1, 2, 3};
|
Vec3 v { 1, 2, 3 };
|
||||||
std::println("v: {}", v);
|
std::println("v: {}", v);
|
||||||
auto v2 = swizzle<"zyx">(v);
|
auto v2 = swizzle<"zyx">(v);
|
||||||
std::println("v2: {}", v2);
|
std::println("v2: {}", v2);
|
||||||
@@ -39,7 +40,7 @@ int main() {
|
|||||||
std::println("std::get<1>(v): {}", std::get<1>(v));
|
std::println("std::get<1>(v): {}", std::get<1>(v));
|
||||||
auto [x, y, z] = v;
|
auto [x, y, z] = v;
|
||||||
std::println("Bindings: [{}, {}, {}]", x, y, z);
|
std::println("Bindings: [{}, {}, {}]", x, y, z);
|
||||||
float x1{}, y1{}, z1{};
|
float x1 {}, y1 {}, z1 {};
|
||||||
v.unpack(x1, y1, z1);
|
v.unpack(x1, y1, z1);
|
||||||
std::println("Unpacked: {}, {}, {}", x1, y1, z1);
|
std::println("Unpacked: {}, {}, {}", x1, y1, z1);
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
clang-tools
|
clang-tools
|
||||||
lldb
|
lldb
|
||||||
pkg-config
|
pkg-config
|
||||||
|
doxygen
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -55,10 +56,14 @@
|
|||||||
})
|
})
|
||||||
];
|
];
|
||||||
|
|
||||||
|
extraCMakeFlags = [
|
||||||
|
"-DSMATH_INSTALL_INTEROP_HEADERS=ON"
|
||||||
|
];
|
||||||
|
|
||||||
installPhase = ''
|
installPhase = ''
|
||||||
runHook preInstall
|
runHook preInstall
|
||||||
mkdir -p $out/include
|
mkdir -p $out/include/
|
||||||
cp ../include/smath.hpp $out/include/
|
cp -r ../include/smath/ $out/include/
|
||||||
runHook postInstall
|
runHook postInstall
|
||||||
'';
|
'';
|
||||||
|
|
||||||
|
|||||||
131
include/smath/interop/eigen.hpp
Normal file
131
include/smath/interop/eigen.hpp
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
/*
|
||||||
|
* smath - Single-file linear algebra math library for C++23.
|
||||||
|
*
|
||||||
|
* Copyright 2025 Slendi <slendi@socopon.com>
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Eigen/Core>
|
||||||
|
#include <Eigen/Geometry>
|
||||||
|
|
||||||
|
#include <smath/smath.hpp>
|
||||||
|
|
||||||
|
namespace smath
|
||||||
|
{
|
||||||
|
|
||||||
|
template<class Scalar, int N, int Options, int MaxRows, int MaxCols>
|
||||||
|
requires(std::is_arithmetic_v<Scalar> && (N > 0))
|
||||||
|
struct interop_adapter<Eigen::Matrix<Scalar, N, 1, Options, MaxRows, MaxCols>>
|
||||||
|
{
|
||||||
|
using smath_type = Vec<static_cast<std::size_t>(N), Scalar>;
|
||||||
|
|
||||||
|
static constexpr auto to_smath(
|
||||||
|
Eigen::Matrix<Scalar, N, 1, Options, MaxRows, MaxCols> const &v)
|
||||||
|
-> smath_type
|
||||||
|
{
|
||||||
|
smath_type out {};
|
||||||
|
for (std::size_t i = 0; i < static_cast<std::size_t>(N); ++i)
|
||||||
|
out[i] = v(static_cast<int>(i));
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr auto from_smath(smath_type const &v)
|
||||||
|
-> Eigen::Matrix<Scalar, N, 1, Options, MaxRows, MaxCols>
|
||||||
|
{
|
||||||
|
Eigen::Matrix<Scalar, N, 1, Options, MaxRows, MaxCols> out;
|
||||||
|
for (std::size_t i = 0; i < static_cast<std::size_t>(N); ++i)
|
||||||
|
out(static_cast<int>(i)) = v[i];
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class Scalar, int N, int Options, int MaxRows, int MaxCols>
|
||||||
|
requires(std::is_arithmetic_v<Scalar> && (N > 0))
|
||||||
|
struct interop_adapter<Eigen::Matrix<Scalar, 1, N, Options, MaxRows, MaxCols>>
|
||||||
|
{
|
||||||
|
using smath_type = Vec<static_cast<std::size_t>(N), Scalar>;
|
||||||
|
|
||||||
|
static constexpr auto to_smath(
|
||||||
|
Eigen::Matrix<Scalar, 1, N, Options, MaxRows, MaxCols> const &v)
|
||||||
|
-> smath_type
|
||||||
|
{
|
||||||
|
smath_type out {};
|
||||||
|
for (std::size_t i = 0; i < static_cast<std::size_t>(N); ++i)
|
||||||
|
out[i] = v(static_cast<int>(i));
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr auto from_smath(smath_type const &v)
|
||||||
|
-> Eigen::Matrix<Scalar, 1, N, Options, MaxRows, MaxCols>
|
||||||
|
{
|
||||||
|
Eigen::Matrix<Scalar, 1, N, Options, MaxRows, MaxCols> out;
|
||||||
|
for (std::size_t i = 0; i < static_cast<std::size_t>(N); ++i)
|
||||||
|
out(static_cast<int>(i)) = v[i];
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class Scalar, int R, int C, int Options, int MaxRows, int MaxCols>
|
||||||
|
requires(std::is_arithmetic_v<Scalar> && (R > 1) && (C > 1))
|
||||||
|
struct interop_adapter<Eigen::Matrix<Scalar, R, C, Options, MaxRows, MaxCols>>
|
||||||
|
{
|
||||||
|
using smath_type
|
||||||
|
= Mat<static_cast<std::size_t>(R), static_cast<std::size_t>(C), Scalar>;
|
||||||
|
|
||||||
|
static constexpr auto to_smath(
|
||||||
|
Eigen::Matrix<Scalar, R, C, Options, MaxRows, MaxCols> const &m)
|
||||||
|
-> smath_type
|
||||||
|
{
|
||||||
|
smath_type out {};
|
||||||
|
for (std::size_t c = 0; c < static_cast<std::size_t>(C); ++c) {
|
||||||
|
for (std::size_t r = 0; r < static_cast<std::size_t>(R); ++r)
|
||||||
|
out[r, c] = m(static_cast<int>(r), static_cast<int>(c));
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr auto from_smath(smath_type const &m)
|
||||||
|
-> Eigen::Matrix<Scalar, R, C, Options, MaxRows, MaxCols>
|
||||||
|
{
|
||||||
|
Eigen::Matrix<Scalar, R, C, Options, MaxRows, MaxCols> out;
|
||||||
|
for (std::size_t c = 0; c < static_cast<std::size_t>(C); ++c) {
|
||||||
|
for (std::size_t r = 0; r < static_cast<std::size_t>(R); ++r)
|
||||||
|
out(static_cast<int>(r), static_cast<int>(c)) = m[r, c];
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class Scalar, int Options>
|
||||||
|
requires std::is_arithmetic_v<Scalar>
|
||||||
|
struct interop_adapter<Eigen::Quaternion<Scalar, Options>>
|
||||||
|
{
|
||||||
|
using smath_type = Quaternion<Scalar>;
|
||||||
|
|
||||||
|
static constexpr auto to_smath(Eigen::Quaternion<Scalar, Options> const &q)
|
||||||
|
-> smath_type
|
||||||
|
{
|
||||||
|
return { q.x(), q.y(), q.z(), q.w() };
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr auto from_smath(smath_type const &q)
|
||||||
|
-> Eigen::Quaternion<Scalar, Options>
|
||||||
|
{
|
||||||
|
return { q.w(), q.x(), q.y(), q.z() };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace smath
|
||||||
103
include/smath/interop/glm.hpp
Normal file
103
include/smath/interop/glm.hpp
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
* smath - Single-file linear algebra math library for C++23.
|
||||||
|
*
|
||||||
|
* Copyright 2025 Slendi <slendi@socopon.com>
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
#include <glm/gtc/quaternion.hpp>
|
||||||
|
|
||||||
|
#include <smath/smath.hpp>
|
||||||
|
|
||||||
|
namespace smath
|
||||||
|
{
|
||||||
|
|
||||||
|
template<glm::length_t L, class T, glm::qualifier Q>
|
||||||
|
requires std::is_arithmetic_v<T>
|
||||||
|
struct interop_adapter<glm::vec<L, T, Q>>
|
||||||
|
{
|
||||||
|
using smath_type = Vec<static_cast<std::size_t>(L), T>;
|
||||||
|
|
||||||
|
static constexpr auto to_smath(glm::vec<L, T, Q> const &v) -> smath_type
|
||||||
|
{
|
||||||
|
smath_type out {};
|
||||||
|
for (std::size_t i = 0; i < static_cast<std::size_t>(L); ++i)
|
||||||
|
out[i] = v[static_cast<glm::length_t>(i)];
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr auto from_smath(smath_type const &v) -> glm::vec<L, T, Q>
|
||||||
|
{
|
||||||
|
glm::vec<L, T, Q> out {};
|
||||||
|
for (std::size_t i = 0; i < static_cast<std::size_t>(L); ++i)
|
||||||
|
out[static_cast<glm::length_t>(i)] = v[i];
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<glm::length_t C, glm::length_t R, class T, glm::qualifier Q>
|
||||||
|
requires std::is_arithmetic_v<T>
|
||||||
|
struct interop_adapter<glm::mat<C, R, T, Q>>
|
||||||
|
{
|
||||||
|
using smath_type
|
||||||
|
= Mat<static_cast<std::size_t>(R), static_cast<std::size_t>(C), T>;
|
||||||
|
|
||||||
|
static constexpr auto to_smath(glm::mat<C, R, T, Q> const &m) -> smath_type
|
||||||
|
{
|
||||||
|
smath_type out {};
|
||||||
|
for (std::size_t c = 0; c < static_cast<std::size_t>(C); ++c) {
|
||||||
|
for (std::size_t r = 0; r < static_cast<std::size_t>(R); ++r) {
|
||||||
|
out[r, c] = m[static_cast<glm::length_t>(c)]
|
||||||
|
[static_cast<glm::length_t>(r)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr auto from_smath(smath_type const &m)
|
||||||
|
-> glm::mat<C, R, T, Q>
|
||||||
|
{
|
||||||
|
glm::mat<C, R, T, Q> out {};
|
||||||
|
for (std::size_t c = 0; c < static_cast<std::size_t>(C); ++c) {
|
||||||
|
for (std::size_t r = 0; r < static_cast<std::size_t>(R); ++r) {
|
||||||
|
out[static_cast<glm::length_t>(c)]
|
||||||
|
[static_cast<glm::length_t>(r)]
|
||||||
|
= m[r, c];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T, glm::qualifier Q>
|
||||||
|
requires std::is_arithmetic_v<T>
|
||||||
|
struct interop_adapter<glm::qua<T, Q>>
|
||||||
|
{
|
||||||
|
using smath_type = Quaternion<T>;
|
||||||
|
|
||||||
|
static constexpr auto to_smath(glm::qua<T, Q> const &q) -> smath_type
|
||||||
|
{
|
||||||
|
return { q.x, q.y, q.z, q.w };
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr auto from_smath(smath_type const &q) -> glm::qua<T, Q>
|
||||||
|
{
|
||||||
|
return { q.w(), q.x(), q.y(), q.z() };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace smath
|
||||||
125
include/smath/interop/hmm.hpp
Normal file
125
include/smath/interop/hmm.hpp
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
/*
|
||||||
|
* smath - Single-file linear algebra math library for C++23.
|
||||||
|
*
|
||||||
|
* Copyright 2025 Slendi <slendi@socopon.com>
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <HandmadeMath.h>
|
||||||
|
|
||||||
|
#include <smath/smath.hpp>
|
||||||
|
|
||||||
|
namespace smath
|
||||||
|
{
|
||||||
|
|
||||||
|
template<> struct interop_adapter<HMM_Vec2>
|
||||||
|
{
|
||||||
|
using smath_type = Vec<2, float>;
|
||||||
|
|
||||||
|
static constexpr auto to_smath(HMM_Vec2 const &v) -> smath_type
|
||||||
|
{
|
||||||
|
return { v.X, v.Y };
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr auto from_smath(smath_type const &v) -> HMM_Vec2
|
||||||
|
{
|
||||||
|
return { v.x(), v.y() };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<> struct interop_adapter<HMM_Vec3>
|
||||||
|
{
|
||||||
|
using smath_type = Vec<3, float>;
|
||||||
|
|
||||||
|
static constexpr auto to_smath(HMM_Vec3 const &v) -> smath_type
|
||||||
|
{
|
||||||
|
return { v.X, v.Y, v.Z };
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr auto from_smath(smath_type const &v) -> HMM_Vec3
|
||||||
|
{
|
||||||
|
return { v.x(), v.y(), v.z() };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<> struct interop_adapter<HMM_Vec4>
|
||||||
|
{
|
||||||
|
using smath_type = Vec<4, float>;
|
||||||
|
|
||||||
|
static constexpr auto to_smath(HMM_Vec4 const &v) -> smath_type
|
||||||
|
{
|
||||||
|
return { v.X, v.Y, v.Z, v.W };
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr auto from_smath(smath_type const &v) -> HMM_Vec4
|
||||||
|
{
|
||||||
|
return { v.x(), v.y(), v.z(), v.w() };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<> struct interop_adapter<HMM_Mat4>
|
||||||
|
{
|
||||||
|
using smath_type = Mat<4, 4, float>;
|
||||||
|
|
||||||
|
static constexpr auto to_smath(HMM_Mat4 const &m) -> smath_type
|
||||||
|
{
|
||||||
|
smath_type out {};
|
||||||
|
out[0, 0] = m.Columns[0].X;
|
||||||
|
out[1, 0] = m.Columns[0].Y;
|
||||||
|
out[2, 0] = m.Columns[0].Z;
|
||||||
|
out[3, 0] = m.Columns[0].W;
|
||||||
|
out[0, 1] = m.Columns[1].X;
|
||||||
|
out[1, 1] = m.Columns[1].Y;
|
||||||
|
out[2, 1] = m.Columns[1].Z;
|
||||||
|
out[3, 1] = m.Columns[1].W;
|
||||||
|
out[0, 2] = m.Columns[2].X;
|
||||||
|
out[1, 2] = m.Columns[2].Y;
|
||||||
|
out[2, 2] = m.Columns[2].Z;
|
||||||
|
out[3, 2] = m.Columns[2].W;
|
||||||
|
out[0, 3] = m.Columns[3].X;
|
||||||
|
out[1, 3] = m.Columns[3].Y;
|
||||||
|
out[2, 3] = m.Columns[3].Z;
|
||||||
|
out[3, 3] = m.Columns[3].W;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr auto from_smath(smath_type const &m) -> HMM_Mat4
|
||||||
|
{
|
||||||
|
HMM_Mat4 out {};
|
||||||
|
out.Columns[0] = { m[0, 0], m[1, 0], m[2, 0], m[3, 0] };
|
||||||
|
out.Columns[1] = { m[0, 1], m[1, 1], m[2, 1], m[3, 1] };
|
||||||
|
out.Columns[2] = { m[0, 2], m[1, 2], m[2, 2], m[3, 2] };
|
||||||
|
out.Columns[3] = { m[0, 3], m[1, 3], m[2, 3], m[3, 3] };
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<> struct interop_adapter<HMM_Quat>
|
||||||
|
{
|
||||||
|
using smath_type = Quaternion<float>;
|
||||||
|
|
||||||
|
static constexpr auto to_smath(HMM_Quat const &q) -> smath_type
|
||||||
|
{
|
||||||
|
return { q.X, q.Y, q.Z, q.W };
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr auto from_smath(smath_type const &q) -> HMM_Quat
|
||||||
|
{
|
||||||
|
return { q.x(), q.y(), q.z(), q.w() };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace smath
|
||||||
122
include/smath/interop/raylib.hpp
Normal file
122
include/smath/interop/raylib.hpp
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
/*
|
||||||
|
* smath - Single-file linear algebra math library for C++23.
|
||||||
|
*
|
||||||
|
* Copyright 2025 Slendi <slendi@socopon.com>
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <raylib.h>
|
||||||
|
|
||||||
|
#include <smath/smath.hpp>
|
||||||
|
|
||||||
|
namespace smath
|
||||||
|
{
|
||||||
|
|
||||||
|
template<> struct interop_adapter<Vector2>
|
||||||
|
{
|
||||||
|
using smath_type = Vec<2, float>;
|
||||||
|
|
||||||
|
static constexpr auto to_smath(Vector2 const &v) -> smath_type
|
||||||
|
{
|
||||||
|
return { v.x, v.y };
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr auto from_smath(smath_type const &v) -> Vector2
|
||||||
|
{
|
||||||
|
return { v.x(), v.y() };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<> struct interop_adapter<Vector3>
|
||||||
|
{
|
||||||
|
using smath_type = Vec<3, float>;
|
||||||
|
|
||||||
|
static constexpr auto to_smath(Vector3 const &v) -> smath_type
|
||||||
|
{
|
||||||
|
return { v.x, v.y, v.z };
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr auto from_smath(smath_type const &v) -> Vector3
|
||||||
|
{
|
||||||
|
return { v.x(), v.y(), v.z() };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<> struct interop_adapter<Vector4>
|
||||||
|
{
|
||||||
|
using smath_type = Vec<4, float>;
|
||||||
|
|
||||||
|
static constexpr auto to_smath(Vector4 const &v) -> smath_type
|
||||||
|
{
|
||||||
|
return { v.x, v.y, v.z, v.w };
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr auto from_smath(smath_type const &v) -> Vector4
|
||||||
|
{
|
||||||
|
return { v.x(), v.y(), v.z(), v.w() };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<> struct interop_adapter<Matrix>
|
||||||
|
{
|
||||||
|
using smath_type = Mat<4, 4, float>;
|
||||||
|
|
||||||
|
static constexpr auto to_smath(Matrix const &m) -> smath_type
|
||||||
|
{
|
||||||
|
smath_type out {};
|
||||||
|
out[0, 0] = m.m0;
|
||||||
|
out[1, 0] = m.m1;
|
||||||
|
out[2, 0] = m.m2;
|
||||||
|
out[3, 0] = m.m3;
|
||||||
|
out[0, 1] = m.m4;
|
||||||
|
out[1, 1] = m.m5;
|
||||||
|
out[2, 1] = m.m6;
|
||||||
|
out[3, 1] = m.m7;
|
||||||
|
out[0, 2] = m.m8;
|
||||||
|
out[1, 2] = m.m9;
|
||||||
|
out[2, 2] = m.m10;
|
||||||
|
out[3, 2] = m.m11;
|
||||||
|
out[0, 3] = m.m12;
|
||||||
|
out[1, 3] = m.m13;
|
||||||
|
out[2, 3] = m.m14;
|
||||||
|
out[3, 3] = m.m15;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr auto from_smath(smath_type const &m) -> Matrix
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
m[0, 0],
|
||||||
|
m[0, 1],
|
||||||
|
m[0, 2],
|
||||||
|
m[0, 3],
|
||||||
|
m[1, 0],
|
||||||
|
m[1, 1],
|
||||||
|
m[1, 2],
|
||||||
|
m[1, 3],
|
||||||
|
m[2, 0],
|
||||||
|
m[2, 1],
|
||||||
|
m[2, 2],
|
||||||
|
m[2, 3],
|
||||||
|
m[3, 0],
|
||||||
|
m[3, 1],
|
||||||
|
m[3, 2],
|
||||||
|
m[3, 3],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace smath
|
||||||
63
include/smath/interop/sfml.hpp
Normal file
63
include/smath/interop/sfml.hpp
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* smath - Single-file linear algebra math library for C++23.
|
||||||
|
*
|
||||||
|
* Copyright 2025 Slendi <slendi@socopon.com>
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <SFML/System/Vector2.hpp>
|
||||||
|
#include <SFML/System/Vector3.hpp>
|
||||||
|
|
||||||
|
#include <smath/smath.hpp>
|
||||||
|
|
||||||
|
namespace smath
|
||||||
|
{
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
requires std::is_arithmetic_v<T>
|
||||||
|
struct interop_adapter<sf::Vector2<T>>
|
||||||
|
{
|
||||||
|
using smath_type = Vec<2, T>;
|
||||||
|
|
||||||
|
static constexpr auto to_smath(sf::Vector2<T> const &v) -> smath_type
|
||||||
|
{
|
||||||
|
return { v.x, v.y };
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr auto from_smath(smath_type const &v) -> sf::Vector2<T>
|
||||||
|
{
|
||||||
|
return { v.x(), v.y() };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
requires std::is_arithmetic_v<T>
|
||||||
|
struct interop_adapter<sf::Vector3<T>>
|
||||||
|
{
|
||||||
|
using smath_type = Vec<3, T>;
|
||||||
|
|
||||||
|
static constexpr auto to_smath(sf::Vector3<T> const &v) -> smath_type
|
||||||
|
{
|
||||||
|
return { v.x, v.y, v.z };
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr auto from_smath(smath_type const &v) -> sf::Vector3<T>
|
||||||
|
{
|
||||||
|
return { v.x(), v.y(), v.z() };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace smath
|
||||||
@@ -17,6 +17,7 @@
|
|||||||
*
|
*
|
||||||
* You can define the following macros to change functionality:
|
* You can define the following macros to change functionality:
|
||||||
* - SMATH_IMPLICIT_CONVERSIONS
|
* - SMATH_IMPLICIT_CONVERSIONS
|
||||||
|
* - SMATH_ANGLE_UNIT (=rad, =deg, =turns)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@@ -32,20 +33,29 @@
|
|||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
#ifndef SMATH_ANGLE_UNIT
|
#ifndef SMATH_ANGLE_UNIT
|
||||||
# define SMATH_ANGLE_UNIT rad
|
/**
|
||||||
|
* @brief Angle unit to be used for the actual values. Can be rad, deg, or
|
||||||
|
* turns.
|
||||||
|
*/
|
||||||
|
#define SMATH_ANGLE_UNIT rad
|
||||||
#endif // SMATH_ANGLE_UNIT
|
#endif // SMATH_ANGLE_UNIT
|
||||||
|
|
||||||
namespace smath {
|
namespace smath
|
||||||
|
{
|
||||||
|
|
||||||
template<std::size_t N, typename T>
|
template<std::size_t N, typename T>
|
||||||
requires std::is_arithmetic_v<T> struct Vec;
|
requires std::is_arithmetic_v<T>
|
||||||
|
struct Vec;
|
||||||
|
|
||||||
namespace detail {
|
namespace detail
|
||||||
|
{
|
||||||
|
|
||||||
|
/// \cond DO_NOT_DOCUMENT
|
||||||
#define SMATH_STR(x) #x
|
#define SMATH_STR(x) #x
|
||||||
#define SMATH_XSTR(x) SMATH_STR(x)
|
#define SMATH_XSTR(x) SMATH_STR(x)
|
||||||
|
/// \endcond
|
||||||
|
|
||||||
consteval bool streq(const char *a, const char *b)
|
consteval auto streq(const char *a, const char *b) -> bool
|
||||||
{
|
{
|
||||||
for (;; ++a, ++b) {
|
for (;; ++a, ++b) {
|
||||||
if (*a != *b)
|
if (*a != *b)
|
||||||
@@ -55,13 +65,14 @@ consteval bool streq(const char *a, const char *b)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class AngularUnit {
|
enum class AngularUnit
|
||||||
|
{
|
||||||
Radians,
|
Radians,
|
||||||
Degrees,
|
Degrees,
|
||||||
Turns,
|
Turns,
|
||||||
};
|
};
|
||||||
|
|
||||||
consteval std::optional<AngularUnit> parse_unit(char const *s)
|
consteval auto parse_unit(char const *s) -> std::optional<AngularUnit>
|
||||||
{
|
{
|
||||||
if (streq(s, "rad"))
|
if (streq(s, "rad"))
|
||||||
return AngularUnit::Radians;
|
return AngularUnit::Radians;
|
||||||
@@ -76,7 +87,8 @@ constexpr auto SMATH_ANGLE_UNIT_ID = parse_unit(SMATH_XSTR(SMATH_ANGLE_UNIT));
|
|||||||
static_assert(SMATH_ANGLE_UNIT_ID != std::nullopt,
|
static_assert(SMATH_ANGLE_UNIT_ID != std::nullopt,
|
||||||
"Invalid SMATH_ANGLE_UNIT. Should be rad, deg, or turns.");
|
"Invalid SMATH_ANGLE_UNIT. Should be rad, deg, or turns.");
|
||||||
|
|
||||||
template<std::size_t N> struct FixedString {
|
template<std::size_t N> struct FixedString
|
||||||
|
{
|
||||||
char data[N] {};
|
char data[N] {};
|
||||||
static constexpr std::size_t size = N - 1;
|
static constexpr std::size_t size = N - 1;
|
||||||
constexpr FixedString(char const (&s)[N])
|
constexpr FixedString(char const (&s)[N])
|
||||||
@@ -86,8 +98,10 @@ template<std::size_t N> struct FixedString {
|
|||||||
}
|
}
|
||||||
constexpr char operator[](std::size_t i) const { return data[i]; }
|
constexpr char operator[](std::size_t i) const { return data[i]; }
|
||||||
};
|
};
|
||||||
template<class X> struct is_Vec : std::false_type { };
|
template<class X> struct is_Vec : std::false_type
|
||||||
template<std::size_t M, class U> struct is_Vec<Vec<M, U>> : std::true_type { };
|
{ };
|
||||||
|
template<std::size_t M, class U> struct is_Vec<Vec<M, U>> : std::true_type
|
||||||
|
{ };
|
||||||
template<class X>
|
template<class X>
|
||||||
inline constexpr bool is_Vec_v = is_Vec<std::remove_cvref_t<X>>::value;
|
inline constexpr bool is_Vec_v = is_Vec<std::remove_cvref_t<X>>::value;
|
||||||
template<class X>
|
template<class X>
|
||||||
@@ -95,7 +109,8 @@ inline constexpr bool is_scalar_v
|
|||||||
= std::is_arithmetic_v<std::remove_cvref_t<X>>;
|
= std::is_arithmetic_v<std::remove_cvref_t<X>>;
|
||||||
template<class X> struct Vec_size;
|
template<class X> struct Vec_size;
|
||||||
template<std::size_t M, class U>
|
template<std::size_t M, class U>
|
||||||
struct Vec_size<Vec<M, U>> : std::integral_constant<std::size_t, M> { };
|
struct Vec_size<Vec<M, U>> : std::integral_constant<std::size_t, M>
|
||||||
|
{ };
|
||||||
|
|
||||||
template<class T> constexpr auto pack_unorm8(T v) -> std::uint8_t
|
template<class T> constexpr auto pack_unorm8(T v) -> std::uint8_t
|
||||||
{
|
{
|
||||||
@@ -144,9 +159,16 @@ template<class T> constexpr auto unpack_snorm8(std::int8_t b) -> T
|
|||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
template<std::size_t N, typename T = float>
|
template<std::size_t N, typename T = float>
|
||||||
requires std::is_arithmetic_v<T> struct Vec : std::array<T, N> {
|
requires std::is_arithmetic_v<T>
|
||||||
|
/**
|
||||||
|
* @brief Fixed-size arithmetic vector.
|
||||||
|
* @tparam N Number of components.
|
||||||
|
* @tparam T Component type.
|
||||||
|
*/
|
||||||
|
struct Vec : std::array<T, N>
|
||||||
|
{
|
||||||
private:
|
private:
|
||||||
template<class X> static consteval std::size_t extent()
|
template<class X> static consteval auto extent() -> std::size_t
|
||||||
{
|
{
|
||||||
if constexpr (detail::is_Vec_v<X>)
|
if constexpr (detail::is_Vec_v<X>)
|
||||||
return detail::Vec_size<std::remove_cvref_t<X>>::value;
|
return detail::Vec_size<std::remove_cvref_t<X>>::value;
|
||||||
@@ -155,19 +177,24 @@ private:
|
|||||||
else
|
else
|
||||||
return 0; // Should be unreachable
|
return 0; // Should be unreachable
|
||||||
}
|
}
|
||||||
template<class... Args> static consteval std::size_t total_extent()
|
template<class... Args> static consteval auto total_extent() -> std::size_t
|
||||||
{
|
{
|
||||||
return (extent<Args>() + ... + 0);
|
return (extent<Args>() + ... + 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Constructors
|
// Constructors
|
||||||
|
/** @brief Constructs a zero-initialized vector. */
|
||||||
constexpr Vec() noexcept
|
constexpr Vec() noexcept
|
||||||
{
|
{
|
||||||
for (auto &v : *this)
|
for (auto &v : *this)
|
||||||
v = T(0);
|
v = T(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Fills all components with the same scalar.
|
||||||
|
* @param s Scalar value assigned to every component.
|
||||||
|
*/
|
||||||
explicit constexpr Vec(T const &s) noexcept
|
explicit constexpr Vec(T const &s) noexcept
|
||||||
{
|
{
|
||||||
for (auto &v : *this)
|
for (auto &v : *this)
|
||||||
@@ -178,6 +205,10 @@ public:
|
|||||||
requires((detail::is_scalar_v<Args> || detail::is_Vec_v<Args>) && ...)
|
requires((detail::is_scalar_v<Args> || detail::is_Vec_v<Args>) && ...)
|
||||||
&& (total_extent<Args...>() == N)
|
&& (total_extent<Args...>() == N)
|
||||||
&& (!(sizeof...(Args) == 1 && (detail::is_Vec_v<Args> && ...)))
|
&& (!(sizeof...(Args) == 1 && (detail::is_Vec_v<Args> && ...)))
|
||||||
|
/**
|
||||||
|
* @brief Constructs from scalars and/or vectors whose flattened extent is
|
||||||
|
* N.
|
||||||
|
*/
|
||||||
constexpr Vec(Args &&...args) noexcept
|
constexpr Vec(Args &&...args) noexcept
|
||||||
{
|
{
|
||||||
std::size_t i = 0;
|
std::size_t i = 0;
|
||||||
@@ -187,13 +218,12 @@ public:
|
|||||||
// Member accesses
|
// Member accesses
|
||||||
// NOTE: This can (probably) be improved with C++26 reflection in the
|
// NOTE: This can (probably) be improved with C++26 reflection in the
|
||||||
// future.
|
// future.
|
||||||
|
|
||||||
|
/// \cond DO_NOT_DOCUMENT
|
||||||
#define VEC_ACC(component, req, idx) \
|
#define VEC_ACC(component, req, idx) \
|
||||||
constexpr auto component() noexcept -> T & \
|
constexpr auto component() noexcept -> T &requires(N >= req) { \
|
||||||
requires(N >= req) \
|
|
||||||
{ \
|
|
||||||
return (*this)[idx]; \
|
return (*this)[idx]; \
|
||||||
} \
|
} constexpr auto component() const->T const & \
|
||||||
constexpr auto component() const -> T const & \
|
|
||||||
requires(N >= req) \
|
requires(N >= req) \
|
||||||
{ \
|
{ \
|
||||||
return (*this)[idx]; \
|
return (*this)[idx]; \
|
||||||
@@ -217,6 +247,7 @@ public:
|
|||||||
VEC_ACC(u, 1, 0)
|
VEC_ACC(u, 1, 0)
|
||||||
VEC_ACC(v, 2, 1)
|
VEC_ACC(v, 2, 1)
|
||||||
#undef VEC_ACC
|
#undef VEC_ACC
|
||||||
|
/// \endcond
|
||||||
|
|
||||||
template<class... Args, std::size_t... Is>
|
template<class... Args, std::size_t... Is>
|
||||||
constexpr void unpack_impl(
|
constexpr void unpack_impl(
|
||||||
@@ -225,7 +256,11 @@ public:
|
|||||||
((args = (*this)[Is]), ...);
|
((args = (*this)[Is]), ...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class... Args> constexpr void unpack(Args &...args) noexcept
|
template<class... Args>
|
||||||
|
/**
|
||||||
|
* @brief Unpacks components into output references.
|
||||||
|
*/
|
||||||
|
constexpr auto unpack(Args &...args) noexcept -> void
|
||||||
{
|
{
|
||||||
unpack_impl(std::index_sequence_for<Args...> {}, args...);
|
unpack_impl(std::index_sequence_for<Args...> {}, args...);
|
||||||
}
|
}
|
||||||
@@ -261,6 +296,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Members
|
// Members
|
||||||
|
/// \cond DO_NOT_DOCUMENT
|
||||||
#define VEC_OP(op) \
|
#define VEC_OP(op) \
|
||||||
constexpr auto operator op(Vec const &rhs) const noexcept -> Vec \
|
constexpr auto operator op(Vec const &rhs) const noexcept -> Vec \
|
||||||
{ \
|
{ \
|
||||||
@@ -284,13 +320,13 @@ public:
|
|||||||
VEC_OP(/)
|
VEC_OP(/)
|
||||||
#undef VEC_OP
|
#undef VEC_OP
|
||||||
#define VEC_OP_ASSIGN(sym) \
|
#define VEC_OP_ASSIGN(sym) \
|
||||||
constexpr Vec &operator sym## = (Vec const &rhs) noexcept \
|
constexpr Vec &operator sym##=(Vec const &rhs) noexcept \
|
||||||
{ \
|
{ \
|
||||||
for (std::size_t i = 0; i < N; ++i) \
|
for (std::size_t i = 0; i < N; ++i) \
|
||||||
(*this)[i] sym## = rhs[i]; \
|
(*this)[i] sym## = rhs[i]; \
|
||||||
return *this; \
|
return *this; \
|
||||||
} \
|
} \
|
||||||
constexpr Vec &operator sym## = (T const &s) noexcept \
|
constexpr Vec &operator sym##=(T const &s) noexcept \
|
||||||
{ \
|
{ \
|
||||||
for (std::size_t i = 0; i < N; ++i) \
|
for (std::size_t i = 0; i < N; ++i) \
|
||||||
(*this)[i] sym## = s; \
|
(*this)[i] sym## = s; \
|
||||||
@@ -301,6 +337,7 @@ public:
|
|||||||
VEC_OP_ASSIGN(*)
|
VEC_OP_ASSIGN(*)
|
||||||
VEC_OP_ASSIGN(/)
|
VEC_OP_ASSIGN(/)
|
||||||
#undef VEC_OP_ASSIGN
|
#undef VEC_OP_ASSIGN
|
||||||
|
/// \endcond
|
||||||
|
|
||||||
constexpr auto operator==(Vec const &v) const noexcept -> bool
|
constexpr auto operator==(Vec const &v) const noexcept -> bool
|
||||||
{
|
{
|
||||||
@@ -315,6 +352,7 @@ public:
|
|||||||
return !(*this == v);
|
return !(*this == v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @brief Returns Euclidean magnitude. */
|
||||||
constexpr auto magnitude() const noexcept -> T
|
constexpr auto magnitude() const noexcept -> T
|
||||||
requires std::is_floating_point_v<T>
|
requires std::is_floating_point_v<T>
|
||||||
{
|
{
|
||||||
@@ -323,6 +361,7 @@ public:
|
|||||||
total += v * v;
|
total += v * v;
|
||||||
return std::sqrt(total);
|
return std::sqrt(total);
|
||||||
}
|
}
|
||||||
|
/** @brief Alias for magnitude(). */
|
||||||
constexpr auto length() const noexcept -> T
|
constexpr auto length() const noexcept -> T
|
||||||
requires std::is_floating_point_v<T>
|
requires std::is_floating_point_v<T>
|
||||||
{
|
{
|
||||||
@@ -331,6 +370,9 @@ public:
|
|||||||
|
|
||||||
template<typename U = T>
|
template<typename U = T>
|
||||||
requires std::is_floating_point_v<U>
|
requires std::is_floating_point_v<U>
|
||||||
|
/**
|
||||||
|
* @brief Normalizes with zero fallback for very small magnitudes.
|
||||||
|
*/
|
||||||
constexpr auto normalized_safe(U eps = EPS_DEFAULT) const noexcept -> Vec
|
constexpr auto normalized_safe(U eps = EPS_DEFAULT) const noexcept -> Vec
|
||||||
{
|
{
|
||||||
auto m = magnitude();
|
auto m = magnitude();
|
||||||
@@ -338,27 +380,32 @@ public:
|
|||||||
}
|
}
|
||||||
template<typename U = T>
|
template<typename U = T>
|
||||||
requires std::is_floating_point_v<U>
|
requires std::is_floating_point_v<U>
|
||||||
|
/** @brief Alias for normalized_safe(). */
|
||||||
constexpr auto normalize_safe(U eps = EPS_DEFAULT) const noexcept -> Vec
|
constexpr auto normalize_safe(U eps = EPS_DEFAULT) const noexcept -> Vec
|
||||||
{
|
{
|
||||||
return normalized_safe(eps);
|
return normalized_safe(eps);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @brief Returns normalized vector; undefined for zero magnitude. */
|
||||||
[[nodiscard]] constexpr auto normalized() noexcept -> Vec<N, T>
|
[[nodiscard]] constexpr auto normalized() noexcept -> Vec<N, T>
|
||||||
requires std::is_floating_point_v<T>
|
requires std::is_floating_point_v<T>
|
||||||
{
|
{
|
||||||
return (*this) / this->magnitude();
|
return (*this) / this->magnitude();
|
||||||
}
|
}
|
||||||
|
/** @brief Alias for normalized(). */
|
||||||
[[nodiscard]] constexpr auto normalize() noexcept -> Vec<N, T>
|
[[nodiscard]] constexpr auto normalize() noexcept -> Vec<N, T>
|
||||||
requires std::is_floating_point_v<T>
|
requires std::is_floating_point_v<T>
|
||||||
{
|
{
|
||||||
return this->normalized();
|
return this->normalized();
|
||||||
}
|
}
|
||||||
|
/** @brief Alias for normalized(). */
|
||||||
[[nodiscard]] constexpr auto unit() noexcept -> Vec<N, T>
|
[[nodiscard]] constexpr auto unit() noexcept -> Vec<N, T>
|
||||||
requires std::is_floating_point_v<T>
|
requires std::is_floating_point_v<T>
|
||||||
{
|
{
|
||||||
return this->normalized();
|
return this->normalized();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @brief Dot product with `other`. */
|
||||||
[[nodiscard]] constexpr auto dot(Vec<N, T> const &other) const noexcept -> T
|
[[nodiscard]] constexpr auto dot(Vec<N, T> const &other) const noexcept -> T
|
||||||
{
|
{
|
||||||
T res = 0;
|
T res = 0;
|
||||||
@@ -369,6 +416,13 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static constexpr T EPS_DEFAULT = T(1e-6);
|
static constexpr T EPS_DEFAULT = T(1e-6);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Approximate equality with per-component absolute epsilon.
|
||||||
|
* @param rhs Vec to compare against.
|
||||||
|
* @param eps Absolute tolerance per component.
|
||||||
|
* @return `true` when all components are approximately equal.
|
||||||
|
*/
|
||||||
template<class U = T>
|
template<class U = T>
|
||||||
requires std::is_floating_point_v<U>
|
requires std::is_floating_point_v<U>
|
||||||
[[nodiscard]] constexpr auto approx_equal(
|
[[nodiscard]] constexpr auto approx_equal(
|
||||||
@@ -382,6 +436,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<class U = T>
|
template<class U = T>
|
||||||
|
/** @brief Magnitude computed in promoted type `U` (or `double`). */
|
||||||
constexpr auto magnitude_promoted() const noexcept
|
constexpr auto magnitude_promoted() const noexcept
|
||||||
requires std::is_floating_point_v<T>
|
requires std::is_floating_point_v<T>
|
||||||
{
|
{
|
||||||
@@ -393,19 +448,25 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename U = T>
|
template<typename U = T>
|
||||||
requires(N == 3) constexpr auto cross(Vec const &r) const noexcept -> Vec
|
requires(N == 3)
|
||||||
|
/** @brief 3D cross product. */
|
||||||
|
constexpr auto cross(Vec const &r) const noexcept -> Vec
|
||||||
{
|
{
|
||||||
return { (*this)[1] * r[2] - (*this)[2] * r[1],
|
return {
|
||||||
|
(*this)[1] * r[2] - (*this)[2] * r[1],
|
||||||
(*this)[2] * r[0] - (*this)[0] * r[2],
|
(*this)[2] * r[0] - (*this)[0] * r[2],
|
||||||
(*this)[0] * r[1] - (*this)[1] * r[0] };
|
(*this)[0] * r[1] - (*this)[1] * r[0],
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @brief Distance between this vector and `r`. */
|
||||||
constexpr auto distance(Vec const &r) const noexcept -> T
|
constexpr auto distance(Vec const &r) const noexcept -> T
|
||||||
requires std::is_floating_point_v<T>
|
requires std::is_floating_point_v<T>
|
||||||
{
|
{
|
||||||
return (*this - r).magnitude();
|
return (*this - r).magnitude();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @brief Projection of this vector onto `n`. */
|
||||||
constexpr auto project_onto(Vec const &n) const noexcept -> Vec
|
constexpr auto project_onto(Vec const &n) const noexcept -> Vec
|
||||||
requires std::is_floating_point_v<T>
|
requires std::is_floating_point_v<T>
|
||||||
{
|
{
|
||||||
@@ -425,8 +486,8 @@ public:
|
|||||||
|
|
||||||
template<class U>
|
template<class U>
|
||||||
requires(std::is_arithmetic_v<U> && N >= 1)
|
requires(std::is_arithmetic_v<U> && N >= 1)
|
||||||
constexpr explicit(!std::is_convertible_v<T, U>)
|
constexpr explicit(
|
||||||
operator Vec<N, U>() const noexcept
|
!std::is_convertible_v<T, U>) operator Vec<N, U>() const noexcept
|
||||||
{
|
{
|
||||||
Vec<N, U> r {};
|
Vec<N, U> r {};
|
||||||
for (std::size_t i = 0; i < N; ++i)
|
for (std::size_t i = 0; i < N; ++i)
|
||||||
@@ -444,26 +505,26 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
constexpr void fill_one(std::size_t &i, T const &v) noexcept
|
constexpr auto fill_one(std::size_t &i, T const &v) noexcept -> void
|
||||||
{
|
{
|
||||||
(*this)[i++] = v;
|
(*this)[i++] = v;
|
||||||
}
|
}
|
||||||
#ifdef SMATH_IMPLICIT_CONVERSIONS
|
#ifdef SMATH_IMPLICIT_CONVERSIONS
|
||||||
template<class U>
|
template<class U>
|
||||||
requires std::is_arithmetic_v<U> && (!std::is_same_v<U, T>)constexpr void
|
requires std::is_arithmetic_v<U> && (!std::is_same_v<U, T>)
|
||||||
fill_one(std::size_t &i, const U &v) noexcept
|
constexpr auto fill_one(std::size_t &i, const U &v) noexcept -> void
|
||||||
{
|
{
|
||||||
(*this)[i++] = static_cast<T>(v);
|
(*this)[i++] = static_cast<T>(v);
|
||||||
}
|
}
|
||||||
template<std::size_t M, class U>
|
template<std::size_t M, class U>
|
||||||
constexpr void fill_one(std::size_t &i, Vec<M, U> const &v) noexcept
|
constexpr auto fill_one(std::size_t &i, Vec<M, U> const &v) noexcept -> void
|
||||||
{
|
{
|
||||||
for (std::size_t k = 0; k < M; ++k)
|
for (std::size_t k = 0; k < M; ++k)
|
||||||
(*this)[i++] = static_cast<T>(v[k]);
|
(*this)[i++] = static_cast<T>(v[k]);
|
||||||
}
|
}
|
||||||
#endif // SMATH_IMPLICIT_CONVERSIONS
|
#endif // SMATH_IMPLICIT_CONVERSIONS
|
||||||
template<std::size_t M>
|
template<std::size_t M>
|
||||||
constexpr void fill_one(std::size_t &i, const Vec<M, T> &v) noexcept
|
constexpr auto fill_one(std::size_t &i, const Vec<M, T> &v) noexcept -> void
|
||||||
{
|
{
|
||||||
for (std::size_t k = 0; k < M; ++k)
|
for (std::size_t k = 0; k < M; ++k)
|
||||||
(*this)[i++] = static_cast<T>(v[k]);
|
(*this)[i++] = static_cast<T>(v[k]);
|
||||||
@@ -495,9 +556,15 @@ constexpr T const &&get(Vec<N, T> const &&v) noexcept
|
|||||||
|
|
||||||
template<std::size_t N, typename T = float>
|
template<std::size_t N, typename T = float>
|
||||||
requires std::is_arithmetic_v<T>
|
requires std::is_arithmetic_v<T>
|
||||||
|
/**
|
||||||
|
* @brief Return type used by swizzle operations.
|
||||||
|
*
|
||||||
|
* Produces `T` when `N == 1`, otherwise `Vec<N, T>`.
|
||||||
|
*/
|
||||||
using VecOrScalar = std::conditional_t<N == 1, T, Vec<N, T>>;
|
using VecOrScalar = std::conditional_t<N == 1, T, Vec<N, T>>;
|
||||||
|
|
||||||
namespace detail {
|
namespace detail
|
||||||
|
{
|
||||||
|
|
||||||
consteval auto char_to_idx(char c) -> std::size_t
|
consteval auto char_to_idx(char c) -> std::size_t
|
||||||
{
|
{
|
||||||
@@ -567,22 +634,39 @@ concept ValidSwizzle
|
|||||||
|
|
||||||
template<detail::FixedString S, std::size_t N, typename T>
|
template<detail::FixedString S, std::size_t N, typename T>
|
||||||
requires detail::ValidSwizzle<S, N>
|
requires detail::ValidSwizzle<S, N>
|
||||||
|
/**
|
||||||
|
* @brief Compile-time swizzle selection.
|
||||||
|
* @tparam S Swizzle pattern like `"xy"`, `"rgba"`, or `"stp"`.
|
||||||
|
* @param v Source vector.
|
||||||
|
* @return Swizzled scalar/vector according to `S`.
|
||||||
|
*/
|
||||||
constexpr auto swizzle(Vec<N, T> const &v) -> VecOrScalar<S.size, T>
|
constexpr auto swizzle(Vec<N, T> const &v) -> VecOrScalar<S.size, T>
|
||||||
{
|
{
|
||||||
return detail::swizzle_impl<S>(v, std::make_index_sequence<S.size> {});
|
return detail::swizzle_impl<S>(v, std::make_index_sequence<S.size> {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @brief 2D float vector alias. */
|
||||||
using Vec2 = Vec<2>;
|
using Vec2 = Vec<2>;
|
||||||
|
/** @brief 3D float vector alias. */
|
||||||
using Vec3 = Vec<3>;
|
using Vec3 = Vec<3>;
|
||||||
|
/** @brief 4D float vector alias. */
|
||||||
using Vec4 = Vec<4>;
|
using Vec4 = Vec<4>;
|
||||||
|
|
||||||
|
/** @brief 2D double vector alias. */
|
||||||
using Vec2d = Vec<2, double>;
|
using Vec2d = Vec<2, double>;
|
||||||
|
/** @brief 3D double vector alias. */
|
||||||
using Vec3d = Vec<3, double>;
|
using Vec3d = Vec<3, double>;
|
||||||
|
/** @brief 4D double vector alias. */
|
||||||
using Vec4d = Vec<4, double>;
|
using Vec4d = Vec<4, double>;
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
using angle_ret_t = std::conditional_t<std::is_same_v<T, float>, float, double>;
|
using angle_ret_t = std::conditional_t<std::is_same_v<T, float>, float, double>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Convert degrees to the configured angle unit.
|
||||||
|
* @param value Angle in degrees.
|
||||||
|
* @return Angle in `SMATH_ANGLE_UNIT`.
|
||||||
|
*/
|
||||||
template<class T> constexpr auto deg(T value)
|
template<class T> constexpr auto deg(T value)
|
||||||
{
|
{
|
||||||
using R = angle_ret_t<T>;
|
using R = angle_ret_t<T>;
|
||||||
@@ -597,6 +681,11 @@ template<class T> constexpr auto deg(T value)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Convert radians to the configured angle unit.
|
||||||
|
* @param value Angle in radians.
|
||||||
|
* @return Angle in `SMATH_ANGLE_UNIT`.
|
||||||
|
*/
|
||||||
template<class T> constexpr auto rad(T value)
|
template<class T> constexpr auto rad(T value)
|
||||||
{
|
{
|
||||||
using R = angle_ret_t<T>;
|
using R = angle_ret_t<T>;
|
||||||
@@ -612,6 +701,11 @@ template<class T> constexpr auto rad(T value)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Convert turns to the configured angle unit.
|
||||||
|
* @param value Angle in turns.
|
||||||
|
* @return Angle in `SMATH_ANGLE_UNIT`.
|
||||||
|
*/
|
||||||
template<class T> constexpr auto turns(T value)
|
template<class T> constexpr auto turns(T value)
|
||||||
{
|
{
|
||||||
using R = angle_ret_t<T>;
|
using R = angle_ret_t<T>;
|
||||||
@@ -627,14 +721,22 @@ template<class T> constexpr auto turns(T value)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
template<std::size_t R, std::size_t C, typename T>
|
template<std::size_t R, std::size_t C, typename T>
|
||||||
requires std::is_arithmetic_v<T> struct Mat;
|
requires std::is_arithmetic_v<T>
|
||||||
|
struct Mat;
|
||||||
|
|
||||||
template<class T> struct Quaternion : Vec<4, T> {
|
/**
|
||||||
|
* @brief Quaternion represented as `(x, y, z, w)`.
|
||||||
|
* @tparam T Component type.
|
||||||
|
*/
|
||||||
|
template<class T> struct Quaternion : Vec<4, T>
|
||||||
|
{
|
||||||
using Base = Vec<4, T>;
|
using Base = Vec<4, T>;
|
||||||
using Base::Base;
|
using Base::Base;
|
||||||
using Base::operator=;
|
using Base::operator=;
|
||||||
|
|
||||||
|
/** @brief Returns this quaternion as its vector base type. */
|
||||||
constexpr Base &vec() noexcept { return *this; }
|
constexpr Base &vec() noexcept { return *this; }
|
||||||
|
/** @brief Returns this quaternion as its vector base type. */
|
||||||
constexpr Base const &vec() const noexcept { return *this; }
|
constexpr Base const &vec() const noexcept { return *this; }
|
||||||
|
|
||||||
constexpr T &x() noexcept { return Base::x(); }
|
constexpr T &x() noexcept { return Base::x(); }
|
||||||
@@ -646,6 +748,11 @@ template<class T> struct Quaternion : Vec<4, T> {
|
|||||||
constexpr T &w() noexcept { return Base::w(); }
|
constexpr T &w() noexcept { return Base::w(); }
|
||||||
constexpr T const &w() const noexcept { return Base::w(); }
|
constexpr T const &w() const noexcept { return Base::w(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Hamilton product.
|
||||||
|
* @param rhs Right-hand quaternion.
|
||||||
|
* @return Product quaternion.
|
||||||
|
*/
|
||||||
constexpr auto operator*(Quaternion const &rhs) const noexcept -> Quaternion
|
constexpr auto operator*(Quaternion const &rhs) const noexcept -> Quaternion
|
||||||
{
|
{
|
||||||
Quaternion r;
|
Quaternion r;
|
||||||
@@ -663,6 +770,10 @@ template<class T> struct Quaternion : Vec<4, T> {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Converts this quaternion to a 4x4 rotation matrix.
|
||||||
|
* @return Homogeneous rotation matrix.
|
||||||
|
*/
|
||||||
[[nodiscard]] constexpr auto as_matrix() const noexcept -> Mat<4, 4, T>
|
[[nodiscard]] constexpr auto as_matrix() const noexcept -> Mat<4, 4, T>
|
||||||
{
|
{
|
||||||
auto const xx = x() * x();
|
auto const xx = x() * x();
|
||||||
@@ -683,6 +794,12 @@ template<class T> struct Quaternion : Vec<4, T> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Builds a quaternion from axis-angle input.
|
||||||
|
* @param axis Rotation axis.
|
||||||
|
* @param angle Rotation angle in configured angle units.
|
||||||
|
* @return Quaternion representing the rotation.
|
||||||
|
*/
|
||||||
[[nodiscard]] static constexpr auto from_axis_angle(
|
[[nodiscard]] static constexpr auto from_axis_angle(
|
||||||
Vec<3, T> const &axis, T const angle) noexcept -> Quaternion
|
Vec<3, T> const &axis, T const angle) noexcept -> Quaternion
|
||||||
{
|
{
|
||||||
@@ -702,6 +819,10 @@ template<class T> struct Quaternion : Vec<4, T> {
|
|||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
requires std::is_floating_point_v<T>
|
requires std::is_floating_point_v<T>
|
||||||
|
/**
|
||||||
|
* @brief Packs `[0, 1]` RGBA values into 4x8-bit UNORM.
|
||||||
|
* @return Packed 32-bit value in RGBA byte order.
|
||||||
|
*/
|
||||||
[[nodiscard]] constexpr auto pack_unorm4x8(Vec<4, T> const &v) -> std::uint32_t
|
[[nodiscard]] constexpr auto pack_unorm4x8(Vec<4, T> const &v) -> std::uint32_t
|
||||||
{
|
{
|
||||||
std::uint32_t r = detail::pack_unorm8(v[0]);
|
std::uint32_t r = detail::pack_unorm8(v[0]);
|
||||||
@@ -714,6 +835,10 @@ requires std::is_floating_point_v<T>
|
|||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
requires std::is_floating_point_v<T>
|
requires std::is_floating_point_v<T>
|
||||||
|
/**
|
||||||
|
* @brief Packs `[-1, 1]` RGBA values into 4x8-bit SNORM.
|
||||||
|
* @return Packed 32-bit value in RGBA byte order.
|
||||||
|
*/
|
||||||
[[nodiscard]] constexpr auto pack_snorm4x8(Vec<4, T> const &v) -> std::uint32_t
|
[[nodiscard]] constexpr auto pack_snorm4x8(Vec<4, T> const &v) -> std::uint32_t
|
||||||
{
|
{
|
||||||
std::uint32_t r = static_cast<std::uint8_t>(detail::pack_snorm8(v[0]));
|
std::uint32_t r = static_cast<std::uint8_t>(detail::pack_snorm8(v[0]));
|
||||||
@@ -726,6 +851,10 @@ requires std::is_floating_point_v<T>
|
|||||||
|
|
||||||
template<class T = float>
|
template<class T = float>
|
||||||
requires std::is_floating_point_v<T>
|
requires std::is_floating_point_v<T>
|
||||||
|
/**
|
||||||
|
* @brief Unpacks a 4x8-bit UNORM RGBA value.
|
||||||
|
* @return RGBA vector with components in `[0, 1]`.
|
||||||
|
*/
|
||||||
[[nodiscard]] constexpr auto unpack_unorm4x8(std::uint32_t packed) -> Vec<4, T>
|
[[nodiscard]] constexpr auto unpack_unorm4x8(std::uint32_t packed) -> Vec<4, T>
|
||||||
{
|
{
|
||||||
std::uint8_t r = static_cast<std::uint8_t>(packed & 0xFFu);
|
std::uint8_t r = static_cast<std::uint8_t>(packed & 0xFFu);
|
||||||
@@ -743,6 +872,10 @@ requires std::is_floating_point_v<T>
|
|||||||
|
|
||||||
template<class T = float>
|
template<class T = float>
|
||||||
requires std::is_floating_point_v<T>
|
requires std::is_floating_point_v<T>
|
||||||
|
/**
|
||||||
|
* @brief Unpacks a 4x8-bit SNORM RGBA value.
|
||||||
|
* @return RGBA vector with components in `[-1, 1]`.
|
||||||
|
*/
|
||||||
[[nodiscard]] constexpr auto unpack_snorm4x8(std::uint32_t packed) -> Vec<4, T>
|
[[nodiscard]] constexpr auto unpack_snorm4x8(std::uint32_t packed) -> Vec<4, T>
|
||||||
{
|
{
|
||||||
std::int8_t r = static_cast<std::int8_t>(packed & 0xFFu);
|
std::int8_t r = static_cast<std::int8_t>(packed & 0xFFu);
|
||||||
@@ -759,7 +892,15 @@ requires std::is_floating_point_v<T>
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t R, std::size_t C, typename T = float>
|
template<std::size_t R, std::size_t C, typename T = float>
|
||||||
requires std::is_arithmetic_v<T> struct Mat : std::array<Vec<R, T>, C> {
|
requires std::is_arithmetic_v<T>
|
||||||
|
/**
|
||||||
|
* @brief Column-major matrix with `R` rows and `C` columns.
|
||||||
|
* @tparam R Row count.
|
||||||
|
* @tparam C Column count.
|
||||||
|
* @tparam T Scalar type.
|
||||||
|
*/
|
||||||
|
struct Mat : std::array<Vec<R, T>, C>
|
||||||
|
{
|
||||||
using Base = std::array<Vec<R, T>, C>;
|
using Base = std::array<Vec<R, T>, C>;
|
||||||
using Base::operator[];
|
using Base::operator[];
|
||||||
|
|
||||||
@@ -774,12 +915,17 @@ requires std::is_arithmetic_v<T> struct Mat : std::array<Vec<R, T>, C> {
|
|||||||
return col(column)[row];
|
return col(column)[row];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @brief Constructs a zero matrix. */
|
||||||
constexpr Mat() noexcept
|
constexpr Mat() noexcept
|
||||||
{
|
{
|
||||||
for (auto &col : *this)
|
for (auto &col : *this)
|
||||||
col = Vec<R, T> {};
|
col = Vec<R, T> {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Constructs a diagonal matrix.
|
||||||
|
* @param diag Value used for every diagonal component.
|
||||||
|
*/
|
||||||
constexpr explicit Mat(T const &diag) noexcept
|
constexpr explicit Mat(T const &diag) noexcept
|
||||||
requires(R == C)
|
requires(R == C)
|
||||||
{
|
{
|
||||||
@@ -792,10 +938,12 @@ requires std::is_arithmetic_v<T> struct Mat : std::array<Vec<R, T>, C> {
|
|||||||
template<typename... Cols>
|
template<typename... Cols>
|
||||||
requires(sizeof...(Cols) == C
|
requires(sizeof...(Cols) == C
|
||||||
&& (std::same_as<std::remove_cvref_t<Cols>, Vec<R, T>> && ...))
|
&& (std::same_as<std::remove_cvref_t<Cols>, Vec<R, T>> && ...))
|
||||||
constexpr Mat(Cols const &...cols) noexcept
|
/**
|
||||||
: Base { cols... }
|
* @brief Constructs from explicit column vectors.
|
||||||
{
|
* @param cols Columns in column-major order.
|
||||||
}
|
*/
|
||||||
|
constexpr Mat(Cols const &...cols) noexcept : Base { cols... }
|
||||||
|
{ }
|
||||||
|
|
||||||
constexpr auto col(std::size_t j) noexcept -> Vec<R, T> &
|
constexpr auto col(std::size_t j) noexcept -> Vec<R, T> &
|
||||||
{
|
{
|
||||||
@@ -890,6 +1038,13 @@ requires std::is_arithmetic_v<T> struct Mat : std::array<Vec<R, T>, C> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static constexpr T EPS_DEFAULT = T(1e-6);
|
static constexpr T EPS_DEFAULT = T(1e-6);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Approximate matrix equality check.
|
||||||
|
* @param rhs Matrix to compare against.
|
||||||
|
* @param eps Absolute tolerance per component.
|
||||||
|
* @return `true` when all columns are approximately equal.
|
||||||
|
*/
|
||||||
template<class U = T>
|
template<class U = T>
|
||||||
requires std::is_floating_point_v<U>
|
requires std::is_floating_point_v<U>
|
||||||
[[nodiscard]] constexpr auto approx_equal(
|
[[nodiscard]] constexpr auto approx_equal(
|
||||||
@@ -901,6 +1056,7 @@ requires std::is_arithmetic_v<T> struct Mat : std::array<Vec<R, T>, C> {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @brief Returns the transposed matrix. */
|
||||||
[[nodiscard]] constexpr auto transposed() const noexcept -> Mat<C, R, T>
|
[[nodiscard]] constexpr auto transposed() const noexcept -> Mat<C, R, T>
|
||||||
{
|
{
|
||||||
Mat<C, R, T> r {};
|
Mat<C, R, T> r {};
|
||||||
@@ -910,6 +1066,7 @@ requires std::is_arithmetic_v<T> struct Mat : std::array<Vec<R, T>, C> {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @brief Returns an identity matrix. */
|
||||||
[[nodiscard]] static constexpr auto identity() noexcept -> Mat<R, C, T>
|
[[nodiscard]] static constexpr auto identity() noexcept -> Mat<R, C, T>
|
||||||
requires(R == C)
|
requires(R == C)
|
||||||
{
|
{
|
||||||
@@ -920,15 +1077,25 @@ requires std::is_arithmetic_v<T> struct Mat : std::array<Vec<R, T>, C> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** @brief 2x2 float matrix alias. */
|
||||||
using Mat2 = Mat<2, 2>;
|
using Mat2 = Mat<2, 2>;
|
||||||
|
/** @brief 3x3 float matrix alias. */
|
||||||
using Mat3 = Mat<3, 3>;
|
using Mat3 = Mat<3, 3>;
|
||||||
|
/** @brief 4x4 float matrix alias. */
|
||||||
using Mat4 = Mat<4, 4>;
|
using Mat4 = Mat<4, 4>;
|
||||||
|
|
||||||
|
/** @brief 2x2 double matrix alias. */
|
||||||
using Mat2d = Mat<2, 2, double>;
|
using Mat2d = Mat<2, 2, double>;
|
||||||
|
/** @brief 3x3 double matrix alias. */
|
||||||
using Mat3d = Mat<3, 3, double>;
|
using Mat3d = Mat<3, 3, double>;
|
||||||
|
/** @brief 4x4 double matrix alias. */
|
||||||
using Mat4d = Mat<4, 4, double>;
|
using Mat4d = Mat<4, 4, double>;
|
||||||
|
|
||||||
template<std::size_t R, std::size_t C, typename T>
|
template<std::size_t R, std::size_t C, typename T>
|
||||||
|
/**
|
||||||
|
* @brief Matrix-vector multiplication.
|
||||||
|
* @return Product vector.
|
||||||
|
*/
|
||||||
[[nodiscard]] constexpr Vec<R, T> operator*(
|
[[nodiscard]] constexpr Vec<R, T> operator*(
|
||||||
Mat<R, C, T> const &m, Vec<C, T> const &v) noexcept
|
Mat<R, C, T> const &m, Vec<C, T> const &v) noexcept
|
||||||
{
|
{
|
||||||
@@ -938,7 +1105,10 @@ template<std::size_t R, std::size_t C, typename T>
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Matrix * Matrix
|
/**
|
||||||
|
* @brief Matrix-matrix multiplication.
|
||||||
|
* @return Product matrix.
|
||||||
|
*/
|
||||||
template<std::size_t R, std::size_t C, std::size_t K, typename T>
|
template<std::size_t R, std::size_t C, std::size_t K, typename T>
|
||||||
[[nodiscard]] constexpr Mat<R, K, T> operator*(
|
[[nodiscard]] constexpr Mat<R, K, T> operator*(
|
||||||
Mat<R, C, T> const &a, Mat<C, K, T> const &b) noexcept
|
Mat<R, C, T> const &a, Mat<C, K, T> const &b) noexcept
|
||||||
@@ -955,7 +1125,10 @@ template<std::size_t R, std::size_t C, std::size_t K, typename T>
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mat3 transformations
|
/** @name 2D transforms (Mat3)
|
||||||
|
* @{ */
|
||||||
|
|
||||||
|
/** @brief Applies translation to an existing 3x3 transform. */
|
||||||
template<typename T>
|
template<typename T>
|
||||||
[[nodiscard]] inline auto translate(Mat<3, 3, T> const &m, Vec<2, T> const &v)
|
[[nodiscard]] inline auto translate(Mat<3, 3, T> const &m, Vec<2, T> const &v)
|
||||||
-> Mat<3, 3, T>
|
-> Mat<3, 3, T>
|
||||||
@@ -965,6 +1138,7 @@ template<typename T>
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @brief Creates a 3x3 translation matrix. */
|
||||||
template<typename T>
|
template<typename T>
|
||||||
[[nodiscard]] inline auto translate(Vec<2, T> const &v) -> Mat<3, 3, T>
|
[[nodiscard]] inline auto translate(Vec<2, T> const &v) -> Mat<3, 3, T>
|
||||||
{
|
{
|
||||||
@@ -974,6 +1148,7 @@ template<typename T>
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @brief Applies rotation to an existing 3x3 transform. */
|
||||||
template<typename T>
|
template<typename T>
|
||||||
[[nodiscard]] inline auto rotate(Mat<3, 3, T> const &m, T const angle)
|
[[nodiscard]] inline auto rotate(Mat<3, 3, T> const &m, T const angle)
|
||||||
-> Mat<3, 3, T>
|
-> Mat<3, 3, T>
|
||||||
@@ -990,6 +1165,7 @@ template<typename T>
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @brief Applies scaling to an existing 3x3 transform. */
|
||||||
template<typename T>
|
template<typename T>
|
||||||
[[nodiscard]] inline auto scale(Mat<3, 3, T> const &m, Vec<2, T> const &v)
|
[[nodiscard]] inline auto scale(Mat<3, 3, T> const &m, Vec<2, T> const &v)
|
||||||
-> Mat<3, 3, T>
|
-> Mat<3, 3, T>
|
||||||
@@ -1003,6 +1179,7 @@ template<typename T>
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @brief Applies X shear to an existing 3x3 transform. */
|
||||||
template<typename T>
|
template<typename T>
|
||||||
[[nodiscard]] inline auto shear_x(Mat<3, 3, T> const &m, T const v)
|
[[nodiscard]] inline auto shear_x(Mat<3, 3, T> const &m, T const v)
|
||||||
-> Mat<3, 3, T>
|
-> Mat<3, 3, T>
|
||||||
@@ -1012,6 +1189,7 @@ template<typename T>
|
|||||||
return m * res;
|
return m * res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @brief Applies Y shear to an existing 3x3 transform. */
|
||||||
template<typename T>
|
template<typename T>
|
||||||
[[nodiscard]] inline auto shear_y(Mat<3, 3, T> const &m, T const v)
|
[[nodiscard]] inline auto shear_y(Mat<3, 3, T> const &m, T const v)
|
||||||
-> Mat<3, 3, T>
|
-> Mat<3, 3, T>
|
||||||
@@ -1021,7 +1199,12 @@ template<typename T>
|
|||||||
return m * res;
|
return m * res;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mat4 transformations
|
/** @} */
|
||||||
|
|
||||||
|
/** @name 3D transforms (Mat4)
|
||||||
|
* @{ */
|
||||||
|
|
||||||
|
/** @brief Applies translation to an existing 4x4 transform. */
|
||||||
template<typename T>
|
template<typename T>
|
||||||
[[nodiscard]] inline auto translate(Mat<4, 4, T> const &m, Vec<3, T> const &v)
|
[[nodiscard]] inline auto translate(Mat<4, 4, T> const &m, Vec<3, T> const &v)
|
||||||
-> Mat<4, 4, T>
|
-> Mat<4, 4, T>
|
||||||
@@ -1031,6 +1214,7 @@ template<typename T>
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @brief Creates a 4x4 translation matrix. */
|
||||||
template<typename T>
|
template<typename T>
|
||||||
[[nodiscard]] inline auto translate(Vec<3, T> const &v) -> Mat<4, 4, T>
|
[[nodiscard]] inline auto translate(Vec<3, T> const &v) -> Mat<4, 4, T>
|
||||||
{
|
{
|
||||||
@@ -1041,6 +1225,7 @@ template<typename T>
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @brief Applies rotation to an existing 4x4 transform. */
|
||||||
template<typename T>
|
template<typename T>
|
||||||
[[nodiscard]] inline auto rotate(Mat<4, 4, T> const &m, T const angle)
|
[[nodiscard]] inline auto rotate(Mat<4, 4, T> const &m, T const angle)
|
||||||
-> Mat<4, 4, T>
|
-> Mat<4, 4, T>
|
||||||
@@ -1058,6 +1243,7 @@ template<typename T>
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @brief Applies scaling to an existing 4x4 transform. */
|
||||||
template<typename T>
|
template<typename T>
|
||||||
[[nodiscard]] inline auto scale(Mat<4, 4, T> const &m, Vec<3, T> const &v)
|
[[nodiscard]] inline auto scale(Mat<4, 4, T> const &m, Vec<3, T> const &v)
|
||||||
-> Mat<4, 4, T>
|
-> Mat<4, 4, T>
|
||||||
@@ -1072,6 +1258,7 @@ template<typename T>
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @brief Applies X shear to an existing 4x4 transform. */
|
||||||
template<typename T>
|
template<typename T>
|
||||||
[[nodiscard]] inline auto shear_x(Mat<4, 4, T> const &m, T const v)
|
[[nodiscard]] inline auto shear_x(Mat<4, 4, T> const &m, T const v)
|
||||||
-> Mat<4, 4, T>
|
-> Mat<4, 4, T>
|
||||||
@@ -1081,6 +1268,7 @@ template<typename T>
|
|||||||
return m * res;
|
return m * res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @brief Applies Y shear to an existing 4x4 transform. */
|
||||||
template<typename T>
|
template<typename T>
|
||||||
[[nodiscard]] inline auto shear_y(Mat<4, 4, T> const &m, T const v)
|
[[nodiscard]] inline auto shear_y(Mat<4, 4, T> const &m, T const v)
|
||||||
-> Mat<4, 4, T>
|
-> Mat<4, 4, T>
|
||||||
@@ -1090,6 +1278,7 @@ template<typename T>
|
|||||||
return m * res;
|
return m * res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @brief Applies Z shear to an existing 4x4 transform. */
|
||||||
template<typename T>
|
template<typename T>
|
||||||
[[nodiscard]] inline auto shear_z(Mat<4, 4, T> const &m, T const v)
|
[[nodiscard]] inline auto shear_z(Mat<4, 4, T> const &m, T const v)
|
||||||
-> Mat<4, 4, T>
|
-> Mat<4, 4, T>
|
||||||
@@ -1099,9 +1288,24 @@ template<typename T>
|
|||||||
return m * res;
|
return m * res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Builds an orthographic projection matrix.
|
||||||
|
* @param left Left clipping plane.
|
||||||
|
* @param right Right clipping plane.
|
||||||
|
* @param bottom Bottom clipping plane.
|
||||||
|
* @param top Top clipping plane.
|
||||||
|
* @param near Near clipping plane.
|
||||||
|
* @param far Far clipping plane.
|
||||||
|
* @param flip_z_axis Whether to flip the output Z axis convention.
|
||||||
|
* @return Orthographic projection matrix.
|
||||||
|
*/
|
||||||
template<typename T>
|
template<typename T>
|
||||||
[[nodiscard]] inline auto matrix_ortho3d(T const left, T const right,
|
[[nodiscard]] inline auto matrix_ortho3d(T const left,
|
||||||
T const bottom, T const top, T const near, T const far,
|
T const right,
|
||||||
|
T const bottom,
|
||||||
|
T const top,
|
||||||
|
T const near,
|
||||||
|
T const far,
|
||||||
bool const flip_z_axis = true) -> Mat<4, 4, T>
|
bool const flip_z_axis = true) -> Mat<4, 4, T>
|
||||||
{
|
{
|
||||||
Mat<4, 4, T> res {};
|
Mat<4, 4, T> res {};
|
||||||
@@ -1121,6 +1325,9 @@ template<typename T>
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Builds a finite perspective projection matrix.
|
||||||
|
*/
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline auto matrix_perspective(
|
inline auto matrix_perspective(
|
||||||
T fovy, T aspect, T znear, T zfar, bool flip_z_axis = false) -> Mat<4, 4, T>
|
T fovy, T aspect, T znear, T zfar, bool flip_z_axis = false) -> Mat<4, 4, T>
|
||||||
@@ -1147,9 +1354,13 @@ inline auto matrix_perspective(
|
|||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Builds a right-handed look-at view matrix.
|
||||||
|
*/
|
||||||
template<typename T>
|
template<typename T>
|
||||||
[[nodiscard]] inline auto matrix_look_at(Vec<3, T> const eye,
|
[[nodiscard]] inline auto matrix_look_at(
|
||||||
Vec<3, T> const center, Vec<3, T> const up) -> Mat<4, 4, T>
|
Vec<3, T> const eye, Vec<3, T> const center, Vec<3, T> const up)
|
||||||
|
-> Mat<4, 4, T>
|
||||||
{
|
{
|
||||||
auto f = (center - eye).normalized_safe();
|
auto f = (center - eye).normalized_safe();
|
||||||
auto s = f.cross(up).normalized_safe();
|
auto s = f.cross(up).normalized_safe();
|
||||||
@@ -1163,9 +1374,13 @@ template<typename T>
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Builds a perspective matrix with an infinite far plane.
|
||||||
|
*/
|
||||||
template<typename T>
|
template<typename T>
|
||||||
[[nodiscard]] inline auto matrix_infinite_perspective(T const fovy,
|
[[nodiscard]] inline auto matrix_infinite_perspective(
|
||||||
T const aspect, T const znear, bool flip_z_axis = false) -> Mat<4, 4, T>
|
T const fovy, T const aspect, T const znear, bool flip_z_axis = false)
|
||||||
|
-> Mat<4, 4, T>
|
||||||
{
|
{
|
||||||
Mat<4, 4, T> m {};
|
Mat<4, 4, T> m {};
|
||||||
|
|
||||||
@@ -1186,11 +1401,38 @@ template<typename T>
|
|||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Extension point for external math-type interoperability.
|
||||||
|
*/
|
||||||
|
template<class Ext> struct interop_adapter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Converts an external value into its mapped smath type.
|
||||||
|
*/
|
||||||
|
template<class Ext>
|
||||||
|
constexpr auto from_external(Ext const &ext) ->
|
||||||
|
typename interop_adapter<Ext>::smath_type
|
||||||
|
{
|
||||||
|
return interop_adapter<Ext>::to_smath(ext);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Converts a smath value into an external type.
|
||||||
|
*/
|
||||||
|
template<class Ext, class SMathT>
|
||||||
|
constexpr auto to_external(SMathT const &value) -> Ext
|
||||||
|
{
|
||||||
|
return interop_adapter<Ext>::from_smath(value);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace smath
|
} // namespace smath
|
||||||
|
|
||||||
template<std::size_t N, typename T>
|
template<std::size_t N, typename T>
|
||||||
requires std::formattable<T, char>
|
requires std::formattable<T, char>
|
||||||
struct std::formatter<smath::Vec<N, T>> : std::formatter<T> {
|
struct std::formatter<smath::Vec<N, T>> : std::formatter<T>
|
||||||
|
{
|
||||||
constexpr auto parse(std::format_parse_context &ctx)
|
constexpr auto parse(std::format_parse_context &ctx)
|
||||||
{
|
{
|
||||||
return std::formatter<T>::parse(ctx);
|
return std::formatter<T>::parse(ctx);
|
||||||
@@ -1213,12 +1455,14 @@ struct std::formatter<smath::Vec<N, T>> : std::formatter<T> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace std {
|
namespace std
|
||||||
|
{
|
||||||
template<size_t N, class T>
|
template<size_t N, class T>
|
||||||
struct tuple_size<smath::Vec<N, T>> : std::integral_constant<size_t, N> { };
|
struct tuple_size<smath::Vec<N, T>> : std::integral_constant<size_t, N>
|
||||||
|
{ };
|
||||||
|
|
||||||
template<size_t I, size_t N, class T>
|
template<size_t I, size_t N, class T> struct tuple_element<I, smath::Vec<N, T>>
|
||||||
struct tuple_element<I, smath::Vec<N, T>> {
|
{
|
||||||
static_assert(I < N);
|
static_assert(I < N);
|
||||||
using type = T;
|
using type = T;
|
||||||
};
|
};
|
||||||
190
smath_big.svg
Normal file
190
smath_big.svg
Normal file
@@ -0,0 +1,190 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
width="1280"
|
||||||
|
height="640"
|
||||||
|
viewBox="0 0 1280.0001 640.00006"
|
||||||
|
version="1.1"
|
||||||
|
id="svg1"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<defs
|
||||||
|
id="defs1">
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient13">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#25ff0c;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop12" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#16d800;stop-opacity:1;"
|
||||||
|
offset="1"
|
||||||
|
id="stop13" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient10">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#25ff0c;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop10" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#25ff0c;stop-opacity:1;"
|
||||||
|
offset="1"
|
||||||
|
id="stop11" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient8">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#c50000;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop8" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#ff0c0c;stop-opacity:1;"
|
||||||
|
offset="1"
|
||||||
|
id="stop9" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient5">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#000000;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop5" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#969696;stop-opacity:1;"
|
||||||
|
offset="1"
|
||||||
|
id="stop6" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
xlink:href="#linearGradient5"
|
||||||
|
id="linearGradient6-2"
|
||||||
|
x1="482.5849"
|
||||||
|
y1="589.83472"
|
||||||
|
x2="613.15253"
|
||||||
|
y2="-24.437733"
|
||||||
|
gradientUnits="userSpaceOnUse" />
|
||||||
|
<rect
|
||||||
|
x="227.90907"
|
||||||
|
y="175.81558"
|
||||||
|
width="659.85107"
|
||||||
|
height="227.90907"
|
||||||
|
id="rect1-5" />
|
||||||
|
<linearGradient
|
||||||
|
xlink:href="#linearGradient10"
|
||||||
|
id="linearGradient11-0"
|
||||||
|
x1="50.894115"
|
||||||
|
y1="80.727814"
|
||||||
|
x2="50.894115"
|
||||||
|
y2="68.866821"
|
||||||
|
gradientUnits="userSpaceOnUse" />
|
||||||
|
<marker
|
||||||
|
style="overflow:visible"
|
||||||
|
id="RoundedArrow-45"
|
||||||
|
refX="0"
|
||||||
|
refY="0"
|
||||||
|
orient="auto-start-reverse"
|
||||||
|
markerWidth="1"
|
||||||
|
markerHeight="1"
|
||||||
|
viewBox="0 0 1 1"
|
||||||
|
preserveAspectRatio="xMidYMid">
|
||||||
|
<path
|
||||||
|
transform="scale(0.7)"
|
||||||
|
d="m -0.21114562,-4.1055728 6.42229122,3.21114561 a 1,1 90 0 1 0,1.78885438 L -0.21114562,4.1055728 A 1.236068,1.236068 31.717474 0 1 -2,3 v -6 a 1.236068,1.236068 148.28253 0 1 1.78885438,-1.1055728 z"
|
||||||
|
style="fill:context-stroke;fill-rule:evenodd;stroke:none"
|
||||||
|
id="path8-2" />
|
||||||
|
</marker>
|
||||||
|
<linearGradient
|
||||||
|
xlink:href="#linearGradient8"
|
||||||
|
id="linearGradient9-6"
|
||||||
|
x1="107.55984"
|
||||||
|
y1="103.63171"
|
||||||
|
x2="51.891579"
|
||||||
|
y2="103.63171"
|
||||||
|
gradientUnits="userSpaceOnUse" />
|
||||||
|
<marker
|
||||||
|
style="overflow:visible"
|
||||||
|
id="RoundedArrow-4-1"
|
||||||
|
refX="0"
|
||||||
|
refY="0"
|
||||||
|
orient="auto-start-reverse"
|
||||||
|
markerWidth="1"
|
||||||
|
markerHeight="1"
|
||||||
|
viewBox="0 0 1 1"
|
||||||
|
preserveAspectRatio="xMidYMid">
|
||||||
|
<path
|
||||||
|
transform="scale(0.7)"
|
||||||
|
d="m -0.21114562,-4.1055728 6.42229122,3.21114561 a 1,1 90 0 1 0,1.78885438 L -0.21114562,4.1055728 A 1.236068,1.236068 31.717474 0 1 -2,3 v -6 a 1.236068,1.236068 148.28253 0 1 1.78885438,-1.1055728 z"
|
||||||
|
style="fill:context-stroke;fill-rule:evenodd;stroke:none"
|
||||||
|
id="path8-3-1" />
|
||||||
|
</marker>
|
||||||
|
<linearGradient
|
||||||
|
xlink:href="#linearGradient13"
|
||||||
|
id="linearGradient16"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(1,0,0,0.93927134,0,6.2326702)"
|
||||||
|
x1="50.894115"
|
||||||
|
y1="80.727814"
|
||||||
|
x2="50.894115"
|
||||||
|
y2="68.866821" />
|
||||||
|
</defs>
|
||||||
|
<rect
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
id="rect16"
|
||||||
|
width="1280.0001"
|
||||||
|
height="640"
|
||||||
|
x="1.1474608e-06"
|
||||||
|
y="2.8421709e-14" />
|
||||||
|
<g
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(-419.99999)">
|
||||||
|
<g
|
||||||
|
id="g13-2"
|
||||||
|
transform="matrix(4.6783888,0,0,4.6783888,411.42933,-46.143325)">
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
transform="matrix(0.26458333,0,0,0.26458333,2.4199432,-2.3937254)"
|
||||||
|
id="text1-0"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:192px;font-family:'Shree Devanagari 714';-inkscape-font-specification:'Shree Devanagari 714, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;writing-mode:lr-tb;direction:ltr;white-space:pre;shape-inside:url(#rect1-5);display:inline;fill:url(#linearGradient6-2);stroke-width:7.55906;stroke-dasharray:none"><tspan
|
||||||
|
x="227.9082"
|
||||||
|
y="353.41641"
|
||||||
|
id="tspan1">SMATH</tspan></text>
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:8.37934px;font-family:'Shree Devanagari 714';-inkscape-font-specification:'Shree Devanagari 714, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;writing-mode:lr-tb;direction:ltr;text-anchor:start;fill:#000000;stroke-width:2;stroke-dasharray:none"
|
||||||
|
x="110.62661"
|
||||||
|
y="105.75446"
|
||||||
|
id="text2-1"><tspan
|
||||||
|
id="tspan2-24"
|
||||||
|
style="font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:8.37934px;font-family:'Shree Devanagari 714';-inkscape-font-specification:'Shree Devanagari 714, Bold Italic';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:2;stroke-dasharray:none"
|
||||||
|
x="110.62661"
|
||||||
|
y="105.75446">Linear algebra library for C++23</tspan></text>
|
||||||
|
<path
|
||||||
|
style="fill:#000000;stroke:url(#linearGradient11-0);stroke-width:2;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#RoundedArrow-45)"
|
||||||
|
d="M 50.894116,102.63145 V 56.432683"
|
||||||
|
id="path4-5" />
|
||||||
|
<path
|
||||||
|
style="fill:#000000;stroke:url(#linearGradient16);stroke-width:1.93832;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="M 50.894116,102.63145 V 59.238272"
|
||||||
|
id="path4-0-5" />
|
||||||
|
<path
|
||||||
|
style="fill:none;stroke:url(#linearGradient9-6);stroke-width:2;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#RoundedArrow-4-1)"
|
||||||
|
d="m 51.891583,103.63172 h 46.19876"
|
||||||
|
id="path4-9-23" />
|
||||||
|
<path
|
||||||
|
style="fill:#ff0c0c;fill-opacity:1;stroke:none;stroke-width:2;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 51.891583,104.63115 v -1.9997 l -1.998196,1.99844 z"
|
||||||
|
id="path5-2" />
|
||||||
|
<path
|
||||||
|
style="fill:#25ff0c;fill-opacity:1;stroke:none;stroke-width:2;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 49.895018,102.63082 v 1.9997 l 1.998196,-1.99844 z"
|
||||||
|
id="path5-8-3" />
|
||||||
|
<circle
|
||||||
|
style="fill:#1162ff;fill-opacity:1;stroke:none;stroke-width:2;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
id="path13-1"
|
||||||
|
cx="50.894115"
|
||||||
|
cy="103.6313"
|
||||||
|
r="3.4155982" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 7.1 KiB |
@@ -1,6 +1,6 @@
|
|||||||
module;
|
module;
|
||||||
|
|
||||||
#include "smath.hpp"
|
#include "smath/smath.hpp"
|
||||||
|
|
||||||
export module smath;
|
export module smath;
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,18 @@
|
|||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
#include <smath.hpp>
|
#include <smath/smath.hpp>
|
||||||
|
|
||||||
TEST(AngleReturnRadians, DegInput) {
|
TEST(AngleReturnRadians, DegInput)
|
||||||
|
{
|
||||||
EXPECT_NEAR(smath::deg(180.0), std::numbers::pi, 1e-12);
|
EXPECT_NEAR(smath::deg(180.0), std::numbers::pi, 1e-12);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(AngleReturnRadians, RadInput) {
|
TEST(AngleReturnRadians, RadInput)
|
||||||
|
{
|
||||||
EXPECT_DOUBLE_EQ(smath::rad(std::numbers::pi), std::numbers::pi);
|
EXPECT_DOUBLE_EQ(smath::rad(std::numbers::pi), std::numbers::pi);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(AngleReturnRadians, TurnsInput) {
|
TEST(AngleReturnRadians, TurnsInput)
|
||||||
|
{
|
||||||
EXPECT_NEAR(smath::turns(0.5), std::numbers::pi, 1e-12);
|
EXPECT_NEAR(smath::turns(0.5), std::numbers::pi, 1e-12);
|
||||||
}
|
}
|
||||||
|
|||||||
110
tests/interop.cpp
Normal file
110
tests/interop.cpp
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include <smath/smath.hpp>
|
||||||
|
|
||||||
|
struct ExternalVec3f
|
||||||
|
{
|
||||||
|
float x;
|
||||||
|
float y;
|
||||||
|
float z;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ExternalMat2f
|
||||||
|
{
|
||||||
|
float m00;
|
||||||
|
float m01;
|
||||||
|
float m10;
|
||||||
|
float m11;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace smath
|
||||||
|
{
|
||||||
|
|
||||||
|
template<> struct interop_adapter<ExternalVec3f>
|
||||||
|
{
|
||||||
|
using smath_type = Vec<3, float>;
|
||||||
|
|
||||||
|
static constexpr auto to_smath(ExternalVec3f const &v) -> smath_type
|
||||||
|
{
|
||||||
|
return { v.x, v.y, v.z };
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr auto from_smath(smath_type const &v) -> ExternalVec3f
|
||||||
|
{
|
||||||
|
return { v[0], v[1], v[2] };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<> struct interop_adapter<ExternalMat2f>
|
||||||
|
{
|
||||||
|
using smath_type = Mat<2, 2, float>;
|
||||||
|
|
||||||
|
static constexpr auto to_smath(ExternalMat2f const &m) -> smath_type
|
||||||
|
{
|
||||||
|
smath_type out {};
|
||||||
|
out(0, 0) = m.m00;
|
||||||
|
out(0, 1) = m.m01;
|
||||||
|
out(1, 0) = m.m10;
|
||||||
|
out(1, 1) = m.m11;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr auto from_smath(smath_type const &m) -> ExternalMat2f
|
||||||
|
{
|
||||||
|
return { m(0, 0), m(0, 1), m(1, 0), m(1, 1) };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace smath
|
||||||
|
|
||||||
|
TEST(Interop, FromExternalVec)
|
||||||
|
{
|
||||||
|
ExternalVec3f ext { 1.0f, 2.0f, 3.0f };
|
||||||
|
auto v = smath::from_external(ext);
|
||||||
|
|
||||||
|
static_assert(std::is_same_v<decltype(v), smath::Vec<3, float>>);
|
||||||
|
EXPECT_EQ(v[0], 1.0f);
|
||||||
|
EXPECT_EQ(v[1], 2.0f);
|
||||||
|
EXPECT_EQ(v[2], 3.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Interop, ToExternalVec)
|
||||||
|
{
|
||||||
|
smath::Vec3 v { 4.0f, 5.0f, 6.0f };
|
||||||
|
auto ext = smath::to_external<ExternalVec3f>(v);
|
||||||
|
|
||||||
|
EXPECT_EQ(ext.x, 4.0f);
|
||||||
|
EXPECT_EQ(ext.y, 5.0f);
|
||||||
|
EXPECT_EQ(ext.z, 6.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Interop, RoundtripVec)
|
||||||
|
{
|
||||||
|
ExternalVec3f ext { 7.0f, 8.0f, 9.0f };
|
||||||
|
auto v = smath::from_external(ext);
|
||||||
|
auto ext2 = smath::to_external<ExternalVec3f>(v);
|
||||||
|
|
||||||
|
EXPECT_EQ(ext2.x, 7.0f);
|
||||||
|
EXPECT_EQ(ext2.y, 8.0f);
|
||||||
|
EXPECT_EQ(ext2.z, 9.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Interop, MatrixConversion)
|
||||||
|
{
|
||||||
|
ExternalMat2f ext { 1.0f, 2.0f, 3.0f, 4.0f };
|
||||||
|
auto m = smath::from_external(ext);
|
||||||
|
|
||||||
|
static_assert(std::is_same_v<decltype(m), smath::Mat<2, 2, float>>);
|
||||||
|
EXPECT_EQ(m(0, 0), 1.0f);
|
||||||
|
EXPECT_EQ(m(0, 1), 2.0f);
|
||||||
|
EXPECT_EQ(m(1, 0), 3.0f);
|
||||||
|
EXPECT_EQ(m(1, 1), 4.0f);
|
||||||
|
|
||||||
|
auto ext2 = smath::to_external<ExternalMat2f>(m);
|
||||||
|
EXPECT_EQ(ext2.m00, 1.0f);
|
||||||
|
EXPECT_EQ(ext2.m01, 2.0f);
|
||||||
|
EXPECT_EQ(ext2.m10, 3.0f);
|
||||||
|
EXPECT_EQ(ext2.m11, 4.0f);
|
||||||
|
}
|
||||||
106
tests/vec.cpp
106
tests/vec.cpp
@@ -4,57 +4,63 @@
|
|||||||
|
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
#include <smath.hpp>
|
#include <smath/smath.hpp>
|
||||||
|
|
||||||
using smath::Vec;
|
using smath::Vec;
|
||||||
using smath::Vec2;
|
using smath::Vec2;
|
||||||
using smath::Vec3;
|
using smath::Vec3;
|
||||||
using smath::Vec4;
|
using smath::Vec4;
|
||||||
|
|
||||||
template <class T>
|
template<class T>
|
||||||
static void ExpectVecNear(const Vec<3, T> &a, const Vec<3, T> &b,
|
static void ExpectVecNear(
|
||||||
T eps = T(1e-6)) {
|
const Vec<3, T> &a, const Vec<3, T> &b, T eps = T(1e-6))
|
||||||
|
{
|
||||||
for (int i = 0; i < 3; ++i)
|
for (int i = 0; i < 3; ++i)
|
||||||
EXPECT_NEAR(double(a[i]), double(b[i]), double(eps));
|
EXPECT_NEAR(double(a[i]), double(b[i]), double(eps));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Constructors and accessors
|
// Constructors and accessors
|
||||||
TEST(Vec, DefaultZero) {
|
TEST(Vec, DefaultZero)
|
||||||
|
{
|
||||||
Vec3 v;
|
Vec3 v;
|
||||||
EXPECT_EQ(v[0], 0.0f);
|
EXPECT_EQ(v[0], 0.0f);
|
||||||
EXPECT_EQ(v[1], 0.0f);
|
EXPECT_EQ(v[1], 0.0f);
|
||||||
EXPECT_EQ(v[2], 0.0f);
|
EXPECT_EQ(v[2], 0.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(Vec, ScalarFillCtor) {
|
TEST(Vec, ScalarFillCtor)
|
||||||
Vec4 v{2.0f};
|
{
|
||||||
|
Vec4 v { 2.0f };
|
||||||
EXPECT_EQ(v.x(), 2.0f);
|
EXPECT_EQ(v.x(), 2.0f);
|
||||||
EXPECT_EQ(v.y(), 2.0f);
|
EXPECT_EQ(v.y(), 2.0f);
|
||||||
EXPECT_EQ(v.z(), 2.0f);
|
EXPECT_EQ(v.z(), 2.0f);
|
||||||
EXPECT_EQ(v.w(), 2.0f);
|
EXPECT_EQ(v.w(), 2.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(Vec, VariadicCtorScalarsAndSubvectors) {
|
TEST(Vec, VariadicCtorScalarsAndSubvectors)
|
||||||
Vec2 a{1.0f, 2.0f};
|
{
|
||||||
Vec2 b{3.0f, 4.0f};
|
Vec2 a { 1.0f, 2.0f };
|
||||||
Vec4 v{a, b};
|
Vec2 b { 3.0f, 4.0f };
|
||||||
|
Vec4 v { a, b };
|
||||||
EXPECT_EQ(v.r(), 1.0f);
|
EXPECT_EQ(v.r(), 1.0f);
|
||||||
EXPECT_EQ(v.g(), 2.0f);
|
EXPECT_EQ(v.g(), 2.0f);
|
||||||
EXPECT_EQ(v.b(), 3.0f);
|
EXPECT_EQ(v.b(), 3.0f);
|
||||||
EXPECT_EQ(v.a(), 4.0f);
|
EXPECT_EQ(v.a(), 4.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(Vec, NamedAccessorsAliases) {
|
TEST(Vec, NamedAccessorsAliases)
|
||||||
Vec3 v{1.0f, 2.0f, 3.0f};
|
{
|
||||||
|
Vec3 v { 1.0f, 2.0f, 3.0f };
|
||||||
EXPECT_EQ(v.x(), v.r());
|
EXPECT_EQ(v.x(), v.r());
|
||||||
EXPECT_EQ(v.y(), v.g());
|
EXPECT_EQ(v.y(), v.g());
|
||||||
EXPECT_EQ(v.z(), v.b());
|
EXPECT_EQ(v.z(), v.b());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Arithmetic
|
// Arithmetic
|
||||||
TEST(Vec, ElementwiseAndScalarOps) {
|
TEST(Vec, ElementwiseAndScalarOps)
|
||||||
Vec3 a{1.0f, 2.0f, 3.0f};
|
{
|
||||||
Vec3 b{4.0f, 5.0f, 6.0f};
|
Vec3 a { 1.0f, 2.0f, 3.0f };
|
||||||
|
Vec3 b { 4.0f, 5.0f, 6.0f };
|
||||||
|
|
||||||
auto s1 = a + b;
|
auto s1 = a + b;
|
||||||
EXPECT_EQ(s1[0], 5.0f);
|
EXPECT_EQ(s1[0], 5.0f);
|
||||||
@@ -71,8 +77,8 @@ TEST(Vec, ElementwiseAndScalarOps) {
|
|||||||
EXPECT_EQ(s3[1], 4.0f);
|
EXPECT_EQ(s3[1], 4.0f);
|
||||||
EXPECT_EQ(s3[2], 6.0f);
|
EXPECT_EQ(s3[2], 6.0f);
|
||||||
|
|
||||||
Vec3 c{1.0f, 2.0f, 3.0f};
|
Vec3 c { 1.0f, 2.0f, 3.0f };
|
||||||
c += Vec3{1.0f, 1.0f, 1.0f};
|
c += Vec3 { 1.0f, 1.0f, 1.0f };
|
||||||
EXPECT_EQ(c[0], 2.0f);
|
EXPECT_EQ(c[0], 2.0f);
|
||||||
EXPECT_EQ(c[1], 3.0f);
|
EXPECT_EQ(c[1], 3.0f);
|
||||||
EXPECT_EQ(c[2], 4.0f);
|
EXPECT_EQ(c[2], 4.0f);
|
||||||
@@ -84,58 +90,65 @@ TEST(Vec, ElementwiseAndScalarOps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Length, dot, cross, normalize
|
// Length, dot, cross, normalize
|
||||||
TEST(Vec, MagnitudeAndDot) {
|
TEST(Vec, MagnitudeAndDot)
|
||||||
Vec3 v{3.0f, 4.0f, 12.0f};
|
{
|
||||||
|
Vec3 v { 3.0f, 4.0f, 12.0f };
|
||||||
EXPECT_FLOAT_EQ(v.magnitude(), 13.0f);
|
EXPECT_FLOAT_EQ(v.magnitude(), 13.0f);
|
||||||
EXPECT_FLOAT_EQ(v.length(), 13.0f);
|
EXPECT_FLOAT_EQ(v.length(), 13.0f);
|
||||||
|
|
||||||
Vec3 u{1.0f, 0.0f, 2.0f};
|
Vec3 u { 1.0f, 0.0f, 2.0f };
|
||||||
EXPECT_FLOAT_EQ(v.dot(u), 27.0f);
|
EXPECT_FLOAT_EQ(v.dot(u), 27.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(Vec, Cross3D) {
|
TEST(Vec, Cross3D)
|
||||||
Vec3 x{1.0f, 0.0f, 0.0f};
|
{
|
||||||
Vec3 y{0.0f, 1.0f, 0.0f};
|
Vec3 x { 1.0f, 0.0f, 0.0f };
|
||||||
|
Vec3 y { 0.0f, 1.0f, 0.0f };
|
||||||
auto z = x.cross(y);
|
auto z = x.cross(y);
|
||||||
EXPECT_EQ(z[0], 0.0f);
|
EXPECT_EQ(z[0], 0.0f);
|
||||||
EXPECT_EQ(z[1], 0.0f);
|
EXPECT_EQ(z[1], 0.0f);
|
||||||
EXPECT_EQ(z[2], 1.0f);
|
EXPECT_EQ(z[2], 1.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(Vec, NormalizeAndSafeNormalize) {
|
TEST(Vec, NormalizeAndSafeNormalize)
|
||||||
Vec3 v{10.0f, 0.0f, 0.0f};
|
{
|
||||||
|
Vec3 v { 10.0f, 0.0f, 0.0f };
|
||||||
auto n = v.normalized();
|
auto n = v.normalized();
|
||||||
auto ns = v.normalized_safe();
|
auto ns = v.normalized_safe();
|
||||||
ExpectVecNear(n, Vec3{1.0f, 0.0f, 0.0f});
|
ExpectVecNear(n, Vec3 { 1.0f, 0.0f, 0.0f });
|
||||||
|
ExpectVecNear(ns, Vec3 { 1.0f, 0.0f, 0.0f });
|
||||||
|
|
||||||
Vec3 zero{};
|
Vec3 zero {};
|
||||||
auto zs = zero.normalized_safe();
|
auto zs = zero.normalized_safe();
|
||||||
EXPECT_EQ(zs[0], 0.0f);
|
EXPECT_EQ(zs[0], 0.0f);
|
||||||
EXPECT_EQ(zs[1], 0.0f);
|
EXPECT_EQ(zs[1], 0.0f);
|
||||||
EXPECT_EQ(zs[2], 0.0f);
|
EXPECT_EQ(zs[2], 0.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(Vec, DistanceAndProjection) {
|
TEST(Vec, DistanceAndProjection)
|
||||||
Vec3 a{1.0f, 2.0f, 3.0f};
|
{
|
||||||
Vec3 b{4.0f, 6.0f, 3.0f};
|
Vec3 a { 1.0f, 2.0f, 3.0f };
|
||||||
|
Vec3 b { 4.0f, 6.0f, 3.0f };
|
||||||
EXPECT_FLOAT_EQ(a.distance(b), 5.0f);
|
EXPECT_FLOAT_EQ(a.distance(b), 5.0f);
|
||||||
|
|
||||||
Vec3 n{2.0f, 0.0f, 0.0f}; // onto x-axis scaled
|
Vec3 n { 2.0f, 0.0f, 0.0f }; // onto x-axis scaled
|
||||||
auto p = a.project_onto(n); // (a·n)/(n·n) * n = (2)/4 * n = 0.5 * n
|
auto p = a.project_onto(n); // (a·n)/(n·n) * n = (2)/4 * n = 0.5 * n
|
||||||
ExpectVecNear(p, Vec3{1.0f, 0.0f, 0.0f});
|
ExpectVecNear(p, Vec3 { 1.0f, 0.0f, 0.0f });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Approx equal
|
// Approx equal
|
||||||
TEST(Vec, ApproxEqual) {
|
TEST(Vec, ApproxEqual)
|
||||||
Vec3 a{1.0f, 2.0f, 3.0f};
|
{
|
||||||
Vec3 b{1.0f + 1e-7f, 2.0f - 1e-7f, 3.0f};
|
Vec3 a { 1.0f, 2.0f, 3.0f };
|
||||||
|
Vec3 b { 1.0f + 1e-7f, 2.0f - 1e-7f, 3.0f };
|
||||||
EXPECT_TRUE(a.approx_equal(b, 1e-6f));
|
EXPECT_TRUE(a.approx_equal(b, 1e-6f));
|
||||||
EXPECT_FALSE(a.approx_equal(b, 1e-9f));
|
EXPECT_FALSE(a.approx_equal(b, 1e-9f));
|
||||||
}
|
}
|
||||||
|
|
||||||
// std::get & tuple interop
|
// std::get & tuple interop
|
||||||
TEST(Vec, StdGetAndTuple) {
|
TEST(Vec, StdGetAndTuple)
|
||||||
Vec3 v{7.0f, 8.0f, 9.0f};
|
{
|
||||||
|
Vec3 v { 7.0f, 8.0f, 9.0f };
|
||||||
static_assert(std::tuple_size_v<Vec3> == 3);
|
static_assert(std::tuple_size_v<Vec3> == 3);
|
||||||
static_assert(std::is_same_v<std::tuple_element_t<1, Vec3>, float>);
|
static_assert(std::is_same_v<std::tuple_element_t<1, Vec3>, float>);
|
||||||
EXPECT_EQ(std::get<0>(v), 7.0f);
|
EXPECT_EQ(std::get<0>(v), 7.0f);
|
||||||
@@ -144,8 +157,9 @@ TEST(Vec, StdGetAndTuple) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Swizzle
|
// Swizzle
|
||||||
TEST(Vec, SwizzleBasic) {
|
TEST(Vec, SwizzleBasic)
|
||||||
const Vec3 v{1.0f, 2.0f, 3.0f};
|
{
|
||||||
|
const Vec3 v { 1.0f, 2.0f, 3.0f };
|
||||||
|
|
||||||
auto yz = smath::swizzle<"yz">(v);
|
auto yz = smath::swizzle<"yz">(v);
|
||||||
EXPECT_EQ(yz[0], 2.0f);
|
EXPECT_EQ(yz[0], 2.0f);
|
||||||
@@ -158,16 +172,18 @@ TEST(Vec, SwizzleBasic) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// std::formatter
|
// std::formatter
|
||||||
TEST(Vec, Formatter) {
|
TEST(Vec, Formatter)
|
||||||
smath::Vec<3, int> vi{1, 2, 3};
|
{
|
||||||
|
smath::Vec<3, int> vi { 1, 2, 3 };
|
||||||
std::string s = std::format("{}", vi);
|
std::string s = std::format("{}", vi);
|
||||||
EXPECT_EQ(s, "{1, 2, 3}");
|
EXPECT_EQ(s, "{1, 2, 3}");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Conversions
|
// Conversions
|
||||||
TEST(Vec, ExplicitConversionBetweenScalarTypes) {
|
TEST(Vec, ExplicitConversionBetweenScalarTypes)
|
||||||
smath::Vec<3, int> vi{1, 2, 3};
|
{
|
||||||
smath::Vec<3, float> vf{vi};
|
smath::Vec<3, int> vi { 1, 2, 3 };
|
||||||
|
smath::Vec<3, float> vf { vi };
|
||||||
EXPECT_EQ(vf[0], 1.0f);
|
EXPECT_EQ(vf[0], 1.0f);
|
||||||
EXPECT_EQ(vf[1], 2.0f);
|
EXPECT_EQ(vf[1], 2.0f);
|
||||||
EXPECT_EQ(vf[2], 3.0f);
|
EXPECT_EQ(vf[2], 3.0f);
|
||||||
|
|||||||
Reference in New Issue
Block a user