mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-11-02 20:51:23 -07:00 
			
		
		
		
	Add simplification GUI
This commit is contained in:
		
							parent
							
								
									756d2694eb
								
							
						
					
					
						commit
						af526c54f4
					
				
					 12 changed files with 476 additions and 195 deletions
				
			
		| 
						 | 
				
			
			@ -57,6 +57,8 @@ set(SLIC3R_GUI_SOURCES
 | 
			
		|||
    GUI/Gizmos/GLGizmoPainterBase.hpp
 | 
			
		||||
    GUI/Gizmos/GLGizmoSeam.cpp
 | 
			
		||||
    GUI/Gizmos/GLGizmoSeam.hpp
 | 
			
		||||
    GUI/Gizmos/GLGizmoSimplify.cpp
 | 
			
		||||
    GUI/Gizmos/GLGizmoSimplify.hpp
 | 
			
		||||
    GUI/Gizmos/GLGizmoMmuSegmentation.cpp
 | 
			
		||||
    GUI/Gizmos/GLGizmoMmuSegmentation.hpp
 | 
			
		||||
    GUI/GLSelectionRectangle.cpp
 | 
			
		||||
| 
						 | 
				
			
			@ -97,8 +99,6 @@ set(SLIC3R_GUI_SOURCES
 | 
			
		|||
    GUI/SavePresetDialog.cpp
 | 
			
		||||
    GUI/PhysicalPrinterDialog.hpp
 | 
			
		||||
    GUI/PhysicalPrinterDialog.cpp
 | 
			
		||||
    GUI/SimplificationDialog.cpp
 | 
			
		||||
    GUI/SimplificationDialog.hpp
 | 
			
		||||
    GUI/GUI_Factories.cpp
 | 
			
		||||
    GUI/GUI_Factories.hpp
 | 
			
		||||
    GUI/GUI_ObjectList.cpp
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,7 +4,6 @@
 | 
			
		|||
#include "GUI_Factories.hpp"
 | 
			
		||||
#include "GUI_ObjectManipulation.hpp"
 | 
			
		||||
#include "GUI_ObjectLayers.hpp"
 | 
			
		||||
#include "SimplificationDialog.hpp"
 | 
			
		||||
#include "GUI_App.hpp"
 | 
			
		||||
#include "I18N.hpp"
 | 
			
		||||
#include "Plater.hpp"
 | 
			
		||||
| 
						 | 
				
			
			@ -3762,13 +3761,8 @@ void ObjectList::fix_through_netfabb()
 | 
			
		|||
 | 
			
		||||
void ObjectList::simplify()
 | 
			
		||||
{
 | 
			
		||||
    int obj_idx, vol_idx;
 | 
			
		||||
    get_selected_item_indexes(obj_idx, vol_idx);
 | 
			
		||||
 | 
			
		||||
    SimplificationDialog dlg(this);
 | 
			
		||||
    dlg.ShowModal();
 | 
			
		||||
 | 
			
		||||
    wxGetApp().plater()->simplify(obj_idx, vol_idx);
 | 
			
		||||
    GLGizmosManager& gizmos_mgr = wxGetApp().plater()->canvas3D()->get_gizmos_manager();
 | 
			
		||||
    gizmos_mgr.open_gizmo(GLGizmosManager::EType::Simplify);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ObjectList::update_item_error_icon(const int obj_idx, const int vol_idx) const 
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										231
									
								
								src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										231
									
								
								src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,231 @@
 | 
			
		|||
// Include GLGizmoBase.hpp before I18N.hpp as it includes some libigl code, which overrides our localization "L" macro.
 | 
			
		||||
#include "GLGizmoSimplify.hpp"
 | 
			
		||||
#include "slic3r/GUI/GLCanvas3D.hpp"
 | 
			
		||||
#include "slic3r/GUI/GUI_App.hpp"
 | 
			
		||||
#include "slic3r/GUI/Plater.hpp"
 | 
			
		||||
#include "slic3r/GUI/GUI_ObjectManipulation.hpp"
 | 
			
		||||
#include "libslic3r/AppConfig.hpp"
 | 
			
		||||
#include "libslic3r/Model.hpp"
 | 
			
		||||
#include "libslic3r/QuadricEdgeCollapse.hpp"
 | 
			
		||||
 | 
			
		||||
namespace Slic3r::GUI {
 | 
			
		||||
 | 
			
		||||
GLGizmoSimplify::GLGizmoSimplify(GLCanvas3D &       parent,
 | 
			
		||||
                                 const std::string &icon_filename,
 | 
			
		||||
                                 unsigned int       sprite_id)
 | 
			
		||||
    : GLGizmoBase(parent, icon_filename, -1)
 | 
			
		||||
    , state(State::settings)
 | 
			
		||||
    , is_valid_result(false)
 | 
			
		||||
    , progress(0)
 | 
			
		||||
    , volume(nullptr)
 | 
			
		||||
    , obj_index(0)
 | 
			
		||||
    , need_reload(false)
 | 
			
		||||
{}
 | 
			
		||||
 | 
			
		||||
GLGizmoSimplify::~GLGizmoSimplify() { 
 | 
			
		||||
    state = State::canceling;
 | 
			
		||||
    if (worker.joinable()) worker.join();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool GLGizmoSimplify::on_init()
 | 
			
		||||
{
 | 
			
		||||
    //m_grabbers.emplace_back();
 | 
			
		||||
    //m_shortcut_key = WXK_CONTROL_C;
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string GLGizmoSimplify::on_get_name() const
 | 
			
		||||
{
 | 
			
		||||
    return (_L("Simplify")).ToUTF8().data();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLGizmoSimplify::on_render() const{}
 | 
			
		||||
void GLGizmoSimplify::on_render_for_picking() const{}
 | 
			
		||||
 | 
			
		||||
void GLGizmoSimplify::on_render_input_window(float x, float y, float bottom_limit)
 | 
			
		||||
{
 | 
			
		||||
    const Selection &selection = m_parent.get_selection();
 | 
			
		||||
    int object_idx = selection.get_object_idx();
 | 
			
		||||
    ModelObject *obj = wxGetApp().plater()->model().objects[object_idx];
 | 
			
		||||
    ModelVolume *act_volume = obj->volumes.front();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    // Check selection of new volume
 | 
			
		||||
    // Do not reselect object when processing 
 | 
			
		||||
    if (act_volume != volume && state == State::settings) {
 | 
			
		||||
        obj_index = object_idx; // to remember correct object
 | 
			
		||||
        volume = act_volume;
 | 
			
		||||
        original_its = {};
 | 
			
		||||
        const TriangleMesh &tm = volume->mesh();
 | 
			
		||||
        c.wanted_percent = 50.;  // default value
 | 
			
		||||
        c.update_percent(tm.its.indices.size());
 | 
			
		||||
        is_valid_result = false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    size_t triangle_count = volume->mesh().its.indices.size();
 | 
			
		||||
    // already reduced mesh
 | 
			
		||||
    if (original_its.has_value())
 | 
			
		||||
        triangle_count = original_its->indices.size();
 | 
			
		||||
 | 
			
		||||
    int flag = ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize |
 | 
			
		||||
               ImGuiWindowFlags_NoCollapse;
 | 
			
		||||
    m_imgui->begin(_L("Simplify mesh ") + volume->name, flag);
 | 
			
		||||
    std::string description = "Reduce amout of triangle in mesh( " +
 | 
			
		||||
                              volume->name + " has " +
 | 
			
		||||
                              std::to_string(triangle_count) + " triangles)";
 | 
			
		||||
    ImGui::Text(description.c_str());
 | 
			
		||||
    // First initialization + fix triangle count
 | 
			
		||||
    if (c.wanted_count > triangle_count) c.update_percent(triangle_count);
 | 
			
		||||
    if (m_imgui->checkbox(_L("Until triangle count is less than "), c.use_count)) {
 | 
			
		||||
        if (!c.use_count) c.use_error = true;
 | 
			
		||||
        is_valid_result = false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    m_imgui->disabled_begin(!c.use_count);
 | 
			
		||||
    ImGui::SameLine();
 | 
			
		||||
    int wanted_count = c.wanted_count;
 | 
			
		||||
    if (ImGui::SliderInt("triangles", &wanted_count, 0,
 | 
			
		||||
                         triangle_count, "%d")) {
 | 
			
		||||
        c.wanted_count = static_cast<uint32_t>(wanted_count);
 | 
			
		||||
        c.update_count(triangle_count);
 | 
			
		||||
        is_valid_result = false;
 | 
			
		||||
    }
 | 
			
		||||
    ImGui::SameLine();
 | 
			
		||||
    ImGui::SetNextItemWidth(80);
 | 
			
		||||
    int precision = (c.wanted_percent > 10)? 0: ((c.wanted_percent > 1)? 1:2);
 | 
			
		||||
    float step = (c.wanted_percent > 10)? 1.f: ((c.wanted_percent > 1)? 0.1f : 0.01f);
 | 
			
		||||
    if (ImGui::InputFloat("%", &c.wanted_percent, step, 10*step, precision)) {
 | 
			
		||||
        if (c.wanted_percent < 0.f) c.wanted_percent = 0.f;
 | 
			
		||||
        if (c.wanted_percent > 100.f) c.wanted_percent = 100.f;
 | 
			
		||||
        c.update_percent(triangle_count);
 | 
			
		||||
        is_valid_result = false;
 | 
			
		||||
    }
 | 
			
		||||
    m_imgui->disabled_end(); // use_count
 | 
			
		||||
 | 
			
		||||
    if (m_imgui->checkbox(_L("Until error"), c.use_error)) {
 | 
			
		||||
        if (!c.use_error) c.use_count = true;
 | 
			
		||||
        is_valid_result = false;
 | 
			
		||||
    }
 | 
			
		||||
    ImGui::SameLine();
 | 
			
		||||
    m_imgui->disabled_begin(!c.use_error);
 | 
			
		||||
    if (ImGui::InputFloat("(maximal quadric error)", &c.max_error, 0.01f, .1f, 2)) {
 | 
			
		||||
        if (c.max_error < 0.f) c.max_error = 0.f;
 | 
			
		||||
        is_valid_result = false;
 | 
			
		||||
    }
 | 
			
		||||
    m_imgui->disabled_end(); // use_error
 | 
			
		||||
 | 
			
		||||
    if (state == State::settings) {
 | 
			
		||||
        if (m_imgui->button(_L("Cancel"))) {
 | 
			
		||||
            if (original_its.has_value()) { 
 | 
			
		||||
                 set_its(*original_its);
 | 
			
		||||
                state = State::close_on_end;
 | 
			
		||||
            } else {
 | 
			
		||||
                close();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        ImGui::SameLine();
 | 
			
		||||
        if (m_imgui->button(_L("Preview"))) {
 | 
			
		||||
            state = State::simplifying;
 | 
			
		||||
            // simplify but not aply on mesh
 | 
			
		||||
            process();
 | 
			
		||||
        }
 | 
			
		||||
        ImGui::SameLine();
 | 
			
		||||
        if (m_imgui->button(_L("Aply"))) {
 | 
			
		||||
            if (!is_valid_result) {
 | 
			
		||||
                state = State::close_on_end;
 | 
			
		||||
                process();
 | 
			
		||||
            } else {
 | 
			
		||||
                // use preview and close
 | 
			
		||||
                close();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    } else {        
 | 
			
		||||
        m_imgui->disabled_begin(state == State::canceling);
 | 
			
		||||
        if (m_imgui->button(_L("Cancel"))) state = State::canceling;
 | 
			
		||||
        m_imgui->disabled_end(); 
 | 
			
		||||
 | 
			
		||||
        ImGui::SameLine();
 | 
			
		||||
        // draw progress bar
 | 
			
		||||
        ImGui::Text("Processing %c \t %d / 100",
 | 
			
		||||
                    "|/-\\"[(int) (ImGui::GetTime() / 0.05f) & 3], progress);
 | 
			
		||||
    }
 | 
			
		||||
    m_imgui->end();
 | 
			
		||||
 | 
			
		||||
    if (need_reload) { 
 | 
			
		||||
        need_reload = false;
 | 
			
		||||
 | 
			
		||||
        // Reload visualization of mesh - change VBO, FBO on GPU
 | 
			
		||||
        m_parent.reload_scene(true); // deactivate gizmo??
 | 
			
		||||
        GLGizmosManager &gizmos_mgr = m_parent.get_gizmos_manager();
 | 
			
		||||
        gizmos_mgr.open_gizmo(GLGizmosManager::EType::Simplify);
 | 
			
		||||
 | 
			
		||||
        if (state == State::close_on_end) {
 | 
			
		||||
            // fix hollowing, sla support points, modifiers, ...
 | 
			
		||||
            auto plater = wxGetApp().plater();
 | 
			
		||||
            plater->changed_mesh(obj_index); // deactivate gizmo??
 | 
			
		||||
            // changed_mesh cause close();
 | 
			
		||||
            //close(); 
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // change from simplifying | aply
 | 
			
		||||
        state = State::settings;
 | 
			
		||||
        
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLGizmoSimplify::close() {
 | 
			
		||||
    volume = nullptr;
 | 
			
		||||
    
 | 
			
		||||
    // close gizmo == open it again
 | 
			
		||||
    GLGizmosManager &gizmos_mgr = m_parent.get_gizmos_manager();
 | 
			
		||||
    gizmos_mgr.open_gizmo(GLGizmosManager::EType::Simplify);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void GLGizmoSimplify::process()
 | 
			
		||||
{
 | 
			
		||||
    class SimplifyCanceledException : public std::exception {
 | 
			
		||||
    public:
 | 
			
		||||
       const char* what() const throw() { return L("Model simplification has been canceled"); }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    if (!original_its.has_value()) 
 | 
			
		||||
        original_its = volume->mesh().its; // copy
 | 
			
		||||
    
 | 
			
		||||
    auto plater = wxGetApp().plater();
 | 
			
		||||
    plater->take_snapshot(_L("Simplify ") + volume->name);
 | 
			
		||||
    plater->clear_before_change_mesh(obj_index);
 | 
			
		||||
    progress = 0;
 | 
			
		||||
    if (worker.joinable()) worker.join();
 | 
			
		||||
    worker = std::thread([&]() {
 | 
			
		||||
        // store original triangles        
 | 
			
		||||
        uint32_t                  triangle_count  = (c.use_count)? c.wanted_count : 0;
 | 
			
		||||
        float*                    max_error       = (c.use_error)? &c.max_error : nullptr;
 | 
			
		||||
        std::function<void(void)> throw_on_cancel = [&]() { if ( state == State::canceling) throw SimplifyCanceledException(); };    
 | 
			
		||||
        std::function<void(int)> statusfn = [&](int percent) { progress = percent; };
 | 
			
		||||
        indexed_triangle_set collapsed = original_its.value(); // copy
 | 
			
		||||
        try {
 | 
			
		||||
            its_quadric_edge_collapse(collapsed, triangle_count, max_error, throw_on_cancel, statusfn);
 | 
			
		||||
            set_its(collapsed);
 | 
			
		||||
            is_valid_result = true;
 | 
			
		||||
        } catch (SimplifyCanceledException &) {
 | 
			
		||||
            is_valid_result = false;
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLGizmoSimplify::set_its(indexed_triangle_set &its) {
 | 
			
		||||
    auto tm = std::make_unique<TriangleMesh>(its);
 | 
			
		||||
    tm->repair();
 | 
			
		||||
    volume->set_mesh(std::move(tm));
 | 
			
		||||
    volume->set_new_unique_id();
 | 
			
		||||
    volume->get_object()->invalidate_bounding_box();
 | 
			
		||||
    need_reload = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool GLGizmoSimplify::on_is_activable() const
 | 
			
		||||
{
 | 
			
		||||
    return !m_parent.get_selection().is_empty();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace Slic3r::GUI
 | 
			
		||||
							
								
								
									
										76
									
								
								src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,76 @@
 | 
			
		|||
#ifndef slic3r_GLGizmoSimplify_hpp_
 | 
			
		||||
#define slic3r_GLGizmoSimplify_hpp_
 | 
			
		||||
 | 
			
		||||
#include "GLGizmoBase.hpp"
 | 
			
		||||
#include "libslic3r/Model.hpp"
 | 
			
		||||
#include <thread>
 | 
			
		||||
#include <optional>
 | 
			
		||||
 | 
			
		||||
namespace Slic3r {
 | 
			
		||||
namespace GUI {
 | 
			
		||||
 | 
			
		||||
class GLGizmoSimplify : public GLGizmoBase
 | 
			
		||||
{
 | 
			
		||||
    enum class State {
 | 
			
		||||
        settings,
 | 
			
		||||
        simplifying, // start processing
 | 
			
		||||
        canceling, // canceled
 | 
			
		||||
        successfull, // successful simplified
 | 
			
		||||
        close_on_end
 | 
			
		||||
    } state;
 | 
			
		||||
 | 
			
		||||
    bool is_valid_result; // differ what to do in apply
 | 
			
		||||
 | 
			
		||||
    int progress;
 | 
			
		||||
    
 | 
			
		||||
    ModelVolume *volume;
 | 
			
		||||
    size_t obj_index;
 | 
			
		||||
    std::optional<indexed_triangle_set> original_its;
 | 
			
		||||
 | 
			
		||||
    bool need_reload; // after simplify, glReload must be on main thread
 | 
			
		||||
    std::thread worker;
 | 
			
		||||
public:
 | 
			
		||||
    GLGizmoSimplify(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
 | 
			
		||||
    virtual ~GLGizmoSimplify();
 | 
			
		||||
    void set_selectable(bool value);
 | 
			
		||||
protected:
 | 
			
		||||
    virtual bool on_init() override;
 | 
			
		||||
    virtual std::string on_get_name() const override;
 | 
			
		||||
    virtual void on_render() const override;
 | 
			
		||||
    virtual void on_render_for_picking() const override;    
 | 
			
		||||
    virtual void on_render_input_window(float x, float y, float bottom_limit) override;
 | 
			
		||||
    virtual bool on_is_activable() const override;
 | 
			
		||||
    virtual bool on_is_selectable() const override { return false; };
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    void close();
 | 
			
		||||
    void process();
 | 
			
		||||
    void set_its(indexed_triangle_set &its);
 | 
			
		||||
    struct Configuration
 | 
			
		||||
    {
 | 
			
		||||
        bool use_count = true;
 | 
			
		||||
        // minimal triangle count
 | 
			
		||||
        float    wanted_percent = 50.f;
 | 
			
		||||
        uint32_t wanted_count   = 0; // initialize by percents
 | 
			
		||||
 | 
			
		||||
        bool use_error = false;
 | 
			
		||||
        // maximal quadric error
 | 
			
		||||
        float max_error = 1.;
 | 
			
		||||
 | 
			
		||||
        void update_count(size_t triangle_count)
 | 
			
		||||
        {
 | 
			
		||||
            wanted_percent = (float) wanted_count / triangle_count * 100.f;
 | 
			
		||||
        }
 | 
			
		||||
        void update_percent(size_t triangle_count)
 | 
			
		||||
        {
 | 
			
		||||
            wanted_count = static_cast<uint32_t>(
 | 
			
		||||
                std::round(triangle_count * wanted_percent / 100.f));
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
    Configuration c;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace GUI
 | 
			
		||||
} // namespace Slic3r
 | 
			
		||||
 | 
			
		||||
#endif // slic3r_GLGizmoSimplify_hpp_
 | 
			
		||||
| 
						 | 
				
			
			@ -20,6 +20,7 @@
 | 
			
		|||
#include "slic3r/GUI/Gizmos/GLGizmoHollow.hpp"
 | 
			
		||||
#include "slic3r/GUI/Gizmos/GLGizmoSeam.hpp"
 | 
			
		||||
#include "slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp"
 | 
			
		||||
#include "slic3r/GUI/Gizmos/GLGizmoSimplify.hpp"
 | 
			
		||||
 | 
			
		||||
#include "libslic3r/Model.hpp"
 | 
			
		||||
#include "libslic3r/PresetBundle.hpp"
 | 
			
		||||
| 
						 | 
				
			
			@ -110,6 +111,7 @@ bool GLGizmosManager::init()
 | 
			
		|||
    m_gizmos.emplace_back(new GLGizmoFdmSupports(m_parent, "fdm_supports.svg", 7));
 | 
			
		||||
    m_gizmos.emplace_back(new GLGizmoSeam(m_parent, "seam.svg", 8));
 | 
			
		||||
    m_gizmos.emplace_back(new GLGizmoMmuSegmentation(m_parent, "fdm_supports.svg", 9));
 | 
			
		||||
    m_gizmos.emplace_back(new GLGizmoSimplify(m_parent, "cut.svg", 10));
 | 
			
		||||
 | 
			
		||||
    m_common_gizmos_data.reset(new CommonGizmosDataPool(&m_parent));
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -169,7 +171,7 @@ void GLGizmosManager::reset_all_states()
 | 
			
		|||
bool GLGizmosManager::open_gizmo(EType type)
 | 
			
		||||
{
 | 
			
		||||
    int idx = int(type);
 | 
			
		||||
    if (m_gizmos[idx]->is_selectable() && m_gizmos[idx]->is_activable()) {
 | 
			
		||||
    if (/*m_gizmos[idx]->is_selectable() &&*/ m_gizmos[idx]->is_activable()) {
 | 
			
		||||
        activate_gizmo(m_current == idx ? Undefined : (EType)idx);
 | 
			
		||||
        update_data();
 | 
			
		||||
        return true;
 | 
			
		||||
| 
						 | 
				
			
			@ -1021,6 +1023,8 @@ void GLGizmosManager::do_render_overlay() const
 | 
			
		|||
    float u_offset = 1.0f / (float)tex_width;
 | 
			
		||||
    float v_offset = 1.0f / (float)tex_height;
 | 
			
		||||
 | 
			
		||||
    float toolbar_top = 0.f;
 | 
			
		||||
    float current_y   = 0.f;
 | 
			
		||||
    for (size_t idx : selectable_idxs)
 | 
			
		||||
    {
 | 
			
		||||
        GLGizmoBase* gizmo = m_gizmos[idx].get();
 | 
			
		||||
| 
						 | 
				
			
			@ -1035,11 +1039,14 @@ void GLGizmosManager::do_render_overlay() const
 | 
			
		|||
 | 
			
		||||
        GLTexture::render_sub_texture(icons_texture_id, zoomed_top_x, zoomed_top_x + zoomed_icons_size, zoomed_top_y - zoomed_icons_size, zoomed_top_y, { { u_left, v_bottom }, { u_right, v_bottom }, { u_right, v_top }, { u_left, v_top } });
 | 
			
		||||
        if (idx == m_current) {
 | 
			
		||||
            float toolbar_top = cnv_h - wxGetApp().plater()->get_view_toolbar().get_height();
 | 
			
		||||
            gizmo->render_input_window(width, 0.5f * cnv_h - zoomed_top_y * zoom, toolbar_top);
 | 
			
		||||
            toolbar_top = cnv_h - wxGetApp().plater()->get_view_toolbar().get_height();
 | 
			
		||||
            current_y = 0.5f * cnv_h - zoomed_top_y * zoom;
 | 
			
		||||
        }
 | 
			
		||||
        zoomed_top_y -= zoomed_stride_y;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (m_current != Undefined) 
 | 
			
		||||
        m_gizmos[m_current]->render_input_window(width, current_y, toolbar_top);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float GLGizmosManager::get_scaled_total_height() const
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -69,6 +69,7 @@ public:
 | 
			
		|||
        FdmSupports,
 | 
			
		||||
        Seam,
 | 
			
		||||
        MmuSegmentation,
 | 
			
		||||
        Simplify,
 | 
			
		||||
        Undefined
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1730,7 +1730,6 @@ struct Plater::priv
 | 
			
		|||
    void replace_with_stl();
 | 
			
		||||
    void reload_all_from_disk();
 | 
			
		||||
    void fix_through_netfabb(const int obj_idx, const int vol_idx = -1);
 | 
			
		||||
    void simplify(const int obj_idx, const int vol_idx = -1);
 | 
			
		||||
 | 
			
		||||
    void set_current_panel(wxPanel* panel);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3555,70 +3554,10 @@ void Plater::priv::fix_through_netfabb(const int obj_idx, const int vol_idx/* =
 | 
			
		|||
    // size_t snapshot_time = undo_redo_stack().active_snapshot_time();
 | 
			
		||||
    Plater::TakeSnapshot snapshot(q, _L("Fix through NetFabb"));
 | 
			
		||||
 | 
			
		||||
    q->clear_before_change_mesh(obj_idx);
 | 
			
		||||
    ModelObject* mo = model.objects[obj_idx];
 | 
			
		||||
 | 
			
		||||
    // If there are custom supports/seams/mmu segmentation, remove them. Fixed mesh
 | 
			
		||||
    // may be different and they would make no sense.
 | 
			
		||||
    bool paint_removed = false;
 | 
			
		||||
    for (ModelVolume* mv : mo->volumes) {
 | 
			
		||||
        paint_removed |= ! mv->supported_facets.empty() || ! mv->seam_facets.empty() || ! mv->mmu_segmentation_facets.empty();
 | 
			
		||||
        mv->supported_facets.clear();
 | 
			
		||||
        mv->seam_facets.clear();
 | 
			
		||||
        mv->mmu_segmentation_facets.clear();
 | 
			
		||||
    }
 | 
			
		||||
    if (paint_removed) {
 | 
			
		||||
        // snapshot_time is captured by copy so the lambda knows where to undo/redo to.
 | 
			
		||||
        notification_manager->push_notification(
 | 
			
		||||
                    NotificationType::CustomSupportsAndSeamRemovedAfterRepair,
 | 
			
		||||
                    NotificationManager::NotificationLevel::RegularNotification,
 | 
			
		||||
                    _u8L("Custom supports and seams were removed after repairing the mesh."));
 | 
			
		||||
//                    _u8L("Undo the repair"),
 | 
			
		||||
//                    [this, snapshot_time](wxEvtHandler*){
 | 
			
		||||
//                        // Make sure the snapshot is still available and that
 | 
			
		||||
//                        // we are in the main stack and not in a gizmo-stack.
 | 
			
		||||
//                        if (undo_redo_stack().has_undo_snapshot(snapshot_time)
 | 
			
		||||
//                         && q->canvas3D()->get_gizmos_manager().get_current() == nullptr)
 | 
			
		||||
//                            undo_redo_to(snapshot_time);
 | 
			
		||||
//                        else
 | 
			
		||||
//                            notification_manager->push_notification(
 | 
			
		||||
//                                NotificationType::CustomSupportsAndSeamRemovedAfterRepair,
 | 
			
		||||
//                                NotificationManager::NotificationLevel::RegularNotification,
 | 
			
		||||
//                                _u8L("Cannot undo to before the mesh repair!"));
 | 
			
		||||
//                        return true;
 | 
			
		||||
//                    });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fix_model_by_win10_sdk_gui(*mo, vol_idx);
 | 
			
		||||
    sla::reproject_points_and_holes(mo);
 | 
			
		||||
    this->update();
 | 
			
		||||
    this->object_list_changed();
 | 
			
		||||
    this->schedule_background_process();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Plater::priv::simplify(const int obj_idx, const int vol_idx/* = -1*/)
 | 
			
		||||
{
 | 
			
		||||
    if (obj_idx < 0)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    // Do not fix anything when a gizmo is open. There might be issues with updates
 | 
			
		||||
    // and what is worse, the snapshot time would refer to the internal stack.
 | 
			
		||||
    if (q->canvas3D()->get_gizmos_manager().get_current_type() != GLGizmosManager::Undefined) {
 | 
			
		||||
        notification_manager->push_notification(
 | 
			
		||||
                    NotificationType::CustomSupportsAndSeamRemovedAfterRepair,
 | 
			
		||||
                    NotificationManager::NotificationLevel::RegularNotification,
 | 
			
		||||
                    _u8L("ERROR: Please close all manipulators available from "
 | 
			
		||||
                         "the left toolbar before fixing the mesh."));
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // size_t snapshot_time = undo_redo_stack().active_snapshot_time();
 | 
			
		||||
    Plater::TakeSnapshot snapshot(q, _L("Symplify model"));
 | 
			
		||||
 | 
			
		||||
    // ToDo
 | 
			
		||||
 | 
			
		||||
    this->update();
 | 
			
		||||
    this->object_list_changed();
 | 
			
		||||
    this->schedule_background_process();
 | 
			
		||||
    q->changed_mesh(obj_idx);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Plater::priv::set_current_panel(wxPanel* panel)
 | 
			
		||||
| 
						 | 
				
			
			@ -6262,6 +6201,51 @@ bool Plater::set_printer_technology(PrinterTechnology printer_technology)
 | 
			
		|||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Plater::clear_before_change_mesh(int obj_idx)
 | 
			
		||||
{
 | 
			
		||||
    ModelObject* mo = model().objects[obj_idx];
 | 
			
		||||
 | 
			
		||||
    // If there are custom supports/seams/mmu segmentation, remove them. Fixed mesh
 | 
			
		||||
    // may be different and they would make no sense.
 | 
			
		||||
    bool paint_removed = false;
 | 
			
		||||
    for (ModelVolume* mv : mo->volumes) {
 | 
			
		||||
        paint_removed |= ! mv->supported_facets.empty() || ! mv->seam_facets.empty() || ! mv->mmu_segmentation_facets.empty();
 | 
			
		||||
        mv->supported_facets.clear();
 | 
			
		||||
        mv->seam_facets.clear();
 | 
			
		||||
        mv->mmu_segmentation_facets.clear();
 | 
			
		||||
    }
 | 
			
		||||
    if (paint_removed) {
 | 
			
		||||
        // snapshot_time is captured by copy so the lambda knows where to undo/redo to.
 | 
			
		||||
        get_notification_manager()->push_notification(
 | 
			
		||||
                    NotificationType::CustomSupportsAndSeamRemovedAfterRepair,
 | 
			
		||||
                    NotificationManager::NotificationLevel::RegularNotification,
 | 
			
		||||
                    _u8L("Custom supports and seams were removed after repairing the mesh."));
 | 
			
		||||
//                    _u8L("Undo the repair"),
 | 
			
		||||
//                    [this, snapshot_time](wxEvtHandler*){
 | 
			
		||||
//                        // Make sure the snapshot is still available and that
 | 
			
		||||
//                        // we are in the main stack and not in a gizmo-stack.
 | 
			
		||||
//                        if (undo_redo_stack().has_undo_snapshot(snapshot_time)
 | 
			
		||||
//                         && q->canvas3D()->get_gizmos_manager().get_current() == nullptr)
 | 
			
		||||
//                            undo_redo_to(snapshot_time);
 | 
			
		||||
//                        else
 | 
			
		||||
//                            notification_manager->push_notification(
 | 
			
		||||
//                                NotificationType::CustomSupportsAndSeamRemovedAfterRepair,
 | 
			
		||||
//                                NotificationManager::NotificationLevel::RegularNotification,
 | 
			
		||||
//                                _u8L("Cannot undo to before the mesh repair!"));
 | 
			
		||||
//                        return true;
 | 
			
		||||
//                    });
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Plater::changed_mesh(int obj_idx)
 | 
			
		||||
{
 | 
			
		||||
    ModelObject* mo = model().objects[obj_idx];
 | 
			
		||||
    sla::reproject_points_and_holes(mo);
 | 
			
		||||
    update();
 | 
			
		||||
    p->object_list_changed();
 | 
			
		||||
    p->schedule_background_process();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Plater::changed_object(int obj_idx)
 | 
			
		||||
{
 | 
			
		||||
    if (obj_idx < 0)
 | 
			
		||||
| 
						 | 
				
			
			@ -6343,7 +6327,6 @@ void Plater::suppress_background_process(const bool stop_background_process)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
void Plater::fix_through_netfabb(const int obj_idx, const int vol_idx/* = -1*/) { p->fix_through_netfabb(obj_idx, vol_idx); }
 | 
			
		||||
void Plater::simplify(const int obj_idx, const int vol_idx/* = -1*/) { p->simplify(obj_idx, vol_idx); }
 | 
			
		||||
void Plater::mirror(Axis axis)      { p->mirror(axis); }
 | 
			
		||||
void Plater::split_object()         { p->split_object(); }
 | 
			
		||||
void Plater::split_volume()         { p->split_volume(); }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -230,13 +230,16 @@ public:
 | 
			
		|||
    void reslice_SLA_supports(const ModelObject &object, bool postpone_error_messages = false);
 | 
			
		||||
    void reslice_SLA_hollowing(const ModelObject &object, bool postpone_error_messages = false);
 | 
			
		||||
    void reslice_SLA_until_step(SLAPrintObjectStep step, const ModelObject &object, bool postpone_error_messages = false);
 | 
			
		||||
 | 
			
		||||
    void clear_before_change_mesh(int obj_idx);
 | 
			
		||||
    void changed_mesh(int obj_idx);
 | 
			
		||||
 | 
			
		||||
    void changed_object(int obj_idx);
 | 
			
		||||
    void changed_objects(const std::vector<size_t>& object_idxs);
 | 
			
		||||
    void schedule_background_process(bool schedule = true);
 | 
			
		||||
    bool is_background_process_update_scheduled() const;
 | 
			
		||||
    void suppress_background_process(const bool stop_background_process) ;
 | 
			
		||||
    void fix_through_netfabb(const int obj_idx, const int vol_idx = -1);
 | 
			
		||||
    void simplify(const int obj_idx, const int vol_idx = -1);
 | 
			
		||||
    void send_gcode();
 | 
			
		||||
	void eject_drive();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,91 +0,0 @@
 | 
			
		|||
#include "SimplificationDialog.hpp"
 | 
			
		||||
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <boost/algorithm/string.hpp>
 | 
			
		||||
 | 
			
		||||
#include <wx/sizer.h>
 | 
			
		||||
#include <wx/stattext.h>
 | 
			
		||||
#include <wx/textctrl.h>
 | 
			
		||||
#include <wx/button.h>
 | 
			
		||||
#include <wx/statbox.h>
 | 
			
		||||
#include <wx/wupdlock.h>
 | 
			
		||||
 | 
			
		||||
#include "GUI.hpp"
 | 
			
		||||
#include "GUI_App.hpp"
 | 
			
		||||
#include "format.hpp"
 | 
			
		||||
#include "wxExtensions.hpp"
 | 
			
		||||
#include "I18N.hpp"
 | 
			
		||||
#include "libslic3r/Utils.hpp"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace Slic3r {
 | 
			
		||||
namespace GUI {
 | 
			
		||||
 | 
			
		||||
#define BORDER_W 10
 | 
			
		||||
 | 
			
		||||
SimplificationDialog::SimplificationDialog(wxWindow* parent) :
 | 
			
		||||
    DPIDialog(parent, wxID_ANY, _L("Name of Dialog"), wxDefaultPosition, wxSize(45 * wxGetApp().em_unit(), -1), wxDEFAULT_DIALOG_STYLE/* | wxRESIZE_BORDER*/)
 | 
			
		||||
{
 | 
			
		||||
    SetFont(wxGetApp().normal_font());
 | 
			
		||||
 | 
			
		||||
    wxStaticText* label_top = new wxStaticText(this, wxID_ANY, _L("Some text") + ":");
 | 
			
		||||
 | 
			
		||||
    wxFlexGridSizer* grid_sizer = new wxFlexGridSizer(3, 2, 1, 2);
 | 
			
		||||
    grid_sizer->AddGrowableCol(1, 1);
 | 
			
		||||
    grid_sizer->SetFlexibleDirection(wxBOTH);
 | 
			
		||||
 | 
			
		||||
    for (int i = 0; i < 3; i++) {
 | 
			
		||||
        auto* text = new wxStaticText(this, wxID_ANY, _L("Text") + " " + std::to_string(i) + " :");
 | 
			
		||||
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
        long style = wxBORDER_SIMPLE;
 | 
			
		||||
#else
 | 
			
		||||
        long style = 0
 | 
			
		||||
#endif
 | 
			
		||||
        auto value = new wxTextCtrl(this, wxID_ANY, "Some Value", wxDefaultPosition, wxDefaultSize, style);
 | 
			
		||||
 | 
			
		||||
        grid_sizer->Add(text, 0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxRIGHT, 4);
 | 
			
		||||
        grid_sizer->Add(value, 1, wxEXPAND | wxBOTTOM, 1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    wxStdDialogButtonSizer* btns = this->CreateStdDialogButtonSizer(wxOK | wxCANCEL);
 | 
			
		||||
    this->Bind(wxEVT_BUTTON, &SimplificationDialog::OnOK, this, wxID_OK);
 | 
			
		||||
 | 
			
		||||
    wxBoxSizer* topSizer = new wxBoxSizer(wxVERTICAL);
 | 
			
		||||
 | 
			
		||||
    topSizer->Add(label_top , 0, wxEXPAND | wxLEFT | wxTOP | wxRIGHT, BORDER_W);
 | 
			
		||||
    topSizer->Add(grid_sizer, 1, wxEXPAND | wxLEFT | wxTOP | wxRIGHT, BORDER_W);
 | 
			
		||||
    topSizer->Add(btns      , 0, wxEXPAND | wxALL, BORDER_W); 
 | 
			
		||||
 | 
			
		||||
    SetSizer(topSizer);
 | 
			
		||||
    topSizer->SetSizeHints(this);
 | 
			
		||||
 | 
			
		||||
    wxGetApp().UpdateDlgDarkUI(this);
 | 
			
		||||
 | 
			
		||||
    this->CenterOnScreen();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SimplificationDialog::~SimplificationDialog()
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SimplificationDialog::on_dpi_changed(const wxRect& suggested_rect)
 | 
			
		||||
{
 | 
			
		||||
    const int& em = em_unit();
 | 
			
		||||
    msw_buttons_rescale(this, em, { wxID_OK, wxID_CANCEL });
 | 
			
		||||
 | 
			
		||||
    const wxSize& size = wxSize(45 * em, 35 * em);
 | 
			
		||||
    SetMinSize(size);
 | 
			
		||||
 | 
			
		||||
    Fit();
 | 
			
		||||
    Refresh();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SimplificationDialog::OnOK(wxEvent& event)
 | 
			
		||||
{
 | 
			
		||||
    event.Skip();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}}    // namespace Slic3r::GUI
 | 
			
		||||
| 
						 | 
				
			
			@ -1,25 +0,0 @@
 | 
			
		|||
#ifndef slic3r_SimplificationDialog_hpp_
 | 
			
		||||
#define slic3r_SimplificationDialog_hpp_
 | 
			
		||||
 | 
			
		||||
#include "GUI_Utils.hpp"
 | 
			
		||||
 | 
			
		||||
namespace Slic3r {
 | 
			
		||||
namespace GUI {
 | 
			
		||||
 | 
			
		||||
class SimplificationDialog : public DPIDialog
 | 
			
		||||
{
 | 
			
		||||
    void OnOK(wxEvent& event);
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    SimplificationDialog(wxWindow* parent);
 | 
			
		||||
    ~SimplificationDialog();
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
    void on_dpi_changed(const wxRect& suggested_rect) override;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
} // namespace GUI
 | 
			
		||||
} // namespace Slic3r
 | 
			
		||||
 | 
			
		||||
#endif //slic3r_SimplificationDialog_hpp_
 | 
			
		||||
| 
						 | 
				
			
			@ -231,9 +231,10 @@ TEST_CASE("Reduce one edge by Quadric Edge Collapse", "[its]")
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
#include "test_utils.hpp"
 | 
			
		||||
TEST_CASE("Symplify mesh by Quadric edge collapse to 5%", "[its]")
 | 
			
		||||
TEST_CASE("Simplify mesh by Quadric edge collapse to 5%", "[its]")
 | 
			
		||||
{
 | 
			
		||||
    TriangleMesh mesh = load_model("frog_legs.obj"); 
 | 
			
		||||
    //TriangleMesh mesh; load_obj("C:/Users/filip/Documents/models/scarecrow_torso.obj", &mesh); 
 | 
			
		||||
    double original_volume = its_volume(mesh.its);
 | 
			
		||||
    uint32_t wanted_count = mesh.its.indices.size() * 0.05;
 | 
			
		||||
    REQUIRE_FALSE(mesh.empty());
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -339,3 +339,104 @@ TEST_CASE("Mutable priority queue - reshedule first", "[MutableSkipHeapPriorityQ
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("Mutable priority queue - first pop", "[MutableSkipHeapPriorityQueue]")
 | 
			
		||||
{
 | 
			
		||||
    struct MyValue{
 | 
			
		||||
        int   id;
 | 
			
		||||
        float val;
 | 
			
		||||
    };
 | 
			
		||||
    size_t              count = 50000;
 | 
			
		||||
    std::vector<size_t> idxs(count, {0});
 | 
			
		||||
    std::vector<bool>   dels(count, false);
 | 
			
		||||
    auto q = make_miniheap_mutable_priority_queue<MyValue, 16, true>(
 | 
			
		||||
        [&](MyValue &v, size_t idx) {
 | 
			
		||||
            idxs[v.id] = idx; 
 | 
			
		||||
        },
 | 
			
		||||
        [](MyValue &l, MyValue &r) { return l.val < r.val; });
 | 
			
		||||
    q.reserve(count);
 | 
			
		||||
    for (size_t id = 0; id < count; id++) {
 | 
			
		||||
        MyValue mv;
 | 
			
		||||
        mv.id  = id;
 | 
			
		||||
        mv.val = rand();
 | 
			
		||||
        q.push(mv);
 | 
			
		||||
    }
 | 
			
		||||
    MyValue it = q.top(); // copy
 | 
			
		||||
    q.pop();
 | 
			
		||||
    bool valid = (it.id != 0) && (idxs[0] < 3 * count);
 | 
			
		||||
    CHECK(valid);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("Mutable priority queue complex", "[MutableSkipHeapPriorityQueue]")
 | 
			
		||||
{
 | 
			
		||||
    struct MyValue {
 | 
			
		||||
        int id;
 | 
			
		||||
        float val;
 | 
			
		||||
    };
 | 
			
		||||
    size_t               count = 5000;
 | 
			
		||||
    std::vector<size_t>  idxs(count, {0});
 | 
			
		||||
    std::vector<bool>    dels(count, false);
 | 
			
		||||
    auto q = make_miniheap_mutable_priority_queue<MyValue, 16, true>(
 | 
			
		||||
        [&](MyValue &v, size_t idx) { idxs[v.id] = idx; },
 | 
			
		||||
        [](MyValue &l, MyValue &r) { return l.val < r.val; });
 | 
			
		||||
    q.reserve(count);
 | 
			
		||||
 | 
			
		||||
    auto rand_val = [&]()->float { return (rand() % 53) / 10.f; };
 | 
			
		||||
    int ord = 0;
 | 
			
		||||
    for (size_t id = 0; id < count; id++) {
 | 
			
		||||
        MyValue mv;
 | 
			
		||||
        mv.id = ord++;
 | 
			
		||||
        mv.val = rand_val();
 | 
			
		||||
        q.push(mv);
 | 
			
		||||
    }
 | 
			
		||||
    auto check = [&]()->bool{
 | 
			
		||||
        for (size_t i = 0; i < idxs.size(); ++i) {
 | 
			
		||||
            if (dels[i]) continue;
 | 
			
		||||
            size_t   qid = idxs[i];
 | 
			
		||||
            if (qid > 3*count) { 
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
            MyValue &mv  = q[qid]; 
 | 
			
		||||
            if (mv.id != i) { 
 | 
			
		||||
                return false; // ERROR 
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    CHECK(check()); // initial check
 | 
			
		||||
 | 
			
		||||
    auto get_valid_id = [&]()->int { 
 | 
			
		||||
        int id = 0;
 | 
			
		||||
        do {
 | 
			
		||||
            id = rand() % count;
 | 
			
		||||
        } while (dels[id]);
 | 
			
		||||
        return id;
 | 
			
		||||
    };
 | 
			
		||||
    for (size_t i = 0; i < 100; i++) {
 | 
			
		||||
        MyValue it = q.top(); // copy
 | 
			
		||||
        q.pop();
 | 
			
		||||
        dels[it.id] = true;
 | 
			
		||||
        CHECK(check());
 | 
			
		||||
        if (i % 20 == 0) {
 | 
			
		||||
            it.val = rand_val();
 | 
			
		||||
            q.push(it);
 | 
			
		||||
            dels[it.id] = false;
 | 
			
		||||
            CHECK(check());
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        int id = get_valid_id();
 | 
			
		||||
        q.remove(idxs[id]);
 | 
			
		||||
        dels[id] = true;
 | 
			
		||||
        CHECK(check());
 | 
			
		||||
        for (size_t j = 0; j < 5; j++) { 
 | 
			
		||||
            int id = get_valid_id();
 | 
			
		||||
            size_t   qid = idxs[id];
 | 
			
		||||
            MyValue &mv  = q[qid];
 | 
			
		||||
            mv.val       = rand_val();
 | 
			
		||||
            q.update(qid);
 | 
			
		||||
            CHECK(check());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue