diff --git a/CMakeLists.txt b/CMakeLists.txt
index 647ff5ee57918209b4fb681f18dca50ea110207b..3a79bd57b7a3041fcd8c4a96db2f1ace248a371f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -9,7 +9,7 @@
 cmake_minimum_required( VERSION 3.1 FATAL_ERROR )
 
 # visimpl project and version
-project( visimpl VERSION 1.6.0 )
+project( visimpl VERSION 1.6.1 )
 set( visimpl_VERSION_ABI 6 )
 
 SET( VISIMPL_LICENSE "GPL")
diff --git a/visimpl/MainWindow.cpp b/visimpl/MainWindow.cpp
index d114bbc1feac056ab85365c4bd84d9162326561b..774c800c991c5635b566ad77995652b810c13150 100644
--- a/visimpl/MainWindow.cpp
+++ b/visimpl/MainWindow.cpp
@@ -2413,10 +2413,10 @@ void MainWindow::clearGroups( void )
 
     const QFileInfo currentFile{_lastOpenedNetworkFileName};
     const QString jsonGroupsFile = jsonObj.value("filename").toString();
-    if(jsonGroupsFile.compare(currentFile.fileName(), Qt::CaseInsensitive) != 0)
+    if(!jsonGroupsFile.isEmpty() && jsonGroupsFile.compare(currentFile.fileName(), Qt::CaseInsensitive) != 0)
     {
-      const auto message = tr("This groups definitions are from file %1. Current file"
-                              " is %2. Do you want to continue?").arg(jsonGroupsFile).arg(currentFile.fileName());
+      const auto message = tr("This groups definitions are from file '%1'. Current file"
+                              " is '%2'. Do you want to continue?").arg(jsonGroupsFile).arg(currentFile.fileName());
 
       QMessageBox msgbox{this};
       msgbox.setWindowTitle(title);
@@ -2733,7 +2733,7 @@ void MainWindow::clearGroups( void )
     const auto numActions = actions.size();
     if(numActions > 0)
     {
-      const auto warnText = tr("Loading new camera positions will erase"
+      const auto warnText = tr("Loading new camera positions will remove"
                                " %1 existing position%2. Are you sure?").arg(numActions).arg(numActions > 1 ? "s":"");
       if(QMessageBox::Ok != QMessageBox::warning(this, title, warnText, QMessageBox::Cancel|QMessageBox::Ok))
         return;
@@ -2807,6 +2807,25 @@ void MainWindow::clearGroups( void )
       return;
     }
 
+    const QFileInfo currentFile{_lastOpenedNetworkFileName};
+    const QString jsonPositionsFile = jsonObj.value("filename").toString();
+    if(!jsonPositionsFile.isEmpty() && jsonPositionsFile.compare(currentFile.fileName(), Qt::CaseInsensitive) != 0)
+    {
+      const auto message = tr("This positions are from file '%1'. Current file"
+                              " is '%2'. Do you want to continue?").arg(jsonPositionsFile).arg(currentFile.fileName());
+
+      QMessageBox msgbox{this};
+      msgbox.setWindowTitle(title);
+      msgbox.setIcon(QMessageBox::Icon::Question);
+      msgbox.setText(message);
+      msgbox.setWindowIcon(QIcon(":/visimpl.png"));
+      msgbox.setStandardButtons(QMessageBox::Cancel|QMessageBox::Ok);
+      msgbox.setDefaultButton(QMessageBox::Ok);
+
+      if(QMessageBox::Ok != msgbox.exec())
+        return;
+    }
+
     // Clear existing actions before entering new ones.
     for(auto action: actions)
     {
@@ -2844,19 +2863,29 @@ void MainWindow::clearGroups( void )
   {
     const QString nameFilter = "Camera positions (*.json)";
     QDir directory;
+    QString filename;
 
     if(_lastOpenedNetworkFileName.isEmpty())
+    {
       directory = QDir::home();
+      filename = "positions.json";
+    }
     else
-      directory = QFileInfo(_lastOpenedNetworkFileName).dir();
+    {
+      QFileInfo fi(_lastOpenedNetworkFileName);
+      directory = fi.dir();
+      filename = QString("%1_positions.json").arg(fi.baseName());
+    }
 
     QFileDialog fDialog(this);
     fDialog.setWindowIcon(QIcon(":/visimpl.png"));
     fDialog.setWindowTitle("Save camera positions");
     fDialog.setAcceptMode(QFileDialog::AcceptMode::AcceptSave);
     fDialog.setDefaultSuffix("json");
+    fDialog.selectFile(filename);
     fDialog.setDirectory(directory);
     fDialog.setOption(QFileDialog::Option::DontUseNativeDialog, true);
+    fDialog.setOption(QFileDialog::Option::DontConfirmOverwrite, false);
     fDialog.setFileMode(QFileDialog::FileMode::AnyFile);
     fDialog.setNameFilters(QStringList{nameFilter});
     fDialog.setNameFilter(nameFilter);
@@ -2866,7 +2895,7 @@ void MainWindow::clearGroups( void )
 
     if(fDialog.selectedFiles().empty()) return;
 
-    const auto filename = fDialog.selectedFiles().first();
+    filename = fDialog.selectedFiles().first();
 
     QFile wFile{filename};
     if(!wFile.open(QIODevice::WriteOnly|QIODevice::Text|QIODevice::Truncate))
@@ -2910,6 +2939,7 @@ void MainWindow::clearGroups( void )
     std::for_each(actions.cbegin(), actions.cend(), insertPosition);
 
     QJsonObject obj;
+    obj.insert("filename", QFileInfo{_lastOpenedNetworkFileName}.fileName());
     obj.insert("positions", positionsObjs);
 
     QJsonDocument doc{obj};
diff --git a/visimpl/OpenGLWidget.cpp b/visimpl/OpenGLWidget.cpp
index b7bc98789ceae3f98b33cf1235a0450d737342b6..ec033811bac9d7569a7f9cb84eaa4cda35e6011a 100644
--- a/visimpl/OpenGLWidget.cpp
+++ b/visimpl/OpenGLWidget.cpp
@@ -1356,6 +1356,7 @@ void main()
     _gidPositions.clear( );
     _gidPositions.reserve( positions.size( ));
 
+    vec3 bbmin, bbmax;
     auto gidit = _player->gids( ).cbegin( );
     auto insertElement = [ & ]( const vmml::Vector3f& v )
     {
@@ -1364,9 +1365,28 @@ void main()
                            v.z( ) * _scaleFactor.z );
 
       _gidPositions.insert( std::make_pair( *gidit , position ));
+      if(gidit == _player->gids().cbegin())
+      {
+        bbmin = bbmax = position;
+      }
+      else
+      {
+        auto x = std::min(bbmin.x, position.x);
+        auto y = std::min(bbmin.y, position.y);
+        auto z = std::min(bbmin.z, position.z);
+        bbmin = vec3{x,y,z};
+
+        x = std::max(bbmax.x, position.x);
+        y = std::max(bbmax.y, position.y);
+        z = std::max(bbmax.z, position.z);
+        bbmax = vec3{x,y,z};
+      }
       ++gidit;
     };
     std::for_each( positions.cbegin( ) , positions.cend( ) , insertElement );
+
+    _boundingBoxHome = tBoundingBox{ bbmin, bbmax };
+
     return true;
   }
 
diff --git a/visimpl/OpenGLWidget.h b/visimpl/OpenGLWidget.h
index acfe5f8c17852e7453101cd383b51660586411ef..482f1382ed6534862a3b18fa28c04cd785288234 100644
--- a/visimpl/OpenGLWidget.h
+++ b/visimpl/OpenGLWidget.h
@@ -37,6 +37,8 @@
 #include <chrono>
 #include <unordered_set>
 #include <queue>
+#include <locale>
+#include <iostream>
 
 #define VISIMPL_SKIP_GLEW_INCLUDE 1
 
@@ -65,6 +67,11 @@ class QLabel;
 class LoadingDialog;
 class LoaderThread;
 
+struct streamDotSeparator: std::numpunct<char>
+{
+    char do_decimal_point() const { return '.'; }
+};
+
 namespace visimpl
 {
   /** \class CameraPosition
@@ -93,19 +100,29 @@ namespace visimpl
        */
       CameraPosition(const QString &data)
       {
-        const auto parts = data.split(";");
+        const auto separator = std::use_facet<std::numpunct<char>>(std::cout.getloc()).decimal_point();
+        const bool needSubst = (separator == ',');
+
+        auto parts = data.split(";");
         Q_ASSERT(parts.size() == 3);
         const auto posData = parts.first();
         const auto rotData = parts.last();
-        radius = parts.at(1).toFloat();
+        auto radiusData = parts.at(1);
 
-        const auto posParts = posData.split(",");
+        auto posParts = posData.split(",");
         Q_ASSERT(posParts.size() == 3);
-        const auto rotParts = rotData.split(",");
+        auto rotParts = rotData.split(",");
         Q_ASSERT(rotParts.size() == 9);
 
+        if(needSubst)
+        {
+          for(auto &part: posParts) part.replace('.', ',');
+          for(auto &part: rotParts) part.replace('.', ',');
+          radiusData.replace('.', ',');
+        }
+
         position = Eigen::Vector3f(posParts[0].toFloat(), posParts[1].toFloat(), posParts[2].toFloat());
-        radius = parts.at(1).toFloat();
+        radius = radiusData.toFloat();
         rotation.block<1,3>(0,0) = Eigen::Vector3f{rotParts[0].toFloat(), rotParts[1].toFloat(), rotParts[2].toFloat()};
         rotation.block<1,3>(1,0) = Eigen::Vector3f{rotParts[3].toFloat(), rotParts[4].toFloat(), rotParts[5].toFloat()};
         rotation.block<1,3>(2,0) = Eigen::Vector3f{rotParts[6].toFloat(), rotParts[7].toFloat(), rotParts[8].toFloat()};
@@ -117,6 +134,7 @@ namespace visimpl
       QString toString() const
       {
         std::stringstream stream;
+        stream.imbue(std::locale(stream.getloc(), new streamDotSeparator()));
         stream << position << ";" << radius << ";"
                << rotation(0,0) << "," << rotation(0,1) << "," << rotation(0,2) << ","
                << rotation(1,0) << "," << rotation(1,1) << "," << rotation(1,2) << ","