/* +------------------------------------------------------------------------+
   |                     Mobile Robot Programming Toolkit (MRPT)            |
   |                          https://www.mrpt.org/                         |
   |                                                                        |
   | Copyright (c) 2005-2024, Individual contributors, see AUTHORS file     |
   | See: https://www.mrpt.org/Authors - All rights reserved.               |
   | Released under BSD License. See: https://www.mrpt.org/License          |
   +------------------------------------------------------------------------+ */
#include "CFormEdit.h"

#include <wx/msgdlg.h>

#include "xRawLogViewerMain.h"

//(*InternalHeaders(CFormEdit)
#include <wx/intl.h>
#include <wx/string.h>
//*)
#include <wx/app.h>
#include <wx/busyinfo.h>
#include <wx/filedlg.h>
#include <wx/imaglist.h>
#include <wx/progdlg.h>

// General global variables:
#include <mrpt/containers/stl_containers_utils.h>
#include <mrpt/io/CFileGZInputStream.h>
#include <mrpt/io/CFileGZOutputStream.h>
#include <mrpt/obs/CObservation2DRangeScan.h>
#include <mrpt/obs/CObservationImage.h>
#include <mrpt/obs/CObservationStereoImages.h>
#include <mrpt/serialization/CArchive.h>
#include <mrpt/system/filesystem.h>

using namespace mrpt;
using namespace mrpt::obs;
using namespace mrpt::opengl;
using namespace mrpt::system;
using namespace mrpt::img;
using namespace mrpt::math;
using namespace mrpt::containers;
using namespace mrpt::serialization;
using namespace mrpt::math;
using namespace mrpt::img;
using namespace mrpt::io;
using namespace std;

//(*IdInit(CFormEdit)
const long CFormEdit::ID_RADIOBUTTON1 = wxNewId();
const long CFormEdit::ID_RADIOBUTTON2 = wxNewId();
const long CFormEdit::ID_STATICTEXT22 = wxNewId();
const long CFormEdit::ID_TEXTCTRL11 = wxNewId();
const long CFormEdit::ID_BUTTON9 = wxNewId();
const long CFormEdit::ID_STATICTEXT23 = wxNewId();
const long CFormEdit::ID_TEXTCTRL12 = wxNewId();
const long CFormEdit::ID_BUTTON11 = wxNewId();
const long CFormEdit::ID_STATICTEXT1 = wxNewId();
const long CFormEdit::ID_SLIDER1 = wxNewId();
const long CFormEdit::ID_SPINCTRL1 = wxNewId();
const long CFormEdit::ID_STATICTEXT3 = wxNewId();
const long CFormEdit::ID_SLIDER2 = wxNewId();
const long CFormEdit::ID_SPINCTRL2 = wxNewId();
const long CFormEdit::ID_BUTTON1 = wxNewId();
const long CFormEdit::ID_BUTTON2 = wxNewId();
const long CFormEdit::ID_CHECKBOX1 = wxNewId();
const long CFormEdit::ID_CHECKBOX2 = wxNewId();
const long CFormEdit::ID_CHECKBOX3 = wxNewId();
const long CFormEdit::ID_CHECKBOX4 = wxNewId();
const long CFormEdit::ID_CHECKBOX5 = wxNewId();
const long CFormEdit::ID_BUTTON4 = wxNewId();
const long CFormEdit::ID_CHECKBOX6 = wxNewId();
const long CFormEdit::ID_CHECKBOX7 = wxNewId();
const long CFormEdit::ID_CHECKBOX8 = wxNewId();
const long CFormEdit::ID_CHECKBOX9 = wxNewId();
const long CFormEdit::ID_CHECKBOX10 = wxNewId();
const long CFormEdit::ID_BUTTON5 = wxNewId();
const long CFormEdit::ID_CHECKLISTBOX2 = wxNewId();
const long CFormEdit::ID_BUTTON7 = wxNewId();
const long CFormEdit::ID_BUTTON8 = wxNewId();
const long CFormEdit::ID_CHECKLISTBOX1 = wxNewId();
const long CFormEdit::ID_BUTTON10 = wxNewId();
const long CFormEdit::ID_BUTTON12 = wxNewId();
const long CFormEdit::ID_BUTTON13 = wxNewId();
const long CFormEdit::ID_STATICTEXT2 = wxNewId();
const long CFormEdit::ID_TEXTCTRL2 = wxNewId();
const long CFormEdit::ID_BUTTON3 = wxNewId();
const long CFormEdit::ID_BUTTON6 = wxNewId();
//*)

BEGIN_EVENT_TABLE(CFormEdit, wxDialog)
//(*EventTable(CFormEdit)
//*)
END_EVENT_TABLE()

