ENH: show the layer and height of conflict position
Change-Id: If80e81b5556f5afc3228a00edc2593bd8cfe63e4 (cherry picked from commit 895e0f2ecf8e259cfdb7c27081b767bfbaa3ffb6)
This commit is contained in:
parent
98f3aaa4bf
commit
87eb0f3665
|
@ -92,8 +92,11 @@ inline Grids line_rasterization(const Line &line, int64_t xdist = RasteXDistance
|
|||
void LinesBucketQueue::emplace_back_bucket(std::vector<ExtrusionPaths> &&paths, const void *objPtr, Point offset)
|
||||
{
|
||||
auto oldSize = _buckets.capacity();
|
||||
_buckets.emplace_back(std::move(paths), _objsPtrToId.size(), offset);
|
||||
_objsPtrToId.push_back(objPtr);
|
||||
if (_objsPtrToId.find(objPtr) == _objsPtrToId.end()) {
|
||||
_objsPtrToId.insert({objPtr, _objsPtrToId.size()});
|
||||
_idToObjsPtr.insert({_objsPtrToId.size() - 1, objPtr});
|
||||
}
|
||||
_buckets.emplace_back(std::move(paths), _objsPtrToId[objPtr], offset);
|
||||
_pq.push(&_buckets.back());
|
||||
auto newSize = _buckets.capacity();
|
||||
if (oldSize != newSize) { // pointers change
|
||||
|
@ -103,11 +106,11 @@ void LinesBucketQueue::emplace_back_bucket(std::vector<ExtrusionPaths> &&paths,
|
|||
}
|
||||
}
|
||||
|
||||
void LinesBucketQueue::removeLowests()
|
||||
double LinesBucketQueue::removeLowests()
|
||||
{
|
||||
auto lowest = _pq.top();
|
||||
_pq.pop();
|
||||
|
||||
double curHeight = lowest->curHeight();
|
||||
std::vector<LinesBucket *> lowests;
|
||||
lowests.push_back(lowest);
|
||||
|
||||
|
@ -120,6 +123,7 @@ void LinesBucketQueue::removeLowests()
|
|||
bp->raise();
|
||||
if (bp->valid()) { _pq.push(bp); }
|
||||
}
|
||||
return curHeight;
|
||||
}
|
||||
|
||||
LineWithIDs LinesBucketQueue::getCurLines() const
|
||||
|
@ -180,7 +184,7 @@ std::pair<std::vector<ExtrusionPaths>, std::vector<ExtrusionPaths>> getAllLayers
|
|||
return {std::move(objPaths), std::move(supportPaths)};
|
||||
}
|
||||
|
||||
ConflictRet ConflictChecker::find_inter_of_lines(const LineWithIDs &lines)
|
||||
ConflictComputeOpt ConflictChecker::find_inter_of_lines(const LineWithIDs &lines)
|
||||
{
|
||||
using namespace RasterizationImpl;
|
||||
std::map<IndexPair, std::vector<int>> indexToLine;
|
||||
|
@ -200,7 +204,7 @@ ConflictRet ConflictChecker::find_inter_of_lines(const LineWithIDs &lines)
|
|||
return {};
|
||||
}
|
||||
|
||||
ConflictObjName ConflictChecker::find_inter_of_lines_in_diff_objs(PrintObjectPtrs objs,
|
||||
ConflictResultOpt ConflictChecker::find_inter_of_lines_in_diff_objs(PrintObjectPtrs objs,
|
||||
std::optional<const FakeWipeTower *> wtdptr) // find the first intersection point of lines in different objects
|
||||
{
|
||||
if (objs.size() <= 1) { return {}; }
|
||||
|
@ -216,45 +220,48 @@ ConflictObjName ConflictChecker::find_inter_of_lines_in_diff_objs(PrintObjectPtr
|
|||
}
|
||||
|
||||
std::vector<LineWithIDs> layersLines;
|
||||
std::vector<double> heights;
|
||||
while (conflictQueue.valid()) {
|
||||
LineWithIDs lines = conflictQueue.getCurLines();
|
||||
conflictQueue.removeLowests();
|
||||
LineWithIDs lines = conflictQueue.getCurLines();
|
||||
double curHeight = conflictQueue.removeLowests();
|
||||
heights.push_back(curHeight);
|
||||
layersLines.push_back(std::move(lines));
|
||||
}
|
||||
|
||||
bool find = false;
|
||||
tbb::concurrent_vector<ConflictResult> conflict;
|
||||
tbb::concurrent_vector<std::pair<ConflictComputeResult,double>> conflict;
|
||||
|
||||
tbb::parallel_for(tbb::blocked_range<size_t>(0, layersLines.size()), [&](tbb::blocked_range<size_t> range) {
|
||||
for (size_t i = range.begin(); i < range.end(); i++) {
|
||||
auto interRes = find_inter_of_lines(layersLines[i]);
|
||||
if (interRes.has_value()) {
|
||||
find = true;
|
||||
conflict.emplace_back(interRes.value());
|
||||
conflict.emplace_back(interRes.value(),heights[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (find) {
|
||||
const void *ptr1 = conflictQueue.idToObjsPtr(conflict[0]._obj1);
|
||||
const void *ptr2 = conflictQueue.idToObjsPtr(conflict[0]._obj2);
|
||||
const void *ptr1 = conflictQueue.idToObjsPtr(conflict[0].first._obj1);
|
||||
const void *ptr2 = conflictQueue.idToObjsPtr(conflict[0].first._obj2);
|
||||
double conflictHeight = conflict[0].second;
|
||||
if (wtdptr.has_value()) {
|
||||
const FakeWipeTower *wtdp = wtdptr.value();
|
||||
if (ptr1 == wtdp || ptr2 == wtdp) {
|
||||
if (ptr2 == wtdp) { std::swap(ptr1, ptr2); }
|
||||
const PrintObject *obj2 = reinterpret_cast<const PrintObject *>(ptr2);
|
||||
return {std::make_pair("WipeTower", obj2->model_object()->name)};
|
||||
return std::make_optional<ConflictResult>("WipeTower", obj2->model_object()->name, conflictHeight, nullptr, ptr2);
|
||||
}
|
||||
}
|
||||
const PrintObject *obj1 = reinterpret_cast<const PrintObject *>(ptr1);
|
||||
const PrintObject *obj2 = reinterpret_cast<const PrintObject *>(ptr2);
|
||||
return {std::make_pair(obj1->model_object()->name, obj2->model_object()->name)};
|
||||
return std::make_optional<ConflictResult>(obj1->model_object()->name, obj2->model_object()->name, conflictHeight, ptr1, ptr2);
|
||||
} else
|
||||
return {};
|
||||
}
|
||||
|
||||
ConflictRet ConflictChecker::line_intersect(const LineWithID &l1, const LineWithID &l2)
|
||||
ConflictComputeOpt ConflictChecker::line_intersect(const LineWithID &l1, const LineWithID &l2)
|
||||
{
|
||||
if (l1._id == l2._id) { return {}; } // return true if lines are from same object
|
||||
Point inter;
|
||||
|
@ -263,7 +270,7 @@ ConflictRet ConflictChecker::line_intersect(const LineWithID &l1, const LineWith
|
|||
auto dist1 = std::min(unscale(Point(l1._line.a - inter)).norm(), unscale(Point(l1._line.b - inter)).norm());
|
||||
auto dist2 = std::min(unscale(Point(l2._line.a - inter)).norm(), unscale(Point(l2._line.b - inter)).norm());
|
||||
auto dist = std::min(dist1, dist2);
|
||||
if (dist > 0.01) { return std::make_optional<ConflictResult>(l1._id, l2._id); } // the two lines intersects if dist>0.01mm
|
||||
if (dist > 0.01) { return std::make_optional<ConflictComputeResult>(l1._id, l2._id); } // the two lines intersects if dist>0.01mm
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
|
|
@ -75,19 +75,20 @@ class LinesBucketQueue
|
|||
private:
|
||||
std::vector<LinesBucket> _buckets;
|
||||
std::priority_queue<LinesBucket *, std::vector<LinesBucket *>, LinesBucketPtrComp> _pq;
|
||||
std::vector<const void *> _objsPtrToId;
|
||||
std::map<int, const void *> _idToObjsPtr;
|
||||
std::map<const void *, int> _objsPtrToId;
|
||||
|
||||
public:
|
||||
void emplace_back_bucket(std::vector<ExtrusionPaths> &&paths, const void *objPtr, Point offset);
|
||||
bool valid() const { return _pq.empty() == false; }
|
||||
const void *idToObjsPtr(int id)
|
||||
{
|
||||
if (id >= 0 && id < _objsPtrToId.size()) {
|
||||
return _objsPtrToId[id];
|
||||
} else
|
||||
if (_idToObjsPtr.find(id) != _idToObjsPtr.end())
|
||||
return _idToObjsPtr[id];
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
void removeLowests();
|
||||
double removeLowests();
|
||||
LineWithIDs getCurLines() const;
|
||||
};
|
||||
|
||||
|
@ -99,23 +100,24 @@ ExtrusionPaths getExtrusionPathsFromSupportLayer(SupportLayer *supportLayer);
|
|||
|
||||
std::pair<std::vector<ExtrusionPaths>, std::vector<ExtrusionPaths>> getAllLayersExtrusionPathsFromObject(PrintObject *obj);
|
||||
|
||||
struct ConflictResult
|
||||
struct ConflictComputeResult
|
||||
{
|
||||
int _obj1;
|
||||
int _obj2;
|
||||
ConflictResult(int obj1, int obj2) : _obj1(obj1), _obj2(obj2) {}
|
||||
ConflictResult() = default;
|
||||
|
||||
ConflictComputeResult(int o1, int o2) : _obj1(o1), _obj2(o2) {}
|
||||
ConflictComputeResult() = default;
|
||||
};
|
||||
|
||||
using ConflictRet = std::optional<ConflictResult>;
|
||||
using ConflictComputeOpt = std::optional<ConflictComputeResult>;
|
||||
|
||||
using ConflictObjName = std::optional<std::pair<std::string, std::string>>;
|
||||
|
||||
struct ConflictChecker
|
||||
{
|
||||
static ConflictObjName find_inter_of_lines_in_diff_objs(PrintObjectPtrs objs, std::optional<const FakeWipeTower *> wtdptr);
|
||||
static ConflictRet find_inter_of_lines(const LineWithIDs &lines);
|
||||
static ConflictRet line_intersect(const LineWithID &l1, const LineWithID &l2);
|
||||
static ConflictResultOpt find_inter_of_lines_in_diff_objs(PrintObjectPtrs objs, std::optional<const FakeWipeTower *> wtdptr);
|
||||
static ConflictComputeOpt find_inter_of_lines(const LineWithIDs &lines);
|
||||
static ConflictComputeOpt line_intersect(const LineWithID &l1, const LineWithID &l2);
|
||||
};
|
||||
|
||||
} // namespace Slic3r
|
||||
|
|
|
@ -93,31 +93,25 @@ namespace Slic3r {
|
|||
}
|
||||
};
|
||||
|
||||
struct ConflictResult
|
||||
{
|
||||
std::string _objName1;
|
||||
std::string _objName2;
|
||||
double _height;
|
||||
const void *_obj1; // nullptr means wipe tower
|
||||
const void *_obj2;
|
||||
int layer = -1;
|
||||
ConflictResult(const std::string &objName1, const std::string &objName2, double height, const void *obj1, const void *obj2)
|
||||
: _objName1(objName1), _objName2(objName2), _height(height), _obj1(obj1), _obj2(obj2)
|
||||
{}
|
||||
ConflictResult() = default;
|
||||
};
|
||||
|
||||
using ConflictResultOpt = std::optional<ConflictResult>;
|
||||
|
||||
struct GCodeProcessorResult
|
||||
{
|
||||
//BBS
|
||||
struct ConflictResult
|
||||
{
|
||||
bool conflicted;
|
||||
std::string obj1Name;
|
||||
std::string obj2Name;
|
||||
|
||||
void set(const std::string &o1, const std::string &o2)
|
||||
{
|
||||
conflicted = true;
|
||||
obj1Name = o1;
|
||||
obj2Name = o2;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
conflicted = false;
|
||||
obj1Name.clear();
|
||||
obj2Name.clear();
|
||||
}
|
||||
|
||||
ConflictResult() = default;
|
||||
ConflictResult(const ConflictResult &) = default;
|
||||
}conflict_result;
|
||||
ConflictResultOpt conflict_result;
|
||||
|
||||
struct SettingsIds
|
||||
{
|
||||
|
|
|
@ -1689,11 +1689,9 @@ void Print::process(bool use_cache)
|
|||
volatile double seconds = std::chrono::duration_cast<std::chrono::milliseconds>(endTime - startTime).count() / (double) 1000;
|
||||
BOOST_LOG_TRIVIAL(info) << "gcode path conflicts check takes " << seconds << " secs.";
|
||||
|
||||
m_conflict_result = conflictRes;
|
||||
if (conflictRes.has_value()) {
|
||||
m_conflict_result.set(conflictRes.value().first, conflictRes.value().second);
|
||||
BOOST_LOG_TRIVIAL(error) << boost::format("gcode path conflicts found between %1% and %2%")%conflictRes.value().first %conflictRes.value().second;
|
||||
} else {
|
||||
m_conflict_result.reset();
|
||||
BOOST_LOG_TRIVIAL(error) << boost::format("gcode path conflicts found between %1% and %2%")%conflictRes.value()._objName1 %conflictRes.value()._objName2;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1726,11 +1724,7 @@ std::string Print::export_gcode(const std::string& path_template, GCodeProcessor
|
|||
gcode.set_gcode_offset(origin(0), origin(1));
|
||||
gcode.do_export(this, path.c_str(), result, thumbnail_cb);
|
||||
//BBS
|
||||
if (m_conflict_result.conflicted) {
|
||||
result->conflict_result.set(m_conflict_result.obj1, m_conflict_result.obj2);
|
||||
} else {
|
||||
result->conflict_result.reset();
|
||||
}
|
||||
result->conflict_result = m_conflict_result;
|
||||
return path.c_str();
|
||||
}
|
||||
|
||||
|
|
|
@ -775,14 +775,15 @@ public:
|
|||
std::string get_conflict_string() const
|
||||
{
|
||||
std::string result;
|
||||
if (m_conflict_result.conflicted) {
|
||||
result = "Found gcode path conflicts between object " + m_conflict_result.obj1 + " and " + m_conflict_result.obj2;
|
||||
if (m_conflict_result) {
|
||||
result = "Found gcode path conflicts between object " + m_conflict_result.value()._objName1 + " and " + m_conflict_result.value()._objName2;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
//BBS
|
||||
static StringObjectException sequential_print_clearance_valid(const Print &print, Polygons *polygons = nullptr, std::vector<std::pair<Polygon, float>>* height_polygons = nullptr);
|
||||
ConflictResultOpt get_conflict_result() const { return m_conflict_result; }
|
||||
|
||||
// Return 4 wipe tower corners in the world coordinates (shifted and rotated), including the wipe tower brim.
|
||||
std::vector<Point> first_layer_wipe_tower_corners(bool check_wipe_tower_existance=true) const;
|
||||
|
@ -837,28 +838,8 @@ private:
|
|||
//BBS: modified_count
|
||||
int m_modified_count {0};
|
||||
//BBS
|
||||
struct ConflictResult
|
||||
{
|
||||
bool conflicted;
|
||||
std::string obj1;
|
||||
std::string obj2;
|
||||
//TODO
|
||||
//the actual loaction
|
||||
|
||||
void set(const std::string& o1, const std::string& o2)
|
||||
{
|
||||
conflicted = true;
|
||||
obj1 = o1;
|
||||
obj2 = o2;
|
||||
}
|
||||
void reset()
|
||||
{
|
||||
conflicted = false;
|
||||
obj1.clear();
|
||||
obj2.clear();
|
||||
}
|
||||
}m_conflict_result;
|
||||
FakeWipeTower m_fake_wipe_tower;
|
||||
ConflictResultOpt m_conflict_result;
|
||||
FakeWipeTower m_fake_wipe_tower;
|
||||
|
||||
// To allow GCode to set the Print's GCodeExport step status.
|
||||
friend class GCode;
|
||||
|
|
|
@ -1095,6 +1095,7 @@ void GCodeViewer::load(const GCodeProcessorResult& gcode_result, const Print& pr
|
|||
|
||||
//BBS
|
||||
m_conflict_result = gcode_result.conflict_result;
|
||||
if (m_conflict_result) { m_conflict_result.value().layer = m_layers.get_l_at(m_conflict_result.value()._height); }
|
||||
|
||||
//BBS: add mutex for protection of gcode result
|
||||
gcode_result.unlock();
|
||||
|
|
|
@ -490,6 +490,11 @@ class GCodeViewer
|
|||
std::vector<Endpoints>& get_endpoints() { return m_endpoints; }
|
||||
double get_z_at(unsigned int id) const { return (id < m_zs.size()) ? m_zs[id] : 0.0; }
|
||||
Endpoints get_endpoints_at(unsigned int id) const { return (id < m_endpoints.size()) ? m_endpoints[id] : Endpoints(); }
|
||||
int get_l_at(double z) const
|
||||
{
|
||||
auto iter = std::upper_bound(m_zs.begin(), m_zs.end(), z);
|
||||
return std::distance(m_zs.begin(), iter);
|
||||
}
|
||||
|
||||
bool operator != (const Layers& other) const {
|
||||
if (m_zs != other.m_zs)
|
||||
|
@ -728,7 +733,7 @@ public:
|
|||
};
|
||||
|
||||
//BBS
|
||||
GCodeProcessorResult::ConflictResult m_conflict_result;
|
||||
ConflictResultOpt m_conflict_result;
|
||||
|
||||
private:
|
||||
std::vector<int> m_plater_extruder;
|
||||
|
|
|
@ -8846,7 +8846,7 @@ void GLCanvas3D::_set_warning_notification_if_needed(EWarning warning)
|
|||
if (warning == EWarning::ToolpathOutside)
|
||||
show = m_gcode_viewer.has_data() && !m_gcode_viewer.is_contained_in_bed();
|
||||
else if (warning==EWarning::GCodeConflict)
|
||||
show = m_gcode_viewer.has_data() && m_gcode_viewer.is_contained_in_bed() && m_gcode_viewer.m_conflict_result.conflicted;
|
||||
show = m_gcode_viewer.has_data() && m_gcode_viewer.is_contained_in_bed() && m_gcode_viewer.m_conflict_result.has_value();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8886,9 +8886,14 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state)
|
|||
ErrorType error = ErrorType::PLATER_WARNING;
|
||||
switch (warning) {
|
||||
case EWarning::GCodeConflict: {
|
||||
std::string objName1 = m_gcode_viewer.m_conflict_result.obj1Name;
|
||||
std::string objName2 = m_gcode_viewer.m_conflict_result.obj2Name;
|
||||
text = (boost::format(_u8L("Conflicts of gcode paths have been found. Please separate the conflicted objects farther (%s <-> %s).")) % objName1 % objName2).str();
|
||||
if (!m_gcode_viewer.m_conflict_result) { break; }
|
||||
std::string objName1 = m_gcode_viewer.m_conflict_result.value()._objName1;
|
||||
std::string objName2 = m_gcode_viewer.m_conflict_result.value()._objName2;
|
||||
double height = m_gcode_viewer.m_conflict_result.value()._height;
|
||||
int layer = m_gcode_viewer.m_conflict_result.value().layer;
|
||||
text = (boost::format(_u8L("Conflicts of gcode paths have been found at layer %d, z = %.2lf mm. Please separate the conflicted objects farther (%s <-> %s).")) % layer %
|
||||
height % objName1 % objName2)
|
||||
.str();
|
||||
error = ErrorType::SLICING_ERROR;
|
||||
break;
|
||||
}
|
||||
|
@ -8907,6 +8912,26 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state)
|
|||
if (!wxGetApp().plater())
|
||||
return;
|
||||
auto& notification_manager = *wxGetApp().plater()->get_notification_manager();
|
||||
|
||||
if (warning == EWarning::GCodeConflict && m_gcode_viewer.m_conflict_result) {
|
||||
const PrintObject *obj2 = reinterpret_cast<const PrintObject *>(m_gcode_viewer.m_conflict_result.value()._obj2);
|
||||
auto mo = obj2->model_object();
|
||||
ObjectID id = mo->id();
|
||||
auto action_fn = [id](wxEvtHandler *) {
|
||||
auto &objects = wxGetApp().model().objects;
|
||||
auto iter = id.id ? std::find_if(objects.begin(), objects.end(), [id](auto o) { return o->id() == id; }) : objects.end();
|
||||
if (iter != objects.end()) {
|
||||
wxGetApp().mainframe->select_tab(MainFrame::tp3DEditor);
|
||||
wxGetApp().obj_list()->select_items({{*iter, nullptr}});
|
||||
}
|
||||
return false;
|
||||
};
|
||||
auto hypertext = _u8L("Jump to");
|
||||
hypertext += std::string(" [") + mo->name + "]";
|
||||
notification_manager.push_notification(NotificationType::PlaterError, NotificationManager::NotificationLevel::ErrorNotificationLevel, _u8L("ERROR:") + "\n" + text,
|
||||
hypertext, action_fn);
|
||||
return;
|
||||
}
|
||||
switch (error)
|
||||
{
|
||||
case PLATER_WARNING:
|
||||
|
|
|
@ -381,7 +381,7 @@ public:
|
|||
{
|
||||
bool result = m_slice_result_valid;
|
||||
if (result)
|
||||
result = m_gcode_result ? (!m_gcode_result->toolpath_outside && !m_gcode_result->conflict_result.conflicted) : false;
|
||||
result = m_gcode_result ? (!m_gcode_result->toolpath_outside && !m_gcode_result->conflict_result.has_value()) : false;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue