flatten 20260225

This commit is contained in:
Timothy Prepscius
2026-02-25 12:36:47 -05:00
commit 0807c0286a
107 changed files with 12310 additions and 0 deletions

View File

@@ -0,0 +1,83 @@
//
// MathIO.h
// common
//
// Created by Timothy Prepscius on 8/4/18.
// Copyright © 2018 Timothy Prepscius. All rights reserved.
//
#pragma once
#include "Math.h"
#include "Accuracy.h"
#include <tjp/core/io/bin/IO.h>
#include "Vector3.hpp"
#include "Sphere3.hpp"
#include <type_traits>
namespace tjp {
namespace core {
namespace math {
template<typename IO, typename T>
void io_r(IO &io, DispatchIO<T> &a)
{
s64 v;
io.any(v);
*a.t->v = a.t->m * v;
}
template<typename IO, typename T>
void io_w(IO &io, const DispatchIO<T> &a)
{
s64 v = std::round(*a.t->v / a.t->m);
io.any(v);
}
template<typename IO, typename T>
void io_(IO &io, Accuracy<T> &a)
{
auto a_ = makeDispatchIO(a);
io.any(a_);
}
template<typename IO, typename R>
void io_(IO &io, Accuracy<Vector3<R>> &a)
{
auto &v = *a.v;
io.array(
with_accuracy(v[0], a.m),
with_accuracy(v[1], a.m),
with_accuracy(v[2], a.m)
);
}
template<typename IO, typename R>
void io_(IO &io, Accuracy<Vector2<R>> &a)
{
auto &v = *a.v;
io.array(
with_accuracy(v[0], a.m),
with_accuracy(v[1], a.m)
);
}
template<typename IO, typename R>
void io_(IO &io, Accuracy<Sphere3<R>> &a)
{
auto &v = *a.v;
io.object(
"center", with_accuracy(v.center, a.m),
"radius", with_accuracy(v.radius, a.m)
);
}
} // namespace
} // namespace
} // namespace

50
tjp/core/math/Accuracy.h Normal file
View File

@@ -0,0 +1,50 @@
//
// MathIO.h
// common
//
// Created by Timothy Prepscius on 8/4/18.
// Copyright © 2018 Timothy Prepscius. All rights reserved.
//
#pragma once
#include "Real.h"
namespace tjp {
namespace core {
namespace math {
template<typename V>
struct Accuracy
{
V *v;
Real m;
} ;
template<typename V>
Accuracy<V> with_accuracy(V &v, Real m)
{
return Accuracy<V> { &v, m };
}
constexpr s64 compile_time_pow10(const int digits)
{
if (digits == 0)
return 1;
return 10 * compile_time_pow10(digits-1);
}
constexpr Real accuracy_with_digits(const int digits)
{
if (digits < 0)
return 1.0 / compile_time_pow10(-digits);
return compile_time_pow10(digits);
}
} // namespace
} // namespace
} // namespace

View File

@@ -0,0 +1,71 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#include "Algorithm+Segment.hpp"
#include "Math.hpp"
namespace tjp {
namespace core {
namespace math {
template<>
std::tuple<math::Segment1<s64>, math::Segment1<s64>> bisectingSegments(const std::vector<math::Segment1<s64>> &v)
{
typedef s64 Real;
Real mean = 0;
int count = 0;
Real l, r;
bool first = true;
for (auto &s: v)
{
auto [l0, r0] = sortedSegment(s);
// auto numPoints = 10;
// auto d0 = r0 - l0;
// for (auto i=0; i<numPoints; ++i)
// {
// auto v = l0 + i * d0 / numPoints;
// middle += v;
// count++;
// }
mean += l0 + r0;
count += 2;
if (first)
{
first = false;
l = l0;
r = r0;
}
else
{
if (l0 < l)
l = l0;
if (r0 > r)
r = r0;
}
}
if (count > 0)
mean = mean / count;
// auto middle = (l + r) / 2;
// auto middle = l + (r - l) / 2;
auto ls = math::Segment1<Real> { l, mean };
auto rs = math::Segment1<Real> { mean, r };
return { ls, rs };
}
} // namespace
} // namespace
} // namespace

View File

@@ -0,0 +1,22 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#pragma once
#include "Algorithm.h"
namespace tjp {
namespace core {
namespace math {
} // namespace
} // namespace
} // namespace
#include "Algorithm+Segment.inl"

View File

@@ -0,0 +1,225 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#pragma once
#include "Algorithm.h"
#include "Math.hpp"
#include "Zero.h"
#include "Segment1.hpp"
namespace tjp {
namespace core {
namespace math {
template<typename Real>
std::tuple<Real,Real> sortedSegment(const Segment1<Real> &segment)
{
if (segment.begin < segment.end)
{
return { segment.begin, segment.end };
}
return { segment.end, segment.begin };
}
template<typename S, typename R>
bool intersects_segment (const S &l, const S &r, R error)
{
/*
abs((l.l+l.r)/2 - (r.l+r.r))/2 <= abs(l.r-l.l)/2 + abs(r.r-r.l)/2 + error
abs( (l.l+l.r) - (r.l+r.r) )/2 <= (abs(l.r-l.l) + abs(r.r-r.l)) / 2
abs( (l.l+l.r) + (r.l+r.r) ) <= 2 * abs(l.r-l.l) + abs(r.r-r.l) + 2*error
*/
// return distance((l.begin+l.end),(r.begin+r.end)) <= length(l) + length(r) + 2*error;
auto [l0,r0] = sortedSegment(l);
auto [l1,r1] = sortedSegment(r);
if (l1 <= l0+error && r1 >= r0-error)
return true;
if (l1 >= l0-error && l1 <= r0+error)
return true;
if (r1 >= l0-error && r1 <= r0+error)
return true;
return false;
}
template<typename S>
bool intersects_segment (const S &l, const S &r)
{
/*
abs((l.l+l.r)/2 - (r.l+r.r))/2 <= abs(l.r-l.l)/2 + abs(r.r-r.l)/2 + error
abs( (l.l+l.r) - (r.l+r.r) )/2 <= (abs(l.r-l.l) + abs(r.r-r.l)) / 2
abs( (l.l+l.r) + (r.l+r.r) ) <= 2 * abs(l.r-l.l) + abs(r.r-r.l) + 2*error
*/
// return distance((l.begin+l.end),(r.begin+r.end)) <= length(l) + length(r) + 2*error;
auto [l0,r0] = sortedSegment(l);
auto [l1,r1] = sortedSegment(r);
if (l1 <= l0 && r1 >= r0)
return true;
if (l1 >= l0 && l1 <= r0)
return true;
if (r1 >= l0 && r1 <= r0)
return true;
return false;
}
template<typename Real>
bool intersects(const Segment1<Real> &s0, const Segment1<Real> &s1, const Real &error)
{
return intersects_segment(s0, s1, error);
}
template<typename Real>
bool intersects(const Segment1<Real> &s0, const Segment1<Real> &s1)
{
return intersects_segment(s0, s1);
}
template<typename Real>
Real distance(const Segment1<Real> &segment, const Real &p)
{
auto [l, r] = sortedSegment(segment);
if (p <= l)
return l - p;
if (p >= r)
return p - r;
return -std::min(distance(p,l), distance(p,r));
}
template<typename S, typename R>
bool intersects_segment_point (const S &s, const R &p, R error)
{
auto [l, r] = sortedSegment(s);
return (l <= p) && (p <= r);
}
template<typename S>
bool contains_segment (const S &l, const S &r)
{
auto [l0,r0] = sortedSegment(l);
auto [l1,r1] = sortedSegment(r);
if (l0 <= l1 && r0 >= r1)
return true;
return false;
}
template<typename S, typename R>
bool contains_segment (const S &l, const S &r, R error)
{
auto [l0,r0] = sortedSegment(l);
auto [l1,r1] = sortedSegment(r);
if (l0 <= l1+error && r0 >= r1-error)
return true;
return false;
}
template<typename Real>
bool contains (const math::Segment1<Real> &l, const math::Segment1<Real> &r)
{
return contains_segment(l, r);
}
template<typename Real>
bool contains (const math::Segment1<Real> &l, const math::Segment1<Real> &r, Real error)
{
return contains_segment(l, r, error);
}
template<typename Real>
std::tuple<math::Segment1<Real>, math::Segment1<Real>> bisectingSegments(const std::vector<math::Segment1<Real>> &v)
{
Real l, r;
bool first = true;
for (auto &s: v)
{
auto [l0, r0] = sortedSegment(s);
if (first)
{
first = false;
l = l0;
r = r0;
}
else
{
if (l0 < l)
l = l0;
if (r0 > r)
r = r0;
}
}
auto middle = (l + r) / 2;
// auto middle = l + (r - l) / 2;
auto ls = math::Segment1<Real> { l, middle };
auto rs = math::Segment1<Real> { middle, r };
return { ls, rs };
}
template<>
std::tuple<math::Segment1<s64>, math::Segment1<s64>> bisectingSegments(const std::vector<math::Segment1<s64>> &v);
template<typename Real>
math::Segment1<Real> segmentContaining(const std::vector<math::Segment1<Real>> &v, const math::Segment1<Real> &zero)
{
if (v.empty())
return zero;
Real l, r;
bool first = true;
for (auto &s: v)
{
auto [l0, r0] = sortedSegment(s);
if (first)
{
first = false;
l = l0;
r = r0;
}
else
{
if (l0 < l)
l = l0;
if (r0 > r)
r = r0;
}
}
auto s = math::Segment1<Real> { l, r };
return s;
}
} // namespace
} // namespace
} // namespace

View File

@@ -0,0 +1,102 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#include "Algorithm+SimplifyCurve.hpp"
#include "Math.hpp"
#include "Algorithm.hpp"
namespace tjp {
namespace core {
namespace math {
typedef math::Vector3r SimplifyVertex;
typedef core::MemoryArray<SimplifyVertex> SimplifyPoints;
// read this and made this, not sure if the same
// https://towardsdatascience.com/simplify-polylines-with-the-douglas-peucker-algorithm-ac8ed487a4a1
typedef std::vector<size_t> SimplifyResult;
void simplify(SimplifyResult &result, const SimplifyPoints &points, size_t from, size_t to, size_t iterations)
{
if (to == from)
return;
Segment3<Real> segment { points[from], points[to] };
size_t farthest = 0;
Real farthestDistance = 0;
for (auto i = from+1; i!=to; ++i)
{
auto distance = math::distance(segment, points[i]);
if (!farthest || distance > farthestDistance)
{
farthest = i;
farthestDistance = distance;
}
}
if (farthest && iterations > 0)
{
simplify(result, points, from , farthest, iterations-1);
simplify(result, points, farthest, to, iterations-1);
}
else
{
if (farthest)
result.push_back(farthest);
result.push_back(to);
}
}
SimplifyResult simplify(const SimplifyPoints &points, size_t iterations)
{
if (points.size() < 2)
return SimplifyResult {};
size_t farthest = 0;
auto begin = 0;
auto end = points.size()-1;
Real farthestDistance = 0;
SimplifyResult result;
result.push_back(begin);
if (points.front() == points.back())
{
for (auto to=1; to!=end; ++to)
{
auto distance = math::distance(points[begin], points[to]);
if (!farthest || distance > farthestDistance)
{
farthest = to;
farthestDistance = distance;
}
}
simplify(result, points, begin, farthest, iterations-1);
if (farthest != end)
simplify(result, points, farthest, end, iterations-1);
}
else
{
simplify(result, points, begin, end, iterations);
}
return result;
}
} // namespace
} // namespace
} // namespace

View File

@@ -0,0 +1,49 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#pragma once
#include "Algorithm.h"
#include <tjp/core/containers/MemoryArray.hpp>
namespace tjp {
namespace core {
namespace math {
std::vector<size_t> simplify(const core::MemoryArray<math::Vector3r> &points, size_t iterations);
template<typename T, typename F>
std::vector<size_t> simplify(const T &points_, size_t iterations, F &&f)
{
std::vector<math::Vector3r> points;
for (auto &v: points_)
{
points.push_back(f(v));
}
return simplify(points, iterations);
}
template<typename T>
T simplified(const T &t, const std::vector<size_t> &indices)
{
T result;
result.reserve(indices.size());
for (auto &i : indices)
{
result.push_back(t[i]);
}
return result;
}
} // namespace
} // namespace
} // namespace

View File

@@ -0,0 +1,197 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#pragma once
#include "Algorithm+Split.hpp"
#include "Algorithm.inl"
#include "Math.hpp"
#include "BigInt.h"
#include "BigDecimal.h"
#include <tjp/core/log/Log.h>
#include <tjp/core/log/LogOf.h>
namespace tjp {
namespace core {
namespace math {
template<typename C, typename D, typename I>
Sphere1<C, D> sphereContaining_points(I i, I end, const Sphere1<C, D> &emptyValue)
{
if (i == end)
return emptyValue;
auto &s = *i;
auto l = s;
auto r = s;
sLogDebug("sphereContaining_spheres", logVar(s));
for (++i; i != end; ++i)
{
auto &v = *i;
l = min_value(l, v);
r = max_value(r, v);
sLogDebug("sphereContaining_spheres", logVar(*i) << logVar(l) << logVar(r));
}
auto c = (l+r)/2;
auto rmc = distance(r,c);
auto cml = distance(c,l);
sLogDebug("sphereContaining_spheres", logVar(c) << logVar(rmc) << logVar(cml));
auto radius = max_value(rmc, cml);
sLogDebug("sphereContaining_spheres", logVar(c) << logVar(radius));
return { c, radius };
}
template<typename C, typename D>
std::tuple<math::Sphere1<C,D>, math::Sphere1<C,D>> bisectingRegions(const std::vector<C> &translates_)
{
debug_assert(!translates_.empty());
debug_assert(translates_.size() > 1);
auto sortable = translates_;
std::sort(sortable.begin(), sortable.end());
auto begin = sortable.begin();
auto halfL = begin + sortable.size()/2;
auto halfR = halfL + 1;
auto end = sortable.end();
auto l = sphereContaining_points(begin, halfR, Sphere1<C,D>::Zero);
auto r = sphereContaining_points(halfR, end, Sphere1<C,D>::Zero);
#ifdef _DEBUG
for (auto i=begin; i != halfR; ++i)
{
if (!intersects(l, *i))// || intersects(r, *i))
{
for (auto i=begin; i!=halfR; ++i)
{
sLogDebug("debug", "L " << logVar(*i));
}
for (auto i=halfR; i!=end; ++i)
{
sLogDebug("debug", "R " << logVar(*i));
}
sLogDebug("debug", logVar(l) << logVar(r) << logVar(*i) << logVar(distance(l.center, *i)));
{
auto sortable = translates_;
std::sort(sortable.begin(), sortable.end());
auto begin = sortable.begin();
auto halfL = begin + sortable.size()/2;
auto halfR = halfL + 1;
auto l = sphereContaining_points(begin, halfR, Sphere1<C,D>::Zero);
intersects(l, *i);
}
}
debug_assert(intersects(l, *i));
// debug_assert(!intersects(r, *i));
}
for (auto i=halfR; i != end; ++i)
{
if (!intersects(r, *i))
{
for (auto i=begin; i!=halfR; ++i)
{
sLogDebug("debug", "L " << logVar(*i));
}
for (auto i=halfR; i!=end; ++i)
{
sLogDebug("debug", "R " << logVar(*i));
}
sLogDebug("debug", logVar(l) << logVar(r) << logVar(*i) << logVar(distance(r.center, *i)));
auto r = sphereContaining_points(halfR, end, Sphere1<C,D>::Zero);
intersects(r, *i);
}
debug_assert(intersects(r, *i));
// debug_assert(!intersects(l, *i));
}
#endif
return { l, r };
}
template<typename C, typename D, typename I>
Sphere1<C, D> sphereContaining_spheres(I begin, I end, const Sphere1<C, D> &emptyValue)
{
if (begin == end)
return emptyValue;
auto c = begin->center;
auto i=begin;
++i;
size_t count = 0;
for (;i!=end; ++i)
{
c = c + i->center;
count++;
}
c = c / count;
auto radius = distance(begin->center, c) + begin->radius;
i = begin;
++i;
for (;i!=end; ++i)
{
auto v = distance(i->center, c) + i->radius;
radius = max_value(radius, v);
}
return { c, radius };
}
template<typename C, typename D>
math::Sphere1<C, D> sphereContaining(const std::vector<math::Sphere1<C, D>> &spheres, const math::Sphere1<C, D> &emptyValue)
{
return sphereContaining_spheres<C, D>(spheres.begin(), spheres.end(), emptyValue);
}
template<typename Real, typename T, typename F>
math::Sphere3<Real> sphereContaining(const math::Sphere3<Real> &emptyValue, T &t, F &&f)
{
std::vector<math::Sphere3<Real>> spheres;
for (auto &v : t)
spheres.push_back(f(v));
return sphereContaining(spheres, emptyValue);
}
template<typename C, typename D, typename T, typename F>
math::Sphere1<C, D> sphereContaining(const math::Sphere1<C, D> &emptyValue, T &t, F &&f)
{
std::vector<math::Sphere1<C, D>> spheres;
for (auto &v : t)
spheres.push_back(f(v));
return sphereContaining(spheres, emptyValue);
}
} // namespace
} // namespace
} // namespace

178
tjp/core/math/Algorithm+Split.cpp Executable file
View File

@@ -0,0 +1,178 @@
//
// Math.cpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#include "Algorithm+Split.hpp"
#include "Sphere3.hpp"
#include <tjp/core/assert/debug_assert.h>
#define dynamic_cast static_cast
#define GTE_NO_LOGGER
#include <Mathematics/ApprOrthogonalLine3.h>
#include <Mathematics/ContSphere3.h>
#include <Mathematics/MinimumVolumeSphere3.h>
#include <Mathematics/IntrSphere3Frustum3.h>
#include <Mathematics/IntrRay3Sphere3.h>
#include <Mathematics/IntrSphere3Cone3.h>
#include <Mathematics/DistPointRay.h>
#include <Mathematics/IntrRay3Plane3.h>
#include <Mathematics/DistPointRay.h>
#include <Mathematics/DistPointSegment.h>
#include "GTE_convert.hpp"
#undef dynamic_cast
#include <vector>
#include <tjp/core/log/Log.h>
#include <tjp/core/log/LogOf.h>
namespace tjp {
namespace core {
namespace math {
template<typename Real>
std::tuple<math::Sphere3<Real>, math::Sphere3<Real>> bisectingRegions_(const std::vector<math::Vector3<Real>> &translates_)
{
std::vector<gte::Vector3<Real>> translates;
for (auto &p : translates_)
translates.push_back(gte_c(p));
gte::ApprOrthogonalLine3<Real> orthogonalLineFit;
orthogonalLineFit.Fit((int)translates.size(), translates.data());
auto &line = orthogonalLineFit.GetParameters();
std::vector<gte::Vector3<Real>> left, right;
for (auto &t : translates)
{
if (gte::Dot((t - line.origin), line.direction) > 0)
right.push_back(t);
else
left.push_back(t);
}
// {
// auto mean = statistics::mean<Vector3r::Super>(left);
// auto stdev = statistics::stdev<Real, Vector3r::Super>(left, mean);
//
// for (auto &t : left)
// {
// if (length(t - mean) < 2*stdev)
// culledLeft.push_back(t);
// }
// }
// {
// auto mean = statistics::mean<Vector3r::Super>(right);
// auto stdev = statistics::stdev<Real, Vector3r::Super>(right, mean);
//
// vector<Vector3r::Super> culled;
// for (auto &t : right)
// {
// if (length(t - mean) < 2*stdev)
// culledRight.push_back(t);
// }
// }
sLogRelease("wired::split", logVar(left.size()) << logVar(right.size()));
// ensure there is data in both sets
if (left.empty())
left = right;
if (right.empty())
right = left;
gte::Sphere3<Real> leftSphere;
// gte::MinimumVolumeSphere3<Real, Real> leftSphereMinimum;
gte::GetContainer(left, leftSphere);
gte::Sphere3<Real> rightSphere;
// gte::MinimumVolumeSphere3<Real, Real> rightSphereMinimum;
gte::GetContainer(right, rightSphere);
return { gte_c(leftSphere), gte_c(rightSphere) };
}
template<>
std::tuple<math::Sphere3<r32>, math::Sphere3<r32>> bisectingRegions(const std::vector<math::Vector3<r32>> &points)
{
return bisectingRegions_(points);
}
template<>
std::tuple<math::Sphere3<r64>, math::Sphere3<r64>> bisectingRegions(const std::vector<math::Vector3<r64>> &points)
{
return bisectingRegions_(points);
}
// ---------------------------------
template<typename Real>
Sphere3<Real> sphereContaining_(const std::vector<Vector3<Real>> &points, const Sphere3<Real> &emptyValue)
{
if (points.empty())
return emptyValue;
std::vector<gte::Vector3<Real>> points_;
points_.reserve(points.size());
for (auto &p: points)
points_.push_back(gte_c(p));
gte::Sphere3<Real> sphere;
gte::GetContainer(points_, sphere);
return gte_c(sphere);
}
template<>
Sphere3<r64> sphereContaining(const std::vector<Vector3<r64>> &points, const Sphere3<r64> &emptyValue)
{
return sphereContaining_(points, emptyValue);
}
template<typename Real>
Sphere3<Real> sphereContaining_(const std::vector<Sphere3<Real>> &spheres, const Sphere3<Real> &emptyValue)
{
if (spheres.empty())
return emptyValue;
auto sphere = gte_c(spheres.front());
if (sphere.radius == Sphere3<Real>::Infinite.radius)
return Sphere3<Real>::Infinite;
for (auto i=spheres.begin()+1; i!=spheres.end(); ++i)
{
if (i->radius == Sphere3<Real>::Infinite.radius)
return Sphere3<Real>::Infinite;
gte::Sphere3<Real> merge;
gte::MergeContainers(sphere, gte_c(*i), merge);
sphere = merge;
}
return gte_c(sphere);
}
template<>
Sphere3<r32> sphereContaining(const std::vector<Sphere3<r32>> &spheres, const Sphere3<r32> &emptyValue)
{
return sphereContaining_(spheres, emptyValue);
}
template<>
Sphere3<r64> sphereContaining(const std::vector<Sphere3<r64>> &spheres, const Sphere3<r64> &emptyValue)
{
return sphereContaining_(spheres, emptyValue);
}
} // namespace
} // namespace
} // namespace

View File

@@ -0,0 +1,34 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#pragma once
#include "Algorithm.hpp"
namespace tjp {
namespace core {
namespace math {
template<>
std::tuple<math::Sphere3<r32>, math::Sphere3<r32>> bisectingRegions(const std::vector<math::Vector3<r32>> &points);
template<>
std::tuple<math::Sphere3<r64>, math::Sphere3<r64>> bisectingRegions(const std::vector<math::Vector3<r64>> &points);
template<>
math::Sphere3<r32> sphereContaining(const std::vector<math::Sphere3<r32>> &spheres, const math::Sphere3<r32> &emptyValue);
template<>
math::Sphere3<r64> sphereContaining(const std::vector<math::Sphere3<r64>> &spheres, const math::Sphere3<r64> &emptyValue);
} // namespace
} // namespace
} // namespace
#include "Algorithm+Split.inl"

195
tjp/core/math/Algorithm+Split.inl Executable file
View File

@@ -0,0 +1,195 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#pragma once
#include "Algorithm+Split.hpp"
#include "Algorithm.inl"
#include "Math.hpp"
#include <tjp/core/log/Log.h>
#include <tjp/core/log/LogOf.h>
namespace tjp {
namespace core {
namespace math {
template<typename C, typename D, typename I>
Sphere1<C, D> sphereContaining_points(I i, I end, const Sphere1<C, D> &emptyValue)
{
if (i == end)
return emptyValue;
auto &s = *i;
auto l = s;
auto r = s;
sLogDebug("sphereContaining_spheres", logVar(s));
for (++i; i != end; ++i)
{
auto &v = *i;
l = min_value(l, v);
r = max_value(r, v);
sLogDebug("sphereContaining_spheres", logVar(*i) << logVar(l) << logVar(r));
}
auto c = (l+r)/2;
auto rmc = distance(r,c);
auto cml = distance(c,l);
sLogDebug("sphereContaining_spheres", logVar(c) << logVar(rmc) << logVar(cml));
auto radius = max_value(rmc, cml);
sLogDebug("sphereContaining_spheres", logVar(c) << logVar(radius));
return { c, radius };
}
template<typename C, typename D>
std::tuple<math::Sphere1<C,D>, math::Sphere1<C,D>> bisectingRegions(const std::vector<C> &translates_)
{
debug_assert(!translates_.empty());
debug_assert(translates_.size() > 1);
auto sortable = translates_;
std::sort(sortable.begin(), sortable.end());
auto begin = sortable.begin();
auto halfL = begin + sortable.size()/2;
auto halfR = halfL + 1;
auto end = sortable.end();
auto l = sphereContaining_points(begin, halfR, Sphere1<C,D>::Zero);
auto r = sphereContaining_points(halfR, end, Sphere1<C,D>::Zero);
#ifdef _DEBUG
for (auto i=begin; i != halfR; ++i)
{
if (!intersects(l, *i))// || intersects(r, *i))
{
for (auto i=begin; i!=halfR; ++i)
{
sLogDebug("debug", "L " << logVar(*i));
}
for (auto i=halfR; i!=end; ++i)
{
sLogDebug("debug", "R " << logVar(*i));
}
sLogDebug("debug", logVar(l) << logVar(r) << logVar(*i) << logVar(distance(l.center, *i)));
{
auto sortable = translates_;
std::sort(sortable.begin(), sortable.end());
auto begin = sortable.begin();
auto halfL = begin + sortable.size()/2;
auto halfR = halfL + 1;
auto l = sphereContaining_points(begin, halfR, Sphere1<C,D>::Zero);
intersects(l, *i);
}
}
debug_assert(intersects(l, *i));
// debug_assert(!intersects(r, *i));
}
for (auto i=halfR; i != end; ++i)
{
if (!intersects(r, *i))
{
for (auto i=begin; i!=halfR; ++i)
{
sLogDebug("debug", "L " << logVar(*i));
}
for (auto i=halfR; i!=end; ++i)
{
sLogDebug("debug", "R " << logVar(*i));
}
sLogDebug("debug", logVar(l) << logVar(r) << logVar(*i) << logVar(distance(r.center, *i)));
auto r = sphereContaining_points(halfR, end, Sphere1<C,D>::Zero);
intersects(r, *i);
}
debug_assert(intersects(r, *i));
// debug_assert(!intersects(l, *i));
}
#endif
return { l, r };
}
template<typename C, typename D, typename I>
Sphere1<C, D> sphereContaining_spheres(I begin, I end, const Sphere1<C, D> &emptyValue)
{
if (begin == end)
return emptyValue;
auto c = begin->center;
auto i=begin;
++i;
size_t count = 0;
for (;i!=end; ++i)
{
c = c + i->center;
count++;
}
c = c / count;
auto radius = distance(begin->center, c) + begin->radius;
i = begin;
++i;
for (;i!=end; ++i)
{
auto v = distance(i->center, c) + i->radius;
radius = max_value(radius, v);
}
return { c, radius };
}
template<typename C, typename D>
math::Sphere1<C, D> sphereContaining(const std::vector<math::Sphere1<C, D>> &spheres, const math::Sphere1<C, D> &emptyValue)
{
return sphereContaining_spheres<C, D>(spheres.begin(), spheres.end(), emptyValue);
}
template<typename Real, typename T, typename F>
math::Sphere3<Real> sphereContaining(const math::Sphere3<Real> &emptyValue, T &t, F &&f)
{
std::vector<math::Sphere3<Real>> spheres;
for (auto &v : t)
spheres.push_back(f(v));
return sphereContaining(spheres, emptyValue);
}
template<typename C, typename D, typename T, typename F>
math::Sphere1<C, D> sphereContaining(const math::Sphere1<C, D> &emptyValue, T &t, F &&f)
{
std::vector<math::Sphere1<C, D>> spheres;
for (auto &v : t)
spheres.push_back(f(v));
return sphereContaining(spheres, emptyValue);
}
} // namespace
} // namespace
} // namespace

414
tjp/core/math/Algorithm.cpp Executable file
View File

@@ -0,0 +1,414 @@
//
// Math.cpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#include "Algorithm.h"
#include "Sphere3.hpp"
#include <tjp/core/assert/debug_assert.h>
#include <tjp/core/algorithm/is_in.hpp>
#define GTE_NO_LOGGER
#include <Mathematics/ApprOrthogonalLine3.h>
#include <Mathematics/ContSphere3.h>
#include <Mathematics/MinimumVolumeSphere3.h>
#include <Mathematics/IntrSphere3Frustum3.h>
#include <Mathematics/IntrRay3Sphere3.h>
#include <Mathematics/IntrSphere3Cone3.h>
#include <Mathematics/IntrSphere3Sphere3.h>
#include <Mathematics/IntrOrientedBox3Frustum3.h>
#include <Mathematics/DistPointRay.h>
#include <Mathematics/DistPointSegment.h>
#include <Mathematics/DistPoint3Plane3.h>
#include <Mathematics/DistLine3Triangle3.h>
#include <Mathematics/IntrRay3Plane3.h>
#include "GTE_convert.hpp"
#include <vector>
namespace tjp {
namespace core {
namespace math {
// ---------------------------------
template<typename R>
R distance_ (const math::Ray3<R> &ray, const math::Vector3<R> &r)
{
auto ray_ = gte_c(ray);
auto point_ = gte_c(r);
gte::DCPPoint3Ray3<R> query;
auto result = query(point_, ray_);
return result.distance;
}
template<>
r32 distance (const math::Ray3<r32> &ray, const math::Vector3<r32> &r)
{
return distance_(ray, r);
}
template<>
r64 distance (const math::Ray3<r64> &ray, const math::Vector3<r64> &r)
{
return distance_(ray, r);
}
// ---------------------------------
template<typename R>
R distance_ (const math::Segment3<R> &ray, const math::Vector3<R> &r)
{
auto segment_ = gte_c(ray);
auto point_ = gte_c(r);
gte::DCPPoint3Segment3<R> query;
auto result = query(point_, segment_);
return result.distance;
}
template<>
r32 distance (const math::Segment3<r32> &ray, const math::Vector3<r32> &r)
{
return distance_(ray, r);
}
template<>
r64 distance (const math::Segment3<r64> &ray, const math::Vector3<r64> &r)
{
return distance_(ray, r);
}
// ---------------------------------
template<typename Real>
bool intersects_ (const Sphere3<Real> &sphere, const Frustum3<Real> &frustum)
{
auto sphere_ = gte_c(sphere);
auto frustum_ = gte_c(frustum);
gte::TIQuery<Real, gte::Sphere3<Real>, gte::Frustum3<Real>> query;
auto result = query(sphere_, frustum_);
return result.intersect;
}
template<typename Real>
bool intersects_ (const Sphere3<Real> &sphere, const Cone3<Real> &cone)
{
auto sphere_ = gte_c(sphere);
auto cone_ = gte_c(cone);
gte::TIQuery<Real, gte::Sphere3<Real>, gte::Cone3<Real>> query;
auto result = query(sphere_, cone_);
return result.intersect;
}
template<typename Real>
bool intersects_ (const Box3<Real> &lhs_, const Frustum3<Real> &rhs_)
{
auto lhs = gte_c(lhs_);
auto rhs = gte_c(rhs_);
gte::TIQuery<Real, decltype(lhs), decltype(rhs)> query;
auto result = query(lhs, rhs);
return result.intersect;
}
template<typename Real>
bool intersects_ (const Vector3<Real> &point, const Frustum3<Real> &frustum)
{
auto frustum_ = gte_c(frustum);
auto point_ = gte_c(point);
gte::DCPQuery<Real, gte::Vector3<Real>, gte::Frustum3<Real>> query;
auto result = query(point_, frustum_);
return result.distance == 0;
}
template<typename Real>
std::tuple<bool, Vector3<Real>> intersection_ (const Ray3<Real> &ray, const Sphere3<Real> &sphere)
{
auto ray_ = gte_c(ray);
auto sphere_ = gte_c(sphere);
gte::FIQuery<Real, gte::Ray3<Real>, gte::Sphere3<Real>> query;
auto result = query(ray_, sphere_);
if (result.intersect)
{
return { true, gte_c(result.point[0]) };
}
return { false, {} };
}
template<typename Real>
std::tuple<bool, Vector3<Real>> intersection_ (const Ray3<Real> &ray, const Plane3<Real> &plane)
{
auto ray_ = gte_c(ray);
auto plane_ = gte_c(plane);
gte::FIQuery<Real, gte::Ray3<Real>, gte::Plane3<Real>> query;
auto result = query(ray_, plane_);
if (result.intersect)
{
return { true, gte_c(result.point) };
}
return { false, {} };
}
template<typename Real>
std::tuple<bool, Circle3<Real>> intersection_ (const Sphere3<Real> &l, const Sphere3<Real> &r)
{
auto l_ = gte_c(l);
auto r_ = gte_c(r);
gte::FIQuery<Real, gte::Sphere3<Real>, gte::Sphere3<Real>> query;
auto result = query(l_, r_);
if (result.intersect)
{
if (is_in(result.type, 1, 4, 6))
{
return { true, { gte_c(result.point), math::Vector3<Real>::Zero, 0 } };
}
return { true, gte_c(result.circle) };
}
return { false, {} };
}
// -------------------
//template<>
//bool intersects (const math::Vector3<r32> &point, const math::Sphere3<r32> &rhs)
//{
// return intersects_(point, rhs);
//}
//
//template<>
//bool intersects (const math::Vector3<r64> &point, const math::Sphere3<r64> &rhs)
//{
// return intersects_(point, rhs);
//}
//
template<>
bool intersects (const math::Sphere3<r32> &sphere, const math::Frustum3<r32> &rhs)
{
return intersects_(sphere, rhs);
}
template<>
bool intersects (const math::Sphere3<r64> &sphere, const math::Frustum3<r64> &rhs)
{
return intersects_(sphere, rhs);
}
template<>
bool intersects (const math::Sphere3<r32> &sphere, const math::Cone3<r32> &rhs)
{
return intersects_(sphere, rhs);
}
template<>
bool intersects (const math::Sphere3<r64> &sphere, const math::Cone3<r64> &rhs)
{
return intersects_(sphere, rhs);
}
template<>
bool intersects (const math::Box3<r32> &lhs, const math::Frustum3<r32> &rhs)
{
return intersects_(lhs, rhs);
}
template<>
bool intersects (const math::Box3<r64> &lhs, const math::Frustum3<r64> &rhs)
{
return intersects_(lhs, rhs);
}
template<>
bool intersects (const math::Vector3<r32> &point, const math::Frustum3<r32> &rhs)
{
return intersects_(point, rhs);
}
template<>
bool intersects (const math::Vector3<r64> &point, const math::Frustum3<r64> &rhs)
{
return intersects_(point, rhs);
}
//template<>
//bool intersects (const math::Segment2<r32> &segment, const math::Circle2<r32> &rhs)
//{
// return intersects_(segment, rhs);
//}
//
//template<>
//bool intersects (const math::Segment2<r64> &segment, const math::Circle2<r64> &rhs)
//{
// return intersects_(segment, rhs);
//}
template<>
std::tuple<bool, math::Vector3<r32>> intersection (const math::Ray3<r32> &ray, const math::Sphere3<r32> &rhs)
{
return intersection_(ray, rhs);
}
template<>
std::tuple<bool, math::Vector3<r64>> intersection (const math::Ray3<r64> &ray, const math::Sphere3<r64> &rhs)
{
return intersection_(ray, rhs);
}
template<>
std::tuple<bool, math::Vector3<r32>> intersection (const math::Ray3<r32> &ray, const math::Plane3<r32> &rhs)
{
return intersection_(ray, rhs);
}
template<>
std::tuple<bool, math::Vector3<r64>> intersection (const math::Ray3<r64> &ray, const math::Plane3<r64> &rhs)
{
return intersection_(ray, rhs);
}
// ----
template<>
std::tuple<bool, math::Circle3<r32>> intersection (const math::Sphere3<r32> &lhs, const math::Sphere3<r32> &rhs)
{
return intersection_(lhs, rhs);
}
template<>
std::tuple<bool, math::Circle3<r64>> intersection (const math::Sphere3<r64> &lhs, const math::Sphere3<r64> &rhs)
{
return intersection_(lhs, rhs);
}
// ----
template<typename Real>
std::tuple<Real, math::Vector3<Real>> closest_(const math::Ray3<Real> &ray, const math::Vector3<Real> &point)
{
auto ray_ = gte_c(ray);
auto point_ = gte_c(point);
gte::DCPPoint3Ray3<Real> dcp;
auto result = dcp(point_, ray_);
gte::Vector3<Real> &closest = result.rayClosest;
return { result.distance, gte_c(closest) };
}
template<>
std::tuple<r64, math::Vector3<r64>> closest(const math::Ray3<r64> &ray, const math::Vector3<r64> &point)
{
return closest_(ray, point);
}
template<>
std::tuple<r32, math::Vector3<r32>> closest(const math::Ray3<r32> &ray, const math::Vector3<r32> &point)
{
return closest_(ray, point);
}
template<typename Real>
std::tuple<Real, math::Vector3<Real>> closest_(const math::Segment3<Real> &ray, const math::Vector3<Real> &point)
{
auto ray_ = gte_c(ray);
auto point_ = gte_c(point);
gte::DCPPoint3Segment3<Real> dcp;
auto result = dcp(point_, ray_);
gte::Vector3<Real> &closest = result.segmentClosest;
return { result.distance, gte_c(closest) };
}
template<>
std::tuple<r64, math::Vector3<r64>> closest(const math::Segment3<r64> &ray, const math::Vector3<r64> &point)
{
return closest_(ray, point);
}
template<>
std::tuple<r32, math::Vector3<r32>> closest(const math::Segment3<r32> &ray, const math::Vector3<r32> &point)
{
return closest_(ray, point);
}
// ------------
template<typename Real>
std::tuple<Real, math::Vector3<Real>> closest_(const math::Plane3<Real> &plane, const math::Vector3<Real> &point)
{
auto plane_ = gte_c(plane);
auto point_ = gte_c(point);
gte::DCPQuery<Real, gte::Vector3<Real>, gte::Plane3<Real>> dcp;
auto result = dcp(point_, plane_);
gte::Vector3<Real> &closest = result.planeClosestPoint;
return { result.distance, gte_c(closest) };
}
template<>
std::tuple<r64, math::Vector3<r64>> closest(const math::Plane3<r64> &plane, const math::Vector3<r64> &point)
{
return closest_(plane, point);
}
// ------------
template<typename Real>
Real distance_(const math::Triangle3<Real> &plane, const math::Line3<Real> &line)
{
auto plane_ = gte_c(plane);
auto line_ = gte_c(line);
gte::DCPQuery<Real, gte::Line3<Real>, gte::Triangle3<Real>> dcp;
auto result = dcp(line_, plane_);
return result.distance;
}
template<>
r64 distance(const math::Triangle3<r64> &plane, const math::Line3<r64> &line)
{
return distance_(plane, line);
}
// ------------
template<>
bool intersects(const math::Triangle3<r64> &plane, const math::Ray3<r64> &line, r64 epsilon)
{
math::Line3<r64> l = { line.origin, line.direction };
return distance(plane, l) < epsilon;
}
} // namespace
} // namespace
} // namespace

124
tjp/core/math/Algorithm.h Executable file
View File

@@ -0,0 +1,124 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#pragma once
#include "Math.h"
#include "Sphere1.h"
#include "Sphere3.h"
#include "Vector3.h"
#include "Box3.h"
#include <tuple>
#include <vector>
#include "Epsilon.h"
namespace tjp {
namespace core {
namespace math {
template<typename Real>
std::tuple<math::Sphere3<Real>, math::Sphere3<Real>> bisectingRegions(const std::vector<math::Vector3<Real>> &points);
template<typename C, typename D=C>
std::tuple<math::Sphere1<C,D>, math::Sphere1<C,D>> bisectingRegions(const std::vector<C> &points);
template<typename Real>
math::Sphere3<Real> sphereContaining(const std::vector<math::Vector3<Real>> &spheres, const math::Sphere3<Real> &emptyValue);
template<typename Real>
math::Sphere3<Real> sphereContaining(const std::vector<math::Sphere3<Real>> &spheres, const math::Sphere3<Real> &emptyValue);
template<typename C, typename D>
math::Sphere1<C,D> sphereContaining(const std::vector<math::Sphere1<C,D>> &spheres, const math::Sphere1<C,D> &emptyValue);
template<typename Real, typename T, typename F>
math::Sphere3<Real> sphereContaining(const math::Sphere3<Real> &emptyValue, T &t, F &&f);
template<typename C, typename D, typename T, typename F>
math::Sphere1<C,D> sphereContaining(const math::Sphere1<C,D> &emptyValue, T &t, F &&f);
// ---------------------
template<typename Real>
Real distance (const math::Ray3<Real> &ray, const math::Vector3<Real> &r);
template<typename Real>
Real distance (const math::Segment3<Real> &ray, const math::Vector3<Real> &r);
template<typename Real>
bool intersects (const math::Sphere3<Real> &sphere, const math::Cone3<Real> &rhs);
// ---------------------
template<typename Real>
bool contains (const math::Sphere3<Real> &parent, const math::Sphere3<Real> &child, Real error = epsilon<Real>());
template<typename C, typename D>
bool contains (const math::Sphere1<C,D> &parent, const math::Sphere1<C,D> &child, D error = epsilon<D>());
// ---------------------
template<typename Real>
bool intersects (const math::Sphere3<Real> &sphere, const math::Sphere3<Real> &rhs, Real error = epsilon<Real>());
template<typename C, typename D>
bool intersects (const math::Sphere1<C,D> &sphere, const math::Sphere1<C,D> &rhs, D error = epsilon<D>());
template<typename C, typename D>
bool intersects (const math::Sphere1<C,D> &sphere, const C &rhs, D error = epsilon<D>());
template<typename D>
bool intersects(const math::Triangle3<D> &plane, const math::Ray3<D> &line, D error = epsilon<D>());
// ---------------------
template<typename Real>
bool intersects (const math::Vector3<Real> &point, const math::Sphere3<Real> &rhs);
template<typename Real>
bool intersects (const math::Sphere3<Real> &sphere, const math::Frustum3<Real> &rhs);
template<typename Real>
bool intersects (const math::Vector3<Real> &point, const math::Frustum3<Real> &rhs);
template<typename Real>
bool intersects (const math::Box3<Real> &rectangle, const math::Frustum3<Real> &rhs);
template<typename Real>
bool intersects (const math::Segment2<Real> &segment, const math::Circle2<Real> &rhs);
template<typename Real>
std::tuple<bool, math::Vector3<Real>> intersection (const math::Ray3<Real> &ray, const math::Sphere3<Real> &rhs);
template<typename Real>
std::tuple<bool, math::Vector3<Real>> intersection (const math::Ray3<Real> &ray, const math::Plane3<Real> &rhs);
template<typename Real>
std::tuple<Real, math::Vector3<Real>> closest(const math::Ray3<Real> &ray, const math::Vector3<Real> &point);
template<typename Real>
std::tuple<Real, math::Vector3<Real>> closest(const math::Segment3<Real> &ray, const math::Vector3<Real> &point);
template<typename Real>
std::tuple<bool, math::Circle3<Real>> intersection (const math::Sphere3<Real> &ray, const math::Sphere3<Real> &rhs);
template<typename Real>
std::tuple<Real, math::Vector3<Real>> closest(const math::Plane3<Real> &plane, const math::Vector3<Real> &point);
template<typename Real>
Real distance(const math::Triangle3<Real> &plane, const math::Line3<Real> &line);
} // namespace
} // namespace
} // namespace

130
tjp/core/math/Algorithm.hpp Executable file
View File

@@ -0,0 +1,130 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#pragma once
#include "Algorithm.h"
#include "Math.hpp"
namespace tjp {
namespace core {
namespace math {
template<>
r32 distance (const math::Ray3<r32> &ray, const math::Vector3<r32> &r);
template<>
r64 distance (const math::Ray3<r64> &ray, const math::Vector3<r64> &r);
template<>
r32 distance (const math::Segment3<r32> &ray, const math::Vector3<r32> &r);
template<>
r64 distance (const math::Segment3<r64> &ray, const math::Vector3<r64> &r);
template<>
std::tuple<math::Sphere3<r32>, math::Sphere3<r32>> bisectingRegions(const std::vector<math::Vector3<r32>> &points);
template<>
std::tuple<math::Sphere3<r64>, math::Sphere3<r64>> bisectingRegions(const std::vector<math::Vector3<r64>> &points);
template<>
math::Sphere3<r64> sphereContaining(const std::vector<math::Vector3<r64>> &points, const math::Sphere3<r64> &emptyValue);
template<>
math::Sphere3<r32> sphereContaining(const std::vector<math::Sphere3<r32>> &spheres, const math::Sphere3<r32> &emptyValue);
template<>
math::Sphere3<r64> sphereContaining(const std::vector<math::Sphere3<r64>> &spheres, const math::Sphere3<r64> &emptyValue);
template<>
bool intersects (const math::Vector3<r32> &point, const math::Sphere3<r32> &rhs);
template<>
bool intersects (const math::Vector3<r64> &point, const math::Sphere3<r64> &rhs);
template<>
bool intersects (const math::Sphere3<r32> &sphere, const math::Frustum3<r32> &rhs);
template<>
bool intersects (const math::Sphere3<r64> &sphere, const math::Frustum3<r64> &rhs);
template<>
bool intersects (const math::Box3<r32> &rectangle, const math::Frustum3<r32> &rhs);
template<>
bool intersects (const math::Box3<r64> &rectangle, const math::Frustum3<r64> &rhs);
template<>
bool intersects (const math::Vector3<r32> &point, const math::Frustum3<r32> &rhs);
template<>
bool intersects (const math::Vector3<r64> &point, const math::Frustum3<r64> &rhs);
template<>
bool intersects (const math::Sphere3<r64> &sphere, const math::Cone3<r64> &rhs);
template<>
bool intersects (const math::Sphere3<r32> &sphere, const math::Cone3<r32> &rhs);
template<>
bool intersects (const math::Segment2<r32> &segment, const math::Circle2<r32> &rhs);
template<>
bool intersects (const math::Segment2<r64> &segment, const math::Circle2<r64> &rhs);
template<>
std::tuple<bool, math::Vector3<r32>> intersection (const math::Ray3<r32> &ray, const math::Sphere3<r32> &rhs);
template<>
std::tuple<bool, math::Vector3<r64>> intersection (const math::Ray3<r64> &ray, const math::Sphere3<Real> &rhs);
template<>
std::tuple<bool, math::Vector3<r32>> intersection (const math::Ray3<r32> &ray, const math::Plane3<r32> &rhs);
template<>
std::tuple<bool, math::Vector3<r64>> intersection (const math::Ray3<r64> &ray, const math::Plane3<Real> &rhs);
template<>
std::tuple<r64, math::Vector3<r64>> closest(const math::Ray3<r64> &ray, const math::Vector3<r64> &point);
template<>
std::tuple<r32, math::Vector3<r32>> closest(const math::Ray3<r32> &ray, const math::Vector3<r32> &point);
template<>
std::tuple<r64, math::Vector3<r64>> closest(const math::Segment3<r64> &ray, const math::Vector3<r64> &point);
template<>
std::tuple<r32, math::Vector3<r32>> closest(const math::Segment3<r32> &ray, const math::Vector3<r32> &point);
template<>
std::tuple<bool, math::Circle3<r32>> intersection (const math::Sphere3<r32> &ray, const math::Sphere3<r32> &rhs);
template<>
std::tuple<bool, math::Circle3<r64>> intersection (const math::Sphere3<r64> &ray, const math::Sphere3<r64> &rhs);
template<>
std::tuple<r64, math::Vector3<r64>> closest(const math::Plane3<r64> &plane, const math::Vector3<r64> &point);
template<>
r64 distance(const math::Triangle3<r64> &plane, const math::Line3<r64> &line);
template<>
bool intersects(const math::Triangle3<r64> &plane, const math::Ray3<r64> &line, r64 error);
} // namespace
} // namespace
} // namespace
#include "Algorithm.inl"

77
tjp/core/math/Algorithm.inl Executable file
View File

@@ -0,0 +1,77 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#pragma once
#include "Algorithm.h"
#include "Math.hpp"
//#include "BigInt.hpp"
//#include "BigDecimal.hpp"
#include <tjp/core/log/LogOf.h>
#include "Vector3.inl"
#include "Real.inl"
#include "Distance.inl"
namespace tjp {
namespace core {
namespace math {
template<typename S, typename R>
bool intersects_sphere (const S &l, const S &r, R error)
{
return distance(l.center, r.center) <= (l.radius + r.radius) + error;
}
template<typename S, typename U, typename R>
bool intersects_sphere_point (const S &l, const U &r, R error)
{
return distance(l.center, r) <= (l.radius) + error;
}
template<typename Real>
bool intersects (const math::Sphere3<Real> &l, const math::Sphere3<Real> &r, Real error)
{
return distance_squared(l.center, r.center) - math::pow2(l.radius + r.radius + error) <= 0;
}
template<typename C, typename D>
bool intersects (const math::Sphere1<C,D> &l, const C &r, D error)
{
return intersects_sphere_point(l, r, error);
}
template<typename C, typename D>
bool intersects (const math::Sphere1<C,D> &l, const math::Sphere1<C,D> &r, D error)
{
return intersects_sphere(l, r, error);
}
template<typename S, typename R>
bool contains_sphere (const S &l, const S &r, R error)
{
return distance(l.center, r.center) + r.radius <= l.radius + error;
}
template<typename Real>
bool contains (const math::Sphere3<Real> &l, const math::Sphere3<Real> &r, Real error)
{
return contains_sphere(l, r, error);
}
template<typename C, typename D>
bool contains (const math::Sphere1<C,D> &l, const math::Sphere1<C,D> &r, D error)
{
return contains_sphere(l, r, error);
}
} // namespace
} // namespace
} // namespace

27
tjp/core/math/Box3.h Executable file
View File

@@ -0,0 +1,27 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#pragma once
#include "Real.h"
namespace tjp {
namespace core {
namespace math {
template<typename Real>
class Box3;
typedef Box3<float> Box3f;
typedef Box3<double> Box3d;
typedef Box3<Real> Box3r;
} // namespace
} // namespace
} // namespace

36
tjp/core/math/Box3.hpp Executable file
View File

@@ -0,0 +1,36 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#pragma once
#include "Box3.h"
#include <array>
namespace tjp {
namespace core {
namespace math {
template<typename Real>
class Box3
{
public:
typedef Real value_type;
typedef Vector3<Real> Center;
Center center;
using Axis = Vector3<Real>;
std::array<Axis, 3> axis;
std::array<Real, 3> extent;
};
} // namespace
} // namespace
} // namespace

140
tjp/core/math/Distance+BigInt.inl Executable file
View File

@@ -0,0 +1,140 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#pragma once
#include "Vector3.inl"
#include "Vector2.hpp"
#include "Vector4.hpp"
#include "Real.inl"
#include "BigInt.hpp"
#include "BigDecimal.hpp"
namespace tjp {
namespace core {
namespace math {
template<typename Real>
inline auto distance_squared(const Vector3<Real> &l, const Vector3<Real> &r)
{
Real
a = r[0] - l[0],
b = r[1] - l[1],
c = r[2] - l[2];
return (a*a) + (b*b) + (c*c);
}
template<typename Real>
inline auto distance_squared(const Vector4<Real> &l, const Vector4<Real> &r)
{
Real
a = r[0] - l[0],
b = r[1] - l[1],
c = r[2] - l[2],
d = r[3] - l[3];
return (a*a) + (b*b) + (c*c) + (d*d);
}
template<typename Real>
inline auto distance_squared(const Vector2<Real> &l, const Vector2<Real> &r)
{
Real
a = r[0] - l[0],
b = r[1] - l[1];
return (a*a) + (b*b);
}
template<typename Real>
inline auto distance_squared(const Vector3<Real> &r, Real x, Real y, Real z)
{
Real a = r[0] - x;
a *= a;
Real b = r[1] - y;
b *= b;
Real c = r[2] - z;
c *= c;
return a + b + c;
}
template<typename Real>
inline auto distance(const Vector3<Real> &r, Real x, Real y, Real z)
{
return std::sqrt(distance_squared(r, x, y, z));
}
inline auto distance(const Vector3<r32> &l, const Vector3<r32> &r) { return sqrt(distance_squared(l, r)); }
inline auto distance(const Vector3<r64> &l, const Vector3<r64> &r) { return sqrt(distance_squared(l, r)); }
inline auto distance(const Vector2<r32> &l, const Vector2<r32> &r) { return sqrt(distance_squared(l, r)); }
inline auto distance(const Vector2<r64> &l, const Vector2<r64> &r) { return sqrt(distance_squared(l, r)); }
inline auto distance(const Vector4<r32> &l, const Vector4<r32> &r) { return sqrt(distance_squared(l, r)); }
inline auto distance(const Vector4<r64> &l, const Vector4<r64> &r) { return sqrt(distance_squared(l, r)); }
//
template<typename V>
auto distance_vector_signed(const V &l, const V &r)
{
return (r-l).length();
}
template<typename V>
V distance_integral_unsigned(const V &l, const V &r)
{
if (r > l)
return r - l;
return l - r;
}
template<typename V>
V distance_integral_signed(const V &l, const V &r)
{
return distance_integral_unsigned(l, r);
}
// ---------------------
inline auto distance(const Vector3<s32> &l, const Vector3<s32> &r) { return distance_vector_signed(l, r); }
inline auto distance(const Vector3<s64> &l, const Vector3<s64> &r) { return distance_vector_signed(l, r); }
inline auto distance(const Vector3<s128> &l, const Vector3<s128> &r) { return distance_vector_signed(l, r); }
inline auto distance(const Vector3<BigInt> &l, const Vector3<BigInt> &r) { return distance_vector_signed(l, r); }
inline auto distance(const Vector3<BigDecimal> &l, const Vector3<BigDecimal> &r) { return distance_vector_signed(l, r); }
inline auto distance(const r32 &l, const r32 &r) { return distance_integral_signed(l, r); }
inline auto distance(const r64 &l, const r64 &r) { return distance_integral_signed(l, r); }
inline auto distance(const s32 &l, const s32 &r) { return distance_integral_signed(l, r); }
inline auto distance(const s64 &l, const s64 &r) { return distance_integral_signed(l, r); }
inline auto distance(const s128 &l, const s128 &r) { return distance_integral_signed(l, r); }
inline auto distance(const u32 &l, const u32 &r) { return distance_integral_unsigned(l, r); }
inline auto distance(const u64 &l, const u64 &r) { return distance_integral_unsigned(l, r); }
inline auto distance(const u128 &l, const u128 &r) { return distance_integral_unsigned(l, r); }
inline auto distance(const BigDecimal &l, const BigDecimal &r) { return distance_integral_signed(l, r); }
template<typename Real>
auto distance_relative(const Real &l, const Real &r)
{
return distance(l, r);
}
} // namespace
} // namespace
} // namespace

135
tjp/core/math/Distance.inl Executable file
View File

@@ -0,0 +1,135 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#pragma once
#include "Vector3.inl"
#include "Vector2.hpp"
#include "Vector4.hpp"
#include "Real.inl"
namespace tjp {
namespace core {
namespace math {
template<typename Real>
inline auto distance_squared(const Vector3<Real> &l, const Vector3<Real> &r)
{
Real
a = r[0] - l[0],
b = r[1] - l[1],
c = r[2] - l[2];
return (a*a) + (b*b) + (c*c);
}
template<typename Real>
inline auto distance_squared(const Vector4<Real> &l, const Vector4<Real> &r)
{
Real
a = r[0] - l[0],
b = r[1] - l[1],
c = r[2] - l[2],
d = r[3] - l[3];
return (a*a) + (b*b) + (c*c) + (d*d);
}
template<typename Real>
inline auto distance_squared(const Vector2<Real> &l, const Vector2<Real> &r)
{
Real
a = r[0] - l[0],
b = r[1] - l[1];
return (a*a) + (b*b);
}
template<typename Real>
inline auto distance_squared(const Vector3<Real> &r, Real x, Real y, Real z)
{
Real a = r[0] - x;
a *= a;
Real b = r[1] - y;
b *= b;
Real c = r[2] - z;
c *= c;
return a + b + c;
}
template<typename Real>
inline auto distance(const Vector3<Real> &r, Real x, Real y, Real z)
{
return std::sqrt(distance_squared(r, x, y, z));
}
inline auto distance(const Vector3<r32> &l, const Vector3<r32> &r) { return sqrt(distance_squared(l, r)); }
inline auto distance(const Vector3<r64> &l, const Vector3<r64> &r) { return sqrt(distance_squared(l, r)); }
inline auto distance(const Vector2<r32> &l, const Vector2<r32> &r) { return sqrt(distance_squared(l, r)); }
inline auto distance(const Vector2<r64> &l, const Vector2<r64> &r) { return sqrt(distance_squared(l, r)); }
inline auto distance(const Vector4<r32> &l, const Vector4<r32> &r) { return sqrt(distance_squared(l, r)); }
inline auto distance(const Vector4<r64> &l, const Vector4<r64> &r) { return sqrt(distance_squared(l, r)); }
//
template<typename V>
auto distance_vector_signed(const V &l, const V &r)
{
return (r-l).length();
}
template<typename V>
V distance_integral_unsigned(const V &l, const V &r)
{
if (r > l)
return r - l;
return l - r;
}
template<typename V>
V distance_integral_signed(const V &l, const V &r)
{
return distance_integral_unsigned(l, r);
}
// ---------------------
inline auto distance(const Vector3<s32> &l, const Vector3<s32> &r) { return distance_vector_signed(l, r); }
inline auto distance(const Vector3<s64> &l, const Vector3<s64> &r) { return distance_vector_signed(l, r); }
inline auto distance(const Vector3<s128> &l, const Vector3<s128> &r) { return distance_vector_signed(l, r); }
inline auto distance(const r32 &l, const r32 &r) { return distance_integral_signed(l, r); }
inline auto distance(const r64 &l, const r64 &r) { return distance_integral_signed(l, r); }
inline auto distance(const s32 &l, const s32 &r) { return distance_integral_signed(l, r); }
inline auto distance(const s64 &l, const s64 &r) { return distance_integral_signed(l, r); }
inline auto distance(const s128 &l, const s128 &r) { return distance_integral_signed(l, r); }
inline auto distance(const u32 &l, const u32 &r) { return distance_integral_unsigned(l, r); }
inline auto distance(const u64 &l, const u64 &r) { return distance_integral_unsigned(l, r); }
inline auto distance(const u128 &l, const u128 &r) { return distance_integral_unsigned(l, r); }
template<typename Real>
auto distance_relative(const Real &l, const Real &r)
{
return distance(l, r);
}
} // namespace
} // namespace
} // namespace

69
tjp/core/math/Epsilon.h Executable file
View File

@@ -0,0 +1,69 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#pragma once
#include <tjp/core/types/Types.h>
namespace tjp {
namespace core {
namespace math {
template<typename T>
T epsilon()
{
return T(0.00001);
}
template<>
inline
s128 epsilon()
{
return 1;
}
template<>
inline
s64 epsilon()
{
return 1;
}
template<>
inline
s32 epsilon()
{
return 1;
}
template<>
inline
u128 epsilon()
{
return 1;
}
template<>
inline
u64 epsilon()
{
return 1;
}
template<>
inline
u32 epsilon()
{
return 1;
}
} // namespace
} // namespace
} // namespace

25
tjp/core/math/Eulers.h Executable file
View File

@@ -0,0 +1,25 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#pragma once
namespace tjp {
namespace core {
namespace math {
template<typename Real>
struct Eulers;
typedef Eulers<double> Eulersd;
typedef Eulers<float> Eulersf;
typedef Eulers<Real> Eulersr;
} // namespace
} // namespace
} // namespace

40
tjp/core/math/Eulers.hpp Executable file
View File

@@ -0,0 +1,40 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#pragma once
#include "Eulers.h"
#include "Zero.h"
#include <tjp/core/types/Types.h>
#include <tjp/core/containers/Pack.h>
#include <tjp/core/assert/debug_assert.h>
#include <initializer_list>
namespace tjp {
namespace core {
namespace math {
template<typename Real>
struct Eulers {
Real pitch, yaw, roll;
} ;
template<typename Real>
bool operator ==(const Eulers<Real> &lhs, const Eulers<Real> &rhs)
{
return
lhs.pitch == rhs.pitch &&
lhs.yaw == rhs.yaw &&
lhs.roll == rhs.roll;
}
} // namespace
} // namespace
} // namespace

20
tjp/core/math/FastFourier.h Executable file
View File

@@ -0,0 +1,20 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#pragma once
namespace tjp {
namespace core {
namespace math {
// https://rosettacode.org/wiki/Fast_Fourier_transform
} // namespace
} // namespace
} // namespace

135
tjp/core/math/FloatPack.inl Executable file
View File

@@ -0,0 +1,135 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#pragma once
#include "Vector2.inl"
#include "Vector3.inl"
#include "Vector4.inl"
namespace tjp {
namespace core {
namespace math {
constexpr int float_2_bits = 12;
constexpr int float_3_bits = 8;
constexpr int float_4_bits = 6;
const float float_2_max = 1 << float_2_bits;
const Vector2f float_2_decoder = { 1, (1<<float_2_bits) };
const Vector2f float_2_encoder = 1/float_2_decoder;
Vector2f unpack2u(r32 v)
{
auto a = float_2_decoder * v;
auto b = fract(a);
auto c = trunc(b * float_2_max) / float_2_max;
return c;
}
r32 pack2u (Vector2f v)
{
auto a = trunc(v * float_2_max);
auto b = a / float_2_max;
auto c = dot(b, float_2_encoder);
return c;
}
Vector2f unpack2s(r32 v)
{
return 2.0f * unpack2u(v) - Vector2f { 1, 1 };
}
r32 pack2s (Vector2f v)
{
return pack2u(0.5f * (v + Vector2f { 1, 1 }));
}
const float float_4_max = 1 << float_4_bits;
const Vector4f float_4_decoder = {
1,
(1<<float_4_bits),
(1<<(2*float_4_bits)),
(1<<(3*float_4_bits))
};
const Vector4f float_4_encoder = 1/float_4_decoder;
Vector4f unpack4u(r32 v)
{
auto a = float_4_decoder * v;
auto b = fract(a);
auto c = trunc(b * float_4_max);
auto d = c / float_4_max;
return d;
}
r32 pack4u (Vector4f v)
{
auto a = trunc(v * float_4_max);
auto b = a / float_4_max;
auto c = dot(b, float_4_encoder);
return c;
}
Vector4f unpack4s(r32 v)
{
return 2.0f * unpack4u(v) - Vector4f { 1, 1, 1, 1 };
}
r32 pack4s (Vector4f v)
{
return pack4u(0.5f * (v + Vector4f { 1, 1, 1, 1 }));
}
const float float_3_max = 1 << float_3_bits;
const Vector3f float_3_decoder = {
1,
(1<<float_3_bits),
(1<<(2*float_3_bits))
} ;
const Vector3f float_3_encoder = 1/float_3_decoder;
Vector3f unpack3u(r32 v)
{
auto a = float_3_decoder * v;
auto b = fract(a);
auto c = trunc(b * float_3_max);
auto d = c / float_3_max;
return d;
}
r32 pack3u (Vector3f v)
{
auto a = trunc(v * float_3_max);
auto b = a / float_3_max;
auto c = dot(b, float_3_encoder);
return c;
}
Vector3f unpack3s(r32 v)
{
return 2.0f * unpack3u(v) - Vector3f { 1, 1, 1 };
}
r32 pack3s (Vector3f v)
{
return pack3u(0.5f * (v + Vector3f { 1, 1, 1 }));
}
} // namespace
} // namespace
} // namespace

188
tjp/core/math/GTE_convert.hpp Executable file
View File

@@ -0,0 +1,188 @@
//
// Math.cpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#include "Algorithm.h"
#include "Math.hpp"
#include "Box3.hpp"
#include <Mathematics/Vector3.h>
#include <Mathematics/Circle3.h>
#include <Mathematics/Frustum3.h>
#include <Mathematics/Segment.h>
#include <Mathematics/Ray.h>
#include <Mathematics/Triangle.h>
#include <Mathematics/Hypersphere.h>
#include <Mathematics/Hyperplane.h>
#include <Mathematics/Cone.h>
#include <Mathematics/Line.h>
#include <Mathematics/OrientedBox.h>
namespace tjp {
namespace core {
namespace math {
template<typename Real>
Vector3<Real> gte_c (const gte::Vector3<Real> &v)
{
return { v[0], v[1], v[2] };
}
template<typename Real>
gte::Vector3<Real> gte_c (const Vector3<Real> &v)
{
return { v[0], v[1], v[2] };
}
template<typename Real>
Circle2<Real> gte_c (const gte::Circle2<Real> &v)
{
return { gte_c(v.center), v.radius };
}
template<typename Real>
gte::Circle2<Real> gte_c (const Circle2<Real> &v)
{
return { gte_c(v.center), v.radius };
}
template<typename Real>
Circle3<Real> gte_c (const gte::Circle3<Real> &v)
{
return { gte_c(v.center), gte_c(v.normal), v.radius };
}
template<typename Real>
gte::Circle3<Real> gte_c (const Circle3<Real> &v)
{
return { gte_c(v.center), gte_c(v.normal), v.radius };
}
template<typename Real>
Sphere3<Real> gte_c (const gte::Sphere3<Real> &v)
{
return { gte_c(v.center), v.radius };
}
template<typename Real>
gte::Sphere3<Real> gte_c (const Sphere3<Real> &v)
{
return { gte_c(v.center), v.radius };
}
template<typename Real>
gte::OrientedBox<3, Real> gte_c (const Box3<Real> &v)
{
return {
gte_c(v.center),
{
gte_c(v.axis[0]),
gte_c(v.axis[1]),
gte_c(v.axis[2])
},
v.extent
};
}
template<typename Real>
Box3<Real> gte_c (const gte::OrientedBox<3, Real> &v)
{
return {
gte_c(v.center),
{
gte_c(v.axis[0]),
gte_c(v.axis[1]),
gte_c(v.axis[2])
},
v.extent
};
}
template<typename Real>
gte::Plane3<Real> gte_c (const Plane3<Real> &v)
{
return { gte_c(v.normal), v.constant };
}
template<typename Real>
gte::Frustum3<Real> gte_c (const Frustum3<Real> &v)
{
return {
gte_c(v.origin),
gte_c(v.dVector),
gte_c(v.uVector),
gte_c(v.rVector),
v.dMin, v.dMax, v.uBound, v.rBound
};
}
template<typename Real>
gte::Cone3<Real> gte_c (const Cone3<Real> &v)
{
return {
gte_c(v.ray),
v.angle
};
}
template<typename Real>
gte::Triangle3<Real> gte_c (const Triangle3<Real> &v)
{
return {
gte_c(v.v[0]),
gte_c(v.v[1]),
gte_c(v.v[2])
};
}
template<typename Real>
Triangle3<Real> gte_c (const gte::Triangle3<Real> &v)
{
return {
gte_c(v.v[0]),
gte_c(v.v[1]),
gte_c(v.v[2])
};
}
template<typename Real>
gte::Line3<Real> gte_c (const Line3<Real> &v)
{
return {
gte_c(v.origin),
gte_c(v.direction)
};
}
template<typename Real>
Line3<Real> gte_c (const gte::Line3<Real> &v)
{
return {
gte_c(v.origin),
gte_c(v.direction)
};
}
template<typename Real>
gte::Ray3<Real> gte_c (const Ray3<Real> &v)
{
return { gte_c(v.origin), gte_c(v.direction) };
}
template<typename Real>
gte::Segment3<Real> gte_c (const Segment3<Real> &v)
{
return { gte_c(v.begin), gte_c(v.end) };
}
} // namespace
} // namespace
} // namespace

56
tjp/core/math/HMatrix.cpp Executable file
View File

@@ -0,0 +1,56 @@
//
// Math.cpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#include "HMatrix.hpp"
#include "HMatrix.inl"
namespace tjp {
namespace core {
namespace math {
// inline
template<>
HMatrix<double> operator *(const HMatrix<double> &lhs, const HMatrix<double> &rhs)
{
HMatrix<Real> result;
for (int r = 0; r < 4; ++r)
{
for (int c = 0; c < 4; ++c)
{
result[r][c] = 0;
for (int i = 0; i < 4; ++i)
{
result[r][c] += lhs[i][c] * rhs[r][i];
}
}
}
return result;
}
template<>
const HMatrix<double> HMatrix<double>::Zero {
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0
};
template<>
const HMatrix<double> HMatrix<double>::Identity {
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
};
} // namespace
} // namespace
} // namespace

27
tjp/core/math/HMatrix.h Executable file
View File

@@ -0,0 +1,27 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#pragma once
#include "Real.h"
namespace tjp {
namespace core {
namespace math {
template<typename Real>
class HMatrix;
typedef HMatrix<Real> HMatrixr;
typedef HMatrix<float> HMatrixf;
typedef HMatrix<double> HMatrixd;
} // namespace
} // namespace
} // namespace

78
tjp/core/math/HMatrix.hpp Executable file
View File

@@ -0,0 +1,78 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#pragma once
#include "HMatrix.h"
#include "Matrix3.h"
#include "Vector3.h"
#include <initializer_list>
#include <tjp/core/types/Types.h>
namespace tjp {
namespace core {
namespace math {
template<typename Real>
class HMatrix
{
public:
typedef Real value_type;
Real v[16];
public:
HMatrix<Real>(std::initializer_list<Real> l);
HMatrix<Real>(const Matrix3<Real> &m, const Vector3<Real> &t, const Vector3<Real> &s);
HMatrix<Real>() {}
const Real* operator[] (size_t row) const;
Real* operator[] (size_t row);
static const HMatrix<Real> Zero;
static const HMatrix<Real> Identity;
template<typename U>
HMatrix<U> asType() const
{
return HMatrix<U> {
(U)v[0], (U)v[1], (U)v[2], (U)v[3],
(U)v[4], (U)v[5], (U)v[6], (U)v[7],
(U)v[8], (U)v[9], (U)v[10], (U)v[11],
(U)v[12], (U)v[13], (U)v[14], (U)v[15],
};
}
} ;
template<typename Real>
const HMatrix<Real> HMatrix<Real>::Zero = {
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0
};
template<typename Real>
const HMatrix<Real> HMatrix<Real>::Identity = {
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
};
typedef HMatrix<Real> HMatrixr;
typedef HMatrix<float> HMatrixf;
typedef HMatrix<double> HMatrixd;
} // namespace
} // namespace
} // namespace

128
tjp/core/math/HMatrix.inl Executable file
View File

@@ -0,0 +1,128 @@
//
// Math.inl
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#pragma once
#include "HMatrix.hpp"
#include "HPoint.hpp"
#include "Zero.h"
namespace tjp {
namespace core {
namespace math {
// inline
template<typename Real>
HMatrix<Real>::HMatrix(std::initializer_list<Real> l)
{
int i=0;
for (auto &r : l)
v[i++] = r;
}
// inline
template<typename Real>
HMatrix<Real>::HMatrix (const Matrix3<Real> &m, const Vector3<Real> &t, const Vector3<Real> &s)
{
Real vn[] {
m.v[0] * s[0], m.v[1] * s[1], m.v[2] * s[2], t[0],
m.v[3] * s[0], m.v[4] * s[1], m.v[5] * s[2], t[1],
m.v[6] * s[0], m.v[7] * s[1], m.v[8] * s[2], t[2],
0, 0, 0, 1
};
for (int i=0; i<16; ++i)
v[i] = vn[i];
}
// inline
template<typename Real>
HMatrix<Real> operator *(const HMatrix<Real> &lhs, const HMatrix<Real> &rhs);
template<>
HMatrix<double> operator *(const HMatrix<double> &lhs, const HMatrix<double> &rhs);
template<typename Real>
Vector3<Real> operator *(const HMatrix<Real> &hm, const Vector3<Real> &p)
{
HPoint<Real> hp(p);
auto v = hm * hp;
return { v.v[0], v.v[1], v.v[2] };
}
// inline
template<typename Real>
HPoint<Real> operator *(const HMatrix<Real> &m, const HPoint<Real> &p)
{
return HPoint<Real>(
m.v[ 0]*p[0] +
m.v[ 1]*p[1] +
m.v[ 2]*p[2] +
m.v[ 3]*p[3],
m.v[ 4]*p[0] +
m.v[ 5]*p[1] +
m.v[ 6]*p[2] +
m.v[ 7]*p[3],
m.v[ 8]*p[0] +
m.v[ 9]*p[1] +
m.v[10]*p[2] +
m.v[11]*p[3],
m.v[12]*p[0] +
m.v[13]*p[1] +
m.v[14]*p[2] +
m.v[15]*p[3]);
}
// inline
template<typename Real>
HPoint<Real> operator* (const HPoint<Real>& p, const HMatrix<Real>& mat)
{
return HPoint<Real>(
p[0]*mat[0][0] + p[1]*mat[1][0] + p[2]*mat[2][0] + p[3]*mat[3][0],
p[0]*mat[0][1] + p[1]*mat[1][1] + p[2]*mat[2][1] + p[3]*mat[3][1],
p[0]*mat[0][2] + p[1]*mat[1][2] + p[2]*mat[2][2] + p[3]*mat[3][2],
p[0]*mat[0][3] + p[1]*mat[1][3] + p[2]*mat[2][3] + p[3]*mat[3][3]);
}
// inline
template<typename Real>
const Real* HMatrix<Real>::operator[] (size_t row) const
{
return &v[4*row];
}
// inline
template<typename Real>
Real* HMatrix<Real>::operator[] (size_t row)
{
return &v[4*row];
}
template<typename Real>
bool operator ==(const HMatrix<Real> &lhs, const HMatrix<Real> &rhs)
{
for (auto i=0; i<16; ++i)
if (lhs.v[i] != rhs.v[i])
return false;
return true;
}
template<typename Real>
bool operator !=(const HMatrix<Real> &lhs, const HMatrix<Real> &rhs)
{
return !(lhs == rhs);
}
} // namespace
} // namespace
} // namespace

27
tjp/core/math/HPoint.h Executable file
View File

@@ -0,0 +1,27 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#pragma once
#include "Real.h"
namespace tjp {
namespace core {
namespace math {
template<typename Real>
struct HPoint;
typedef HPoint<Real> HPointr;
typedef HPoint<float> HPointf;
typedef HPoint<double> HPointd;
} // namespace
} // namespace
} // namespace

44
tjp/core/math/HPoint.hpp Executable file
View File

@@ -0,0 +1,44 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#pragma once
#include "HPoint.h"
#include "Vector3.h"
namespace tjp {
namespace core {
namespace math {
template<typename Real>
struct HPoint
{
typedef Real value_type;
Real v[4];
HPoint();
HPoint(const Vector3<Real> &r);
HPoint(Real v0, Real v1, Real v2, Real v3);
Real &operator[](size_t size);
Real const &operator[](size_t size) const;
operator Vector3<Real>&();
operator const Vector3<Real>&() const;
};
typedef HPoint<Real> HPointr;
typedef HPoint<float> HPointf;
typedef HPoint<double> HPointd;
} // namespace
} // namespace
} // namespace

74
tjp/core/math/HPoint.inl Executable file
View File

@@ -0,0 +1,74 @@
//
// Math.inl
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#pragma once
#include "HPoint.hpp"
#include "Zero.h"
#include "Vector3.hpp"
namespace tjp {
namespace core {
namespace math {
template<typename Real>
HPoint<Real>::HPoint ()
{
}
template<typename Real>
HPoint<Real>::HPoint(Real v0, Real v1, Real v2, Real v3)
{
v[0] = v0;
v[1] = v1;
v[2] = v2;
v[3] = v3;
}
// inline
template<typename Real>
HPoint<Real>::HPoint(const Vector3<Real> &r)
{
v[0] = r.v[0];
v[1] = r.v[1];
v[2] = r.v[2];
v[3] = 1;
}
// inline
template<typename Real>
HPoint<Real>::operator Vector3<Real>&()
{
return *(Vector3<Real> *)this;
}
template<typename Real>
HPoint<Real>::operator const Vector3<Real>&() const
{
return *(const Vector3<Real> *)this;
}
// inline
template<typename Real>
Real &HPoint<Real>::operator[](size_t size)
{
return v[size];
}
// inline
template<typename Real>
Real const &HPoint<Real>::operator[](size_t size) const
{
return v[size];
}
} // namespace
} // namespace
} // namespace

259
tjp/core/math/Math+IO.h Normal file
View File

@@ -0,0 +1,259 @@
//
// MathIO.h
// common
//
// Created by Timothy Prepscius on 8/4/18.
// Copyright © 2018 Timothy Prepscius. All rights reserved.
//
#pragma once
#include "Math.h"
#include <tjp/core/io/bin/IO.h>
#include <iostream>
#include "Matrix3.hpp"
#include "HMatrix.hpp"
#include "HPoint.hpp"
#include "Vector3.hpp"
#include "Sphere3.hpp"
#include "Sphere1.hpp"
#include "Segment1.hpp"
#include "Vector4.hpp"
namespace tjp {
namespace core {
namespace math {
template<typename T>
std::ostream &operator <<(std::ostream &o, const HMatrix<T> &v)
{
for (auto i=0; i<4; ++i)
{
o << "[";
o << v[i][0];
for (auto j=1; j<4; ++j)
{
o << ",";
o << v[i][j];
}
o << "]";
}
return o;
}
template<typename T>
std::ostream &operator <<(std::ostream &o, const Vector3<T> &v)
{
o << v[0];
for (auto j=1; j<3; ++j)
{
o << ",";
o << v[j];
}
return o;
}
template<typename T>
std::ostream &operator <<(std::ostream &o, const Vector4<T> &v)
{
o << v[0];
for (auto j=1; j<4; ++j)
{
o << ",";
o << v[j];
}
return o;
}
template<typename T>
std::ostream &operator <<(std::ostream &o, const HPoint<T> &v)
{
o << "(";
o << v[0];
for (auto j=1; j<4; ++j)
{
o << ",";
o << v[j];
}
o << ")";
return o;
}
template<typename T>
std::ostream &operator <<(std::ostream &o, const Vector2<T> &v)
{
o << v[0];
for (auto j=1; j<2; ++j)
{
o << ",";
o << v[j];
}
return o;
}
template<typename T>
std::ostream &operator <<(std::ostream &o, const Matrix3<T> &v)
{
for (auto i=0; i<3; ++i)
{
o << "[";
o << v[i][0];
for (auto j=1; j<3; ++j)
{
o << ",";
o << v[i][j];
}
o << "]";
}
return o;
}
template<typename T>
std::ostream &operator <<(std::ostream &o, const Sphere3<T> &v)
{
o << "{" << v.center << ":" << v.radius << "}";
return o;
}
template<typename C, typename D>
std::ostream &operator <<(std::ostream &o, const Sphere1<C, D> &v)
{
o << "{" << v.center << ":" << v.radius << "}";
return o;
}
template<typename T>
std::ostream &operator <<(std::ostream &o, const Segment1<T> &v)
{
o << "{" << v.begin << "," << v.end << "}";
return o;
}
// ----------------------------------------------------
template<typename IO, typename R>
void io_(IO &io, math::Vector2<R> &m)
{
io.array(m.v[0], m.v[1]);
}
template<typename IO, typename R>
void io_(IO &io, math::Vector3<R> &m)
{
io.array(m.v[0], m.v[1], m.v[2]);
}
template<typename IO, typename R>
void io_(IO &io, math::Vector4<R> &m)
{
io.array(m.v[0], m.v[1], m.v[2], m.v[3]);
}
template<typename IO, typename R>
void io_(IO &io, math::Plane3<R> &m)
{
io.object("normal", m.normal, "constant", m.constant);
}
template<typename IO, typename R>
void io_(IO &io, math::Sphere3<R> &m)
{
io.object("center", m.center, "radius", m.radius);
}
template<typename IO, typename C, typename D>
void io_(IO &io, math::Sphere1<C, D> &m)
{
io.object("center", m.center, "radius", m.radius);
}
template<typename IO, typename R>
void io_(IO &io, math::Segment1<R> &m)
{
io.object("begin", m.begin, "end", m.end);
}
template<typename IO, typename R>
void io_(IO &io, math::HMatrix<R> &m)
{
io.array(
m.v[0], m.v[1], m.v[2], m.v[3],
m.v[4], m.v[5], m.v[6], m.v[7],
m.v[8], m.v[9], m.v[10], m.v[11],
m.v[12], m.v[13], m.v[14], m.v[15]
);
}
// ----------------------------------------------------
template<typename IO, typename R>
void io_bin(IO &io, math::Vector2<R> &m) { return io_(io, m); }
template<typename IO, typename R>
void io_json(IO &io, math::Vector2<R> &m) { return io_(io, m); }
template<typename IO, typename R>
void io_bin(IO &io, math::Vector3<R> &m) { return io_(io, m); }
template<typename IO, typename R>
void io_json(IO &io, math::Vector3<R> &m) { return io_(io, m); }
template<typename IO, typename R>
void io_bin(IO &io, math::Vector4<R> &m) { return io_(io, m); }
template<typename IO, typename R>
void io_json(IO &io, math::Vector4<R> &m) { return io_(io, m); }
template<typename IO, typename R>
void io_bin(IO &io, math::Plane3<R> &m) { return io_(io, m); }
template<typename IO, typename R>
void io_json(IO &io, math::Plane3<R> &m) { return io_(io, m); }
template<typename IO, typename C, typename D>
void io_bin(IO &io, math::Sphere1<C, D> &m) { return io_(io, m); }
template<typename IO, typename C, typename D>
void io_json(IO &io, math::Sphere1<C, D> &m) { return io_(io, m); }
template<typename IO, typename R>
void io_bin(IO &io, math::Segment1<R> &m) { return io_(io, m); }
template<typename IO, typename R>
void io_json(IO &io, math::Segment1<R> &m) { return io_(io, m); }
template<typename IO, typename R>
void io_bin(IO &io, math::Sphere3<R> &m) { return io_(io, m); }
template<typename IO, typename R>
void io_json(IO &io, math::Sphere3<R> &m) { return io_(io, m); }
template<typename IO, typename R>
void io_bin(IO &io, math::HMatrix<R> &m) { return io_(io, m); }
template<typename IO, typename R>
void io_json(IO &io, math::HMatrix<R> &m) { return io_(io, m); }
// ----------------------------------------------------
} // namespace
} // namespace
} // namespace

28
tjp/core/math/Math+V.h Normal file
View File

@@ -0,0 +1,28 @@
//
// MathIO.h
// common
//
// Created by Timothy Prepscius on 8/4/18.
// Copyright © 2018 Timothy Prepscius. All rights reserved.
//
#pragma once
#include "Math.h"
#include <tjp/core/variant/VType.h>
#include "Vector3.h"
#include "Vector2.h"
#include "Sphere3.h"
namespace tjp {
namespace core {
namespace math {
extern const VType Vector3r_vtype;
extern const VType Sphere3s16_vtype;
} // namespace
} // namespace
} // namespace

89
tjp/core/math/Math.h Executable file
View File

@@ -0,0 +1,89 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#pragma once
#include "Real.h"
#
namespace tjp {
namespace core {
namespace math {
template<typename Real>
struct constants;
template<typename Real>
struct Ray3;
template<typename Real>
struct Segment3;
template<typename Real>
struct Line3;
template<typename Real>
class Plane3;
template<typename Real>
class Cone3;
template<typename Real>
class Frustum3;
template<typename Real>
struct Box3;
template<typename Real>
struct Segment2;
template<typename Real>
class Circle2;
template<typename Real>
class Circle3;
template<typename Real>
class Triangle3;
typedef Ray3<double> Ray3d;
typedef Ray3<float> Ray3f;
typedef Ray3<Real> Ray3r;
typedef Segment2<double> Segment2d;
typedef Segment2<float> Segment2f;
typedef Segment2<Real> Segment2r;
typedef Circle2<double> Circle2d;
typedef Circle2<float> Circle2f;
typedef Circle2<Real> Circle2r;
typedef Line3<double> Line3d;
typedef Line3<float> Line3f;
typedef Line3<Real> Line3r;
typedef Plane3<float> Plane3f;
typedef Plane3<double> Plane3d;
typedef Plane3<Real> Plane3r;
typedef Triangle3<float> Triangle3f;
typedef Triangle3<double> Triangle3d;
typedef Triangle3<Real> Triangle3r;
typedef Cone3<float> Cone3f;
typedef Cone3<double> Cone3d;
typedef Cone3<Real> Cone3r;
typedef Frustum3<double> Frustum3d;
typedef Frustum3<float> Frustum3f;
typedef Frustum3<Real> Frustum3r;
} // namespace
} // namespace
} // namespace

228
tjp/core/math/Math.hpp Executable file
View File

