diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt
index b578932d4..0de0b4e51 100644
--- a/src/libslic3r/CMakeLists.txt
+++ b/src/libslic3r/CMakeLists.txt
@@ -138,6 +138,8 @@ set(SLIC3R_SOURCES
     GCode/ThumbnailData.hpp
     GCode/Thumbnails.cpp
     GCode/Thumbnails.hpp
+    GCode/ConflictChecker.cpp
+    GCode/ConflictChecker.hpp
     GCode/CoolingBuffer.cpp
     GCode/CoolingBuffer.hpp
     GCode/FindReplace.cpp
diff --git a/src/libslic3r/GCode/ConflictChecker.cpp b/src/libslic3r/GCode/ConflictChecker.cpp
new file mode 100644
index 000000000..7f8ba2d0c
--- /dev/null
+++ b/src/libslic3r/GCode/ConflictChecker.cpp
@@ -0,0 +1,301 @@
+#include "libslic3r.h"
+#include "ConflictChecker.hpp"
+
+#if ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION
+
+#include <tbb/parallel_for.h>
+#include <tbb/concurrent_vector.h>
+
+#include <map>
+#include <functional>
+#include <atomic>
+
+namespace Slic3r {
+
+namespace RasterizationImpl {
+using IndexPair = std::pair<int64_t, int64_t>;
+using Grids     = std::vector<IndexPair>;
+
+inline constexpr int64_t RasteXDistance = scale_(1);
+inline constexpr int64_t RasteYDistance = scale_(1);
+
+inline IndexPair point_map_grid_index(const Point &pt, int64_t xdist, int64_t ydist)
+{
+    auto x = pt.x() / xdist;
+    auto y = pt.y() / ydist;
+    return std::make_pair(x, y);
+}
+
+inline bool nearly_equal(const Point &p1, const Point &p2) { return std::abs(p1.x() - p2.x()) < SCALED_EPSILON && std::abs(p1.y() - p2.y()) < SCALED_EPSILON; }
+
+inline Grids line_rasterization(const Line &line, int64_t xdist = RasteXDistance, int64_t ydist = RasteYDistance)
+{
+    Grids     res;
+    Point     rayStart     = line.a;
+    Point     rayEnd       = line.b;
+    IndexPair currentVoxel = point_map_grid_index(rayStart, xdist, ydist);
+    IndexPair firstVoxel   = currentVoxel;
+    IndexPair lastVoxel    = point_map_grid_index(rayEnd, xdist, ydist);
+
+    Point ray = rayEnd - rayStart;
+
+    double stepX = ray.x() >= 0 ? 1 : -1;
+    double stepY = ray.y() >= 0 ? 1 : -1;
+
+    double nextVoxelBoundaryX = (currentVoxel.first + stepX) * xdist;
+    double nextVoxelBoundaryY = (currentVoxel.second + stepY) * ydist;
+
+    if (stepX < 0) { nextVoxelBoundaryX += xdist; }
+    if (stepY < 0) { nextVoxelBoundaryY += ydist; }
+
+    double tMaxX = ray.x() != 0 ? (nextVoxelBoundaryX - rayStart.x()) / ray.x() : DBL_MAX;
+    double tMaxY = ray.y() != 0 ? (nextVoxelBoundaryY - rayStart.y()) / ray.y() : DBL_MAX;
+
+    double tDeltaX = ray.x() != 0 ? static_cast<double>(xdist) / ray.x() * stepX : DBL_MAX;
+    double tDeltaY = ray.y() != 0 ? static_cast<double>(ydist) / ray.y() * stepY : DBL_MAX;
+
+    res.push_back(currentVoxel);
+
+    double tx = tMaxX;
+    double ty = tMaxY;
+
+    while (lastVoxel != currentVoxel) {
+        if (lastVoxel.first == currentVoxel.first) {
+            for (int64_t i = currentVoxel.second; i != lastVoxel.second; i += (int64_t) stepY) {
+                currentVoxel.second += (int64_t) stepY;
+                res.push_back(currentVoxel);
+            }
+            break;
+        }
+        if (lastVoxel.second == currentVoxel.second) {
+            for (int64_t i = currentVoxel.first; i != lastVoxel.first; i += (int64_t) stepX) {
+                currentVoxel.first += (int64_t) stepX;
+                res.push_back(currentVoxel);
+            }
+            break;
+        }
+
+        if (tx < ty) {
+            currentVoxel.first += (int64_t) stepX;
+            tx += tDeltaX;
+        } else {
+            currentVoxel.second += (int64_t) stepY;
+            ty += tDeltaY;
+        }
+        res.push_back(currentVoxel);
+        if (res.size() >= 100000) { // bug
+            assert(0);
+        }
+    }
+
+    return res;
+}
+} // namespace RasterizationImpl
+
+void LinesBucketQueue::emplace_back_bucket(std::vector<ExtrusionPaths> &&paths, const void *objPtr, Point offset)
+{
+    auto oldSize = _buckets.capacity();
+    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
+        decltype(_pq) newQueue;
+        for (LinesBucket &bucket : _buckets) { newQueue.push(&bucket); }
+        std::swap(_pq, newQueue);
+    }
+}
+
+double LinesBucketQueue::removeLowests()
+{
+    auto lowest = _pq.top();
+    _pq.pop();
+    double                     curHeight = lowest->curHeight();
+    std::vector<LinesBucket *> lowests;
+    lowests.push_back(lowest);
+
+    while (_pq.empty() == false && std::abs(_pq.top()->curHeight() - lowest->curHeight()) < EPSILON) {
+        lowests.push_back(_pq.top());
+        _pq.pop();
+    }
+
+    for (LinesBucket *bp : lowests) {
+        bp->raise();
+        if (bp->valid()) { _pq.push(bp); }
+    }
+    return curHeight;
+}
+
+LineWithIDs LinesBucketQueue::getCurLines() const
+{
+    LineWithIDs lines;
+    for (const LinesBucket &bucket : _buckets) {
+        if (bucket.valid()) {
+            LineWithIDs tmpLines = bucket.curLines();
+            lines.insert(lines.end(), tmpLines.begin(), tmpLines.end());
+        }
+    }
+    return lines;
+}
+
+void getExtrusionPathsFromEntity(const ExtrusionEntityCollection *entity, ExtrusionPaths &paths)
+{
+    std::function<void(const ExtrusionEntityCollection *, ExtrusionPaths &)> getExtrusionPathImpl = [&](const ExtrusionEntityCollection *entity, ExtrusionPaths &paths) {
+        for (auto entityPtr : entity->entities) {
+            if (const ExtrusionEntityCollection *collection = dynamic_cast<ExtrusionEntityCollection *>(entityPtr)) {
+                getExtrusionPathImpl(collection, paths);
+            } else if (const ExtrusionPath *path = dynamic_cast<ExtrusionPath *>(entityPtr)) {
+                paths.push_back(*path);
+            } else if (const ExtrusionMultiPath *multipath = dynamic_cast<ExtrusionMultiPath *>(entityPtr)) {
+                for (const ExtrusionPath &path : multipath->paths) { paths.push_back(path); }
+            } else if (const ExtrusionLoop *loop = dynamic_cast<ExtrusionLoop *>(entityPtr)) {
+                for (const ExtrusionPath &path : loop->paths) { paths.push_back(path); }
+            }
+        }
+    };
+    getExtrusionPathImpl(entity, paths);
+}
+
+ExtrusionPaths getExtrusionPathsFromLayer(LayerRegionPtrs layerRegionPtrs)
+{
+    ExtrusionPaths paths;
+    for (auto regionPtr : layerRegionPtrs) {
+#if ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION_MOD
+        getExtrusionPathsFromEntity(&regionPtr->perimeters(), paths);
+        if (!regionPtr->perimeters().empty()) { getExtrusionPathsFromEntity(&regionPtr->fills(), paths); }
+#else
+        getExtrusionPathsFromEntity(&regionPtr->perimeters, paths);
+        if (regionPtr->perimeters.empty() == false) { getExtrusionPathsFromEntity(&regionPtr->fills, paths); }
+#endif // ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION_MOD
+    }
+    return paths;
+}
+
+ExtrusionPaths getExtrusionPathsFromSupportLayer(SupportLayer *supportLayer)
+{
+    ExtrusionPaths paths;
+    getExtrusionPathsFromEntity(&supportLayer->support_fills, paths);
+    return paths;
+}
+
+std::pair<std::vector<ExtrusionPaths>, std::vector<ExtrusionPaths>> getAllLayersExtrusionPathsFromObject(PrintObject *obj)
+{
+    std::vector<ExtrusionPaths> objPaths, supportPaths;
+
+    for (auto layerPtr : obj->layers()) { objPaths.push_back(getExtrusionPathsFromLayer(layerPtr->regions())); }
+
+    for (auto supportLayerPtr : obj->support_layers()) { supportPaths.push_back(getExtrusionPathsFromSupportLayer(supportLayerPtr)); }
+
+    return {std::move(objPaths), std::move(supportPaths)};
+}
+
+ConflictComputeOpt ConflictChecker::find_inter_of_lines(const LineWithIDs &lines)
+{
+    using namespace RasterizationImpl;
+    std::map<IndexPair, std::vector<int>> indexToLine;
+
+    for (int i = 0; i < lines.size(); ++i) {
+        const LineWithID &l1      = lines[i];
+        auto              indexes = line_rasterization(l1._line);
+        for (auto index : indexes) {
+            const auto &possibleIntersectIdxs = indexToLine[index];
+            for (auto possibleIntersectIdx : possibleIntersectIdxs) {
+                const LineWithID &l2 = lines[possibleIntersectIdx];
+                if (auto interRes = line_intersect(l1, l2); interRes.has_value()) { return interRes; }
+            }
+            indexToLine[index].push_back(i);
+        }
+    }
+    return {};
+}
+
+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 {}; }
+    LinesBucketQueue conflictQueue;
+    if (wtdptr.has_value()) { // wipe tower at 0 by default
+#if ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION_MOD
+        auto wtpaths = (*wtdptr)->getFakeExtrusionPathsFromWipeTower();
+        conflictQueue.emplace_back_bucket(std::move(wtpaths), *wtdptr, { (*wtdptr)->plate_origin.x(), (*wtdptr)->plate_origin.y() });
+#else
+        auto wtpaths = wtdptr.value()->getFakeExtrusionPathsFromWipeTower();
+        conflictQueue.emplace_back_bucket(std::move(wtpaths), wtdptr.value(), {wtdptr.value()->plate_origin.x(),wtdptr.value()->plate_origin.y()});
+#endif // ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION_MOD
+    }
+    for (PrintObject *obj : objs) {
+        auto layers = getAllLayersExtrusionPathsFromObject(obj);
+        conflictQueue.emplace_back_bucket(std::move(layers.first), obj, obj->instances().front().shift);
+        conflictQueue.emplace_back_bucket(std::move(layers.second), obj, obj->instances().front().shift);
+    }
+
+    std::vector<LineWithIDs> layersLines;
+    std::vector<double>      heights;
+    while (conflictQueue.valid()) {
+        LineWithIDs lines     = conflictQueue.getCurLines();
+        double      curHeight = conflictQueue.removeLowests();
+        heights.push_back(curHeight);
+        layersLines.push_back(std::move(lines));
+    }
+
+    bool                                   find = false;
+    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;
+#if ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION_MOD
+                conflict.emplace_back(*interRes, heights[i]);
+#else
+                conflict.emplace_back(interRes.value(),heights[i]);
+#endif // ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION_MOD
+                break;
+            }
+        }
+    });
+
+    if (find) {
+        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()) {
+#if ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION_MOD
+            const FakeWipeTower* wtdp = *wtdptr;
+#else
+            const FakeWipeTower *wtdp = wtdptr.value();
+#endif // ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION_MOD
+            if (ptr1 == wtdp || ptr2 == wtdp) {
+                if (ptr2 == wtdp) { std::swap(ptr1, ptr2); }
+                const PrintObject *obj2 = reinterpret_cast<const PrintObject *>(ptr2);
+                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_optional<ConflictResult>(obj1->model_object()->name, obj2->model_object()->name, conflictHeight, ptr1, ptr2);
+    } else
+        return {};
+}
+
+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;
+    bool  intersect = l1._line.intersection(l2._line, &inter);
+    if (intersect) {
+        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<ConflictComputeResult>(l1._id, l2._id); } // the two lines intersects if dist>0.01mm
+    }
+    return {};
+}
+
+} // namespace Slic3r
+
+#endif // ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION
diff --git a/src/libslic3r/GCode/ConflictChecker.hpp b/src/libslic3r/GCode/ConflictChecker.hpp
new file mode 100644
index 000000000..00c975c37
--- /dev/null
+++ b/src/libslic3r/GCode/ConflictChecker.hpp
@@ -0,0 +1,143 @@
+#ifndef slic3r_ConflictChecker_hpp_
+#define slic3r_ConflictChecker_hpp_
+
+#if ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION
+
+#include "../Utils.hpp"
+#include "../Model.hpp"
+#include "../Print.hpp"
+#include "../Layer.hpp"
+
+#include <queue>
+#include <vector>
+#include <optional>
+
+namespace Slic3r {
+
+struct LineWithID
+{
+    Line _line;
+    int  _id;
+#if ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION_MOD
+    ExtrusionRole _role;
+
+    LineWithID(const Line& line, int id, const ExtrusionRole& role) : _line(line), _id(id), _role(role) {}
+#else
+    int  _role;
+
+    LineWithID(const Line& line, int id, int role) : _line(line), _id(id), _role(role) {}
+#endif // ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION_MOD
+};
+
+using LineWithIDs = std::vector<LineWithID>;
+
+class LinesBucket
+{
+private:
+    double   _curHeight  = 0.0;
+    unsigned _curPileIdx = 0;
+
+    std::vector<ExtrusionPaths> _piles;
+    int                         _id;
+    Point                       _offset;
+
+public:
+    LinesBucket(std::vector<ExtrusionPaths> &&paths, int id, Point offset) : _piles(paths), _id(id), _offset(offset) {}
+    LinesBucket(LinesBucket &&) = default;
+
+    bool valid() const { return _curPileIdx < _piles.size(); }
+    void raise()
+    {
+        if (valid()) {
+            if (_piles[_curPileIdx].empty() == false) { _curHeight += _piles[_curPileIdx].front().height; }
+            _curPileIdx++;
+        }
+    }
+    double      curHeight() const { return _curHeight; }
+    LineWithIDs curLines() const
+    {
+        LineWithIDs lines;
+        for (const ExtrusionPath &path : _piles[_curPileIdx]) {
+#if !ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION_MOD
+            //
+            // INTEGRATION WHAT TO DO ???
+            // we do not define path.is_force_no_extrusion()
+            //
+            if (path.is_force_no_extrusion() == false) {
+#endif // !ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION_MOD
+                Polyline check_polyline = path.polyline;
+                check_polyline.translate(_offset);
+                Lines tmpLines = check_polyline.lines();
+                for (const Line &line : tmpLines) { lines.emplace_back(line, _id, path.role()); }
+#if !ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION_MOD
+            }
+#endif // !ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION_MOD
+        }
+        return lines;
+    }
+
+    friend bool operator>(const LinesBucket &left, const LinesBucket &right) { return left._curHeight > right._curHeight; }
+    friend bool operator<(const LinesBucket &left, const LinesBucket &right) { return left._curHeight < right._curHeight; }
+    friend bool operator==(const LinesBucket &left, const LinesBucket &right) { return left._curHeight == right._curHeight; }
+};
+
+struct LinesBucketPtrComp
+{
+    bool operator()(const LinesBucket *left, const LinesBucket *right) { return *left > *right; }
+};
+
+class LinesBucketQueue
+{
+private:
+    std::vector<LinesBucket>                                                           _buckets;
+    std::priority_queue<LinesBucket *, std::vector<LinesBucket *>, LinesBucketPtrComp> _pq;
+    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 (_idToObjsPtr.find(id) != _idToObjsPtr.end())
+            return _idToObjsPtr[id];
+        else
+            return nullptr;
+    }
+    double      removeLowests();
+    LineWithIDs getCurLines() const;
+};
+
+void getExtrusionPathsFromEntity(const ExtrusionEntityCollection *entity, ExtrusionPaths &paths);
+
+ExtrusionPaths getExtrusionPathsFromLayer(LayerRegionPtrs layerRegionPtrs);
+
+ExtrusionPaths getExtrusionPathsFromSupportLayer(SupportLayer *supportLayer);
+
+std::pair<std::vector<ExtrusionPaths>, std::vector<ExtrusionPaths>> getAllLayersExtrusionPathsFromObject(PrintObject *obj);
+
+struct ConflictComputeResult
+{
+    int _obj1;
+    int _obj2;
+
+    ConflictComputeResult(int o1, int o2) : _obj1(o1), _obj2(o2) {}
+    ConflictComputeResult() = default;
+};
+
+using ConflictComputeOpt = std::optional<ConflictComputeResult>;
+
+using ConflictObjName = std::optional<std::pair<std::string, std::string>>;
+
+struct ConflictChecker
+{
+    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
+
+#endif // ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION
+
+#endif
diff --git a/src/libslic3r/GCode/GCodeProcessor.hpp b/src/libslic3r/GCode/GCodeProcessor.hpp
index 26cb89894..6a9d5606e 100644
--- a/src/libslic3r/GCode/GCodeProcessor.hpp
+++ b/src/libslic3r/GCode/GCodeProcessor.hpp
@@ -82,6 +82,24 @@ namespace Slic3r {
         }
     };
 
+#if ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION
+    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>;
+#endif // ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION
+
     struct GCodeProcessorResult
     {
         struct SettingsIds
@@ -137,6 +155,10 @@ namespace Slic3r {
         std::vector<CustomGCode::Item> custom_gcode_per_print_z;
         std::vector<std::pair<float, std::pair<size_t, size_t>>> spiral_vase_layers;
 
+#if ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION
+        ConflictResultOpt conflict_result;
+#endif // ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION
+
 #if ENABLE_GCODE_VIEWER_STATISTICS
         int64_t time{ 0 };
 #endif // ENABLE_GCODE_VIEWER_STATISTICS
diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp
index ca3feb04e..b00b8e218 100644
--- a/src/libslic3r/Print.cpp
+++ b/src/libslic3r/Print.cpp
@@ -11,6 +11,9 @@
 #include "Thread.hpp"
 #include "GCode.hpp"
 #include "GCode/WipeTower.hpp"
+#if ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION
+#include "GCode/ConflictChecker.hpp"
+#endif // ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION
 #include "Utils.hpp"
 #include "BuildVolume.hpp"
 #include "format.hpp"
@@ -962,6 +965,43 @@ void Print::process()
         this->finalize_first_layer_convex_hull();
         this->set_done(psSkirtBrim);
     }
+
+#if ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION
+#if !ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION_MOD
+    //
+    // INTEGRATION WHAT TO DO ???
+    // we do not define m_no_check
+    //
+    if (!m_no_check) {
+        using Clock = std::chrono::high_resolution_clock;
+        auto            startTime = Clock::now();
+#endif // !ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION_MOD
+        std::optional<const FakeWipeTower*> wipe_tower_opt = {};
+        if (this->has_wipe_tower()) {
+#if ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION_MOD
+            m_fake_wipe_tower.set_pos({ m_config.wipe_tower_x, m_config.wipe_tower_y });
+#else
+            m_fake_wipe_tower.set_pos({ m_config.wipe_tower_x.get_at(m_plate_index), m_config.wipe_tower_y.get_at(m_plate_index) });
+#endif // ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION_MOD
+            wipe_tower_opt = std::make_optional<const FakeWipeTower*>(&m_fake_wipe_tower);
+        }
+        auto            conflictRes = ConflictChecker::find_inter_of_lines_in_diff_objs(m_objects, wipe_tower_opt);
+#if !ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION_MOD
+        auto            endTime = Clock::now();
+        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.";
+#endif // !ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION_MOD
+
+        m_conflict_result = conflictRes;
+        if (conflictRes.has_value())
+#if ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION_MOD
+            BOOST_LOG_TRIVIAL(error) << boost::format("gcode path conflicts found between %1% and %2%") % conflictRes->_objName1 % conflictRes->_objName2;
+#else
+            BOOST_LOG_TRIVIAL(error) << boost::format("gcode path conflicts found between %1% and %2%") % conflictRes.value()._objName1 % conflictRes.value()._objName2;
+    }
+#endif // ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION_MOD
+#endif // ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION
+
     BOOST_LOG_TRIVIAL(info) << "Slicing process finished." << log_memory_info();
 }
 
@@ -987,6 +1027,11 @@ std::string Print::export_gcode(const std::string& path_template, GCodeProcessor
     // Create GCode on heap, it has quite a lot of data.
     std::unique_ptr<GCode> gcode(new GCode);
     gcode->do_export(this, path.c_str(), result, thumbnail_cb);
+
+#if ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION
+    result->conflict_result = m_conflict_result;
+#endif // ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION
+
     return path.c_str();
 }
 
diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp
index 5c42709b1..12058734b 100644
--- a/src/libslic3r/Print.hpp
+++ b/src/libslic3r/Print.hpp
@@ -418,6 +418,78 @@ private:
     FillLightning::GeneratorPtr m_lightning_generator;
 };
 
+#if ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION
+struct FakeWipeTower
+{
+    // generate fake extrusion
+    Vec2f pos;
+    float width;
+    float height;
+    float layer_height;
+    float depth;
+    float brim_width;
+    Vec2d plate_origin;
+
+#if ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION_MOD
+    void set_fake_extrusion_data(const Vec2f& p, float w, float h, float lh, float d, float bd, const Vec2d& o)
+#else
+    void set_fake_extrusion_data(Vec2f p, float w, float h, float lh, float d, float bd, Vec2d o)
+#endif // ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION_MOD
+    {
+        pos = p;
+        width = w;
+        height = h;
+        layer_height = lh;
+        depth = d;
+        brim_width = bd;
+        plate_origin = o;
+    }
+
+#if ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION_MOD
+    void set_pos(const Vec2f& p) { pos = p; }
+#else
+    void set_pos(Vec2f p) { pos = p; }
+#endif // ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION_MOD
+
+    std::vector<ExtrusionPaths> getFakeExtrusionPathsFromWipeTower() const
+    {
+        float h = height;
+        float lh = layer_height;
+        int   d = scale_(depth);
+        int   w = scale_(width);
+        int   bd = scale_(brim_width);
+        Point minCorner = { scale_(pos.x()), scale_(pos.y()) };
+        Point maxCorner = { minCorner.x() + w, minCorner.y() + d };
+
+        std::vector<ExtrusionPaths> paths;
+        for (float hh = 0.f; hh < h; hh += lh) {
+#if ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION_MOD
+            ExtrusionPath path(ExtrusionRole::WipeTower, 0.0, 0.0, lh);
+#else
+            ExtrusionPath path(ExtrusionRole::erWipeTower, 0.0, 0.0, lh);
+#endif // ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION_MOD
+            path.polyline = { minCorner, {maxCorner.x(), minCorner.y()}, maxCorner, {minCorner.x(), maxCorner.y()}, minCorner };
+            paths.push_back({ path });
+
+#if !ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION_MOD
+            //
+            // INTEGRATION WHAT TO DO ???
+            // we do not define erBrim
+            //
+            if (hh == 0.f) { // add brim
+                ExtrusionPath fakeBrim(ExtrusionRole::erBrim, 0.0, 0.0, lh);
+                Point         wtbminCorner = { minCorner - Point{bd, bd} };
+                Point         wtbmaxCorner = { maxCorner + Point{bd, bd} };
+                fakeBrim.polyline = { wtbminCorner, {wtbmaxCorner.x(), wtbminCorner.y()}, wtbmaxCorner, {wtbminCorner.x(), wtbmaxCorner.y()}, wtbminCorner };
+                paths.back().push_back(fakeBrim);
+            }
+#endif // !ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION_MOD
+        }
+        return paths;
+    }
+};
+#endif // ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION
+
 struct WipeTowerData
 {
     // Following section will be consumed by the GCodeGenerator.
@@ -668,6 +740,11 @@ private:
     friend class GCodeProcessor;
     // Allow PrintObject to access m_mutex and m_cancel_callback.
     friend class PrintObject;
+
+#if ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION
+    ConflictResultOpt m_conflict_result;
+    FakeWipeTower     m_fake_wipe_tower;
+#endif // ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION
 };
 
 } /* slic3r_Print_hpp_ */
diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp
index 602654633..36b51fe2d 100644
--- a/src/libslic3r/Technologies.hpp
+++ b/src/libslic3r/Technologies.hpp
@@ -62,4 +62,27 @@
 #define ENABLE_ALTERNATIVE_FILE_WILDCARDS_GENERATOR (1 && ENABLE_2_6_0_ALPHA1)
 
 
+//====================
+// 2.6.0.beta1 techs
+//====================
+#define ENABLE_2_6_0_BETA1 1
+
+// Toolpaths conflicts detection
+// Succesfully enhanced and integrated into PrusaSlicer from BambuStudio:
+// https://github.com/bambulab/BambuStudio/commit/d43c7d5c9293508241ee88cee860ea7ea51c2080
+// https://github.com/bambulab/BambuStudio/commit/d72b4c1bfe3f0c275241250a0b1797944147b3b7
+// https://github.com/bambulab/BambuStudio/commit/87eb0f366560b895cb7219a2eb6820027aaf69d3
+// https://github.com/bambulab/BambuStudio/commit/b5b7264e99ea0872d39455bf61af56209cb4cd39
+// Co-authored-by: manch1n <miaoxin.chen@bambulab.com>
+// Co-authored-by: miaoxin <miaoxin.chen@bambulab.com>
+// Co-authored-by: lane.wei <lane.wei@bambulab.com>
+
+#define ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION (1 && ENABLE_2_6_0_BETA1)
+
+// Modifications to original BambuStudio code:
+// * compliance with PS code
+// * removed code which has no clear counterpart in PS
+#define ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION_MOD (1 && ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION)
+
+
 #endif // _prusaslicer_technologies_h_
diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp
index a9e016bb9..5261113e0 100644
--- a/src/slic3r/GUI/GCodeViewer.cpp
+++ b/src/slic3r/GUI/GCodeViewer.cpp
@@ -799,6 +799,15 @@ void GCodeViewer::load(const GCodeProcessorResult& gcode_result, const Print& pr
             short_time(get_time_dhms(time)) == short_time(get_time_dhms(m_print_statistics.modes[static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Normal)].time)))
             m_time_estimate_mode = PrintEstimatedStatistics::ETimeMode::Normal;
     }
+
+#if ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION
+    m_conflict_result = gcode_result.conflict_result;
+#if ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION_MOD
+    if (m_conflict_result.has_value()) { m_conflict_result->layer = m_layers.get_l_at(m_conflict_result->_height); }
+#else
+    if (m_conflict_result) { m_conflict_result.value().layer = m_layers.get_l_at(m_conflict_result.value()._height); }
+#endif // ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION_MOD
+#endif // ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION
 }
 
 void GCodeViewer::refresh(const GCodeProcessorResult& gcode_result, const std::vector<std::string>& str_tool_colors)
diff --git a/src/slic3r/GUI/GCodeViewer.hpp b/src/slic3r/GUI/GCodeViewer.hpp
index 3eb61cfc4..a8290350d 100644
--- a/src/slic3r/GUI/GCodeViewer.hpp
+++ b/src/slic3r/GUI/GCodeViewer.hpp
@@ -526,6 +526,12 @@ class GCodeViewer
         std::vector<Range>& get_ranges() { return m_ranges; }
         double get_z_at(unsigned int id) const { return (id < m_zs.size()) ? m_zs[id] : 0.0; }
         Range get_range_at(unsigned int id) const { return (id < m_ranges.size()) ? m_ranges[id] : Range(); }
+#if ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION
+        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);
+        }
+#endif // ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION
 
         bool operator != (const Layers& other) const {
             if (m_zs != other.m_zs)
@@ -784,6 +790,10 @@ private:
 
     bool m_contained_in_bed{ true };
 
+#if ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION
+    ConflictResultOpt m_conflict_result;
+#endif // ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION
+
 public:
     GCodeViewer();
     ~GCodeViewer() { reset(); }
@@ -841,6 +851,10 @@ public:
 
     void invalidate_legend() { m_legend_resizer.reset(); }
 
+#if ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION
+    const ConflictResultOpt& get_conflict_result() const { return m_conflict_result; }
+#endif // ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION
+
 private:
     void load_toolpaths(const GCodeProcessorResult& gcode_result);
     void load_shells(const Print& print);
diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp
index 3beaa591a..14db2f8df 100644
--- a/src/slic3r/GUI/GLCanvas3D.cpp
+++ b/src/slic3r/GUI/GLCanvas3D.cpp
@@ -2692,6 +2692,9 @@ void GLCanvas3D::load_gcode_preview(const GCodeProcessorResult& gcode_result, co
     if (wxGetApp().is_editor()) {
         m_gcode_viewer.update_shells_color_by_extruder(m_config);
         _set_warning_notification_if_needed(EWarning::ToolpathOutside);
+#if ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION
+        _set_warning_notification_if_needed(EWarning::GCodeConflict);
+#endif // ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION
     }
 
     m_gcode_viewer.refresh(gcode_result, str_tool_colors);
@@ -7440,8 +7443,21 @@ void GLCanvas3D::_set_warning_notification_if_needed(EWarning warning)
     }
     else {
         if (wxGetApp().is_editor()) {
-            if (current_printer_technology() != ptSLA)
+#if ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION
+          if (current_printer_technology() != ptSLA) {
+              if (warning == EWarning::ToolpathOutside)
+                  show = m_gcode_viewer.has_data() && !m_gcode_viewer.is_contained_in_bed();
+              else if (warning == EWarning::GCodeConflict)
+#if ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION_MOD
+                  show = m_gcode_viewer.has_data() && m_gcode_viewer.is_contained_in_bed() && m_gcode_viewer.get_conflict_result().has_value();
+#else
+                  show = m_gcode_viewer.has_data() && m_gcode_viewer.is_contained_in_bed() && m_gcode_viewer.m_conflict_result.has_value();
+#endif // ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION_MOD
+          }
+#else
+          if (current_printer_technology() != ptSLA)
                 show = m_gcode_viewer.has_data() && !m_gcode_viewer.is_contained_in_bed();
+#endif // ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION
         }
     }
 
@@ -7467,8 +7483,88 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state)
             "Resolve the current problem to continue slicing.");
         error = ErrorType::PLATER_ERROR;
         break;
+#if ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION
+    case EWarning::GCodeConflict: {
+#if ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION_MOD
+      const ConflictResultOpt& conflict_result = m_gcode_viewer.get_conflict_result();
+      if (!conflict_result.has_value()) { break; }
+      std::string objName1 = conflict_result->_objName1;
+      std::string objName2 = conflict_result->_objName2;
+      double      height = conflict_result->_height;
+      int         layer = conflict_result->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();
+#else
+        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();
+#endif // ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION_MOD
+        error = ErrorType::SLICING_ERROR;
+        break;
+    }
+#endif // ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION
     }
     auto& notification_manager = *wxGetApp().plater()->get_notification_manager();
+
+#if ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION
+#if ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION_MOD
+    const ConflictResultOpt& conflict_result = m_gcode_viewer.get_conflict_result();
+    if (warning == EWarning::GCodeConflict) {
+        if (conflict_result.has_value()) {
+            const PrintObject* obj2 = reinterpret_cast<const PrintObject*>(conflict_result->_obj2);
+#else
+    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);
+#endif // ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION_MOD
+            auto     mo = obj2->model_object();
+            ObjectID id = mo->id();
+#if ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION_MOD
+            auto     action_fn = [this, id](wxEvtHandler*) {
+#else
+        auto               action_fn = [id](wxEvtHandler*) {
+#endif // ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION_MOD
+                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()) {
+#if ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION_MOD
+                    const unsigned int obj_idx = std::distance(objects.begin(), iter);
+                    wxGetApp().CallAfter([this, obj_idx]() {
+                        wxGetApp().plater()->select_view_3D("3D");
+                        wxGetApp().plater()->canvas3D()->get_selection().add_object(obj_idx, true);
+                        wxGetApp().obj_list()->update_selections();
+                    });
+#else
+            wxGetApp().mainframe->select_tab(MainFrame::tp3DEditor);
+            wxGetApp().obj_list()->select_items({ { *iter, nullptr } });
+#endif // ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION_MOD
+                }
+                return false;
+            };
+            auto hypertext = _u8L("Jump to");
+            hypertext += std::string(" [") + mo->name + "]";
+#if ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION_MOD
+            notification_manager.push_notification(NotificationType::SlicingError, NotificationManager::NotificationLevel::ErrorNotificationLevel,
+                _u8L("ERROR:") + "\n" + text, hypertext, action_fn);
+#else
+        notification_manager.push_notification(NotificationType::PlaterError, NotificationManager::NotificationLevel::ErrorNotificationLevel,
+            _u8L("ERROR:") + "\n" + text, hypertext, action_fn);
+        return;
+#endif // ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION_MOD
+        }
+#if ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION_MOD
+        else
+            notification_manager.close_slicing_error_notification(text);
+
+        return;
+    }
+#endif // ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION_MOD
+#endif // ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION
+
     switch (error)
     {
     case PLATER_WARNING:
diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp
index a58decbcd..613d97698 100644
--- a/src/slic3r/GUI/GLCanvas3D.hpp
+++ b/src/slic3r/GUI/GLCanvas3D.hpp
@@ -362,7 +362,12 @@ class GLCanvas3D
         ToolpathOutside,
         SlaSupportsOutside,
         SomethingNotShown,
+#if ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION
+        ObjectClashed,
+        GCodeConflict
+#else
         ObjectClashed
+#endif // ENABLE_BAMBUSTUDIO_TOOLPATHS_CONFLICTS_DETECTION
     };
 
     class RenderStats