<commit_before>// @(#)root/graf:$Id$
// Author: Anna Kreshuk 18/11/2005

/*************************************************************************
 * Copyright (C) 1995-2005, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#include "TGraphQQ.h"
#include "TAxis.h"
#include "TF1.h"
#include "TMath.h"
#include "TVirtualPad.h"
#include "TLine.h"

ClassImp(TGraphQQ)

//______________________________________________________________________________
//
// This class allows to draw quantile-quantile plots
//
// Plots can be drawn for 2 datasets or for a dataset and a theoretical
// distribution function
//
// 2 datasets:
//   Quantile-quantile plots are used to determine whether 2 samples come from
//   the same distribution.
//   A qq-plot draws the quantiles of one dataset against the quantile of the
//   the other. The quantiles of the dataset with fewer entries are on Y axis,
//   with more entries - on X axis.
//   A straight line, going through 0.25 and 0.75 quantiles is also plotted
//   for reference. It represents a robust linear fit, not sensitive to the
//   extremes of the datasets.
//   If the datasets come from the same distribution, points of the plot should
//   fall approximately on the 45 degrees line. If they have the same
//   distribution function, but location or scale different parameters,
//   they should still fall on the straight line, but not the 45 degrees one.
//   The greater their departure from the straight line, the more evidence there
//   is, that the datasets come from different distributions.
//   The advantage of qq-plot is that it not only shows that the underlying
//   distributions are different, but, unlike the analytical methods, it also
//   gives information on the nature of this difference: heavier tails,
//   different location/scale, different shape, etc.
//
//   Some examples of qqplots of 2 datasets:
//Begin_Html
/*

*/
//End_Html
//
// 1 dataset:
//   Quantile-quantile plots are used to determine if the dataset comes from the
//   specified theoretical distribution, such as normal.
//   A qq-plot draws quantiles of the dataset against quantiles of the specified
//   theoretical distribution.
//   (NOTE, that density, not CDF should be specified)
//   A straight line, going through 0.25 and 0.75 quantiles can also be plotted
//   for reference. It represents a robust linear fit, not sensitive to the
//   extremes of the dataset.
//   As in the 2 datasets case, departures from straight line indicate departures
//   from the specified distribution.
//
//   " The correlation coefficient associated with the linear fit to the data
//     in the probability plot (qq plot in our case) is a measure of the
//     goodness of the fit.
//     Estimates of the location and scale parameters  of the distribution
//     are given by the intercept and slope. Probability plots can be generated
//     for several competing distributions to see which provides the best fit,
//     and the probability plot generating the highest correlation coefficient
//     is the best choice since it generates the straightest probability plot."
//   From "Engineering statistic handbook",
//   http://www.itl.nist.gov/div898/handbook/eda/section3/probplot.htm
//
//   Example of a qq-plot of a dataset from N(3, 2) distribution and
//           TMath::Gaus(0, 1) theoretical function. Fitting parameters
//           are estimates of the distribution mean and sigma.
//
//Begin_Html
/*

*/
//End_Html//
//
//
// References:
// http://www.itl.nist.gov/div898/handbook/eda/section3/qqplot.htm
// http://www.itl.nist.gov/div898/handbook/eda/section3/probplot.htm
//

//______________________________________________________________________________
TGraphQQ::TGraphQQ()
{
   //default constructor

   fF   = 0;
   fY0  = 0;
   fNy0 = 0;
   fXq1 = 0.;
   fXq2 = 0.;
   fYq1 = 0.;
   fYq2 = 0.;

}

//______________________________________________________________________________
TGraphQQ::TGraphQQ(Int_t n, Double_t *x)
   : TGraph(n)
{
   //Creates a quantile-quantile plot of dataset x.
   //Theoretical distribution function can be defined later by SetFunction method

   fNy0 = 0;
   fXq1 = 0.;
   fXq2 = 0.;
   fYq1 = 0.;
   fYq2 = 0.;

   Int_t *index = new Int_t[n];
   TMath::Sort(n, x, index, kFALSE);
   for (Int_t i=0; i<fNpoints; i++)
      fY[i] = x[index[i]];
   fF=0;
   fY0=0;
   delete [] index;
}

//______________________________________________________________________________
TGraphQQ::TGraphQQ(Int_t n, Double_t *x, TF1 *f)
   : TGraph(n)
{
   //Creates a quantile-quantile plot of dataset x against function f

   Int_t *index = new Int_t[n];
   TMath::Sort(n, x, index, kFALSE);
   for (Int_t i=0; i<fNpoints; i++)
      fY[i] = x[index[i]];
   delete [] index;
   fF = f;
   fY0=0;
   MakeFunctionQuantiles();
}

//______________________________________________________________________________
TGraphQQ::TGraphQQ(Int_t nx, Double_t *x, Int_t ny, Double_t *y)
{
   //Creates a quantile-quantile plot of dataset x against dataset y
   //Parameters nx and ny are respective array sizes

   nx<=ny ? fNpoints=nx : fNpoints=ny;

   if (!CtorAllocate()) return;
   fF=0;
   Int_t *index = new Int_t[TMath::Max(nx, ny)];
   TMath::Sort(nx, x, index, kFALSE);
   if (nx <=ny){
      for (Int_t i=0; i<fNpoints; i++)
         fY[i] = x[index[i]];
      TMath::Sort(ny, y, index, kFALSE);
      if (nx==ny){
         for (Int_t i=0; i<fNpoints; i++)
            fX[i] = y[index[i]];
         fY0 = 0;
         Quartiles();
      } else {
         fNy0 = ny;
         fY0 = new Double_t[ny];
         for (Int_t i=0; i<ny; i++)
            fY0[i] = y[i];
         MakeQuantiles();
      }
   } else {
      fNy0 = nx;
      fY0 = new Double_t[nx];
      for (Int_t i=0; i<nx; i++)
         fY0[i] = x[index[i]];
      TMath::Sort(ny, y, index, kFALSE);
      for (Int_t i=0; i<ny; i++)
         fY[i] = y[index[i]];
      MakeQuantiles();
   }

   delete [] index;
}

//______________________________________________________________________________
TGraphQQ::~TGraphQQ()
{
   //Destroys a TGraphQQ

   if (fY0)
      delete [] fY0;
   if (fF)
      fF = 0;
}

//______________________________________________________________________________
void TGraphQQ::MakeFunctionQuantiles()
{
   //Computes quantiles of theoretical distribution function

   if (!fF) return;
   TString s = fF->GetTitle();
   Double_t pk;
   if (s.Contains("TMath::Gaus") || s.Contains("gaus")){
      //use plotting positions optimal for normal distribution
      for (Int_t k=1; k<=fNpoints; k++){
         pk = (k-0.375)/(fNpoints+0.25);
         fX[k-1]=TMath::NormQuantile(pk);
      }
   } else {
      Double_t *prob = new Double_t[fNpoints];
      if (fNpoints > 10){
         for (Int_t k=1; k<=fNpoints; k++)
            prob[k-1] = (k-0.5)/fNpoints;
      } else {
         for (Int_t k=1; k<=fNpoints; k++)
            prob[k-1] = (k-0.375)/(fNpoints+0.25);
      }
      //fF->GetQuantiles(fNpoints, prob, fX);
      fF->GetQuantiles(fNpoints, fX, prob);
      delete [] prob;
   }

   Quartiles();
}

//______________________________________________________________________________

void TGraphQQ::MakeQuantiles()
{
   //When sample sizes are not equal, computes quantiles of the bigger sample
   //by linear interpolation

   if (!fY0) return;

   Double_t pi, pfrac;
   Int_t pint;
   for (Int_t i=0; i<fNpoints-1; i++){
      pi = (fNy0-1)*Double_t(i)/Double_t(fNpoints-1);
      pint = TMath::FloorNint(pi);
      pfrac = pi - pint;
      fX[i] = (1-pfrac)*fY0[pint]+pfrac*fY0[pint+1];
   }
   fX[fNpoints-1]=fY0[fNy0-1];

   Quartiles();
}

//______________________________________________________________________________
void TGraphQQ::Quartiles()
{
   // compute quartiles
   // a quartile is a 25 per cent or 75 per cent quantile

   Double_t prob[]={0.25, 0.75};
   Double_t x[2];
   Double_t y[2];
   TMath::Quantiles(fNpoints, 2, fY, y, prob, kTRUE);
   if (fY0)
      TMath::Quantiles(fNy0, 2, fY0, x, prob, kTRUE);
   else if (fF) {
      TString s = fF->GetTitle();
      if (s.Contains("TMath::Gaus") || s.Contains("gaus")){
         x[0] = TMath::NormQuantile(0.25);
         x[1] = TMath::NormQuantile(0.75);
      } else
         fF->GetQuantiles(2, x, prob);
   }
   else
      TMath::Quantiles(fNpoints, 2, fX, x, prob, kTRUE);

   fXq1=x[0]; fXq2=x[1]; fYq1=y[0]; fYq2=y[1];
}

//______________________________________________________________________________
void TGraphQQ::SetFunction(TF1 *f)
{
   //Sets the theoretical distribution function (density!)
   //and computes its quantiles

   fF = f;
   MakeFunctionQuantiles();
}
<commit_msg>- Initiliaze members (coverity)<commit_after>// @(#)root/graf:$Id$
// Author: Anna Kreshuk 18/11/2005

/*************************************************************************
 * Copyright (C) 1995-2005, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#include "TGraphQQ.h"
#include "TAxis.h"
#include "TF1.h"
#include "TMath.h"
#include "TVirtualPad.h"
#include "TLine.h"

ClassImp(TGraphQQ)

//______________________________________________________________________________
//
// This class allows to draw quantile-quantile plots
//
// Plots can be drawn for 2 datasets or for a dataset and a theoretical
// distribution function
//
// 2 datasets:
//   Quantile-quantile plots are used to determine whether 2 samples come from
//   the same distribution.
//   A qq-plot draws the quantiles of one dataset against the quantile of the
//   the other. The quantiles of the dataset with fewer entries are on Y axis,
//   with more entries - on X axis.
//   A straight line, going through 0.25 and 0.75 quantiles is also plotted
//   for reference. It represents a robust linear fit, not sensitive to the
//   extremes of the datasets.
//   If the datasets come from the same distribution, points of the plot should
//   fall approximately on the 45 degrees line. If they have the same
//   distribution function, but location or scale different parameters,
//   they should still fall on the straight line, but not the 45 degrees one.
//   The greater their departure from the straight line, the more evidence there
//   is, that the datasets come from different distributions.
//   The advantage of qq-plot is that it not only shows that the underlying
//   distributions are different, but, unlike the analytical methods, it also
//   gives information on the nature of this difference: heavier tails,
//   different location/scale, different shape, etc.
//
//   Some examples of qqplots of 2 datasets:
//Begin_Html
/*

*/
//End_Html
//
// 1 dataset:
//   Quantile-quantile plots are used to determine if the dataset comes from the
//   specified theoretical distribution, such as normal.
//   A qq-plot draws quantiles of the dataset against quantiles of the specified
//   theoretical distribution.
//   (NOTE, that density, not CDF should be specified)
//   A straight line, going through 0.25 and 0.75 quantiles can also be plotted
//   for reference. It represents a robust linear fit, not sensitive to the
//   extremes of the dataset.
//   As in the 2 datasets case, departures from straight line indicate departures
//   from the specified distribution.
//
//   " The correlation coefficient associated with the linear fit to the data
//     in the probability plot (qq plot in our case) is a measure of the
//     goodness of the fit.
//     Estimates of the location and scale parameters  of the distribution
//     are given by the intercept and slope. Probability plots can be generated
//     for several competing distributions to see which provides the best fit,
//     and the probability plot generating the highest correlation coefficient
//     is the best choice since it generates the straightest probability plot."
//   From "Engineering statistic handbook",
//   http://www.itl.nist.gov/div898/handbook/eda/section3/probplot.htm
//
//   Example of a qq-plot of a dataset from N(3, 2) distribution and
//           TMath::Gaus(0, 1) theoretical function. Fitting parameters
//           are estimates of the distribution mean and sigma.
//
//Begin_Html
/*

*/
//End_Html//
//
//
// References:
// http://www.itl.nist.gov/div898/handbook/eda/section3/qqplot.htm
// http://www.itl.nist.gov/div898/handbook/eda/section3/probplot.htm
//

//______________________________________________________________________________
TGraphQQ::TGraphQQ()
{
   //default constructor

   fF   = 0;
   fY0  = 0;
   fNy0 = 0;
   fXq1 = 0.;
   fXq2 = 0.;
   fYq1 = 0.;
   fYq2 = 0.;

}

//______________________________________________________________________________
TGraphQQ::TGraphQQ(Int_t n, Double_t *x)
   : TGraph(n)
{
   //Creates a quantile-quantile plot of dataset x.
   //Theoretical distribution function can be defined later by SetFunction method

   fNy0 = 0;
   fXq1 = 0.;
   fXq2 = 0.;
   fYq1 = 0.;
   fYq2 = 0.;

   Int_t *index = new Int_t[n];
   TMath::Sort(n, x, index, kFALSE);
   for (Int_t i=0; i<fNpoints; i++)
      fY[i] = x[index[i]];
   fF=0;
   fY0=0;
   delete [] index;
}

//______________________________________________________________________________
TGraphQQ::TGraphQQ(Int_t n, Double_t *x, TF1 *f)
   : TGraph(n)
{
   //Creates a quantile-quantile plot of dataset x against function f

   fNy0 = 0;

   Int_t *index = new Int_t[n];
   TMath::Sort(n, x, index, kFALSE);
   for (Int_t i=0; i<fNpoints; i++)
      fY[i] = x[index[i]];
   delete [] index;
   fF = f;
   fY0=0;
   MakeFunctionQuantiles();
}

//______________________________________________________________________________
TGraphQQ::TGraphQQ(Int_t nx, Double_t *x, Int_t ny, Double_t *y)
{
   //Creates a quantile-quantile plot of dataset x against dataset y
   //Parameters nx and ny are respective array sizes

   fNy0 = 0;
   fXq1 = 0.;
   fXq2 = 0.;
   fYq1 = 0.;
   fYq2 = 0.;

   nx<=ny ? fNpoints=nx : fNpoints=ny;

   if (!CtorAllocate()) return;
   fF=0;
   Int_t *index = new Int_t[TMath::Max(nx, ny)];
   TMath::Sort(nx, x, index, kFALSE);
   if (nx <=ny){
      for (Int_t i=0; i<fNpoints; i++)
         fY[i] = x[index[i]];
      TMath::Sort(ny, y, index, kFALSE);
      if (nx==ny){
         for (Int_t i=0; i<fNpoints; i++)
            fX[i] = y[index[i]];
         fY0 = 0;
         Quartiles();
      } else {
         fNy0 = ny;
         fY0 = new Double_t[ny];
         for (Int_t i=0; i<ny; i++)
            fY0[i] = y[i];
         MakeQuantiles();
      }
   } else {
      fNy0 = nx;
      fY0 = new Double_t[nx];
      for (Int_t i=0; i<nx; i++)
         fY0[i] = x[index[i]];
      TMath::Sort(ny, y, index, kFALSE);
      for (Int_t i=0; i<ny; i++)
         fY[i] = y[index[i]];
      MakeQuantiles();
   }

   delete [] index;
}

//______________________________________________________________________________
TGraphQQ::~TGraphQQ()
{
   //Destroys a TGraphQQ

   if (fY0)
      delete [] fY0;
   if (fF)
      fF = 0;
}

//______________________________________________________________________________
void TGraphQQ::MakeFunctionQuantiles()
{
   //Computes quantiles of theoretical distribution function

   if (!fF) return;
   TString s = fF->GetTitle();
   Double_t pk;
   if (s.Contains("TMath::Gaus") || s.Contains("gaus")){
      //use plotting positions optimal for normal distribution
      for (Int_t k=1; k<=fNpoints; k++){
         pk = (k-0.375)/(fNpoints+0.25);
         fX[k-1]=TMath::NormQuantile(pk);
      }
   } else {
      Double_t *prob = new Double_t[fNpoints];
      if (fNpoints > 10){
         for (Int_t k=1; k<=fNpoints; k++)
            prob[k-1] = (k-0.5)/fNpoints;
      } else {
         for (Int_t k=1; k<=fNpoints; k++)
            prob[k-1] = (k-0.375)/(fNpoints+0.25);
      }
      //fF->GetQuantiles(fNpoints, prob, fX);
      fF->GetQuantiles(fNpoints, fX, prob);
      delete [] prob;
   }

   Quartiles();
}

//______________________________________________________________________________

void TGraphQQ::MakeQuantiles()
{
   //When sample sizes are not equal, computes quantiles of the bigger sample
   //by linear interpolation

   if (!fY0) return;

   Double_t pi, pfrac;
   Int_t pint;
   for (Int_t i=0; i<fNpoints-1; i++){
      pi = (fNy0-1)*Double_t(i)/Double_t(fNpoints-1);
      pint = TMath::FloorNint(pi);
      pfrac = pi - pint;
      fX[i] = (1-pfrac)*fY0[pint]+pfrac*fY0[pint+1];
   }
   fX[fNpoints-1]=fY0[fNy0-1];

   Quartiles();
}

//______________________________________________________________________________
void TGraphQQ::Quartiles()
{
   // compute quartiles
   // a quartile is a 25 per cent or 75 per cent quantile

   Double_t prob[]={0.25, 0.75};
   Double_t x[2];
   Double_t y[2];
   TMath::Quantiles(fNpoints, 2, fY, y, prob, kTRUE);
   if (fY0)
      TMath::Quantiles(fNy0, 2, fY0, x, prob, kTRUE);
   else if (fF) {
      TString s = fF->GetTitle();
      if (s.Contains("TMath::Gaus") || s.Contains("gaus")){
         x[0] = TMath::NormQuantile(0.25);
         x[1] = TMath::NormQuantile(0.75);
      } else
         fF->GetQuantiles(2, x, prob);
   }
   else
      TMath::Quantiles(fNpoints, 2, fX, x, prob, kTRUE);

   fXq1=x[0]; fXq2=x[1]; fYq1=y[0]; fYq2=y[1];
}

//______________________________________________________________________________
void TGraphQQ::SetFunction(TF1 *f)
{
   //Sets the theoretical distribution function (density!)
   //and computes its quantiles

   fF = f;
   MakeFunctionQuantiles();
}
<|endoftext|>


<commit_before>#ifndef PRESETEDITOR_HPP
#define PRESETEDITOR_HPP

// stdlib
#include <string>
#include <functional>

// Libslic3r
#include "libslic3r.h"
#include "ConfigBase.hpp"
#include "Config.hpp"

// GUI
#include "misc_ui.hpp"

// Wx
#include <wx/treectrl.h>
#include <wx/imaglist.h>
#include <wx/panel.h>

#if SLIC3R_CPPVER==11
    #define st(A) (std::string(#A))
#elif SLIC3R_CPPVER==14
    #define st(A) ((#A)s)
#endif

// TODO for C++14 find/replace st([A-z_]*) with "\1"s

namespace Slic3r { namespace GUI {

class PresetEditor : public wxPanel {

public:
    /// Member function to retrieve a list of options
    /// that this preset governs. Subclasses should
    /// call their own static method.
    virtual t_config_option_keys my_options() = 0;
    static t_config_option_keys options() { return t_config_option_keys {}; }

    wxSizer* sizer() { return _sizer; };
    PresetEditor(wxWindow* parent, t_config_option_keys options = {});
    PresetEditor() : PresetEditor(nullptr, {}) {};

    bool prompt_unsaved_changes();
    void select_preset_by_name(const wxString& name, bool force = false);

    /// suppress the callback when the tree selection is changed.
    bool disable_tree_sel_changed_event {false};

    void save_preset();
    std::function<void ()> on_save_preset {};
    std::function<void ()> on_value_change {};

    config_ptr config;

    virtual wxString title() = 0;
    virtual std::string name() = 0;
protected:
    // Main sizer
    wxSizer* _sizer {nullptr};
    wxString presets;
    wxImageList* _icons {nullptr};
    wxTreeCtrl* _treectrl {nullptr};
    wxBitmapButton* _btn_save_preset {nullptr};
    wxBitmapButton* _btn_delete_preset {nullptr};
    wxChoice* _presets_choice {nullptr};
    int _iconcount {-1};

    std::vector<wxString> _pages {};

    const unsigned int left_col_width {150};
    void _update_tree();
    void load_presets();

    virtual void _build() = 0;
    virtual void _update() = 0;
    virtual void _on_preset_loaded() = 0;
    void set_tooltips() {
        this->_btn_save_preset->SetToolTip(wxString(_("Save current ")) + this->title());
        this->_btn_delete_preset->SetToolTip(_("Delete this preset."));
    }
};

class PrintEditor : public PresetEditor {
public:

    PrintEditor(wxWindow* parent, t_config_option_keys options = {});
    PrintEditor() : PrintEditor(nullptr, {}) {};

    wxString title() override { return _("Print Settings"); }
    std::string name() override { return st("print"); }

    /// Static method to retrieve list of options that this preset governs.
    static t_config_option_keys options() {
        return t_config_option_keys
        {
            st(layer_height), st(first_layer_height),
            st(adaptive_slicing), st(adaptive_slicing_quality), st(match_horizontal_surfaces),
            st(perimeters), st(spiral_vase),
            st(top_solid_layers), st(bottom_solid_layers),
            st(extra_perimeters), st(avoid_crossing_perimeters), st(thin_walls), st(overhangs),
            st(seam_position), st(external_perimeters_first),
            st(fill_density), st(fill_pattern), st(top_infill_pattern), st(bottom_infill_pattern), st(fill_gaps),
            st(infill_every_layers), st(infill_only_where_needed),
            st(solid_infill_every_layers), st(fill_angle), st(solid_infill_below_area), st(),
            st(only_retract_when_crossing_perimeters), st(infill_first),
            st(max_print_speed), st(max_volumetric_speed),
            st(perimeter_speed), st(small_perimeter_speed), st(external_perimeter_speed), st(infill_speed), st(),
            st(solid_infill_speed), st(top_solid_infill_speed), st(support_material_speed),
            st(support_material_interface_speed), st(bridge_speed), st(gap_fill_speed),
            st(travel_speed),
            st(first_layer_speed),
            st(perimeter_acceleration), st(infill_acceleration), st(bridge_acceleration),
            st(first_layer_acceleration), st(default_acceleration),
            st(skirts), st(skirt_distance), st(skirt_height), st(min_skirt_length),
            st(brim_connections_width), st(brim_width), st(interior_brim_width),
            st(support_material), st(support_material_threshold), st(support_material_max_layers), st(support_material_enforce_layers),
            st(raft_layers),
            st(support_material_pattern), st(support_material_spacing), st(support_material_angle), st(),
            st(support_material_interface_layers), st(support_material_interface_spacing),
            st(support_material_contact_distance), st(support_material_buildplate_only), st(dont_support_bridges),
            st(notes),
            st(complete_objects), st(extruder_clearance_radius), st(extruder_clearance_height),
            st(gcode_comments), st(output_filename_format),
            st(post_process),
            st(perimeter_extruder), st(infill_extruder), st(solid_infill_extruder),
            st(support_material_extruder), st(support_material_interface_extruder),
            st(ooze_prevention), st(standby_temperature_delta),
            st(interface_shells), st(regions_overlap),
            st(extrusion_width), st(first_layer_extrusion_width), st(perimeter_extrusion_width), st(),
            st(external_perimeter_extrusion_width), st(infill_extrusion_width), st(solid_infill_extrusion_width),
            st(top_infill_extrusion_width), st(support_material_extrusion_width),
            st(support_material_interface_extrusion_width), st(infill_overlap), st(bridge_flow_ratio),
            st(xy_size_compensation), st(resolution), st(shortcuts), st(compatible_printers),
            st(print_settings_id)
        };
    }

    t_config_option_keys my_options() override { return PrintEditor::options(); }

protected:
    void _update() override;
    void _build() override;
};

class MaterialEditor : public PresetEditor {
public:

    wxString title() override { return _("Material Settings"); }
    std::string name() override { return st("material"); }
    MaterialEditor(wxWindow* parent, t_config_option_keys options = {});
    MaterialEditor() : MaterialEditor(nullptr, {}) {};

    static t_config_option_keys options() {
        return t_config_option_keys
        {
            st(filament_colour), st(filament_diameter), st(filament_notes), st(filament_max_volumetric_speed), st(extrusion_multiplier), st(filament_density), st(filament_cost),
            st(temperature), st(first_layer_temperature), st(bed_temperature), st(first_layer_bed_temperature),
            st(fan_always_on), st(cooling), st(compatible_printers),
            st(min_fan_speed), st(max_fan_speed), st(bridge_fan_speed), st(disable_fan_first_layers),
            st(fan_below_layer_time), st(slowdown_below_layer_time), st(min_print_speed),
            st(start_filament_gcode), st(end_filament_gcode),
            st(filament_settings_id)
        };
    }

    t_config_option_keys my_options() override { return MaterialEditor::options(); }
protected:
    void _update() override;
    void _build() override;
};

class PrinterEditor : public PresetEditor {
public:
    PrinterEditor(wxWindow* parent, t_config_option_keys options = {});
    PrinterEditor() : PrinterEditor(nullptr, {}) {};

    wxString title() override { return _("Printer Settings"); }
    std::string name() override { return st("printer"); }

    static t_config_option_keys options() {
        return t_config_option_keys
        {
            st(bed_shape), st(z_offset), st(z_steps_per_mm), st(has_heatbed),
            st(gcode_flavor), st(use_relative_e_distances),
            st(serial_port), st(serial_speed),
            st(host_type), st(print_host), st(octoprint_apikey),
            st(use_firmware_retraction), st(pressure_advance), st(vibration_limit),
            st(use_volumetric_e),
            st(start_gcode), st(end_gcode), st(before_layer_gcode), st(layer_gcode), st(toolchange_gcode), st(between_objects_gcode),
            st(nozzle_diameter), st(extruder_offset), st(min_layer_height), st(max_layer_height),
            st(retract_length), st(retract_lift), st(retract_speed), st(retract_restart_extra), st(retract_before_travel), st(retract_layer_change), st(wipe),
            st(retract_length_toolchange), st(retract_restart_extra_toolchange), st(retract_lift_above), st(retract_lift_below),
            st(printer_settings_id),
            st(printer_notes),
            st(use_set_and_wait_bed), st(use_set_and_wait_extruder)
        };
    }

    t_config_option_keys my_options() override { return PrinterEditor::options(); }
protected:
    void _update() override;
    void _build() override;
};

}} // namespace Slic3r::GUI
#endif // PRESETEDITOR_HPP
<commit_msg>Moved to C++14 syntax with string literals.<commit_after>#ifndef PRESETEDITOR_HPP
#define PRESETEDITOR_HPP

// stdlib
#include <string>
#include <functional>

// Libslic3r
#include "libslic3r.h"
#include "ConfigBase.hpp"
#include "Config.hpp"

// GUI
#include "misc_ui.hpp"

// Wx
#include <wx/treectrl.h>
#include <wx/imaglist.h>
#include <wx/panel.h>

using namespace std::string_literals;
namespace Slic3r { namespace GUI {

class PresetEditor : public wxPanel {

public:
    /// Member function to retrieve a list of options
    /// that this preset governs. Subclasses should
    /// call their own static method.
    virtual t_config_option_keys my_options() = 0;
    static t_config_option_keys options() { return t_config_option_keys {}; }

    wxSizer* sizer() { return _sizer; };
    PresetEditor(wxWindow* parent, t_config_option_keys options = {});
    PresetEditor() : PresetEditor(nullptr, {}) {};

    bool prompt_unsaved_changes();
    void select_preset_by_name(const wxString& name, bool force = false);

    /// suppress the callback when the tree selection is changed.
    bool disable_tree_sel_changed_event {false};

    void save_preset();
    std::function<void ()> on_save_preset {};
    std::function<void ()> on_value_change {};

    config_ptr config;

    virtual wxString title() = 0;
    virtual std::string name() = 0;
protected:
    // Main sizer
    wxSizer* _sizer {nullptr};
    wxString presets;
    wxImageList* _icons {nullptr};
    wxTreeCtrl* _treectrl {nullptr};
    wxBitmapButton* _btn_save_preset {nullptr};
    wxBitmapButton* _btn_delete_preset {nullptr};
    wxChoice* _presets_choice {nullptr};
    int _iconcount {-1};

    std::vector<wxString> _pages {};

    const unsigned int left_col_width {150};
    void _update_tree();
    void load_presets();

    virtual void _build() = 0;
    virtual void _update() = 0;
    virtual void _on_preset_loaded() = 0;
    void set_tooltips() {
        this->_btn_save_preset->SetToolTip(wxString(_("Save current ")) + this->title());
        this->_btn_delete_preset->SetToolTip(_("Delete this preset."));
    }
};

class PrintEditor : public PresetEditor {
public:

    PrintEditor(wxWindow* parent, t_config_option_keys options = {});
    PrintEditor() : PrintEditor(nullptr, {}) {};

    wxString title() override { return _("Print Settings"); }
    std::string name() override { return "print"s; }

    /// Static method to retrieve list of options that this preset governs.
    static t_config_option_keys options() {
        return t_config_option_keys
        {
            "layer_height"s, "first_layer_height"s,
            "adaptive_slicing"s, "adaptive_slicing_quality"s, "match_horizontal_surfaces"s,
            "perimeters"s, "spiral_vase"s,
            "top_solid_layers"s, "bottom_solid_layers"s,
            "extra_perimeters"s, "avoid_crossing_perimeters"s, "thin_walls"s, "overhangs"s,
            "seam_position"s, "external_perimeters_first"s,
            "fill_density"s, "fill_pattern"s, "top_infill_pattern"s, "bottom_infill_pattern"s, "fill_gaps"s,
            "infill_every_layers"s, "infill_only_where_needed"s,
            "solid_infill_every_layers"s, "fill_angle"s, "solid_infill_below_area"s, ""s,
            "only_retract_when_crossing_perimeters"s, "infill_first"s,
            "max_print_speed"s, "max_volumetric_speed"s,
            "perimeter_speed"s, "small_perimeter_speed"s, "external_perimeter_speed"s, "infill_speed"s, ""s,
            "solid_infill_speed"s, "top_solid_infill_speed"s, "support_material_speed"s,
            "support_material_interface_speed"s, "bridge_speed"s, "gap_fill_speed"s,
            "travel_speed"s,
            "first_layer_speed"s,
            "perimeter_acceleration"s, "infill_acceleration"s, "bridge_acceleration"s,
            "first_layer_acceleration"s, "default_acceleration"s,
            "skirts"s, "skirt_distance"s, "skirt_height"s, "min_skirt_length"s,
            "brim_connections_width"s, "brim_width"s, "interior_brim_width"s,
            "support_material"s, "support_material_threshold"s, "support_material_max_layers"s, "support_material_enforce_layers"s,
            "raft_layers"s,
            "support_material_pattern"s, "support_material_spacing"s, "support_material_angle"s, ""s,
            "support_material_interface_layers"s, "support_material_interface_spacing"s,
            "support_material_contact_distance"s, "support_material_buildplate_only"s, "dont_support_bridges"s,
            "notes"s,
            "complete_objects"s, "extruder_clearance_radius"s, "extruder_clearance_height"s,
            "gcode_comments"s, "output_filename_format"s,
            "post_process"s,
            "perimeter_extruder"s, "infill_extruder"s, "solid_infill_extruder"s,
            "support_material_extruder"s, "support_material_interface_extruder"s,
            "ooze_prevention"s, "standby_temperature_delta"s,
            "interface_shells"s, "regions_overlap"s,
            "extrusion_width"s, "first_layer_extrusion_width"s, "perimeter_extrusion_width"s, ""s,
            "external_perimeter_extrusion_width"s, "infill_extrusion_width"s, "solid_infill_extrusion_width"s,
            "top_infill_extrusion_width"s, "support_material_extrusion_width"s,
            "support_material_interface_extrusion_width"s, "infill_overlap"s, "bridge_flow_ratio"s,
            "xy_size_compensation"s, "resolution"s, "shortcuts"s, "compatible_printers"s,
            "print_settings_id"s
        };
    }

    t_config_option_keys my_options() override { return PrintEditor::options(); }

protected:
    void _update() override;
    void _build() override;
};

class PrinterEditor : public PresetEditor {
public:
    PrinterEditor(wxWindow* parent, t_config_option_keys options = {});
    PrinterEditor() : PrinterEditor(nullptr, {}) {};

    wxString title() override { return _("Printer Settings"); }
    std::string name() override { return "printer"s; }
    static t_config_option_keys overridable_options() { return t_config_option_keys
    {
        "pressure_advance"s,
        "retract_length"s, "retract_lift"s, "retract_speed"s, "retract_restart_extra"s,
        "retract_before_travel"s, "retract_layer_change"s, "wipe"s
    }; };

    static t_config_option_keys options() {
        return t_config_option_keys
        {
            "bed_shape"s, "z_offset"s, "z_steps_per_mm"s, "has_heatbed"s,
            "gcode_flavor"s, "use_relative_e_distances"s,
            "serial_port"s, "serial_speed"s,
            "host_type"s, "print_host"s, "octoprint_apikey"s,
            "use_firmware_retraction"s, "pressure_advance"s, "vibration_limit"s,
            "use_volumetric_e"s,
            "start_gcode"s, "end_gcode"s, "before_layer_gcode"s, "layer_gcode"s, "toolchange_gcode"s, "between_objects_gcode"s,
            "nozzle_diameter"s, "extruder_offset"s, "min_layer_height"s, "max_layer_height"s,
            "retract_length"s, "retract_lift"s, "retract_speed"s, "retract_restart_extra"s, "retract_before_travel"s, "retract_layer_change"s, "wipe"s,
            "retract_length_toolchange"s, "retract_restart_extra_toolchange"s, "retract_lift_above"s, "retract_lift_below"s,
            "printer_settings_id"s,
            "printer_notes"s,
            "use_set_and_wait_bed"s, "use_set_and_wait_extruder"s
        };
    }

    t_config_option_keys my_options() override { return PrinterEditor::options(); }
protected:
    void _update() override;
    void _build() override;
    const std::string LogChannel() override {return "PrinterEditor"s;} //< Which log these messages should go to.
};

class MaterialEditor : public PresetEditor {
public:

    wxString title() override { return _("Material Settings"); }
    std::string name() override { return "material"s; }
    preset_t type() override  { return preset_t::Material; };
    int typeId() override  { return static_cast<int>(preset_t::Material); };
    MaterialEditor(wxWindow* parent, t_config_option_keys options = {});
    MaterialEditor() : MaterialEditor(nullptr, {}) {};

    static t_config_option_keys options() {
        return t_config_option_keys
        {
            "filament_colour"s, "filament_diameter"s, "filament_notes"s, "filament_max_volumetric_speed"s, "extrusion_multiplier"s, "filament_density"s, "filament_cost"s,
            "temperature"s, "first_layer_temperature"s, "bed_temperature"s, "first_layer_bed_temperature"s,
            "fan_always_on"s, "cooling"s, "compatible_printers"s,
            "min_fan_speed"s, "max_fan_speed"s, "bridge_fan_speed"s, "disable_fan_first_layers"s,
            "fan_below_layer_time"s, "slowdown_below_layer_time"s, "min_print_speed"s,
            "start_filament_gcode"s, "end_filament_gcode"s,
            "filament_settings_id"s
        };
    }

    t_config_option_keys my_options() override { return MaterialEditor::options(); }
protected:
    void _update() override;
    void _build() override;
    const std::string LogChannel() override {return "MaterialEditor"s;} //< Which log these messages should go to.
};

}} // namespace Slic3r::GUI
#endif // PRESETEDITOR_HPP
<|endoftext|>


<commit_before>#include "PresetChooser.hpp"
#include "misc_ui.hpp"

namespace Slic3r { namespace GUI {

PresetChooser::PresetChooser(wxWindow* parent, std::weak_ptr<Print> print) : PresetChooser(parent, print, SLIC3RAPP->settings(), SLIC3RAPP->presets) {}

PresetChooser::PresetChooser(wxWindow* parent, std::weak_ptr<Print> print, Settings* external_settings, preset_store& external_presets) :
    wxPanel(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL, ""),
    _local_sizer(new wxFlexGridSizer(3,3,1,2)), _parent(parent), _settings(external_settings), _print(print), _presets(external_presets)
{
    _local_sizer->AddGrowableCol(1, 1);
    _local_sizer->SetFlexibleDirection(wxHORIZONTAL);

    for (auto group : { preset_t::Print, preset_t::Material, preset_t::Printer }) {
        wxString name = "";
        switch(group) {
            case preset_t::Print:
                name << _("Print settings:");
                break;
            case preset_t::Material:
                name << _("Material:");
                break;
            case preset_t::Printer:
                name << _("Printer:");
                break;
            default:
                break;
        }
        auto* text {new wxStaticText(this, wxID_ANY, name, wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT)};
        text->SetFont(_settings->small_font());

        auto* choice {new wxBitmapComboBox(this, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, 0, nullptr, wxCB_READONLY)};
        this->preset_choosers[get_preset(group)].push_back(choice);

        // Settings button
        auto* settings_btn {new wxBitmapButton(this, wxID_ANY, wxBitmap(var("cog.png"), wxBITMAP_TYPE_PNG), wxDefaultPosition, wxDefaultSize, wxBORDER_NONE)};

        this->_local_sizer->Add(text, 0, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL | wxRIGHT, 4);
        this->_local_sizer->Add(choice, 1, wxALIGN_CENTER_VERTICAL | wxEXPAND | wxBOTTOM, 0);
        this->_local_sizer->Add(settings_btn, 0, wxALIGN_CENTER_VERTICAL | wxEXPAND | wxLEFT, 3);

        // setup listener.
        // On a combobox event, puts a call to _on_change_combobox() on the evt_idle stack.
        choice->Bind(wxEVT_COMBOBOX,
            [=](wxCommandEvent& e) {
                wxTheApp->CallAfter([=]() { this->_on_change_combobox(group, choice);} );
            });
    }

    this->SetSizer(_local_sizer);
}

void PresetChooser::load(std::array<Presets, preset_types> presets) {

    wxString selected_printer_name {""};
    for (const auto& group : { preset_t::Printer, preset_t::Material, preset_t::Print }) {
        auto current_list = presets.at(get_preset(group));
        // Filter out profiles not compatible with this printer
        if (group != preset_t::Printer) {
            current_list = grep(presets.at(get_preset(group)), [selected_printer_name] (const Preset& x) -> bool { return x.compatible(selected_printer_name); });
        }

        // show default names if no other presets visible.
        if (current_list.size() > 1) {
            current_list = grep(presets.at(get_preset(group)), [] (const Preset& x) -> bool { return !x.default_preset; });
        }

        // # Read the current defaults from the settings file
        const auto& settings_defaults {_settings->default_presets.at(get_preset(group))};

        size_t i {0};
        std::vector<std::string> preset_names {};
        __chooser_names[get_preset(group)].clear();
        // populate the chooser
        for (auto* chooser : this->preset_choosers[get_preset(group)]) {
            chooser->Clear();
            assert(chooser->GetCount() == 0);
            for (auto preset : current_list) {
                wxBitmap bitmap;
                switch (group) {
                    case preset_t::Print:
                        bitmap = wxBitmap(var("cog.png"), wxBITMAP_TYPE_PNG);
                        break;
                    case preset_t::Material:
                        if (auto config =  preset.config().lock()) {
                            if (preset.default_preset || !config->has("filament_colour"))
                                bitmap = wxBitmap(var("spool.png"), wxBITMAP_TYPE_PNG);
                        } else { // fall back if for some reason the config is dead.
                            bitmap = wxBitmap(var("spool.png"), wxBITMAP_TYPE_PNG);
                        }
                        break;
                    case preset_t::Printer:
                        bitmap = wxBitmap(var("printer_empty.png"), wxBITMAP_TYPE_PNG);
                        break;
                    default: break;
                }
                chooser->Append(preset.name, bitmap);
                __chooser_names[get_preset(group)].push_back(preset.name);
            }
            assert(chooser->GetCount() == current_list.size());

            // Apply default options from settings
            bool updated_from_settings = false;
            if (settings_defaults.size() > i) { // only apply if there is a value from Settings
                updated_from_settings = this->select_preset_by_name(settings_defaults.at(i), chooser);
            }

            if (!updated_from_settings) // default
                chooser->SetSelection(0);

            wxString selected_preset { chooser->GetString(chooser->GetSelection()) };
            if (group == preset_t::Printer) {
                selected_printer_name = selected_preset;
            }

            ++i;
        }
        this->_update_preset_settings(group);
    }
}

bool PresetChooser::select_preset_by_name(wxString name, preset_t group, size_t index = 0) {
    auto& ps_list = this->preset_choosers.at(get_preset(group));
    bool updated = false;
    if (ps_list.size() > index) {
        updated = select_preset_by_name(name, ps_list.at(index));
    }
    if (updated)
        this->_on_select_preset(group);
    return updated;
}

bool PresetChooser::select_preset_by_name(wxString name, wxBitmapComboBox* chooser) {
    auto index { chooser->FindString(name) };
    if (index != wxNOT_FOUND) {
        chooser->SetSelection(index);
        return true;
    }
    return false;
}

void PresetChooser::_update_preset_settings(preset_t preset) {
    auto& settings_presets {_settings->default_presets.at(get_preset(preset))};
    settings_presets.clear(); // make sure previous contents are deconstructed
    settings_presets = this->_get_selected_presets(preset);

}

void PresetChooser::_on_select_preset(preset_t preset) {
    // update settings store
    this->_update_preset_settings(preset);
    // save settings
    _settings->save_settings();
    if (preset == preset_t::Printer) {
        this->load(); // reload print/filament settings to honor compatible printers
    }
}

bool PresetChooser::prompt_unsaved_changes() {
    return true;
}

std::vector<wxString> PresetChooser::_get_selected_presets(preset_t group) const {
        const auto& choosers { this->preset_choosers[get_preset(group)] };
        std::vector<wxString> selected;
        selected.reserve(choosers.size());

        for (auto* chooser :  choosers) {
            selected.push_back(chooser->GetString(chooser->GetSelection()));
        }
        return selected;
}

wxString PresetChooser::_get_selected_preset(preset_t group, size_t index) const {
    auto selected { this->_get_selected_presets(group) };
    if (index > selected.size()) { return wxString(""); }
    return selected.at(index);
}
void PresetChooser::_on_change_combobox(preset_t preset, wxBitmapComboBox* choice) {

    // Prompt for unsaved changes and undo selections if cancelled and return early
    // Callback to close preset editor tab, close editor tabs, reload presets.
    //
    if (!this->prompt_unsaved_changes()) return;
    wxTheApp->CallAfter([this,preset]()
    {
        this->_on_select_preset(preset);
        // reload presets; removes the modified mark
        this->load();
    });
    /*
    sub _on_change_combobox {
    my ($self, $group, $choice) = @_;

    if (0) {
        # This code is disabled because wxPerl doesn't provide GetCurrentSelection
        my $current_name = $self->{preset_choosers_names}{$choice}[$choice->GetCurrentSelection];
        my $current = first { $_->name eq $current_name } @{wxTheApp->presets->{$group}};
        if (!$current->prompt_unsaved_changes($self)) {
            # Restore the previous one
            $choice->SetSelection($choice->GetCurrentSelection);
            return;
        }
    } else {
        return 0 if !$self->prompt_unsaved_changes;
    }
    wxTheApp->CallAfter(sub {
        # Close the preset editor tab if any
        if (exists $self->GetFrame->{preset_editor_tabs}{$group}) {
            my $tabpanel = $self->GetFrame->{tabpanel};
            $tabpanel->DeletePage($tabpanel->GetPageIndex($self->GetFrame->{preset_editor_tabs}{$group}));
            delete $self->GetFrame->{preset_editor_tabs}{$group};
            $tabpanel->SetSelection(0); # without this, a newly created tab will not be selected by wx
        }

        $self->_on_select_preset($group);

        # This will remove the "(modified)" mark from any dirty preset handled here.
        $self->load_presets;
    });
}
*/
}

}} // Slic3r::GUI
<commit_msg>When filtering default values out, it helps to not use the original source and clobber the compatibilty list.<commit_after>#include "PresetChooser.hpp"
#include "misc_ui.hpp"