@@ -0,0 +1,228 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#pragma once
#include "Vector3.hpp"
#include "Vector2.hpp"
#include <cstddef>
#include <array>
namespace tjp {
namespace core {
namespace math {
template<typename Real>
struct Ray3
{
Vector3<Real> origin, direction;
} ;
template<typename Real>
struct Line3
{
Vector3<Real> origin, direction;
} ;
template<typename Real>
class Plane3
{
public:
typedef Real value_type;
Vector3<Real> normal;
Real constant;
Plane3 () {}
Plane3 (const Vector3<Real> &normal_, Real constant_) :
normal(normal_),
constant(constant_)
{
}
Plane3 (const Vector3<Real> &o, const Vector3<Real> &d)
{
normal = d;
constant = d * o;
}
Plane3 (const Vector3<Real> &p0, const Vector3<Real> &p1, const Vector3<Real> &p2)
{
auto v1 = p2 - p0;
auto v2 = p1 - p0;
normal = (v1 ^ v2).normalize();
constant = normal * p0;
}
int whichSide(const Vector3<Real> &p) const;
Real distanceTo (const Vector3<Real> &p) const;
Vector3<Real> closestPoint(const Vector3<Real> &v) const;
};
template<typename Real>
class Frustum3
{
public:
typedef Real value_type;
Vector3<Real> origin, dVector, uVector, rVector;
Real dMin, dMax, uBound, rBound;
template<typename U>
Frustum3<U> asType() const
{
return Frustum3<U> {
origin.template asType<U>(),
dVector.template asType<U>(),
uVector.template asType<U>(),
rVector.template asType<U>(),
(U)dMin, (U)dMax, (U)uBound, (U)rBound
};
}
} ;
//template<typename Real>
//struct Box3
//{
// typedef Real value_type;
//
// Vector3<Real> center;
// std::array<Vector3<Real>, 3> axis;
// Vector3<Real> extent;
//} ;
template<typename Real>
struct Cone3
{
typedef Real value_type;
Ray3<Real> ray;
Real angle;
} ;
template<typename Real>
struct Segment2
{
typedef Real value_type;
Vector2<Real> begin, end;
} ;
template<typename Real>
struct Segment3
{
typedef Real value_type;
Vector3<Real> begin, end;
} ;
template<typename Real>
class Circle2
{
public:
typedef Real value_type;
Vector2<Real> center;
Real radius;
Circle2 () {}
Circle2 (const Vector2<Real> &center_, Real radius_) :
center(center_),
radius(radius_)
{
}
const static Circle2 Zero;
};
template<typename Real>
class Circle3
{
public:
typedef Real value_type;
Vector3<Real> center;
Vector3<Real> normal;
Real radius;
Circle3 () {}
Circle3 (const Vector3<Real> &center_, const Vector3<Real> &normal_, Real radius_) :
center(center_),
normal(normal_),
radius(radius_)
{
}
const static Circle3 Zero;
};
template<typename Real>
const Circle3<Real> Circle3<Real>::Zero = {
Vector3<Real>::Zero, Vector3<Real>::Zero, 0
};
template<typename Real>
class Triangle3
{
public:
Vector3<Real> v[3];
Vector3<Real> normal() const
{
auto s0 = v[0] - v[1];
auto s1 = v[0] - v[2];
return cross(s0, s1);
}
} ;
typedef double Real;
const Real Meter = 1.0;
const Real Centimeter = 0.01;
const Real Millimeter = 0.001;
typedef Ray3<double> Ray3d;
typedef Ray3<float> Ray3f;
typedef Ray3<Real> Ray3r;
typedef Segment2<double> Segment2d;
typedef Segment2<float> Segment2f;
typedef Segment2<Real> Segment2r;
typedef Circle2<double> Circle2d;
typedef Circle2<float> Circle2f;
typedef Circle2<Real> Circle2r;
typedef Line3<double> Line3d;
typedef Line3<float> Line3f;
typedef Line3<Real> Line3r;
typedef Plane3<float> Plane3f;
typedef Plane3<double> Plane3d;
typedef Plane3<Real> Plane3r;
typedef Cone3<float> Cone3f;
typedef Cone3<double> Cone3d;
typedef Cone3<Real> Cone3r;
typedef Frustum3<double> Frustum3d;
typedef Frustum3<float> Frustum3f;
typedef Frustum3<Real> Frustum3r;
} // namespace
} // namespace
} // namespace

100
tjp/core/math/Math.inl Executable file
View File

@@ -0,0 +1,100 @@
//
// Math.inl
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#pragma once
#include "Math.hpp"
#include "Zero.h"
namespace tjp {
namespace core {
namespace math {
// inline
template<typename Real>
Real Plane3<Real>::distanceTo (const Vector3<Real>& p) const
{
return (normal * p) - constant;
}
// inline
template<typename Real>
int Plane3<Real>::whichSide (const Vector3<Real> & p) const
{
Real distance = distanceTo(p);
if (distance < 0.0f)
{
return -1;
}
else if (distance > 0.0f)
{
return +1;
}
else
{
return 0;
}
}
// inline
template<typename Real>
Real angleBetween (const Vector3<Real> &l, const Vector3<Real> &r)
{
auto v1 = l.normalize();
auto v2 = r.normalize();
// | unit(V1) * unit(V2) | = cos A
double cosA = v1 * v2;
// if the shadow is completely in the same direction, then the
// difference in angle is zero
const double episolon = 0.00001;
const auto oneMepsilon = 1 - episolon;
const auto negOneMepsilon = -1 + episolon;
if (cosA >= oneMepsilon)
return 0;
// if the shadow is completely in the opposite direction, then the
// difference in angle is PI
if (cosA <= negOneMepsilon)
return constants<Real>::PI;
double Acos = acos(cosA);
return (Real) Acos;
}
// inline
template<typename Real>
Vector3<Real> axisBetween (const Vector3<Real> &l, const Vector3<Real> &r)
{
return (l ^ r).normalize();
}
// inline
template<typename Real>
Vector3<Real> Plane3<Real>::closestPoint (const Vector3<Real> &p) const
{
// http://stackoverflow.com/questions/9605556/how-to-project-a-3d-point-to-a-3d-plane
auto r = p - (normal * p + constant) * normal;
return r;
}
// --------
template<typename Real>
Real area(const math::Triangle3<Real> &t)
{
auto e0 = t.v[1] - t.v[0];
auto e1 = t.v[2] - t.v[0];
return length(cross(e0, e1)) / 2;
}
} // namespace
} // namespace
} // namespace

102
tjp/core/math/MathGlmC.h Executable file
View File

@@ -0,0 +1,102 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#pragma once
#include "HPoint.hpp"
#include "HMatrix.hpp"
#include "Vector3.hpp"
#include "Vector4.hpp"
#include <tjp/core/graphics/glm.h>
namespace tjp {
namespace core {
namespace math {
template<typename T>
glm::vec<3, T> glm_c(const math::Vector3<T> &v)
{
return { v[0], v[1], v[2] };
}
template<typename T>
math::Vector3<T> glm_c(const glm::vec<3, T> &v)
{
return { v[0], v[1], v[2] };
}
template<typename T>
glm::qua<T> glm_c(const math::Vector4<T> &v)
{
return { v[0], v[1], v[2], v[3] };
}
template<typename T>
math::Vector4<T> glm_c(const glm::qua<T> &v)
{
return { v[0], v[1], v[2], v[3] };
}
template<typename T>
glm::vec<4, T> glm_c(const math::HPoint<T> &v)
{
return { v[0], v[1], v[2], v[3] };
}
template<typename T>
math::HPoint<T> glm_c(const glm::vec<4, T> &v)
{
return { v[0], v[1], v[2], v[3] };
}
template<typename T>
glm::mat<3, 3, T> glm_c(const math::Matrix3<T> &m)
{
return {
m[0][0], m[0][1], m[0][2],
m[1][0], m[1][1], m[1][2],
m[2][0], m[2][1], m[2][2]
} ;
}
template<typename T>
math::Matrix3<T> glm_c(const glm::mat<3, 3, T> &m)
{
return {
m[0][0], m[0][1], m[0][2],
m[1][0], m[1][1], m[1][2],
m[2][0], m[2][1], m[2][2]
} ;
}
template<typename T>
glm::mat<4, 4, T> glm_c(const math::HMatrix<T> &m)
{
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]
} ;
}
template<typename T>
math::HMatrix<T> glm_c(const glm::mat<4, 4, T> &m)
{
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
} // namespace
} // namespace

32
tjp/core/math/Matrix3.cpp Executable file
View File

@@ -0,0 +1,32 @@
//
// Math.cpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#include "Matrix3.hpp"
namespace tjp {
namespace core {
namespace math {
template<>
const Matrix3<double> Matrix3<double>::Zero {
0, 0, 0,
0, 0, 0,
0, 0, 0
};
template<>
const Matrix3<double> Matrix3<double>::Identity {
1, 0, 0,
0, 1, 0,
0, 0, 1
};
} // namespace
} // namespace
} // namespace

25
tjp/core/math/Matrix3.h Executable file
View File

@@ -0,0 +1,25 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#pragma once
namespace tjp {
namespace core {
namespace math {
template<typename Real>
class Matrix3;
typedef Matrix3<Real> Matrix3r;
typedef Matrix3<float> Matrix3f;
typedef Matrix3<double> Matrix3d;
} // namespace
} // namespace
} // namespace

70
tjp/core/math/Matrix3.hpp Executable file
View File

@@ -0,0 +1,70 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#pragma once
#include "Vector3.hpp"
#include <initializer_list>
#include <array>
namespace tjp {
namespace core {
namespace math {
template<typename Real>
class Matrix3
{
public:
typedef Real value_type;
Real v[9];
public:
Matrix3<Real>(std::initializer_list<Real> l)
{
int i=0;
for (auto &r: l)
v[i++] = r;
}
Matrix3<Real> (const Vector3<Real> &a, const Vector3<Real> &b);
Matrix3<Real> (const Vector3<Real> &a, const Vector3<Real> &b, const Vector3<Real> &c);
Matrix3<Real> () {}
const Real* operator[] (size_t row) const;
Real* operator[] (size_t row);
Matrix3<Real> transpose() const;
Matrix3<Real> inverse(Real epsilon) const;
static const Matrix3<Real> Zero;
static const Matrix3<Real> Identity;
} ;
template<typename Real>
const Matrix3<Real> Matrix3<Real>::Zero = {
0, 0, 0,
0, 0, 0,
0, 0, 0
};
template<typename Real>
const Matrix3<Real> Matrix3<Real>::Identity = {
1, 0, 0,
0, 1, 0,
0, 0, 1
};
typedef Matrix3<Real> Matrix3r;
typedef Matrix3<float> Matrix3f;
typedef Matrix3<double> Matrix3d;
} // namespace
} // namespace
} // namespace

200
tjp/core/math/Matrix3.inl Executable file
View File

@@ -0,0 +1,200 @@
//
// Math.inl
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#pragma once
#include "Matrix3.hpp"
#include "HPoint.hpp"
#include "Zero.h"
#include <cmath>
#include "HMatrix.inl"
namespace tjp {
namespace core {
namespace math {
//// inline
//template<typename Real>
//Matrix3<Real>::Matrix3(std::initializer_list<Real> l)
//{
// int i=0;
// for (auto &r : l)
// v[i++] = r;
//}
/*
// inline
template<typename Real>
Matrix3<Real>::Matrix3<Real> (const Vector3<Real> &a, const Vector3<Real> &b)
{
// http://gamedev.stackexchange.com/questions/20097/how-to-calculate-a-3x3-rotation-matrix-from-2-direction-vectors
auto x = a.normalize();
auto y = b.normalize();
Matrix3<Real> &m = *this;
Vector3<Real> *mx = (Vector3<Real> *)m[0];
Vector3<Real> *my = (Vector3<Real> *)m[1];
Vector3<Real> *mz = (Vector3<Real> *)m[2];
*mx = x;
*mz = (x^y).normalize();
*my = (*mz ^ x).normalize();
}
*/
template<typename Real>
Matrix3<Real>::Matrix3 (const Vector3<Real> &a, const Vector3<Real> &b, const Vector3<Real> &c)
{
v[0] = a[0];
v[1] = a[1];
v[2] = a[2];
v[3] = b[0];
v[4] = b[1];
v[5] = b[2];
v[6] = c[0];
v[7] = c[1];
v[8] = c[2];
}
// inline
template<typename Real>
Matrix3<Real>::Matrix3 (const Vector3<Real> &a, const Vector3<Real> &b)
{
// http://math.stackexchange.com/questions/180418/calculate-rotation-matrix-to-align-vector-a-to-vector-b-in-3d
auto acb = a ^ b;
auto s = acb.length();
auto c = a * b;
Real vn[] {
c, -s, 0,
s, c, 0,
0, 0, 1
};
for (int i=0; i<9; ++i)
v[i] = vn[i];
}
template<typename Real>
Matrix3<Real> rotationMatrix(const Vector3<Real> &axis, const Real &angle)
{
Real cosTheta = std::cos(angle);
Real sinTheta = std::sin(angle);
Real oneMinusCosTheta = 1 - cosTheta;
Real x = axis[0];
Real y = axis[1];
Real z = axis[2];
Matrix3<Real> result;
result[0][0] = cosTheta + x * x * oneMinusCosTheta;
result[0][1] = x * y * oneMinusCosTheta - z * sinTheta;
result[0][2] = x * z * oneMinusCosTheta + y * sinTheta;
result[1][0] = y * x * oneMinusCosTheta + z * sinTheta;
result[1][1] = cosTheta + y * y * oneMinusCosTheta;
result[1][2] = y * z * oneMinusCosTheta - x * sinTheta;
result[2][0] = z * x * oneMinusCosTheta - y * sinTheta;
result[2][1] = z * y * oneMinusCosTheta + x * sinTheta;
result[2][2] = cosTheta + z * z * oneMinusCosTheta;
return result;
}
// inline
template<typename Real>
Matrix3<Real> Matrix3<Real>::transpose() const
{
return Matrix3<Real>({
v[0],
v[3],
v[6],
v[1],
v[4],
v[7],
v[2],
v[5],
v[8]
});
}
// inline
template<typename Real>
Matrix3<Real> Matrix3<Real>::inverse(const Real epsilon) const
{
// Invert a 3x3 using cofactors. This is faster than using a generic
// Gaussian elimination because of the loop overhead of such a method.
Matrix3 inverse;
// Compute the adjoint.
inverse.v[0] = v[4]*v[8] - v[5]*v[7];
inverse.v[1] = v[2]*v[7] - v[1]*v[8];
inverse.v[2] = v[1]*v[5] - v[2]*v[4];
inverse.v[3] = v[5]*v[6] - v[3]*v[8];
inverse.v[4] = v[0]*v[8] - v[2]*v[6];
inverse.v[5] = v[2]*v[3] - v[0]*v[5];
inverse.v[6] = v[3]*v[7] - v[4]*v[6];
inverse.v[7] = v[1]*v[6] - v[0]*v[7];
inverse.v[8] = v[0]*v[4] - v[1]*v[3];
Real det = v[0]*inverse.v[0] + v[1]*inverse.v[3] +
v[2]*inverse.v[6];
if (std::abs(det) > epsilon)
{
Real invDet = ((Real)1)/det;
inverse.v[0] *= invDet;
inverse.v[1] *= invDet;
inverse.v[2] *= invDet;
inverse.v[3] *= invDet;
inverse.v[4] *= invDet;
inverse.v[5] *= invDet;
inverse.v[6] *= invDet;
inverse.v[7] *= invDet;
inverse.v[8] *= invDet;
return inverse;
}
return Zero;
}
// inline
template<typename Real>
Vector3<Real> operator *(const Matrix3<Real> &m, const Vector3<Real> &p)
{
HMatrix<Real> hm(m, Vector3<Real>::Zero, { 1, 1, 1 });
HPoint<Real> hp(p);
auto v = hm * hp;
return { v.v[0], v.v[1], v.v[2] };
}
// inline
template<typename Real>
const Real* Matrix3<Real>::operator[] (size_t row) const
{
return &v[3*row];
}
// inline
template<typename Real>
Real* Matrix3<Real>::operator[] (size_t row)
{
return &v[3*row];
}
} // namespace
} // namespace
} // namespace

44
tjp/core/math/Precision.h Normal file
View File

@@ -0,0 +1,44 @@
//
// MathIO.h
// common
//
// Created by Timothy Prepscius on 8/4/18.
// Copyright © 2018 Timothy Prepscius. All rights reserved.
//
#pragma once
#include "Real.h"
#include "Accuracy+IO.h"
namespace tjp {
namespace core {
namespace math {
template<typename V, Real M>
struct Precision
{
V v;
operator V&()
{
return *this;
}
operator const V&() const
{
return *this;
}
} ;
template<typename IO, typename T, Real M>
void io_ (IO &io, Precision<T, M> &v)
{
io.any(with_accuracy(v, M));
}
} // namespace
} // namespace
} // namespace

86
tjp/core/math/Real.cpp Executable file
View File

@@ -0,0 +1,86 @@
//
// Math.cpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#include "Math.hpp"
#include "Real.hpp"
#include "Real.inl"
#include <cmath>
namespace tjp {
namespace core {
namespace math {
// http://www.codecodex.com/wiki/Calculate_an_integer_square_root
template<typename T>
T IntSqrt(T v)
{
T remainder = v;
if (remainder < 0) { return 0; }
T one = 1;
T place = one <<(sizeof(T)*8 -2);
while (place > remainder) { place /= 4; }
T root = 0;
while (place)
{
if (remainder >= root + place)
{
remainder -= root + place;
root += place*2;
}
root /= 2;
place /= 4;
}
return root;
}
// float
template<>
u128 sqrt(const u128 &v)
{
return IntSqrt<u128>(v);
}
template<>
s128 sqrt(const s128 &v)
{
return IntSqrt<s128>(v);
}
template<>
const double tjp::core::math::constants<double>::PI = atan<double>(1)*4.0;
template<>
const float tjp::core::math::constants<float>::PI = atan<float>(1)*4.0;
template<>
const double tjp::core::math::constants<double>::TWO_PI = atan<double>(1)*8.0;
template<>
const float tjp::core::math::constants<float>::TWO_PI = atan<float>(1)*8.0;
template<>
const float tjp::core::math::constants<float>::DEGREES_TO_RADIANS = 4.0 / 180.0 * atan<float>(1);
template<>
const float tjp::core::math::constants<float>::RADIANS_TO_DEGREES = 180.0 / 4.0 / atan<float>(1);
template<>
const double tjp::core::math::constants<double>::DEGREES_TO_RADIANS = 4.0 / 180.0 * atan<double>(1);
template<>
const double tjp::core::math::constants<double>::RADIANS_TO_DEGREES = 180.0 / 4.0 / atan<double>(1);
} // namespace
} // namespace
} // namespace

83
tjp/core/math/Real.h Executable file
View File

@@ -0,0 +1,83 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#pragma once
#include <tjp/core/types/Types.h>
#include <tjp/core/types/Types+IO.h>
namespace tjp {
namespace core {
namespace math {
typedef r64 Real;
template<typename Real>
Real abs(const Real &);
template<typename Real>
Real sqrt(const Real &);
template<typename Real>
Real sin(const Real &);
template<typename Real>
Real cos(const Real &);
template<typename Real>
Real ceil(const Real &);
template<typename Real>
Real floor(const Real &);
template<typename Real>
Real acos(const Real &);
template<typename Real>
Real atan(const Real &);
template<typename Real>
Real atan2(const Real &, const Real &);
template<typename Real>
Real hypot(const Real &, const Real &);
template<typename Real>
Real pow2(const Real &);
template<typename Real>
Real length(const Real &);
template<typename Real>
Real min_value(const Real &lhs, const Real &rhs);
template<typename Real>
Real max_value(const Real &lhs, const Real &rhs);
template<typename T>
math::Real toReal (const T &v)
{
return (math::Real)v;
}
template<>
u128 abs(const u128 &v);
template<>
s128 abs(const s128 &v);
template<>
u128 sqrt(const u128 &v);
template<>
s128 sqrt(const s128 &v);
} // namespace
} // namespace
} // namespace

43
tjp/core/math/Real.hpp Executable file
View File

@@ -0,0 +1,43 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#pragma once
#include "Real.h"
#include "Zero.h"
namespace tjp {
namespace core {
namespace math {
template<typename Real>
struct constants {
static const Real PI;
static const Real TWO_PI;
static const Real DEGREES_TO_RADIANS;
static const Real RADIANS_TO_DEGREES;
} ;
template<>
const double tjp::core::math::constants<double>::PI;
template<>
const float tjp::core::math::constants<float>::PI;
template<>
const double tjp::core::math::constants<double>::TWO_PI;
template<>
const float tjp::core::math::constants<float>::TWO_PI;
} // namespace
} // namespace
} // namespace
#include "Real.inl"

174
tjp/core/math/Real.inl Executable file
View File

@@ -0,0 +1,174 @@
//
// Math.inl
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
// inline
#pragma once
#include "Real.hpp"
#include <cmath>
#include <algorithm>
namespace tjp {
namespace core {
namespace math {
template<typename T>
T clamp(const T &t, T l=0, T r=1)
{
return std::min(std::max(t, l), r);
}
template<typename Real>
Real ceil(const Real &r)
{
return std::ceil(r);
}
template<typename Real>
Real floor(const Real &r)
{
return std::floor(r);
}
template<typename Real>
Real trunc(const Real &r)
{
return std::trunc(r);
}
template<typename Real>
Real pow2(const Real &r)
{
return r*r;
}
template<typename Real>
Real min_value(const Real &lhs, const Real &rhs)
{
if (lhs < rhs)
return lhs;
return rhs;
}
template<typename Real>
Real max_value(const Real &lhs, const Real &rhs)
{
if (lhs > rhs)
return lhs;
return rhs;
}
template<typename Real>
Real sign_of(const Real & a)
{
if (a < 0)
return (Real)-1;
return 1;
}
template<typename Real>
Real abs(const Real & a)
{
return std::abs(a);
}
template<typename Real>
Real sin(const Real & a)
{
return std::sin(a);
}
// inline
template<typename Real>
Real cos(const Real & a)
{
return std::cos(a);
}
// inline
template<typename Real>
Real sqrt(const Real &v)
{
return std::sqrt(v);
}
// inline
template<typename Real>
Real acos(const Real & v)
{
return std::acos(v);
}
// inline
template<typename Real>
Real atan(const Real & v)
{
return std::atan(v);
}
// inline
template<typename Real>
Real atan2(const Real & v, const Real & e)
{
return std::atan2(v, e);
}
// inline
template<typename Real>
Real hypot(const Real & v, const Real & e)
{
return std::hypot(v, e);
}
template<typename Real>
Real length(const Real & r)
{
return abs(r);
}
template<typename Real>
Real lengthSquared(Real r)
{
return r*r;
}
// ----
template<>
inline
u128 abs(const u128 &v)
{
return v;
}
template<>
inline
s128 abs(const s128 &v)
{
return v >= 0 ? v : -v;
}
template<typename Real>
Real fract(Real r)
{
Real _;
return std::modf(r, &_);
}
} // namespace
} // namespace
} // namespace

View File

@@ -0,0 +1,68 @@
//
// MathIO.h
// common
//
// Created by Timothy Prepscius on 8/4/18.
// Copyright © 2018 Timothy Prepscius. All rights reserved.
//
#pragma once
#include "RelativeFront.h"
#include "Accuracy+IO.h"
namespace tjp {
namespace core {
namespace math {
template<typename IO, typename V>
void io_r(IO &io, RelativeFront<V> &a)
{
auto &v = *a.v;
io.on_vector_begin(v);
if (!v.empty())
{
io.on_vector_value(v.front());
auto &front = v.front();
typedef typename V::value_type VV;
VV vv;
Accuracy<VV> avv { &vv, a.m };
for (auto i=++v.begin(); i!=v.end(); ++i)
{
io.on_vector_value(avv);
*i = vv + front;
}
}
io.on_vector_end(v);
}
template<typename IO, typename V>
void io_w(IO &io, const RelativeFront<V> &a)
{
auto &v = *a.v;
io.on_vector_begin(v);
if (!v.empty())
{
auto &front = v.front();
io.on_vector_value(front);
for (auto i=++v.begin(); i!=v.end(); ++i)
{
auto vv = *i - front;
io.on_vector_value(with_accuracy(vv, a.m));
}
}
io.on_vector_end(v);
}
} // namespace
} // namespace
} // namespace

View File

@@ -0,0 +1,31 @@
//
// MathIO.h
// common
//
// Created by Timothy Prepscius on 8/4/18.
// Copyright © 2018 Timothy Prepscius. All rights reserved.
//
#pragma once
namespace tjp {
namespace core {
namespace math {
template<typename V>
struct RelativeFront
{
V *v;
Real m;
} ;
template<typename V>
auto relative_front(V &v, Real m)
{
return RelativeFront<V> { &v, m };
}
} // namespace
} // namespace
} // namespace

23
tjp/core/math/Segment1.h Executable file
View File

@@ -0,0 +1,23 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#pragma once
#include "Real.h"
namespace tjp {
namespace core {
namespace math {
template<typename Real>
struct Segment1;
} // namespace
} // namespace
} // namespace

40
tjp/core/math/Segment1.hpp Executable file
View File

@@ -0,0 +1,40 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#pragma once
#include "Segment1.h"
#include "Vector3.hpp"
#include "Vector2.hpp"
#include <cstddef>
#include <array>
#include "Zero.h"
namespace tjp {
namespace core {
namespace math {
template<typename Real>
struct Segment1
{
typedef Real value_type;
Real begin, end;
static const Segment1 Zero;
} ;
template<typename Real>
const Segment1<Real> Segment1<Real>::Zero = { zero<Real>(), zero<Real>() };
} // namespace
} // namespace
} // namespace

90
tjp/core/math/Segment1.inl Executable file
View File

@@ -0,0 +1,90 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#pragma once
#include "Segment1.hpp"
namespace tjp {
namespace core {
namespace math {
template<typename Real>
auto length(const Segment1<Real> &r)
{
return distance(r.end,r.begin);
}
template<typename Real>
auto length_squared(const Segment1<Real> &r)
{
return distance_squared(r.end,r.begin);
}
template<typename Real>
bool operator==(const Segment1<Real> &lhs, const Segment1<Real> &rhs)
{
return lhs.begin == rhs.begin && lhs.end == rhs.end;
}
template<typename Real>
Segment1<Real> operator +(const Segment1<Real> &lhs, const Segment1<Real> &rhs)
{
return {
lhs.begin + rhs.begin,
lhs.end + rhs.end
};
}
template<typename Real>
Segment1<Real> operator -(const Segment1<Real> &lhs, const Segment1<Real> &rhs)
{
return {
lhs.begin - rhs.begin,
lhs.end - rhs.end
};
}
template<typename Real>
Segment1<Real> operator /(const Segment1<Real> &lhs, const size_t &rhs)
{
return {
(Real)(lhs.begin / rhs),
(Real)(lhs.end / rhs)
};
}
template<typename Real>
auto distance(const Segment1<Real> &s0, const Segment1<Real> &s1)
{
return distance((s0.begin+s0.end),(s1.begin+s1.end)) - (length(s0) + length(s1));
}
template<typename Real>
auto distance_squared(const Segment1<Real> &s0, const Segment1<Real> &s1)
{
return distance_squared((s0.begin+s0.end),(s1.begin+s1.end)) - (length_squared(s0) + length_squared(s1));
}
template<typename Real>
auto distance_relative(const Segment1<Real> &s0, const Segment1<Real> &s1)
{
return distance(s0, s1);
}
template<typename R>
void zero(Segment1<R> &v)
{
v = Segment1<R>::Zero;
}
} // namespace
} // namespace
} // namespace

62
tjp/core/math/SimpleLine.cpp Executable file
View File

@@ -0,0 +1,62 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#include "SimpleLine.hpp"
#include "Vector2.inl"
#include <tjp/core/assert/debug_assert.h>
namespace tjp::core::math {
SimpleLineCompute::SimpleLineCompute(std::initializer_list<math::Vector2f> l, bool cap_) :
cap(cap_)
{
p.insert(p.end(), l.begin(), l.end());
s.resize(p.size()-1);
if (p.empty())
return ;
auto next = p.begin();
auto prev = next++;
auto write = s.begin();
for ( ;next!=p.end(); prev = next++)
{
auto d = *next - *prev;
debug_assert(d[0] != 0);
auto sv = d[1]/d[0];
*write++ = sv;
}
}
float SimpleLineCompute::operator ()(float x)
{
debug_assert(!p.empty());
if (cap && x < p.front().x())
return p.front().y();
auto last = p.size()-1;
for (auto i=1; ; ++i)
{
auto &r = p[i];
if (x < r.x() || i == last)
{
if (i == last && cap)
return p[i].y();
auto &l = p[i-1];
auto &s_ = s[i-1];
return l.y() + (x-l.x()) * s_;
}
}
}
} // namespace

20
tjp/core/math/SimpleLine.h Executable file
View File

@@ -0,0 +1,20 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#pragma once
namespace tjp {
namespace core {
namespace math {
struct SimpleLineCompute;
} // namespace
} // namespace
} // namespace

34
tjp/core/math/SimpleLine.hpp Executable file
View File

@@ -0,0 +1,34 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#include "Vector2.hpp"
#include <tjp/core/containers/Vector.h>
#pragma once
namespace tjp {
namespace core {
namespace math {
struct SimpleLineCompute
{
core::Vector<math::Vector2f> p;
core::Vector<float> s;
bool cap;
SimpleLineCompute(
std::initializer_list<math::Vector2f> l,
bool cap
);
float operator ()(float x);
} ;
} // namespace
} // namespace
} // namespace