CFormEdit::CFormEdit(wxWindow* parent, wxWindowID id)
{
  //(*Initialize(CFormEdit)
  wxFlexGridSizer* FlexGridSizer16;
  wxFlexGridSizer* FlexGridSizer10;
  wxFlexGridSizer* FlexGridSizer5;
  wxFlexGridSizer* FlexGridSizer15;
  wxFlexGridSizer* FlexGridSizer14;
  wxFlexGridSizer* FlexGridSizer13;
  wxFlexGridSizer* FlexGridSizer12;

  Create(
      parent, id, _("Edit the rawlog"), wxDefaultPosition, wxDefaultSize,
      wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER, _T("id"));
  FlexGridSizer1 = new wxFlexGridSizer(5, 1, 0, 0);
  FlexGridSizer1->AddGrowableCol(0);
  FlexGridSizer1->AddGrowableRow(0);
  FlexGridSizer1->AddGrowableRow(1);
  FlexGridSizer1->AddGrowableRow(2);
  FlexGridSizer1->AddGrowableRow(3);
  BoxSizer1 = new wxBoxSizer(wxHORIZONTAL);
  FlexGridSizer12 = new wxFlexGridSizer(1, 2, 0, 0);
  FlexGridSizer12->AddGrowableCol(0);
  FlexGridSizer12->AddGrowableCol(1);
  StaticBoxSizer6 = new wxStaticBoxSizer(wxHORIZONTAL, this, _("Apply to:"));
  BoxSizer4 = new wxBoxSizer(wxVERTICAL);
  BoxSizer5 = new wxBoxSizer(wxHORIZONTAL);
  FlexGridSizer7 = new wxFlexGridSizer(3, 4, 0, 0);
  FlexGridSizer7->AddGrowableCol(2);
  rbLoaded = new wxRadioButton(
      this, ID_RADIOBUTTON1, _("Loaded rawlog"), wxDefaultPosition, wxDefaultSize, 0,
      wxDefaultValidator, _T("ID_RADIOBUTTON1"));
  FlexGridSizer7->Add(rbLoaded, 1, wxALL | wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, 5);
  FlexGridSizer7->Add(-1, -1, 1, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 5);
  FlexGridSizer7->Add(-1, -1, 1, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 5);
  FlexGridSizer7->Add(-1, -1, 1, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 5);
  rbFile = new wxRadioButton(
      this, ID_RADIOBUTTON2, _("Rawlog in file:"), wxDefaultPosition, wxDefaultSize, 0,
      wxDefaultValidator, _T("ID_RADIOBUTTON2"));
  FlexGridSizer7->Add(rbFile, 1, wxALL | wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, 5);
  StaticText22 = new wxStaticText(
      this, ID_STATICTEXT22, _("Input file:"), wxDefaultPosition, wxDefaultSize, 0,
      _T("ID_STATICTEXT22"));
  FlexGridSizer7->Add(StaticText22, 1, wxALL | wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL, 5);
  txtInputFile = new wxTextCtrl(
      this, ID_TEXTCTRL11, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator,
      _T("ID_TEXTCTRL11"));
  FlexGridSizer7->Add(txtInputFile, 1, wxEXPAND, 5);
  btnPickInput = new wxButton(
      this, ID_BUTTON9, _("Select..."), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator,
      _T("ID_BUTTON9"));
  FlexGridSizer7->Add(
      btnPickInput, 1, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 0);
  FlexGridSizer7->Add(-1, -1, 1, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 5);
  StaticText23 = new wxStaticText(
      this, ID_STATICTEXT23, _("Output file:"), wxDefaultPosition, wxDefaultSize, 0,
      _T("ID_STATICTEXT23"));
  FlexGridSizer7->Add(StaticText23, 1, wxALL | wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL, 5);
  txtOutputFile = new wxTextCtrl(
      this, ID_TEXTCTRL12, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator,
      _T("ID_TEXTCTRL12"));
  FlexGridSizer7->Add(txtOutputFile, 1, wxEXPAND, 5);
  btnPickOut = new wxButton(
      this, ID_BUTTON11, _("Select..."), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator,
      _T("ID_BUTTON11"));
  FlexGridSizer7->Add(
      btnPickOut, 1, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 0);
  BoxSizer5->Add(FlexGridSizer7, 1, wxEXPAND, 0);
  BoxSizer4->Add(BoxSizer5, 1, wxEXPAND, 0);
  StaticBoxSizer6->Add(BoxSizer4, 1, wxEXPAND, 0);
  FlexGridSizer12->Add(StaticBoxSizer6, 1, wxEXPAND, 5);
  StaticBoxSizer1 = new wxStaticBoxSizer(wxHORIZONTAL, this, _("Apply changes to this range:"));
  FlexGridSizer2 = new wxFlexGridSizer(2, 3, 0, 0);
  FlexGridSizer2->AddGrowableCol(1);
  FlexGridSizer2->AddGrowableRow(0);
  FlexGridSizer2->AddGrowableRow(1);
  StaticText1 = new wxStaticText(
      this, ID_STATICTEXT1, _("First:"), wxDefaultPosition, wxDefaultSize, 0, _T("ID_STATICTEXT1"));
  FlexGridSizer2->Add(StaticText1, 1, wxALL | wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL, 5);
  slFrom = new wxSlider(
      this, ID_SLIDER1, 0, 0, 100, wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator,
      _T("ID_SLIDER1"));
  FlexGridSizer2->Add(slFrom, 1, wxEXPAND, 5);
  spinFirst = new wxSpinCtrl(
      this, ID_SPINCTRL1, _T("0"), wxDefaultPosition, wxDefaultSize, 0, 0, 100, 0,
      _T("ID_SPINCTRL1"));
  spinFirst->SetValue(_T("0"));
  FlexGridSizer2->Add(spinFirst, 1, wxALL | wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, 5);
  StaticText3 = new wxStaticText(
      this, ID_STATICTEXT3, _("Last:"), wxDefaultPosition, wxDefaultSize, 0, _T("ID_STATICTEXT3"));
  FlexGridSizer2->Add(StaticText3, 1, wxALL | wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL, 5);
  slTo = new wxSlider(
      this, ID_SLIDER2, 0, 0, 100, wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator,
      _T("ID_SLIDER2"));
  FlexGridSizer2->Add(slTo, 1, wxEXPAND, 5);
  spinLast = new wxSpinCtrl(
      this, ID_SPINCTRL2, _T("0"), wxDefaultPosition, wxDefaultSize, 0, 0, 100, 0,
      _T("ID_SPINCTRL2"));
  spinLast->SetValue(_T("0"));
  FlexGridSizer2->Add(spinLast, 1, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 5);
  StaticBoxSizer1->Add(FlexGridSizer2, 1, wxEXPAND, 0);
  FlexGridSizer12->Add(StaticBoxSizer1, 1, wxEXPAND, 5);
  BoxSizer1->Add(FlexGridSizer12, 1, wxEXPAND, 0);
  FlexGridSizer1->Add(BoxSizer1, 1, wxEXPAND, 0);
  BoxSizer2 = new wxBoxSizer(wxHORIZONTAL);
  btnKeep = new wxButton(
      this, ID_BUTTON1, _("Keep the selected range only..."), wxDefaultPosition, wxDefaultSize, 0,
      wxDefaultValidator, _T("ID_BUTTON1"));
  BoxSizer2->Add(btnKeep, 1, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 5);
  btnDelete = new wxButton(
      this, ID_BUTTON2, _("Remove the selected range..."), wxDefaultPosition, wxDefaultSize, 0,
      wxDefaultValidator, _T("ID_BUTTON2"));
  BoxSizer2->Add(btnDelete, 1, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 5);
  FlexGridSizer1->Add(BoxSizer2, 1, wxEXPAND, 0);
  FlexGridSizer8 = new wxFlexGridSizer(1, 2, 0, 0);
  FlexGridSizer8->AddGrowableCol(0);
  FlexGridSizer8->AddGrowableCol(1);
  StaticBoxSizer3 = new wxStaticBoxSizer(
      wxHORIZONTAL, this, _("Remove observations by index in sensorial frame:"));
  FlexGridSizer3 = new wxFlexGridSizer(1, 6, 0, 0);
  cbO0 = new wxCheckBox(
      this, ID_CHECKBOX1, _("0"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator,
      _T("ID_CHECKBOX1"));
  cbO0->SetValue(false);
  FlexGridSizer3->Add(cbO0, 1, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 5);
  cbO1 = new wxCheckBox(
      this, ID_CHECKBOX2, _("1"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator,
      _T("ID_CHECKBOX2"));
  cbO1->SetValue(false);
  FlexGridSizer3->Add(cbO1, 1, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 5);
  cbO2 = new wxCheckBox(
      this, ID_CHECKBOX3, _("2"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator,
      _T("ID_CHECKBOX3"));
  cbO2->SetValue(false);
  FlexGridSizer3->Add(cbO2, 1, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 5);
  cbO3 = new wxCheckBox(
      this, ID_CHECKBOX4, _("3"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator,
      _T("ID_CHECKBOX4"));
  cbO3->SetValue(false);
  FlexGridSizer3->Add(cbO3, 1, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 5);
  cbO4 = new wxCheckBox(
      this, ID_CHECKBOX5, _("4"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator,
      _T("ID_CHECKBOX5"));
  cbO4->SetValue(false);
  FlexGridSizer3->Add(cbO4, 1, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 5);
  btnDelObsIndx = new wxButton(
      this, ID_BUTTON4, _("Do it"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator,
      _T("ID_BUTTON4"));
  FlexGridSizer3->Add(
      btnDelObsIndx, 1, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 5);
  StaticBoxSizer3->Add(FlexGridSizer3, 1, wxEXPAND, 0);
  FlexGridSizer8->Add(StaticBoxSizer3, 1, wxEXPAND, 5);
  StaticBoxSizer4 = new wxStaticBoxSizer(
      wxHORIZONTAL, this, _("Remove actions by index in collection of actions:"));
  FlexGridSizer4 = new wxFlexGridSizer(1, 6, 0, 0);
  FlexGridSizer4->AddGrowableCol(5);
  FlexGridSizer4->AddGrowableRow(0);
  cbA0 = new wxCheckBox(
      this, ID_CHECKBOX6, _("0"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator,
      _T("ID_CHECKBOX6"));
  cbA0->SetValue(false);
  FlexGridSizer4->Add(cbA0, 1, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 5);
  cbA1 = new wxCheckBox(
      this, ID_CHECKBOX7, _("1"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator,
      _T("ID_CHECKBOX7"));
  cbA1->SetValue(false);
  FlexGridSizer4->Add(cbA1, 1, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 5);
  cbA2 = new wxCheckBox(
      this, ID_CHECKBOX8, _("2"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator,
      _T("ID_CHECKBOX8"));
  cbA2->SetValue(false);
  FlexGridSizer4->Add(cbA2, 1, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 5);
  cbA3 = new wxCheckBox(
      this, ID_CHECKBOX9, _("3"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator,
      _T("ID_CHECKBOX9"));
  cbA3->SetValue(false);
  FlexGridSizer4->Add(cbA3, 1, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 5);
  cbA4 = new wxCheckBox(
      this, ID_CHECKBOX10, _("4"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator,
      _T("ID_CHECKBOX10"));
  cbA4->SetValue(false);
  FlexGridSizer4->Add(cbA4, 1, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 5);
  btnRemActsIndx = new wxButton(
      this, ID_BUTTON5, _("Do it"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator,
      _T("ID_BUTTON5"));
  FlexGridSizer4->Add(
      btnRemActsIndx, 1, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 5);
  StaticBoxSizer4->Add(FlexGridSizer4, 1, wxEXPAND, 0);
  FlexGridSizer8->Add(StaticBoxSizer4, 1, wxEXPAND, 5);
  FlexGridSizer1->Add(FlexGridSizer8, 1, wxEXPAND, 0);
  FlexGridSizer9 = new wxFlexGridSizer(1, 2, 0, 0);
  FlexGridSizer9->AddGrowableCol(0);
  FlexGridSizer9->AddGrowableCol(1);
  StaticBoxSizer5 = new wxStaticBoxSizer(wxHORIZONTAL, this, _("Remove observations by CLASS:"));
  FlexGridSizer6 = new wxFlexGridSizer(2, 1, 0, 0);
  FlexGridSizer6->AddGrowableCol(0);
  FlexGridSizer5 = new wxFlexGridSizer(1, 1, 0, 0);
  FlexGridSizer5->AddGrowableCol(0);
  FlexGridSizer5->AddGrowableRow(0);
  cbObsClass = new wxCheckListBox(
      this, ID_CHECKLISTBOX2, wxDefaultPosition, wxSize(-1, 200), 0, nullptr, 0, wxDefaultValidator,
      _T("ID_CHECKLISTBOX2"));
  cbObsClass->SetMaxSize(wxSize(-1, 200));
  FlexGridSizer5->Add(cbObsClass, 1, wxEXPAND, 5);
  FlexGridSizer6->Add(FlexGridSizer5, 1, wxEXPAND, 0);
  FlexGridSizer10 = new wxFlexGridSizer(1, 2, 0, 0);
  FlexGridSizer10->AddGrowableCol(0);
  FlexGridSizer10->AddGrowableCol(1);
  btnRemoveObsClass = new wxButton(
      this, ID_BUTTON7, _("Remove selected..."), wxDefaultPosition, wxDefaultSize, 0,
      wxDefaultValidator, _T("ID_BUTTON7"));
  FlexGridSizer10->Add(
      btnRemoveObsClass, 1, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 5);
  btnRemoveAllButByClass = new wxButton(
      this, ID_BUTTON8, _("Remove all but selected..."), wxDefaultPosition, wxDefaultSize, 0,
      wxDefaultValidator, _T("ID_BUTTON8"));
  FlexGridSizer10->Add(
      btnRemoveAllButByClass, 1, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 5);
  FlexGridSizer6->Add(FlexGridSizer10, 1, wxEXPAND, 0);
  StaticBoxSizer5->Add(FlexGridSizer6, 1, wxEXPAND, 0);
  FlexGridSizer9->Add(StaticBoxSizer5, 1, wxEXPAND, 5);
  StaticBoxSizer7 = new wxStaticBoxSizer(wxHORIZONTAL, this, _("Remove observations by LABEL:"));
  FlexGridSizer11 = new wxFlexGridSizer(2, 1, 0, 0);
  FlexGridSizer11->AddGrowableCol(0);
  FlexGridSizer13 = new wxFlexGridSizer(1, 2, 0, 0);
  FlexGridSizer13->AddGrowableCol(0);
  FlexGridSizer13->AddGrowableRow(0);
  cbObsLabel = new wxCheckListBox(
      this, ID_CHECKLISTBOX1, wxDefaultPosition, wxSize(-1, 200), 0, nullptr, 0, wxDefaultValidator,
      _T("ID_CHECKLISTBOX1"));
  cbObsLabel->SetMaxSize(wxSize(-1, 200));
  FlexGridSizer13->Add(cbObsLabel, 1, wxEXPAND, 5);
  FlexGridSizer11->Add(FlexGridSizer13, 1, wxEXPAND, 0);
  FlexGridSizer14 = new wxFlexGridSizer(1, 2, 0, 0);
  FlexGridSizer14->AddGrowableCol(0);
  FlexGridSizer14->AddGrowableCol(1);
  btnRemByLabel = new wxButton(
      this, ID_BUTTON10, _("Remove matches..."), wxDefaultPosition, wxDefaultSize, 0,
      wxDefaultValidator, _T("ID_BUTTON10"));
  FlexGridSizer14->Add(
      btnRemByLabel, 1, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 5);
  btnRemByLabelNon = new wxButton(
      this, ID_BUTTON12, _("Remove non-matches..."), wxDefaultPosition, wxDefaultSize, 0,
      wxDefaultValidator, _T("ID_BUTTON12"));
  FlexGridSizer14->Add(
      btnRemByLabelNon, 1, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 5);
  FlexGridSizer11->Add(FlexGridSizer14, 1, wxEXPAND, 0);
  StaticBoxSizer7->Add(FlexGridSizer11, 1, wxEXPAND, 0);
  FlexGridSizer9->Add(StaticBoxSizer7, 1, wxEXPAND, 5);
  FlexGridSizer1->Add(FlexGridSizer9, 1, wxEXPAND, 0);
  FlexGridSizer16 = new wxFlexGridSizer(1, 2, 0, 0);
  FlexGridSizer16->AddGrowableCol(1);
  StaticBoxSizer2 = new wxStaticBoxSizer(wxHORIZONTAL, this, _("Miscellaneous"));
  FlexGridSizer15 = new wxFlexGridSizer(2, 3, 0, 0);
  btnLeaveHorizScans = new wxButton(
      this, ID_BUTTON13, _("Leave horizontal laser scans only..."), wxDefaultPosition,
      wxDefaultSize, 0, wxDefaultValidator, _T("ID_BUTTON13"));
  FlexGridSizer15->Add(btnLeaveHorizScans, 1, wxEXPAND, 5);
  StaticText2 = new wxStaticText(
      this, ID_STATICTEXT2, _("Max. pitch (deg):"), wxDefaultPosition, wxDefaultSize, 0,
      _T("ID_STATICTEXT2"));
  FlexGridSizer15->Add(
      StaticText2, 1, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 5);
  edMaxPitch = new wxTextCtrl(
      this, ID_TEXTCTRL2, _("1.5"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator,
      _T("ID_TEXTCTRL2"));
  FlexGridSizer15->Add(
      edMaxPitch, 1, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 5);
  btnImgSwap = new wxButton(
      this, ID_BUTTON3, _("Swap Red-Blue channels of all images..."), wxDefaultPosition,
      wxDefaultSize, 0, wxDefaultValidator, _T("ID_BUTTON3"));
  FlexGridSizer15->Add(
      btnImgSwap, 1, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 5);
  StaticBoxSizer2->Add(FlexGridSizer15, 1, wxEXPAND, 0);
  FlexGridSizer16->Add(
      StaticBoxSizer2, 1, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 5);
  btnClose = new wxButton(
      this, ID_BUTTON6, _("Close"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator,
      _T("ID_BUTTON6"));
  FlexGridSizer16->Add(btnClose, 1, wxALL | wxALIGN_RIGHT | wxALIGN_BOTTOM, 5);
  FlexGridSizer1->Add(FlexGridSizer16, 1, wxEXPAND, 0);
  SetSizer(FlexGridSizer1);
  FlexGridSizer1->Fit(this);
  FlexGridSizer1->SetSizeHints(this);
  Center();

  Bind(wxEVT_RADIOBUTTON, &CFormEdit::OnrbLoadedSelect, this, ID_RADIOBUTTON1);
  Bind(wxEVT_RADIOBUTTON, &CFormEdit::OnrbFileSelect, this, ID_RADIOBUTTON2);
  Bind(wxEVT_BUTTON, &CFormEdit::OnbtnPickInputClick, this, ID_BUTTON9);
  Bind(wxEVT_BUTTON, &CFormEdit::OnbtnPickOutClick, this, ID_BUTTON11);
  Bind(wxEVT_SCROLL_THUMBTRACK, &CFormEdit::OnslFirstCmdScrollChanged, this, ID_SLIDER1);
  Bind(wxEVT_SCROLL_CHANGED, &CFormEdit::OnslFirstCmdScrollChanged, this, ID_SLIDER1);
  Bind(wxEVT_SCROLL_THUMBTRACK, &CFormEdit::OnslToCmdScrollChanged, this, ID_SLIDER2);
  Bind(wxEVT_SCROLL_CHANGED, &CFormEdit::OnslToCmdScrollChanged, this, ID_SLIDER2);
  Bind(wxEVT_BUTTON, &CFormEdit::OnbtnKeepClick, this, ID_BUTTON1);
  Bind(wxEVT_BUTTON, &CFormEdit::OnbtnDeleteClick, this, ID_BUTTON2);
  Bind(wxEVT_BUTTON, &CFormEdit::OnbtnDelObsIndxClick, this, ID_BUTTON4);
  Bind(wxEVT_BUTTON, &CFormEdit::OnbtnRemActsIndxClick, this, ID_BUTTON5);
  Bind(wxEVT_BUTTON, &CFormEdit::OnbtnRemoveObsClassClick, this, ID_BUTTON7);
  Bind(wxEVT_BUTTON, &CFormEdit::OnbtnRemoveAllButByClassClick1, this, ID_BUTTON8);
  Bind(wxEVT_BUTTON, &CFormEdit::OnRemoveByLabel, this, ID_BUTTON10);
  Bind(wxEVT_BUTTON, &CFormEdit::OnRemoveButLabel, this, ID_BUTTON12);
  Bind(wxEVT_BUTTON, &CFormEdit::OnbtnLeaveHorizScansClick, this, ID_BUTTON13);
  Bind(wxEVT_BUTTON, &CFormEdit::OnbtnImgSwapClick, this, ID_BUTTON3);
  Bind(wxEVT_BUTTON, &CFormEdit::OnbtnCloseClick, this, ID_BUTTON6);
  Bind(wxEVT_INIT_DIALOG, &CFormEdit::OnInit, this, wxID_ANY);
  //*)
}

CFormEdit::~CFormEdit()
{
  //(*Destroy(CFormEdit)
  //*)
}

// Load the selected items from list box:
void loadSelectionsFromListBox(std::vector<std::string>& v, wxCheckListBox* c)
{
  v.clear();
  for (unsigned i = 0; i < c->GetCount(); i++)
    if (c->IsChecked(i)) v.emplace_back(c->GetString(i).mb_str());
}

void CFormEdit::OnbtnCloseClick(wxCommandEvent& event) { Close(); }
void CFormEdit::OnslFirstCmdScrollChanged(wxScrollEvent& event)
{
  int toVal = slTo->GetValue();
  int curVal = slFrom->GetValue();

  if (curVal > toVal) slFrom->SetValue(toVal);
  spinFirst->SetValue(slFrom->GetValue());
  // lbFirst->SetLabel( wxString::Format(_("%d"),slFrom->GetValue()) );
}

void CFormEdit::OnslToCmdScrollChanged(wxScrollEvent& event)
{
  int fromVal = spinFirst->GetValue();
  int curVal = slTo->GetValue();

  if (curVal < fromVal) slTo->SetValue(fromVal);
  //    lbLast->SetLabel( wxString::Format(_("%d"),slTo->GetValue()) );
  spinLast->SetValue(slTo->GetValue());
}

void CFormEdit::OnbtnKeepClick(wxCommandEvent& event)
{
  WX_START_TRY

  size_t n = rawlog.size();
  size_t first = spinFirst->GetValue();
  size_t last = spinLast->GetValue();

  ASSERT_(last < n);
  ASSERT_(last >= first);

  wxBusyCursor wait;

  if (last < n - 1) rawlog.remove(last + 1, n - 1);

  if (first > 0) rawlog.remove(0, first - 1);

  Close();

  WX_END_TRY
}

void CFormEdit::OnbtnDeleteClick(wxCommandEvent& event)
{
  WX_START_TRY

  size_t n = rawlog.size();
  size_t first = spinFirst->GetValue();
  size_t last = spinLast->GetValue();

  ASSERT_(last < n);
  ASSERT_(last >= first);

  wxBusyCursor wait;

  rawlog.remove(first, last);

  Close();

  WX_END_TRY
}

std::vector<bool> auxMask;

// Delete observations by index in their sensory frame.
void filter_delObsByIndex(
    mrpt::obs::CActionCollection* acts, mrpt::obs::CSensoryFrame* SF, int& changesCount)
{
  if (SF)
  {
    int j = 0;
    for (auto it = SF->begin(); it != SF->end(); ++j)
    {
      if (auxMask[j])
      {
        it = SF->erase(it);
        changesCount++;
      }
      else
        it++;
    }
  }
}

// Delete observations by index in their sensory frame.
void CFormEdit::OnbtnDelObsIndxClick(wxCommandEvent& event)
{
  WX_START_TRY

  auxMask.clear();
  auxMask.resize(5, false);
  auxMask[0] = cbO0->IsChecked();
  auxMask[1] = cbO1->IsChecked();
  auxMask[2] = cbO2->IsChecked();
  auxMask[3] = cbO3->IsChecked();
  auxMask[4] = cbO4->IsChecked();

  executeOperationOnRawlog(filter_delObsByIndex, "Observations deleted:");

  WX_END_TRY
}

// Remove observations by class name:
std::vector<std::string> classNameOfObsToRemove;

void filter_delObsByClass(
    mrpt::obs::CActionCollection* acts, mrpt::obs::CSensoryFrame* SF, int& changesCount)
{
  if (SF)
  {
    for (auto it = SF->begin(); it != SF->end();)
    {
      CObservation::Ptr obs = *it;
      if (string::npos !=
          find_in_vector(string(obs->GetRuntimeClass()->className), classNameOfObsToRemove))
      {
        // A match: Delete it:
        it = SF->erase(it);
        changesCount++;
      }
      else
        it++;
    }
  }
}

void filter_remObsByClass(
    mrpt::obs::CActionCollection* acts, mrpt::obs::CSensoryFrame* SF, int& changesCount)
{
  if (SF)
  {
    for (auto it = SF->begin(); it != SF->end();)
    {
      CObservation::Ptr obs = *it;
      if (string::npos ==
          find_in_vector(string(obs->GetRuntimeClass()->className), classNameOfObsToRemove))
      {
        // A NO match: Delete it:
        it = SF->erase(it);
      }
      else
        it++;
    }
  }
}

// Remove observations by class name:
void CFormEdit::OnbtnRemoveObsClassClick(wxCommandEvent& event)
{
  WX_START_TRY

  loadSelectionsFromListBox(classNameOfObsToRemove, cbObsClass);
  if (classNameOfObsToRemove.empty()) THROW_EXCEPTION("You must select one class name!");

  executeOperationOnRawlog(filter_delObsByClass, "Observations deleted:");
  Close();

  WX_END_TRY
}

// Delete actions by index.
void filter_delActsByIndex(
    mrpt::obs::CActionCollection* acts, mrpt::obs::CSensoryFrame* SF, int& changesCount)
{
  if (acts)
  {
    int j = 0;
    for (auto it = acts->begin(); it != acts->end(); ++j)
    {
      if (auxMask[j])
      {
        it = acts->erase(it);
        changesCount++;
      }
      else
        it++;
    }
  }
}

// Remove actions by index:
void CFormEdit::OnbtnRemActsIndxClick(wxCommandEvent& event)
{
  WX_START_TRY

  auxMask.clear();
  auxMask.resize(5, false);
  auxMask[0] = cbA0->IsChecked();
  auxMask[1] = cbA1->IsChecked();
  auxMask[2] = cbA2->IsChecked();
  auxMask[3] = cbA3->IsChecked();
  auxMask[4] = cbA4->IsChecked();

  executeOperationOnRawlog(filter_delActsByIndex, "Actions deleted:");

  WX_END_TRY
}

void swapColors(CImage& img)
{
  int lx = img.getWidth();
  int ly = img.getHeight();
  for (int y = 0; y < ly; y++)
  {
    for (int x = 0; x < lx; x++)
    {
      unsigned char* pixels = img(x, y);
      unsigned char temp = pixels[0];
      pixels[0] = pixels[2];
      pixels[2] = temp;
    }
  }
}

// Swap colors:
void filter_swapColors(
    mrpt::obs::CActionCollection* acts, mrpt::obs::CSensoryFrame* SF, int& changesCount)
{
  if (SF)
  {
    for (auto obs : *SF)
    {
      if (IS_CLASS(*obs, CObservationImage))
      {
        auto* o = (CObservationImage*)obs.get();
        if (o->image.isColor())
        {
          swapColors(o->image);
          changesCount++;
        }
      }
      else if (IS_CLASS(*obs, CObservationStereoImages))
      {
        auto* o = (CObservationStereoImages*)obs.get();
        if (o->imageLeft.isColor())
        {
          swapColors(o->imageLeft);
          changesCount++;
        }

        if (o->imageRight.isColor())
        {
          swapColors(o->imageRight);
          changesCount++;
        }
      }
    }
  }
}

// Swap colors:
void CFormEdit::OnbtnImgSwapClick(wxCommandEvent& event)
{
  WX_START_TRY
  executeOperationOnRawlog(filter_swapColors, "Individual images modified:");
  WX_END_TRY
}

void CFormEdit::OnInit(wxInitDialogEvent& event)
{
  Center();
  wxCommandEvent dumm;

  // Is there any rawlog loaded??
  if (!rawlog.size())
  {
    // NO: Disable "modify current":
    OnrbFileSelect(dumm);
    rbFile->SetValue(true);
    rbLoaded->Disable();
  }
  else
  {
    // Select the loaded rawlog by default:
    OnrbLoadedSelect(dumm);
    rbLoaded->SetValue(true);
  }  // end there is loaded rawlog

  FlexGridSizer1->Layout();
}

void CFormEdit::OnrbLoadedSelect(wxCommandEvent& event)
{
  btnPickInput->Disable();
  btnPickOut->Disable();
  txtOutputFile->Disable();
  txtInputFile->Disable();

  slFrom->Enable();
  slTo->Enable();
  spinFirst->Enable();
  spinLast->Enable();

  btnKeep->Enable();
  btnDelete->Enable();
}

void CFormEdit::OnrbFileSelect(wxCommandEvent& event)
{
  btnPickInput->Enable();
  btnPickOut->Enable();
  txtOutputFile->Enable();
  txtInputFile->Enable();

  slFrom->Disable();
  slTo->Disable();
  spinFirst->Disable();
  spinLast->Disable();

  btnKeep->Disable();
  btnDelete->Disable();
}

void CFormEdit::OnbtnRemoveAllButByClassClick1(wxCommandEvent& event)
{
  WX_START_TRY

  loadSelectionsFromListBox(classNameOfObsToRemove, cbObsClass);
  if (classNameOfObsToRemove.empty()) THROW_EXCEPTION("You must select one class name!");

  executeOperationOnRawlog(filter_remObsByClass, "Observations deleted:");
  Close();

  WX_END_TRY
}

void CFormEdit::OnbtnPickInputClick(wxCommandEvent& event)
{
  WX_START_TRY

  wxFileDialog dialog(
      this, _("Select input rawlog file") /* caption */,
      (iniFile->read_string(iniFileSect, "LastDir", ".").c_str()),
      _("*.rawlog") /* defaultFilename */,
      _("Rawlog files (*.rawlog,*.rawlog.gz)|*.rawlog;*.rawlog.gz|All files "
        "(*.*)|*.*") /* wildcard */,
      wxFD_OPEN | wxFD_FILE_MUST_EXIST);

  if (dialog.ShowModal() != wxID_OK) return;

  // Save the path
  WX_START_TRY
  iniFile->write(iniFileSect, "LastDir", std::string(dialog.GetDirectory().mb_str()));
  WX_END_TRY

  txtInputFile->SetValue(dialog.GetPath());

  WX_END_TRY
}

void CFormEdit::OnbtnPickOutClick(wxCommandEvent& event)
{
  WX_START_TRY

  wxFileDialog dialog(
      this, _("Select output rawlog file") /* caption */,
      (iniFile->read_string(iniFileSect, "LastDir", ".").c_str()),
      _("*.rawlog") /* defaultFilename */,
      _("Rawlog files (*.rawlog,*.rawlog.gz)|*.rawlog;*.rawlog.gz|All files "
        "(*.*)|*.*") /* wildcard */,
      wxFD_SAVE | wxFD_OVERWRITE_PROMPT);

  if (dialog.ShowModal() != wxID_OK) return;

  // Save the path
  WX_START_TRY
  iniFile->write(iniFileSect, "LastDir", std::string(dialog.GetDirectory().mb_str()));
  WX_END_TRY

  txtOutputFile->SetValue(dialog.GetPath());

  WX_END_TRY
}

/** This is the common function for all operations over a rawlog file ("filter"
 * a rawlog file into a new one) or over the loaded rawlog (depending on the
 * user selection in the GUI).
 */
void CFormEdit::executeOperationOnRawlog(TRawlogFilter operation, const char* endMsg)
{
  WX_START_TRY

  unsigned int processMax;
  bool isInMemory;
  CFileGZInputStream* in_fil = nullptr;
  CFileGZOutputStream* out_fil = nullptr;
  size_t first = 0, last = 0;

  if (rbLoaded->GetValue())
  {
    // APPLY TO rawlog in memory:
    isInMemory = true;

    processMax = (unsigned int)rawlog.size();
    first = spinFirst->GetValue();
    last = spinLast->GetValue();

    ASSERT_(last < processMax);
    ASSERT_(last >= first);
  }
  else
  {
    // APPLY TO rawlog files:
    isInMemory = false;

    if (!txtInputFile->GetValue().size()) THROW_EXCEPTION("An input rawlog file must be selected");
    if (!txtOutputFile->GetValue().size())
      THROW_EXCEPTION("An output rawlog file must be selected");

    string fileName_IN(txtInputFile->GetValue().mbc_str());
    if (!fileExists(fileName_IN)) THROW_EXCEPTION("Input file does not exist!");

    string fileName_OUT(txtOutputFile->GetValue().mbc_str());

    if (!fileName_OUT.compare(fileName_IN))
      THROW_EXCEPTION("Input and output files must be different!");

    in_fil = new CFileGZInputStream(fileName_IN);
    out_fil = new CFileGZOutputStream(fileName_OUT);

    processMax = (unsigned int)in_fil->getTotalBytesCount();
  }

  wxProgressDialog progDia(
      wxT("Modifying rawlog"), wxT("Processing..."),
      processMax,  // range
      this,        // parent
      wxPD_CAN_ABORT | wxPD_APP_MODAL | wxPD_SMOOTH | wxPD_AUTO_HIDE | wxPD_ELAPSED_TIME |
          wxPD_ESTIMATED_TIME | wxPD_REMAINING_TIME);

  CRawlogTreeView::RAWLOG_UNDERGOING_CHANGES = true;

  wxTheApp->Yield();  // Let the app. process messages

  unsigned int countLoop = 0;
  bool keepLoading = true;
  string errorMsg;
  wxString auxStr;

  CSensoryFrame::Ptr dummy_sf = std::make_shared<CSensoryFrame>();

  // Apply changes:
  int changes = 0;
  wxBusyCursor cursor;

  while ((!isInMemory && keepLoading) || (isInMemory && countLoop < rawlog.size()))
  {
    CSerializable::Ptr newObj;
    try
    {
      if (isInMemory)
      {
        try
        {
          newObj = rawlog.getAsGeneric(countLoop);
        }
        catch (std::exception&)
        {
          break;
        }
      }
      else
      {
        archiveFrom(*in_fil) >> newObj;
      }

      // Check type:
      if (newObj->GetRuntimeClass() == CLASS_ID(CRawlog))
      {
        THROW_EXCEPTION(
            "File is a 'CRawlog' object. Please save it as a sequence "
            "of actions/observations.");
      }
      else if (newObj->GetRuntimeClass() == CLASS_ID(CSensoryFrame))
      {
        // A sensory frame:
        CSensoryFrame::Ptr sf = std::dynamic_pointer_cast<CSensoryFrame>(newObj);

        // Process & save:
        if (!isInMemory || (countLoop >= first && countLoop <= last))
          operation(nullptr, sf.get(), changes);

        if (!isInMemory) archiveFrom(*out_fil) << *sf;
      }
      else if (newObj->GetRuntimeClass()->derivedFrom(CLASS_ID(CObservation)))
      {
        // A single observation:
        dummy_sf->clear();
        dummy_sf->insert(std::dynamic_pointer_cast<CObservation>(newObj));

        // Process & save:
        if (!isInMemory || (countLoop >= first && countLoop <= last))
          operation(nullptr, dummy_sf.get(), changes);

        // Still there?
        if (dummy_sf->size() == 1)
        {
          if (!isInMemory) archiveFrom(*out_fil) << *newObj;
        }
        else
        {
          if (isInMemory)
          {
            rawlog.remove(countLoop);
            countLoop--;
          }
        }
      }
      else if (newObj->GetRuntimeClass() == CLASS_ID(CActionCollection))
      {
        // This is an action:
        CActionCollection::Ptr acts = std::dynamic_pointer_cast<CActionCollection>(newObj);

        // Process & save:
        if (!isInMemory || (countLoop >= first && countLoop <= last))
          operation((CActionCollection*)acts.get(), nullptr, changes);

        if (!isInMemory) archiveFrom(*out_fil) << *acts;
      }
      else
      {  // Unknown class:
        THROW_EXCEPTION(format(
            "Unexpected class found in the file: '%s'", newObj->GetRuntimeClass()->className));
      }
    }
    catch (exception& e)
    {
      errorMsg = mrpt::exception_to_str(e);
      keepLoading = false;
    }
    catch (...)
    {
      keepLoading = false;
    }

    // Step counter & update progress dialog
    if (countLoop++ % 20 == 0)
    {
      auxStr.sprintf(wxT("Processing... (%u objects processed)"), countLoop);
      int curProgr = isInMemory ? countLoop : in_fil->getPosition();
      if (!progDia.Update(curProgr, auxStr)) keepLoading = false;
      wxTheApp->Yield();  // Let the app. process messages
    }

    // Delete only if processing file
    if (newObj && !isInMemory)
    {
      newObj.reset();
    }

  }  // end while keep loading

  progDia.Update(processMax);  // Close dialog.

  wxMessageBox(
      (format("%s %i\n\nEnd message:\n%s", endMsg, changes, errorMsg.c_str()).c_str()),
      _("Result:"), wxOK, this);

  if (in_fil) delete in_fil;
  if (out_fil) delete out_fil;

  WX_END_TRY

  CRawlogTreeView::RAWLOG_UNDERGOING_CHANGES = false;
}

// Remove observations by class name:
std::vector<std::string> labelOfObsToRemove;

void filter_delObsByLabel(
    mrpt::obs::CActionCollection* acts, mrpt::obs::CSensoryFrame* SF, int& changesCount)
{
  if (SF)
  {
    for (auto it = SF->begin(); it != SF->end();)
    {
      CObservation::Ptr obs = *it;
      if (string::npos != find_in_vector(obs->sensorLabel, labelOfObsToRemove))
      {
        // A match: Delete it:
        it = SF->erase(it);
        changesCount++;
      }
      else
        it++;
    }
  }
}

void filter_NotDelObsByLabel(
    mrpt::obs::CActionCollection* acts, mrpt::obs::CSensoryFrame* SF, int& changesCount)
{
  if (SF)
  {
    for (auto it = SF->begin(); it != SF->end();)
    {
      CObservation::Ptr obs = *it;
      if (string::npos == find_in_vector(obs->sensorLabel, labelOfObsToRemove))
      {
        // A match: Delete it:
        it = SF->erase(it);
        changesCount++;
      }
      else
        it++;
    }
  }
}

void CFormEdit::OnRemoveByLabel(wxCommandEvent& event)
{
  WX_START_TRY

  loadSelectionsFromListBox(labelOfObsToRemove, cbObsLabel);
  if (labelOfObsToRemove.empty()) THROW_EXCEPTION("You must select at least one label!");

  executeOperationOnRawlog(filter_delObsByLabel, "Observations deleted:");
  Close();

  WX_END_TRY
}

void CFormEdit::OnRemoveButLabel(wxCommandEvent& event)
{
  WX_START_TRY

  loadSelectionsFromListBox(labelOfObsToRemove, cbObsLabel);
  if (labelOfObsToRemove.empty()) THROW_EXCEPTION("You must select at least one label!");

  executeOperationOnRawlog(filter_NotDelObsByLabel, "Observations deleted:");
  Close();

  WX_END_TRY
}

void CFormEdit::OnslFromCmdScroll(wxScrollEvent& event) {}
void CFormEdit::OnslFromCmdScroll1(wxScrollEvent& event) {}
double minPitchToDeleteLaserScan = 1.2_deg;

void leave_horizontalScans(
    mrpt::obs::CActionCollection* acts, mrpt::obs::CSensoryFrame* SF, int& changesCount)
{
  if (SF)
  {
    for (auto it = SF->begin(); it != SF->end();)
    {
      CObservation::Ptr obs = *it;

      if (IS_CLASS(*obs, CObservation2DRangeScan))
      {
        auto* o = static_cast<CObservation2DRangeScan*>(obs.get());

        if (fabs(o->sensorPose.pitch()) > minPitchToDeleteLaserScan)
        {
          it = SF->erase(it);
        }
        else
        {
          changesCount++;  // Count success
          it++;
        }
      }
      else
        it++;
    }
  }
}

// Leave horizontal scans only:
void CFormEdit::OnbtnLeaveHorizScansClick(wxCommandEvent& event)
{
  WX_START_TRY

  minPitchToDeleteLaserScan = atof(string(edMaxPitch->GetValue().mb_str()).c_str());
  executeOperationOnRawlog(leave_horizontalScans, "Laser scans that passed the filter: ");

  WX_END_TRY
}
