From 2df069323c9de13b7caf9102ab0ce98a49b8ca5e Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Mon, 18 Feb 2019 12:28:58 +0100
Subject: [PATCH] Time estimation improvement

---
 src/libslic3r/PrintExport.hpp |  56 +++++++-----
 src/libslic3r/SLAPrint.cpp    | 164 +++++++++++++++++++++-------------
 src/libslic3r/SLAPrint.hpp    |   4 +
 src/slic3r/GUI/Plater.cpp     |  10 +--
 4 files changed, 147 insertions(+), 87 deletions(-)

diff --git a/src/libslic3r/PrintExport.hpp b/src/libslic3r/PrintExport.hpp
index d40b60aad..64babd507 100644
--- a/src/libslic3r/PrintExport.hpp
+++ b/src/libslic3r/PrintExport.hpp
@@ -16,8 +16,12 @@ namespace Slic3r {
 
 enum ePrintStatistics
 {
-    psObjectsUsedMaterial = 0,
-    psSupportUsedMaterial
+    psUsedMaterial = 0,
+    psNumFade,
+    psNumSlow,
+    psNumFast,
+
+    psCnt
 };
 
 enum class FilePrinterFormat {
@@ -124,40 +128,45 @@ template<> class FilePrinter<FilePrinterFormat::SLA_PNGZIP>
     double m_layer_height = .0;
     Raster::Origin m_o = Raster::Origin::TOP_LEFT;
 
-    double m_objects_used_material = 0.0;
-    double m_support_used_material = 0.0;
+    double m_used_material = 0.0;
+    int    m_cnt_fade_layers = 0;
+    int    m_cnt_slow_layers = 0;
+    int    m_cnt_fast_layers = 0;
 
     std::string createIniContent(const std::string& projectname) {
-        double layer_height = m_layer_height;
+//         double layer_height = m_layer_height;
 
         using std::string;
         using std::to_string;
 
         auto expt_str = to_string(m_exp_time_s);
         auto expt_first_str = to_string(m_exp_time_first_s);
-        auto stepnum_str = to_string(static_cast<unsigned>(800*layer_height));
-        auto layerh_str = to_string(layer_height);
+//         auto stepnum_str = to_string(static_cast<unsigned>(800*layer_height));
+        auto layerh_str = to_string(m_layer_height);
 
-        const std::string objects_used_material = to_string(m_objects_used_material);
-        const std::string support_used_material = to_string(m_support_used_material);
+        const std::string cnt_fade_layers = to_string(m_cnt_fade_layers);
+        const std::string cnt_slow_layers = to_string(m_cnt_slow_layers);
+        const std::string cnt_fast_layers = to_string(m_cnt_fast_layers);
+        const std::string used_material   = to_string(m_used_material);
 
         return string(
         "action = print\n"
         "jobDir = ") + projectname + "\n" +
         "expTime = " + expt_str + "\n"
         "expTimeFirst = " + expt_first_str + "\n"
-        "stepNum = " + stepnum_str + "\n"
-        "wifiOn = 1\n"
-        "tiltSlow = 60\n"
-        "tiltFast = 15\n"
-        "numFade = 10\n"
-        "startdelay = 0\n"
+//         "stepNum = " + stepnum_str + "\n"
+//         "wifiOn = 1\n"
+//         "tiltSlow = 60\n"
+//         "tiltFast = 15\n"
+        "numFade = " + cnt_fade_layers + "\n"
+//         "startdelay = 0\n"
         "layerHeight = " + layerh_str + "\n"
         "noteInfo = "
-        "expTime="+expt_str+"+resinType=generic+layerHeight="
-                  +layerh_str+"+printer=DWARF3\n"
-        "objUsedMaterial=" + objects_used_material + "\n"
-        "supUsedMaterial=" + support_used_material + "\n";
+        "expTime = "+expt_str+" + resinType = generic+layerHeight = "
+                  +layerh_str+" + printer = DWARF3\n"
+        "usedMaterial = " + used_material + "\n"
+        "numSlow = " + cnt_slow_layers + "\n"
+        "numFast = " + cnt_fast_layers + "\n";
     }
 
 public:
@@ -294,8 +303,13 @@ public:
 
     void set_statistics(const std::vector<double> statistics)
     {
-        m_objects_used_material = statistics[psObjectsUsedMaterial];
-        m_support_used_material = statistics[psSupportUsedMaterial];
+        if (statistics.size() != psCnt)
+            return;
+
+        m_used_material   = statistics[psUsedMaterial];
+        m_cnt_fade_layers = int(statistics[psNumFade]);
+        m_cnt_slow_layers = int(statistics[psNumSlow]);
+        m_cnt_fast_layers = int(statistics[psNumFast]);
     }
 };
 
diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp
index f95b16cfe..ecc990d01 100644
--- a/src/libslic3r/SLAPrint.cpp
+++ b/src/libslic3r/SLAPrint.cpp
@@ -971,8 +971,11 @@ void SLAPrint::process()
     fill_statistics();
     // Set statistics values to the printer
     SLAPrinter& printer = *m_printer;
-    printer.set_statistics({m_print_statistics.objects_used_material,
-                            m_print_statistics.support_used_material});
+    printer.set_statistics({(m_print_statistics.objects_used_material + m_print_statistics.support_used_material)/1000,
+                            10.0,
+                            double(m_print_statistics.slow_layers_count),
+                            double(m_print_statistics.fast_layers_count)
+                            });
 
     // If everything vent well
     report_status(*this, 100, L("Slicing done"));
@@ -1037,80 +1040,119 @@ bool SLAPrint::invalidate_state_by_config_options(const std::vector<t_config_opt
 
 void SLAPrint::fill_statistics()
 {
-    float supports_volume = 0.0;
-    float models_volume = 0.0;
+    const double init_layer_height  = m_material_config.initial_layer_height.getFloat();
+    const double layer_height       = m_default_object_config.layer_height.getFloat();
 
-    int max_layers_cnt = 0;
+    // TODO : slow_fast_limit, fast_tilt, slow_tilt should be filled in the future
+    // These variables will be a part of the printer preset
+    const double slow_fast_limit    = 0.5; // if printing area is more than 50% of the bed area, then use a slow tilt
+    const double fast_tilt          = 5.0;
+    const double slow_tilt          = 8.0;
 
-    const float init_layer_height = m_material_config.initial_layer_height.getFloat();
-    const float layer_height = m_default_object_config.layer_height.getFloat();
+    const double init_exp_time      = m_material_config.initial_exposure_time.getFloat();
+    const double exp_time           = m_material_config.exposure_time.getFloat();
 
-    // Used material
+    // TODO : fade_layers_cnt should be filled in the future
+    // This variable will be a part of the print preset
+    const int fade_layers_cnt       = 10; // [3;20]
+
+    const double width  = m_printer_config.display_width.getFloat() / SCALING_FACTOR;
+    const double height = m_printer_config.display_width.getFloat() / SCALING_FACTOR;
+    const double display_area       = width*height;
+
+    double supports_volume = 0.0;
+    double models_volume = 0.0;
+
+    double estim_time = 0.0;
+
+    size_t slow_layers = 0;
+    size_t fast_layers = 0;
+
+    // find highest object
+    size_t max_layers_cnt = 0;
+    size_t highest_obj_idx = 0;
     for (SLAPrintObject * po : m_objects) {
-        // Calculate full volume of the supports (+pad) 
-        for (const ExPolygons& polygons : po->get_support_slices())
-            for (const ExPolygon& polygon : polygons)
-                supports_volume += polygon.area() *layer_height;
-
-        // Calculate full volume of the object 
-        for (const ExPolygons& polygons : po->get_model_slices())
-            for (const ExPolygon& polygon : polygons)
-                models_volume += polygon.area() *layer_height;
-
         const SLAPrintObject::SliceIndex& slice_index = po->get_slice_index();
-
-        // If init_layer_height isn't equivalent to the layer_height,
-        // let correct volume of the first(initial) layer
-        if (init_layer_height != layer_height) 
-        {
-            const auto index = slice_index.begin();
-            if (index->second.support_slices_idx != SLAPrintObject::SliceRecord::NONE)
-                for (const ExPolygon& polygon : po->get_support_slices().front())
-                    supports_volume += polygon.area() *(init_layer_height - layer_height);
-            if (index->second.model_slices_idx != SLAPrintObject::SliceRecord::NONE)
-                for (const ExPolygon& polygon : po->get_model_slices().front())
-                    models_volume += polygon.area() *(init_layer_height - layer_height);
-        }
-
-        if (max_layers_cnt < slice_index.size())
+        if (max_layers_cnt < slice_index.size()) {
             max_layers_cnt = slice_index.size();
+            highest_obj_idx = std::find(m_objects.begin(), m_objects.end(), po) - m_objects.begin();
+        }
     }
 
-    m_print_statistics.support_used_material = supports_volume * SCALING_FACTOR * SCALING_FACTOR;
+    const SLAPrintObject * highest_obj = m_objects[highest_obj_idx];
+    const SLAPrintObject::SliceIndex& highest_obj_slice_index = highest_obj->get_slice_index();
+
+    const double delta_fade_time = (init_exp_time - exp_time) / (fade_layers_cnt + 1);
+    double fade_layer_time = init_exp_time;
+
+    int sliced_layer_cnt = 0;
+    for (const auto& layer : highest_obj_slice_index)
+    {
+        const double l_height = (layer.first == highest_obj_slice_index.begin()->first &&
+                                init_layer_height != layer_height) ? 
+                                init_layer_height : layer_height;
+
+        // Calculation of the consumed material 
+
+        double layer_model_area = 0;
+        double layer_support_area = 0;
+        for (SLAPrintObject * po : m_objects)
+        {
+            const auto index = po->get_slice_index();
+            if (index.find(layer.first) == index.end())
+                continue;
+                        
+            if (index.at(layer.first).model_slices_idx != SLAPrintObject::SliceRecord::NONE) {
+                for (const ExPolygon& polygon : po->get_model_slices().at(index.at(layer.first).model_slices_idx))
+                    layer_model_area += polygon.area();
+            }
+            /*else */if (index.at(layer.first).support_slices_idx != SLAPrintObject::SliceRecord::NONE) {
+                for (const ExPolygon& polygon : po->get_support_slices().front())
+                    layer_support_area += polygon.area();
+            }
+        }
+        models_volume += layer_model_area * l_height;
+        supports_volume += layer_support_area * l_height;
+
+        // Calculation of the slow and fast layers to the future controlling those values on FW
+
+        const bool is_fast_layer = (layer_model_area + layer_support_area) <= display_area*slow_fast_limit;
+        const double tilt_time = is_fast_layer ? fast_tilt : slow_tilt;
+        if (is_fast_layer)
+            fast_layers++;
+        else
+            slow_layers++;
+
+
+        // Calculation of the printing time
+
+        if (sliced_layer_cnt < 3)
+            estim_time += init_exp_time;
+        else if (fade_layer_time > exp_time)
+        {
+            fade_layer_time -= delta_fade_time;
+            estim_time += fade_layer_time;
+        }
+        else
+            estim_time += exp_time;
+
+        estim_time += tilt_time;
+
+        sliced_layer_cnt++;
+    }
+
+    m_print_statistics.support_used_material = supports_volume * SCALING_FACTOR * SCALING_FACTOR; 
     m_print_statistics.objects_used_material = models_volume  * SCALING_FACTOR * SCALING_FACTOR;
 
     // Estimated printing time
     // A layers count o the highest object 
     if (max_layers_cnt == 0)
         m_print_statistics.estimated_print_time = "N/A";
-    float init_exp_time = m_material_config.initial_exposure_time.getFloat();//35;
-    float exp_time = m_material_config.exposure_time.getFloat();//8;
+    else
+        m_print_statistics.estimated_print_time = get_time_dhms(float(estim_time));
 
-    // TODO : fade_layers_cnt should be filled in the future
-    // This variable will be a part of the print(material) preset
-    const int fade_layers_cnt = 10; // [3;20]
-
-    // TODO : tilt_delay_before_time & tilt_delay_after_time should be filled in the future
-    // These values are received from the printer after a printing start
-    const float tilt_delay_before_time = 0.0;
-    const float tilt_delay_after_time = 0.0;
-    if (tilt_delay_before_time + tilt_delay_after_time > 0.0)
-    {
-        init_exp_time += tilt_delay_before_time + tilt_delay_after_time;
-        exp_time += tilt_delay_before_time + tilt_delay_after_time;
-    }
-
-    float estim_time = init_exp_time * 3 + exp_time * (max_layers_cnt - 3 - fade_layers_cnt);
-
-    const float delta_time = (init_exp_time - exp_time) / (fade_layers_cnt+1);
-    double fade_layer_time = init_exp_time;
-    while (fade_layer_time > exp_time)
-    {
-        fade_layer_time -= delta_time;
-        estim_time += fade_layer_time;
-    }
-
-    m_print_statistics.estimated_print_time = get_time_dhms(estim_time);
+    m_print_statistics.fast_layers_count = fast_layers;
+    m_print_statistics.slow_layers_count = slow_layers;
 }
 
 // Returns true if an object step is done on all objects and there's at least one object.
diff --git a/src/libslic3r/SLAPrint.hpp b/src/libslic3r/SLAPrint.hpp
index f054921c8..ffa451b35 100644
--- a/src/libslic3r/SLAPrint.hpp
+++ b/src/libslic3r/SLAPrint.hpp
@@ -177,6 +177,8 @@ struct SLAPrintStatistics
     std::string                     estimated_print_time;
     double                          objects_used_material;
     double                          support_used_material;
+    size_t                          slow_layers_count;
+    size_t                          fast_layers_count;
     double                          total_cost;
     double                          total_weight;
 
@@ -191,6 +193,8 @@ struct SLAPrintStatistics
         estimated_print_time.clear();
         objects_used_material = 0.;
         support_used_material = 0.;
+        slow_layers_count = 0;
+        fast_layers_count = 0;
         total_cost = 0.;
         total_weight = 0.;
     }
diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp
index f4a3c0b48..fc5f52161 100644
--- a/src/slic3r/GUI/Plater.cpp
+++ b/src/slic3r/GUI/Plater.cpp
@@ -822,16 +822,16 @@ void Sidebar::show_sliced_info_sizer(const bool show)
         if (p->plater->printer_technology() == ptSLA)
         {
             const SLAPrintStatistics& ps = p->plater->sla_print().print_statistics();
-            wxString new_label = _(L("Used Material (mm³)")) + " :";
+            wxString new_label = _(L("Used Material (ml)")) + " :";
             const bool is_supports = ps.support_used_material > 0.0;
             if (is_supports)
                 new_label += wxString::Format("\n    - %s\n    - %s", _(L("object(s)")), _(L("supports and pad")));
 
             wxString info_text = is_supports ?
-                wxString::Format("%.2f \n%.2f \n%.2f", ps.objects_used_material + ps.support_used_material/* / 1000*/,
-                                                       ps.objects_used_material/* / 1000*/,
-                                                       ps.support_used_material/* / 1000*/) :
-                wxString::Format("%.2f", ps.objects_used_material + ps.support_used_material/* / 1000*/);
+                wxString::Format("%.2f \n%.2f \n%.2f", (ps.objects_used_material + ps.support_used_material) / 1000,
+                                                       ps.objects_used_material / 1000,
+                                                       ps.support_used_material / 1000) :
+                wxString::Format("%.2f", ps.objects_used_material + ps.support_used_material / 1000);
             p->sliced_info->SetTextAndShow(siMateril_unit, info_text, new_label);
 
             p->sliced_info->SetTextAndShow(siCost, "N/A"/*wxString::Format("%.2f", ps.total_cost)*/);