24
tjp/core/math/Sphere1.h Executable file
View File

@@ -0,0 +1,24 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#pragma once
namespace tjp {
namespace core {
namespace math {
template<typename C,typename D=C>
class Sphere1;
typedef Sphere1<s64> Sphere1i64;
typedef Sphere1<s128> Sphere1i128;
} // namespace
} // namespace
} // namespace

64
tjp/core/math/Sphere1.hpp Executable file
View File

@@ -0,0 +1,64 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#pragma once
#include "Sphere1.h"
#include "Zero.h"
#include <tjp/core/types/Types.h>
#include <limits>
namespace tjp {
namespace core {
namespace math {
template<typename C, typename D>
class Sphere1
{
public:
typedef Real value_type;
typedef D Distance;
typedef C Center;
typedef Sphere1<C, D> Self;
Center center;
Distance radius;
Sphere1 () {}
Sphere1 (Center center_, Distance radius_) :
center(center_),
radius(radius_)
{
}
const static Self Zero;
const static Self Infinite;
Distance distanceTo(Real p) const;
Distance minDistanceTo (const Self &v) const;
Distance maxDistanceTo (const Self &v) const;
Distance minDistanceTo (Real v) const;
Distance maxDistanceTo (Real v) const;
} ;
template<typename Center, typename Distance>
const Sphere1<Center,Distance> Sphere1<Center,Distance>::Zero = { zero<Center>(), zero<Distance>() };
template<typename Center, typename Distance>
const Sphere1<Center,Distance> Sphere1<Center,Distance>::Infinite = { zero<Center>(), std::numeric_limits<Distance>::infinity() };
typedef Sphere1<s64> Sphere1i64;
typedef Sphere1<s128> Sphere1i128;
} // namespace
} // namespace
} // namespace

117
tjp/core/math/Sphere1.inl Executable file
View File

@@ -0,0 +1,117 @@
//
// Math.inl
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#pragma once
#include "Zero.h"
#include "Sphere1.hpp"
namespace tjp {
namespace core {
namespace math {
template<typename C, typename D>
D Sphere1<C,D>::distanceTo (Real p) const
{
return (p - center) - radius;
}
// inline
template<typename C, typename D>
D Sphere1<C,D>::minDistanceTo (const Self &p) const
{
return distance(p.center, center) - (radius + p.radius);
}
template<typename C, typename D>
D Sphere1<C,D>::maxDistanceTo (const Self & p) const
{
auto centerDistance = (p.center - center);
auto diffRadius = std::abs(p.radius - radius);
// if the circle is within the other
if (diffRadius > centerDistance)
return diffRadius - centerDistance;
// if the circle is not within the other
auto sumRadius = p.radius + radius;
return centerDistance + sumRadius;
}
template<typename C, typename D>
bool operator ==(const Sphere1<C,D> &l, const Sphere1<C,D> &r)
{
return l.center == r.center && l.radius == r.radius;
}
template<typename C, typename D>
D distance (const Sphere1<C,D> &lhs, const Sphere1<C,D> &rhs)
{
return distance(lhs.center, rhs.center) - (lhs.radius + rhs.radius);
}
template<typename C, typename D>
D distance_squared (const Sphere1<C,D> &lhs, const Sphere1<C,D> &rhs)
{
return distance_squared(lhs.center, rhs.center) - pow2(lhs.radius + rhs.radius);
}
template<typename C, typename D>
D distance_relative(const Sphere1<C, D> &l, const Sphere1<C, D> &r)
{
return distance_squared(l, r);
}
template<typename C, typename D>
Sphere1<C, D> operator+(const Sphere1<C,D> &lhs, const Sphere1<C,D> &rhs)
{
return {
lhs.center + rhs.center,
lhs.radius + rhs.radius
};
}
template<typename C, typename D>
Sphere1<C, D> operator-(const Sphere1<C,D> &lhs, const Sphere1<C,D> &rhs)
{
return {
lhs.center - rhs.center,
lhs.radius - rhs.radius
};
}
template<typename C, typename D>
Sphere1<C, D> operator /(const Sphere1<C,D> &lhs, const D &rhs)
{
return {
lhs.center / rhs,
lhs.radius / rhs
};
}
template<typename C, typename D>
Sphere1<C, D> operator /(const Sphere1<C,D> &lhs, size_t rhs)
{
return {
lhs.center / rhs,
lhs.radius / rhs
};
}
template<typename C, typename D>
void zero(Sphere1<C, D> &v)
{
v = {
zero<C>(),
zero<D>()
};
}
} // namespace
} // namespace
} // namespace

43
tjp/core/math/Sphere3.cpp Executable file
View File

@@ -0,0 +1,43 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#include "Sphere3.hpp"
#include "GTE_convert.hpp"
#define GTE_NO_LOGGER
#include <Mathematics/MinimumVolumeSphere3.h>
#include <Mathematics/ContSphere3.h>
namespace tjp {
namespace core {
namespace math {
Sphere3r minimumBoundingSphere(const Vector<math::Vector3r> &translates_)
{
if (translates_.empty())
return Sphere3r::Zero;
std::vector<gte::Vector3<Real>> translates;
for (auto &p : translates_)
translates.push_back(gte_c(p));
gte::Sphere3<Real> sphere;
gte::MinimumVolumeSphere3<Real, Real> generator;
generator(static_cast<int>(translates.size()), translates.data(), sphere);
return gte_c(sphere);
}
} // namespace
} // namespace
} // namespace

27
tjp/core/math/Sphere3.h Executable file
View File

@@ -0,0 +1,27 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#pragma once
#include "Real.h"
namespace tjp {
namespace core {
namespace math {
template<typename Real>
class Sphere3;
typedef Sphere3<float> Sphere3f;
typedef Sphere3<double> Sphere3d;
typedef Sphere3<Real> Sphere3r;
} // namespace
} // namespace
} // namespace

78
tjp/core/math/Sphere3.hpp Executable file
View File

@@ -0,0 +1,78 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#pragma once
#include "Sphere3.h"
#include "Zero.h"
#include <tjp/core/types/Types.h>
#include <limits>
#include "Vector3.hpp"
#include <tjp/core/containers/Vector.hpp>
namespace tjp {
namespace core {
namespace math {
template<typename Real>
class Sphere3
{
public:
typedef Real value_type;
typedef Vector3<Real> Center;
Center center;
Real radius;
Sphere3 () {}
Sphere3 (const Vector3<Real> &center_, Real radius_) :
center(center_),
radius(radius_)
{
}
Real distanceTo(const Vector3<Real> &p) const;
Real minDistanceTo (const Sphere3<Real> &v) const;
Real maxDistanceTo (const Sphere3<Real> &v) const;
Real minDistanceTo (const Vector3<Real> &v) const;
Real maxDistanceTo (const Vector3<Real> &v) const;
bool contains(const Vector3<Real> &p) const;
bool contains(const Sphere3<Real> &v) const;
const static Sphere3 Zero;
const static Sphere3 Infinite;
template<typename T>
Sphere3<T> asType() const
{
return Sphere3<T> { center.template asType<T>(), T(radius) };
}
};
template<typename Real>
const Sphere3<Real> Sphere3<Real>::Zero = { Vector3<Real>::Zero, 0 };
template<typename Real>
const Sphere3<Real> Sphere3<Real>::Infinite = { Vector3<Real>::Zero, std::numeric_limits<Real>::infinity() };
typedef Sphere3<float> Sphere3f;
typedef Sphere3<double> Sphere3d;
typedef Sphere3<Real> Sphere3r;
Sphere3r minimumBoundingSphere(const Vector<math::Vector3r> &points);
} // namespace
} // namespace
} // namespace

197
tjp/core/math/Sphere3.inl Executable file
View File

@@ -0,0 +1,197 @@
//
// Math.inl
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#pragma once
#include "Sphere3.hpp"
#include "Real.hpp"
#include "Vector3.inl"
#include "Zero.h"
namespace tjp {
namespace core {
namespace math {
template<typename Real>
bool operator==(const Sphere3<Real>& lhs, const Sphere3<Real>& rhs)
{
return lhs.center == rhs.center && lhs.radius == rhs.radius;
}
template<typename Real>
bool operator!=(const Sphere3<Real>& lhs, const Sphere3<Real>& rhs)
{
return !(lhs == rhs);
}
// inline
template<typename Real>
Real Sphere3<Real>::distanceTo (const Vector3<Real>& p) const
{
return distance(p, center) - radius;
}
// inline
template<typename Real>
Real Sphere3<Real>::minDistanceTo (const Sphere3<Real>& p) const
{
return distance(p.center, center) - (radius + p.radius);
}
// inline
template<typename Real>
Real Sphere3<Real>::maxDistanceTo (const Sphere3<Real>& p) const
{
auto centerDistance = distance(p.center, center);
auto diffRadius = std::abs(p.radius - radius);
// if the circle is within the other
if (diffRadius > centerDistance)
return diffRadius - centerDistance;
// if the circle is not within the other
auto sumRadius = p.radius + radius;
return centerDistance + sumRadius;
}
template<typename Real>
Real Sphere3<Real>::minDistanceTo (const Vector3<Real>& p) const
{
return (p - center).length() - radius;
}
template<typename Real>
Real Sphere3<Real>::maxDistanceTo (const Vector3<Real>& p) const
{
auto distance = (p - center).length();
if (radius > distance)
return distance - radius;
return distance + radius;
}
template<typename Real>
Real distance(const Sphere3<Real> &l, const Sphere3<Real> &r)
{
return distance(l.center, r.center) - (l.radius + r.radius);
}
template<typename Real>
Real distance(const Sphere3<Real> &l, const Vector3<Real> &r)
{
return distance(l.center, r) - (l.radius);
}
//
template<typename Real>
Real distance_squared_exact(const Sphere3<Real> &l, const Sphere3<Real> &r)
{
return pow2(distance(l, r));
}
template<typename Real>
Real distance_squared_approx(const Sphere3<Real> &l, const Sphere3<Real> &r)
{
return distance_squared(l.center, r.center) - math::pow2(l.radius + r.radius);
}
template<typename Real>
Real distance_squared(const Sphere3<Real> &l, const Vector3<Real> &r)
{
return distance_squared(l.center, r) - math::pow2(l.radius);
}
template<typename Real>
Real distance_relative(const Sphere3<Real> &l, const Sphere3<Real> &r)
{
return distance_squared_approx(l, r);
}
// inline
template<typename Real>
bool Sphere3<Real>::contains (const Vector3<Real>& p) const
{
auto radiusSquared = radius * radius;
return (p - center).lengthSquared() < radiusSquared;
}
template<typename Real>
bool Sphere3<Real>::contains (const Sphere3<Real>& v) const
{
auto r = (radius - v.radius);
auto r2 = r * r;
return (v.center - center).lengthSquared() < r2;
}
template<typename Real>
bool same(const Sphere3<Real> &lhs, const Sphere3<Real> &rhs, Real epsilon)
{
if ((lhs.center - rhs.center).length() > epsilon)
return false;
if (std::abs(lhs.radius - rhs.radius) > epsilon)
return false;
return true;
}
template<typename Real>
void zero(Sphere3<Real> &r)
{
r = {
zero<typename Sphere3<Real>::Center>(),
zero<Real>()
} ;
}
template<typename Real>
Sphere3<Real> &operator +=(Sphere3<Real> &lhs, const Sphere3<Real> &rhs)
{
lhs.center += rhs.center;
lhs.radius += rhs.radius;
return lhs;
}
template<typename Real>
Sphere3<Real> operator +(const Sphere3<Real> &lhs, const Sphere3<Real> &rhs)
{
return { lhs.center+rhs.center, lhs.radius+rhs.radius };
}
template<typename Real>
Sphere3<Real> operator -(const Sphere3<Real> &lhs, const Sphere3<Real> &rhs)
{
return { lhs.center-rhs.center, lhs.radius-rhs.radius };
}
template<typename Real, typename U>
Sphere3<Real> operator /(const Sphere3<Real> &lhs, const U &rhs)
{
return Sphere3<Real> {
lhs.center / rhs,
lhs.radius / rhs
};
}
template<typename Real, typename U>
Sphere3<Real> operator *(const U &lhs, const Sphere3<Real> &rhs)
{
return Sphere3<Real> {
lhs * rhs.center,
lhs * rhs.radius
};
}
} // namespace
} // namespace
} // namespace

665
tjp/core/math/Statistics.h Executable file
View File

@@ -0,0 +1,665 @@
//
// Server.hpp
// TimeSync
//
// Created by Timothy Prepscius on 1/27/17.
// Copyright © 2017 Timothy Prepscius. All rights reserved.
//
#pragma once
#include <cmath>
#include <vector>
#include <numeric>
#include <iostream>
#include <functional>
#include <climits>
#include <algorithm>
#include <deque>
namespace tjp {
namespace core {
namespace math {
struct RunningStatsWeightedAverager
{
typedef double T;
double weight, oneMinusWeight;
T m, s;
bool initialized = false;
RunningStatsWeightedAverager(double weight_ = 0.8) :
m(0),
s(0),
weight(weight_),
oneMinusWeight(1.0 - weight_)
{
clear();
}
void clear()
{
m = 0;
s = 0;
}
void initialize(T x)
{
m = x;
initialized = true;
}
void push(T x)
{
if (!initialized)
initialize(x);
// See Knuth TAOCP vol 2, 3rd edition, page 232
auto newM = weight * m + oneMinusWeight * x;
auto newS = weight * s + oneMinusWeight * std::abs(x - m);
// set up for next iteration
m = newM;
s = newS;
}
double mean() const
{
return m;
}
double error() const
{
return s;
}
};
template<typename T>
class RunningStats
{
public:
RunningStats()
{
clear();
}
void clear()
{
n = 0;
m = 0;
s = 0;
}
void push(T x)
{
n++;
// See Knuth TAOCP vol 2, 3rd edition, page 232
auto newM = m + (x - m) / n;
auto newS = s + (x - m)*(x - newM);
// set up for next iteration
m = newM;
s = newS;
}
int numDataValues() const
{
return n;
}
double mean() const
{
return (n > 0) ? m : 0.0;
}
double variance() const
{
return ((n > 1) ? s / (n - 1) : 0.0);
}
double standardDeviation() const
{
return std::sqrt(variance());
}
private:
int n;
T m, s;
};
template<typename T>
class AccumulatedStats
{
protected:
std::vector<T> samples;
T unresolved;
T m;
T e;
void calculate()
{
m = e = unresolved;
if (samples.empty())
return;
T s = 0;
for (auto &t : samples)
{
s += t;
}
m = s /= samples.size();
if (samples.size() < 2)
return;
T s0 = 0;
for (int i = 0; i < samples.size() / 2; ++i)
{
s0 += samples[i];
}
T s1 = 0;
for (int i = samples.size() / 2; i < samples.size(); ++i)
{
s1 += samples[i];
}
s0 /= samples.size() / 2;
s1 /= samples.size() - samples.size() / 2;
e = s1 - s0;
}
public:
AccumulatedStats(T unresolved)
{
this->unresolved = unresolved;
}
void push(T t)
{
samples.push_back(t);
calculate();
}
void clear()
{
samples.clear();
calculate();
}
T mean()
{
return m;
}
T error()
{
return e;
}
T errorSize()
{
return std::abs(e);
}
};
template<typename R, typename T=R>
R valueOf(const T &t) { return (R)t; }
template<typename R, typename T=R>
R weightOf(const T &t) { return (R)1.0; }
template<typename T>
double stdev_lengthSquared(const T &d)
{
return (double)d * (double)d;
}
template<typename T>
T zero_of()
{
return (T)0.0;
}
template<typename R, typename V>
R mean(const V &v, std::function<R(const typename V::value_type &)> f=valueOf<R, typename V::value_type>)
{
R sum = zero_of<R>();
for (auto &t : v)
{
sum += f(t);
}
auto mean = sum / v.size();
return mean;
}
template<typename R, typename V>
R weighted_mean(const V &v,
std::function<R(const typename V::value_type &)> f=valueOf<R, typename V::value_type>,
std::function<R(const typename V::value_type &)> w=weightOf<R, typename V::value_type>
)
{
R sum = zero_of<R>();
R weight = zero_of<R>();
for (auto &t : v)
{
auto w_ = w(t);
sum += w_ * f(t);
weight += w_;
}
auto mean = sum / weight;
return mean;
}
template<typename R, typename V>
double stdev(const V &v, const R &mean, std::function<R(const typename V::value_type &)> f=valueOf<R, typename V::value_type>)
{
double sum = zero_of<double>();
for (auto &t : v)
{
auto diff = f(t) - mean;
sum += stdev_lengthSquared(diff);
}
return std::sqrt(sum / (double)v.size());
}
template<typename R, typename V>
double stdev(const V &v, std::function<R(const typename V::value_type &)> f=valueOf<R, typename V::value_type>)
{
typedef typename V::value_type T;
T mean = math::mean<T>(v, f);
return stdev(v, mean);
}
template<typename T>
struct MeanStddev
{
T mean;
T stddev;
} ;
template<typename R, typename V>
MeanStddev<R> rejectOutliersMeanStddev(const V &samples, R a, std::function<R(const typename V::value_type &)> f=valueOf<R, typename V::value_type>)
{
R m, e;
auto u = math::mean(samples);
auto s = math::stdev(samples);
// filtered = [e for e in data_bad if (u - 2 * s < e < u + 2 * s)]
std::vector<R> filtered;
for (auto &v : samples)
{
if (u - a * s < v && v < u + a * s)
{
filtered.push_back(v);
}
}
if (filtered.empty())
{
m = e = 0;
return { m, e };
}
return { math::mean(filtered), math::stdev(filtered) };
}
template<typename T>
class RejectOutlierStats
{
protected:
std::vector<T> samples;
double a;
T unresolved;
T m;
T e;
void calculate()
{
if (samples.empty())
{
m = e = unresolved;
return;
}
auto u = math::mean<T>(samples);
auto s = math::stdev<T>(samples);
// filtered = [e for e in data_bad if (u - 2 * s < e < u + 2 * s)]
std::vector<T> filtered;
for (auto &v : samples)
{
if (u - a * s < v && v < u + a * s)
{
filtered.push_back(v);
}
}
if (filtered.empty())
{
m = e = unresolved;
return;
}
auto m = math::mean<T>(filtered);
auto e = math::stdev<T>(filtered);
this->m = m;
this->e = e;
}
public:
RejectOutlierStats(T unresolved, double a = 2.0)
{
this->unresolved = unresolved;
m = e = unresolved;
this->a = a;
}
void push(T t)
{
samples.push_back(t);
calculate();
}
void clear()
{
samples.clear();
calculate();
}
T mean()
{
return m;
}
T error()
{
return e;
}
T errorSize()
{
return std::abs(e);
}
size_t size () const
{
return samples.size();
}
};
template<typename T>
class WindowStats
{
protected:
std::deque<T> samples;
int windowSize;
double a;
T unresolved;
T m;
T e;
T l;
void calculate()
{
m = e = l = unresolved;
if (samples.empty())
return;
auto &window = samples;
typedef double R;
m = math::mean<R>(window);
e = math::stdev<R>(window);
}
public:
WindowStats(T unresolved, int windowSize, double a = 2.0)
{
this->unresolved = unresolved;
l = m = e = unresolved;
this->a = a;
this->windowSize = windowSize;
}
void push(T t)
{
samples.push_front(t);
while (samples.size() > windowSize)
samples.pop_back();
calculate();
}
void clear()
{
samples.clear();
calculate();
}
T mean()
{
return m;
}
T min()
{
return l;
}
T error()
{
return e;
}
T errorSize()
{
return std::abs(e);
}
};
template<typename T>
class RejectOutlierWindowStats
{
protected:
std::deque<T> samples;
int windowSize;
double a;
T unresolved;
T m;
T e;
T l;
void calculate()
{
m = e = l = unresolved;
if (samples.empty())
return;
auto &window = samples;
typedef double R;
R u = math::mean<R>(window);
R s = math::stdev<R>(window);
// filtered = [e for e in data_bad if (u - 2 * s < e < u + 2 * s)]
std::vector<T> filtered;
for (auto &v : window)
{
if (l == unresolved)
l = v;
else
l = std::min(l, v);
if (u - a * s < v && v < u + a * s)
{
filtered.push_back(v);
}
}
if (filtered.empty())
return;
m = math::mean<R>(filtered);
e = math::stdev<R>(filtered);
}
public:
RejectOutlierWindowStats(T unresolved, int windowSize, double a = 2.0)
{
this->unresolved = unresolved;
l = m = e = unresolved;
this->a = a;
this->windowSize = windowSize;
}
void push(T t)
{
samples.push_back(t);
if (samples.size() > windowSize)
samples.pop_front();
calculate();
}
void clear()
{
samples.clear();
calculate();
}
T mean()
{
return m;
}
T min()
{
return l;
}
T error()
{
return e;
}
T errorSize()
{
return std::abs(e);
}
};
template<typename T, typename R>
class RejectOutlierUseBestStatsWindow
{
protected:
typedef std::pair<T, R> Sample;
std::vector<Sample> samples;
int numSamplesToReduce;
int numSamplesToInclude;
double a;
T unresolved;
T m;
T e;
void calculate()
{
m = e = unresolved;
if (samples.empty())
return;
auto numSamplesToReduce = std::min((int)samples.size(), this->numSamplesToReduce == -1 ? INT_MAX : this->numSamplesToReduce);
std::vector<Sample> last(samples.end() - numSamplesToReduce, samples.end());
std::sort(last.begin(), last.end(), [](Sample &l, Sample &r) { return l.second < r.second; });
auto numSamplesToInclude = std::min((int)last.size(), this->numSamplesToInclude);
std::vector<T> best;
for (auto i = 0; i < numSamplesToInclude; ++i)
{
best.push_back(last[i].first);
}
double u = math::mean(best);
double s = math::stdev(best);
// filtered = [e for e in data_bad if (u - 2 * s < e < u + 2 * s)]
std::vector<T> filtered;
for (auto &v : best)
{
if (u - a * s < v && v < u + a * s)
{
filtered.push_back(v);
}
}
if (filtered.empty())
return;
m = math::mean(filtered);
e = math::stdev(filtered);
}
public:
RejectOutlierUseBestStatsWindow(T unresolved, int numSamplesToReduce, int numSamplesToInclude, double a = 2.0)
{
this->unresolved = unresolved;
m = e = unresolved;
this->a = a;
this->numSamplesToReduce = numSamplesToReduce;
this->numSamplesToInclude = numSamplesToInclude;
}
void push(T t, R r)
{
samples.push_back({ t, r });
calculate();
}
void clear()
{
samples.clear();
calculate();
}
T mean()
{
return m;
}
T error()
{
return e;
}
T errorSize()
{
return std::abs(e);
}
};
} // namespace
} // namespace
} // namespace

36
tjp/core/math/Vector2.h Executable file
View File

@@ -0,0 +1,36 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#pragma once
#include "Real.h"
namespace tjp {
namespace core {
namespace math {
template<typename T>
struct Vector2_;
typedef Vector2_<double> Vector2d_;
typedef Vector2_<float> Vector2f_;
typedef Vector2_<Real> Vector2r_;
typedef Vector2_<int> Vector2i_;
template<typename T>
struct Vector2;
typedef Vector2<double> Vector2d;
typedef Vector2<float> Vector2f;
typedef Vector2<Real> Vector2r;
typedef Vector2<int> Vector2i;
} // namespace
} // namespace
} // namespace

125
tjp/core/math/Vector2.hpp Executable file
View File

@@ -0,0 +1,125 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#pragma once
#include "Vector2.h"
#include "Zero.h"
#include <tjp/core/types/Types.h>
#include <initializer_list>
namespace tjp::core::math {
template<typename Real>
struct Vector2_ {
using V = Real[2];
V v;
Real &operator[](size_t i) { return v[i]; }
Real const &operator[](size_t i) const { return v[i]; };
} ;
template<typename T>
struct Vector2
{
using Real = T;
using V = Vector2_<Real>;
V v;
constexpr Vector2(int zero) :
v { (T)zero, (T)zero }
{}
constexpr Vector2() = default;
constexpr Vector2(const Vector2 &) = default;
constexpr Vector2(const V &rhs) : v (rhs) {}
constexpr Vector2(const std::initializer_list<Real> &v_)
{
auto i = 0;
for (auto &n: v_)
v[i++] = n;
}
constexpr Vector2& operator=(const Vector2 &) = default;
constexpr Vector2& operator=(const V &v_)
{
v = v_;
return *this;
}
constexpr Vector2& operator=(const std::initializer_list<Real> &v_)
{
auto i = 0;
for (auto &n: v_)
v[i++] = n;
return *this;
}
constexpr Vector2(Real x, Real y)
: v {x, y}
{}
operator V &() { return v; }
operator const V &() const { return v; }
T &x() { return v[0]; }
T &y() { return v[1]; }
const T &x() const { return v[0]; }
const T &y() const { return v[1]; }
template<typename U>
Vector2<U> asType() const;
T lengthSquared () const;
T length () const;
template<typename D=T>
Vector2<D> normalize() const;
T &operator[](size_t i);
const T &operator[](size_t i) const;
void flip ();
static const Vector2 Zero;
} ;
template<typename Real>
const Vector2<Real> Vector2<Real>::Zero = { zero<Real>(),zero<Real>() };
template<typename Real>
Real &Vector2<Real>::operator[](size_t i)
{
return v[i];
}
template<typename Real>
const Real &Vector2<Real>::operator[](size_t i) const
{
return v[i];
}
template<typename Real>
template<typename U>
Vector2<U> Vector2<Real>::asType() const
{
return Vector2<U> { (U)x(), (U)y() };
}
typedef Vector2<double> Vector2d;
typedef Vector2<float> Vector2f;
typedef Vector2<Real> Vector2r;
typedef Vector2<int> Vector2i;
} // namespace

241
tjp/core/math/Vector2.inl Executable file
View File

@@ -0,0 +1,241 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#pragma once
#include "Vector2.hpp"
#include "Real.h"
#include "Real.inl"
#include <utility>
#include <initializer_list>
#include "Zero.h"
namespace tjp {
namespace core {
namespace math {
template<typename Real>
void zero(Vector2<Real> &v)
{
v = Vector2<Real>::Zero;
}
template<typename Real>
Vector2<Real> abs(const Vector2<Real> &v)
{
return { abs(v[0]), abs(v[1]) };
}
template<typename Real>
Real lengthSquared(const Vector2<Real> &r)
{
return r.lengthSquared();
}
template<typename Real>
Real length(const Vector2<Real> &r)
{
return r.length();
}
template<typename Real>
Real Vector2<Real>::lengthSquared () const
{
Real x = v[0];
Real y = v[1];
return x*x + y*y;
}
template<typename Real>
Real Vector2<Real>::length () const
{
return sqrt(lengthSquared());
}
template<typename Real>
template<typename D>
Vector2<D> Vector2<Real>::normalize() const
{
auto l = length();
if (l == 0)
return { D(0), D(0) };
return *this / l;
}
template<typename Real>
void Vector2<Real>::flip ()
{
std::swap(v[0], v[1]);
}
template<typename Real>
Real dot(Vector2<Real> const& l, Vector2<Real> const& r)
{
return l[0] * r[0] + l[1] * r[1];
}
template<typename Real>
Vector2<Real> operator *(Real m, Vector2<Real> const& r)
{
return { m * r[0], m * r[1] };
}
template<typename Real>
Vector2<Real> operator *(Vector2<Real> const& r, Real m)
{
return { m * r[0], m * r[1] };
}
template<typename Real, typename U>
Vector2<Real> operator /(U m, Vector2<Real> const& r)
{
return { m / r[0], m / r[1] };
}
template<typename Real>
Vector2<Real> operator -(const Vector2<Real> &v)
{
return { -v[0], -v[1] };
}
template<typename Real>
Vector2<Real> &operator +=(Vector2<Real> &v, const Vector2<Real> &r)
{
v[0] += r[0];
v[1] += r[1];
return v;
}
template<typename Real>
Vector2<Real> &operator -=(Vector2<Real> &v, const Vector2<Real> &r)
{
v[0] -= r[1];
v[0] -= r[1];
return v;
}
template<typename Real>
Vector2<Real> &operator /=(Vector2<Real> &v, Real r)
{
v[0] /= r;
v[1] /= r;
return v;
}
template<typename Real>
Vector2<Real> &operator *=(Vector2<Real> &v, Real r)
{
v[0] *= r;
v[1] *= r;
return v;
}
template<typename T>
Vector2_<T> operator -(const Vector2_<T> &l, const Vector2_<T> &r)
{
return { l[0] - r[0], l[1] - r[1] };
}
template<typename T>
Vector2<T> operator -(const Vector2<T> &l, const Vector2<T> &r)
{
return Vector2<T>(l.v - r.v);
}
template<typename T>
Vector2<T> operator +(const Vector2<T> &l, const Vector2<T> &r)
{
return { l[0] + r[0], l[1] + r[1] };
}
template<typename T, typename X>
Vector2<T> operator /(const Vector2<T> &p, const X &m)
{
return { T(p[0]/m), T(p[1]/m) };
}
template<typename T>
Vector2<T> cross(const Vector2<T> &l, const Vector2<T> &r);
template<typename T>
Vector2<T> multiply(const Vector2<T> &l, const Vector2<T> &r)
{
return { l[0] * r[0], l[1] * r[1] };
}
template<typename T>
Vector2<T> mul(const Vector2<T> &l, const Vector2<T> &r)
{
return multiply(l, r);
}
template<typename T>
Vector2<T> divide(const Vector2<T> &l, const Vector2<T> &r)
{
return { l[0] / r[0], l[1] / r[1] };
}
template<typename T>
Vector2<T> operator /(const Vector2<T> &l, const Vector2<T> &r)
{
return { l[0] / r[0], l[1] / r[1] };
}
template<typename T>
bool operator !=(const Vector2_<T> &l, const Vector2_<T> &r)
{
return
l[0] != r[0] ||
l[1] != r[1];
}
template<typename T>
bool operator ==(const Vector2_<T> &l, const Vector2_<T> &r)
{
return
l[0] == r[0] &&
l[1] == r[1];
}
template<typename T>
bool operator !=(const Vector2<T> &l, const Vector2<T> &r) { return l.v != r.v; }
template<typename T>
bool operator ==(const Vector2<T> &l, const Vector2<T> &r) { return l.v == r.v; }
template<typename Real>
Vector2<Real> fract(const Vector2<Real> &v)
{
return {
fract(v[0]),
fract(v[1])
};
}
template<typename Real>
Vector2<Real> trunc(const Vector2<Real> &v)
{
return {
trunc(v[0]),
trunc(v[1])
};
}
} // namespace
} // namespace
} // namespace

