extract explicit mesh with topology information from implicit surfaces with boolean operations, and do surface/volume integrating on them.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

271 lines
8.5 KiB

#pragma once
#include <utils/eigen_alias.hpp>
// ======================================================================
// AABB
// ======================================================================
struct aabb_t {
Eigen::Vector3d min{std::numeric_limits<double>::max(),
std::numeric_limits<double>::max(),
std::numeric_limits<double>::max()};
Eigen::Vector3d max{std::numeric_limits<double>::min(),
std::numeric_limits<double>::min(),
std::numeric_limits<double>::min()};
void extend(const Eigen::Vector3d& point)
{
min = min.cwiseMin(point);
max = max.cwiseMax(point);
}
void extend(const aabb_t& aabb)
{
min = min.cwiseMin(aabb.min);
max = max.cwiseMax(aabb.max);
}
void offset(const Eigen::Vector3d& offset)
{
min = min + offset;
max = max + offset;
}
};
// ======================================================================
// Node
// ======================================================================
struct node_t {
uint64_t data[2];
constexpr node_t() : data{0, 0} {}
constexpr node_t(const uint64_t n1, const uint64_t n2) : data{n1, n2} {}
template <typename T, typename = std::enable_if_t<sizeof(T) <= sizeof(uint64_t)>>
constexpr node_t(T value)
{
data[0] = 0;
data[1] = static_cast<uint64_t>(value);
}
template <typename T, typename = std::enable_if_t<sizeof(T) <= sizeof(uint64_t)>>
constexpr operator T() const
{
return static_cast<T>(data[1]);
}
node_t operator>>(const uint32_t shift) const
{
if (shift == 0) { return *this; }
node_t result = *this;
if (shift >= 128) {
result.data[0] = 0;
result.data[1] = 0;
} else if (shift >= 64) {
result.data[1] = this->data[0] >> (shift - 64);
result.data[0] = 0;
} else {
result.data[1] = (this->data[1] >> shift) | (this->data[0] << (64 - shift));
result.data[0] = this->data[0] >> shift;
}
return result;
}
node_t operator<<(const uint32_t shift) const
{
if (shift == 0) { return *this; }
node_t result = *this;
if (shift >= 128) {
result.data[0] = 0;
result.data[1] = 0;
} else if (shift >= 64) {
result.data[0] = this->data[1] << (shift - 64);
result.data[1] = 0;
} else {
result.data[0] = (this->data[0] << shift) | (this->data[1] >> (64 - shift));
result.data[1] = this->data[1] << shift;
}
return result;
}
const node_t operator&(const node_t& other) const
{
node_t result = *this;
result.data[0] &= other.data[0];
result.data[1] &= other.data[1];
return result;
}
friend const node_t operator&(node_t, const uint32_t&);
const node_t operator|(const node_t& other) const
{
node_t result = *this;
result.data[0] |= other.data[0];
result.data[1] |= other.data[1];
return result;
}
friend const node_t operator|(node_t, const uint32_t&);
const node_t operator~() const
{
node_t result = *this;
result.data[0] = ~result.data[0];
result.data[1] = ~result.data[1];
return result;
}
};
inline const node_t operator&(node_t lhs, const uint32_t& rhs)
{
lhs.data[1] &= rhs;
return lhs;
}
inline const node_t operator|(node_t lhs, const uint32_t& rhs)
{
lhs.data[1] |= rhs;
return lhs;
}
enum class eNodeLocation : uint32_t { in = 0, out = 1, edge = 2, unset = 3 };
enum class eNodeOperation : uint32_t { unionOp = 0, intersectionOp = 1, differenceOp = 2, unsetOp = 3 };
/* getter/setter for node_t */
template <typename _Tp>
struct node_proxy {
constexpr node_proxy() = default;
constexpr node_proxy(node_t& _data, uint32_t _offset, node_t _mask) : data(&_data), offset(_offset), mask(_mask) {}
void reinit(node_t& _data, uint32_t _offset, node_t _mask)
{
data = &_data;
offset = _offset;
mask = _mask;
}
void reinit(node_proxy&& other)
{
data = std::move(other.data);
offset = std::move(other.offset);
mask = std::move(other.mask);
}
node_proxy(const node_proxy&) = delete;
node_proxy(node_proxy&&) = delete;
constexpr node_proxy& operator=(const node_proxy& other)
{
const auto _mask = mask << offset;
*data = (*data & ~_mask) | (other.data & _mask);
return *this;
}
constexpr node_proxy& operator=(node_proxy&& other)
{
const auto _mask = mask << offset;
*data = (*data & ~_mask) | (std::forward(other.data) & _mask);
return *this;
}
template <typename _Fp, typename = std::enable_if_t<!std::is_same_v<_Fp, node_proxy>>>
constexpr node_proxy& operator=(_Fp&& other)
{
const auto _mask = mask << offset;
if constexpr (std::is_enum_v<_Fp>) {
const auto offset_value = static_cast<std::underlying_type_t<_Fp>>(std::forward<_Fp>(other)) << offset;
*data = (*data & ~_mask) | (_mask & offset_value);
} else if constexpr (std::is_same_v<_Fp, bool>) {
const auto offset_value = static_cast<uint32_t>(std::forward<_Fp>(other)) << offset;
*data = (*data & ~_mask) | (_mask & offset_value);
} else {
const auto offset_value = std::forward<_Fp>(other) << offset;
*data = (*data & ~_mask) | (_mask & offset_value);
}
return *this;
}
template <typename _Fp,
typename = std::enable_if_t<!std::is_same_v<_Fp, node_proxy> && //
!std::is_enum_v<_Fp> && //
!std::is_same_v<_Fp, bool>>>
constexpr node_proxy& operator+=(_Fp&& other)
{
const auto _mask = mask << offset;
const _Fp low_data = (*data) >> offset;
const auto low_result = std::forward<_Fp>(other) + low_data;
*data = (*data & ~_mask) | (_mask & (low_result << offset));
return *this;
}
constexpr operator _Tp() const { return static_cast<_Tp>(((*data) >> offset) & mask); }
protected:
node_t* data;
uint32_t offset{};
node_t mask{};
};
template <typename _Tp>
struct const_node_proxy {
constexpr const_node_proxy(const node_t& _data, uint32_t _offset, node_t _mask) : data(&_data), offset(_offset), mask(_mask)
{
}
const_node_proxy(const const_node_proxy&) = delete;
const_node_proxy(const_node_proxy&&) = delete;
constexpr operator _Tp() const { return static_cast<_Tp>(((*data) >> offset) & mask); }
protected:
const node_t* data;
uint32_t offset{};
node_t mask{};
};
// 0 for internal node, 1 for primitive node
static constexpr inline auto node_fetch_is_primitive(node_t& node) { return node_proxy<bool>(node, 127u, 0x01u); }
// 0 for union, 1 for intersection, 2 for difference, 3 for unset
static constexpr inline auto node_fetch_operation(node_t& node) { return node_proxy<eNodeOperation>(node, 125u, 0x03u); }
// 0 for in, 1 for out, 2 for on edge, 3 for unset
static constexpr inline auto node_fetch_in_out(node_t& node) { return node_proxy<eNodeLocation>(node, 123u, 0x03u); }
// If primitive node, the index to the primitive information
static constexpr inline auto node_fetch_primitive_index(node_t& node) { return node_proxy<uint32_t>(node, 96u, 0xFFFFFFu); }
static constexpr inline auto node_is_parent_null(const node_t& node)
{
return const_node_proxy<uint32_t>(node, 96u, 0xFFFFFFu) == 0xFFFFFFFFu;
}
// Parent node index
static constexpr inline auto node_fetch_parent_index(node_t& node) { return node_proxy<uint32_t>(node, 64u, 0xFFFFFFFFu); }
// Left child node index
static constexpr inline auto node_fetch_left_child_index(node_t& node) { return node_proxy<uint32_t>(node, 32u, 0xFFFFFFFFu); }
static constexpr inline auto node_is_left_child_null(const node_t& node)
{
return const_node_proxy<uint32_t>(node, 32u, 0xFFFFFFFFu) == 0xFFFFFFFFu;
}
// Right child node index
static constexpr inline auto node_fetch_right_child_index(node_t& node) { return node_proxy<uint32_t>(node, 0u, 0xFFFFFFFFu); }
static constexpr inline auto node_is_right_child_null(const node_t& node)
{
return const_node_proxy<uint32_t>(node, 0u, 0xFFFFFFFFu) == 0xFFFFFFFFu;
}