mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-01 04:22:04 +08:00
ClipperLib sometimes hangs forever on a single union / diff / offset task.
Implemented optional time limit on ClipperLib execution.
This commit is contained in:
parent
b3b44681a9
commit
29719a7ab9
@ -116,7 +116,8 @@ using DoublePoint = Eigen::Matrix<double, 2, 1, Eigen::DontAlign>;
|
|||||||
|
|
||||||
template<typename BaseType>
|
template<typename BaseType>
|
||||||
using Allocator = tbb::scalable_allocator<BaseType>;
|
using Allocator = tbb::scalable_allocator<BaseType>;
|
||||||
using Path = std::vector<IntPoint, Allocator<IntPoint>>;
|
//using Allocator = std::allocator<BaseType>;
|
||||||
|
using Path = std::vector<IntPoint, Allocator<IntPoint>>;
|
||||||
using Paths = std::vector<Path, Allocator<Path>>;
|
using Paths = std::vector<Path, Allocator<Path>>;
|
||||||
|
|
||||||
inline Path& operator <<(Path& poly, const IntPoint& p) {poly.push_back(p); return poly;}
|
inline Path& operator <<(Path& poly, const IntPoint& p) {poly.push_back(p); return poly;}
|
||||||
|
@ -3,6 +3,20 @@
|
|||||||
#include "ShortestPath.hpp"
|
#include "ShortestPath.hpp"
|
||||||
#include "Utils.hpp"
|
#include "Utils.hpp"
|
||||||
|
|
||||||
|
// #define CLIPPER_UTILS_TIMING
|
||||||
|
|
||||||
|
#ifdef CLIPPER_UTILS_TIMING
|
||||||
|
// time limit for one ClipperLib operation (union / diff / offset), in ms
|
||||||
|
#define CLIPPER_UTILS_TIME_LIMIT_DEFAULT 50
|
||||||
|
#include <boost/current_function.hpp>
|
||||||
|
#include "Timer.hpp"
|
||||||
|
#define CLIPPER_UTILS_TIME_LIMIT_SECONDS(limit) Timing::TimeLimitAlarm time_limit_alarm(uint64_t(limit) * 1000000000l, BOOST_CURRENT_FUNCTION)
|
||||||
|
#define CLIPPER_UTILS_TIME_LIMIT_MILLIS(limit) Timing::TimeLimitAlarm time_limit_alarm(uint64_t(limit) * 1000000l, BOOST_CURRENT_FUNCTION)
|
||||||
|
#else
|
||||||
|
#define CLIPPER_UTILS_TIME_LIMIT_SECONDS(limit) do {} while(false)
|
||||||
|
#define CLIPPER_UTILS_TIME_LIMIT_MILLIS(limit) do {} while(false)
|
||||||
|
#endif // CLIPPER_UTILS_TIMING
|
||||||
|
|
||||||
// #define CLIPPER_UTILS_DEBUG
|
// #define CLIPPER_UTILS_DEBUG
|
||||||
|
|
||||||
#ifdef CLIPPER_UTILS_DEBUG
|
#ifdef CLIPPER_UTILS_DEBUG
|
||||||
@ -260,6 +274,8 @@ bool has_duplicate_points(const ClipperLib::PolyTree &polytree)
|
|||||||
template<typename PathsProvider, ClipperLib::EndType endType = ClipperLib::etClosedPolygon>
|
template<typename PathsProvider, ClipperLib::EndType endType = ClipperLib::etClosedPolygon>
|
||||||
static ClipperLib::Paths raw_offset(PathsProvider &&paths, float offset, ClipperLib::JoinType joinType, double miterLimit)
|
static ClipperLib::Paths raw_offset(PathsProvider &&paths, float offset, ClipperLib::JoinType joinType, double miterLimit)
|
||||||
{
|
{
|
||||||
|
CLIPPER_UTILS_TIME_LIMIT_MILLIS(CLIPPER_UTILS_TIME_LIMIT_DEFAULT);
|
||||||
|
|
||||||
ClipperLib::ClipperOffset co;
|
ClipperLib::ClipperOffset co;
|
||||||
ClipperLib::Paths out;
|
ClipperLib::Paths out;
|
||||||
out.reserve(paths.size());
|
out.reserve(paths.size());
|
||||||
@ -301,6 +317,8 @@ TResult clipper_do(
|
|||||||
TClip && clip,
|
TClip && clip,
|
||||||
const ClipperLib::PolyFillType fillType)
|
const ClipperLib::PolyFillType fillType)
|
||||||
{
|
{
|
||||||
|
CLIPPER_UTILS_TIME_LIMIT_MILLIS(CLIPPER_UTILS_TIME_LIMIT_DEFAULT);
|
||||||
|
|
||||||
ClipperLib::Clipper clipper;
|
ClipperLib::Clipper clipper;
|
||||||
clipper.AddPaths(std::forward<TSubj>(subject), ClipperLib::ptSubject, true);
|
clipper.AddPaths(std::forward<TSubj>(subject), ClipperLib::ptSubject, true);
|
||||||
clipper.AddPaths(std::forward<TClip>(clip), ClipperLib::ptClip, true);
|
clipper.AddPaths(std::forward<TClip>(clip), ClipperLib::ptClip, true);
|
||||||
@ -330,6 +348,8 @@ TResult clipper_union(
|
|||||||
// fillType pftNonZero and pftPositive "should" produce the same result for "normalized with implicit union" set of polygons
|
// fillType pftNonZero and pftPositive "should" produce the same result for "normalized with implicit union" set of polygons
|
||||||
const ClipperLib::PolyFillType fillType = ClipperLib::pftNonZero)
|
const ClipperLib::PolyFillType fillType = ClipperLib::pftNonZero)
|
||||||
{
|
{
|
||||||
|
CLIPPER_UTILS_TIME_LIMIT_MILLIS(CLIPPER_UTILS_TIME_LIMIT_DEFAULT);
|
||||||
|
|
||||||
ClipperLib::Clipper clipper;
|
ClipperLib::Clipper clipper;
|
||||||
clipper.AddPaths(std::forward<TSubj>(subject), ClipperLib::ptSubject, true);
|
clipper.AddPaths(std::forward<TSubj>(subject), ClipperLib::ptSubject, true);
|
||||||
TResult retval;
|
TResult retval;
|
||||||
@ -368,6 +388,8 @@ template<> void remove_outermost_polygon<ClipperLib::PolyTree>(ClipperLib::PolyT
|
|||||||
template<class TResult, typename PathsProvider>
|
template<class TResult, typename PathsProvider>
|
||||||
static TResult shrink_paths(PathsProvider &&paths, float offset, ClipperLib::JoinType joinType, double miterLimit)
|
static TResult shrink_paths(PathsProvider &&paths, float offset, ClipperLib::JoinType joinType, double miterLimit)
|
||||||
{
|
{
|
||||||
|
CLIPPER_UTILS_TIME_LIMIT_MILLIS(CLIPPER_UTILS_TIME_LIMIT_DEFAULT);
|
||||||
|
|
||||||
assert(offset > 0);
|
assert(offset > 0);
|
||||||
TResult out;
|
TResult out;
|
||||||
if (auto raw = raw_offset(std::forward<PathsProvider>(paths), - offset, joinType, miterLimit); ! raw.empty()) {
|
if (auto raw = raw_offset(std::forward<PathsProvider>(paths), - offset, joinType, miterLimit); ! raw.empty()) {
|
||||||
@ -407,6 +429,8 @@ Slic3r::Polygons offset(const Slic3r::Polylines &polylines, const float delta, C
|
|||||||
// returns number of expolygons collected (0 or 1).
|
// returns number of expolygons collected (0 or 1).
|
||||||
static int offset_expolygon_inner(const Slic3r::ExPolygon &expoly, const float delta, ClipperLib::JoinType joinType, double miterLimit, ClipperLib::Paths &out)
|
static int offset_expolygon_inner(const Slic3r::ExPolygon &expoly, const float delta, ClipperLib::JoinType joinType, double miterLimit, ClipperLib::Paths &out)
|
||||||
{
|
{
|
||||||
|
CLIPPER_UTILS_TIME_LIMIT_MILLIS(CLIPPER_UTILS_TIME_LIMIT_DEFAULT);
|
||||||
|
|
||||||
// 1) Offset the outer contour.
|
// 1) Offset the outer contour.
|
||||||
ClipperLib::Paths contours;
|
ClipperLib::Paths contours;
|
||||||
{
|
{
|
||||||
@ -615,6 +639,8 @@ inline ClipperLib::PolyTree clipper_do_polytree(
|
|||||||
PathProvider2 &&clip,
|
PathProvider2 &&clip,
|
||||||
const ClipperLib::PolyFillType fillType)
|
const ClipperLib::PolyFillType fillType)
|
||||||
{
|
{
|
||||||
|
CLIPPER_UTILS_TIME_LIMIT_MILLIS(CLIPPER_UTILS_TIME_LIMIT_DEFAULT);
|
||||||
|
|
||||||
// Perform the operation with the output to input_subject.
|
// Perform the operation with the output to input_subject.
|
||||||
// This pass does not generate a PolyTree, which is a very expensive operation with the current Clipper library
|
// This pass does not generate a PolyTree, which is a very expensive operation with the current Clipper library
|
||||||
// if there are overapping edges.
|
// if there are overapping edges.
|
||||||
@ -753,6 +779,8 @@ Slic3r::ExPolygons union_ex(const Slic3r::Surfaces &subject)
|
|||||||
template<typename PathsProvider1, typename PathsProvider2>
|
template<typename PathsProvider1, typename PathsProvider2>
|
||||||
Polylines _clipper_pl_open(ClipperLib::ClipType clipType, PathsProvider1 &&subject, PathsProvider2 &&clip)
|
Polylines _clipper_pl_open(ClipperLib::ClipType clipType, PathsProvider1 &&subject, PathsProvider2 &&clip)
|
||||||
{
|
{
|
||||||
|
CLIPPER_UTILS_TIME_LIMIT_MILLIS(CLIPPER_UTILS_TIME_LIMIT_DEFAULT);
|
||||||
|
|
||||||
ClipperLib::Clipper clipper;
|
ClipperLib::Clipper clipper;
|
||||||
clipper.AddPaths(std::forward<PathsProvider1>(subject), ClipperLib::ptSubject, false);
|
clipper.AddPaths(std::forward<PathsProvider1>(subject), ClipperLib::ptSubject, false);
|
||||||
clipper.AddPaths(std::forward<PathsProvider2>(clip), ClipperLib::ptClip, true);
|
clipper.AddPaths(std::forward<PathsProvider2>(clip), ClipperLib::ptClip, true);
|
||||||
@ -938,6 +966,8 @@ Polygons union_pt_chained_outside_in(const Polygons &subject)
|
|||||||
|
|
||||||
Polygons simplify_polygons(const Polygons &subject, bool preserve_collinear)
|
Polygons simplify_polygons(const Polygons &subject, bool preserve_collinear)
|
||||||
{
|
{
|
||||||
|
CLIPPER_UTILS_TIME_LIMIT_MILLIS(CLIPPER_UTILS_TIME_LIMIT_DEFAULT);
|
||||||
|
|
||||||
ClipperLib::Paths output;
|
ClipperLib::Paths output;
|
||||||
if (preserve_collinear) {
|
if (preserve_collinear) {
|
||||||
ClipperLib::Clipper c;
|
ClipperLib::Clipper c;
|
||||||
@ -955,6 +985,8 @@ Polygons simplify_polygons(const Polygons &subject, bool preserve_collinear)
|
|||||||
|
|
||||||
ExPolygons simplify_polygons_ex(const Polygons &subject, bool preserve_collinear)
|
ExPolygons simplify_polygons_ex(const Polygons &subject, bool preserve_collinear)
|
||||||
{
|
{
|
||||||
|
CLIPPER_UTILS_TIME_LIMIT_MILLIS(CLIPPER_UTILS_TIME_LIMIT_DEFAULT);
|
||||||
|
|
||||||
if (! preserve_collinear)
|
if (! preserve_collinear)
|
||||||
return union_ex(simplify_polygons(subject, false));
|
return union_ex(simplify_polygons(subject, false));
|
||||||
|
|
||||||
@ -971,6 +1003,8 @@ ExPolygons simplify_polygons_ex(const Polygons &subject, bool preserve_collinear
|
|||||||
|
|
||||||
Polygons top_level_islands(const Slic3r::Polygons &polygons)
|
Polygons top_level_islands(const Slic3r::Polygons &polygons)
|
||||||
{
|
{
|
||||||
|
CLIPPER_UTILS_TIME_LIMIT_MILLIS(CLIPPER_UTILS_TIME_LIMIT_DEFAULT);
|
||||||
|
|
||||||
// init Clipper
|
// init Clipper
|
||||||
ClipperLib::Clipper clipper;
|
ClipperLib::Clipper clipper;
|
||||||
clipper.Clear();
|
clipper.Clear();
|
||||||
@ -994,6 +1028,8 @@ ClipperLib::Paths fix_after_outer_offset(
|
|||||||
ClipperLib::PolyFillType filltype, // = ClipperLib::pftPositive
|
ClipperLib::PolyFillType filltype, // = ClipperLib::pftPositive
|
||||||
bool reverse_result) // = false
|
bool reverse_result) // = false
|
||||||
{
|
{
|
||||||
|
CLIPPER_UTILS_TIME_LIMIT_MILLIS(CLIPPER_UTILS_TIME_LIMIT_DEFAULT);
|
||||||
|
|
||||||
ClipperLib::Paths solution;
|
ClipperLib::Paths solution;
|
||||||
if (! input.empty()) {
|
if (! input.empty()) {
|
||||||
ClipperLib::Clipper clipper;
|
ClipperLib::Clipper clipper;
|
||||||
@ -1012,6 +1048,8 @@ ClipperLib::Paths fix_after_inner_offset(
|
|||||||
ClipperLib::PolyFillType filltype, // = ClipperLib::pftNegative
|
ClipperLib::PolyFillType filltype, // = ClipperLib::pftNegative
|
||||||
bool reverse_result) // = true
|
bool reverse_result) // = true
|
||||||
{
|
{
|
||||||
|
CLIPPER_UTILS_TIME_LIMIT_MILLIS(CLIPPER_UTILS_TIME_LIMIT_DEFAULT);
|
||||||
|
|
||||||
ClipperLib::Paths solution;
|
ClipperLib::Paths solution;
|
||||||
if (! input.empty()) {
|
if (! input.empty()) {
|
||||||
ClipperLib::Clipper clipper;
|
ClipperLib::Clipper clipper;
|
||||||
@ -1032,6 +1070,8 @@ ClipperLib::Paths fix_after_inner_offset(
|
|||||||
|
|
||||||
ClipperLib::Path mittered_offset_path_scaled(const Points &contour, const std::vector<float> &deltas, double miter_limit)
|
ClipperLib::Path mittered_offset_path_scaled(const Points &contour, const std::vector<float> &deltas, double miter_limit)
|
||||||
{
|
{
|
||||||
|
CLIPPER_UTILS_TIME_LIMIT_MILLIS(CLIPPER_UTILS_TIME_LIMIT_DEFAULT);
|
||||||
|
|
||||||
assert(contour.size() == deltas.size());
|
assert(contour.size() == deltas.size());
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
@ -1172,6 +1212,8 @@ ClipperLib::Path mittered_offset_path_scaled(const Points &contour, const std::v
|
|||||||
|
|
||||||
static void variable_offset_inner_raw(const ExPolygon &expoly, const std::vector<std::vector<float>> &deltas, double miter_limit, ClipperLib::Paths &contours, ClipperLib::Paths &holes)
|
static void variable_offset_inner_raw(const ExPolygon &expoly, const std::vector<std::vector<float>> &deltas, double miter_limit, ClipperLib::Paths &contours, ClipperLib::Paths &holes)
|
||||||
{
|
{
|
||||||
|
CLIPPER_UTILS_TIME_LIMIT_MILLIS(CLIPPER_UTILS_TIME_LIMIT_DEFAULT);
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
// Verify that the deltas are all non positive.
|
// Verify that the deltas are all non positive.
|
||||||
for (const std::vector<float> &ds : deltas)
|
for (const std::vector<float> &ds : deltas)
|
||||||
@ -1205,6 +1247,8 @@ static void variable_offset_inner_raw(const ExPolygon &expoly, const std::vector
|
|||||||
|
|
||||||
Polygons variable_offset_inner(const ExPolygon &expoly, const std::vector<std::vector<float>> &deltas, double miter_limit)
|
Polygons variable_offset_inner(const ExPolygon &expoly, const std::vector<std::vector<float>> &deltas, double miter_limit)
|
||||||
{
|
{
|
||||||
|
CLIPPER_UTILS_TIME_LIMIT_MILLIS(CLIPPER_UTILS_TIME_LIMIT_DEFAULT);
|
||||||
|
|
||||||
ClipperLib::Paths contours, holes;
|
ClipperLib::Paths contours, holes;
|
||||||
variable_offset_inner_raw(expoly, deltas, miter_limit, contours, holes);
|
variable_offset_inner_raw(expoly, deltas, miter_limit, contours, holes);
|
||||||
|
|
||||||
@ -1227,6 +1271,8 @@ Polygons variable_offset_inner(const ExPolygon &expoly, const std::vector<std::v
|
|||||||
|
|
||||||
ExPolygons variable_offset_inner_ex(const ExPolygon &expoly, const std::vector<std::vector<float>> &deltas, double miter_limit)
|
ExPolygons variable_offset_inner_ex(const ExPolygon &expoly, const std::vector<std::vector<float>> &deltas, double miter_limit)
|
||||||
{
|
{
|
||||||
|
CLIPPER_UTILS_TIME_LIMIT_MILLIS(CLIPPER_UTILS_TIME_LIMIT_DEFAULT);
|
||||||
|
|
||||||
ClipperLib::Paths contours, holes;
|
ClipperLib::Paths contours, holes;
|
||||||
variable_offset_inner_raw(expoly, deltas, miter_limit, contours, holes);
|
variable_offset_inner_raw(expoly, deltas, miter_limit, contours, holes);
|
||||||
|
|
||||||
@ -1253,6 +1299,8 @@ ExPolygons variable_offset_inner_ex(const ExPolygon &expoly, const std::vector<s
|
|||||||
|
|
||||||
static void variable_offset_outer_raw(const ExPolygon &expoly, const std::vector<std::vector<float>> &deltas, double miter_limit, ClipperLib::Paths &contours, ClipperLib::Paths &holes)
|
static void variable_offset_outer_raw(const ExPolygon &expoly, const std::vector<std::vector<float>> &deltas, double miter_limit, ClipperLib::Paths &contours, ClipperLib::Paths &holes)
|
||||||
{
|
{
|
||||||
|
CLIPPER_UTILS_TIME_LIMIT_MILLIS(CLIPPER_UTILS_TIME_LIMIT_DEFAULT);
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
// Verify that the deltas are all non positive.
|
// Verify that the deltas are all non positive.
|
||||||
for (const std::vector<float> &ds : deltas)
|
for (const std::vector<float> &ds : deltas)
|
||||||
@ -1288,6 +1336,8 @@ static void variable_offset_outer_raw(const ExPolygon &expoly, const std::vector
|
|||||||
|
|
||||||
Polygons variable_offset_outer(const ExPolygon &expoly, const std::vector<std::vector<float>> &deltas, double miter_limit)
|
Polygons variable_offset_outer(const ExPolygon &expoly, const std::vector<std::vector<float>> &deltas, double miter_limit)
|
||||||
{
|
{
|
||||||
|
CLIPPER_UTILS_TIME_LIMIT_MILLIS(CLIPPER_UTILS_TIME_LIMIT_DEFAULT);
|
||||||
|
|
||||||
ClipperLib::Paths contours, holes;
|
ClipperLib::Paths contours, holes;
|
||||||
variable_offset_outer_raw(expoly, deltas, miter_limit, contours, holes);
|
variable_offset_outer_raw(expoly, deltas, miter_limit, contours, holes);
|
||||||
|
|
||||||
@ -1309,6 +1359,8 @@ Polygons variable_offset_outer(const ExPolygon &expoly, const std::vector<std::v
|
|||||||
|
|
||||||
ExPolygons variable_offset_outer_ex(const ExPolygon &expoly, const std::vector<std::vector<float>> &deltas, double miter_limit)
|
ExPolygons variable_offset_outer_ex(const ExPolygon &expoly, const std::vector<std::vector<float>> &deltas, double miter_limit)
|
||||||
{
|
{
|
||||||
|
CLIPPER_UTILS_TIME_LIMIT_MILLIS(CLIPPER_UTILS_TIME_LIMIT_DEFAULT);
|
||||||
|
|
||||||
ClipperLib::Paths contours, holes;
|
ClipperLib::Paths contours, holes;
|
||||||
variable_offset_outer_raw(expoly, deltas, miter_limit, contours, holes);
|
variable_offset_outer_raw(expoly, deltas, miter_limit, contours, holes);
|
||||||
|
|
||||||
|
@ -54,6 +54,7 @@ using Vec4d = Eigen::Matrix<double, 4, 1, Eigen::DontAlign>;
|
|||||||
|
|
||||||
template<typename BaseType>
|
template<typename BaseType>
|
||||||
using PointsAllocator = tbb::scalable_allocator<BaseType>;
|
using PointsAllocator = tbb::scalable_allocator<BaseType>;
|
||||||
|
//using PointsAllocator = std::allocator<BaseType>;
|
||||||
using Points = std::vector<Point, PointsAllocator<Point>>;
|
using Points = std::vector<Point, PointsAllocator<Point>>;
|
||||||
using PointPtrs = std::vector<Point*>;
|
using PointPtrs = std::vector<Point*>;
|
||||||
using PointConstPtrs = std::vector<const Point*>;
|
using PointConstPtrs = std::vector<const Point*>;
|
||||||
|
@ -10,3 +10,12 @@ Slic3r::Timer::~Timer()
|
|||||||
BOOST_LOG_TRIVIAL(debug) << "Timer '" << m_name << "' spend " <<
|
BOOST_LOG_TRIVIAL(debug) << "Timer '" << m_name << "' spend " <<
|
||||||
duration_cast<milliseconds>(steady_clock::now() - m_start).count() << "ms";
|
duration_cast<milliseconds>(steady_clock::now() - m_start).count() << "ms";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
namespace Slic3r::Timing {
|
||||||
|
|
||||||
|
void TimeLimitAlarm::report_time_exceeded() const {
|
||||||
|
BOOST_LOG_TRIVIAL(error) << "Time limit exceeded for " << m_limit_exceeded_message << ": " << m_timer.elapsed_seconds() << "s";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
@ -27,5 +27,66 @@ public:
|
|||||||
~Timer();
|
~Timer();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace Timing {
|
||||||
|
|
||||||
|
// Timing code from Catch2 unit testing library
|
||||||
|
static inline uint64_t nanoseconds_since_epoch() {
|
||||||
|
return std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now().time_since_epoch()).count();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Timing code from Catch2 unit testing library
|
||||||
|
class Timer {
|
||||||
|
public:
|
||||||
|
void start() {
|
||||||
|
m_nanoseconds = nanoseconds_since_epoch();
|
||||||
|
}
|
||||||
|
uint64_t elapsed_nanoseconds() const {
|
||||||
|
return nanoseconds_since_epoch() - m_nanoseconds;
|
||||||
|
}
|
||||||
|
uint64_t elapsed_microseconds() const {
|
||||||
|
return elapsed_nanoseconds() / 1000;
|
||||||
|
}
|
||||||
|
unsigned int elapsed_milliseconds() const {
|
||||||
|
return static_cast<unsigned int>(elapsed_microseconds()/1000);
|
||||||
|
}
|
||||||
|
double elapsed_seconds() const {
|
||||||
|
return elapsed_microseconds() / 1000000.0;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
uint64_t m_nanoseconds = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Emits a Boost::log error if the life time of this timing object exceeds a limit.
|
||||||
|
class TimeLimitAlarm {
|
||||||
|
public:
|
||||||
|
TimeLimitAlarm(uint64_t time_limit_nanoseconds, std::string_view limit_exceeded_message) :
|
||||||
|
m_time_limit_nanoseconds(time_limit_nanoseconds), m_limit_exceeded_message(limit_exceeded_message) {
|
||||||
|
m_timer.start();
|
||||||
|
}
|
||||||
|
~TimeLimitAlarm() {
|
||||||
|
auto elapsed = m_timer.elapsed_nanoseconds();
|
||||||
|
if (elapsed > m_time_limit_nanoseconds)
|
||||||
|
this->report_time_exceeded();
|
||||||
|
}
|
||||||
|
static TimeLimitAlarm new_nanos(uint64_t time_limit_nanoseconds, std::string_view limit_exceeded_message) {
|
||||||
|
return TimeLimitAlarm(time_limit_nanoseconds, limit_exceeded_message);
|
||||||
|
}
|
||||||
|
static TimeLimitAlarm new_milis(uint64_t time_limit_milis, std::string_view limit_exceeded_message) {
|
||||||
|
return TimeLimitAlarm(uint64_t(time_limit_milis) * 1000000l, limit_exceeded_message);
|
||||||
|
}
|
||||||
|
static TimeLimitAlarm new_seconds(uint64_t time_limit_seconds, std::string_view limit_exceeded_message) {
|
||||||
|
return TimeLimitAlarm(uint64_t(time_limit_seconds) * 1000000000l, limit_exceeded_message);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
void report_time_exceeded() const;
|
||||||
|
|
||||||
|
Timer m_timer;
|
||||||
|
uint64_t m_time_limit_nanoseconds;
|
||||||
|
std::string_view m_limit_exceeded_message;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Catch
|
||||||
|
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
#endif // libslic3r_Timer_hpp_
|
|
||||||
|
#endif // libslic3r_Timer_hpp_
|
||||||
|
Loading…
x
Reference in New Issue
Block a user