35
tjp/core/math/Vector3.h Executable file
View File

@@ -0,0 +1,35 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#pragma once
#include "Real.h"
namespace tjp {
namespace core {
namespace math {
template<typename Real>
struct Vector3_;
typedef Vector3_<double> Vector3d_;
typedef Vector3_<float> Vector3f_;
typedef Vector3_<Real> Vector3r_;
template<typename Real>
struct Vector3;
typedef Vector3<double> Vector3d;
typedef Vector3<float> Vector3f;
typedef Vector3<Real> Vector3r;
} // namespace
} // namespace
} // namespace

118
tjp/core/math/Vector3.hpp Executable file
View File

@@ -0,0 +1,118 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#pragma once
#include "Vector3.h"
#include "Zero.h"
#include <tjp/core/types/Types.h>
#include <tjp/core/containers/Pack.h>
#include <tjp/core/assert/debug_assert.h>
#include <initializer_list>
namespace tjp {
namespace core {
namespace math {
template<typename Real>
struct Vector3_ {
using V = Real[3];
V v;
Real &operator[](size_t i) { return v[i]; }
Real const &operator[](size_t i) const { return v[i]; };
} ;
template<typename T>
struct Vector3
{
using Real = T;
using V = Vector3_<Real>;
V v;
constexpr Vector3(int zero) :
v { static_cast<T>(zero), static_cast<T>(zero), static_cast<T>(zero) }
{}
constexpr Vector3() = default;
constexpr Vector3(const Vector3 &) = default;
constexpr Vector3(const V &rhs) : v (rhs) {}
constexpr Vector3(const std::initializer_list<Real> &v_)
{
auto i = 0;
for (auto &n: v_)
v[i++] = n;
}
constexpr Vector3& operator=(const Vector3 &) = default;
constexpr Vector3& operator=(const V &v_)
{
v = v_;
return *this;
}
constexpr Vector3(Real x, Real y, Real z)
: v {x, y, z}
{}
operator V()
{
return { v[0], v[1], v[2] };
}
Real length () const;
Real lengthSquared () const;
Vector3 normalize () const;
Vector3 operator -() const;
Vector3 &operator +=(const Vector3 &r);
Vector3 &operator -=(const Vector3 &r);
Vector3 &operator /=(Real r);
Vector3 &operator *=(Real r);
Real &operator[](size_t size);
Real const &operator[](size_t size) const;
template<typename U>
Vector3<U> asType() const;
static const Vector3 Zero;
} ;
template<typename Real>
const Vector3<Real> Vector3<Real>::Zero = { zero<Real>(),zero<Real>(),zero<Real>() };
template<typename Real>
Real &Vector3<Real>::operator[](size_t size)
{
return v[size];
}
template<typename Real>
Real const &Vector3<Real>::operator[](size_t size) const
{
return v[size];
}
template<typename Real>
template<typename U>
Vector3<U> Vector3<Real>::asType() const
{
return Vector3<U> { (U)v[0], (U)v[1], (U)v[2] };
}
typedef Vector3<double> Vector3d;
typedef Vector3<float> Vector3f;
typedef Vector3<Real> Vector3r;
} // namespace
} // namespace
} // namespace

285
tjp/core/math/Vector3.inl Executable file
View File

@@ -0,0 +1,285 @@
//
// Math.inl
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#pragma once
#include "Vector3.hpp"
#include "Zero.h"
namespace tjp {
namespace core {
namespace math {
template<typename Real>
Real lengthSquared(const Vector3<Real> &r)
{
return r.lengthSquared();
}
template<typename Real>
Real length(const Vector3<Real> &r)
{
return r.length();
}
template<typename Real>
void zero(Vector3<Real> &v)
{
v = Vector3<Real>::Zero;
}
// inline
template<typename Real>
Real Vector3<Real>::length () const
{
return sqrt(lengthSquared());
}
// inline
template<typename Real>
Real Vector3<Real>::lengthSquared() const
{
return v[0] * v[0] + v[1] * v[1] + v[2] * v[2];
}
// inline
template<typename Real>
Vector3<Real> Vector3<Real>::normalize () const
{
return *this / length();
}
// inline
template<typename Real, typename U>
Vector3<Real> operator *(const Vector3<Real> &l, U r)
{
return Vector3<Real> {
l[0] * r,
l[1] * r,
l[2] * r
};
}
template<typename Real>
Vector3<Real> mul(const Vector3<Real> &l, const Vector3<Real> &r)
{
return { l[0] * r[0], l[1] * r[1], l[2] * r[2]};
}
// inline
template<typename Real, typename U>
Vector3<Real> operator /(const Vector3<Real> &l, U r)
{
return Vector3<Real> {
l[0] / r,
l[1] / r,
l[2] / r
};
}
// inline
template<typename Real, typename U>
Vector3<Real> operator *(U l, const Vector3<Real> &r)
{
return r * l;
}
// inline
template<typename Real, typename U>
Vector3<Real> operator /(U l, const Vector3<Real> &r)
{
return Vector3<Real> {
l / r[0],
l / r[1],
l / r[2]
};
}
template<typename Real>
Vector3<Real> div(const Vector3<Real> &l, const Vector3<Real> &r)
{
return { l[0] / r[0], l[1] / r[1], l[2] / r[2] };
}
// inline
template<typename Real>
Vector3<Real> Vector3<Real>::operator -() const
{
return { -v[0], -v[1], -v[2] };
}
// inline
template<typename Real>
Vector3_<Real> operator +(const Vector3_<Real> &l, const Vector3_<Real> &r)
{
return { l[0] + r[0], l[1] + r[1], l[2] + r[2] };
}
// inline
template<typename Real>
Vector3<Real> operator +(const Vector3<Real> &l, const Vector3<Real> &r)
{
return l.v + r.v;
}
template<typename Real>
Vector3_<Real> operator -(const Vector3_<Real> &l, const Vector3_<Real> &r)
{
return { l[0] - r[0], l[1] - r[1], l[2] - r[2] };
}
// inline
template<typename Real>
Vector3<Real> operator -(const Vector3<Real> &l, const Vector3<Real> &r)
{
return l.v - r.v;
}
// inline
template<typename Real>
Vector3<Real> &Vector3<Real>::operator +=(const Vector3<Real> &r)
{
v[0] += r.v[0];
v[1] += r.v[1];
v[2] += r.v[2];
return *this;
}
// inline
template<typename Real>
Vector3<Real> &Vector3<Real>::operator -=(const Vector3<Real> &r)
{
v[0] -= r.v[0];
v[1] -= r.v[1];
v[2] -= r.v[2];
return *this;
}
// inline
template<typename Real>
Vector3<Real> &Vector3<Real>::operator /=(Real r)
{
v[0] /= r;
v[1] /= r;
v[2] /= r;
return *this;
}
// inline
template<typename Real>
Vector3<Real> &Vector3<Real>::operator *=(Real r)
{
v[0] *= r;
v[1] *= r;
v[2] *= r;
return *this;
}
// inline
template<typename Real>
Real dot(Vector3<Real> const& l, Vector3<Real> const& r)
{
return l[0] * r[0] + l[1] * r[1] + l[2] * r[2];
}
// inline
template<typename Real>
Vector3<Real> cross(Vector3<Real> const& v0, Vector3<Real> const& v1)
{
Vector3<Real> result = Vector3<Real>::Zero;
result[0] = v0[1] * v1[2] - v0[2] * v1[1];
result[1] = v0[2] * v1[0] - v0[0] * v1[2];
result[2] = v0[0] * v1[1] - v0[1] * v1[0];
return result;
}
// inline
template<typename Real>
Vector3<Real> operator ^(Vector3<Real> const& v0, Vector3<Real> const& v1)
{
return cross(v0, v1);
}
template<typename Real>
bool operator ==(const Vector3_<Real> &l, const Vector3_<Real> &r)
{
return
l[0] == r[0] &&
l[1] == r[1] &&
l[2] == r[2];
}
template<typename Real>
bool operator !=(const Vector3_<Real> &l, const Vector3_<Real> &r)
{
return
l[0] != r[0] ||
l[1] != r[1] ||
l[2] != r[2];
}
template<typename Real>
bool operator !=(const Vector3<Real> &l, const Vector3<Real> &r) { return l.v != r.v; }
template<typename Real>
bool operator ==(const Vector3<Real> &l, const Vector3<Real> &r) { return l.v == r.v; }
template<typename Real>
bool operator<(const Vector3<Real> &l, const Vector3<Real> &r)
{
if (l[0] < r[0]) return true;
if (l[0] > r[0]) return false;
if (l[1] < r[1]) return true;
if (l[1] > r[1]) return false;
if (l[2] < r[2]) return true;
return false;
}
// inline
template<typename Real>
Real operator *(const Vector3<Real> &l, const Vector3<Real> &r)
{
return dot(l, r);
}
template<typename Real>
Vector3<Real> fract(const Vector3<Real> &v)
{
return {
fract(v[0]),
fract(v[1]),
fract(v[2])
};
}
template<typename Real>
Vector3<Real> trunc(const Vector3<Real> &v)
{
return {
trunc(v[0]),
trunc(v[1]),
trunc(v[2])
};
}
template<typename Real>
Real distance_relative(const Vector3<Real> &l, const Vector3<Real> &r)
{
return distance_squared(l, r);
}
} // namespace
} // namespace
} // namespace

28
tjp/core/math/Vector4.h Executable file
View File

@@ -0,0 +1,28 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#pragma once
#include "Real.h"
namespace tjp {
namespace core {
namespace math {
template<typename T>
struct Vector4;
typedef Vector4<double> Vector4d;
typedef Vector4<float> Vector4f;
typedef Vector4<Real> Vector4r;
typedef Vector4<int> Vector4i;
} // namespace
} // namespace
} // namespace

137
tjp/core/math/Vector4.hpp Executable file
View File

@@ -0,0 +1,137 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#pragma once
#include "Vector4.h"
#include "Vector3.h"
#include "Zero.h"
#include <tjp/core/containers/Tuple.h>
namespace tjp {
namespace core {
namespace math {
template<typename Real>
struct Vector4_ {
using V = Real[4];
V v;
Real &operator[](size_t i) { return v[i]; }
Real const &operator[](size_t i) const { return v[i]; };
} ;
template<typename T>
struct Vector4
{
using Real = T;
using V = Vector4_<Real>;
V v;
constexpr Vector4(int zero) :
v { static_cast<T>(zero), static_cast<T>(zero), static_cast<T>(zero) }
{}
constexpr Vector4() = default;
constexpr Vector4(const Vector4 &) = default;
constexpr Vector4(const V &rhs) : v (rhs) {}
constexpr Vector4(const std::initializer_list<Real> &v_)
{
auto i = 0;
for (auto &n: v_)
v[i++] = n;
}
constexpr Vector4& operator=(const Vector4 &) = default;
constexpr Vector4& operator=(const V &v_)
{
v = v_;
return *this;
}
constexpr Vector4(const Vector3_<T> &v3, Real w)
: v {v3[0], v3[1], v3[2], w}
{}
constexpr Vector4(Real x, Real y, Real z, Real w)
: v {x, y, z, w}
{}
operator V()
{
return { v[0], v[1], v[2], v[3] };
}
template<typename U>
Vector4<U> asType() const
{
return Vector4<U> { (U)v[0], (U)v[1], (U)v[2], (U)v[3] };
}
Tuple<Vector3<T>, T> as3p1() const
{
return {
Vector3<T> { v[0], v[1], v[2] },
v[3]
};
}
T &operator[](size_t i)
{
return v[i];
}
const T &operator[](size_t i) const
{
return v[i];
}
Vector3<T> xyz() const
{
return {v[0], v[1], v[2] };
}
Real w() const
{
return v[3];
}
// operator bool() const
// {
// return
// v[0] != 0 ||
// v[1] != 0 ||
// v[2] != 0 ||
// v[3] != 0;
// }
//
// bool operator!() const
// {
// return
// v[0] == 0 &&
// v[1] == 0 &&
// v[2] == 0 &&
// v[3] == 0;
// }
public:
static const Vector4 Zero;
} ;
template<typename Real>
const Vector4<Real> Vector4<Real>::Zero = {
zero<Real>(),
zero<Real>(),
zero<Real>(),
zero<Real>()
};
} // namespace
} // namespace
} // namespace

154
tjp/core/math/Vector4.inl Executable file
View File

@@ -0,0 +1,154 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#pragma once
#include "Vector4.hpp"
#include "Vector3.hpp"
#include "Real.inl"
namespace tjp::core::math {
template<typename Real>
bool operator ==(const Vector4_<Real> &l, const Vector4_<Real> &r)
{
return
l[0] == r[0] &&
l[1] == r[1] &&
l[2] == r[2] &&
l[3] == r[3];
}
template<typename Real>
bool operator !=(const Vector4_<Real> &l, const Vector4_<Real> &r)
{
return
l[0] != r[0] ||
l[1] != r[1] ||
l[2] != r[2] ||
l[3] != r[3];
}
template<typename T>
bool operator !=(const Vector4<T> &l, const Vector4<T> &r) { return l.v != r.v; }
template<typename T>
bool operator ==(const Vector4<T> &l, const Vector4<T> &r) { return l.v == r.v; }
template<typename Real>
void zero(Vector4<Real> &v)
{
v = Vector4<Real>(0,0,0,0);
}
//template<typename Real>
//Vector4<Real> Vector4_(const Vector3<Real> &l, const float a)
//{
// return { l[0], l[1], l[2], a };
//}
template<typename Real>
Vector4<Real> operator +(const Vector4<Real> &l, const Vector4<Real> &r)
{
return { l[0] + r[0], l[1] + r[1], l[2] + r[2], l[3] + r[3] };
}
// inline
template<typename Real>
Vector4<Real> operator -(const Vector4<Real> &l, const Vector4<Real> &r)
{
return { l[0] - r[0], l[1] - r[1], l[2] - r[2], l[3] + r[3] };
}
template<typename Real>
void operator -=(Vector4<Real> &l, const Vector4<Real> &r)
{
l[0] -= r[0];
l[1] -= r[1];
l[2] -= r[2];
l[3] -= r[3];
}
// inline
template<typename Real, typename U>
Vector4<Real> operator *(const Vector4<Real> &l, U r)
{
return Vector4<Real> {
l[0] * r,
l[1] * r,
l[2] * r,
l[3] * r
};
}
template<typename Real>
Real dot(const Vector4<Real> &l, const Vector4<Real> &r)
{
return
l[0] * r[0] +
l[1] * r[1] +
l[2] * r[2] +
l[3] * r[3]
;
}
template<typename Real, typename U>
Vector4<Real> operator *(U r, const Vector4<Real> &l)
{
return l * r;
}
template<typename Real, typename U>
Vector4<Real> operator /(U l, const Vector4<Real> &r)
{
return {
l/r[0],
l/r[1],
l/r[2],
l/r[3]
};
}
template<typename Real, typename U>
Vector4<Real> operator /(const Vector4<Real> &l, U r)
{
return {
l[0]/r,
l[1]/r,
l[2]/r,
l[3]/r
};
}
template<typename Real>
Vector4<Real> fract(const Vector4<Real> &v)
{
return {
fract(v[0]),
fract(v[1]),
fract(v[2]),
fract(v[3])
};
}
template<typename Real>
Vector4<Real> trunc(const Vector4<Real> &v)
{
return {
trunc(v[0]),
trunc(v[1]),
trunc(v[2]),
trunc(v[3])
};
}
} // namespace

33
tjp/core/math/Zero.h Executable file
View File

@@ -0,0 +1,33 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#pragma once
namespace tjp::core::math {
template<typename T>
void zero(T &t)
{
t = T{0};
}
template<typename T>
T zero()
{
T t;
zero(t);
return t;
}
template<typename T>
bool is_zero(const T &t)
{
return t == zero<T>();
}
} // namespace

View File

@@ -0,0 +1,50 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#include "BigDecimal+IO.h"
#include <tjp/core/io/bin/IO.h>
#include <tjp/core/io/json/in_sajson.h>
#include <tjp/core/io/json/out.h>
#include <tjp/core/testing/catch.hpp>
namespace tjp {
namespace core {
namespace math {
namespace test {
SCENARIO("big decimal io")
{
GIVEN("a number")
{
auto a = BigDecimal::fromSignificandExponent(10923905823095,-5);
WHEN("bin")
{
auto s = io::bin::serialize(a);
auto b = io::bin::deserialize<BigDecimal>(s);
REQUIRE(a == b);
}
WHEN("json")
{
auto s = io::json::serialize(a);
auto b = io::json::deserialize<BigDecimal>(s);
REQUIRE(a == b);
}
}
}
} // namespace
} // namespace
} // namespace
} // namespace

View File

@@ -0,0 +1,60 @@
//
// Math.cpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#include "BigDecimal+IO.h"
#include <tjp/core/string/to_string.hpp>
namespace tjp {
namespace core {
namespace math {
std::ostream &operator <<(std::ostream &o, const BigDecimal &m)
{
std::string num_ = core::to_string(m.significand);
std::string_view num = num_;
auto leading = (s32)num.length() + m.exp;
if (leading <= 0)
{
o << "0.";
while (leading++ < 0)
o << "0";
o << num;
return o;
}
else
{
s32 lastNonZero = num.size();
for (; lastNonZero>0; --lastNonZero)
if (num[lastNonZero-1] != '0')
break;
auto left = std::min(lastNonZero, leading);
auto right = lastNonZero - left;
auto zeros = leading - lastNonZero;
o << num.substr(0, left);
if (right > 0)
o << ".";
o << num.substr(left, right);
while (zeros-- > 0)
o << "0";
}
return o;
}
} // namespace
} // namespace
} // namespace

View File

@@ -0,0 +1,41 @@
//
// MathIO.h
// common
//
// Created by Timothy Prepscius on 8/4/18.
// Copyright © 2018 Timothy Prepscius. All rights reserved.
//
#pragma once
#include "BigDecimal.hpp"
#include "BigInt+IO.h"
#include <iosfwd>
namespace tjp {
namespace core {
namespace math {
std::ostream &operator <<(std::ostream &o, const BigDecimal &m);
template<typename IO>
void io_(IO &io, BigDecimal &v)
{
io.object("significand", v.significand, "exp", v.exp);
#ifdef DEBUG_BIGDECIMAL
generateDebug(v);
#endif
}
template<typename IO>
void io_bin(IO &io, BigDecimal &v) { return io_(io, v); }
template<typename IO>
void io_json(IO &io, BigDecimal &v) { return io_(io, v); }
} // namespace
} // namespace
} // namespace

View File

@@ -0,0 +1,194 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#include "BigDecimal.h"
#include "BigDecimal+IO.h"
#include "Algorithm.hpp"
#include <tjp/core/string/to_string.hpp>
#include <tjp/core/string/starts_with.hpp>
#include <tjp/core/testing/catch.hpp>
namespace tjp {
namespace core {
namespace math {
namespace test {
SCENARIO("big decimal")
{
auto a3_5 = BigDecimal::fromIntegerDecimalExponent(3,5);
auto a3_5124124 = BigDecimal::fromIntegerDecimalExponent(3,5124124);
auto a0_005124124 = BigDecimal::fromIntegerDecimalExponent(5,124124,-3);
auto a0_006124124 = BigDecimal::fromIntegerDecimalExponent(6,124124,-3);
auto a30000 = BigDecimal::fromIntegerDecimalExponent(3,0,4);
auto a30001 = BigDecimal::fromIntegerDecimalExponent(30001,0);
auto a30000_2 = BigDecimal::fromIntegerDecimalExponent(30000,2);
GIVEN("a number")
{
REQUIRE(core::to_string(a3_5) == "3.5");
REQUIRE(core::to_string(a3_5124124) == "3.5124124");
REQUIRE(core::to_string(a0_005124124) == "0.005124124");
REQUIRE(core::to_string(a0_006124124) == "0.006124124");
REQUIRE(core::to_string(a30000) == "30000");
REQUIRE(core::to_string(a30001) == "30001");
REQUIRE(core::to_string(a30000_2) == "30000.2");
REQUIRE(core::to_string(a30000/1) == "30000");
}
GIVEN("a number")
{
REQUIRE(a3_5.getInteger() == 3);
REQUIRE(a3_5124124.getInteger() == 3);
REQUIRE(a0_005124124.getInteger() == 0);
REQUIRE(a30000.getInteger() == 30000);
REQUIRE(a30000_2.getInteger() == 30000);
auto a_5 = BigDecimal::fromIntegerDecimalExponent(0,5);
auto a_5124124 = BigDecimal::fromIntegerDecimalExponent(0,5124124);
auto a_005124124 = BigDecimal::fromIntegerDecimalExponent(0,5124124, -2);
auto a_0 = BigDecimal();
auto a_2 = BigDecimal::fromIntegerDecimalExponent(0,2);
REQUIRE(a3_5.getDecimal() == a_5);
REQUIRE(a3_5124124.getDecimal() == a_5124124);
REQUIRE(a0_005124124.getDecimal() == a_005124124);
REQUIRE(a30000.getDecimal() == a_0);
REQUIRE(a30000_2.getDecimal() == a_2);
}
GIVEN("reals")
{
auto b30001 = BigDecimal(30001);
auto b3_5 = BigDecimal(3.5);
auto b3_5124124 = BigDecimal(3.5124124);
auto b0_005124124 = BigDecimal(0.005124124);
auto b0_006124124 = BigDecimal(0.006124124);
auto b30001_s = core::to_string(b30001);
auto sigma = BigDecimal(0.0001);
REQUIRE(distance(a3_5, b3_5) < sigma);
REQUIRE(distance(a3_5124124, b3_5124124) < sigma);
REQUIRE(distance(a0_005124124, b0_005124124) < sigma);
REQUIRE(distance(a0_006124124, b0_006124124) < sigma);
REQUIRE(distance(a30001, b30001) < sigma);
}
GIVEN("numbers")
{
auto b3_5 = BigDecimal::fromIntegerDecimalExponent(3,5);
REQUIRE (a3_5 < a3_5124124);
REQUIRE (a3_5 <= a3_5124124);
REQUIRE (a3_5124124 > a3_5);
REQUIRE (a0_005124124 < a0_006124124);
REQUIRE (a0_005124124 <= a0_006124124);
REQUIRE (a0_006124124 > a0_005124124);
REQUIRE (a3_5 <= b3_5);
}
GIVEN("a number")
{
auto a = BigDecimal::fromIntegerDecimalExponent(3,5);
auto b = BigDecimal::fromIntegerDecimalExponent(7,3);
auto a_ = core::to_string(a);
auto b_ = core::to_string(b);
WHEN("add")
{
auto c = a + b;
auto c_ = core::to_string(c);
REQUIRE(c == BigDecimal::fromIntegerDecimalExponent(10,8));
}
WHEN("multiply")
{
auto c = a / b;
auto c_ = core::to_string(c);
auto c_s = std::string("0.4794");
REQUIRE(core::starts_with(c_, c_s));
}
WHEN("divide")
{
auto c = a * b;
auto c_ = core::to_string(c);
REQUIRE(c == BigDecimal::fromIntegerDecimalExponent(25, 55));
}
WHEN("sqrt")
{
auto a = BigDecimal::fromIntegerDecimalExponent(20,25);
auto b = sqrt(a);
auto a_ = core::to_string(a);
auto b_ = core::to_string(b);
REQUIRE(b == BigDecimal::fromIntegerDecimalExponent(4,5));
auto c = BigDecimal::fromIntegerDecimalExponent(300000,0,-5);
auto s = std::sqrt(3.0);
auto d_s = std::string("1.73205");
auto d = sqrt(c);
auto d_ = core::to_string(d);
REQUIRE(core::starts_with(d_, d_s));
}
}
GIVEN("a number to reduce")
{
auto a = BigDecimal::fromIntegerDecimalExponent(100,0,0);
auto b = BigDecimal::fromIntegerDecimalExponent(1,0,2);
REQUIRE(a == b);
reduce(a);
auto a_ = core::to_string(a);
auto b_ = core::to_string(b);
REQUIRE(a == b);
REQUIRE(a.significand == 1);
REQUIRE(a.exp == b.exp);
REQUIRE(a.significand == b.significand);
}
GIVEN("a number to reduce < 1")
{
auto a = BigDecimal::fromIntegerDecimalExponent(100,0,-4);
auto b = BigDecimal::fromIntegerDecimalExponent(1,0,-2);
REQUIRE(a == b);
reduce(a);
auto a_ = core::to_string(a);
auto b_ = core::to_string(b);
REQUIRE(a == b);
REQUIRE(a.significand == 1);
REQUIRE(a.exp == b.exp);
REQUIRE(a.significand == b.significand);
}
}
} // namespace
} // namespace
} // namespace
} // namespace

View File

@@ -0,0 +1,353 @@
//
// Math.cpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#include "BigDecimal.hpp"
#include "BigDecimal+IO.h"
#include <tjp/core/string/to_string.hpp>
#include <tjp/core/assert/debug_assert.h>
#include <tjp/core/debug/Debug.h>
#include "Real.inl"
#include "BigInt+Imp.hpp"
namespace tjp {
namespace core {
namespace math {
BigDecimal BigDecimal::Zero(0);
// -------
static BigInt::Imp::V ten(10);
double sqrt_10 = sqrt(10.0);
#ifdef _DEBUG
#define DEBUG_BIGDECIMAL
#endif
#ifdef DEBUG_BIGDECIMAL
void generateDebug(BigDecimal &d)
{
d.debug = core::to_string(d);
}
#endif
void reduce(BigDecimal &v)
{
while (!is_zero(v.significand) && is_zero(v.significand % 10))
{
v.significand /= 10;
v.exp++;
}
generateDebug(v);
}
size_t numDigits(const BigInt &v_)
{
if (is_zero(v_))
return 0;
auto v = v_;
size_t length = 0;
while (!is_zero(v))
{
v /= 10;
length++;
}
return length;
}
// -------
BigDecimal::BigDecimal() :
exp(0)
{
generateDebug(*this);
}
BigDecimal::BigDecimal(const math::Real &real) :
BigDecimal(real, 16)
{}
BigDecimal::BigDecimal(const math::Real &real, s32 precision)
{
long double d = real;
d *= std::pow(10.0, precision);
auto d_ = std::to_string(d);
std::string_view v = d_;
debug_assert(v.find('E') == -1);
v = v.substr(0, v.find('.'));
long i = v.size()-1;
for (; i>=0; --i)
{
if (v[i] != '0')
break;
}
if (i < 0 || (v[i] == '-'))
{
exp = 0;
generateDebug(*this);
return;
}
precision -= (v.size()-1 - i);
significand = BigInt(v.substr(0, i+1));
exp = -precision;
generateDebug(*this);
}
BigDecimal::BigDecimal(BigInt &&significand_, s32 exp_) :
significand(significand_),
exp(exp_)
{
generateDebug(*this);
}
BigDecimal::BigDecimal(const BigInt &integer, const BigInt &decimal, s32 exp_)
{
auto precision = (s32)numDigits(decimal);
auto m = boost::multiprecision::pow(ten, precision);
significand = BigInt::Imp { m * integer.imp->v + decimal.imp->v };
exp = exp_ - precision;
generateDebug(*this);
}
// ------------------
BigDecimal BigDecimal::fromInteger(BigInt &&significand_)
{
return fromSignificandExponent(std::move(significand_), 0);
}
BigDecimal BigDecimal::fromReal(math::Real real, int precision)
{
return BigDecimal(real, precision);
}
BigDecimal BigDecimal::fromIntegerDecimalExponent(const BigInt &integer, const BigInt &decimal, s32 exp)
{
return BigDecimal(integer, decimal, exp);
}
BigDecimal BigDecimal::fromSignificandExponent(BigInt &&significand, s32 exp)
{
return BigDecimal(std::move(significand), exp);
}
BigInt BigDecimal::getInteger() const
{
auto m = boost::multiprecision::pow(ten, std::abs(exp));
if (exp > 0)
return BigInt::Imp { m * significand.imp->v };
else
return BigInt::Imp { significand.imp->v / m };
}
BigDecimal BigDecimal::getDecimal() const
{
if (exp >= 0)
return BigDecimal();
auto m = boost::multiprecision::pow(ten, -exp);
return BigDecimal(BigInt::Imp { significand.imp->v % m }, exp);
}
// ------------------
template<>
BigDecimal sqrt(const BigDecimal &v)
{
// a = sqrt(10^d * v)
// a = sqrt(10^d) * sqrt(v)
// a = sqrt(10^(d/2)) * sqrt(v)
auto addedPrecision = 6;
auto addedOffset = v.exp % 2 ? 1 : 0;
auto offset = addedPrecision + addedOffset;
auto m = boost::multiprecision::pow(ten, offset);
auto vp = BigInt::Imp::V(v.significand.imp->v * m);
auto vpr = boost::multiprecision::sqrt(vp);
auto result = BigDecimal::fromSignificandExponent(
BigInt::Imp { std::move(vpr) },
(v.exp - offset) / 2
);
/*
auto v_ = core::to_string(v);
auto vp_ = core::to_string(vp);
auto vpr_ = core::to_string(vpr);
auto result_ = core::to_string(result);
*/
return result;
}
template<>
BigDecimal abs(const BigDecimal &v)
{
return BigDecimal::fromSignificandExponent( abs(v.significand), v.exp );
}
BigDecimal operator*(const BigDecimal &lhs, const BigDecimal &rhs)
{
// 1.5 = 15, 1
// 13 = 13, 0
// 19.5 = 195, 1
return BigDecimal::fromSignificandExponent(lhs.significand * rhs.significand, lhs.exp + rhs.exp);
}
BigDecimal operator/(const BigDecimal &lhs, const BigDecimal &rhs)
{
static auto precision = 6;
static auto m = boost::multiprecision::pow(ten, precision);
return BigDecimal::fromSignificandExponent(
BigInt::Imp{ m * lhs.significand.imp->v / rhs.significand.imp->v },
lhs.exp - rhs.exp - precision
);
}
BigDecimal operator/(const BigDecimal &lhs, size_t rhs)
{
return lhs / BigDecimal(rhs);
}
BigDecimal operator+(const BigDecimal &lhs, const BigDecimal &rhs)
{
if (lhs.exp > rhs.exp)
return rhs + lhs;
// 1.5 = 15, 1
// 10 = 10, 0
auto m = boost::multiprecision::pow(ten, rhs.exp - lhs.exp);
auto v = m * rhs.significand.imp->v;
auto s = v + lhs.significand.imp->v;
auto result = BigDecimal::fromSignificandExponent(BigInt::Imp { s }, lhs.exp);
auto lhs_ = core::to_string(lhs);
auto rhs_ = core::to_string(rhs);
auto lhs_s = core::to_string(lhs.significand);
auto rhs_s = core::to_string(rhs.significand);
auto m_ = core::to_string(BigInt(BigInt::Imp { m }));
auto v_ = core::to_string(BigInt(BigInt::Imp { v }));
auto s_ = core::to_string(BigInt(BigInt::Imp { s }));
auto result_ = core::to_string(result);
return result;
}
BigDecimal operator-(const BigDecimal &lhs, const BigDecimal &rhs)
{
return lhs + (-rhs);
}
BigDecimal operator-(const BigDecimal &v)
{
return BigDecimal::fromSignificandExponent(BigInt::Imp { -v.significand.imp->v }, v.exp);
}
void normalize(BigDecimal &lhs, BigDecimal &rhs)
{
if (lhs.exp == rhs.exp)
return;
auto *big = (lhs.exp < rhs.exp) ? &rhs : &lhs;
auto *small = (lhs.exp < rhs.exp) ? &lhs : &rhs;
auto d = big->exp - small->exp;
auto m = boost::multiprecision::pow(ten, d);
big->significand.imp->v *= m;
big->exp -= d;
generateDebug(lhs);
generateDebug(rhs);
}
bool operator==(const BigDecimal &lhs, const BigDecimal &rhs)
{
// 10 = 1, 1
// 10 = 10, 0
if (lhs.exp == rhs.exp)
return lhs.significand == rhs.significand;
auto lhs_ = lhs;
auto rhs_ = rhs;
normalize(lhs_, rhs_);
return (lhs_.significand == rhs_.significand);
}
bool operator<(const BigDecimal &lhs, const BigDecimal &rhs)
{
if (lhs.exp == rhs.exp)
return lhs.significand < rhs.significand;
auto lhs_ = lhs;
auto rhs_ = rhs;
normalize(lhs_, rhs_);
return lhs_.significand < rhs_.significand;
}
bool operator<=(const BigDecimal &lhs, const BigDecimal &rhs)
{
if (lhs.exp == rhs.exp)
return lhs.significand <= rhs.significand;
auto lhs_ = lhs;
auto rhs_ = rhs;
normalize(lhs_, rhs_);
return lhs_.significand <= rhs_.significand;
}
bool operator!=(const BigDecimal &lhs, const BigDecimal &rhs)
{
return !(lhs == rhs);
}
bool operator>(const BigDecimal &lhs, const BigDecimal &rhs)
{
return rhs < lhs;
}
bool operator>=(const BigDecimal &lhs, const BigDecimal &rhs)
{
return rhs <= lhs;
}
} // namespace
} // namespace
} // namespace

View File

@@ -0,0 +1,20 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#pragma once
namespace tjp {
namespace core {
namespace math {
struct BigDecimal;
} // namespace
} // namespace
} // namespace

View File

@@ -0,0 +1,82 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#pragma once
#include "BigInt.h"
#include "Real.h"
#define DEBUG_BIGDECIMAL
namespace tjp {
namespace core {
namespace math {
struct BigDecimal {
BigInt significand;
s32 exp = 0;
#ifdef DEBUG_BIGDECIMAL
std::string debug;
#endif
BigDecimal();
explicit BigDecimal(const math::Real &real);
explicit BigDecimal(const math::Real &real, s32 precision);
static BigDecimal fromInteger(BigInt &&integer);
static BigDecimal fromIntegerDecimalExponent(const BigInt &integer, const BigInt &decimal, s32 exp=0);
static BigDecimal fromReal(math::Real real, s32 precision=16);
static BigDecimal fromSignificandExponent(BigInt &&significand, s32 exp);
BigInt getInteger() const;
BigDecimal getDecimal() const;
static BigDecimal Zero;
protected:
BigDecimal(BigInt &&integer, s32 exp);
BigDecimal(const BigInt &integer, const BigInt &decimal, s32 exp);
};
#ifdef DEBUG_BIGDECIMAL
void generateDebug(BigDecimal &v);
#else
inline
void generateDebug(BigDecimal &) {}
#endif
template<>
BigDecimal sqrt(const BigDecimal &);
template<>
BigDecimal abs(const BigDecimal &);
BigDecimal operator-(const BigDecimal &lhs);
BigDecimal operator-(const BigDecimal &lhs, const BigDecimal &rhs);
BigDecimal operator+(const BigDecimal &lhs, const BigDecimal &rhs);
BigDecimal operator*(const BigDecimal &lhs, const BigDecimal &rhs);
BigDecimal operator/(const BigDecimal &lhs, const BigDecimal &rhs);
BigDecimal operator/(const BigDecimal &lhs, size_t rhs);
bool operator==(const BigDecimal &lhs, const BigDecimal &rhs);
bool operator!=(const BigDecimal &lhs, const BigDecimal &rhs);
bool operator<(const BigDecimal &lhs, const BigDecimal &rhs);
bool operator<=(const BigDecimal &lhs, const BigDecimal &rhs);
bool operator>(const BigDecimal &lhs, const BigDecimal &rhs);
bool operator>=(const BigDecimal &lhs, const BigDecimal &rhs);
void reduce(BigDecimal &);
void normalize(BigDecimal &lhs, BigDecimal &rhs);
} // namespace
} // namespace
} // namespace

View File

@@ -0,0 +1,50 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#include "BigInt+IO.h"
#include <tjp/core/io/bin/IO.h>
#include <tjp/core/io/json/in_sajson.h>
#include <tjp/core/io/json/out.h>
#include <tjp/core/testing/catch.hpp>
namespace tjp {
namespace core {
namespace math {
namespace test {
SCENARIO("big int io")
{
GIVEN("a number")
{
BigInt a = 10923905823095;
WHEN("bin")
{
auto s = io::bin::serialize(a);
auto b = io::bin::deserialize<BigInt>(s);
REQUIRE(a == b);
}
WHEN("json")
{
auto s = io::json::serialize(a);
auto b = io::json::deserialize<BigInt>(s);
REQUIRE(a == b);
}
}
}
} // namespace
} // namespace
} // namespace
} // namespace

View File

@@ -0,0 +1,41 @@
//
// MathIO.h
// common
//
// Created by Timothy Prepscius on 8/4/18.
// Copyright © 2018 Timothy Prepscius. All rights reserved.
//
#include "BigInt+IO.h"
#include "BigInt+Imp.hpp"
#include <tjp/core/assert/debug_assert.h>
namespace tjp {
namespace core {
namespace math {
void write(const BigInt &v, Vector<char> &bytes)
{
auto *mp = &v.imp->v.backend().data();
auto binSize = mp_ubin_size(mp);
bytes.resize(binSize);
size_t written;
auto error = mp_to_ubin(mp, (unsigned char *)bytes.data(), bytes.size(), &written);
debug_assert(written == binSize);
debug_assert(error == 0);
}
void read(BigInt &v, const Vector<char> &bytes)
{
auto *mp = &v.imp->v.backend().data();
auto error = mp_from_ubin(mp, (unsigned char *)bytes.data(), bytes.size());
debug_assert(error == 0);
}
} // namespace
} // namespace
} // namespace

View File

@@ -0,0 +1,54 @@
//
// MathIO.h
// common
//
// Created by Timothy Prepscius on 8/4/18.
// Copyright © 2018 Timothy Prepscius. All rights reserved.
//
#pragma once
#include "BigInt.h"
#include <tjp/core/containers/Vector.h>
namespace tjp {
namespace core {
namespace math {
void write(const BigInt &v, Vector<char> &bytes);
void read(BigInt &, const Vector<char> &bytes);
template<typename IO>
void io_w(IO &io, const tjp::core::math::BigInt &v)
{
std::vector<char> bytes;
write(v, bytes);
io.any(bytes);
}
template<typename IO>
void io_r(IO &io, tjp::core::math::BigInt &v)
{
std::vector<char> bytes;
io.any(bytes);
read(v, bytes);
}
template<typename IO>
void io_bin_w(IO &io, const tjp::core::math::BigInt &v) { return io_w(io, v); }
template<typename IO>
void io_json_w(IO &io, const tjp::core::math::BigInt &v) { return io_w(io, v); }
template<typename IO>
void io_bin_r(IO &io, tjp::core::math::BigInt &v) { return io_r(io, v); }
template<typename IO>
void io_json_r(IO &io, tjp::core::math::BigInt &v) { return io_r(io, v); }
} // namespace
} // namespace
} // namespace

View File

@@ -0,0 +1,29 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#pragma once
#include <tjp/core/system/DisableWarningsPush.h>
#include <boost/multiprecision/tommath.hpp>
#include <tjp/core/system/DisableWarningsPop.h>
#include "Real.h"
namespace tjp {
namespace core {
namespace math {
struct BigInt::Imp {
typedef boost::multiprecision::tom_int V;
V v;
} ;
} // namespace
} // namespace
} // namespace

View File

@@ -0,0 +1,63 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#include "BigInt.h"
#include <catch2/catch.hpp>
namespace tjp {
namespace core {
namespace math {
namespace test {
SCENARIO("big int")
{
GIVEN("a number")
{
BigInt a = 1;
WHEN("add")
{
a += 2;
REQUIRE(a == 3);
}
WHEN("sqrt")
{
a = 17;
auto b = sqrt(a);
REQUIRE(b == 4);
}
WHEN("and")
{
a = 32767;
auto b = a & 0xFF;
REQUIRE(b == 0xFF);
}
WHEN("shift")
{
a = 0xDEDEFEFE;
auto b = a >> 16;
REQUIRE(b == 0xDEDE);
}
}
}
} // namespace
} // namespace
} // namespace
} // namespace

235
tjp/core/math/_delete/BigInt.cpp Executable file
View File

@@ -0,0 +1,235 @@
//
// Math.cpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#include "BigInt.hpp"
#include "BigInt+Imp.hpp"
#include <tjp/core/algorithm/remove_const_of_var.hpp>
namespace tjp {
namespace core {
namespace math {
BigInt BigInt::Zero(0);
BigInt::Imp::V &m(BigInt &v)
{
return v.imp->v;
}
const BigInt::Imp::V &m(const BigInt &v)
{
return v.imp->v;
}
BigInt::Imp::V &c(BigInt &v)
{
if (v.imp == nullptr)
v.imp = core::strong<BigInt::Imp>();
return m(v);
}
BigInt::Imp::V &c(const BigInt &v)
{
return c(remove_const_of_var(v));
}
BigInt::BigInt()
{
c(*this);
}
BigInt::BigInt(s64 v)
{
c(*this) = v;
}
BigInt::BigInt(Imp &&imp_) :
imp(core::strong<BigInt::Imp>(std::move(imp_)))
{
}
BigInt::BigInt(const StringView &s)
{
c(*this) = Imp::V(s);
}
BigInt::BigInt(const BigInt &v)
{
c(*this) = m(v);
}
s64 BigInt::toInteger() const
{
return c(*this).convert_to<s64>();
}
template<>
BigInt sqrt(const BigInt &b)
{
BigInt result;
c(result) = boost::multiprecision::sqrt(m(b));
return result;
}
template<>
BigInt abs(const BigInt &b)
{
BigInt result;
c(result) = boost::multiprecision::abs(m(b));
return result;
}
template<>
BigInt pow2(const BigInt &b)
{
BigInt result;
c(result) = m(b) * m(b);
return result;
}
bool is_zero(const BigInt &lhs)
{
return m(lhs).is_zero();
}
BigInt operator %(const BigInt &lhs, int rhs)
{
BigInt r;
c(r) = m(lhs) % rhs;
return r;
}
BigInt operator %(const BigInt &lhs, const BigInt &rhs)
{
BigInt r;
c(r) = m(lhs) % m(rhs);
return r;
}
BigInt operator /(const BigInt &lhs, int rhs)
{
BigInt r;
c(r) = m(lhs) / rhs;
return r;
}
BigInt operator /(const BigInt &lhs, size_t rhs)
{
BigInt r;
c(r) = m(lhs) / rhs;
return r;
}
BigInt &operator /=(BigInt &lhs, int rhs)
{
m(lhs) = m(lhs) / rhs;
return lhs;
}
BigInt operator *(int lhs, const BigInt &rhs)
{
BigInt r;
c(r) = lhs * m(rhs);
return r;
}
BigInt operator *(const BigInt &rhs, int lhs)
{
return lhs * rhs;
}
BigInt operator +(const BigInt &lhs, const BigInt &rhs)
{
BigInt r;
c(r) = m(lhs) + m(rhs);
return r;
}
BigInt operator -(const BigInt &lhs, const BigInt &rhs)
{
BigInt r;
c(r) = m(lhs) - m(rhs);
return r;
}
BigInt operator *(const BigInt &lhs, const BigInt &rhs)
{
BigInt r;
c(r) = m(lhs) * m(rhs);
return r;
}
BigInt operator /(const BigInt &lhs, const BigInt &rhs)
{
BigInt r;
c(r) = m(lhs) / m(rhs);
return r;
}
math::Real toReal(const BigInt &lhs)
{
return m(lhs).convert_to<math::Real>();
}
bool operator ==(const BigInt &lhs, const BigInt &rhs)
{
return m(lhs) == m(rhs);
}
bool operator <(const BigInt &lhs, const BigInt &rhs)
{
return m(lhs) < m(rhs);
}
bool operator <=(const BigInt &lhs, const BigInt &rhs)
{
return m(lhs) <= m(rhs);
}
bool operator >(const BigInt &lhs, const BigInt &rhs)
{
return m(lhs) > m(rhs);
}
bool operator >=(const BigInt &lhs, const BigInt &rhs)
{
return m(lhs) >= m(rhs);
}
std::ostream &operator<<(std::ostream &o, const math::BigInt &v)
{
return o << m(v);
}
BigInt distance_squared(const BigInt &lhs, const BigInt &rhs)
{
return pow2(rhs-lhs);
}
BigInt distance_relative(const BigInt &lhs, const BigInt &rhs)
{
return distance(lhs,rhs);
}
BigInt distance(const BigInt &lhs, const BigInt &rhs)
{
return rhs > lhs ? (rhs-lhs) : (lhs-rhs);
}
} // namespace
} // namespace
} // namespace

81
tjp/core/math/_delete/BigInt.h Executable file
View File

@@ -0,0 +1,81 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#pragma once
#include "Real.h"
#include <tjp/core/ptr/Ptr.hpp>
#include <tjp/core/string/String.h>
#include <tjp/core/string/StringView.h>
#include <iosfwd>
namespace tjp {
namespace core {
namespace math {
struct BigInt {
struct Imp;
core::StrongPtr<Imp> imp;
explicit BigInt(const StringView &v);
explicit BigInt(s64 i);
BigInt(Imp &&imp);
BigInt();
BigInt(const BigInt &m);
static BigInt Zero;
s64 toInteger() const;
};
template<>
BigInt sqrt(const BigInt &);
template<>
BigInt abs(const BigInt &);
bool is_zero(const BigInt &lhs);
BigInt operator %(const BigInt &lhs, int rhs);
BigInt operator %(const BigInt &lhs, const BigInt &rhs);
BigInt operator /(const BigInt &lhs, int rhs);
BigInt operator *(const BigInt &lhs, int rhs);
BigInt &operator /=(BigInt &lhs, int rhs);
BigInt operator /(const BigInt &lhs, size_t rhs);
BigInt operator *(int lhs, const BigInt &rhs);
BigInt operator +(const BigInt &lhs, const BigInt &rhs);
BigInt operator -(const BigInt &lhs, const BigInt &rhs);
BigInt operator *(const BigInt &lhs, const BigInt &rhs);
BigInt operator /(const BigInt &lhs, const BigInt &rhs);
math::Real toReal(const BigInt &lhs);
bool operator ==(const BigInt &lhs, const BigInt &rhs);
bool operator <(const BigInt &lhs, const BigInt &rhs);
bool operator <=(const BigInt &lhs, const BigInt &rhs);
bool operator >(const BigInt &lhs, const BigInt &rhs);
bool operator >=(const BigInt &lhs, const BigInt &rhs);
std::ostream &operator<<(std::ostream &o, const math::BigInt &v);
BigInt distance_squared(const BigInt &lhs, const BigInt &rhs);
BigInt distance_relative(const BigInt &lhs, const BigInt &rhs);
BigInt distance(const BigInt &lhs, const BigInt &rhs);
} // namespace
//std::string to_string(const math::BigInt &t);
} // namespace
} // namespace

View File

@@ -0,0 +1,11 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#pragma once
#include "BigInt.h"

View File

@@ -0,0 +1,79 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#include <tjp/core/math/Algorithm+Segment.hpp>
#include <tjp/core/testing/catch.hpp>
namespace tjp {
namespace core {
namespace math {
namespace test {
SCENARIO("math_segment")
{
GIVEN("a segment")
{
Segment1<int> a = { 10, 15 };
Segment1<int> b = {4,9};
REQUIRE(!intersects(b, a));
REQUIRE(!intersects(a, b));
REQUIRE(!contains(b, a));
REQUIRE(!contains(a, b));
REQUIRE(intersects(b, a, 1));
REQUIRE(intersects(a, b, 1));
Segment1<int> c = {9,11};
REQUIRE(intersects(c, a));
REQUIRE(intersects(a, c));
REQUIRE(!contains(c, a));
REQUIRE(!contains(a, c));
REQUIRE(intersects(c, a, 1));
REQUIRE(intersects(a, c, 1));
Segment1<int> d = {11,11};
REQUIRE(intersects(d, a));
REQUIRE(intersects(a, d));
REQUIRE(!contains(d, a));
REQUIRE(contains(a, d));
REQUIRE(intersects(d, a, 1));
REQUIRE(intersects(a, d, 1));
Segment1<int> e = {11,12};
REQUIRE(intersects(e, a));
REQUIRE(intersects(a, e));
REQUIRE(!contains(e, a));
REQUIRE(contains(a, e));
Segment1<int> f = {12,16};
REQUIRE(intersects(f, a));
REQUIRE(intersects(a, f));
Segment1<int> g = {16,19};
REQUIRE(!intersects(g, a));
REQUIRE(!intersects(a, g));
REQUIRE(intersects(g, a, 1));
REQUIRE(intersects(a, g, 1));
Segment1<int> h = {4,19};
REQUIRE(intersects(h, a));
REQUIRE(intersects(a, h));
REQUIRE(contains(h, a));
REQUIRE(!contains(a, h));
REQUIRE(intersects(h, a, 1));
REQUIRE(intersects(a, h, 1));
}
}
} // namespace
} // namespace
} // namespace
} // namespace

View File

@@ -0,0 +1,19 @@
//
// Math.cpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#include <tjp/core/math/Algorithm.hpp>
#include <vector>
#include <tjp/core/math/Vector2.inl>
using namespace tjp::core::math;
void test_math_algorithm ()
{
Vector2f a, b;
auto c = mul(a, b);
}

View File

@@ -0,0 +1,133 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#include <tjp/core/math/FloatPack.inl>
#include <tjp/core/math/Distance.inl>
#include <tjp/core/random/Random.h>
#include <tjp/core/testing/catch.hpp>
namespace tjp::core::math {
namespace {
const auto precision = 0.0000000000000000001;
//template<typename R>
//bool close(R l, R r)
//{
// return std::abs(r - l) < precision;
//}
bool close(Vector4f l, Vector4f r, r32 p)
{
for (auto i=0; i<4; ++i)
if (std::abs(l[i] - r[i]) > p)
return false;
return true;
}
bool close(Vector3f l, Vector3f r, r32 p)
{
for (auto i=0; i<3; ++i)
if (std::abs(l[i] - r[i]) > p)
return false;
return true;
}
bool close(Vector2f l, Vector2f r, r32 p)
{
for (auto i=0; i<2; ++i)
if (std::abs(l[i] - r[i]) > p)
return false;
return true;
}
SCENARIO("floatpack")
{
// GIVEN("a number")
// {
// //0.0000000000000000001
// float a = 0.2412541239199123125;
//
// WHEN("enc-dec-vec4")
// {
// auto v = toVec4f(a);
// auto a_ = toFloat(v);
//
// REQUIRE(close(a, a_));
// }
//
// WHEN("enc-dec-vec2")
// {
// auto v = toVec2f(a);
// auto a_ = toFloat(v);
//
// REQUIRE(close(a, a_));
// }
//
// WHEN("enc-dec-vec3")
// {
// auto v = toVec3f(a);
// auto a_ = toFloat(v);
//
// REQUIRE(close(a, a_));
// }
// }
GIVEN("a vector")
{
for (auto i=0; i<10000; ++i)
{
auto a = StandardRandom.nextReal<float>();
auto b = StandardRandom.nextReal<float>();
auto c = StandardRandom.nextReal<float>();
auto d = StandardRandom.nextReal<float>();
// WHEN("vec4")
{
Vector4f v { a, b, c, d };
auto a_ = pack4u(v);
auto v_ = unpack4u(a_);
bool isClose = close(v, v_, 1/float_4_max);
REQUIRE(isClose);
}
// WHEN("vec3")
{
Vector3f v { a, b, c };
auto a_ = pack3u(v);
auto v_ = unpack3u(a_);
bool isClose = close(v, v_, 1/float_3_max);
REQUIRE(isClose);
}
// WHEN("vec2")
{
Vector2f v { a, b };
auto a_ = pack2u(v);
auto v_ = unpack2u(a_);
bool isClose = close(v, v_, 1/float_2_max);
REQUIRE(isClose);
}
}
}
}
} // namespace
} // namespace

24
tjp/core/math/clamp.hpp Executable file
View File

@@ -0,0 +1,24 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#pragma once
namespace tjp::core::math {
template<typename V, typename L, typename R>
inline V clamp(const V &v, const L &l, const R &r)
{
if (v < l)
return (V)l;
if (v > r)
return (V)r;
return v;
}
} // namespace

View File

