coord: make template parameters more flexible
The coordinate system was unable to support types that prohibited redim or retype operations. Additionally, the `tags' type used for providing named data parameters was unwiedly. We remove much of the dependance on template template parameters in the defined operations and instead define these in terms of a template specialisation of is_coord. The tag types were replaced with direct specialisation of the `store' struct by the primary type, and passing this type through use of the CRTP.
This commit is contained in:
parent
34788756d2
commit
d3f434b523
@ -180,9 +180,9 @@ list (
|
||||
coord.hpp
|
||||
coord/init.hpp
|
||||
coord/iostream.hpp
|
||||
coord/names.hpp
|
||||
coord/ops.hpp
|
||||
coord/store.hpp
|
||||
coord/traits.hpp
|
||||
crypto/arc4.cpp
|
||||
crypto/arc4.hpp
|
||||
crypto/ice.cpp
|
||||
|
450
colour.cpp
450
colour.cpp
@ -15,453 +15,3 @@
|
||||
*/
|
||||
|
||||
#include "colour.hpp"
|
||||
|
||||
#include "ascii.hpp"
|
||||
#include "debug.hpp"
|
||||
#include "log.hpp"
|
||||
#include "range.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <map>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
using util::colour;
|
||||
using util::colour3f;
|
||||
using util::colour4f;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <size_t S, typename T>
|
||||
colour<S,T>
|
||||
colour<S,T>::parse_html (const char *fmt)
|
||||
{
|
||||
// ensure the format is the correct length
|
||||
auto len = strlen (fmt);
|
||||
|
||||
switch (len) {
|
||||
case 1 + 2 * S:
|
||||
if (*fmt != '#')
|
||||
throw std::invalid_argument ("missing leading hash");
|
||||
++fmt;
|
||||
break;
|
||||
|
||||
case 2 * S:
|
||||
break;
|
||||
|
||||
default:
|
||||
throw std::invalid_argument ("format is the wrong length");
|
||||
}
|
||||
|
||||
// parse the octets
|
||||
util::colour<S,uint8_t> res;
|
||||
for (size_t i = 0; i < res.size (); ++i) {
|
||||
auto a = util::ascii::from_hex (fmt[i*2+0]);
|
||||
auto b = util::ascii::from_hex (fmt[i*2+1]);
|
||||
|
||||
res[i] = (a << 4u) | b;
|
||||
}
|
||||
|
||||
return res.template cast<T> ();
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
static const std::map<std::string, colour<4,uint8_t>>
|
||||
HTML_COLOURS { {
|
||||
{ "white", { 0xff, 0xff, 0xff, 0xff } },
|
||||
{ "silver", { 0xc0, 0xc0, 0xc0, 0xff } },
|
||||
{ "gray", { 0x80, 0x80, 0x80, 0xff } },
|
||||
{ "black", { 0x00, 0x00, 0x00, 0xff } },
|
||||
{ "red", { 0xff, 0x00, 0x00, 0xff } },
|
||||
{ "maroon", { 0x80, 0x00, 0x00, 0xff } },
|
||||
{ "yellow", { 0xff, 0xff, 0x00, 0xff } },
|
||||
{ "olive", { 0x80, 0x80, 0x00, 0xff } },
|
||||
{ "lime", { 0x00, 0xff, 0x00, 0xff } },
|
||||
{ "green", { 0x00, 0x80, 0x00, 0xff } },
|
||||
{ "aqua", { 0x00, 0xff, 0xff, 0xff } },
|
||||
{ "teal", { 0x00, 0x80, 0x80, 0xff } },
|
||||
{ "blue", { 0x00, 0x00, 0xff, 0xff } },
|
||||
{ "navy", { 0x00, 0x00, 0x80, 0xff } },
|
||||
{ "fuchsia", { 0xff, 0x00, 0xff, 0xff } },
|
||||
{ "purple", { 0x80, 0x00, 0x80, 0xff } },
|
||||
} };
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
static const std::map<std::string, colour<4,uint8_t>> X11_COLOURS
|
||||
{
|
||||
/* pink */
|
||||
{ "pink", { 0xff, 0xc0, 0xcb, 0xff } },
|
||||
{ "lightpink", { 0xff, 0xb6, 0xc1, 0xff } },
|
||||
{ "hotpink", { 0xff, 0x69, 0xb4, 0xff } },
|
||||
{ "deeppink", { 0xff, 0x14, 0x93, 0xff } },
|
||||
{ "palevioletred", { 0xdb, 0x70, 0x93, 0xff } },
|
||||
{ "mediumvioletred", { 0xc7, 0x15, 0x85, 0xff } },
|
||||
|
||||
/* red */
|
||||
{ "lightsalmon", { 0xff, 0xa0, 0x7a, 0xff } },
|
||||
{ "salmon", { 0xfa, 0x80, 0x72, 0xff } },
|
||||
{ "darksalmon", { 0xe9, 0x96, 0x7a, 0xff } },
|
||||
{ "lightcoral", { 0xf0, 0x80, 0x80, 0xff } },
|
||||
{ "indianred", { 0xcd, 0x5c, 0x5c, 0xff } },
|
||||
{ "crimson", { 0xdc, 0x14, 0x3c, 0xff } },
|
||||
{ "firebrick", { 0xb2, 0x22, 0x22, 0xff } },
|
||||
{ "darkred", { 0x8b, 0x00, 0x00, 0xff } },
|
||||
{ "red", { 0xff, 0x00, 0x00, 0xff } },
|
||||
|
||||
/* orange */
|
||||
{ "orangered", { 0xff, 0x45, 0x00, 0xff } },
|
||||
{ "tomato", { 0xff, 0x63, 0x47, 0xff } },
|
||||
{ "coral", { 0xff, 0x7f, 0x50, 0xff } },
|
||||
{ "darkorange", { 0xff, 0x8c, 0x00, 0xff } },
|
||||
{ "orange", { 0xff, 0xa5, 0x00, 0xff } },
|
||||
|
||||
/* yellow */
|
||||
{ "yellow", { 0xff, 0xff, 0x00, 0xff } },
|
||||
{ "lightyellow", { 0xff, 0xff, 0xe0, 0xff } },
|
||||
{ "lemonchiffon", { 0xff, 0xfa, 0xcd, 0xff } },
|
||||
{ "lightgoldenrodyellow", { 0xfa, 0xfa, 0xd2, 0xff } },
|
||||
{ "papayawhip", { 0xff, 0xef, 0xd5, 0xff } },
|
||||
{ "moccasin", { 0xff, 0xe4, 0xb5, 0xff } },
|
||||
{ "peachpuff", { 0xff, 0xda, 0xb9, 0xff } },
|
||||
{ "palegoldenrod", { 0xee, 0xe8, 0xaa, 0xff } },
|
||||
{ "khaki", { 0xf0, 0xe6, 0x8c, 0xff } },
|
||||
{ "darkkhaki", { 0xbd, 0xb7, 0x6b, 0xff } },
|
||||
{ "gold", { 0xff, 0xd7, 0x00, 0xff } },
|
||||
|
||||
/* brown */
|
||||
{ "cornsilk", { 0xff, 0xf8, 0xdc, 0xff } },
|
||||
{ "blanchedalmond", { 0xff, 0xeb, 0xcd, 0xff } },
|
||||
{ "bisque", { 0xff, 0xe4, 0xc4, 0xff } },
|
||||
{ "navajowhite", { 0xff, 0xde, 0xad, 0xff } },
|
||||
{ "wheat", { 0xf5, 0xde, 0xb3, 0xff } },
|
||||
{ "burlywood", { 0xde, 0xb8, 0x87, 0xff } },
|
||||
{ "tan", { 0xd2, 0xb4, 0x8c, 0xff } },
|
||||
{ "rosybrown", { 0xbc, 0x8f, 0x8f, 0xff } },
|
||||
{ "sandybrown", { 0xf4, 0xa4, 0x60, 0xff } },
|
||||
{ "goldenrod", { 0xda, 0xa5, 0x20, 0xff } },
|
||||
{ "darkgoldenrod", { 0xb8, 0x86, 0x0b, 0xff } },
|
||||
{ "peru", { 0xcd, 0x85, 0x3f, 0xff } },
|
||||
{ "chocolate", { 0xd2, 0x69, 0x1e, 0xff } },
|
||||
{ "saddlebrown", { 0x8b, 0x45, 0x13, 0xff } },
|
||||
{ "sienna", { 0xa0, 0x52, 0x2d, 0xff } },
|
||||
{ "brown", { 0xa5, 0x2a, 0x2a, 0xff } },
|
||||
{ "maroon", { 0x80, 0x00, 0x00, 0xff } },
|
||||
|
||||
/* green */
|
||||
{ "darkolivegreen", { 0x55, 0x6b, 0x2f, 0xff } },
|
||||
{ "olive", { 0x80, 0x80, 0x00, 0xff } },
|
||||
{ "olivedrab", { 0x6b, 0x8e, 0x23, 0xff } },
|
||||
{ "yellowgreen", { 0x9a, 0xcd, 0x32, 0xff } },
|
||||
{ "limegreen", { 0x32, 0xcd, 0x32, 0xff } },
|
||||
{ "lime", { 0x00, 0xff, 0x00, 0xff } },
|
||||
{ "lawngreen", { 0x7c, 0xfc, 0x00, 0xff } },
|
||||
{ "chartreuse", { 0x7f, 0xff, 0x00, 0xff } },
|
||||
{ "greenyellow", { 0xad, 0xff, 0x2f, 0xff } },
|
||||
{ "springgreen", { 0x00, 0xff, 0x7f, 0xff } },
|
||||
{ "mediumspringgreen", { 0x00, 0xfa, 0x9a, 0xff } },
|
||||
{ "lightgreen", { 0x90, 0xee, 0x90, 0xff } },
|
||||
{ "palegreen", { 0x98, 0xfb, 0x98, 0xff } },
|
||||
{ "darkseagreen", { 0x8f, 0xbc, 0x8f, 0xff } },
|
||||
{ "mediumseagreen", { 0x3c, 0xb3, 0x71, 0xff } },
|
||||
{ "seagreen", { 0x2e, 0x8b, 0x57, 0xff } },
|
||||
{ "forestgreen", { 0x22, 0x8b, 0x22, 0xff } },
|
||||
{ "green", { 0x00, 0x80, 0x00, 0xff } },
|
||||
{ "darkgreen", { 0x00, 0x64, 0x00, 0xff } },
|
||||
|
||||
/* cyan */
|
||||
{ "mediumaquamarine", { 0x66, 0xcd, 0xaa, 0xff } },
|
||||
{ "aqua", { 0x00, 0xff, 0xff, 0xff } },
|
||||
{ "cyan", { 0x00, 0xff, 0xff, 0xff } },
|
||||
{ "lightcyan", { 0xe0, 0xff, 0xff, 0xff } },
|
||||
{ "paleturquoise", { 0xaf, 0xee, 0xee, 0xff } },
|
||||
{ "aquamarine", { 0x7f, 0xff, 0xd4, 0xff } },
|
||||
{ "turquoise", { 0x40, 0xe0, 0xd0, 0xff } },
|
||||
{ "mediumturquoise", { 0x48, 0xd1, 0xcc, 0xff } },
|
||||
{ "darkturquoise", { 0x00, 0xce, 0xd1, 0xff } },
|
||||
{ "lightseagreen", { 0x20, 0xb2, 0xaa, 0xff } },
|
||||
{ "cadetblue", { 0x5f, 0x9e, 0xa0, 0xff } },
|
||||
{ "darkcyan", { 0x00, 0x8b, 0x8b, 0xff } },
|
||||
{ "teal", { 0x00, 0x80, 0x80, 0xff } },
|
||||
|
||||
/* blue */
|
||||
{ "lightsteelblue", { 0xb0, 0xc4, 0xde, 0xff } },
|
||||
{ "powderblue", { 0xb0, 0xe0, 0xe6, 0xff } },
|
||||
{ "lightblue", { 0xad, 0xd8, 0xe6, 0xff } },
|
||||
{ "skyblue", { 0x87, 0xce, 0xeb, 0xff } },
|
||||
{ "lightskyblue", { 0x87, 0xce, 0xfa, 0xff } },
|
||||
{ "deepskyblue", { 0x00, 0xbf, 0xff, 0xff } },
|
||||
{ "dodgerblue", { 0x1e, 0x90, 0xff, 0xff } },
|
||||
{ "cornflowerblue", { 0x64, 0x95, 0xed, 0xff } },
|
||||
{ "steelblue", { 0x46, 0x82, 0xb4, 0xff } },
|
||||
{ "royalblue", { 0x41, 0x69, 0xe1, 0xff } },
|
||||
{ "blue", { 0x00, 0x00, 0xff, 0xff } },
|
||||
{ "mediumblue", { 0x00, 0x00, 0xcd, 0xff } },
|
||||
{ "darkblue", { 0x00, 0x00, 0x8b, 0xff } },
|
||||
{ "navy", { 0x00, 0x00, 0x80, 0xff } },
|
||||
{ "midnightblue", { 0x19, 0x19, 0x70, 0xff } },
|
||||
|
||||
/* purple */
|
||||
{ "lavender", { 0xe6, 0xe6, 0xfa, 0xff } },
|
||||
{ "thistle", { 0xd8, 0xbf, 0xd8, 0xff } },
|
||||
{ "plum", { 0xdd, 0xa0, 0xdd, 0xff } },
|
||||
{ "violet", { 0xee, 0x82, 0xee, 0xff } },
|
||||
{ "orchid", { 0xda, 0x70, 0xd6, 0xff } },
|
||||
{ "fuchsia", { 0xff, 0x00, 0xff, 0xff } },
|
||||
{ "magenta", { 0xff, 0x00, 0xff, 0xff } },
|
||||
{ "mediumorchid", { 0xba, 0x55, 0xd3, 0xff } },
|
||||
{ "mediumpurple", { 0x93, 0x70, 0xdb, 0xff } },
|
||||
{ "blueviolet", { 0x8a, 0x2b, 0xe2, 0xff } },
|
||||
{ "darkviolet", { 0x94, 0x00, 0xd3, 0xff } },
|
||||
{ "darkorchid", { 0x99, 0x32, 0xcc, 0xff } },
|
||||
{ "darkmagenta", { 0x8b, 0x00, 0x8b, 0xff } },
|
||||
{ "purple", { 0x80, 0x00, 0x80, 0xff } },
|
||||
{ "indigo", { 0x4b, 0x00, 0x82, 0xff } },
|
||||
{ "darkslateblue", { 0x48, 0x3d, 0x8b, 0xff } },
|
||||
{ "rebeccapurple", { 0x66, 0x33, 0x99, 0xff } },
|
||||
{ "slateblue", { 0x6a, 0x5a, 0xcd, 0xff } },
|
||||
{ "mediumslateblue", { 0x7b, 0x68, 0xee, 0xff } },
|
||||
|
||||
/* white */
|
||||
{ "white", { 0xff, 0xff, 0xff, 0xff } },
|
||||
{ "snow", { 0xff, 0xfa, 0xfa, 0xff } },
|
||||
{ "honeydew", { 0xf0, 0xff, 0xf0, 0xff } },
|
||||
{ "mintcream", { 0xf5, 0xff, 0xfa, 0xff } },
|
||||
{ "azure", { 0xf0, 0xff, 0xff, 0xff } },
|
||||
{ "aliceblue", { 0xf0, 0xf8, 0xff, 0xff } },
|
||||
{ "ghostwhite", { 0xf8, 0xf8, 0xff, 0xff } },
|
||||
{ "whitesmoke", { 0xf5, 0xf5, 0xf5, 0xff } },
|
||||
{ "seashell", { 0xff, 0xf5, 0xee, 0xff } },
|
||||
{ "beige", { 0xf5, 0xf5, 0xdc, 0xff } },
|
||||
{ "oldlace", { 0xfd, 0xf5, 0xe6, 0xff } },
|
||||
{ "floralwhite", { 0xff, 0xfa, 0xf0, 0xff } },
|
||||
{ "ivory", { 0xff, 0xff, 0xf0, 0xff } },
|
||||
{ "antiquewhite", { 0xfa, 0xeb, 0xd7, 0xff } },
|
||||
{ "linen", { 0xfa, 0xf0, 0xe6, 0xff } },
|
||||
{ "lavenderblush", { 0xff, 0xf0, 0xf5, 0xff } },
|
||||
{ "mistyrose", { 0xff, 0xe4, 0xe1, 0xff } },
|
||||
|
||||
/* grey/black */
|
||||
{ "gainsboro", { 0xdc, 0xdc, 0xdc, 0xff } },
|
||||
{ "lightgrey", { 0xd3, 0xd3, 0xd3, 0xff } },
|
||||
{ "silver", { 0xc0, 0xc0, 0xc0, 0xff } },
|
||||
{ "darkgray", { 0xa9, 0xa9, 0xa9, 0xff } },
|
||||
{ "gray", { 0x80, 0x80, 0x80, 0xff } },
|
||||
{ "dimgray", { 0x69, 0x69, 0x69, 0xff } },
|
||||
{ "lightslategray", { 0x77, 0x88, 0x99, 0xff } },
|
||||
{ "slategray", { 0x70, 0x80, 0x90, 0xff } },
|
||||
{ "darkslategray", { 0x2f, 0x4f, 0x4f, 0xff } },
|
||||
{ "black", { 0x00, 0x00, 0x00, 0xff } },
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <size_t S, typename T>
|
||||
static colour<S,T>
|
||||
lookup_colour (const std::string &name,
|
||||
const std::map<std::string,colour<4,uint8_t>> &map)
|
||||
{
|
||||
std::string lower (name);
|
||||
std::transform (lower.begin (), lower.end (), lower.begin (), tolower);
|
||||
|
||||
auto pos = map.find (lower);
|
||||
if (pos == map.end ())
|
||||
throw std::out_of_range (name);
|
||||
|
||||
static_assert (S <= 4, "cannot invent additional data");
|
||||
return pos->second.template redim<S> ().template cast<T> ();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <size_t S, typename T>
|
||||
colour<S,T>
|
||||
colour<S,T>::from_html (const std::string &name)
|
||||
{
|
||||
return lookup_colour<S,T> (name, HTML_COLOURS);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <size_t S, typename T>
|
||||
colour<S,T>
|
||||
colour<S,T>::from_x11 (const std::string &name)
|
||||
{
|
||||
return lookup_colour<S,T> (name, X11_COLOURS);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
colour3f
|
||||
util::rgb_to_hsv (colour3f rgb)
|
||||
{
|
||||
// Calculate chroma
|
||||
auto M = max (rgb);
|
||||
auto m = min (rgb);
|
||||
auto C = M - m;
|
||||
|
||||
// Undefined for zero chroma
|
||||
if (almost_zero (C))
|
||||
return { -1.f, 0.f, M };
|
||||
|
||||
// Calculate hue
|
||||
float H = exactly_equal (rgb.r, M) ? (rgb.g - rgb.b) :
|
||||
exactly_equal (rgb.g, M) ? 2 + (rgb.b - rgb.r) :
|
||||
exactly_equal (rgb.b, M) ? 4 + (rgb.r - rgb.g) :
|
||||
0 ;
|
||||
|
||||
H /= C;
|
||||
H *= 60;
|
||||
|
||||
if (H < 0)
|
||||
H += 360;
|
||||
|
||||
// Calculate value
|
||||
auto V = M;
|
||||
|
||||
// Calculate saturation
|
||||
auto S = almost_zero (V) ? 0.f : C / V;
|
||||
|
||||
return { H, S, V };
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
colour3f
|
||||
util::hsv_to_rgb (colour3f hsv)
|
||||
{
|
||||
CHECK_GE (hsv.h, 0);
|
||||
CHECK_LT (hsv.h, 360);
|
||||
CHECK_GE (hsv.s, 0);
|
||||
CHECK_LE (hsv.s, 1);
|
||||
CHECK_GE (hsv.v, 0);
|
||||
CHECK_LE (hsv.v, 1);
|
||||
|
||||
float C = hsv.v * hsv.s;
|
||||
float H = hsv.h / 60;
|
||||
float X = C * (1 - std::abs (std::fmod (H, 2.f) - 1));
|
||||
|
||||
// monochromatic'ish
|
||||
if (almost_zero (hsv.s))
|
||||
return colour3f { hsv.v };
|
||||
|
||||
colour3f rgb;
|
||||
|
||||
unsigned hex = (unsigned)H;
|
||||
switch (hex) {
|
||||
case 0: rgb = { C, X, 0 }; break;
|
||||
case 1: rgb = { X, C, 0 }; break;
|
||||
case 2: rgb = { 0, C, X }; break;
|
||||
case 3: rgb = { 0, X, C }; break;
|
||||
case 4: rgb = { X, 0, C }; break;
|
||||
case 5: rgb = { C, 0, X }; break;
|
||||
}
|
||||
|
||||
auto m = hsv.v - C;
|
||||
|
||||
return rgb + m;
|
||||
}
|
||||
|
||||
|
||||
///----------------------------------------------------------------------------
|
||||
/// Extract a colour object from a JSON node.
|
||||
#include "json/tree.hpp"
|
||||
|
||||
namespace json::tree {
|
||||
template <>
|
||||
util::colour4f
|
||||
io<util::colour4f>::deserialise (const node &root) {
|
||||
return {
|
||||
root[0].as<float> (),
|
||||
root[1].as<float> (),
|
||||
root[2].as<float> (),
|
||||
root[3].as<float> (),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <size_t S, typename T>
|
||||
std::ostream&
|
||||
util::operator<< (std::ostream &os, util::colour<S,T> c) {
|
||||
os << "colour(";
|
||||
for (size_t i = 0; i < S - 1; ++i)
|
||||
os << +c[i] << ", ";
|
||||
os << +c[S-1] << ")";
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <size_t S, typename T>
|
||||
std::istream&
|
||||
util::operator>> (std::istream &is, util::colour<S,T> &c)
|
||||
{
|
||||
std::array<
|
||||
std::conditional_t<
|
||||
sizeof(T) == 1,
|
||||
uint16_t,
|
||||
T
|
||||
>,S
|
||||
> v;
|
||||
|
||||
static_assert (S > 0, "current implementation requires strictly positive components");
|
||||
char comma;
|
||||
|
||||
for (size_t i = 0; i < S - 1; ++i) {
|
||||
is >> v[i] >> comma;
|
||||
|
||||
if (comma != ',' || is.eof ()) {
|
||||
is.setstate (std::ios_base::failbit);
|
||||
return is;
|
||||
}
|
||||
}
|
||||
|
||||
is >> v[S-1];
|
||||
|
||||
if (!std::is_same<T, typename decltype(v)::value_type>::value) {
|
||||
if (std::any_of (std::cbegin (v),
|
||||
std::cend (v),
|
||||
[] (auto i) {
|
||||
return i > std::numeric_limits<T>::max ();
|
||||
})) {
|
||||
is.setstate (std::ios_base::failbit);
|
||||
return is;
|
||||
}
|
||||
}
|
||||
|
||||
std::copy (std::cbegin (v),
|
||||
std::cend (v),
|
||||
std::begin (c));
|
||||
|
||||
return is;
|
||||
}
|
||||
|
||||
template std::istream& util::operator>> (std::istream&, util::colour<3,uint8_t>&);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INSTANTIATE_S_T(S,T) \
|
||||
template \
|
||||
struct util::colour<S,T>; \
|
||||
\
|
||||
template \
|
||||
std::ostream& \
|
||||
util::operator<< (std::ostream&, util::colour<S,T>); \
|
||||
\
|
||||
template \
|
||||
const char* \
|
||||
util::to_string<util::colour<S,T>> (void);
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
#define INSTANTIATE_S(S) \
|
||||
INSTANTIATE_S_T(S,uint8_t) \
|
||||
INSTANTIATE_S_T(S,float) \
|
||||
INSTANTIATE_S_T(S,double)
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
INSTANTIATE_S(1)
|
||||
INSTANTIATE_S(3)
|
||||
INSTANTIATE_S(4)
|
||||
|
138
colour.hpp
138
colour.hpp
@ -11,7 +11,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Copyright 2010-2015 Danny Robson <danny@nerdcruft.net>
|
||||
* Copyright 2010-2017 Danny Robson <danny@nerdcruft.net>
|
||||
*/
|
||||
|
||||
#ifndef __UTIL_COLOUR_HPP
|
||||
@ -21,68 +21,94 @@
|
||||
#include "introspection.hpp"
|
||||
|
||||
#include <ostream>
|
||||
#include <type_traits>
|
||||
|
||||
namespace util {
|
||||
/// An RGBA colour POD type.
|
||||
template <size_t S, typename T>
|
||||
struct colour : public coord::base<S,T,colour,coord::rgba,coord::hsv> {
|
||||
using coord::base<S,T,util::colour,coord::rgba,coord::hsv>::base;
|
||||
using base_t = coord::base<S,T,util::colour,coord::rgba,coord::hsv>;
|
||||
/// An abstract colour POD type componsed of S components of type T.
|
||||
///
|
||||
/// Not to be used directly, instead the use of derived types is required.
|
||||
/// This exists purely to simplify generic colour code.
|
||||
template <
|
||||
size_t S,
|
||||
typename T,
|
||||
typename SelfT
|
||||
>
|
||||
struct colour : coord::base<S,T,SelfT> {
|
||||
using coord::base<S,T,SelfT>::base;
|
||||
|
||||
// overloaded cast operator which assumes values are unit normalised
|
||||
template <typename U>
|
||||
colour<S,U>
|
||||
cast (void) const;
|
||||
|
||||
/// parse colours specified as "#AABBCCDD".
|
||||
///
|
||||
/// * the leading hash is optional.
|
||||
/// * all components must be 2 hex digits.
|
||||
static colour parse_html (const char*);
|
||||
static colour parse_html (const std::string&);
|
||||
|
||||
/// look up the name of a colour from those specified in
|
||||
/// html/x11/etc specifications.
|
||||
static colour from_html (const std::string &name);
|
||||
static colour from_x11 (const std::string &name);
|
||||
|
||||
/// look up all the specifications and returns the colour from one
|
||||
/// that matches. the search order is unspecified, so if you want a
|
||||
/// known colour then try them first yourself.
|
||||
static colour from_string (const std::string &name);
|
||||
auto
|
||||
cast (void) const
|
||||
{
|
||||
::util::revalue_t<SelfT,U> ret;
|
||||
std::transform (std::begin (*this),
|
||||
std::end (*this),
|
||||
std::begin (ret),
|
||||
renormalise<T,U>);
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
// Convenience types
|
||||
template <typename T> using colour1 = colour<1,T>;
|
||||
template <typename T> using colour3 = colour<3,T>;
|
||||
template <typename T> using colour4 = colour<4,T>;
|
||||
|
||||
typedef colour1<uint8_t> colour1u;
|
||||
typedef colour3<uint8_t> colour3u;
|
||||
typedef colour4<uint8_t> colour4u;
|
||||
|
||||
typedef colour1<float> colour1f;
|
||||
typedef colour3<float> colour3f;
|
||||
typedef colour4<float> colour4f;
|
||||
|
||||
// RGB/HSV conversions
|
||||
colour3f rgb_to_hsv (colour3f);
|
||||
colour3f hsv_to_rgb (colour3f);
|
||||
|
||||
// ostream/istream operators
|
||||
template <size_t S, typename T>
|
||||
std::ostream&
|
||||
operator<< (std::ostream&, util::colour<S,T>);
|
||||
|
||||
template <size_t S, typename T>
|
||||
std::istream&
|
||||
operator>> (std::istream&, util::colour<S,T>&);
|
||||
|
||||
// type name introspection specialisation
|
||||
template <size_t S, typename T>
|
||||
struct type_name<colour<S,T>> {
|
||||
static constexpr const char value[] = "colour";
|
||||
template <typename T>
|
||||
struct util::coord::store<1,T,srgba<1,T>> {
|
||||
union { struct { T r; }; T data[1]; };
|
||||
};
|
||||
template <typename T>
|
||||
struct util::coord::store<2,T,srgba<2,T>> {
|
||||
union { struct { T r, g; }; T data[2]; };
|
||||
};
|
||||
template <typename T>
|
||||
struct util::coord::store<3,T,srgba<3,T>> {
|
||||
union { struct { T r, g, b; }; T data[3]; };
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct util::coord::store<4,T,srgba<4,T>> {
|
||||
union { struct { T r, g, b, a; }; T data[4]; };
|
||||
};
|
||||
|
||||
template <size_t S, typename T> struct srgba : colour<S,T,srgba<S,T>> {
|
||||
using colour<S,T,srgba<S,T>>::colour;
|
||||
};
|
||||
|
||||
using srgba3f = srgba<3,float>;
|
||||
using srgba4f = srgba<4,float>;
|
||||
|
||||
template <size_t S, typename T> struct hsva : colour<S,T,hsva<S,T>> {};
|
||||
|
||||
template <size_t S, typename T>
|
||||
struct redim_type<
|
||||
srgba<S,T>
|
||||
> { template <size_t _S> using type = srgba<_S,T>; };
|
||||
|
||||
template <size_t S, typename T>
|
||||
struct revalue_type<srgba<S,T>> {
|
||||
template <typename _T>
|
||||
using type = srgba<S,_T>;
|
||||
};
|
||||
|
||||
|
||||
template <typename> struct is_colour : public std::false_type {};
|
||||
template <
|
||||
size_t S,
|
||||
typename T,
|
||||
template <
|
||||
size_t,
|
||||
typename
|
||||
> typename ColourT
|
||||
> struct is_colour<ColourT<S,T>>
|
||||
:std::conditional_t<
|
||||
std::is_base_of_v<
|
||||
colour<S,T,ColourT<S,T>>,
|
||||
ColourT<S,T>
|
||||
>,
|
||||
std::true_type,
|
||||
std::false_type
|
||||
> {};
|
||||
|
||||
|
||||
template <typename T>
|
||||
constexpr auto is_colour_v = is_colour<T>::value;
|
||||
}
|
||||
|
||||
#include "colour.ipp"
|
||||
|
12
colour.ipp
12
colour.ipp
@ -19,15 +19,3 @@
|
||||
#endif
|
||||
#define __UTIL_COLOUR_IPP
|
||||
|
||||
template <size_t S, typename T>
|
||||
template <typename U>
|
||||
util::colour<S,U>
|
||||
util::colour<S,T>::cast (void) const
|
||||
{
|
||||
colour<S,U> ret;
|
||||
std::transform (this->begin (),
|
||||
this->end (),
|
||||
ret.begin (),
|
||||
renormalise<T,U>);
|
||||
return ret;
|
||||
}
|
||||
|
@ -17,44 +17,56 @@
|
||||
#ifndef __UTIL_COORD_BASE_HPP
|
||||
#define __UTIL_COORD_BASE_HPP
|
||||
|
||||
#include "fwd.hpp"
|
||||
|
||||
#include "init.hpp"
|
||||
#include "traits.hpp"
|
||||
#include "../maths.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <type_traits>
|
||||
|
||||
|
||||
namespace util::coord {
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// the base class for all coordinate-like types.
|
||||
//
|
||||
// SelfT should not be exposed as a template template directly because
|
||||
// some types (eg, XYZ colours) do not conform to the same template
|
||||
// parameters are others (eg, vector2f). ie, it does not make sense to
|
||||
// allow redim, or type changing on some types so they just aren't exposed.
|
||||
template <
|
||||
size_t S,
|
||||
typename T,
|
||||
template <size_t, typename> class KLASS,
|
||||
typename ...tags
|
||||
typename SelfT
|
||||
>
|
||||
struct base : public init<S,T,tags...> {
|
||||
struct base : public init<S,T,SelfT> {
|
||||
static_assert (S > 0);
|
||||
static_assert (std::is_arithmetic<T>::value);
|
||||
static_assert (sizeof (init<S,T,SelfT>) == S * sizeof (T));
|
||||
|
||||
using value_type = T;
|
||||
static constexpr size_t dimension = S;
|
||||
static constexpr size_t elements = S;
|
||||
|
||||
static constexpr size_t size (void) { return S; }
|
||||
static constexpr auto size (void) { return S; }
|
||||
|
||||
// constructors
|
||||
using init<S,T,tags...>::init;
|
||||
using init<S,T,SelfT>::init;
|
||||
base () = default;
|
||||
|
||||
constexpr explicit base (T val)
|
||||
{ std::fill (begin (), end (), val); }
|
||||
|
||||
constexpr base (const base<S,T,KLASS,tags...> &rhs) = default;
|
||||
base& operator= (const base<S,T,KLASS,tags...> &rhs) = default;
|
||||
constexpr base (const base<S,T,SelfT> &rhs) = default;
|
||||
base& operator= (const base<S,T,SelfT> &rhs) = default;
|
||||
|
||||
// element accessors
|
||||
T& operator[] (size_t i) { return this->data[i]; }
|
||||
constexpr const T& operator[] (size_t i) const { return this->data[i]; }
|
||||
T& operator[] (int i) { return this->data[i]; }
|
||||
constexpr const T& operator[] (int i) const { return this->data[i]; }
|
||||
|
||||
auto cbegin (void) const { return std::cbegin (this->data); }
|
||||
auto cend (void) const { return std::cend (this->data); }
|
||||
@ -81,12 +93,28 @@ namespace util::coord {
|
||||
return k;
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
template <
|
||||
typename K,
|
||||
typename = std::enable_if_t<is_coord_v<K>,void>
|
||||
>
|
||||
K as (void) const
|
||||
{
|
||||
static_assert (K::elements == elements);
|
||||
K k;
|
||||
std::copy (begin (), end (), k.begin ());
|
||||
return k;
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------
|
||||
template <typename U>
|
||||
KLASS<S,U>
|
||||
auto
|
||||
cast (void) const
|
||||
{
|
||||
KLASS<S,U> out;
|
||||
typename revalue_type<SelfT>::template type<U> out;
|
||||
|
||||
std::copy (std::cbegin (this->data),
|
||||
std::cend (this->data),
|
||||
std::begin (out.data));
|
||||
@ -95,11 +123,18 @@ namespace util::coord {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// redimension
|
||||
template <size_t D>
|
||||
KLASS<D,T>
|
||||
template <
|
||||
size_t D,
|
||||
typename _sfinae = SelfT
|
||||
>
|
||||
std::enable_if_t<
|
||||
has_redim_v<_sfinae>,
|
||||
redim_t<_sfinae,D>
|
||||
>
|
||||
redim (void) const
|
||||
{
|
||||
KLASS<D,T> out;
|
||||
redim_t<SelfT,D> out;
|
||||
|
||||
std::copy_n (std::cbegin (this->data),
|
||||
min (S, D),
|
||||
std::begin (out.data));
|
||||
@ -108,11 +143,14 @@ namespace util::coord {
|
||||
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
template<size_t D>
|
||||
KLASS<D,T>
|
||||
redim (const KLASS<D,T> fill) const
|
||||
template<size_t D,typename _sfinae = SelfT>
|
||||
std::enable_if_t<
|
||||
has_redim_v<_sfinae>,
|
||||
redim_t<_sfinae,D>
|
||||
>
|
||||
redim (const redim_t<_sfinae,D> fill) const
|
||||
{
|
||||
KLASS<D,T> out;
|
||||
redim_t<SelfT,D> out;
|
||||
|
||||
static constexpr auto L1 = min (S, D);
|
||||
static constexpr auto L2 = D - L1;
|
||||
@ -128,11 +166,17 @@ namespace util::coord {
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
template <size_t D>
|
||||
KLASS<D,T>
|
||||
template <
|
||||
size_t D,
|
||||
typename _sfinae = SelfT
|
||||
>
|
||||
std::enable_if_t<
|
||||
has_redim_v<_sfinae>,
|
||||
redim_t<_sfinae,D>
|
||||
>
|
||||
redim (T fill) const
|
||||
{
|
||||
KLASS<D,T> out;
|
||||
redim_t<SelfT,D> out;
|
||||
|
||||
auto cursor = std::copy_n (std::cbegin (this->data),
|
||||
min (S, D),
|
||||
@ -144,5 +188,6 @@ namespace util::coord {
|
||||
};
|
||||
}
|
||||
|
||||
#include "ops.hpp"
|
||||
|
||||
#endif
|
||||
|
@ -14,11 +14,20 @@
|
||||
* Copyright 2016 Danny Robson <danny@nerdcruft.net>
|
||||
*/
|
||||
|
||||
#ifndef __UTIL_COORD_FWD_HPP
|
||||
#define __UTIL_COORD_FWD_HPP
|
||||
#ifndef CRUFT_UTIL_COORD_FWD_HPP
|
||||
#define CRUFT_UTIL_COORD_FWD_HPP
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
namespace util {
|
||||
template <size_t,typename> struct colour;
|
||||
namespace coord {
|
||||
template <size_t S,typename T,typename ParentT> struct store;
|
||||
template <size_t,typename,typename> struct init;
|
||||
template <size_t,typename,typename> struct base;
|
||||
}
|
||||
|
||||
template <size_t,typename> struct srgba;
|
||||
template <size_t,typename> struct hsva;
|
||||
template <size_t,typename> struct extent;
|
||||
template <size_t,typename> struct point;
|
||||
template <size_t,typename> struct vector;
|
||||
|
@ -22,53 +22,53 @@
|
||||
#include <cstdlib>
|
||||
|
||||
namespace util::coord {
|
||||
template <size_t S, typename T, typename...>
|
||||
template <size_t S, typename T, typename SelfT>
|
||||
struct init;
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
template <typename T, typename ...tags>
|
||||
struct init<1,T,tags...> : public store<1,T,tags...>
|
||||
template <typename T, typename SelfT>
|
||||
struct init<1,T,SelfT> : public store<1,T,SelfT>
|
||||
{
|
||||
using store<1,T,tags...>::store;
|
||||
using store<1,T,SelfT>::store;
|
||||
constexpr init () = default;
|
||||
constexpr init (T v0):
|
||||
store<1,T,tags...> ({v0})
|
||||
store<1,T,SelfT> ({v0})
|
||||
{ ; }
|
||||
};
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
template <typename T, typename ...tags>
|
||||
struct init<2,T,tags...> : public store<2,T,tags...>
|
||||
template <typename T, typename SelfT>
|
||||
struct init<2,T,SelfT> : public store<2,T,SelfT>
|
||||
{
|
||||
using store<2,T,tags...>::store;
|
||||
using store<2,T,SelfT>::store;
|
||||
constexpr init () = default;
|
||||
constexpr init (T v0, T v1):
|
||||
store<2,T,tags...> ({ v0, v1 })
|
||||
store<2,T,SelfT> ({ v0, v1 })
|
||||
{ ; }
|
||||
};
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
template <typename T, typename ...tags>
|
||||
struct init<3,T,tags...> : public store<3,T,tags...>
|
||||
template <typename T, typename SelfT>
|
||||
struct init<3,T,SelfT> : public store<3,T,SelfT>
|
||||
{
|
||||
using store<3,T,tags...>::store;
|
||||
using store<3,T,SelfT>::store;
|
||||
constexpr init () = default;
|
||||
constexpr init (T v0, T v1, T v2):
|
||||
store<3,T,tags...> ({v0, v1, v2})
|
||||
store<3,T,SelfT> ({v0, v1, v2})
|
||||
{ ; }
|
||||
};
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
template <typename T, typename ...tags>
|
||||
struct init<4,T,tags...> : public store<4,T,tags...>
|
||||
template <typename T, typename SelfT>
|
||||
struct init<4,T,SelfT> : public store<4,T,SelfT>
|
||||
{
|
||||
using store<4,T,tags...>::store;
|
||||
using store<4,T,SelfT>::store;
|
||||
constexpr init () = default;
|
||||
constexpr init (T v0, T v1, T v2, T v3):
|
||||
store<4,T,tags...> ({ v0, v1, v2, v3 })
|
||||
store<4,T,SelfT> ({ v0, v1, v2, v3 })
|
||||
{ ; }
|
||||
};
|
||||
}
|
||||
|
@ -24,8 +24,8 @@
|
||||
|
||||
namespace util {
|
||||
template <
|
||||
template <size_t,typename> class K,
|
||||
size_t S,
|
||||
template <std::size_t,typename> class K,
|
||||
std::size_t S,
|
||||
typename T
|
||||
>
|
||||
std::ostream&
|
||||
|
@ -1,42 +0,0 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Copyright 2015 Danny Robson <danny@nerdcruft.net>
|
||||
*/
|
||||
|
||||
#ifndef __UTIL_COORD_NAMES_HPP
|
||||
#define __UTIL_COORD_NAMES_HPP
|
||||
|
||||
namespace util::coord {
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// tags for accessor names
|
||||
//
|
||||
// colours
|
||||
struct rgba { };
|
||||
struct hsv { };
|
||||
|
||||
// physical positions
|
||||
struct xyzw { };
|
||||
|
||||
// texture coords
|
||||
struct stpq { };
|
||||
|
||||
// physical dimensions
|
||||
struct whd { };
|
||||
|
||||
// quaternions
|
||||
struct wxyz { };
|
||||
struct abcd { };
|
||||
}
|
||||
|
||||
#endif
|
750
coord/ops.hpp
750
coord/ops.hpp
File diff suppressed because it is too large
Load Diff
230
coord/store.hpp
230
coord/store.hpp
@ -11,17 +11,18 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Copyright 2015 Danny Robson <danny@nerdcruft.net>
|
||||
* Copyright 2015-2017 Danny Robson <danny@nerdcruft.net>
|
||||
*/
|
||||
|
||||
#ifndef __UTIL_COORD_STORE_HPP
|
||||
#define __UTIL_COORD_STORE_HPP
|
||||
|
||||
#include "names.hpp"
|
||||
#include "fwd.hpp"
|
||||
|
||||
#include "../preprocessor.hpp"
|
||||
#include "../platform.hpp"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstddef>
|
||||
#include <type_traits>
|
||||
|
||||
|
||||
@ -55,156 +56,79 @@ namespace util::coord::detail {
|
||||
#define SIMD_ALIGN(S,T) alignas (util::coord::detail::alignment<T> (S))
|
||||
|
||||
|
||||
namespace util::coord {
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Coordinate storage class.
|
||||
//
|
||||
// Types with trivially suitable arity are aligned appropriately to take
|
||||
// advantage of native platform SIMD. eg, 4f types are aligned to 16 bytes
|
||||
// on SSE platforms.
|
||||
template <
|
||||
size_t S,
|
||||
typename T,
|
||||
typename...
|
||||
>
|
||||
struct
|
||||
SIMD_ALIGN(S,T)
|
||||
store {
|
||||
T data[S];
|
||||
};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
template <typename T>
|
||||
struct store<3,T,rgba,hsv> {
|
||||
union {
|
||||
T data[3];
|
||||
struct { T r,g,b; };
|
||||
struct { T h,s,v; };
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
// Align on 16 bytes if the data is at least 16 bytes long. Prevents tiny
|
||||
// types like colour4u requiring massive alignments, reduces internal
|
||||
// fragmentation.
|
||||
//
|
||||
// TODO: expand this for other instruction sets. maybe switch on type.
|
||||
template <typename T>
|
||||
struct
|
||||
SIMD_ALIGN(4,T)
|
||||
store<4,T,rgba,hsv> {
|
||||
union {
|
||||
T data[4];
|
||||
struct { T r,g,b,a; };
|
||||
struct { T h,s,v; };
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
template <typename T>
|
||||
struct store<2,T,xyzw> {
|
||||
union {
|
||||
T data[2];
|
||||
struct { T x,y; };
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
struct store<3,T,xyzw> {
|
||||
union {
|
||||
T data[3];
|
||||
struct { T x,y,z; };
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
// Align on 16 bytes if the data is at least 16 bytes long. Prevents tiny
|
||||
// types like colour4u requiring massive alignments, reduces internal
|
||||
// fragmentation.
|
||||
//
|
||||
// TODO: expand this for other instruction sets. maybe switch on type.
|
||||
template <typename T>
|
||||
struct
|
||||
SIMD_ALIGN(4,T)
|
||||
store<4,T,xyzw> {
|
||||
union {
|
||||
T data[4];
|
||||
struct { T x,y,z,w; };
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
template <typename T>
|
||||
struct store<2,T,xyzw,stpq> {
|
||||
union {
|
||||
T data[2];
|
||||
struct { T x,y; };
|
||||
struct { T s,t; };
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
struct store<3,T,xyzw,stpq> {
|
||||
union {
|
||||
T data[3];
|
||||
struct { T x,y,z; };
|
||||
struct { T s,t,p; };
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
// Align on 16 bytes if the data is at least 16 bytes long. Prevents tiny
|
||||
// types like colour4u requiring massive alignments, reduces internal
|
||||
// fragmentation.
|
||||
//
|
||||
// TODO: expand this for other instruction sets. maybe switch on type.
|
||||
template <typename T>
|
||||
struct
|
||||
SIMD_ALIGN(4,T)
|
||||
store<4,T,xyzw,stpq> {
|
||||
union {
|
||||
T data[4];
|
||||
struct { T x,y,z,w; };
|
||||
struct { T s,t,p,q; };
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
template <typename T>
|
||||
struct store<2,T,whd> {
|
||||
union {
|
||||
T data[2];
|
||||
struct { T w,h; };
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
struct store<3,T,whd> {
|
||||
union {
|
||||
T data[3];
|
||||
struct { T w,h,d; };
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
template <typename T>
|
||||
struct
|
||||
SIMD_ALIGN(4,T)
|
||||
store<4,T,wxyz,abcd> {
|
||||
union {
|
||||
T data[4];
|
||||
struct { T w,x,y,z; };
|
||||
struct { T a,b,c,d; };
|
||||
};
|
||||
};
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// defines the named member variables that a coordinate type is composed of
|
||||
#define DEFINE_COORD_STORE(TAG,...) \
|
||||
namespace util::coord { \
|
||||
template <typename T> \
|
||||
struct store< \
|
||||
VA_ARGS_COUNT(__VA_ARGS__), \
|
||||
T, \
|
||||
TAG \
|
||||
> { \
|
||||
union { \
|
||||
struct { \
|
||||
T __VA_ARGS__; \
|
||||
}; \
|
||||
T data[VA_ARGS_COUNT(__VA_ARGS__)]; \
|
||||
}; \
|
||||
}; \
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
struct util::coord::store<1,T,::util::extent<1,T>> {
|
||||
union { struct { T w; }; T data[1]; };
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct util::coord::store<2,T,::util::extent<2,T>> {
|
||||
union { struct { T w, h; }; T data[2]; };
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct util::coord::store<3,T,::util::extent<3,T>> {
|
||||
union { struct { T w, h, d; }; T data[3]; };
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct util::coord::store<1,T,::util::point<1,T>> {
|
||||
union { struct { T x; }; T data[1]; };
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct util::coord::store<2,T,::util::point<2,T>> {
|
||||
union { struct { T x, y; }; T data[2]; };
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct util::coord::store<3,T,::util::point<3,T>> {
|
||||
union { struct { T x, y, z; }; T data[3]; };
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct util::coord::store<4,T,::util::point<4,T>> {
|
||||
union { struct { T x, y, z, w; }; T data[4]; };
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct util::coord::store<1,T,::util::vector<1,T>> {
|
||||
union { struct { T x; }; T data[1]; };
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct util::coord::store<2,T,::util::vector<2,T>> {
|
||||
union { struct { T x, y; }; T data[2]; };
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct util::coord::store<3,T,::util::vector<3,T>> {
|
||||
union { struct { T x, y, z; }; T data[3]; };
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct util::coord::store<4,T,::util::vector<4,T>> {
|
||||
union { struct { T x, y, z, w; }; T data[4]; };
|
||||
};
|
||||
|
||||
#endif
|
||||
|
170
coord/traits.hpp
Normal file
170
coord/traits.hpp
Normal file
@ -0,0 +1,170 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Copyright 2012-2017 Danny Robson <danny@nerdcruft.net>
|
||||
*/
|
||||
|
||||
#ifndef CRUFT_UTIL_COORD_TRAITS_HPP
|
||||
#define CRUFT_UTIL_COORD_TRAITS_HPP
|
||||
|
||||
#include "fwd.hpp"
|
||||
|
||||
#include <cstddef>
|
||||
#include <type_traits>
|
||||
|
||||
namespace util {
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// operation traits
|
||||
template <typename, typename>
|
||||
struct result { };
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
template <std::size_t S, typename T> struct result<srgba<S,T>,srgba<S,T>> { using type = srgba<S,T>; };
|
||||
template <std::size_t S, typename T> struct result<srgba<S,T>,vector<S,T>> { using type = srgba<S,T>; };
|
||||
template <std::size_t S, typename T> struct result<vector<S,T>,srgba<S,T>> { using type = srgba<S,T>; };
|
||||
template <std::size_t S, typename T> struct result<extent<S,T>,extent<S,T>> { using type = extent<S,T>; };
|
||||
template <std::size_t S, typename T> struct result<extent<S,T>,vector<S,T>> { using type = extent<S,T>; };
|
||||
template <std::size_t S, typename T> struct result<point<S,T>,extent<S,T>> { using type = point <S,T>; };
|
||||
template <std::size_t S, typename T> struct result<point<S,T>,vector<S,T>> { using type = point <S,T>; };
|
||||
template <std::size_t S, typename T> struct result<vector<S,T>,point<S,T>> { using type = point <S,T>; };
|
||||
template <std::size_t S, typename T> struct result<vector<S,T>,vector<S,T>> { using type = vector<S,T>; };
|
||||
|
||||
template <
|
||||
typename A, typename B
|
||||
>
|
||||
using result_t = typename result<A,B>::type;
|
||||
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
template <typename>
|
||||
struct has_norm : public std::false_type { };
|
||||
|
||||
template <std::size_t S, typename T> struct has_norm<vector<S,T>> : public std::true_type { };
|
||||
|
||||
template <typename T>
|
||||
constexpr auto has_norm_v = has_norm<T>::value;
|
||||
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
template <typename T>
|
||||
struct has_scalar_op : public std::false_type { };
|
||||
|
||||
template <std::size_t S, typename T> struct has_scalar_op<srgba<S,T>> : public std::true_type { };
|
||||
template <std::size_t S, typename T> struct has_scalar_op<extent<S,T>> : public std::true_type { };
|
||||
template <std::size_t S, typename T> struct has_scalar_op<point<S,T>> : public std::true_type { };
|
||||
template <std::size_t S, typename T> struct has_scalar_op<vector<S,T>> : public std::true_type { };
|
||||
|
||||
template <typename T>
|
||||
constexpr auto has_scalar_op_v = has_scalar_op<T>::value;
|
||||
|
||||
|
||||
template <class> struct is_coord : std::false_type { };
|
||||
|
||||
template <typename T> struct is_coord<const T> : is_coord<T> {};
|
||||
template <typename T> struct is_coord<T&> : is_coord<T> {};
|
||||
|
||||
template <std::size_t S, typename T> struct is_coord<point<S,T>> : std::true_type { };
|
||||
template <std::size_t S, typename T> struct is_coord<extent<S,T>> : std::true_type { };
|
||||
template <std::size_t S, typename T> struct is_coord<vector<S,T>> : std::true_type { };
|
||||
template <std::size_t S, typename T> struct is_coord<srgba<S,T>> : std::true_type { };
|
||||
|
||||
template <class K>
|
||||
constexpr bool
|
||||
is_coord_v = is_coord<K>::value;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
template <typename T> struct has_redim : std::false_type {};
|
||||
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
template <std::size_t S, typename T> struct has_redim< point<S,T>> : public std::true_type {};
|
||||
template <std::size_t S, typename T> struct has_redim<vector<S,T>> : public std::true_type {};
|
||||
template <std::size_t S, typename T> struct has_redim<extent<S,T>> : public std::true_type {};
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
template <typename T> constexpr auto has_redim_v = has_redim<T>::value;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
template <typename> struct redim_type {};
|
||||
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
template <std::size_t S, typename T> struct redim_type<point<S,T>>
|
||||
{ template <std::size_t _S> using type = point<_S,T>; };
|
||||
|
||||
template <std::size_t S, typename T> struct redim_type<vector<S,T>>
|
||||
{ template <std::size_t _S> using type = vector<_S,T>; };
|
||||
|
||||
template <std::size_t S, typename T> struct redim_type<extent<S,T>>
|
||||
{ template <std::size_t _S> using type = extent<_S,T>; };
|
||||
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
template <
|
||||
typename Self,
|
||||
std::size_t S
|
||||
>
|
||||
using redim_t = typename redim_type<Self>::template type<S>;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
template <typename> struct revalue_type {};
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
template <std::size_t S, typename T>
|
||||
struct revalue_type<point<S,T>> {
|
||||
template <typename _T> using type = point<S,_T>;
|
||||
};
|
||||
|
||||
template <std::size_t S, typename T>
|
||||
struct revalue_type<vector<S,T>> {
|
||||
template <typename _T> using type = vector<S,_T>;
|
||||
};
|
||||
|
||||
template <std::size_t S, typename T>
|
||||
struct revalue_type<extent<S,T>> {
|
||||
template <typename _T> using type = extent<S,_T>;
|
||||
};
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
template <typename Self, typename T>
|
||||
using revalue_t = typename revalue_type<Self>::template type<T>;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
template <typename,typename=void> struct arity {};
|
||||
|
||||
|
||||
template <typename T>
|
||||
struct arity<T,std::enable_if_t<std::is_arithmetic_v<T>,void>
|
||||
> :std::integral_constant<std::size_t, 1>
|
||||
{ };
|
||||
|
||||
|
||||
template <typename T>
|
||||
struct arity<
|
||||
T,std::enable_if_t<is_coord_v<T>,void>
|
||||
> :std::integral_constant<std::size_t,T::elements>
|
||||
{ };
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
template <typename T>
|
||||
constexpr auto arity_v = arity<T>::value;
|
||||
}
|
||||
|
||||
#endif
|
@ -187,9 +187,9 @@ namespace util::debug {
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
#define INSTANTIATE_S_T(S,T) \
|
||||
template struct util::extent<S,T>; \
|
||||
template bool util::debug::is_valid (const extent<S,T>&); \
|
||||
template struct util::debug::validator<extent<S,T>>;
|
||||
template struct ::util::extent<S,T>; \
|
||||
template bool ::util::debug::is_valid (const ::util::extent<S,T>&); \
|
||||
template struct ::util::debug::validator<::util::extent<S,T>>;
|
||||
|
||||
#define INSTANTIATE(T) \
|
||||
INSTANTIATE_S_T(1,T) \
|
||||
|
32
extent.hpp
32
extent.hpp
@ -17,22 +17,24 @@
|
||||
#ifndef __UTIL_EXTENT_HPP
|
||||
#define __UTIL_EXTENT_HPP
|
||||
|
||||
#include "coord/fwd.hpp"
|
||||
#include "coord/base.hpp"
|
||||
#include "vector.hpp"
|
||||
#include "point.hpp"
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
namespace util {
|
||||
/**
|
||||
* A pure two-dimensional size, without positioning
|
||||
* A pure n-dimensional size, without positioning
|
||||
*/
|
||||
template <size_t S, typename T>
|
||||
struct extent : public coord::base<S,T,extent,coord::whd>
|
||||
struct extent : public ::util::coord::base<S,T,::util::extent<S,T>>
|
||||
{
|
||||
using coord::base<S,T,util::extent,coord::whd>::base;
|
||||
using ::util::coord::base<S,T,::util::extent<S,T>>::base;
|
||||
|
||||
extent () = default;
|
||||
explicit extent (vector<S,T>);
|
||||
explicit extent (::util::vector<S,T>);
|
||||
|
||||
constexpr T area (void) const;
|
||||
constexpr T diameter (void) const;
|
||||
@ -42,25 +44,29 @@ namespace util {
|
||||
U aspect (void) const;
|
||||
|
||||
template <typename U>
|
||||
bool includes (util::point<S,U>) const;
|
||||
bool includes (::util::point<S,U>) const;
|
||||
|
||||
extent expanded (vector<S,T>) const;
|
||||
extent expanded (T) const;
|
||||
extent contracted (vector<S,T>) const;
|
||||
extent contracted (T) const;
|
||||
::util::extent<S,T> expanded (::util::vector<S,T>) const;
|
||||
::util::extent<S,T> expanded (T) const;
|
||||
::util::extent<S,T> contracted (::util::vector<S,T>) const;
|
||||
::util::extent<S,T> contracted (T) const;
|
||||
|
||||
bool empty (void) const;
|
||||
|
||||
static constexpr extent max (void);
|
||||
static constexpr extent min (void);
|
||||
static constexpr ::util::extent<S,T> max (void);
|
||||
static constexpr ::util::extent<S,T> min (void);
|
||||
};
|
||||
|
||||
template <size_t S, typename T>
|
||||
struct extent_range {
|
||||
public:
|
||||
struct iterator : public std::iterator<std::forward_iterator_tag, point<S,T>, size_t> {
|
||||
struct iterator : public std::iterator<
|
||||
std::forward_iterator_tag,
|
||||
::util::point<S,T>,
|
||||
size_t
|
||||
> {
|
||||
public:
|
||||
iterator (extent<S,T>, util::point<S,T>);
|
||||
iterator (::util::extent<S,T>, ::util::point<S,T>);
|
||||
|
||||
point<S,T> operator* () const;
|
||||
iterator& operator++ (void);
|
||||
|
@ -83,92 +83,6 @@ AABB<S,T>::closest (point<S,T> q) const
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <size_t S, typename T>
|
||||
AABB<S,T>&
|
||||
AABB<S,T>::expand (util::vector<S,T> mag)
|
||||
{
|
||||
p0 -= mag / T{2};
|
||||
p1 += mag / T{2};
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <size_t S, typename T>
|
||||
AABB<S,T>&
|
||||
AABB<S,T>::expand (T t)
|
||||
{
|
||||
return expand (vector<S,T> {t});
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <size_t S, typename T>
|
||||
AABB<S,T>
|
||||
AABB<S,T>::expanded (vector<S,T> mag)
|
||||
{
|
||||
auto ret = *this;
|
||||
ret.expand (mag);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <size_t S, typename T>
|
||||
AABB<S,T>
|
||||
AABB<S,T>::expanded (T t)
|
||||
{
|
||||
return expanded (vector<S,T> {t});
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <size_t S, typename T>
|
||||
AABB<S,T>&
|
||||
AABB<S,T>::contract (util::vector<S,T> mag)
|
||||
{
|
||||
// Avoid contracting magnitudes larger than our extent
|
||||
auto diff = p1 - p0;
|
||||
auto delta = min (diff, mag);
|
||||
|
||||
p0 += delta / T{2};
|
||||
p1 -= delta / T{2};
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <size_t S, typename T>
|
||||
AABB<S,T>&
|
||||
AABB<S,T>::contract (T mag)
|
||||
{
|
||||
return contract (util::vector<S,T> {mag});
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <size_t S, typename T>
|
||||
AABB<S,T>
|
||||
AABB<S,T>::contracted (util::vector<S,T> mag) const
|
||||
{
|
||||
AABB<S,T> res = *this;
|
||||
res.contract (mag);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <size_t S, typename T>
|
||||
AABB<S,T>
|
||||
AABB<S,T>::contracted (T mag) const
|
||||
{
|
||||
return contracted (vector<S,T> {mag});
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <size_t S, typename T>
|
||||
void
|
||||
|
@ -36,16 +36,6 @@ namespace util::geom {
|
||||
|
||||
point<S,T> closest (point<S,T>) const;
|
||||
|
||||
AABB<S,T>& expand (util::vector<S,T>);
|
||||
AABB<S,T>& expand (T);
|
||||
AABB<S,T> expanded (util::vector<S,T>);
|
||||
AABB<S,T> expanded (T);
|
||||
|
||||
AABB<S,T>& contract (util::vector<S,T>);
|
||||
AABB<S,T>& contract (T);
|
||||
AABB<S,T> contracted (util::vector<S,T>) const;
|
||||
AABB<S,T> contracted (T) const;
|
||||
|
||||
void cover (point<S,T>);
|
||||
|
||||
AABB<S,T> operator+ (vector<S,T>) const;
|
||||
@ -53,8 +43,8 @@ namespace util::geom {
|
||||
|
||||
bool operator== (AABB) const;
|
||||
|
||||
point<S,T> p0;
|
||||
point<S,T> p1;
|
||||
::util::point<S,T> p0;
|
||||
::util::point<S,T> p1;
|
||||
};
|
||||
|
||||
typedef AABB<2,float> AABB2f;
|
||||
|
@ -24,8 +24,7 @@ using util::geom::plane;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <size_t S, typename T>
|
||||
plane<S,T>::plane (point<S,T> _p,
|
||||
vector<S,T> _n):
|
||||
plane<S,T>::plane (point<S,T> _p, vector<S,T> _n):
|
||||
p (_p),
|
||||
n (_n)
|
||||
{
|
||||
|
@ -23,11 +23,10 @@
|
||||
namespace util::geom {
|
||||
template <size_t S, typename T>
|
||||
struct plane {
|
||||
plane (util::point<S,T> p,
|
||||
util::vector<S,T> n);
|
||||
plane (util::point<S,T>, util::vector<S,T>);
|
||||
|
||||
util::point<S,T> p;
|
||||
util::vector<S,T> n;
|
||||
::util::point<S,T> p;
|
||||
::util::vector<S,T> n;
|
||||
};
|
||||
|
||||
|
||||
|
@ -48,9 +48,8 @@ bsdsum::update (const void *restrict data, size_t size) noexcept
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
void
|
||||
bsdsum::update (
|
||||
const uint8_t *const restrict first,
|
||||
const uint8_t *const restrict last) noexcept
|
||||
bsdsum::update (const uint8_t *const restrict first,
|
||||
const uint8_t *const restrict last) noexcept
|
||||
{
|
||||
CHECK (first);
|
||||
CHECK (last);
|
||||
|
@ -203,7 +203,7 @@ namespace util {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
template <typename T>
|
||||
T
|
||||
std::enable_if_t<std::is_arithmetic_v<T>, T>
|
||||
abs [[gnu::const]] (T t)
|
||||
{
|
||||
return t > 0 ? t : -t;
|
||||
@ -604,9 +604,9 @@ namespace util {
|
||||
//-------------------------------------------------------------------------
|
||||
/// Variadic maximum
|
||||
template <typename T>
|
||||
constexpr T
|
||||
constexpr std::enable_if_t<std::is_arithmetic_v<T>, T>
|
||||
max (const T a)
|
||||
{ return a; }
|
||||
{ return a; }
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
115
matrix.cpp
115
matrix.cpp
@ -27,7 +27,7 @@ using util::matrix;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <size_t Rows, size_t Cols, typename T>
|
||||
template <std::size_t Rows, std::size_t Cols, typename T>
|
||||
matrix<Rows,Cols,T>&
|
||||
matrix<Rows,Cols,T>::invert (void)
|
||||
{
|
||||
@ -36,7 +36,7 @@ matrix<Rows,Cols,T>::invert (void)
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//template <size_t S, typename T>
|
||||
//template <std::size_t S, typename T>
|
||||
//matrix<S,T>&
|
||||
//matrix<S,T>::invert_affine (void)
|
||||
//{
|
||||
@ -85,7 +85,7 @@ matrix<Rows,Cols,T>::invert (void)
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <size_t Rows, size_t Cols, typename T>
|
||||
template <std::size_t Rows, std::size_t Cols, typename T>
|
||||
T
|
||||
util::matrix<Rows,Cols,T>::determinant (void) const
|
||||
{
|
||||
@ -94,7 +94,7 @@ util::matrix<Rows,Cols,T>::determinant (void) const
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <size_t Rows, size_t Cols, typename T>
|
||||
template <std::size_t Rows, std::size_t Cols, typename T>
|
||||
util::matrix<Rows,Cols,T>
|
||||
util::matrix<Rows,Cols,T>::inverse (void) const
|
||||
{
|
||||
@ -103,14 +103,14 @@ util::matrix<Rows,Cols,T>::inverse (void) const
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <size_t Rows, size_t Cols, typename T>
|
||||
template <std::size_t Rows, std::size_t Cols, typename T>
|
||||
matrix<Cols,Rows,T>
|
||||
util::transposed (const matrix<Rows,Cols,T> &m)
|
||||
{
|
||||
util::matrix<Cols,Rows,T> res;
|
||||
|
||||
for (size_t y = 0; y < Rows; ++y)
|
||||
for (size_t x = 0; x < Cols; ++x)
|
||||
for (std::size_t y = 0; y < Rows; ++y)
|
||||
for (std::size_t x = 0; x < Cols; ++x)
|
||||
res[y][x] = m[x][y];
|
||||
|
||||
return res;
|
||||
@ -123,42 +123,14 @@ template util::matrix4f util::transposed (const matrix4f&);
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <size_t Rows, size_t Cols, typename T>
|
||||
util::vector<Rows,T>
|
||||
matrix<Rows,Cols,T>::operator* (const vector<Rows,T> &rhs) const
|
||||
{
|
||||
vector<Rows,T> out;
|
||||
|
||||
for (size_t i = 0; i < Rows; ++i)
|
||||
out[i] = dot (rhs, values[i]);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <size_t Rows, size_t Cols, typename T>
|
||||
util::point<Rows,T>
|
||||
matrix<Rows,Cols,T>::operator* (const point<Rows,T> &rhs) const
|
||||
{
|
||||
point<Rows,T> out;
|
||||
|
||||
for (size_t i = 0; i < Rows; ++i)
|
||||
out[i] = dot (rhs, values[i]);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <size_t Rows, size_t Cols, typename T>
|
||||
template <std::size_t Rows, std::size_t Cols, typename T>
|
||||
bool
|
||||
matrix<Rows,Cols,T>::is_affine (void) const
|
||||
{
|
||||
if (Rows != Cols)
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < Rows - 1; ++i)
|
||||
for (std::size_t i = 0; i < Rows - 1; ++i)
|
||||
if (!exactly_zero (values[Rows-1][i]))
|
||||
return false;
|
||||
|
||||
@ -167,11 +139,11 @@ matrix<Rows,Cols,T>::is_affine (void) const
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <size_t Rows, size_t Cols, typename T>
|
||||
template <typename T>
|
||||
util::matrix4<T>
|
||||
matrix<Rows,Cols,T>::ortho (T left, T right,
|
||||
T bottom, T top,
|
||||
T near, T far)
|
||||
util::ortho (T left, T right,
|
||||
T bottom, T top,
|
||||
T near, T far)
|
||||
{
|
||||
CHECK_GT (far, near);
|
||||
|
||||
@ -183,29 +155,29 @@ matrix<Rows,Cols,T>::ortho (T left, T right,
|
||||
T tb = 2 / (top - bottom);
|
||||
T fn = 2 / (far - near);
|
||||
|
||||
return { {
|
||||
return {{
|
||||
{ rl, 0, 0, tx },
|
||||
{ 0, tb, 0, ty },
|
||||
{ 0, 0, fn, tz },
|
||||
{ 0, 0, 0, 1 },
|
||||
} };
|
||||
}};
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <size_t Rows, size_t Cols, typename T>
|
||||
template <typename T>
|
||||
util::matrix4<T>
|
||||
matrix<Rows, Cols,T>::ortho2D (T left , T right,
|
||||
T bottom, T top)
|
||||
util::ortho2D (T left, T right,
|
||||
T bottom, T top)
|
||||
{
|
||||
return ortho (left, right, bottom, top, -1, 1);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <size_t Rows, size_t Cols, typename T>
|
||||
template <typename T>
|
||||
util::matrix4<T>
|
||||
matrix<Rows,Cols,T>::perspective (T fov, T aspect, range<T> Z)
|
||||
util::perspective (T fov, T aspect, range<T> Z)
|
||||
{
|
||||
CHECK_GE (Z.lo, 0);
|
||||
CHECK_GE (Z.hi, 0);
|
||||
@ -234,11 +206,11 @@ matrix<Rows,Cols,T>::perspective (T fov, T aspect, range<T> Z)
|
||||
// Implemented for right handed world coordinates.
|
||||
//
|
||||
// Assumes 'up' is normalised.
|
||||
template <size_t Rows, size_t Cols, typename T>
|
||||
template <typename T>
|
||||
util::matrix4<T>
|
||||
matrix<Rows,Cols,T>::look_at (const util::point<3,T> eye,
|
||||
const util::point<3,T> centre,
|
||||
const util::vector<3,T> up)
|
||||
util::look_at (const util::point<3,T> eye,
|
||||
const util::point<3,T> centre,
|
||||
const util::vector<3,T> up)
|
||||
{
|
||||
CHECK (is_normalised (up));
|
||||
|
||||
@ -253,23 +225,16 @@ matrix<Rows,Cols,T>::look_at (const util::point<3,T> eye,
|
||||
{ 0, 0, 0, 1 },
|
||||
}};
|
||||
|
||||
return rot * util::matrix4<T>::translation (0-eye);
|
||||
return rot * util::translation<T> (0-eye);
|
||||
}
|
||||
|
||||
template util::matrix4f util::look_at (util::point3f, util::point3f, util::vector3f);
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <size_t Rows, size_t Cols, typename T>
|
||||
template <typename T>
|
||||
util::matrix4<T>
|
||||
matrix<Rows,Cols,T>::translation (util::vector<2,T> v)
|
||||
{
|
||||
return translation ({v.x, v.y, 0});
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <size_t Rows, size_t Cols, typename T>
|
||||
util::matrix4<T>
|
||||
matrix<Rows,Cols,T>::translation (util::vector<3,T> v)
|
||||
util::translation (util::vector<3,T> v)
|
||||
{
|
||||
return { {
|
||||
{ 1.f, 0.f, 0.f, v.x },
|
||||
@ -280,18 +245,21 @@ matrix<Rows,Cols,T>::translation (util::vector<3,T> v)
|
||||
}
|
||||
|
||||
|
||||
template util::matrix4f util::translation (util::vector3f);
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <size_t Rows, size_t Cols, typename T>
|
||||
template <typename T>
|
||||
util::matrix4<T>
|
||||
matrix<Rows,Cols,T>::scale (T mag)
|
||||
util::scale (T mag)
|
||||
{
|
||||
return scale (vector<3,T> (mag));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <size_t Rows, size_t Cols, typename T>
|
||||
template <typename T>
|
||||
util::matrix4<T>
|
||||
matrix<Rows,Cols,T>::scale (util::vector<3,T> v)
|
||||
util::scale (util::vector<3,T> v)
|
||||
{
|
||||
return { {
|
||||
{ v.x, 0.f, 0.f, 0.f },
|
||||
@ -303,9 +271,9 @@ matrix<Rows,Cols,T>::scale (util::vector<3,T> v)
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <size_t Rows, size_t Cols, typename T>
|
||||
template <typename T>
|
||||
util::matrix4<T>
|
||||
matrix<Rows,Cols,T>::rotation (T angle, util::vector<3,T> about)
|
||||
util::rotation (T angle, util::vector<3,T> about)
|
||||
{
|
||||
CHECK (is_normalised (about));
|
||||
|
||||
@ -338,6 +306,7 @@ matrix<Rows,Cols,T>::rotation (T angle, util::vector<3,T> about)
|
||||
} };
|
||||
}
|
||||
|
||||
template util::matrix4f util::rotation (float, util::vector3f);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template struct util::matrix<2,2,float>;
|
||||
@ -354,7 +323,7 @@ template struct util::matrix<4,4,double>;
|
||||
// Uses the algorithm from:
|
||||
// "Extracting Euler Angles from a Rotation Matrix" by
|
||||
// Mike Day, Insomniac Games.
|
||||
template <size_t Rows, size_t Cols, typename T>
|
||||
template <std::size_t Rows, std::size_t Cols, typename T>
|
||||
util::vector<3,T>
|
||||
util::to_euler (const matrix<Rows,Cols,T> &m)
|
||||
{
|
||||
@ -383,13 +352,13 @@ template util::vector<3,float> util::to_euler (const matrix<4,4,float>&);
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <size_t Rows, size_t Cols, typename T>
|
||||
template <std::size_t Rows, std::size_t Cols, typename T>
|
||||
std::ostream&
|
||||
util::operator<< (std::ostream &os, const matrix<Rows,Cols,T> &m)
|
||||
{
|
||||
os << "{ ";
|
||||
|
||||
for (size_t i = 0; i < Rows; ++i) {
|
||||
for (std::size_t i = 0; i < Rows; ++i) {
|
||||
os << "{ ";
|
||||
std::copy_n (m[i], Cols, util::infix_iterator<float> (os, ", "));
|
||||
os << ((i == Rows - 1) ? " }" : " }, ");
|
||||
|
172
matrix.hpp
172
matrix.hpp
@ -19,23 +19,43 @@
|
||||
|
||||
#include "point.hpp"
|
||||
#include "range.hpp"
|
||||
#include "vector.hpp"
|
||||
|
||||
#include <ostream>
|
||||
#include <cstdlib>
|
||||
|
||||
namespace util {
|
||||
template <size_t Rows, size_t Cols, typename T>
|
||||
template <std::size_t Rows, std::size_t Cols, typename T>
|
||||
struct matrix {
|
||||
static constexpr auto rows = Rows;
|
||||
static constexpr auto cols = Cols;
|
||||
|
||||
T values[Rows][Cols];
|
||||
constexpr matrix () noexcept = default;
|
||||
|
||||
constexpr matrix (const T(&_data)[Rows][Cols]) noexcept:
|
||||
values {}
|
||||
{
|
||||
for (std::size_t r = 0; r < Rows; ++r)
|
||||
for (std::size_t c = 0; c < Cols; ++c)
|
||||
values[r][c] = _data[r][c];
|
||||
}
|
||||
|
||||
|
||||
template <std::size_t S, typename SelfT>
|
||||
constexpr matrix (const util::coord::base<S,T,SelfT> (&_data)[Rows]) noexcept
|
||||
{
|
||||
for (std::size_t r = 0; r < Rows; ++r)
|
||||
for (std::size_t c = 0; c < Cols; ++c)
|
||||
values[r][c] = _data[r][c];
|
||||
}
|
||||
|
||||
T values[rows][cols];
|
||||
|
||||
// index operators return a pointer into the data array so that
|
||||
// multidimensional array syntax can be used transparently on this
|
||||
// type.
|
||||
T* operator[] (size_t);
|
||||
const T* operator[] (size_t) const;
|
||||
constexpr auto& operator[] (std::size_t idx) { return values[idx]; }
|
||||
constexpr const auto& operator[] (std::size_t idx) const { return values[idx]; }
|
||||
|
||||
T* data (void);
|
||||
const T* data (void) const;
|
||||
@ -54,8 +74,18 @@ namespace util {
|
||||
matrix inverse_affine (void) const;
|
||||
matrix& invert_affine (void);
|
||||
|
||||
vector<Rows,T> operator* (const vector<Rows,T>&) const;
|
||||
point<Rows,T> operator* (const point<Rows,T> &) const;
|
||||
|
||||
template <typename VectorT>
|
||||
std::enable_if_t<is_coord_v<VectorT>, VectorT>
|
||||
operator* (const VectorT &rhs) const
|
||||
{
|
||||
VectorT out;
|
||||
|
||||
for (std::size_t i = 0; i < Rows; ++i)
|
||||
out[i] = dot (rhs, values[i]);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
bool is_affine (void) const;
|
||||
|
||||
@ -63,44 +93,44 @@ namespace util {
|
||||
matrix<Rows,Cols,U>
|
||||
cast (void) const;
|
||||
|
||||
// Perspective matrices
|
||||
static matrix<4,4,T> ortho (T left, T right, T bottom, T top, T near, T far);
|
||||
static matrix<4,4,T> ortho2D (T left, T right, T bottom, T top);
|
||||
static matrix<4,4,T> perspective (T fov, T aspect, range<T> Z);
|
||||
static matrix<4,4,T> look_at (point<3,T> eye, point<3,T> target, vector<3,T> up);
|
||||
|
||||
// Affine matrices
|
||||
static matrix<4,4,T> translation (util::vector<2,T>);
|
||||
static matrix<4,4,T> translation (util::vector<3,T>);
|
||||
static matrix<4,4,T> scale (util::vector<3,T>);
|
||||
static matrix<4,4,T> scale (T);
|
||||
static matrix<4,4,T> rotation (T angle, util::vector<3,T> about);
|
||||
|
||||
// Constant matrices
|
||||
static constexpr matrix identity ();
|
||||
static constexpr matrix zeroes ();
|
||||
};
|
||||
|
||||
|
||||
// Perspective matrices
|
||||
template <typename T> matrix<4,4,T> ortho (T left, T right, T bottom, T top, T near, T far);
|
||||
template <typename T> matrix<4,4,T> ortho2D (T left, T right, T bottom, T top);
|
||||
template <typename T> matrix<4,4,T> perspective (T fov, T aspect, range<T> Z);
|
||||
template <typename T> matrix<4,4,T> look_at (point<3,T> eye, point<3,T> target, vector<3,T> up);
|
||||
|
||||
// Affine matrices
|
||||
template <typename T> matrix<4,4,T> translation (util::vector<3,T>);
|
||||
template <typename T> matrix<4,4,T> scale (util::vector<3,T>);
|
||||
template <typename T> matrix<4,4,T> scale (T);
|
||||
template <typename T> matrix<4,4,T> rotation (T angle, util::vector<3,T> about);
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Convert an affine rotation matrix to euler angles.
|
||||
//
|
||||
// Results are undefined if the matrix is not purely a rotation matrix,
|
||||
// or if the dimension is not 3x3 or 4x4.
|
||||
template <size_t Rows, size_t Cols, typename T>
|
||||
template <std::size_t Rows, std::size_t Cols, typename T>
|
||||
vector<3,T>
|
||||
to_euler (const matrix<Rows, Cols, T>&);
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// logical operations
|
||||
template <size_t Rows, size_t Cols, typename T>
|
||||
template <std::size_t Rows, std::size_t Cols, typename T>
|
||||
constexpr
|
||||
bool
|
||||
operator== (const matrix<Rows,Cols,T>&, const matrix<Rows,Cols,T>&);
|
||||
|
||||
|
||||
template <size_t Rows, size_t Cols, typename T>
|
||||
template <std::size_t Rows, std::size_t Cols, typename T>
|
||||
constexpr
|
||||
bool
|
||||
operator!= (const matrix<Rows,Cols,T>&, const matrix<Rows,Cols,T>&);
|
||||
@ -108,51 +138,95 @@ namespace util {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// element operations
|
||||
template <size_t Rows, size_t Cols, typename T>
|
||||
template <std::size_t Rows, std::size_t Cols, typename T>
|
||||
constexpr
|
||||
matrix<Rows,Cols,T>
|
||||
operator+ (const matrix<Rows,Cols,T>&, const matrix<Rows,Cols,T>&);
|
||||
|
||||
template <size_t Rows, size_t Cols, typename T>
|
||||
template <std::size_t Rows, std::size_t Cols, typename T>
|
||||
constexpr
|
||||
matrix<Rows,Cols,T>
|
||||
operator- (const matrix<Rows,Cols,T>&, const matrix<Rows,Cols,T>&);
|
||||
|
||||
|
||||
template <std::size_t Rows, std::size_t Cols, typename T>
|
||||
constexpr
|
||||
matrix<Rows,Cols,T>
|
||||
div (const matrix<Rows,Cols,T> &a, const matrix<Rows,Cols,T> &b)
|
||||
{
|
||||
matrix<Rows,Cols,T> out {};
|
||||
for (std::size_t r = 0; r < Rows; ++r)
|
||||
for (std::size_t c = 0; c < Cols; ++c)
|
||||
out[r][c] = a[r][c] / b[r][c];
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
template <std::size_t Rows, std::size_t Cols, typename T>
|
||||
constexpr T
|
||||
max (const matrix<Rows,Cols,T> &m)
|
||||
{
|
||||
T val = m[0][0];
|
||||
for (std::size_t r = 0; r < Rows; ++r)
|
||||
for (std::size_t c = 0; c < Cols; ++c)
|
||||
val = max (val, m[r][c]);
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// scalar operations
|
||||
template <size_t R, size_t C, typename T> constexpr matrix<R,C,T> operator* (const matrix<R,C,T>&, T);
|
||||
template <size_t R, size_t C, typename T> constexpr matrix<R,C,T> operator/ (const matrix<R,C,T>&, T);
|
||||
template <size_t R, size_t C, typename T> constexpr matrix<R,C,T> operator+ (const matrix<R,C,T>&, T);
|
||||
template <size_t R, size_t C, typename T> constexpr matrix<R,C,T> operator- (const matrix<R,C,T>&, T);
|
||||
template <std::size_t R, std::size_t C, typename T> constexpr matrix<R,C,T> operator* (const matrix<R,C,T>&, T);
|
||||
template <std::size_t R, std::size_t C, typename T> constexpr matrix<R,C,T> operator/ (const matrix<R,C,T>&, T);
|
||||
template <std::size_t R, std::size_t C, typename T> constexpr matrix<R,C,T> operator+ (const matrix<R,C,T>&, T);
|
||||
template <std::size_t R, std::size_t C, typename T> constexpr matrix<R,C,T> operator- (const matrix<R,C,T>&, T);
|
||||
|
||||
template <size_t R, size_t C, typename T> constexpr matrix<R,C,T> operator* (T, const matrix<R,C,T>&);
|
||||
template <size_t R, size_t C, typename T> constexpr matrix<R,C,T> operator/ (T, const matrix<R,C,T>&);
|
||||
template <size_t R, size_t C, typename T> constexpr matrix<R,C,T> operator+ (T, const matrix<R,C,T>&);
|
||||
template <size_t R, size_t C, typename T> constexpr matrix<R,C,T> operator- (T, const matrix<R,C,T>&);
|
||||
template <std::size_t R, std::size_t C, typename T> constexpr matrix<R,C,T> operator* (T, const matrix<R,C,T>&);
|
||||
template <std::size_t R, std::size_t C, typename T> constexpr matrix<R,C,T> operator/ (T, const matrix<R,C,T>&);
|
||||
template <std::size_t R, std::size_t C, typename T> constexpr matrix<R,C,T> operator+ (T, const matrix<R,C,T>&);
|
||||
template <std::size_t R, std::size_t C, typename T> constexpr matrix<R,C,T> operator- (T, const matrix<R,C,T>&);
|
||||
|
||||
template <size_t R, size_t C, typename T> constexpr matrix<R,C,T>& operator*= (matrix<R,C,T>&, T);
|
||||
template <size_t R, size_t C, typename T> constexpr matrix<R,C,T>& operator/= (matrix<R,C,T>&, T);
|
||||
template <size_t R, size_t C, typename T> constexpr matrix<R,C,T>& operator+= (matrix<R,C,T>&, T);
|
||||
template <size_t R, size_t C, typename T> constexpr matrix<R,C,T>& operator-= (matrix<R,C,T>&, T);
|
||||
template <std::size_t R, std::size_t C, typename T> constexpr matrix<R,C,T>& operator*= (matrix<R,C,T>&, T);
|
||||
template <std::size_t R, std::size_t C, typename T> constexpr matrix<R,C,T>& operator/= (matrix<R,C,T>&, T);
|
||||
template <std::size_t R, std::size_t C, typename T> constexpr matrix<R,C,T>& operator+= (matrix<R,C,T>&, T);
|
||||
template <std::size_t R, std::size_t C, typename T> constexpr matrix<R,C,T>& operator-= (matrix<R,C,T>&, T);
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// matrix operations
|
||||
template <
|
||||
size_t R1, size_t C1,
|
||||
size_t R2, size_t C2,
|
||||
std::size_t R1, //int C1,
|
||||
std::size_t RC, //int R2,
|
||||
std::size_t C2,
|
||||
typename T
|
||||
>
|
||||
constexpr
|
||||
matrix<R1,C2,T>
|
||||
operator* (const matrix<R1,C1,T>&, const matrix<R2,C2,T>&);
|
||||
operator* (const matrix<R1,RC,T>&a, const matrix<RC,C2,T>&b)
|
||||
{
|
||||
matrix<R1,C2,T> res {};
|
||||
|
||||
// we use a column first iteration approach because otherwise we risk
|
||||
// triggering clang#????
|
||||
for (std::size_t c = 0; c < C2; ++c) {
|
||||
for (std::size_t r = 0; r < R1; ++r) {
|
||||
T accum {0};
|
||||
|
||||
for (std::size_t i = 0; i < RC; ++i)
|
||||
accum += a[r][i] * b[i][c];
|
||||
|
||||
res[r][c] = accum;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
template <
|
||||
size_t R1, size_t C1,
|
||||
size_t R2, size_t C2,
|
||||
std::size_t R1, std::size_t C1,
|
||||
std::size_t R2, std::size_t C2,
|
||||
typename T
|
||||
>
|
||||
constexpr
|
||||
@ -162,25 +236,25 @@ namespace util {
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
template <size_t Rows, size_t Cols, typename T>
|
||||
template <std::size_t Rows, std::size_t Cols, typename T>
|
||||
T
|
||||
determinant (const matrix<Rows,Cols,T>&);
|
||||
|
||||
template <size_t Rows, size_t Cols, typename T>
|
||||
template <std::size_t Rows, std::size_t Cols, typename T>
|
||||
matrix<Rows,Cols,T>
|
||||
inverse (const matrix<Rows,Cols,T>&);
|
||||
|
||||
template <size_t Rows, size_t Cols, typename T>
|
||||
template <std::size_t Rows, std::size_t Cols, typename T>
|
||||
matrix<Cols,Rows,T>
|
||||
transposed (const matrix<Rows,Cols,T>&);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <size_t Rows, size_t Cols, typename T>
|
||||
template <std::size_t Rows, std::size_t Cols, typename T>
|
||||
matrix<Rows,Cols,T>
|
||||
abs (const matrix<Rows,Cols,T>&);
|
||||
|
||||
template <size_t Rows, size_t Cols, typename T>
|
||||
template <std::size_t Rows, std::size_t Cols, typename T>
|
||||
constexpr
|
||||
T
|
||||
sum (const matrix<Rows,Cols,T>&);
|
||||
@ -190,8 +264,8 @@ namespace util {
|
||||
template <typename T> using matrix3 = matrix<3,3,T>;
|
||||
template <typename T> using matrix4 = matrix<4,4,T>;
|
||||
|
||||
template <size_t Rows, size_t Cols> using matrixf = matrix<Rows,Cols,float>;
|
||||
template <size_t Rows, size_t Cols> using matrixd = matrix<Rows,Cols,double>;
|
||||
template <std::size_t Rows, std::size_t Cols> using matrixf = matrix<Rows,Cols,float>;
|
||||
template <std::size_t Rows, std::size_t Cols> using matrixd = matrix<Rows,Cols,double>;
|
||||
|
||||
typedef matrix<2,2,float> matrix2f;
|
||||
typedef matrix<2,2,double> matrix2d;
|
||||
@ -204,7 +278,7 @@ namespace util {
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
template <size_t Rows, size_t Cols, typename T>
|
||||
template <std::size_t Rows, std::size_t Cols, typename T>
|
||||
std::ostream& operator<< (std::ostream&, const matrix<Rows,Cols,T>&);
|
||||
}
|
||||
|
||||
|
104
matrix.ipp
104
matrix.ipp
@ -19,29 +19,30 @@
|
||||
#error
|
||||
#endif
|
||||
|
||||
#include "matrix.hpp"
|
||||
#define __UTIL_MATRIX_IPP
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <size_t Rows, size_t Cols, typename T>
|
||||
T*
|
||||
util::matrix<Rows,Cols,T>::operator[] (size_t idx)
|
||||
{
|
||||
return this->values[idx];
|
||||
}
|
||||
//template <std::size_t Rows, std::size_t Cols, typename T>
|
||||
//T*
|
||||
//util::matrix<Rows,Cols,T>::operator[] (int idx)
|
||||
//{
|
||||
// return this->values[idx];
|
||||
//}
|
||||
//
|
||||
//
|
||||
////-----------------------------------------------------------------------------
|
||||
//template <std::size_t Rows, std::size_t Cols, typename T>
|
||||
//const T*
|
||||
//util::matrix<Rows,Cols,T>::operator[] (int idx) const
|
||||
//{
|
||||
// return this->values[idx];
|
||||
//}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <size_t Rows, size_t Cols, typename T>
|
||||
const T*
|
||||
util::matrix<Rows,Cols,T>::operator[] (size_t idx) const
|
||||
{
|
||||
return this->values[idx];
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <size_t Rows, size_t Cols, typename T>
|
||||
template <std::size_t Rows, std::size_t Cols, typename T>
|
||||
T*
|
||||
util::matrix<Rows,Cols,T>::data (void)
|
||||
{
|
||||
@ -50,7 +51,7 @@ util::matrix<Rows,Cols,T>::data (void)
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <size_t Rows, size_t Cols, typename T>
|
||||
template <std::size_t Rows, std::size_t Cols, typename T>
|
||||
const T*
|
||||
util::matrix<Rows,Cols,T>::data (void) const
|
||||
{
|
||||
@ -59,7 +60,7 @@ util::matrix<Rows,Cols,T>::data (void) const
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <size_t Rows, size_t Cols, typename T>
|
||||
template <std::size_t Rows, std::size_t Cols, typename T>
|
||||
const T*
|
||||
util::matrix<Rows,Cols,T>::begin (void) const
|
||||
{
|
||||
@ -68,7 +69,7 @@ util::matrix<Rows,Cols,T>::begin (void) const
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <size_t Rows, size_t Cols, typename T>
|
||||
template <std::size_t Rows, std::size_t Cols, typename T>
|
||||
const T*
|
||||
util::matrix<Rows,Cols,T>::end (void) const
|
||||
{
|
||||
@ -77,7 +78,7 @@ util::matrix<Rows,Cols,T>::end (void) const
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <size_t Rows, size_t Cols, typename T>
|
||||
template <std::size_t Rows, std::size_t Cols, typename T>
|
||||
const T*
|
||||
util::matrix<Rows,Cols,T>::cbegin (void) const
|
||||
{
|
||||
@ -86,7 +87,7 @@ util::matrix<Rows,Cols,T>::cbegin (void) const
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <size_t Rows, size_t Cols, typename T>
|
||||
template <std::size_t Rows, std::size_t Cols, typename T>
|
||||
const T*
|
||||
util::matrix<Rows,Cols,T>::cend (void) const
|
||||
{
|
||||
@ -95,7 +96,7 @@ util::matrix<Rows,Cols,T>::cend (void) const
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <size_t Rows, size_t Cols, typename T>
|
||||
template <std::size_t Rows, std::size_t Cols, typename T>
|
||||
T*
|
||||
util::matrix<Rows,Cols,T>::begin (void)
|
||||
{
|
||||
@ -104,7 +105,7 @@ util::matrix<Rows,Cols,T>::begin (void)
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <size_t Rows, size_t Cols, typename T>
|
||||
template <std::size_t Rows, std::size_t Cols, typename T>
|
||||
T*
|
||||
util::matrix<Rows,Cols,T>::end (void)
|
||||
{
|
||||
@ -113,7 +114,7 @@ util::matrix<Rows,Cols,T>::end (void)
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <size_t Rows, size_t Cols, typename T>
|
||||
template <std::size_t Rows, std::size_t Cols, typename T>
|
||||
template <typename U>
|
||||
util::matrix<Rows,Cols,U>
|
||||
util::matrix<Rows,Cols,T>::cast (void) const
|
||||
@ -126,7 +127,7 @@ util::matrix<Rows,Cols,T>::cast (void) const
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define MATRIX_ELEMENT_OP(OP) \
|
||||
template <size_t Rows, size_t Cols, typename T> \
|
||||
template <std::size_t Rows, std::size_t Cols, typename T> \
|
||||
constexpr \
|
||||
util::matrix<Rows,Cols,T> \
|
||||
util::operator OP ( \
|
||||
@ -135,8 +136,8 @@ util::operator OP ( \
|
||||
{ \
|
||||
util::matrix<Rows,Cols,T> res {}; \
|
||||
\
|
||||
for (size_t i = 0; i < a.rows; ++i) \
|
||||
for (size_t j = 0; j < a.cols; ++j) \
|
||||
for (std::size_t i = 0; i < a.rows; ++i) \
|
||||
for (std::size_t j = 0; j < a.cols; ++j) \
|
||||
res[i][j] = a[i][j] OP b[i][j]; \
|
||||
\
|
||||
return res; \
|
||||
@ -150,7 +151,7 @@ MATRIX_ELEMENT_OP(+)
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define MATRIX_SCALAR_OP(OP) \
|
||||
template <size_t Rows, size_t Cols, typename T> \
|
||||
template <std::size_t Rows, std::size_t Cols, typename T> \
|
||||
constexpr \
|
||||
util::matrix<Rows,Cols,T> \
|
||||
util::operator OP (const util::matrix<Rows,Cols,T> &m, const T t) \
|
||||
@ -168,7 +169,7 @@ util::operator OP (const util::matrix<Rows,Cols,T> &m, const T t) \
|
||||
} \
|
||||
\
|
||||
\
|
||||
template <size_t Rows, size_t Cols, typename T> \
|
||||
template <std::size_t Rows, std::size_t Cols, typename T> \
|
||||
constexpr \
|
||||
util::matrix<Rows,Cols,T> \
|
||||
util::operator OP (const T t, const util::matrix<Rows,Cols,T> &m) \
|
||||
@ -177,7 +178,7 @@ util::operator OP (const T t, const util::matrix<Rows,Cols,T> &m) \
|
||||
} \
|
||||
\
|
||||
\
|
||||
template <size_t Rows, size_t Cols, typename T> \
|
||||
template <std::size_t Rows, std::size_t Cols, typename T> \
|
||||
constexpr \
|
||||
util::matrix<Rows,Cols,T>& \
|
||||
util::operator OP##= (util::matrix<Rows,Cols,T> &m, T t) \
|
||||
@ -202,40 +203,21 @@ MATRIX_SCALAR_OP(-)
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <
|
||||
std::size_t R1, std::size_t C1,
|
||||
std::size_t R2, std::size_t C2,
|
||||
typename T
|
||||
>
|
||||
constexpr
|
||||
util::matrix<R1,C2,T>
|
||||
util::operator* (const matrix<R1,C1,T> &a, const matrix<R2,C2,T> &b)
|
||||
{
|
||||
static_assert (R2 == C1);
|
||||
|
||||
matrix<R1,C2,T> res {0};
|
||||
|
||||
for (size_t r = 0; r < R1; ++r)
|
||||
for (size_t c = 0; c < C2; ++c)
|
||||
for (size_t i = 0; i < R2; ++i)
|
||||
res[r][c] += a[r][i] * b[i][c];
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <size_t Rows, size_t Cols, typename T>
|
||||
template <std::size_t Rows, std::size_t Cols, typename T>
|
||||
constexpr
|
||||
util::matrix<Rows,Cols,T>
|
||||
util::matrix<Rows,Cols,T>::zeroes (void)
|
||||
{
|
||||
return {0};
|
||||
util::matrix<Rows,Cols,T> ret {};
|
||||
for (std::size_t r = 0; r < Rows; ++r)
|
||||
for (std::size_t c = 0; c < Cols; ++c)
|
||||
ret[r][c] = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <size_t Rows, size_t Cols, typename T>
|
||||
template <std::size_t Rows, std::size_t Cols, typename T>
|
||||
constexpr
|
||||
util::matrix<Rows,Cols,T>
|
||||
util::matrix<Rows,Cols,T>::identity (void)
|
||||
@ -243,14 +225,14 @@ util::matrix<Rows,Cols,T>::identity (void)
|
||||
static_assert (Rows == Cols);
|
||||
|
||||
auto m = zeroes ();
|
||||
for (size_t i = 0; i < Rows; ++i)
|
||||
for (std::size_t i = 0; i < Rows; ++i)
|
||||
m[i][i] = 1;
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <size_t Rows, size_t Cols, typename T>
|
||||
template <std::size_t Rows, std::size_t Cols, typename T>
|
||||
constexpr
|
||||
bool
|
||||
util::operator== (const matrix<Rows,Cols,T> &a, const matrix<Rows,Cols,T> &b)
|
||||
@ -260,7 +242,7 @@ util::operator== (const matrix<Rows,Cols,T> &a, const matrix<Rows,Cols,T> &b)
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <size_t Rows, size_t Cols, typename T>
|
||||
template <std::size_t Rows, std::size_t Cols, typename T>
|
||||
constexpr
|
||||
bool
|
||||
util::operator!= (const matrix<Rows,Cols,T> &a, const matrix<Rows,Cols,T> &b)
|
||||
@ -270,7 +252,7 @@ util::operator!= (const matrix<Rows,Cols,T> &a, const matrix<Rows,Cols,T> &b)
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <size_t Rows, size_t Cols, typename T>
|
||||
template <std::size_t Rows, std::size_t Cols, typename T>
|
||||
util::matrix<Rows,Cols,T>
|
||||
util::abs (const util::matrix<Rows,Cols,T> &src)
|
||||
{
|
||||
@ -281,7 +263,7 @@ util::abs (const util::matrix<Rows,Cols,T> &src)
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <size_t Rows, size_t Cols, typename T>
|
||||
template <std::size_t Rows, std::size_t Cols, typename T>
|
||||
constexpr
|
||||
T
|
||||
util::sum (const util::matrix<Rows, Cols,T> &src)
|
||||
|
12
matrix2.cpp
12
matrix2.cpp
@ -20,7 +20,7 @@ using util::matrix;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <size_t Rows, size_t Cols, typename T>
|
||||
template <std::size_t Rows, std::size_t Cols, typename T>
|
||||
T
|
||||
util::determinant (const matrix<Rows,Cols,T> &m)
|
||||
{
|
||||
@ -34,16 +34,16 @@ template double util::determinant (const matrix<2,2,double>&);
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <size_t Rows, size_t Cols, typename T>
|
||||
template <std::size_t Rows, std::size_t Cols, typename T>
|
||||
matrix<Rows,Cols,T>
|
||||
util::inverse (const matrix<Rows,Cols,T> &m)
|
||||
{
|
||||
static_assert (Rows == 2 && Cols == 2);
|
||||
|
||||
return matrix<2,2,T> {
|
||||
m[1][1], -m[0][1],
|
||||
-m[1][0], m[0][0]
|
||||
} / determinant (m);
|
||||
return matrix<2,2,T> {{
|
||||
{ m[1][1], -m[0][1], },
|
||||
{ -m[1][0], m[0][0], },
|
||||
}} / determinant (m);
|
||||
}
|
||||
|
||||
|
||||
|
26
matrix3.cpp
26
matrix3.cpp
@ -20,7 +20,7 @@ using util::matrix;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <size_t Rows, size_t Cols, typename T>
|
||||
template <std::size_t Rows, std::size_t Cols, typename T>
|
||||
T
|
||||
util::determinant (const matrix<Rows,Cols,T>& m)
|
||||
{
|
||||
@ -36,25 +36,25 @@ template double util::determinant (const matrix<3,3,double>&);
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <size_t Rows, size_t Cols, typename T>
|
||||
template <std::size_t Rows, std::size_t Cols, typename T>
|
||||
matrix<Rows,Cols,T>
|
||||
util::inverse (const matrix<Rows,Cols,T> &m)
|
||||
{
|
||||
static_assert (Rows == 3 && Cols == 3);
|
||||
|
||||
return matrix<3,3,T> {
|
||||
m[1][1] * m[2][2] - m[2][1] * m[1][2],
|
||||
m[0][2] * m[2][1] - m[0][1] * m[2][2],
|
||||
m[0][1] * m[1][2] - m[0][2] * m[1][1],
|
||||
return matrix<3,3,T> {{
|
||||
{ m[1][1] * m[2][2] - m[2][1] * m[1][2],
|
||||
m[0][2] * m[2][1] - m[0][1] * m[2][2],
|
||||
m[0][1] * m[1][2] - m[0][2] * m[1][1], },
|
||||
|
||||
m[1][2] * m[2][0] - m[1][0] * m[2][2],
|
||||
m[0][0] * m[2][2] - m[0][2] * m[2][0],
|
||||
m[1][0] * m[0][2] - m[0][0] * m[1][2],
|
||||
{ m[1][2] * m[2][0] - m[1][0] * m[2][2],
|
||||
m[0][0] * m[2][2] - m[0][2] * m[2][0],
|
||||
m[1][0] * m[0][2] - m[0][0] * m[1][2], },
|
||||
|
||||
m[1][0] * m[2][1] - m[2][0] * m[1][1],
|
||||
m[2][0] * m[0][1] - m[0][0] * m[2][1],
|
||||
m[0][0] * m[1][1] - m[1][0] * m[0][1],
|
||||
} / determinant (m);
|
||||
{ m[1][0] * m[2][1] - m[2][0] * m[1][1],
|
||||
m[2][0] * m[0][1] - m[0][0] * m[2][1],
|
||||
m[0][0] * m[1][1] - m[1][0] * m[0][1], },
|
||||
}} / determinant (m);
|
||||
}
|
||||
|
||||
template util::matrix<3,3,float> util::inverse (const matrix<3,3,float>&);
|
||||
|
135
matrix4.cpp
135
matrix4.cpp
@ -20,7 +20,7 @@ using util::matrix;
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <size_t Rows, size_t Cols, typename T>
|
||||
template <std::size_t Rows, std::size_t Cols, typename T>
|
||||
T
|
||||
util::determinant (const matrix<Rows,Cols,T> &m)
|
||||
{
|
||||
@ -45,30 +45,125 @@ template double util::determinant (const matrix<4,4,double>&);
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <size_t Rows, size_t Cols, typename T>
|
||||
template <std::size_t Rows, std::size_t Cols, typename T>
|
||||
matrix<Rows,Cols,T>
|
||||
util::inverse (const matrix<Rows,Cols,T> &m)
|
||||
{
|
||||
static_assert (Rows == 4 && Cols == 4);
|
||||
|
||||
return matrix<4,4,T> {
|
||||
m[1][2]*m[2][3]*m[3][1] - m[1][3]*m[2][2]*m[3][1] + m[1][3]*m[2][1]*m[3][2] - m[1][1]*m[2][3]*m[3][2] - m[1][2]*m[2][1]*m[3][3] + m[1][1]*m[2][2]*m[3][3],
|
||||
m[0][3]*m[2][2]*m[3][1] - m[0][2]*m[2][3]*m[3][1] - m[0][3]*m[2][1]*m[3][2] + m[0][1]*m[2][3]*m[3][2] + m[0][2]*m[2][1]*m[3][3] - m[0][1]*m[2][2]*m[3][3],
|
||||
m[0][2]*m[1][3]*m[3][1] - m[0][3]*m[1][2]*m[3][1] + m[0][3]*m[1][1]*m[3][2] - m[0][1]*m[1][3]*m[3][2] - m[0][2]*m[1][1]*m[3][3] + m[0][1]*m[1][2]*m[3][3],
|
||||
m[0][3]*m[1][2]*m[2][1] - m[0][2]*m[1][3]*m[2][1] - m[0][3]*m[1][1]*m[2][2] + m[0][1]*m[1][3]*m[2][2] + m[0][2]*m[1][1]*m[2][3] - m[0][1]*m[1][2]*m[2][3],
|
||||
m[1][3]*m[2][2]*m[3][0] - m[1][2]*m[2][3]*m[3][0] - m[1][3]*m[2][0]*m[3][2] + m[1][0]*m[2][3]*m[3][2] + m[1][2]*m[2][0]*m[3][3] - m[1][0]*m[2][2]*m[3][3],
|
||||
m[0][2]*m[2][3]*m[3][0] - m[0][3]*m[2][2]*m[3][0] + m[0][3]*m[2][0]*m[3][2] - m[0][0]*m[2][3]*m[3][2] - m[0][2]*m[2][0]*m[3][3] + m[0][0]*m[2][2]*m[3][3],
|
||||
m[0][3]*m[1][2]*m[3][0] - m[0][2]*m[1][3]*m[3][0] - m[0][3]*m[1][0]*m[3][2] + m[0][0]*m[1][3]*m[3][2] + m[0][2]*m[1][0]*m[3][3] - m[0][0]*m[1][2]*m[3][3],
|
||||
m[0][2]*m[1][3]*m[2][0] - m[0][3]*m[1][2]*m[2][0] + m[0][3]*m[1][0]*m[2][2] - m[0][0]*m[1][3]*m[2][2] - m[0][2]*m[1][0]*m[2][3] + m[0][0]*m[1][2]*m[2][3],
|
||||
m[1][1]*m[2][3]*m[3][0] - m[1][3]*m[2][1]*m[3][0] + m[1][3]*m[2][0]*m[3][1] - m[1][0]*m[2][3]*m[3][1] - m[1][1]*m[2][0]*m[3][3] + m[1][0]*m[2][1]*m[3][3],
|
||||
m[0][3]*m[2][1]*m[3][0] - m[0][1]*m[2][3]*m[3][0] - m[0][3]*m[2][0]*m[3][1] + m[0][0]*m[2][3]*m[3][1] + m[0][1]*m[2][0]*m[3][3] - m[0][0]*m[2][1]*m[3][3],
|
||||
m[0][1]*m[1][3]*m[3][0] - m[0][3]*m[1][1]*m[3][0] + m[0][3]*m[1][0]*m[3][1] - m[0][0]*m[1][3]*m[3][1] - m[0][1]*m[1][0]*m[3][3] + m[0][0]*m[1][1]*m[3][3],
|
||||
m[0][3]*m[1][1]*m[2][0] - m[0][1]*m[1][3]*m[2][0] - m[0][3]*m[1][0]*m[2][1] + m[0][0]*m[1][3]*m[2][1] + m[0][1]*m[1][0]*m[2][3] - m[0][0]*m[1][1]*m[2][3],
|
||||
m[1][2]*m[2][1]*m[3][0] - m[1][1]*m[2][2]*m[3][0] - m[1][2]*m[2][0]*m[3][1] + m[1][0]*m[2][2]*m[3][1] + m[1][1]*m[2][0]*m[3][2] - m[1][0]*m[2][1]*m[3][2],
|
||||
m[0][1]*m[2][2]*m[3][0] - m[0][2]*m[2][1]*m[3][0] + m[0][2]*m[2][0]*m[3][1] - m[0][0]*m[2][2]*m[3][1] - m[0][1]*m[2][0]*m[3][2] + m[0][0]*m[2][1]*m[3][2],
|
||||
m[0][2]*m[1][1]*m[3][0] - m[0][1]*m[1][2]*m[3][0] - m[0][2]*m[1][0]*m[3][1] + m[0][0]*m[1][2]*m[3][1] + m[0][1]*m[1][0]*m[3][2] - m[0][0]*m[1][1]*m[3][2],
|
||||
m[0][1]*m[1][2]*m[2][0] - m[0][2]*m[1][1]*m[2][0] + m[0][2]*m[1][0]*m[2][1] - m[0][0]*m[1][2]*m[2][1] - m[0][1]*m[1][0]*m[2][2] + m[0][0]*m[1][1]*m[2][2],
|
||||
} / determinant (m);
|
||||
return matrix<4,4,T> {{
|
||||
{ m[1][2]*m[2][3]*m[3][1]
|
||||
-m[1][3]*m[2][2]*m[3][1]
|
||||
+m[1][3]*m[2][1]*m[3][2]
|
||||
-m[1][1]*m[2][3]*m[3][2]
|
||||
-m[1][2]*m[2][1]*m[3][3]
|
||||
+m[1][1]*m[2][2]*m[3][3],
|
||||
|
||||
m[0][3]*m[2][2]*m[3][1]
|
||||
-m[0][2]*m[2][3]*m[3][1]
|
||||
-m[0][3]*m[2][1]*m[3][2]
|
||||
+m[0][1]*m[2][3]*m[3][2]
|
||||
+m[0][2]*m[2][1]*m[3][3]
|
||||
-m[0][1]*m[2][2]*m[3][3],
|
||||
|
||||
m[0][2]*m[1][3]*m[3][1]
|
||||
-m[0][3]*m[1][2]*m[3][1]
|
||||
+m[0][3]*m[1][1]*m[3][2]
|
||||
-m[0][1]*m[1][3]*m[3][2]
|
||||
-m[0][2]*m[1][1]*m[3][3]
|
||||
+m[0][1]*m[1][2]*m[3][3],
|
||||
|
||||
m[0][3]*m[1][2]*m[2][1]
|
||||
-m[0][2]*m[1][3]*m[2][1]
|
||||
-m[0][3]*m[1][1]*m[2][2]
|
||||
+m[0][1]*m[1][3]*m[2][2]
|
||||
+m[0][2]*m[1][1]*m[2][3]
|
||||
-m[0][1]*m[1][2]*m[2][3], },
|
||||
|
||||
{ m[1][3]*m[2][2]*m[3][0]
|
||||
-m[1][2]*m[2][3]*m[3][0]
|
||||
-m[1][3]*m[2][0]*m[3][2]
|
||||
+m[1][0]*m[2][3]*m[3][2]
|
||||
+m[1][2]*m[2][0]*m[3][3]
|
||||
-m[1][0]*m[2][2]*m[3][3],
|
||||
|
||||
m[0][2]*m[2][3]*m[3][0]
|
||||
-m[0][3]*m[2][2]*m[3][0]
|
||||
+m[0][3]*m[2][0]*m[3][2]
|
||||
-m[0][0]*m[2][3]*m[3][2]
|
||||
-m[0][2]*m[2][0]*m[3][3]
|
||||
+m[0][0]*m[2][2]*m[3][3],
|
||||
|
||||
m[0][3]*m[1][2]*m[3][0]
|
||||
-m[0][2]*m[1][3]*m[3][0]
|
||||
-m[0][3]*m[1][0]*m[3][2]
|
||||
+m[0][0]*m[1][3]*m[3][2]
|
||||
+m[0][2]*m[1][0]*m[3][3]
|
||||
-m[0][0]*m[1][2]*m[3][3],
|
||||
|
||||
m[0][2]*m[1][3]*m[2][0]
|
||||
-m[0][3]*m[1][2]*m[2][0]
|
||||
+m[0][3]*m[1][0]*m[2][2]
|
||||
-m[0][0]*m[1][3]*m[2][2]
|
||||
-m[0][2]*m[1][0]*m[2][3]
|
||||
+m[0][0]*m[1][2]*m[2][3], },
|
||||
|
||||
{ m[1][1]*m[2][3]*m[3][0]
|
||||
-m[1][3]*m[2][1]*m[3][0]
|
||||
+m[1][3]*m[2][0]*m[3][1]
|
||||
-m[1][0]*m[2][3]*m[3][1]
|
||||
-m[1][1]*m[2][0]*m[3][3]
|
||||
+m[1][0]*m[2][1]*m[3][3],
|
||||
|
||||
m[0][3]*m[2][1]*m[3][0]
|
||||
-m[0][1]*m[2][3]*m[3][0]
|
||||
-m[0][3]*m[2][0]*m[3][1]
|
||||
+m[0][0]*m[2][3]*m[3][1]
|
||||
+m[0][1]*m[2][0]*m[3][3]
|
||||
-m[0][0]*m[2][1]*m[3][3],
|
||||
|
||||
m[0][1]*m[1][3]*m[3][0]
|
||||
-m[0][3]*m[1][1]*m[3][0]
|
||||
+m[0][3]*m[1][0]*m[3][1]
|
||||
-m[0][0]*m[1][3]*m[3][1]
|
||||
-m[0][1]*m[1][0]*m[3][3]
|
||||
+m[0][0]*m[1][1]*m[3][3],
|
||||
|
||||
m[0][3]*m[1][1]*m[2][0]
|
||||
-m[0][1]*m[1][3]*m[2][0]
|
||||
-m[0][3]*m[1][0]*m[2][1]
|
||||
+m[0][0]*m[1][3]*m[2][1]
|
||||
+m[0][1]*m[1][0]*m[2][3]
|
||||
-m[0][0]*m[1][1]*m[2][3], },
|
||||
|
||||
{ m[1][2]*m[2][1]*m[3][0]
|
||||
-m[1][1]*m[2][2]*m[3][0]
|
||||
-m[1][2]*m[2][0]*m[3][1]
|
||||
+m[1][0]*m[2][2]*m[3][1]
|
||||
+m[1][1]*m[2][0]*m[3][2]
|
||||
-m[1][0]*m[2][1]*m[3][2],
|
||||
|
||||
m[0][1]*m[2][2]*m[3][0]
|
||||
-m[0][2]*m[2][1]*m[3][0]
|
||||
+m[0][2]*m[2][0]*m[3][1]
|
||||
-m[0][0]*m[2][2]*m[3][1]
|
||||
-m[0][1]*m[2][0]*m[3][2]
|
||||
+m[0][0]*m[2][1]*m[3][2],
|
||||
|
||||
m[0][2]*m[1][1]*m[3][0]
|
||||
-m[0][1]*m[1][2]*m[3][0]
|
||||
-m[0][2]*m[1][0]*m[3][1]
|
||||
+m[0][0]*m[1][2]*m[3][1]
|
||||
+m[0][1]*m[1][0]*m[3][2]
|
||||
-m[0][0]*m[1][1]*m[3][2],
|
||||
|
||||
m[0][1]*m[1][2]*m[2][0]
|
||||
-m[0][2]*m[1][1]*m[2][0]
|
||||
+m[0][2]*m[1][0]*m[2][1]
|
||||
-m[0][0]*m[1][2]*m[2][1]
|
||||
-m[0][1]*m[1][0]*m[2][2]
|
||||
+m[0][0]*m[1][1]*m[2][2], }
|
||||
}} / determinant (m);
|
||||
}
|
||||
|
||||
template util::matrix<4,4,float> util::inverse (const matrix<4,4,float>&);
|
||||
|
@ -28,9 +28,9 @@ namespace util {
|
||||
/// \tparam S number of dimensions
|
||||
/// \tparam T the underlying per-dimension datatype
|
||||
template <size_t S, typename T>
|
||||
struct point : public coord::base<S,T,point,coord::xyzw>
|
||||
struct point : public coord::base<S,T,point<S,T>>
|
||||
{
|
||||
using coord::base<S,T,util::point,coord::xyzw>::base;
|
||||
using coord::base<S,T,point<S,T>>::base;
|
||||
|
||||
vector<S,T> to (point) const;
|
||||
vector<S,T> from (point) const;
|
||||
|
@ -17,7 +17,7 @@
|
||||
#ifndef __UTIL_QUATERNION_HPP
|
||||
#define __UTIL_QUATERNION_HPP
|
||||
|
||||
#include "coord.hpp"
|
||||
#include "coord/traits.hpp"
|
||||
|
||||
#include "vector.hpp"
|
||||
#include "matrix.hpp"
|
||||
@ -38,6 +38,8 @@ namespace util {
|
||||
struct quaternion {
|
||||
T w, x, y, z;
|
||||
|
||||
static constexpr std::size_t size (void) { return 4; }
|
||||
|
||||
static quaternion angle_axis (T radians, vector<3,T> axis);
|
||||
static quaternion from_euler (vector<3,T>);
|
||||
|
||||
@ -50,6 +52,12 @@ namespace util {
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
struct arity<quaternion<T>,void>
|
||||
:std::integral_constant<std::size_t, 4>
|
||||
{ };
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
template <typename T>
|
||||
vector3<T>
|
||||
|
40
random.hpp
40
random.hpp
@ -17,6 +17,7 @@
|
||||
#ifndef __UTIL_RANDOM_HPP
|
||||
#define __UTIL_RANDOM_HPP
|
||||
|
||||
#include <algorithm>
|
||||
#include <random>
|
||||
|
||||
|
||||
@ -45,6 +46,43 @@ namespace util::rand {
|
||||
std::uniform_int_distribution<size_t> dist (0, N-1);
|
||||
return t[dist (gen)];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
template <
|
||||
typename T,
|
||||
typename IteratorT,
|
||||
typename GeneratorT = default_generator
|
||||
>
|
||||
void
|
||||
uniform (T lo, T hi, IteratorT first, IteratorT last)
|
||||
{
|
||||
static_assert (std::is_same_v<T, typename std::iterator_traits<IteratorT>::value_type>);
|
||||
auto &gen = thread_engine<GeneratorT> ();
|
||||
|
||||
static_assert (std::is_integral_v<T> || std::is_floating_point_v<T>);
|
||||
|
||||
if constexpr (std::is_integral_v<T>) {
|
||||
std::generate (
|
||||
first,
|
||||
last,
|
||||
[&gen, d = std::uniform_int_distribution<T> (lo, hi)]
|
||||
{
|
||||
return d (gen);
|
||||
});
|
||||
}
|
||||
|
||||
if constexpr (std::is_floating_point_v<T>) {
|
||||
auto d = std::uniform_real_distribution<T> (lo, hi);
|
||||
std::generate (
|
||||
first,
|
||||
last,
|
||||
[&]
|
||||
{
|
||||
return d (gen);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -6,6 +6,9 @@
|
||||
|
||||
#include "coord/iostream.hpp"
|
||||
|
||||
#include <array>
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
void
|
||||
test_matrix_identities (util::TAP::logger &tap)
|
||||
@ -15,16 +18,16 @@ test_matrix_identities (util::TAP::logger &tap)
|
||||
{
|
||||
util::point3f p { 1, 2, 3 };
|
||||
|
||||
auto m = util::matrix4f::translation (0-p);
|
||||
auto m = util::translation (0-p);
|
||||
auto x = m * p.homog<4> ();
|
||||
tap.expect_eq (x, util::point4f {0,0,0,1}, "trivial translation to origin");
|
||||
}
|
||||
|
||||
{
|
||||
util::point3f p {0};
|
||||
auto m = util::matrix4f::rotation (1, { 1, 0, 0 }) *
|
||||
util::matrix4f::rotation (1, { 0, 1, 0 }) *
|
||||
util::matrix4f::rotation (1, { 0, 0, 1 });
|
||||
auto m = util::rotation<float> (1, { 1, 0, 0 }) *
|
||||
util::rotation<float> (1, { 0, 1, 0 }) *
|
||||
util::rotation<float> (1, { 0, 0, 1 });
|
||||
auto x = m * p.homog<4> ();
|
||||
|
||||
tap.expect_eq (x, util::point4f {0,0,0,1}, "trivial rotation at origin");
|
||||
@ -34,7 +37,7 @@ test_matrix_identities (util::TAP::logger &tap)
|
||||
util::point3f eye { 1, 2, 3 };
|
||||
util::point3f tgt { 0, 0, 0 };
|
||||
|
||||
auto m = util::matrix4f::look_at (eye, tgt, UP);
|
||||
auto m = util::look_at (eye, tgt, UP);
|
||||
auto x = m * eye.homog<4> ();
|
||||
tap.expect_eq (x, util::point4f {0,0,0,1}, "look_at eye translation");
|
||||
}
|
||||
@ -43,7 +46,7 @@ test_matrix_identities (util::TAP::logger &tap)
|
||||
util::point3f eye { 1, 2, 3 };
|
||||
util::point3f tgt { 4, 5, 6 };
|
||||
|
||||
auto m = util::matrix4f::look_at (eye, tgt, UP);
|
||||
auto m = util::look_at (eye, tgt, UP);
|
||||
auto x = m * eye.homog<4> ();
|
||||
tap.expect_eq (x, util::point4f {0,0,0,1}, "look_at eye translation with target");
|
||||
}
|
||||
@ -64,7 +67,7 @@ test_mq_axis (util::TAP::logger &tap)
|
||||
};
|
||||
|
||||
for (auto t: TESTS) {
|
||||
auto m = util::matrix4f::rotation (1, t.euler);
|
||||
auto m = util::rotation<float> (1, t.euler);
|
||||
auto q = util::quaternionf::angle_axis (1, t.euler);
|
||||
|
||||
auto diff = sum (abs (m - q.as_matrix ()));
|
||||
@ -78,27 +81,32 @@ void
|
||||
test_mq_euler (util::TAP::logger &tap)
|
||||
{
|
||||
static const struct {
|
||||
util::vector3f euler;
|
||||
float x, y, z;
|
||||
const char *msg;
|
||||
} TESTS[] = {
|
||||
{ { 0, 0, 0 }, "zeroes" },
|
||||
{ { 1, 0, 0 }, "x-axis" },
|
||||
{ { 0, 1, 0 }, "y-axis" },
|
||||
{ { 0, 0, 1 }, "z-axis" },
|
||||
{ { 1, 1, 1 }, "ones" },
|
||||
{ { 9, 9, 9 }, "nines" }
|
||||
{ 0, 0, 0, "zeroes" },
|
||||
{ 1, 0, 0, "x-axis" },
|
||||
{ 0, 1, 0, "y-axis" },
|
||||
{ 0, 0, 1, "z-axis" },
|
||||
{ 1, 1, 1, "ones" },
|
||||
{ 9, 9, 9, "nines" }
|
||||
};
|
||||
|
||||
for (auto t: TESTS) {
|
||||
auto m = util::matrix4f::rotation (t.euler[0], { 1, 0, 0 }) *
|
||||
util::matrix4f::rotation (t.euler[1], { 0, 1, 0 }) *
|
||||
util::matrix4f::rotation (t.euler[2], { 0, 0, 1 });
|
||||
const auto mx = util::rotation<float> (t.x, {1,0,0});
|
||||
const auto my = util::rotation<float> (t.y, {0,1,0});
|
||||
const auto mz = util::rotation<float> (t.z, {0,0,1});
|
||||
const auto m = mx * my * mz;
|
||||
|
||||
auto q = (
|
||||
util::quaternionf::angle_axis (t.euler[0], { 1, 0, 0 }) *
|
||||
util::quaternionf::angle_axis (t.euler[1], { 0, 1, 0 }) *
|
||||
util::quaternionf::angle_axis (t.euler[2], { 0, 0, 1 })
|
||||
util::quaternionf::angle_axis (t.x, { 1, 0, 0 }) *
|
||||
util::quaternionf::angle_axis (t.y, { 0, 1, 0 }) *
|
||||
util::quaternionf::angle_axis (t.z, { 0, 0, 1 })
|
||||
).as_matrix ();
|
||||
|
||||
if (abs (m - q)[0])
|
||||
exit (0);
|
||||
|
||||
auto diff = util::sum (abs (m - q));
|
||||
tap.expect_le (diff, 1e-6f, "matrix-quaternion xyz euler rotations, %s", t.msg);
|
||||
}
|
||||
|
@ -10,83 +10,11 @@ main (int, char**)
|
||||
|
||||
// Check casting works between intergral and floating formats
|
||||
{
|
||||
util::colour4f f (1);
|
||||
util::colour<4,uint8_t> u (255);
|
||||
util::srgba<4,float> f {1.f};
|
||||
util::srgba<4,uint8_t> u {255};
|
||||
tap.expect_eq (f.cast<uint8_t> (), u, "cast float to u8");
|
||||
tap.expect_eq (u.cast<float> (), f, "cast u8 to float");
|
||||
}
|
||||
|
||||
// Check parsing is working
|
||||
tap.expect_eq (
|
||||
util::colour4u::parse_html ("#11223344"),
|
||||
util::colour4u (0x11, 0x22, 0x33, 0x44),
|
||||
"4-component html parsing with hash"
|
||||
);
|
||||
|
||||
tap.expect_eq (
|
||||
util::colour4u::parse_html ("11223344"),
|
||||
util::colour4u (0x11, 0x22, 0x33, 0x44),
|
||||
"4-component html parsing without hash"
|
||||
);
|
||||
|
||||
tap.expect_eq (
|
||||
util::colour1f::parse_html ("ff"),
|
||||
util::colour1f (1.f),
|
||||
"1-component html parsing"
|
||||
);
|
||||
|
||||
tap.expect_eq (
|
||||
util::colour3u::parse_html ("3399ff"),
|
||||
util::colour3u (0x33, 0x99, 0xff),
|
||||
"3-component html parsing"
|
||||
);
|
||||
|
||||
tap.expect_throw<std::invalid_argument> (
|
||||
[] () { util::colour1f::parse_html ("00112233"); },
|
||||
"1-component parsing with 4-component format"
|
||||
);
|
||||
|
||||
tap.expect_throw<std::invalid_argument> (
|
||||
[] () { util::colour4f::parse_html ("00"); },
|
||||
"4-component parsing with 1-component format"
|
||||
);
|
||||
|
||||
tap.expect_throw<std::invalid_argument> (
|
||||
[] () { util::colour4f::parse_html ("0011223"); },
|
||||
"4-component parsing with one too few digits"
|
||||
);
|
||||
|
||||
|
||||
// Check lookups are working
|
||||
tap.expect_eq (util::colour4f::from_html ("white"), util::colour4f {1}, "HTML lookup");
|
||||
tap.expect_eq ( util::colour4f::from_x11 ("white"), util::colour4f {1}, "X11 lookup");
|
||||
|
||||
// Check HSV conversions
|
||||
{
|
||||
// white: hue is undefined
|
||||
auto white = util::rgb_to_hsv ({1,1,1});
|
||||
tap.expect (util::exactly_zero (white.s) && util::exactly_equal (white.v, 1), "white hsv");
|
||||
|
||||
// black: hue is undefined
|
||||
auto black = util::rgb_to_hsv ({0,0,0});
|
||||
tap.expect (util::exactly_zero (black.s) && util::exactly_zero (black.v), "black hsv");
|
||||
|
||||
struct {
|
||||
const char *name;
|
||||
util::colour3f rgb;
|
||||
util::colour3f hsv;
|
||||
} TESTS[] = {
|
||||
{ "red", { 1, 0, 0, }, { 0, 1, 1, } }, // red
|
||||
{ "green", { 0, 1, 0, }, { 120, 1, 1, } }, // green
|
||||
{ "blue", { 0, 0, 1, }, { 240, 1, 1, } }, // blue
|
||||
{ "misc", { 0.75f, 0.25f, 0.75f }, { 300, 2/3.f, 0.75f } },
|
||||
};
|
||||
|
||||
for (auto i: TESTS) {
|
||||
tap.expect_eq (util::rgb_to_hsv (i.rgb), i.hsv, "rgb-to-hsv %s", i.name);
|
||||
tap.expect_eq (util::hsv_to_rgb (i.hsv), i.rgb, "hsv-to-rgb %s", i.name);
|
||||
}
|
||||
}
|
||||
|
||||
return tap.status ();
|
||||
}
|
||||
|
@ -12,42 +12,5 @@ main (int, char**)
|
||||
{
|
||||
util::TAP::logger tap;
|
||||
|
||||
{
|
||||
// Test contraction
|
||||
AABB2f box {
|
||||
{ 2, 2 },
|
||||
{ 8, 8 }
|
||||
};
|
||||
|
||||
box.contract (2.f);
|
||||
|
||||
tap.expect_eq<AABB2f, AABB2f> (box, { { 3, 3 }, { 7, 7 }}, "over contraction");
|
||||
}
|
||||
|
||||
{
|
||||
// Test expansion
|
||||
AABB2f box {
|
||||
{ 2, 2 },
|
||||
{ 8, 8 }
|
||||
};
|
||||
|
||||
box.expand (2.f);
|
||||
|
||||
tap.expect_eq<AABB2f, AABB2f> (box, { { 1, 1 }, { 9, 9 }}, "expansion");
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
// Ensure we don't wrap-around on unsigned position types when contracting
|
||||
AABB2f small {
|
||||
{ 0, 0 },
|
||||
{ 1, 1 }
|
||||
};
|
||||
|
||||
small.contract (10);
|
||||
|
||||
tap.expect_eq<AABB2f, AABB2f> (small, { { 0.5f, 0.5f }, { 0.5f, 0.5f }}, "unsigned over-contract");
|
||||
}
|
||||
|
||||
return tap.status ();
|
||||
}
|
||||
|
@ -34,6 +34,10 @@ main (void)
|
||||
}
|
||||
|
||||
// Redim to higher dimension with fill
|
||||
//
|
||||
// HACK: This fails under GCC-7.1.0, and i'm not wasting any more time
|
||||
// reducing this test case. it's _really_ template heavy.
|
||||
#if !(__GNUC_PREREQ (7, 1))
|
||||
{
|
||||
static const point4f FILL (1.f, 2.f, 3.f, 4.f);
|
||||
const point2f p (0.1f, 1.f);
|
||||
@ -48,6 +52,7 @@ main (void)
|
||||
"redim to higher with fill"
|
||||
);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Simple linking check for coord type casting. Relies on truncation.
|
||||
{
|
||||
|
@ -86,7 +86,7 @@ main (void)
|
||||
const auto &r = ROTATIONS[i];
|
||||
|
||||
auto q = quaternionf::angle_axis (r.mag, r.axis).as_matrix ();
|
||||
auto m = util::matrix4f::rotation (r.mag, r.axis);
|
||||
auto m = util::rotation<float> (r.mag, r.axis);
|
||||
auto diff = util::abs (q - m);
|
||||
|
||||
tap.expect_lt (util::sum (diff), 1e-6f, "single basis rotation %zu", i);
|
||||
@ -97,7 +97,7 @@ main (void)
|
||||
|
||||
for (auto r: ROTATIONS) {
|
||||
q = q.angle_axis (r.mag, r.axis) * q;
|
||||
m = m.rotation (r.mag, r.axis) * m;
|
||||
m = util::rotation<float> (r.mag, r.axis) * m;
|
||||
}
|
||||
|
||||
auto diff = util::abs (q.as_matrix () - m);
|
||||
|
@ -6,8 +6,12 @@ int
|
||||
main (int, char**)
|
||||
{
|
||||
util::TAP::logger tap;
|
||||
|
||||
const char csv[] = "\0,a,123,,this is a test,";
|
||||
|
||||
// the string_literal prefix is required to (easily) construct a string
|
||||
// with an internal null character.
|
||||
using namespace std::literals::string_literals;
|
||||
const std::string csv = "\0,a,123,,this is a test,"s;
|
||||
|
||||
const std::string values[] = {
|
||||
{ "\0", 1 },
|
||||
{ "a" },
|
||||
@ -17,8 +21,7 @@ main (int, char**)
|
||||
{ "" }
|
||||
};
|
||||
|
||||
std::string str (std::cbegin (csv), std::cbegin (csv) + std::size (csv));
|
||||
auto tok = util::make_tokeniser (str, ',');
|
||||
auto tok = util::make_tokeniser (csv, ',');
|
||||
auto t_cursor = tok.cbegin ();
|
||||
auto v_cursor = std::cbegin (values);
|
||||
|
||||
|
@ -22,9 +22,9 @@
|
||||
|
||||
namespace util {
|
||||
template <size_t S, typename T>
|
||||
struct vector : public coord::base<S,T,vector,coord::xyzw,coord::stpq>
|
||||
struct vector : public coord::base<S,T,vector<S,T>>
|
||||
{
|
||||
using coord::base<S,T,util::vector,coord::xyzw,coord::stpq>::base;
|
||||
using coord::base<S,T,vector<S,T>>::base;
|
||||
|
||||
// representations
|
||||
template <size_t D> vector<D,T> homog (void) const;
|
||||
|
Loading…
Reference in New Issue
Block a user