namespace Slic3r { namespace GUI {

PresetChooser::PresetChooser(wxWindow* parent, std::weak_ptr<Print> print) : PresetChooser(parent, print, SLIC3RAPP->settings(), SLIC3RAPP->presets) {}

PresetChooser::PresetChooser(wxWindow* parent, std::weak_ptr<Print> print, Settings* external_settings, preset_store& external_presets) :
    wxPanel(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL, ""),
    _local_sizer(new wxFlexGridSizer(3,3,1,2)), _parent(parent), _settings(external_settings), _print(print), _presets(external_presets)
{
    _local_sizer->AddGrowableCol(1, 1);
    _local_sizer->SetFlexibleDirection(wxHORIZONTAL);

    for (auto group : { preset_t::Print, preset_t::Material, preset_t::Printer }) {
        wxString name = "";
        switch(group) {
            case preset_t::Print:
                name << _("Print settings:");
                break;
            case preset_t::Material:
                name << _("Material:");
                break;
            case preset_t::Printer:
                name << _("Printer:");
                break;
            default:
                break;
        }
        auto* text {new wxStaticText(this, wxID_ANY, name, wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT)};
        text->SetFont(_settings->small_font());

        auto* choice {new wxBitmapComboBox(this, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, 0, nullptr, wxCB_READONLY)};
        this->preset_choosers[get_preset(group)].push_back(choice);

        // Settings button
        auto* settings_btn {new wxBitmapButton(this, wxID_ANY, wxBitmap(var("cog.png"), wxBITMAP_TYPE_PNG), wxDefaultPosition, wxDefaultSize, wxBORDER_NONE)};

        this->_local_sizer->Add(text, 0, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL | wxRIGHT, 4);
        this->_local_sizer->Add(choice, 1, wxALIGN_CENTER_VERTICAL | wxEXPAND | wxBOTTOM, 0);
        this->_local_sizer->Add(settings_btn, 0, wxALIGN_CENTER_VERTICAL | wxEXPAND | wxLEFT, 3);

        // setup listener.
        // On a combobox event, puts a call to _on_change_combobox() on the evt_idle stack.
        choice->Bind(wxEVT_COMBOBOX,
            [=](wxCommandEvent& e) {
                wxTheApp->CallAfter([=]() { this->_on_change_combobox(group, choice);} );
            });
    }

    this->SetSizer(_local_sizer);
}

void PresetChooser::load(std::array<Presets, preset_types> presets) {

    wxString selected_printer_name {""};
    for (const auto& group : { preset_t::Printer, preset_t::Material, preset_t::Print }) {
        auto current_list = presets.at(get_preset(group));
        // Filter out profiles not compatible with this printer
        if (group != preset_t::Printer) {
            current_list = grep(presets.at(get_preset(group)), [selected_printer_name] (const Preset& x) -> bool { return x.compatible(selected_printer_name); });
        }

        // show default names if no other presets visible.
        if (current_list.size() > 1) {
            current_list = grep(current_list, [] (const Preset& x) -> bool { return !x.default_preset; });
        }

        // # Read the current defaults from the settings file
        const auto& settings_defaults {_settings->default_presets.at(get_preset(group))};

        size_t i {0};
        std::vector<std::string> preset_names {};
        __chooser_names[get_preset(group)].clear();
        // populate the chooser
        for (auto* chooser : this->preset_choosers[get_preset(group)]) {
            chooser->Clear();
            assert(chooser->GetCount() == 0);
            for (auto preset : current_list) {
                wxBitmap bitmap;
                switch (group) {
                    case preset_t::Print:
                        bitmap = wxBitmap(var("cog.png"), wxBITMAP_TYPE_PNG);
                        break;
                    case preset_t::Material:
                        if (auto config =  preset.config().lock()) {
                            if (preset.default_preset || !config->has("filament_colour"))
                                bitmap = wxBitmap(var("spool.png"), wxBITMAP_TYPE_PNG);
                        } else { // fall back if for some reason the config is dead.
                            bitmap = wxBitmap(var("spool.png"), wxBITMAP_TYPE_PNG);
                        }
                        break;
                    case preset_t::Printer:
                        bitmap = wxBitmap(var("printer_empty.png"), wxBITMAP_TYPE_PNG);
                        break;
                    default: break;
                }
                chooser->Append(preset.name, bitmap);
                __chooser_names[get_preset(group)].push_back(preset.name);
            }
            assert(chooser->GetCount() == current_list.size());

            // Apply default options from settings
            bool updated_from_settings = false;
            if (settings_defaults.size() > i) { // only apply if there is a value from Settings
                updated_from_settings = this->select_preset_by_name(settings_defaults.at(i), chooser);
            }

            if (!updated_from_settings) // default
                chooser->SetSelection(0);

            wxString selected_preset { chooser->GetString(chooser->GetSelection()) };
            if (group == preset_t::Printer) {
                selected_printer_name = selected_preset;
            }

            ++i;
        }
        this->_update_preset_settings(group);
    }
}

bool PresetChooser::select_preset_by_name(wxString name, preset_t group, size_t index = 0) {
    auto& ps_list = this->preset_choosers.at(get_preset(group));
    bool updated = false;
    if (ps_list.size() > index) {
        updated = select_preset_by_name(name, ps_list.at(index));
    }
    if (updated)
        this->_on_select_preset(group);
    return updated;
}

bool PresetChooser::select_preset_by_name(wxString name, wxBitmapComboBox* chooser) {
    auto index { chooser->FindString(name) };
    if (index != wxNOT_FOUND) {
        chooser->SetSelection(index);
        return true;
    }
    return false;
}

void PresetChooser::_update_preset_settings(preset_t preset) {
    auto& settings_presets {_settings->default_presets.at(get_preset(preset))};
    settings_presets.clear(); // make sure previous contents are deconstructed
    settings_presets = this->_get_selected_presets(preset);

}

void PresetChooser::_on_select_preset(preset_t preset) {
    // update settings store
    this->_update_preset_settings(preset);
    // save settings
    _settings->save_settings();
    if (preset == preset_t::Printer) {
        this->load(); // reload print/filament settings to honor compatible printers
    }
}

bool PresetChooser::prompt_unsaved_changes() {
    return true;
}

std::vector<wxString> PresetChooser::_get_selected_presets(preset_t group) const {
        const auto& choosers { this->preset_choosers[get_preset(group)] };
        std::vector<wxString> selected;
        selected.reserve(choosers.size());

        for (auto* chooser :  choosers) {
            selected.push_back(chooser->GetString(chooser->GetSelection()));
        }
        return selected;
}

wxString PresetChooser::_get_selected_preset(preset_t group, size_t index) const {
    auto selected { this->_get_selected_presets(group) };
    if (index > selected.size()) { return wxString(""); }
    return selected.at(index);
}
void PresetChooser::_on_change_combobox(preset_t preset, wxBitmapComboBox* choice) {

    // Prompt for unsaved changes and undo selections if cancelled and return early
    // Callback to close preset editor tab, close editor tabs, reload presets.
    //
    if (!this->prompt_unsaved_changes()) return;
    wxTheApp->CallAfter([this,preset]()
    {
        this->_on_select_preset(preset);
        // reload presets; removes the modified mark
        this->load();
    });
    /*
    sub _on_change_combobox {
    my ($self, $group, $choice) = @_;

    if (0) {
        # This code is disabled because wxPerl doesn't provide GetCurrentSelection
        my $current_name = $self->{preset_choosers_names}{$choice}[$choice->GetCurrentSelection];
        my $current = first { $_->name eq $current_name } @{wxTheApp->presets->{$group}};
        if (!$current->prompt_unsaved_changes($self)) {
            # Restore the previous one
            $choice->SetSelection($choice->GetCurrentSelection);
            return;
        }
    } else {
        return 0 if !$self->prompt_unsaved_changes;
    }
    wxTheApp->CallAfter(sub {
        # Close the preset editor tab if any
        if (exists $self->GetFrame->{preset_editor_tabs}{$group}) {
            my $tabpanel = $self->GetFrame->{tabpanel};
            $tabpanel->DeletePage($tabpanel->GetPageIndex($self->GetFrame->{preset_editor_tabs}{$group}));
            delete $self->GetFrame->{preset_editor_tabs}{$group};
            $tabpanel->SetSelection(0); # without this, a newly created tab will not be selected by wx
        }

        $self->_on_select_preset($group);

        # This will remove the "(modified)" mark from any dirty preset handled here.
        $self->load_presets;
    });
}
*/
}

}} // Slic3r::GUI
<|endoftext|>


<commit_before>/*
=============================================================================
  Name: MiniKing.h
  Author: Emilio Garcia-Fidalgo
  Date: 30/10/06 18:22
  Description: Main Library class
=============================================================================
*/

#include "libminiking/MiniKing.h"

MiniKing::MiniKing(char *port, int timeout) :
    cp(port, br115200, db8, None, sb1, timeout, false),
    mtheadcommand(&conf),
    mtreboot(),
    mtsenddata(),
    mtsendversion(),
    mtsendbbuser(),
    mtversiondata(),
    mtalive(),
    mtbbuserdata(),
    mtheaddata1(),
    mtheaddata2() {

    // Default Settings

    setDefaultConfig();

    // Need send 'MtSendData' command

    needData = true;

    // To receive mtHeadData Packets

    allReceived = true;

    // Verbose Mode

    verbose = false;
}

// Configuration access functions

void MiniKing::set8Bits(bool op) { conf.hdctrlbits[0] = op; }

bool MiniKing::get8Bits(void) { return conf.hdctrlbits[0]; }

void MiniKing::setContinuous(bool op) { conf.hdctrlbits[1] = op; }

bool MiniKing::getContinuous(void) { return conf.hdctrlbits[1]; }

void MiniKing::setInverted(bool op) { conf.hdctrlbits[3] = op; }

bool MiniKing::getInverted(void) { return conf.hdctrlbits[3]; }

void MiniKing::setMotorDisabled(bool op) { conf.hdctrlbits[4] = op; }

bool MiniKing::getMotorDisabled(void) { return conf.hdctrlbits[4]; }

void MiniKing::setTransmitDisabled(bool op) { conf.hdctrlbits[5] = op; }

bool MiniKing::getTransmitDisabled(void) { return conf.hdctrlbits[5]; }

void MiniKing::setApplyOffset(bool op) { conf.hdctrlbits[10] = op;}

bool MiniKing::getApplyOffset(void) { return conf.hdctrlbits[10]; }

void MiniKing::setStare(bool op) { conf.hdctrlbits[12] = op;}

bool MiniKing::getStare(void) { return conf.hdctrlbits[12]; }

void MiniKing::setSonarType(SonarType st) { conf.sonartype = st; }

SonarType MiniKing::getSonarType(void) { return conf.sonartype; }

void MiniKing::setFrequency(Frequency freq) { conf.frequency = freq; }

Frequency MiniKing::getFrequency(void) { return conf.frequency; }

void MiniKing::setRange(int range) { conf.rangescale = range; }

int MiniKing::getRange(void) { return conf.rangescale; }

void MiniKing::setLeftLim(int lim) { conf.leftlim = (lim * 10) / 9; }

float MiniKing::getLeftLim(void) { return (conf.leftlim * 9.0) / 10.0; }

void MiniKing::setRightLim(int lim) { conf.rightlim = (lim * 10) / 9; }

float MiniKing::getRightLim(void) { return (conf.rightlim * 9.0) / 10.0; }

void MiniKing::setADSpan(int ads) { conf.adspan = ads; }

int MiniKing::getADSpan(void) { return conf.adspan; }

void MiniKing::setADLow(int adl) { conf.adlow = adl; }

int MiniKing::getADLow(void) { return conf.adlow; }

void MiniKing::setGain(int gn) { conf.gain = gn; }

int MiniKing::getGain(void) { return conf.gain; }

void MiniKing::setResolution(Resolution rs) { conf.resolution = rs; }

Resolution MiniKing::getResolution(void) { return conf.resolution; }

void MiniKing::setBins(int bn) { conf.bins = bn; }

int MiniKing::getBins(void) { return conf.bins; }

// Version data access functions

BoardType MiniKing::getBoardType(void) { return vd.bt; }

int MiniKing::getSerialNumber(void) { return vd.serialnumber; }

int MiniKing::getProgramLength(void) { return vd.programlength; }

int MiniKing::getChecksum(void) { return vd.checksum; }

// 'MtAlive' access functions

bool MiniKing::hasParams(void) { return mtalive.hasParams(); }

int MiniKing::getHeadTime(void) { return mtalive.getHeadTime(); }

float MiniKing::getMotorPos(void) { return (((mtalive.getMotorPos() / 16.0) * 9.0) / 10.0); } // In grads

bool MiniKing::isCentering(void) { return mtalive.isCentering(); }

bool MiniKing::isCentred(void) { return mtalive.isCentred(); }

bool MiniKing::isMotoring(void) { return mtalive.isMotoring(); }

bool MiniKing::isMotorOn(void) { return mtalive.isMotorOn(); }

bool MiniKing::isDir(void) { return mtalive.isDir(); }

bool MiniKing::isScan(void) { return mtalive.isScan(); }

bool MiniKing::configReceived(void) { return mtalive.paramsReceived(); }

// 'MtBBUserData' access functions

LANBitRate MiniKing::getLanBaudLow(void) { return mtbbuserdata.getLanBaudLow(); }

LANBitRate MiniKing::getLanBaudHigh(void) { return mtbbuserdata.getLanBaudHigh(); }

LANSensitivity MiniKing::getSensitivityLow(void) { return mtbbuserdata.getSensitivityLow(); }

LANSensitivity MiniKing::getSensitivityHigh(void) { return mtbbuserdata.getSensitivityHigh(); }

int MiniKing::getLanTimeout(void) { return mtbbuserdata.getLanTimeout(); }

BitRate MiniKing::getCOMBaudLow(void) { return mtbbuserdata.getA0BaudLow(); }

BitRate MiniKing::getCOMBaudHigh(void) { return mtbbuserdata.getA0BaudHigh(); }

Parity MiniKing::getCOMParityLow(void) { return mtbbuserdata.getA0ParityLow(); }

Parity MiniKing::getCOMParityHigh(void) { return mtbbuserdata.getA0ParityHigh(); }

DataBits MiniKing::getCOMDataBitsLow(void) { return mtbbuserdata.getA0DataBitsLow(); }

DataBits MiniKing::getCOMDataBitsHigh(void) { return mtbbuserdata.getA0DataBitsHigh(); }

BitRate MiniKing::getAUXBaudLow(void) { return mtbbuserdata.getA1BaudLow(); }

BitRate MiniKing::getAUXBaudHigh(void) { return mtbbuserdata.getA1BaudHigh(); }

Parity MiniKing::getAUXParityLow(void) { return mtbbuserdata.getA1ParityLow(); }

Parity MiniKing::getAUXParityHigh(void) { return mtbbuserdata.getA1ParityHigh(); }

DataBits MiniKing::getAUXDataBitsLow(void) { return mtbbuserdata.getA1DataBitsLow(); }

DataBits MiniKing::getAUXDataBitsHigh(void) { return mtbbuserdata.getA1DataBitsHigh(); }

bool MiniKing::hasMotor(void) { return mtbbuserdata.hasMotor(); }

bool MiniKing::hasAux(void) { return mtbbuserdata.hasAux(); }

bool MiniKing::hasRollSensor(void) { return mtbbuserdata.hasRollSensor(); }

SonarBlock *MiniKing::otherInfo(void) { return &(mtbbuserdata.snb); }

// 'MtHeadData' access functions

float MiniKing::getPosition(void) {

    if (needData)
        return ((((float)mtheaddata2.getBearing() / 16.0) * 9.0) / 10.0);      // In grads
    else
        return ((((float)mtheaddata1.getBearing() / 16.0) * 9.0) / 10.0);      // In grads
}

int MiniKing::getDataLength(void) {

    if (needData)
        return mtheaddata2.getDataLength();
    else
        return mtheaddata1.getDataLength();
}

// General functions

void MiniKing::setDefaultConfig() { // Need updateConfig() after to take effect

    // Hdctrl bits

    conf.hdctrlbits[0] = true;    // 8 Data Bits
    conf.hdctrlbits[1] = true;    // Scan continuous
    conf.hdctrlbits[2] = true;    // Clockwise
    conf.hdctrlbits[3] = false;   // Normal mounted
    conf.hdctrlbits[4] = false;   // Motor Enabled
    conf.hdctrlbits[5] = false;   // Transmitter Enabled
    conf.hdctrlbits[6] = false;   // Default, Always 0
    conf.hdctrlbits[7] = false;   // Only One Channel Operation
    conf.hdctrlbits[8] = true;    // Default, Always 1
    conf.hdctrlbits[9] = true;    // Sonar has scanning motor
    conf.hdctrlbits[10] = false;  // Do not apply offsets
    conf.hdctrlbits[11] = false;  // Not pingpong, only one channel
    conf.hdctrlbits[12] = false;  // Don´t stare in a fixed direction
    conf.hdctrlbits[13] = true;   // Default, Always 1
    conf.hdctrlbits[14] = false;  // Default, Always 0
    conf.hdctrlbits[15] = false;  // Don´t ignore sensor

    // Head Type

    conf.sonartype = ImagingSonar;

    // Head Frequency

    conf.frequency = f675;

    // Range Scale

    conf.rangescale = 30;

    // Scan Limits

    conf.leftlim = 0;
    conf.rightlim = 0;

    // ADSpan and ADLow (in Db´s)

    conf.adspan = 12;
    conf.adlow = 13;

    // Initial Gain

    conf.gain = 40;

    // Resolution

    conf.resolution = Medium;

    // Number of Range Bins for each ping

    conf.bins = 300;
}

void MiniKing::initSonar(void) {       // Basic initialization procedure

    while (receive(&cp) != mtAlive);

    mtsendversion.send(&cp);
    if (verbose) mtsendversion.printPacket(true);

    while (receive(&cp) != mtVersionData);

    vd.fr = mtversiondata.getFrequency();
    vd.bt = mtversiondata.getBoardType();
    vd.serialnumber = mtversiondata.getSerialNumber();
    vd.programlength = mtversiondata.getProgramLength();
    vd.checksum = mtversiondata.getChecksum();

    mtsendbbuser.send(&cp);
    if (verbose) mtsendversion.printPacket(true);

    while (receive(&cp) != mtBBUserData);

    while (receive(&cp) != mtAlive);

    while (!hasParams()) {

        mtheadcommand.send(&cp);
        if (verbose) mtheadcommand.printPacket(true);
        while (receive(&cp) != mtAlive);
    }
}

void MiniKing::reboot(void) {           // Reboots sonar

    setDefaultConfig();

    mtreboot.send(&cp);
    if (verbose) mtreboot.printPacket(true);
    while (receive(&cp) != mtAlive);

    while (hasParams()) receive(&cp);

    while (!hasParams()) {

        mtheadcommand.send(&cp);
        if (verbose) mtheadcommand.printPacket(true);

        while (receive(&cp) != mtAlive);
    }
}

void MiniKing::updateConfig(void) {     // Update sonar´s parametres

    do {

        mtheadcommand.send(&cp);
        if (verbose) mtheadcommand.printPacket(true);
        while (receive(&cp) != mtAlive);
    } while (!hasParams());
}

BYTE *MiniKing::getScanLine(void) {    // Get a data scan

    if (needData) {

        mtsenddata.send(&cp);
        if (verbose) mtsenddata.printPacket(true);

        while (receive(&cp) != mtHeadData);

        allReceived = false;

        while (receive(&cp) != mtHeadData);

        allReceived = true;

        needData = false;

        return mtheaddata1.getDataBytes();
    }
    else {

        needData = true;

        return mtheaddata2.getDataBytes();
    }
}

void MiniKing::setVerboseMode(bool op) {

    verbose = op;
}

bool MiniKing::isLeftLimit(void) {

    if (needData) {

        if (mtheaddata1.getSweepCode() == ScanLeftLimit)
            return true;
        else
            return false;
    }
    else {

        if (mtheaddata2.getSweepCode() == ScanLeftLimit)
            return true;
        else
            return false;
    }
}

bool MiniKing::isRightLimit(void) {

    if (needData) {

        if (mtheaddata1.getSweepCode() == ScanRightLimit)
            return true;
        else
            return false;
    }
    else {

        if (mtheaddata2.getSweepCode() == ScanRightLimit)
            return true;
        else
            return false;
    }
}

// Waits for Initial Character

BYTE synchronize(SerialPort *cport) {

    BYTE ch;

    try {

        while((ch = cport->read()) != '@');
        return ch;
    }
    catch (runtime_error &e) {        // Error in timeouts or bytes
        cout << e.what() << endl;
        return false;
    }
}

// General receive

PacketType MiniKing::receive(SerialPort *cport) {

    BYTE inchar = synchronize(cport);
    BYTE hdr;
    BYTE hexln[4];
    BYTE binln[2];
    BYTE sid;
    BYTE did;
    BYTE countmsg;
    BYTE ptype;
    BYTE sequence;
    BYTE node;

    if (!inchar) {
        cout << "Can´t receive message" << endl;
    }
    else if (inchar == '@') {
        try {

            // Header

            hdr = inchar;

            // Hex Length

            cport->read(hexln, 4);

            // Bin Length

            cport->read(binln, 2);

            // Source ID and Destination ID

            sid = cport->read();
            did = cport->read();

            // Count Message

            countmsg = cport->read();

            // Packet Type

            ptype = cport->read();

            // Sequence Number

            sequence = cport->read();

            // Copy of Byte 8

            node = cport->read();

            Message *msg = NULL;

            switch (ptype) {
            case mtAlive:
                msg = &mtalive;
                mtalive.receive(&cp);
                break;
            case mtBBUserData:
                msg = &mtbbuserdata;
                mtbbuserdata.receive(&cp);
                break;
            case mtVersionData:
                msg = &mtversiondata;
                mtversiondata.receive(&cp);
                break;
            case mtHeadData:
                if (allReceived) {
                    msg = &mtheaddata1;
                    mtheaddata1.receive(&cp);
                }
                else {
                    msg = &mtheaddata2;
                    mtheaddata2.receive(&cp);
                }
                break;
            default:
                break;
            }
            msg->hdr = inchar;
            for (int i = 0; i < 4; i++)
                msg->hexln[i] = hexln[i];
            for (int i = 0; i < 2; i++)
                msg->binln[i] = binln[i];
            msg->sid = sid;
            msg->did = did;
            msg->countmsg = countmsg;
            msg->ptype = ptype;
            msg->sequence = sequence;
            msg->node = node;
            if (verbose) msg->printPacket(true);
            return (PacketType)ptype;
        }
        catch (runtime_error &e) {        // Error in timeouts or bytes
            cout << e.what() << endl;
        }
    }
    else {
        cout << "Unknown error receiving message" << endl;
    }
    return errorPacket;
}
<commit_msg>Minnor changes<commit_after>/*
=============================================================================
  Name: MiniKing.h
  Author: Emilio Garcia-Fidalgo
  Date: 30/10/06 18:22
  Description: Main Library class
=============================================================================
*/

#include "libminiking/MiniKing.h"

MiniKing::MiniKing(char *port, int timeout) :
    cp(port, br115200, db8, None, sb1, timeout, false),
    mtheadcommand(&conf),
    mtreboot(),
    mtsenddata(),
    mtsendversion(),
    mtsendbbuser(),
    mtversiondata(),
    mtalive(),
    mtbbuserdata(),
    mtheaddata1(),
    mtheaddata2() {

    // Default Settings

    setDefaultConfig();

    // Need send 'MtSendData' command

    needData = true;

    // To receive mtHeadData Packets

    allReceived = true;

    // Verbose Mode

    verbose = false;
}

// Configuration access functions

void MiniKing::set8Bits(bool op) { conf.hdctrlbits[0] = op; }

bool MiniKing::get8Bits(void) { return conf.hdctrlbits[0]; }

void MiniKing::setContinuous(bool op) { conf.hdctrlbits[1] = op; }

bool MiniKing::getContinuous(void) { return conf.hdctrlbits[1]; }

void MiniKing::setInverted(bool op) { conf.hdctrlbits[3] = op; }

bool MiniKing::getInverted(void) { return conf.hdctrlbits[3]; }

void MiniKing::setMotorDisabled(bool op) { conf.hdctrlbits[4] = op; }

bool MiniKing::getMotorDisabled(void) { return conf.hdctrlbits[4]; }

void MiniKing::setTransmitDisabled(bool op) { conf.hdctrlbits[5] = op; }

bool MiniKing::getTransmitDisabled(void) { return conf.hdctrlbits[5]; }

void MiniKing::setApplyOffset(bool op) { conf.hdctrlbits[10] = op;}

bool MiniKing::getApplyOffset(void) { return conf.hdctrlbits[10]; }

void MiniKing::setStare(bool op) { conf.hdctrlbits[12] = op;}

bool MiniKing::getStare(void) { return conf.hdctrlbits[12]; }

void MiniKing::setSonarType(SonarType st) { conf.sonartype = st; }

SonarType MiniKing::getSonarType(void) { return conf.sonartype; }

void MiniKing::setFrequency(Frequency freq) { conf.frequency = freq; }

Frequency MiniKing::getFrequency(void) { return conf.frequency; }

void MiniKing::setRange(int range) { conf.rangescale = range; }

int MiniKing::getRange(void) { return conf.rangescale; }

void MiniKing::setLeftLim(int lim) { conf.leftlim = (lim * 10) / 9; }

float MiniKing::getLeftLim(void) { return (conf.leftlim * 9.0) / 10.0; }

void MiniKing::setRightLim(int lim) { conf.rightlim = (lim * 10) / 9; }

float MiniKing::getRightLim(void) { return (conf.rightlim * 9.0) / 10.0; }

void MiniKing::setADSpan(int ads) { conf.adspan = ads; }

int MiniKing::getADSpan(void) { return conf.adspan; }

void MiniKing::setADLow(int adl) { conf.adlow = adl; }

int MiniKing::getADLow(void) { return conf.adlow; }

void MiniKing::setGain(int gn) { conf.gain = gn; }

int MiniKing::getGain(void) { return conf.gain; }

void MiniKing::setResolution(Resolution rs) { conf.resolution = rs; }

Resolution MiniKing::getResolution(void) { return conf.resolution; }

void MiniKing::setBins(int bn) { conf.bins = bn; }

int MiniKing::getBins(void) { return conf.bins; }

// Version data access functions

BoardType MiniKing::getBoardType(void) { return vd.bt; }

int MiniKing::getSerialNumber(void) { return vd.serialnumber; }

int MiniKing::getProgramLength(void) { return vd.programlength; }

int MiniKing::getChecksum(void) { return vd.checksum; }

// 'MtAlive' access functions

bool MiniKing::hasParams(void) { return mtalive.hasParams(); }

int MiniKing::getHeadTime(void) { return mtalive.getHeadTime(); }

float MiniKing::getMotorPos(void) { return (((mtalive.getMotorPos() / 16.0) * 9.0) / 10.0); } // In grads

bool MiniKing::isCentering(void) { return mtalive.isCentering(); }

bool MiniKing::isCentred(void) { return mtalive.isCentred(); }

bool MiniKing::isMotoring(void) { return mtalive.isMotoring(); }

bool MiniKing::isMotorOn(void) { return mtalive.isMotorOn(); }

bool MiniKing::isDir(void) { return mtalive.isDir(); }

bool MiniKing::isScan(void) { return mtalive.isScan(); }

bool MiniKing::configReceived(void) { return mtalive.paramsReceived(); }

// 'MtBBUserData' access functions

LANBitRate MiniKing::getLanBaudLow(void) { return mtbbuserdata.getLanBaudLow(); }

LANBitRate MiniKing::getLanBaudHigh(void) { return mtbbuserdata.getLanBaudHigh(); }

LANSensitivity MiniKing::getSensitivityLow(void) { return mtbbuserdata.getSensitivityLow(); }

LANSensitivity MiniKing::getSensitivityHigh(void) { return mtbbuserdata.getSensitivityHigh(); }

int MiniKing::getLanTimeout(void) { return mtbbuserdata.getLanTimeout(); }

BitRate MiniKing::getCOMBaudLow(void) { return mtbbuserdata.getA0BaudLow(); }

BitRate MiniKing::getCOMBaudHigh(void) { return mtbbuserdata.getA0BaudHigh(); }

Parity MiniKing::getCOMParityLow(void) { return mtbbuserdata.getA0ParityLow(); }

Parity MiniKing::getCOMParityHigh(void) { return mtbbuserdata.getA0ParityHigh(); }

DataBits MiniKing::getCOMDataBitsLow(void) { return mtbbuserdata.getA0DataBitsLow(); }

DataBits MiniKing::getCOMDataBitsHigh(void) { return mtbbuserdata.getA0DataBitsHigh(); }

BitRate MiniKing::getAUXBaudLow(void) { return mtbbuserdata.getA1BaudLow(); }

BitRate MiniKing::getAUXBaudHigh(void) { return mtbbuserdata.getA1BaudHigh(); }

Parity MiniKing::getAUXParityLow(void) { return mtbbuserdata.getA1ParityLow(); }

Parity MiniKing::getAUXParityHigh(void) { return mtbbuserdata.getA1ParityHigh(); }

DataBits MiniKing::getAUXDataBitsLow(void) { return mtbbuserdata.getA1DataBitsLow(); }

DataBits MiniKing::getAUXDataBitsHigh(void) { return mtbbuserdata.getA1DataBitsHigh(); }

bool MiniKing::hasMotor(void) { return mtbbuserdata.hasMotor(); }

bool MiniKing::hasAux(void) { return mtbbuserdata.hasAux(); }

bool MiniKing::hasRollSensor(void) { return mtbbuserdata.hasRollSensor(); }

SonarBlock *MiniKing::otherInfo(void) { return &(mtbbuserdata.snb); }

// 'MtHeadData' access functions

float MiniKing::getPosition(void) {

    if (needData)
        return ((((float)mtheaddata2.getBearing() / 16.0) * 9.0) / 10.0);      // In grads
    else
        return ((((float)mtheaddata1.getBearing() / 16.0) * 9.0) / 10.0);      // In grads
}

int MiniKing::getDataLength(void) {

    if (needData)
        return mtheaddata2.getDataLength();
    else
        return mtheaddata1.getDataLength();
}

// General functions

void MiniKing::setDefaultConfig() { // Need updateConfig() after to take effect

    // Hdctrl bits

    conf.hdctrlbits[0] = true;    // 8 Data Bits
    conf.hdctrlbits[1] = true;    // Scan continuous
    conf.hdctrlbits[2] = true;    // Clockwise
    conf.hdctrlbits[3] = false;   // Normal mounted
    conf.hdctrlbits[4] = false;   // Motor Enabled
    conf.hdctrlbits[5] = false;   // Transmitter Enabled
    conf.hdctrlbits[6] = false;   // Default, Always 0
    conf.hdctrlbits[7] = false;   // Only One Channel Operation
    conf.hdctrlbits[8] = true;    // Default, Always 1
    conf.hdctrlbits[9] = true;    // Sonar has scanning motor
    conf.hdctrlbits[10] = false;  // Do not apply offsets
    conf.hdctrlbits[11] = false;  // Not pingpong, only one channel
    conf.hdctrlbits[12] = false;  // Don´t stare in a fixed direction
    conf.hdctrlbits[13] = true;   // Default, Always 1
    conf.hdctrlbits[14] = false;  // Default, Always 0
    conf.hdctrlbits[15] = false;  // Don´t ignore sensor

    // Head Type

    conf.sonartype = ImagingSonar;

    // Head Frequency

    conf.frequency = f675;

    // Range Scale

    conf.rangescale = 30;

    // Scan Limits

    conf.leftlim = 0;
    conf.rightlim = 0;

    // ADSpan and ADLow (in Db´s)

    conf.adspan = 12;
    conf.adlow = 13;

    // Initial Gain

    conf.gain = 40;

    // Resolution

    conf.resolution = Medium;

    // Number of Range Bins for each ping

    conf.bins = 300;
}

void MiniKing::initSonar(void) {       // Basic initialization procedure

    while (receive(&cp) != mtAlive);

    mtsendversion.send(&cp);
    if (verbose) mtsendversion.printPacket(true);

    while (receive(&cp) != mtVersionData);

    vd.fr = mtversiondata.getFrequency();
    vd.bt = mtversiondata.getBoardType();
    vd.serialnumber = mtversiondata.getSerialNumber();
    vd.programlength = mtversiondata.getProgramLength();
    vd.checksum = mtversiondata.getChecksum();

    mtsendbbuser.send(&cp);
    if (verbose) mtsendversion.printPacket(true);

    while (receive(&cp) != mtBBUserData);

    while (receive(&cp) != mtAlive);

    while (!hasParams()) {

        mtheadcommand.send(&cp);
        if (verbose) mtheadcommand.printPacket(true);
        while (receive(&cp) != mtAlive);
    }
}

void MiniKing::reboot(void) {           // Reboots sonar

    setDefaultConfig();

    mtreboot.send(&cp);
    if (verbose) mtreboot.printPacket(true);
    while (receive(&cp) != mtAlive);

    while (hasParams()) receive(&cp);

    while (!hasParams()) {

        mtheadcommand.send(&cp);
        if (verbose) mtheadcommand.printPacket(true);

        while (receive(&cp) != mtAlive);
    }
}

void MiniKing::updateConfig(void) {     // Update sonar´s parametres

    do {

        mtheadcommand.send(&cp);
        if (verbose) mtheadcommand.printPacket(true);
        while (receive(&cp) != mtAlive);
    } while (!hasParams());
}

BYTE *MiniKing::getScanLine(void) {    // Get a data scan

    if (needData) {

        mtsenddata.send(&cp);
        if (verbose) mtsenddata.printPacket(true);

        while (receive(&cp) != mtHeadData);

        allReceived = false;

        while (receive(&cp) != mtHeadData);

        allReceived = true;

        needData = false;

        return mtheaddata1.getDataBytes();
    }
    else {

        needData = true;

        return mtheaddata2.getDataBytes();
    }
}

void MiniKing::setVerboseMode(bool op) {

    verbose = op;
}

bool MiniKing::isLeftLimit(void) {

    if (needData) {

        if (mtheaddata1.getSweepCode() == ScanLeftLimit)
            return true;
        else
            return false;
    }
    else {

        if (mtheaddata2.getSweepCode() == ScanLeftLimit)
            return true;
        else
            return false;
    }
}

bool MiniKing::isRightLimit(void) {

    if (needData) {

        if (mtheaddata1.getSweepCode() == ScanRightLimit)
            return true;
        else
            return false;
    }
    else {

        if (mtheaddata2.getSweepCode() == ScanRightLimit)
            return true;
        else
            return false;
    }
}

// Waits for Initial Character

BYTE synchronize(SerialPort *cport) {

    BYTE ch;

    try {

        while((ch = cport->read()) != '@');
        return ch;
    }
    catch (runtime_error &e) {        // Error in timeouts or bytes
        cout << e.what() << endl;
        return false;
    }
}

// General receive

PacketType MiniKing::receive(SerialPort *cport) {

    BYTE inchar = synchronize(cport);
    BYTE hdr;
    BYTE hexln[4];
    BYTE binln[2];
    BYTE sid;
    BYTE did;
    BYTE countmsg;
    BYTE ptype;
    BYTE sequence;
    BYTE node;

    if (!inchar) {
        cout << "Can´t receive message" << endl;
    }
    else if (inchar == '@') {
        try {

            // Header

            hdr = inchar;

            // Hex Length

            cport->read(hexln, 4);

            // Bin Length

            cport->read(binln, 2);

            // Source ID and Destination ID

            sid = cport->read();
            did = cport->read();

            // Count Message

            countmsg = cport->read();

            // Packet Type

            ptype = cport->read();

            // Sequence Number

            sequence = cport->read();

            // Copy of Byte 8

            node = cport->read();

            Message *msg = NULL;

            switch (ptype) {
            case mtAlive:
                msg = &mtalive;
                mtalive.receive(&cp);
                break;
            case mtBBUserData:
                msg = &mtbbuserdata;
                mtbbuserdata.receive(&cp);
                break;
            case mtVersionData:
                msg = &mtversiondata;
                mtversiondata.receive(&cp);
                break;
            case mtHeadData:
                if (allReceived) {
                    msg = &mtheaddata1;
                    mtheaddata1.receive(&cp);
                }
                else {
                    msg = &mtheaddata2;
                    mtheaddata2.receive(&cp);
                }
                break;
            default:
                break;
            }
            msg->hdr = inchar;
            for (int i = 0; i < 4; i++)
                msg->hexln[i] = hexln[i];
            for (int i = 0; i < 2; i++)
                msg->binln[i] = binln[i];
            msg->sid = sid;
            msg->did = did;
            msg->countmsg = countmsg;
            msg->ptype = ptype;
            msg->sequence = sequence;
            msg->node = node;
            if (verbose) msg->printPacket(true);
            return (PacketType)ptype;
        }
        catch (runtime_error &e) {        // Error in timeouts or bytes
            cout << e.what() << endl;
        }
    }
    else {
        cout << "Unknown error receiving message" << endl;
    }
    return errorPacket;
}
<|endoftext|>


<commit_before>
#include "OsmLayer.h"

#include <stdio.h>

// This is the total number of meters in the world -180. - 180 W,
#define MAXLAT 85.0511287798066
#define MAXLON 180.0

// from http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames
int long2tilex(double lon, int z)
{
	return (int)(floor((lon + 180.0) / 360.0 * pow(2.0, z)));
}

int lat2tiley(double lat, int z)
{
	return (int)(floor((1.0 - log( tan(lat * M_PI/180.0) + 1.0 /
                                  cos(lat * M_PI/180.0)) / M_PI) /
                       2.0 * pow(2.0, z)));
}

double tilex2long(int x, int z)
{
	return x / pow(2.0, z) * 360.0 - 180;
}

double tiley2lat(int y, int z)
{
	double n = M_PI - 2.0 * M_PI * y / pow(2.0, z);
	return 180.0 / M_PI * atan(0.5 * (exp(n) - exp(-n)));
}

void _drawQuad(const MapPoint &upperLeft, const MapPoint &lowerRight)
{
    gl::drawSolidRect(Rectf(upperLeft.x, upperLeft.y,
                            lowerRight.x, lowerRight.y));
}

OsmLayer::OsmLayer() : Layer(),
    _tileSource(new OsmTileSource()),
    _worldSize(0.0),
    _tileSize(1.0),
    _currentZoom(0),
    _numEdgeTiles(1),
    _lastResolution(0.),
    _shader(new QGLShaderProgram),
    _isSetup(false)
{
    connect(_tileSource, SIGNAL(tileReady(unsigned int, unsigned int, unsigned int)),
            SLOT(onTileReady(unsigned int, unsigned int, unsigned int)));
}

OsmLayer::~OsmLayer()
{
    delete _shader;
}

QString
OsmLayer::name() const
{
    return QString("Open Street Map");
}

QString
OsmLayer::sport() const
{
    return QString("map");
}

QDateTime
OsmLayer::startTime() const
{
    return QDateTime();
}

PassMap
OsmLayer::passes() const
{
    PassMap layers;
    layers.insert(Pass_BaseMap);
    return layers;
}

void
OsmLayer::project(const Projection &projection)
{
    _worldTopLeft = projection.toProjection(LonLat(-MAXLON, MAXLAT));
    _worldLowerRight = projection.toProjection(LonLat(MAXLON, -MAXLAT));
    _worldSize = _worldTopLeft.y - _worldLowerRight.y;
    for (int i = 0; i < numZoomLevels; i++)
        _resolutions[i] = (_worldSize / (1 << i)) / pixelsPerTile;
}

void
OsmLayer::draw(uint pass, const ViewCtx &viewCtx, const TimeCtx&)
{
    if (pass != Pass_BaseMap)
        return;

    if (_lastResolution != viewCtx.getResolution()) {
        _lastResolution = viewCtx.getResolution();
        _currentZoom = _getZoomLevel(viewCtx.getResolution());
        _numEdgeTiles = pow(2., _currentZoom);
        _tileSize = _worldSize / _numEdgeTiles;
    }

    BoundingBox viewport = viewCtx.getBoundingBox();
    unsigned int upperLeftX, upperLeftY, lowerRightX, lowerRightY;
    _getTileXYAtMapPoint(viewport.upperLeft, &upperLeftX, &upperLeftY);
    _getTileXYAtMapPoint(viewport.lowerRight, &lowerRightX, &lowerRightY);

    if (!_isSetup)
        _setup();

    OsmIndexSet visibleTiles;
    for (unsigned int x = upperLeftX; x <= lowerRightX && x < _numEdgeTiles; x++) {
        for (unsigned int y=upperLeftY; y <= lowerRightY && y < _numEdgeTiles; y++)
        {
            OsmIndex idx(x, y, _currentZoom);
            visibleTiles.insert(idx);
            TileMap::iterator foundTile = _tiles.find(idx);
            if (foundTile == _tiles.end()) {
                Tile *newTile = new Tile();
                newTile->shader = _shader;
                newTile->index = idx;
                newTile->upperLeft.x = _worldTopLeft.x +
                    (_worldSize * ((double)x / (double)_numEdgeTiles));
                newTile->upperLeft.y = _worldTopLeft.y -
                    (_worldSize * ((double)y / (double)_numEdgeTiles));
                newTile->lowerRight.x = newTile->upperLeft.x + _tileSize;
                newTile->lowerRight.y = newTile->upperLeft.y - _tileSize;
                _tiles.insert(std::pair<OsmIndex, Tile*>(idx, newTile));
                _tileSource->getTile(idx.x, idx.y, idx.z);
                newTile->draw();
            } else {
                foundTile->second->draw();
            }
        }
    }

    // clean up tiles we no longer display
    for (TileMap::iterator i=_tiles.begin(); i != _tiles.end(); i++) {
        if (visibleTiles.find(i->first) == visibleTiles.end()) {
            delete i->second;
            _tiles.erase(i);
        }
    }
}

BoundingBox
OsmLayer::getBoundingBox() const
{
    return BoundingBox();
}

MapPoint
OsmLayer::position() const
{
    return MapPoint(0., 0.);
}

void
OsmLayer::onTileReady(unsigned int x, unsigned int y, unsigned int z)
{
    OsmIndex idx = OsmIndex(x, y, z);
    TileMap::iterator i = _tiles.find(idx);
    if (i != _tiles.end()) {
        i->second->setTexture(_tileSource->retrieveFinishedTile(x, y, z));
        emit layerUpdated();
    }
}

OsmLayer::Tile::Tile() : texture(NULL), shader(NULL)
{

}

void
OsmLayer::Tile::draw()
{
    // debug, draw diagonal lines
    gl::color( Color( 1, 1, 1 ) );
    gl::drawLine(upperLeft, lowerRight);
    gl::drawLine(Vec2f(upperLeft.x, lowerRight.y),
                 Vec2f(lowerRight.x, upperLeft.y));
    // end debug diagonal lines
    if (texture != NULL) {
        texture->enableAndBind();
        shader->bind();
        shader->setUniformValue(shader->uniformLocation("tex0"), 0 );
        _drawQuad(upperLeft, lowerRight);
        texture->unbind();
        shader->release();
    }
}

void
OsmLayer::Tile::setTexture(const Surface8u &surface)
{
    texture = new cinder::gl::Texture(surface);
}

uint
OsmLayer::_getZoomLevel(double resolution) const
{
    uint i;
    for (i = 0; i < numZoomLevels && resolution < _resolutions[i]; i++) {}
    return i;
}

void
OsmLayer::_setup()
{
    _shader->addShaderFromSourceCode(QGLShader::Fragment,
                                     "#version 110\n\n"
                                     "uniform sampler2D tex0;\n"
                                     "void main()\n"
                                     "{\n"
                                     "gl_FragColor = texture2D( tex0, gl_TexCoord[0].st);\n"
                                     "}\n");
    _isSetup = true;
}

void
OsmLayer::_getTileXYAtMapPoint(const MapPoint &pos,
                               unsigned int *x,
                               unsigned int *y) const
{
    int px, py;
    px = int(floor(_numEdgeTiles * ((pos.x - _worldTopLeft.x) / _worldSize)));
    py = int(floor(_numEdgeTiles * (_worldTopLeft.y - pos.y) / _worldSize));
    *x = (px < 0) ? 0 : px;
    *y = (py < 0) ? 0 : py;
}

<commit_msg>Don’t iterate to an invalidated iterator after erasing.<commit_after>
#include "OsmLayer.h"

#include <stdio.h>

// This is the total number of meters in the world -180. - 180 W,
#define MAXLAT 85.0511287798066
#define MAXLON 180.0

// from http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames
int long2tilex(double lon, int z)
{
	return (int)(floor((lon + 180.0) / 360.0 * pow(2.0, z)));
}

int lat2tiley(double lat, int z)
{
	return (int)(floor((1.0 - log( tan(lat * M_PI/180.0) + 1.0 /
                                  cos(lat * M_PI/180.0)) / M_PI) /
                       2.0 * pow(2.0, z)));
}

double tilex2long(int x, int z)
{
	return x / pow(2.0, z) * 360.0 - 180;
}

double tiley2lat(int y, int z)
{
	double n = M_PI - 2.0 * M_PI * y / pow(2.0, z);
	return 180.0 / M_PI * atan(0.5 * (exp(n) - exp(-n)));
}

void _drawQuad(const MapPoint &upperLeft, const MapPoint &lowerRight)
{
    gl::drawSolidRect(Rectf(upperLeft.x, upperLeft.y,
                            lowerRight.x, lowerRight.y));
}

OsmLayer::OsmLayer() : Layer(),
    _tileSource(new OsmTileSource()),
    _worldSize(0.0),
    _tileSize(1.0),
    _currentZoom(0),
    _numEdgeTiles(1),
    _lastResolution(0.),
    _shader(new QGLShaderProgram),
    _isSetup(false)
{
    connect(_tileSource, SIGNAL(tileReady(unsigned int, unsigned int, unsigned int)),
            SLOT(onTileReady(unsigned int, unsigned int, unsigned int)));
}

OsmLayer::~OsmLayer()
{
    delete _shader;
}

QString
OsmLayer::name() const
{
    return QString("Open Street Map");
}

QString
OsmLayer::sport() const
{
    return QString("map");
}

QDateTime
OsmLayer::startTime() const
{
    return QDateTime();
}

PassMap
OsmLayer::passes() const
{
    PassMap layers;
    layers.insert(Pass_BaseMap);
    return layers;
}

void
OsmLayer::project(const Projection &projection)
{
    _worldTopLeft = projection.toProjection(LonLat(-MAXLON, MAXLAT));
    _worldLowerRight = projection.toProjection(LonLat(MAXLON, -MAXLAT));
    _worldSize = _worldTopLeft.y - _worldLowerRight.y;
    for (int i = 0; i < numZoomLevels; i++)
        _resolutions[i] = (_worldSize / (1 << i)) / pixelsPerTile;
}

void
OsmLayer::draw(uint pass, const ViewCtx &viewCtx, const TimeCtx&)
{
    if (pass != Pass_BaseMap)
        return;

    if (_lastResolution != viewCtx.getResolution()) {
        _lastResolution = viewCtx.getResolution();
        _currentZoom = _getZoomLevel(viewCtx.getResolution());
        _numEdgeTiles = pow(2., _currentZoom);
        _tileSize = _worldSize / _numEdgeTiles;
    }

    BoundingBox viewport = viewCtx.getBoundingBox();
    unsigned int upperLeftX, upperLeftY, lowerRightX, lowerRightY;
    _getTileXYAtMapPoint(viewport.upperLeft, &upperLeftX, &upperLeftY);
    _getTileXYAtMapPoint(viewport.lowerRight, &lowerRightX, &lowerRightY);

    if (!_isSetup)
        _setup();

    OsmIndexSet visibleTiles;
    for (unsigned int x = upperLeftX; x <= lowerRightX && x < _numEdgeTiles; x++) {
        for (unsigned int y=upperLeftY; y <= lowerRightY && y < _numEdgeTiles; y++)
        {
            OsmIndex idx(x, y, _currentZoom);
            visibleTiles.insert(idx);
            TileMap::iterator foundTile = _tiles.find(idx);
            if (foundTile == _tiles.end()) {
                Tile *newTile = new Tile();
                newTile->shader = _shader;
                newTile->index = idx;
                newTile->upperLeft.x = _worldTopLeft.x +
                    (_worldSize * ((double)x / (double)_numEdgeTiles));
                newTile->upperLeft.y = _worldTopLeft.y -
                    (_worldSize * ((double)y / (double)_numEdgeTiles));
                newTile->lowerRight.x = newTile->upperLeft.x + _tileSize;
                newTile->lowerRight.y = newTile->upperLeft.y - _tileSize;
                _tiles.insert(std::pair<OsmIndex, Tile*>(idx, newTile));
                _tileSource->getTile(idx.x, idx.y, idx.z);
                newTile->draw();
            } else {
                foundTile->second->draw();
            }
        }
    }

    // clean up tiles we no longer display
    for (TileMap::iterator i=_tiles.begin(); i != _tiles.end();) {
        if (visibleTiles.find(i->first) == visibleTiles.end()) {
            delete i->second;
            i = _tiles.erase(i);
        } else {
            ++i;
        }
    }
}

BoundingBox
OsmLayer::getBoundingBox() const
{
    return BoundingBox();
}

MapPoint
OsmLayer::position() const
{
    return MapPoint(0., 0.);
}

void
OsmLayer::onTileReady(unsigned int x, unsigned int y, unsigned int z)
{
    OsmIndex idx = OsmIndex(x, y, z);
    TileMap::iterator i = _tiles.find(idx);
    if (i != _tiles.end()) {
        i->second->setTexture(_tileSource->retrieveFinishedTile(x, y, z));
        emit layerUpdated();
    }
}

OsmLayer::Tile::Tile() : texture(NULL), shader(NULL)
{

}

void
OsmLayer::Tile::draw()
{
    // debug, draw diagonal lines
    gl::color( Color( 1, 1, 1 ) );
    gl::drawLine(upperLeft, lowerRight);
    gl::drawLine(Vec2f(upperLeft.x, lowerRight.y),
                 Vec2f(lowerRight.x, upperLeft.y));
    // end debug diagonal lines
    if (texture != NULL) {
        texture->enableAndBind();
        shader->bind();
        shader->setUniformValue(shader->uniformLocation("tex0"), 0 );
        _drawQuad(upperLeft, lowerRight);
        texture->unbind();
        shader->release();
    }
}

void
OsmLayer::Tile::setTexture(const Surface8u &surface)
{
    texture = new cinder::gl::Texture(surface);
}

uint
OsmLayer::_getZoomLevel(double resolution) const
{
    uint i;
    for (i = 0; i < numZoomLevels && resolution < _resolutions[i]; i++) {}
    return i;
}

void
OsmLayer::_setup()
{
    _shader->addShaderFromSourceCode(QGLShader::Fragment,
                                     "#version 110\n\n"
                                     "uniform sampler2D tex0;\n"
                                     "void main()\n"
                                     "{\n"
                                     "gl_FragColor = texture2D( tex0, gl_TexCoord[0].st);\n"
                                     "}\n");
    _isSetup = true;
}

void
OsmLayer::_getTileXYAtMapPoint(const MapPoint &pos,
                               unsigned int *x,
                               unsigned int *y) const
{
    int px, py;
    px = int(floor(_numEdgeTiles * ((pos.x - _worldTopLeft.x) / _worldSize)));
    py = int(floor(_numEdgeTiles * (_worldTopLeft.y - pos.y) / _worldSize));
    *x = (px < 0) ? 0 : px;
    *y = (py < 0) ? 0 : py;
}

<|endoftext|>