@@ -0,0 +1,692 @@
//
// Wm5.cpp
// algorithm
//
// Created by Timothy Prepscius on 5/3/18.
// Copyright © 2018 Timothy Prepscius. All rights reserved.
//
#include "Wm5.h"
#define assertion(...)
namespace Wm5 {
template<> const float Math<float>::ZERO_TOLERANCE = 1e-06f;
template<> const double Math<double>::ZERO_TOLERANCE = 1e-08;
/************************************************************************/
//----------------------------------------------------------------------------
template <typename Real>
EigenDecomposition<Real>::EigenDecomposition (int size)
:
mMatrix(size, size)
{
assertion(size >= 2, "Invalid size in Eigendecomposition constructor\n");
mSize = size;
mDiagonal = new1<Real>(mSize);
mSubdiagonal = new1<Real>(mSize);
mIsRotation = false;
}
/*
//----------------------------------------------------------------------------
template <typename Real>
EigenDecomposition<Real>::EigenDecomposition (const Matrix2<Real>& mat)
:
mMatrix(2, 2, &mat[0][0])
{
mSize = 2;
mDiagonal = new1<Real>(mSize);
mSubdiagonal = new1<Real>(mSize);
mIsRotation = false;
}
//----------------------------------------------------------------------------
template <typename Real>
EigenDecomposition<Real>::EigenDecomposition (const Matrix3<Real>& mat)
:
mMatrix(3, 3, &mat[0][0])
{
mSize = 3;
mDiagonal = new1<Real>(mSize);
mSubdiagonal = new1<Real>(mSize);
mIsRotation = false;
}
*/
//----------------------------------------------------------------------------
template <typename Real>
EigenDecomposition<Real>::EigenDecomposition (const GMatrix<Real>& mat)
:
mMatrix(mat)
{
mSize = mat.GetRows();
assertion(mSize >= 2 && (mat.GetColumns() == mSize),
"Square matrix required in EigenDecomposition constructor\n");
mDiagonal = new1<Real>(mSize);
mSubdiagonal = new1<Real>(mSize);
mIsRotation = false;
}
//----------------------------------------------------------------------------
template <typename Real>
EigenDecomposition<Real>::~EigenDecomposition ()
{
delete1(mDiagonal);
delete1(mSubdiagonal);
}
//----------------------------------------------------------------------------
template <typename Real>
Real& EigenDecomposition<Real>::operator() (int row, int column)
{
return mMatrix[row][column];
}
//----------------------------------------------------------------------------
/*
template <typename Real>
EigenDecomposition<Real>& EigenDecomposition<Real>::operator= (
const Matrix2<Real>& mat)
{
mMatrix.SetMatrix(2, 2, &mat[0][0]);
mSize = 2;
delete1(mDiagonal);
delete1(mSubdiagonal);
mDiagonal = new1<Real>(mSize);
mSubdiagonal = new1<Real>(mSize);
return *this;
}
//----------------------------------------------------------------------------
template <typename Real>
EigenDecomposition<Real>& EigenDecomposition<Real>::operator= (
const Matrix3<Real>& mat)
{
mMatrix.SetMatrix(3, 3, &mat[0][0]);
mSize = 3;
delete1(mDiagonal);
delete1(mSubdiagonal);
mDiagonal = new1<Real>(mSize);
mSubdiagonal = new1<Real>(mSize);
return *this;
}
*/
//----------------------------------------------------------------------------
template <typename Real>
EigenDecomposition<Real>& EigenDecomposition<Real>::operator= (
const GMatrix<Real>& mat)
{
mMatrix = mat;
return *this;
}
//----------------------------------------------------------------------------
template <typename Real>
void EigenDecomposition<Real>::Solve (bool increasingSort)
{
if (mSize == 2)
{
Tridiagonal2();
}
else if (mSize == 3)
{
Tridiagonal3();
}
else
{
TridiagonalN();
}
QLAlgorithm();
if (increasingSort)
{
IncreasingSort();
}
else
{
DecreasingSort();
}
GuaranteeRotation();
}
//----------------------------------------------------------------------------
template <typename Real>
Real EigenDecomposition<Real>::GetEigenvalue (int i) const
{
assertion(0 <= i && i < mSize, "Invalid index in GetEigenvalue\n");
return mDiagonal[i];
}
//----------------------------------------------------------------------------
template <typename Real>
const Real* EigenDecomposition<Real>::GetEigenvalues () const
{
return mDiagonal;
}
//----------------------------------------------------------------------------
/*
template <typename Real>
Vector2<Real> EigenDecomposition<Real>::GetEigenvector2 (int i) const
{
assertion(mSize == 2, "Mismatched dimension in GetEigenvector2\n");
if (mSize == 2)
{
Vector2<Real> eigenvector;
for (int row = 0; row < mSize; ++row)
{
eigenvector[row] = mMatrix[row][i];
}
return eigenvector;
}
return Vector2<Real>::ZERO;
}
//----------------------------------------------------------------------------
template <typename Real>
Matrix2<Real> EigenDecomposition<Real>::GetEigenvectors2 () const
{
assertion(mSize == 2, "Mismatched dimension in GetEigenvectors2\n");
Matrix2<Real> eigenvectors;
for (int row = 0; row < 2; ++row)
{
for (int column = 0; column < 2; ++column)
{
eigenvectors[row][column] = mMatrix[row][column];
}
}
return eigenvectors;
}
//----------------------------------------------------------------------------
template <typename Real>
Vector3<Real> EigenDecomposition<Real>::GetEigenvector3 (int i) const
{
assertion(mSize == 3, "Mismatched dimension in GetEigenvector3\n");
if (mSize == 3)
{
Vector3<Real> eigenvector;
for (int row = 0; row < mSize; ++row)
{
eigenvector[row] = mMatrix[row][i];
}
return eigenvector;
}
return Vector3<Real>::ZERO;
}
//----------------------------------------------------------------------------
template <typename Real>
Matrix3<Real> EigenDecomposition<Real>::GetEigenvectors3 () const
{
assertion(mSize == 3, "Mismatched dimension in GetEigenvectors2\n");
Matrix3<Real> eigenvectors;
for (int row = 0; row < 3; ++row)
{
for (int column = 0; column < 3; ++column)
{
eigenvectors[row][column] = mMatrix[row][column];
}
}
return eigenvectors;
}
*/
//----------------------------------------------------------------------------
template <typename Real>
GVector<Real> EigenDecomposition<Real>::GetEigenvector (int i) const
{
return mMatrix.GetColumn(i);
}
//----------------------------------------------------------------------------
template <typename Real>
const GMatrix<Real>& EigenDecomposition<Real>::GetEigenvectors () const
{
return mMatrix;
}
//----------------------------------------------------------------------------
template <typename Real>
void EigenDecomposition<Real>::Tridiagonal2 ()
{
// The matrix is already tridiagonal.
mDiagonal[0] = mMatrix[0][0];
mDiagonal[1] = mMatrix[1][1];
mSubdiagonal[0] = mMatrix[0][1];
mSubdiagonal[1] = (Real)0;
mMatrix[0][0] = (Real)1;
mMatrix[0][1] = (Real)0;
mMatrix[1][0] = (Real)0;
mMatrix[1][1] = (Real)1;
mIsRotation = true;
}
//----------------------------------------------------------------------------
template <typename Real>
void EigenDecomposition<Real>::Tridiagonal3 ()
{
Real m00 = mMatrix[0][0];
Real m01 = mMatrix[0][1];
Real m02 = mMatrix[0][2];
Real m11 = mMatrix[1][1];
Real m12 = mMatrix[1][2];
Real m22 = mMatrix[2][2];
mDiagonal[0] = m00;
mSubdiagonal[2] = (Real)0;
if (Math<Real>::FAbs(m02) > Math<Real>::ZERO_TOLERANCE)
{
Real length = Math<Real>::Sqrt(m01*m01 + m02*m02);
Real invLength = ((Real)1)/length;
m01 *= invLength;
m02 *= invLength;
Real q = ((Real)2)*m01*m12 + m02*(m22 - m11);
mDiagonal[1] = m11 + m02*q;
mDiagonal[2] = m22 - m02*q;
mSubdiagonal[0] = length;
mSubdiagonal[1] = m12 - m01*q;
mMatrix[0][0] = (Real)1;
mMatrix[0][1] = (Real)0;
mMatrix[0][2] = (Real)0;
mMatrix[1][0] = (Real)0;
mMatrix[1][1] = m01;
mMatrix[1][2] = m02;
mMatrix[2][0] = (Real)0;
mMatrix[2][1] = m02;
mMatrix[2][2] = -m01;
mIsRotation = false;
}
else
{
mDiagonal[1] = m11;
mDiagonal[2] = m22;
mSubdiagonal[0] = m01;
mSubdiagonal[1] = m12;
mMatrix[0][0] = (Real)1;
mMatrix[0][1] = (Real)0;
mMatrix[0][2] = (Real)0;
mMatrix[1][0] = (Real)0;
mMatrix[1][1] = (Real)1;
mMatrix[1][2] = (Real)0;
mMatrix[2][0] = (Real)0;
mMatrix[2][1] = (Real)0;
mMatrix[2][2] = (Real)1;
mIsRotation = true;
}
}
//----------------------------------------------------------------------------
template <typename Real>
void EigenDecomposition<Real>::TridiagonalN ()
{
// TODO: This is Numerical Recipes in C code. Rewrite to avoid
// copyright issues.
int i0, i1, i2, i3;
for (i0 = mSize - 1, i3 = mSize - 2; i0 >= 1; --i0, --i3)
{
Real value0 = (Real)0;
Real scale = (Real)0;
if (i3 > 0)
{
for (i2 = 0; i2 <= i3; ++i2)
{
scale += Math<Real>::FAbs(mMatrix[i0][i2]);
}
if (scale == (Real)0)
{
mSubdiagonal[i0] = mMatrix[i0][i3];
}
else
{
Real invScale = ((Real)1)/scale;
for (i2 = 0; i2 <= i3; ++i2)
{
mMatrix[i0][i2] *= invScale;
value0 += mMatrix[i0][i2]*mMatrix[i0][i2];
}
Real value1 = mMatrix[i0][i3];
Real value2 = Math<Real>::Sqrt(value0);
if (value1 > (Real)0)
{
value2 = -value2;
}
mSubdiagonal[i0] = scale*value2;
value0 -= value1*value2;
mMatrix[i0][i3] = value1-value2;
value1 = (Real)0;
Real invValue0 = ((Real)1)/value0;
for (i1 = 0; i1 <= i3; ++i1)
{
mMatrix[i1][i0] = mMatrix[i0][i1]*invValue0;
value2 = (Real)0;
for (i2 = 0; i2 <= i1; ++i2)
{
value2 += mMatrix[i1][i2]*mMatrix[i0][i2];
}
for (i2 = i1+1; i2 <= i3; ++i2)
{
value2 += mMatrix[i2][i1]*mMatrix[i0][i2];
}
mSubdiagonal[i1] = value2*invValue0;
value1 += mSubdiagonal[i1]*mMatrix[i0][i1];
}
Real value3 = ((Real)0.5)*value1*invValue0;
for (i1 = 0; i1 <= i3; ++i1)
{
value1 = mMatrix[i0][i1];
value2 = mSubdiagonal[i1] - value3*value1;
mSubdiagonal[i1] = value2;
for (i2 = 0; i2 <= i1; i2++)
{
mMatrix[i1][i2] -=
value1*mSubdiagonal[i2] + value2*mMatrix[i0][i2];
}
}
}
}
else
{
mSubdiagonal[i0] = mMatrix[i0][i3];
}
mDiagonal[i0] = value0;
}
mDiagonal[0] = (Real)0;
mSubdiagonal[0] = (Real)0;
for (i0 = 0, i3 = -1; i0 <= mSize - 1; ++i0, ++i3)
{
if (mDiagonal[i0] != (Real)0)
{
for (i1 = 0; i1 <= i3; ++i1)
{
Real sum = (Real)0;
for (i2 = 0; i2 <= i3; ++i2)
{
sum += mMatrix[i0][i2]*mMatrix[i2][i1];
}
for (i2 = 0; i2 <= i3; ++i2)
{
mMatrix[i2][i1] -= sum*mMatrix[i2][i0];
}
}
}
mDiagonal[i0] = mMatrix[i0][i0];
mMatrix[i0][i0] = (Real)1;
for (i1 = 0; i1 <= i3; ++i1)
{
mMatrix[i1][i0] = (Real)0;
mMatrix[i0][i1] = (Real)0;
}
}
// Reordering needed by EigenDecomposition::QLAlgorithm.
for (i0 = 1, i3 = 0; i0 < mSize; ++i0, ++i3)
{
mSubdiagonal[i3] = mSubdiagonal[i0];
}
mSubdiagonal[mSize-1] = (Real)0;
mIsRotation = ((mSize % 2) == 0);
}
//----------------------------------------------------------------------------
template <typename Real>
bool EigenDecomposition<Real>::QLAlgorithm ()
{
// TODO: This is Numerical Recipes in C code. Rewrite to avoid
// copyright issues.
const int iMaxIter = 32;
for (int i0 = 0; i0 < mSize; ++i0)
{
int i1;
for (i1 = 0; i1 < iMaxIter; ++i1)
{
int i2;
for (i2 = i0; i2 <= mSize - 2; ++i2)
{
Real tmp = Math<Real>::FAbs(mDiagonal[i2]) +
Math<Real>::FAbs(mDiagonal[i2+1]);
if (Math<Real>::FAbs(mSubdiagonal[i2]) + tmp == tmp)
{
break;
}
}
if (i2 == i0)
{
break;
}
Real value0 = (mDiagonal[i0 + 1]
- mDiagonal[i0])/(((Real)2)*mSubdiagonal[i0]);
Real value1 = Math<Real>::Sqrt(value0*value0 + (Real)1);
if (value0 < (Real)0)
{
value0 = mDiagonal[i2] - mDiagonal[i0]
+ mSubdiagonal[i0]/(value0 - value1);
}
else
{
value0 = mDiagonal[i2] - mDiagonal[i0]
+ mSubdiagonal[i0]/(value0 + value1);
}
Real sn = (Real)1, cs = (Real)1, value2 = (Real)0;
for (int i3 = i2 - 1; i3 >= i0; --i3)
{
Real value3 = sn*mSubdiagonal[i3];
Real value4 = cs*mSubdiagonal[i3];
if (Math<Real>::FAbs(value3) >= Math<Real>::FAbs(value0))
{
cs = value0/value3;
value1 = Math<Real>::Sqrt(cs*cs + (Real)1);
mSubdiagonal[i3 + 1] = value3*value1;
sn = ((Real)1)/value1;
cs *= sn;
}
else
{
sn = value3/value0;
value1 = Math<Real>::Sqrt(sn*sn + (Real)1);
mSubdiagonal[i3 + 1] = value0*value1;
cs = ((Real)1)/value1;
sn *= cs;
}
value0 = mDiagonal[i3 + 1] - value2;
value1 = (mDiagonal[i3] - value0)*sn + ((Real)2)*value4*cs;
value2 = sn*value1;
mDiagonal[i3 + 1] = value0 + value2;
value0 = cs*value1 - value4;
for (int i4 = 0; i4 < mSize; ++i4)
{
value3 = mMatrix[i4][i3 + 1];
mMatrix[i4][i3 + 1] = sn*mMatrix[i4][i3] + cs*value3;
mMatrix[i4][i3] = cs*mMatrix[i4][i3] - sn*value3;
}
}
mDiagonal[i0] -= value2;
mSubdiagonal[i0] = value0;
mSubdiagonal[i2] = (Real)0;
}
if (i1 == iMaxIter)
{
return false;
}
}
return true;
}
//----------------------------------------------------------------------------
template <typename Real>
void EigenDecomposition<Real>::DecreasingSort ()
{
// Sort the eigenvalues in decreasing order, e[0] >= ... >= e[mSize-1]
for (int i0 = 0, i1; i0 <= mSize - 2; ++i0)
{
// Locate the maximum eigenvalue.
i1 = i0;
Real maxValue = mDiagonal[i1];
int i2;
for (i2 = i0 + 1; i2 < mSize; ++i2)
{
if (mDiagonal[i2] > maxValue)
{
i1 = i2;
maxValue = mDiagonal[i1];
}
}
if (i1 != i0)
{
// Swap the eigenvalues.
mDiagonal[i1] = mDiagonal[i0];
mDiagonal[i0] = maxValue;
// Swap the eigenvectors corresponding to the eigenvalues.
for (i2 = 0; i2 < mSize; ++i2)
{
Real tmp = mMatrix[i2][i0];
mMatrix[i2][i0] = mMatrix[i2][i1];
mMatrix[i2][i1] = tmp;
mIsRotation = !mIsRotation;
}
}
}
}
//----------------------------------------------------------------------------
template <typename Real>
void EigenDecomposition<Real>::IncreasingSort ()
{
// Sort the eigenvalues in increasing order, e[0] <= ... <= e[mSize-1]
for (int i0 = 0, i1; i0 <= mSize - 2; ++i0)
{
// Locate the minimum eigenvalue.
i1 = i0;
Real minValue = mDiagonal[i1];
int i2;
for (i2 = i0 + 1; i2 < mSize; ++i2)
{
if (mDiagonal[i2] < minValue)
{
i1 = i2;
minValue = mDiagonal[i1];
}
}
if (i1 != i0)
{
// Swap the eigenvalues.
mDiagonal[i1] = mDiagonal[i0];
mDiagonal[i0] = minValue;
// Swap the eigenvectors corresponding to the eigenvalues.
for (i2 = 0; i2 < mSize; ++i2)
{
Real tmp = mMatrix[i2][i0];
mMatrix[i2][i0] = mMatrix[i2][i1];
mMatrix[i2][i1] = tmp;
mIsRotation = !mIsRotation;
}
}
}
}
//----------------------------------------------------------------------------
template <typename Real>
void EigenDecomposition<Real>::GuaranteeRotation ()
{
if (!mIsRotation)
{
// Change sign on the first column.
for (int row = 0; row < mSize; ++row)
{
mMatrix[row][0] = -mMatrix[row][0];
}
}
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
// Explicit instantiation.
//----------------------------------------------------------------------------
template WM5_MATHEMATICS_ITEM
class EigenDecomposition<float>;
template WM5_MATHEMATICS_ITEM
class EigenDecomposition<double>;
//----------------------------------------------------------------------------
template <typename Real>
Line3<Real> OrthogonalLineFit3 (int numPoints, const Vector3<Real>* points)
{
Line3<Real> line(Vector3<Real>(3), Vector3<Real>(3));
// Compute the mean of the points.
line.Origin = points[0];
int i;
for (i = 1; i < numPoints; i++)
{
line.Origin += points[i];
}
Real invNumPoints = ((Real)1)/numPoints;
line.Origin *= invNumPoints;
// Compute the covariance matrix of the points.
Real sumXX = (Real)0, sumXY = (Real)0, sumXZ = (Real)0;
Real sumYY = (Real)0, sumYZ = (Real)0, sumZZ = (Real)0;
for (i = 0; i < numPoints; i++)
{
Vector3<Real> diff = points[i] - line.Origin;
sumXX += diff[0]*diff[0];
sumXY += diff[0]*diff[1];
sumXZ += diff[0]*diff[2];
sumYY += diff[1]*diff[1];
sumYZ += diff[1]*diff[2];
sumZZ += diff[2]*diff[2];
}
sumXX *= invNumPoints;
sumXY *= invNumPoints;
sumXZ *= invNumPoints;
sumYY *= invNumPoints;
sumYZ *= invNumPoints;
sumZZ *= invNumPoints;
// Set up the eigensolver.
EigenDecomposition<Real> esystem(3);
esystem(0,0) = sumYY+sumZZ;
esystem(0,1) = -sumXY;
esystem(0,2) = -sumXZ;
esystem(1,0) = esystem(0,1);
esystem(1,1) = sumXX+sumZZ;
esystem(1,2) = -sumYZ;
esystem(2,0) = esystem(0,2);
esystem(2,1) = esystem(1,2);
esystem(2,2) = sumXX+sumYY;
// Compute eigenstuff, smallest eigenvalue is in last position.
esystem.Solve(false);
// Unit-length direction for best-fit line.
line.Direction = esystem.GetEigenvector(2);
return line;
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
// Explicit instantiation.
//----------------------------------------------------------------------------
template WM5_MATHEMATICS_ITEM
Line3<float> OrthogonalLineFit3<float> (int, const Vector3<float>*);
template WM5_MATHEMATICS_ITEM
Line3<double> OrthogonalLineFit3<double> (int, const Vector3<double>*);
//----------------------------------------------------------------------------
} // namespace

355
tjp/core/math/detail/Wm5.h Normal file
View File

@@ -0,0 +1,355 @@
//
// Wm5.h
// algorithm
//
// Created by Timothy Prepscius on 5/3/18.
// Copyright © 2018 Timothy Prepscius. All rights reserved.
//
#pragma once
#include <stddef.h>
#include <memory.h>
#include <math.h>
namespace Wm5 {
#define WM5_MATHEMATICS_ITEM
#define assertion(...)
template <typename T>
T *new1(size_t size)
{
return new T[size];
}
template <typename T>
void delete1(T *t)
{
delete[] t;
}
// -----
template <typename Real>
struct Math
{
WM5_MATHEMATICS_ITEM static const Real ZERO_TOLERANCE;
static Real FAbs (Real value);
static Real Sqrt (Real value);
} ;
typedef Math<float> Mathf;
typedef Math<double> Mathd;
// -----
template <typename Real>
class GVector
{
public:
// Construction and destruction.
GVector (int size = 0);
GVector (int size, const Real* tuple);
GVector (const GVector& vec);
~GVector ();
// Coordinate access.
void SetSize (int size);
inline int GetSize () const;
inline operator const Real* () const;
inline operator Real* ();
inline const Real& operator[] (int i) const;
inline Real& operator[] (int i);
// Assignment.
GVector& operator= (const GVector& vec);
// Comparison (for use by STL containers).
bool operator== (const GVector& vec) const;
bool operator!= (const GVector& vec) const;
bool operator< (const GVector& vec) const;
bool operator<= (const GVector& vec) const;
bool operator> (const GVector& vec) const;
bool operator>= (const GVector& vec) const;
// Arithmetic operations.
GVector operator+ (const GVector& vec) const;
GVector operator- (const GVector& vec) const;
GVector operator* (Real scalar) const;
GVector operator/ (Real scalar) const;
GVector operator- () const;
friend GVector operator* (Real scalar, const GVector& vec)
{
return vec*scalar;
}
// Arithmetic updates.
GVector& operator+= (const GVector& vec);
GVector& operator-= (const GVector& vec);
GVector& operator*= (Real scalar);
GVector& operator/= (Real scalar);
// Vector operations.
Real Length () const;
Real SquaredLength () const;
Real Dot (const GVector& vec) const;
Real Normalize (Real epsilon = Math<Real>::ZERO_TOLERANCE);
protected:
int mSize;
Real* mTuple;
};
typedef GVector<float> GVectorf;
typedef GVector<double> GVectord;
// -----
template <typename Real>
class GMatrix
{
public:
// Construction and destruction.
GMatrix (int rows = 0, int columns = 0);
GMatrix (int rows, int columns, const Real* entry);
GMatrix (int rows, int columns, const Real** matrix);
GMatrix (const GMatrix& mat);
~GMatrix ();
// Coordinate access.
void SetSize (int rows, int columns);
inline void GetSize (int& rows, int& columns) const;
inline int GetRows () const;
inline int GetColumns () const;
inline int GetQuantity () const;
inline operator const Real* () const;
inline operator Real* ();
inline const Real* operator[] (int row) const;
inline Real* operator[] (int row);
inline const Real& operator() (int row, int column) const;
inline Real& operator() (int row, int column);
void SwapRows (int row0, int row1);
void SetRow (int row, const GVector<Real>& vec);
GVector<Real> GetRow (int row) const;
void SetColumn (int column, const GVector<Real>& vec);
GVector<Real> GetColumn (int column) const;
void SetMatrix (int rows, int columns, const Real* entry);
void SetMatrix (int rows, int columns, const Real** matrix);
void GetColumnMajor (Real* columnMajor) const;
// Assignment.
GMatrix& operator= (const GMatrix& mat);
// Comparison (for use by STL containers).
bool operator== (const GMatrix& mat) const;
bool operator!= (const GMatrix& mat) const;
bool operator< (const GMatrix& mat) const;
bool operator<= (const GMatrix& mat) const;
bool operator> (const GMatrix& mat) const;
bool operator>= (const GMatrix& mat) const;
// Arithmetic operations.
GMatrix operator+ (const GMatrix& mat) const;
GMatrix operator- (const GMatrix& mat) const;
GMatrix operator* (const GMatrix& mat) const;
GMatrix operator* (Real fScalar) const;
GMatrix operator/ (Real fScalar) const;
GMatrix operator- () const;
// Arithmetic updates.
GMatrix& operator+= (const GMatrix& mat);
GMatrix& operator-= (const GMatrix& mat);
GMatrix& operator*= (Real fScalar);
GMatrix& operator/= (Real fScalar);
// M*vec
GVector<Real> operator* (const GVector<Real>& vec) const;
// u^T*M*v
Real QForm (const GVector<Real>& u, const GVector<Real>& v) const;
// M^T
GMatrix Transpose () const;
// M^T*mat
GMatrix TransposeTimes (const GMatrix& mat) const;
// M*mat^T
GMatrix TimesTranspose (const GMatrix& mat) const;
// M^T*mat^T
GMatrix TransposeTimesTranspose (const GMatrix& mat) const;
// Inversion. The matrix must be square. The function returns 'true'
// whenever the matrix is square and invertible.
bool GetInverse (GMatrix<Real>& inverse) const;
// c * M
friend GMatrix<Real> operator* (Real scalar, const GMatrix<Real>& mat)
{
return mat*scalar;
}
// v^T * M
friend GVector<Real> operator* (const GVector<Real>& vec,
const GMatrix<Real>& mat)
{
assertion(vec.GetSize() == mat.GetRows(), "Mismatch in operator*\n");
GVector<Real> prod(mat.GetColumns());
Real* entry = prod;
for (int c = 0; c < mat.GetColumns(); ++c)
{
for (int r = 0; r < mat.GetRows(); ++r)
{
entry[c] += vec[r]*mat[r][c];
}
}
return prod;
}
protected:
// Support for allocation and deallocation. The allocation call requires
// m_iRows, m_iCols, and m_iQuantity to have already been correctly
// initialized.
void Allocate (bool setToZero);
void Deallocate ();
int mRows, mColumns, mQuantity;
// The matrix is stored in row-major form as a 1-dimensional array.
Real* mData;
// An array of pointers to the rows of the matrix. The separation of
// row pointers and actual data supports swapping of rows in linear
// algebraic algorithms such as solving linear systems of equations.
Real** mEntry;
};
typedef GMatrix<float> GMatrixf;
typedef GMatrix<double> GMatrixd;
// -----
template <typename Real>
class WM5_MATHEMATICS_ITEM EigenDecomposition
{
public:
// Construction and destruction. The matrix of an eigensystem must be
// symmetric.
EigenDecomposition (int size);
// EigenDecomposition (const Matrix2<Real>& mat);
// EigenDecomposition (const Matrix3<Real>& mat);
EigenDecomposition (const GMatrix<Real>& mat);
~EigenDecomposition ();
// Set the matrix for the eigensystem.
Real& operator() (int row, int column);
// EigenDecomposition& operator= (const Matrix2<Real>& mat);
// EigenDecomposition& operator= (const Matrix3<Real>& mat);
EigenDecomposition& operator= (const GMatrix<Real>& mat);
// Solve the eigensystem. Set 'increasingSort' to 'true' when you want
// the eigenvalues to be sorted in increasing order; otherwise, the
// eigenvalues are sorted in decreasing order.
void Solve (bool increasingSort);
// Get the results. The calls to GetEigenvector2, GetEigenvectors2,
// GetEigenvector3, and GetEigenvector3 should be made only if you know
// that the eigensystem is of the corresponding size.
Real GetEigenvalue (int i) const;
const Real* GetEigenvalues () const;
// Vector2<Real> GetEigenvector2 (int i) const;
// Matrix2<Real> GetEigenvectors2 () const;
// Vector3<Real> GetEigenvector3 (int i) const;
// Matrix3<Real> GetEigenvectors3 () const;
GVector<Real> GetEigenvector (int i) const;
const GMatrix<Real>& GetEigenvectors () const;
private:
int mSize;
GMatrix<Real> mMatrix;
Real* mDiagonal;
Real* mSubdiagonal;
// For odd size matrices, the Householder reduction involves an odd
// number of reflections. The product of these is a reflection. The
// QL algorithm uses rotations for further reductions. The final
// orthogonal matrix whose columns are the eigenvectors is a reflection,
// so its determinant is -1. For even size matrices, the Householder
// reduction involves an even number of reflections whose product is a
// rotation. The final orthogonal matrix has determinant +1. Many
// algorithms that need an eigendecomposition want a rotation matrix.
// We want to guarantee this is the case, so mRotation keeps track of
// this. The DecrSort and IncrSort further complicate the issue since
// they swap columns of the orthogonal matrix, causing the matrix to
// toggle between rotation and reflection. The value mRotation must
// be toggled accordingly.
bool mIsRotation;
void GuaranteeRotation ();
// Householder reduction to tridiagonal form.
void Tridiagonal2 ();
void Tridiagonal3 ();
void TridiagonalN ();
// QL algorithm with implicit shifting. This function is called for
// tridiagonal matrices.
bool QLAlgorithm ();
// Sort eigenvalues from largest to smallest.
void DecreasingSort ();
// Sort eigenvalues from smallest to largest.
void IncreasingSort ();
};
typedef EigenDecomposition<float> EigenDecompositionf;
typedef EigenDecomposition<double> EigenDecompositiond;
// -----
template<typename Real>
using Vector3 = GVector<Real>;
template <typename Real>
class Line3
{
public:
// The line is represented as P+t*D where P is the line origin, D is a
// unit-length direction vector, and t is any real number. The user must
// ensure that D is indeed unit length.
// Construction and destruction.
Line3 () {}; // uninitialized
~Line3 () {};
Line3 (const Vector3<Real>& origin, const Vector3<Real>& direction) :
Origin(origin),
Direction(direction)
{
}
Vector3<Real> Origin, Direction;
};
typedef Line3<float> Line3f;
typedef Line3<double> Line3d;
// -------
// Least-squares fit of a line to (x,y,z) data by using distance measurements
// orthogonal to the proposed line.
template <typename Real> WM5_MATHEMATICS_ITEM
Line3<Real> OrthogonalLineFit3 (int numPoints, const Vector3<Real>* points);
// ------
#include "Wm5.inl"
} // namespace

1089
tjp/core/math/detail/Wm5.inl Normal file

File diff suppressed because it is too large Load Diff

86
tjp/core/math/mean.hpp Executable file
View File

@@ -0,0 +1,86 @@
//
// Math.hpp
// amoeba
//
// Created by Timothy Prepscius on 12/30/16.
// Copyright © 2016 Timothy Prepscius. All rights reserved.
//
#pragma once
namespace tjp::core::math {
template<typename T>
struct Mean_SumDivide
{
T t = zero<T>();
size_t count = 0;
void add(const T &v)
{
t = t + v;
count++;
}
T mean() const
{
return t / count;
}
};
// https://www.geeksforgeeks.org/program-for-average-of-an-array-without-running-into-overflow/
template<typename T>
struct Mean_AddDivide
{
T t = zero<T>();
size_t count = 0;
void add(const T &v)
{
++count;
t = t + (v - t) / (count);
}
T mean() const
{
return t / count;
}
} ;
// https://www.geeksforgeeks.org/compute-average-two-numbers-without-overflow/
template<typename T>
struct Mean_AddDivideMod
{
T t = zero<T>();
size_t count = 0;
void add(const T &v)
{
++count;
t = t + (v - t) / (count);
}
T mean() const
{
return t / count;
}
} ;
template<typename T, typename U>
auto mean_(const U &u)
{
T t;
for (auto &v: u)
t.add(v);
return t.mean();
}
template<typename U>
auto mean(const U &u)
{
return mean_<Mean_SumDivide<typename U::value_type>>(u);
}
} // namespace