mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-12-11 16:00:17 -07:00
Fix arrange crash with incorrect geometries. Guard the case with tests.
This commit is contained in:
parent
4aec14ddab
commit
a6f5fe7bea
6 changed files with 92 additions and 120 deletions
|
|
@ -81,17 +81,16 @@ inline void offset(PolygonImpl& sh, TCoord<PointImpl> distance, const PolygonTag
|
|||
using ClipperLib::etClosedPolygon;
|
||||
using ClipperLib::Paths;
|
||||
|
||||
// If the input is not at least a triangle, we can not do this algorithm
|
||||
if(sh.Contour.size() <= 3 ||
|
||||
std::any_of(sh.Holes.begin(), sh.Holes.end(),
|
||||
[](const PathImpl& p) { return p.size() <= 3; })
|
||||
) throw GeometryException(GeomErr::OFFSET);
|
||||
|
||||
ClipperOffset offs;
|
||||
Paths result;
|
||||
offs.AddPath(sh.Contour, jtMiter, etClosedPolygon);
|
||||
offs.AddPaths(sh.Holes, jtMiter, etClosedPolygon);
|
||||
offs.Execute(result, static_cast<double>(distance));
|
||||
|
||||
try {
|
||||
ClipperOffset offs;
|
||||
offs.AddPath(sh.Contour, jtMiter, etClosedPolygon);
|
||||
offs.AddPaths(sh.Holes, jtMiter, etClosedPolygon);
|
||||
offs.Execute(result, static_cast<double>(distance));
|
||||
} catch (ClipperLib::clipperException &) {
|
||||
throw GeometryException(GeomErr::OFFSET);
|
||||
}
|
||||
|
||||
// Offsetting reverts the orientation and also removes the last vertex
|
||||
// so boost will not have a closed polygon.
|
||||
|
|
|
|||
|
|
@ -1144,7 +1144,7 @@ inline bool isInside(const TBGuest& ibb, const TBHost& box,
|
|||
auto minY = getY(box.minCorner());
|
||||
auto maxY = getY(box.maxCorner());
|
||||
|
||||
return iminX > minX && imaxX < maxX && iminY > minY && imaxY < maxY;
|
||||
return iminX >= minX && imaxX <= maxX && iminY >= minY && imaxY <= maxY;
|
||||
}
|
||||
|
||||
template<class S, class TB>
|
||||
|
|
|
|||
|
|
@ -3,9 +3,6 @@
|
|||
|
||||
#include <cassert>
|
||||
|
||||
// For caching nfps
|
||||
#include <unordered_map>
|
||||
|
||||
// For parallel for
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
|
|
@ -76,55 +73,6 @@ inline void enumerate(
|
|||
|
||||
}
|
||||
|
||||
namespace __itemhash {
|
||||
|
||||
using Key = size_t;
|
||||
|
||||
template<class S>
|
||||
Key hash(const _Item<S>& item) {
|
||||
using Point = TPoint<S>;
|
||||
using Segment = _Segment<Point>;
|
||||
|
||||
static const int N = 26;
|
||||
static const int M = N*N - 1;
|
||||
|
||||
std::string ret;
|
||||
auto& rhs = item.rawShape();
|
||||
auto& ctr = sl::contour(rhs);
|
||||
auto it = ctr.begin();
|
||||
auto nx = std::next(it);
|
||||
|
||||
double circ = 0;
|
||||
while(nx != ctr.end()) {
|
||||
Segment seg(*it++, *nx++);
|
||||
Radians a = seg.angleToXaxis();
|
||||
double deg = Degrees(a);
|
||||
int ms = 'A', ls = 'A';
|
||||
while(deg > N) { ms++; deg -= N; }
|
||||
ls += int(deg);
|
||||
ret.push_back(char(ms)); ret.push_back(char(ls));
|
||||
circ += std::sqrt(seg.template sqlength<double>());
|
||||
}
|
||||
|
||||
it = ctr.begin(); nx = std::next(it);
|
||||
|
||||
while(nx != ctr.end()) {
|
||||
Segment seg(*it++, *nx++);
|
||||
auto l = int(M * std::sqrt(seg.template sqlength<double>()) / circ);
|
||||
int ms = 'A', ls = 'A';
|
||||
while(l > N) { ms++; l -= N; }
|
||||
ls += l;
|
||||
ret.push_back(char(ms)); ret.push_back(char(ls));
|
||||
}
|
||||
|
||||
return std::hash<std::string>()(ret);
|
||||
}
|
||||
|
||||
template<class S>
|
||||
using Hash = std::unordered_map<Key, nfp::NfpResult<S>>;
|
||||
|
||||
}
|
||||
|
||||
namespace placers {
|
||||
|
||||
template<class RawShape>
|
||||
|
|
@ -529,17 +477,9 @@ class _NofitPolyPlacer: public PlacerBoilerplate<_NofitPolyPlacer<RawShape, TBin
|
|||
|
||||
using MaxNfpLevel = nfp::MaxNfpLevel<RawShape>;
|
||||
|
||||
using ItemKeys = std::vector<__itemhash::Key>;
|
||||
|
||||
// Norming factor for the optimization function
|
||||
const double norm_;
|
||||
|
||||
// Caching calculated nfps
|
||||
__itemhash::Hash<RawShape> nfpcache_;
|
||||
|
||||
// Storing item hash keys
|
||||
ItemKeys item_keys_;
|
||||
|
||||
public:
|
||||
|
||||
using Pile = nfp::Shapes<RawShape>;
|
||||
|
|
@ -636,15 +576,12 @@ public:
|
|||
private:
|
||||
|
||||
using Shapes = TMultiShape<RawShape>;
|
||||
using ItemRef = std::reference_wrapper<Item>;
|
||||
using ItemWithHash = const std::pair<ItemRef, __itemhash::Key>;
|
||||
|
||||
Shapes calcnfp(const ItemWithHash itsh, Lvl<nfp::NfpLevel::CONVEX_ONLY>)
|
||||
Shapes calcnfp(const Item &trsh, Lvl<nfp::NfpLevel::CONVEX_ONLY>)
|
||||
{
|
||||
using namespace nfp;
|
||||
|
||||
Shapes nfps(items_.size());
|
||||
const Item& trsh = itsh.first;
|
||||
|
||||
// /////////////////////////////////////////////////////////////////////
|
||||
// TODO: this is a workaround and should be solved in Item with mutexes
|
||||
|
|
@ -678,12 +615,11 @@ private:
|
|||
|
||||
|
||||
template<class Level>
|
||||
Shapes calcnfp( const ItemWithHash itsh, Level)
|
||||
Shapes calcnfp(const Item &trsh, Level)
|
||||
{ // Function for arbitrary level of nfp implementation
|
||||
using namespace nfp;
|
||||
|
||||
Shapes nfps;
|
||||
const Item& trsh = itsh.first;
|
||||
|
||||
auto& orb = trsh.transformedShape();
|
||||
bool orbconvex = trsh.isContourConvex();
|
||||
|
|
@ -849,8 +785,6 @@ private:
|
|||
remlist.insert(remlist.end(), remaining.from, remaining.to);
|
||||
}
|
||||
|
||||
size_t itemhash = __itemhash::hash(item);
|
||||
|
||||
if(items_.empty()) {
|
||||
setInitialPosition(item);
|
||||
best_overfit = overfit(item.transformedShape(), bin_);
|
||||
|
|
@ -875,7 +809,7 @@ private:
|
|||
// it is disjunct from the current merged pile
|
||||
placeOutsideOfBin(item);
|
||||
|
||||
nfps = calcnfp({item, itemhash}, Lvl<MaxNfpLevel::value>());
|
||||
nfps = calcnfp(item, Lvl<MaxNfpLevel::value>());
|
||||
|
||||
auto iv = item.referenceVertex();
|
||||
|
||||
|
|
@ -1112,7 +1046,6 @@ private:
|
|||
|
||||
if(can_pack) {
|
||||
ret = PackResult(item);
|
||||
item_keys_.emplace_back(itemhash);
|
||||
} else {
|
||||
ret = PackResult(best_overfit);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ protected:
|
|||
|
||||
Placer p{bin};
|
||||
p.configure(pcfg);
|
||||
if (!p.pack(cpy)) it = c.erase(it);
|
||||
if (itm.area() <= 0 || !p.pack(cpy)) it = c.erase(it);
|
||||
else it++;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue