mirror of https://github.com/godotengine/godot
manifold: Update to 3.3.2
This commit is contained in:
parent
08e6cd181f
commit
3a48029fc2
|
|
@ -658,7 +658,7 @@ See `linuxbsd_headers/README.md`.
|
|||
## manifold
|
||||
|
||||
- Upstream: https://github.com/elalish/manifold
|
||||
- Version: git (76208dc02b069d2be50ed2d8a9279ee5622fa5fd, 2025)
|
||||
- Version: 3.3.2 (798d83c8d7fabcddd23c1617097b95ba40f2597c, 2025)
|
||||
- License: Apache 2.0
|
||||
|
||||
File extracted from upstream source:
|
||||
|
|
|
|||
|
|
@ -488,80 +488,12 @@ constexpr double DEFAULT_LENGTH = 1.0;
|
|||
*/
|
||||
class Quality {
|
||||
private:
|
||||
inline static int circularSegments_ = DEFAULT_SEGMENTS;
|
||||
inline static double circularAngle_ = DEFAULT_ANGLE;
|
||||
inline static double circularEdgeLength_ = DEFAULT_LENGTH;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Sets an angle constraint the default number of circular segments for the
|
||||
* CrossSection::Circle(), Manifold::Cylinder(), Manifold::Sphere(), and
|
||||
* Manifold::Revolve() constructors. The number of segments will be rounded up
|
||||
* to the nearest factor of four.
|
||||
*
|
||||
* @param angle The minimum angle in degrees between consecutive segments. The
|
||||
* angle will increase if the the segments hit the minimum edge length.
|
||||
* Default is 10 degrees.
|
||||
*/
|
||||
static void SetMinCircularAngle(double angle) {
|
||||
if (angle <= 0) return;
|
||||
circularAngle_ = angle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a length constraint the default number of circular segments for the
|
||||
* CrossSection::Circle(), Manifold::Cylinder(), Manifold::Sphere(), and
|
||||
* Manifold::Revolve() constructors. The number of segments will be rounded up
|
||||
* to the nearest factor of four.
|
||||
*
|
||||
* @param length The minimum length of segments. The length will
|
||||
* increase if the the segments hit the minimum angle. Default is 1.0.
|
||||
*/
|
||||
static void SetMinCircularEdgeLength(double length) {
|
||||
if (length <= 0) return;
|
||||
circularEdgeLength_ = length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default number of circular segments for the
|
||||
* CrossSection::Circle(), Manifold::Cylinder(), Manifold::Sphere(), and
|
||||
* Manifold::Revolve() constructors. Overrides the edge length and angle
|
||||
* constraints and sets the number of segments to exactly this value.
|
||||
*
|
||||
* @param number Number of circular segments. Default is 0, meaning no
|
||||
* constraint is applied.
|
||||
*/
|
||||
static void SetCircularSegments(int number) {
|
||||
if (number < 3 && number != 0) return;
|
||||
circularSegments_ = number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the result of the SetMinCircularAngle(),
|
||||
* SetMinCircularEdgeLength(), and SetCircularSegments() defaults.
|
||||
*
|
||||
* @param radius For a given radius of circle, determine how many default
|
||||
* segments there will be.
|
||||
*/
|
||||
static int GetCircularSegments(double radius) {
|
||||
if (circularSegments_ > 0) return circularSegments_;
|
||||
int nSegA = 360.0 / circularAngle_;
|
||||
int nSegL = 2.0 * radius * kPi / circularEdgeLength_;
|
||||
int nSeg = fmin(nSegA, nSegL) + 3;
|
||||
nSeg -= nSeg % 4;
|
||||
return std::max(nSeg, 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the circular construction parameters to their defaults if
|
||||
* SetMinCircularAngle, SetMinCircularEdgeLength, or SetCircularSegments have
|
||||
* been called.
|
||||
*/
|
||||
static void ResetToDefaults() {
|
||||
circularSegments_ = DEFAULT_SEGMENTS;
|
||||
circularAngle_ = DEFAULT_ANGLE;
|
||||
circularEdgeLength_ = DEFAULT_LENGTH;
|
||||
}
|
||||
static void SetMinCircularAngle(double angle);
|
||||
static void SetMinCircularEdgeLength(double length);
|
||||
static void SetCircularSegments(int number);
|
||||
static int GetCircularSegments(double radius);
|
||||
static void ResetToDefaults();
|
||||
};
|
||||
/** @} */
|
||||
|
||||
|
|
@ -600,39 +532,6 @@ struct ExecutionParams {
|
|||
/** @} */
|
||||
|
||||
#ifdef MANIFOLD_DEBUG
|
||||
template <class T>
|
||||
std::ostream& operator<<(std::ostream& out, const la::vec<T, 1>& v) {
|
||||
return out << '{' << v[0] << '}';
|
||||
}
|
||||
template <class T>
|
||||
std::ostream& operator<<(std::ostream& out, const la::vec<T, 2>& v) {
|
||||
return out << '{' << v[0] << ',' << v[1] << '}';
|
||||
}
|
||||
template <class T>
|
||||
std::ostream& operator<<(std::ostream& out, const la::vec<T, 3>& v) {
|
||||
return out << '{' << v[0] << ',' << v[1] << ',' << v[2] << '}';
|
||||
}
|
||||
template <class T>
|
||||
std::ostream& operator<<(std::ostream& out, const la::vec<T, 4>& v) {
|
||||
return out << '{' << v[0] << ',' << v[1] << ',' << v[2] << ',' << v[3] << '}';
|
||||
}
|
||||
|
||||
template <class T, int M>
|
||||
std::ostream& operator<<(std::ostream& out, const la::mat<T, M, 1>& m) {
|
||||
return out << '{' << m[0] << '}';
|
||||
}
|
||||
template <class T, int M>
|
||||
std::ostream& operator<<(std::ostream& out, const la::mat<T, M, 2>& m) {
|
||||
return out << '{' << m[0] << ',' << m[1] << '}';
|
||||
}
|
||||
template <class T, int M>
|
||||
std::ostream& operator<<(std::ostream& out, const la::mat<T, M, 3>& m) {
|
||||
return out << '{' << m[0] << ',' << m[1] << ',' << m[2] << '}';
|
||||
}
|
||||
template <class T, int M>
|
||||
std::ostream& operator<<(std::ostream& out, const la::mat<T, M, 4>& m) {
|
||||
return out << '{' << m[0] << ',' << m[1] << ',' << m[2] << ',' << m[3] << '}';
|
||||
}
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& stream, const Box& box) {
|
||||
return stream << "min: " << box.min << ", "
|
||||
|
|
|
|||
|
|
@ -2360,6 +2360,46 @@ struct converter<std::array<T, 4>, vec<T, 4>> {
|
|||
/** @} */
|
||||
} // namespace linalg
|
||||
|
||||
#ifdef MANIFOLD_DEBUG
|
||||
#include <iostream>
|
||||
|
||||
namespace linalg {
|
||||
template <class T>
|
||||
std::ostream& operator<<(std::ostream& out, const vec<T, 1>& v) {
|
||||
return out << '{' << v[0] << '}';
|
||||
}
|
||||
template <class T>
|
||||
std::ostream& operator<<(std::ostream& out, const vec<T, 2>& v) {
|
||||
return out << '{' << v[0] << ',' << v[1] << '}';
|
||||
}
|
||||
template <class T>
|
||||
std::ostream& operator<<(std::ostream& out, const vec<T, 3>& v) {
|
||||
return out << '{' << v[0] << ',' << v[1] << ',' << v[2] << '}';
|
||||
}
|
||||
template <class T>
|
||||
std::ostream& operator<<(std::ostream& out, const vec<T, 4>& v) {
|
||||
return out << '{' << v[0] << ',' << v[1] << ',' << v[2] << ',' << v[3] << '}';
|
||||
}
|
||||
|
||||
template <class T, int M>
|
||||
std::ostream& operator<<(std::ostream& out, const mat<T, M, 1>& m) {
|
||||
return out << '{' << m[0] << '}';
|
||||
}
|
||||
template <class T, int M>
|
||||
std::ostream& operator<<(std::ostream& out, const mat<T, M, 2>& m) {
|
||||
return out << '{' << m[0] << ',' << m[1] << '}';
|
||||
}
|
||||
template <class T, int M>
|
||||
std::ostream& operator<<(std::ostream& out, const mat<T, M, 3>& m) {
|
||||
return out << '{' << m[0] << ',' << m[1] << ',' << m[2] << '}';
|
||||
}
|
||||
template <class T, int M>
|
||||
std::ostream& operator<<(std::ostream& out, const mat<T, M, 4>& m) {
|
||||
return out << '{' << m[0] << ',' << m[1] << ',' << m[2] << ',' << m[3] << '}';
|
||||
}
|
||||
} // namespace linalg
|
||||
#endif
|
||||
|
||||
namespace std {
|
||||
/** @addtogroup hash
|
||||
* @ingroup LinAlg
|
||||
|
|
|
|||
|
|
@ -878,10 +878,6 @@ Manifold::Impl Boolean3::Result(OpType op) const {
|
|||
#endif
|
||||
|
||||
// Level 6
|
||||
|
||||
if (ManifoldParams().intermediateChecks)
|
||||
DEBUG_ASSERT(outR.IsManifold(), logicErr, "polygon mesh is not manifold!");
|
||||
|
||||
outR.Face2Tri(faceEdge, halfedgeRef);
|
||||
halfedgeRef.clear();
|
||||
faceEdge.clear();
|
||||
|
|
|
|||
|
|
@ -342,7 +342,9 @@ std::shared_ptr<CsgLeafNode> BatchBoolean(
|
|||
std::vector<std::shared_ptr<CsgLeafNode>> tmp;
|
||||
#if MANIFOLD_PAR == 1
|
||||
tbb::task_group group;
|
||||
std::mutex mutex;
|
||||
// make sure the order of result is deterministic
|
||||
std::vector<std::shared_ptr<CsgLeafNode>> parallelTmp;
|
||||
for (int i = 0; i < 4; i++) parallelTmp.push_back(nullptr);
|
||||
#endif
|
||||
while (results.size() > 1) {
|
||||
for (size_t i = 0; i < 4 && results.size() > 1; i++) {
|
||||
|
|
@ -353,11 +355,8 @@ std::shared_ptr<CsgLeafNode> BatchBoolean(
|
|||
auto b = std::move(results.back());
|
||||
results.pop_back();
|
||||
#if MANIFOLD_PAR == 1
|
||||
group.run([&, a, b]() {
|
||||
auto result = SimpleBoolean(*a->GetImpl(), *b->GetImpl(), operation);
|
||||
mutex.lock();
|
||||
tmp.push_back(result);
|
||||
mutex.unlock();
|
||||
group.run([&, i, a, b]() {
|
||||
parallelTmp[i] = SimpleBoolean(*a->GetImpl(), *b->GetImpl(), operation);
|
||||
});
|
||||
#else
|
||||
auto result = SimpleBoolean(*a->GetImpl(), *b->GetImpl(), operation);
|
||||
|
|
@ -366,6 +365,8 @@ std::shared_ptr<CsgLeafNode> BatchBoolean(
|
|||
}
|
||||
#if MANIFOLD_PAR == 1
|
||||
group.wait();
|
||||
for (int i = 0; i < 4 && parallelTmp[i]; i++)
|
||||
tmp.emplace_back(std::move(parallelTmp[i]));
|
||||
#endif
|
||||
for (auto result : tmp) {
|
||||
results.push_back(result);
|
||||
|
|
@ -617,6 +618,7 @@ std::shared_ptr<CsgLeafNode> CsgOpNode::ToLeafNode() const {
|
|||
std::shared_ptr<CsgStackFrame> frame = stack.back();
|
||||
auto impl = frame->op_node->impl_.GetGuard();
|
||||
if (frame->finalize) {
|
||||
if (!frame->op_node->cache_) {
|
||||
switch (frame->op_node->op_) {
|
||||
case OpType::Add:
|
||||
*impl = {BatchUnion(frame->positive_children)};
|
||||
|
|
@ -636,14 +638,15 @@ std::shared_ptr<CsgLeafNode> CsgOpNode::ToLeafNode() const {
|
|||
*impl = {frame->positive_children[0]};
|
||||
} else {
|
||||
auto negative = BatchUnion(frame->negative_children);
|
||||
*impl = {SimpleBoolean(*positive->GetImpl(), *negative->GetImpl(),
|
||||
OpType::Subtract)};
|
||||
*impl = {SimpleBoolean(*positive->GetImpl(),
|
||||
*negative->GetImpl(), OpType::Subtract)};
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
frame->op_node->cache_ = std::static_pointer_cast<CsgLeafNode>(
|
||||
(*impl)[0]->Transform(frame->op_node->transform_));
|
||||
}
|
||||
if (frame->positive_dest != nullptr)
|
||||
frame->positive_dest->push_back(std::static_pointer_cast<CsgLeafNode>(
|
||||
frame->op_node->cache_->Transform(frame->transform)));
|
||||
|
|
|
|||
|
|
@ -202,6 +202,7 @@ namespace manifold {
|
|||
*/
|
||||
void Manifold::Impl::CleanupTopology() {
|
||||
if (!halfedge_.size()) return;
|
||||
DEBUG_ASSERT(IsManifold(), logicErr, "polygon mesh is not manifold!");
|
||||
|
||||
// In the case of a very bad triangulation, it is possible to create pinched
|
||||
// verts. They must be removed before edge collapse.
|
||||
|
|
|
|||
|
|
@ -149,8 +149,12 @@ int GetLabels(std::vector<int>& components,
|
|||
namespace manifold {
|
||||
|
||||
#if (MANIFOLD_PAR == 1)
|
||||
#if (TBB_VERSION_MAJOR < 2021)
|
||||
tbb::task_arena gc_arena(1, 1);
|
||||
#else
|
||||
tbb::task_arena gc_arena(1, 1, tbb::task_arena::priority::low);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
std::atomic<uint32_t> Manifold::Impl::meshIDCounter_(1);
|
||||
|
||||
|
|
@ -484,7 +488,8 @@ void Manifold::Impl::CreateHalfedges(const Vec<ivec3>& triProp,
|
|||
const int pair1 = ids[k];
|
||||
Halfedge& h1 = halfedge_[pair1];
|
||||
if (h0.startVert != h1.endVert || h0.endVert != h1.startVert) break;
|
||||
if (halfedge_[NextHalfedge(pair0)].endVert ==
|
||||
if (h1.pairedHalfedge != kRemovedHalfedge &&
|
||||
halfedge_[NextHalfedge(pair0)].endVert ==
|
||||
halfedge_[NextHalfedge(pair1)].endVert) {
|
||||
h0.pairedHalfedge = h1.pairedHalfedge = kRemovedHalfedge;
|
||||
// Reorder so that remaining edges pair up
|
||||
|
|
|
|||
|
|
@ -68,6 +68,16 @@ struct Manifold::Impl {
|
|||
const uint32_t numVert = meshGL.NumVert();
|
||||
const uint32_t numTri = meshGL.NumTri();
|
||||
|
||||
if (numVert == 0 && numTri == 0) {
|
||||
MakeEmpty(Error::NoError);
|
||||
return;
|
||||
}
|
||||
|
||||
if (numVert < 4 || numTri < 4) {
|
||||
MakeEmpty(Error::NotManifold);
|
||||
return;
|
||||
}
|
||||
|
||||
if (meshGL.numProp < 3) {
|
||||
MakeEmpty(Error::MissingPositionProperties);
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -200,6 +200,80 @@ MeshGLP<Precision, I> GetMeshGLImpl(const manifold::Manifold::Impl& impl,
|
|||
|
||||
namespace manifold {
|
||||
|
||||
static int circularSegments_ = DEFAULT_SEGMENTS;
|
||||
static double circularAngle_ = DEFAULT_ANGLE;
|
||||
static double circularEdgeLength_ = DEFAULT_LENGTH;
|
||||
|
||||
/**
|
||||
* Sets an angle constraint the default number of circular segments for the
|
||||
* CrossSection::Circle(), Manifold::Cylinder(), Manifold::Sphere(), and
|
||||
* Manifold::Revolve() constructors. The number of segments will be rounded up
|
||||
* to the nearest factor of four.
|
||||
*
|
||||
* @param angle The minimum angle in degrees between consecutive segments. The
|
||||
* angle will increase if the the segments hit the minimum edge length.
|
||||
* Default is 10 degrees.
|
||||
*/
|
||||
void Quality::SetMinCircularAngle(double angle) {
|
||||
if (angle <= 0) return;
|
||||
circularAngle_ = angle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a length constraint the default number of circular segments for the
|
||||
* CrossSection::Circle(), Manifold::Cylinder(), Manifold::Sphere(), and
|
||||
* Manifold::Revolve() constructors. The number of segments will be rounded up
|
||||
* to the nearest factor of four.
|
||||
*
|
||||
* @param length The minimum length of segments. The length will
|
||||
* increase if the the segments hit the minimum angle. Default is 1.0.
|
||||
*/
|
||||
void Quality::SetMinCircularEdgeLength(double length) {
|
||||
if (length <= 0) return;
|
||||
circularEdgeLength_ = length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default number of circular segments for the
|
||||
* CrossSection::Circle(), Manifold::Cylinder(), Manifold::Sphere(), and
|
||||
* Manifold::Revolve() constructors. Overrides the edge length and angle
|
||||
* constraints and sets the number of segments to exactly this value.
|
||||
*
|
||||
* @param number Number of circular segments. Default is 0, meaning no
|
||||
* constraint is applied.
|
||||
*/
|
||||
void Quality::SetCircularSegments(int number) {
|
||||
if (number < 3 && number != 0) return;
|
||||
circularSegments_ = number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the result of the SetMinCircularAngle(),
|
||||
* SetMinCircularEdgeLength(), and SetCircularSegments() defaults.
|
||||
*
|
||||
* @param radius For a given radius of circle, determine how many default
|
||||
* segments there will be.
|
||||
*/
|
||||
int Quality::GetCircularSegments(double radius) {
|
||||
if (circularSegments_ > 0) return circularSegments_;
|
||||
int nSegA = 360.0 / circularAngle_;
|
||||
int nSegL = 2.0 * radius * kPi / circularEdgeLength_;
|
||||
int nSeg = fmin(nSegA, nSegL) + 3;
|
||||
nSeg -= nSeg % 4;
|
||||
return std::max(nSeg, 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the circular construction parameters to their defaults if
|
||||
* SetMinCircularAngle, SetMinCircularEdgeLength, or SetCircularSegments have
|
||||
* been called.
|
||||
*/
|
||||
void Quality::ResetToDefaults() {
|
||||
circularSegments_ = DEFAULT_SEGMENTS;
|
||||
circularAngle_ = DEFAULT_ANGLE;
|
||||
circularEdgeLength_ = DEFAULT_LENGTH;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an empty Manifold.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -73,7 +73,13 @@ struct CheckHalfedges {
|
|||
|
||||
bool operator()(size_t edge) const {
|
||||
const Halfedge halfedge = halfedges[edge];
|
||||
if (halfedge.startVert == -1 || halfedge.endVert == -1) return true;
|
||||
if (halfedge.startVert == -1 && halfedge.endVert == -1 &&
|
||||
halfedge.pairedHalfedge == -1)
|
||||
return true;
|
||||
if (halfedges[NextHalfedge(edge)].startVert == -1 ||
|
||||
halfedges[NextHalfedge(NextHalfedge(edge))].startVert == -1) {
|
||||
return false;
|
||||
}
|
||||
if (halfedge.pairedHalfedge == -1) return false;
|
||||
|
||||
const Halfedge paired = halfedges[halfedge.pairedHalfedge];
|
||||
|
|
@ -114,6 +120,7 @@ namespace manifold {
|
|||
*/
|
||||
bool Manifold::Impl::IsManifold() const {
|
||||
if (halfedge_.size() == 0) return true;
|
||||
if (halfedge_.size() % 3 != 0) return false;
|
||||
return all_of(countAt(0_uz), countAt(halfedge_.size()),
|
||||
CheckHalfedges({halfedge_}));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,9 @@
|
|||
#include "quickhull.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <limits>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "impl.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include "impl.h"
|
||||
#include "parallel.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,225 +0,0 @@
|
|||
// Copyright 2021 The Manifold Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
#include "./parallel.h"
|
||||
#include "./utils.h"
|
||||
#include "./vec.h"
|
||||
#include "manifold/common.h"
|
||||
#include "manifold/optional_assert.h"
|
||||
|
||||
namespace {
|
||||
template <typename T>
|
||||
inline bool FirstFinite(T v) {
|
||||
return std::isfinite(v[0]);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool FirstFinite<double>(double v) {
|
||||
return std::isfinite(v);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace manifold {
|
||||
|
||||
/** @ingroup Private */
|
||||
class SparseIndices {
|
||||
// sparse indices where {p1: q1, p2: q2, ...} are laid out as
|
||||
// p1 q1 p2 q2 or q1 p1 q2 p2, depending on endianness
|
||||
// such that the indices are sorted by (p << 32) | q
|
||||
public:
|
||||
#if defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN || \
|
||||
defined(__BIG_ENDIAN__) || defined(__ARMEB__) || defined(__THUMBEB__) || \
|
||||
defined(__AARCH64EB__) || defined(_MIBSEB) || defined(__MIBSEB) || \
|
||||
defined(__MIBSEB__)
|
||||
static constexpr size_t pOffset = 0;
|
||||
#elif defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN || \
|
||||
defined(__LITTLE_ENDIAN__) || defined(__ARMEL__) || \
|
||||
defined(__THUMBEL__) || defined(__AARCH64EL__) || defined(_MIPSEL) || \
|
||||
defined(__MIPSEL) || defined(__MIPSEL__) || defined(__EMSCRIPTEN__) || \
|
||||
defined(_WIN32)
|
||||
static constexpr size_t pOffset = 1;
|
||||
#else
|
||||
#error "unknown architecture"
|
||||
#endif
|
||||
static constexpr int64_t EncodePQ(int p, int q) {
|
||||
return (int64_t(p) << 32) | q;
|
||||
}
|
||||
|
||||
SparseIndices() = default;
|
||||
SparseIndices(size_t size) { data_ = Vec<char>(size * sizeof(int64_t)); }
|
||||
|
||||
void Clear() { data_.clear(false); }
|
||||
|
||||
void FromIndices(const std::vector<SparseIndices>& indices) {
|
||||
std::vector<size_t> sizes;
|
||||
size_t total_size = 0;
|
||||
for (const auto& ind : indices) {
|
||||
sizes.push_back(total_size);
|
||||
total_size += ind.data_.size();
|
||||
}
|
||||
data_ = Vec<char>(total_size);
|
||||
for_each_n(ExecutionPolicy::Par, countAt(0), indices.size(), [&](size_t i) {
|
||||
std::copy(indices[i].data_.begin(), indices[i].data_.end(),
|
||||
data_.begin() + sizes[i]);
|
||||
});
|
||||
}
|
||||
|
||||
size_t size() const { return data_.size() / sizeof(int64_t); }
|
||||
|
||||
Vec<int> Copy(bool use_q) const {
|
||||
Vec<int> out(size());
|
||||
size_t offset = pOffset;
|
||||
if (use_q) offset = 1 - offset;
|
||||
const int* p = ptr();
|
||||
for_each(autoPolicy(out.size()), countAt(0_uz), countAt(out.size()),
|
||||
[&](size_t i) { out[i] = p[i * 2 + offset]; });
|
||||
return out;
|
||||
}
|
||||
|
||||
void Sort() {
|
||||
VecView<int64_t> view = AsVec64();
|
||||
stable_sort(view.begin(), view.end());
|
||||
}
|
||||
|
||||
void Resize(size_t size) { data_.resize(size * sizeof(int64_t), -1); }
|
||||
|
||||
inline int& Get(size_t i, bool use_q) {
|
||||
if (use_q)
|
||||
return ptr()[2 * i + 1 - pOffset];
|
||||
else
|
||||
return ptr()[2 * i + pOffset];
|
||||
}
|
||||
|
||||
inline int Get(size_t i, bool use_q) const {
|
||||
if (use_q)
|
||||
return ptr()[2 * i + 1 - pOffset];
|
||||
else
|
||||
return ptr()[2 * i + pOffset];
|
||||
}
|
||||
|
||||
inline int64_t GetPQ(size_t i) const {
|
||||
VecView<const int64_t> view = AsVec64();
|
||||
return view[i];
|
||||
}
|
||||
|
||||
inline void Set(size_t i, int p, int q) {
|
||||
VecView<int64_t> view = AsVec64();
|
||||
view[i] = EncodePQ(p, q);
|
||||
}
|
||||
|
||||
inline void SetPQ(size_t i, int64_t pq) {
|
||||
VecView<int64_t> view = AsVec64();
|
||||
view[i] = pq;
|
||||
}
|
||||
|
||||
VecView<int64_t> AsVec64() {
|
||||
return VecView<int64_t>(reinterpret_cast<int64_t*>(data_.data()),
|
||||
data_.size() / sizeof(int64_t));
|
||||
}
|
||||
|
||||
VecView<const int64_t> AsVec64() const {
|
||||
return VecView<const int64_t>(
|
||||
reinterpret_cast<const int64_t*>(data_.data()),
|
||||
data_.size() / sizeof(int64_t));
|
||||
}
|
||||
|
||||
VecView<int32_t> AsVec32() {
|
||||
return VecView<int32_t>(reinterpret_cast<int32_t*>(data_.data()),
|
||||
data_.size() / sizeof(int32_t));
|
||||
}
|
||||
|
||||
VecView<const int32_t> AsVec32() const {
|
||||
return VecView<const int32_t>(
|
||||
reinterpret_cast<const int32_t*>(data_.data()),
|
||||
data_.size() / sizeof(int32_t));
|
||||
}
|
||||
|
||||
inline void Add(int p, int q, bool seq = false) {
|
||||
data_.extend(sizeof(int64_t), seq);
|
||||
Set(size() - 1, p, q);
|
||||
}
|
||||
|
||||
void Unique() {
|
||||
Sort();
|
||||
VecView<int64_t> view = AsVec64();
|
||||
size_t newSize = unique(view.begin(), view.end()) - view.begin();
|
||||
Resize(newSize);
|
||||
}
|
||||
|
||||
size_t RemoveZeros(Vec<int>& S) {
|
||||
DEBUG_ASSERT(S.size() == size(), userErr,
|
||||
"Different number of values than indicies!");
|
||||
|
||||
Vec<size_t> new2Old(S.size());
|
||||
sequence(new2Old.begin(), new2Old.end());
|
||||
|
||||
size_t size = copy_if(countAt(0_uz), countAt(S.size()), new2Old.begin(),
|
||||
[&S](const size_t i) { return S[i] != 0; }) -
|
||||
new2Old.begin();
|
||||
new2Old.resize(size);
|
||||
|
||||
Permute(S, new2Old);
|
||||
Vec<char> tmp(std::move(data_));
|
||||
Resize(size);
|
||||
gather(new2Old.begin(), new2Old.end(),
|
||||
reinterpret_cast<int64_t*>(tmp.data()),
|
||||
reinterpret_cast<int64_t*>(data_.data()));
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
size_t KeepFinite(Vec<T>& v, Vec<int>& x) {
|
||||
DEBUG_ASSERT(x.size() == size(), userErr,
|
||||
"Different number of values than indicies!");
|
||||
|
||||
Vec<int> new2Old(v.size());
|
||||
size_t size = copy_if(countAt(0_uz), countAt(v.size()), new2Old.begin(),
|
||||
[&v](size_t i) { return FirstFinite(v[i]); }) -
|
||||
new2Old.begin();
|
||||
new2Old.resize(size);
|
||||
|
||||
Permute(v, new2Old);
|
||||
Permute(x, new2Old);
|
||||
Vec<char> tmp(std::move(data_));
|
||||
Resize(size);
|
||||
gather(new2Old.begin(), new2Old.end(),
|
||||
reinterpret_cast<int64_t*>(tmp.data()),
|
||||
reinterpret_cast<int64_t*>(data_.data()));
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
#ifdef MANIFOLD_DEBUG
|
||||
void Dump() const {
|
||||
std::cout << "SparseIndices = " << std::endl;
|
||||
const int* p = ptr();
|
||||
for (size_t i = 0; i < size(); ++i) {
|
||||
std::cout << i << ", p = " << Get(i, false) << ", q = " << Get(i, true)
|
||||
<< std::endl;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
Vec<char> data_;
|
||||
inline int* ptr() { return reinterpret_cast<int32_t*>(data_.data()); }
|
||||
inline const int* ptr() const {
|
||||
return reinterpret_cast<const int32_t*>(data_.data());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace manifold
|
||||
|
|
@ -12,6 +12,8 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include "impl.h"
|
||||
#include "parallel.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -228,10 +228,14 @@ class Vec : public VecView<T> {
|
|||
// Currently it is set to 64 pages (4kB page).
|
||||
constexpr size_t ASYNC_FREE_THRESHOLD = 1 << 18;
|
||||
TracyFreeS(ptr, 3);
|
||||
#if defined(__has_feature)
|
||||
#if !__has_feature(address_sanitizer)
|
||||
#if (MANIFOLD_PAR == 1)
|
||||
if (size * sizeof(T) > ASYNC_FREE_THRESHOLD)
|
||||
gc_arena.enqueue([ptr]() { free(ptr); });
|
||||
else
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
free(ptr);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue