Commit 4ba50364 authored by Alexander Stukowski's avatar Alexander Stukowski

Added the 'Sort particles by ID' option to file readers, which allows…

Added the 'Sort particles by ID' option to file readers, which allows automatically reordering the imported particles according to ascending identifiers
parent 7666295d
Pipeline #25800104 failed with stage
in 49 minutes and 17 seconds
......@@ -35,7 +35,7 @@
<simplesect xml:id="usage.import.sequence">
<title>Simulation sequences</title>
<para>
OVITO can load and animate simulation trajectories that consist of a sequence of snapshots or frames.
OVITO can load and animate simulation trajectories that consist of a sequence of frames.
The following scenarios are supported by the software:
<variablelist>
<varlistentry><term>Series of files:</term><listitem>
......
......@@ -215,7 +215,14 @@ public:
template<typename FC>
void finally_future(FC&& cont) { finally_future(detail::InlineExecutor(), std::forward<FC>(cont)); }
#ifndef Q_CC_GNU
protected:
#else
// This is a workaround for what is likely a bug in the GCC compiler, which doesn't respect the
// template fiend class declarations made below. The AsynchronousTask<> template specialization
// doesn't seem to get access to the Future constructor.
public:
#endif
/// Constructor that constructs a Future that is associated with the given shared state.
explicit Future(PromiseStatePtr p) noexcept : FutureBase(std::move(p)) {}
......
......@@ -669,6 +669,11 @@ FileSourceImporter::FrameDataPtr AMBERNetCDFImporter::FrameLoader::loadFile(QFil
}
closeNetCDF();
// Sort particles by ID if requested.
if(_sortParticles)
frameData->sortParticlesById();
frameData->setStatus(tr("Loaded %1 particles").arg(particleCount));
return frameData;
}
......
......@@ -74,7 +74,7 @@ public:
/// Creates an asynchronous loader object that loads the data for the given frame from the external file.
virtual std::shared_ptr<FileSourceImporter::FrameLoader> createFrameLoader(const Frame& frame, const QString& localFilename) override {
return std::make_shared<FrameLoader>(frame, localFilename, useCustomColumnMapping(), customColumnMapping());
return std::make_shared<FrameLoader>(frame, localFilename, sortParticles(), useCustomColumnMapping(), customColumnMapping());
}
/// Creates an asynchronous frame discovery object that scans the input file for contained animation frames.
......@@ -109,8 +109,9 @@ private:
/// Normal constructor.
FrameLoader(const FileSourceImporter::Frame& frame, const QString& filename,
bool sortParticles,
bool useCustomColumnMapping, const InputColumnMapping& customColumnMapping)
: FileSourceImporter::FrameLoader(frame, filename), _parseFileHeaderOnly(false), _useCustomColumnMapping(useCustomColumnMapping), _customColumnMapping(customColumnMapping) {}
: FileSourceImporter::FrameLoader(frame, filename), _parseFileHeaderOnly(false), _sortParticles(sortParticles), _useCustomColumnMapping(useCustomColumnMapping), _customColumnMapping(customColumnMapping) {}
/// Constructor used when reading only the file header information.
FrameLoader(const FileSourceImporter::Frame& frame, const QString& filename)
......@@ -146,6 +147,7 @@ private:
void closeNetCDF();
bool _parseFileHeaderOnly;
bool _sortParticles;
bool _useCustomColumnMapping;
InputColumnMapping _customColumnMapping;
};
......
......@@ -95,8 +95,17 @@ void AMBERNetCDFImporterEditor::createUI(const RolloutInsertionParameters& rollo
layout->setContentsMargins(4,4,4,4);
layout->setSpacing(4);
QGroupBox* optionsBox = new QGroupBox(tr("Options"), rollout);
QVBoxLayout* sublayout = new QVBoxLayout(optionsBox);
sublayout->setContentsMargins(4,4,4,4);
layout->addWidget(optionsBox);
// Sort particles
BooleanParameterUI* sortParticlesUI = new BooleanParameterUI(this, PROPERTY_FIELD(ParticleImporter::sortParticles));
sublayout->addWidget(sortParticlesUI->checkBox());
QGroupBox* columnMappingBox = new QGroupBox(tr("File columns"), rollout);
QVBoxLayout* sublayout = new QVBoxLayout(columnMappingBox);
sublayout = new QVBoxLayout(columnMappingBox);
sublayout->setContentsMargins(4,4,4,4);
layout->addWidget(columnMappingBox);
......
......@@ -59,6 +59,9 @@ SET(SourceFiles
import/lammps/LAMMPSTextDumpImporterEditor.cpp
import/lammps/LAMMPSBinaryDumpImporterEditor.cpp
import/lammps/LAMMPSDataImporterEditor.cpp
import/parcas/ParcasFileImporterEditor.cpp
import/imd/IMDImporterEditor.cpp
import/cfg/CFGImporterEditor.cpp
import/xyz/XYZImporterEditor.cpp
export/FileColumnParticleExporterEditor.cpp
export/lammps/LAMMPSDataExporterEditor.cpp
......
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (2018) Alexander Stukowski
//
// This file is part of OVITO (Open Visualization Tool).
//
// OVITO is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// OVITO is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
///////////////////////////////////////////////////////////////////////////////
#include <plugins/particles/gui/ParticlesGui.h>
#include <plugins/particles/import/cfg/CFGImporter.h>
#include <gui/properties/BooleanParameterUI.h>
#include "CFGImporterEditor.h"
namespace Ovito { namespace Particles { OVITO_BEGIN_INLINE_NAMESPACE(Import) OVITO_BEGIN_INLINE_NAMESPACE(Formats) OVITO_BEGIN_INLINE_NAMESPACE(Internal)
IMPLEMENT_OVITO_CLASS(CFGImporterEditor);
SET_OVITO_OBJECT_EDITOR(CFGImporter, CFGImporterEditor);
/******************************************************************************
* Sets up the UI widgets of the editor.
******************************************************************************/
void CFGImporterEditor::createUI(const RolloutInsertionParameters& rolloutParams)
{
// Create a rollout.
QWidget* rollout = createRollout(tr("CFG reader"), rolloutParams);
// Create the rollout contents.
QVBoxLayout* layout = new QVBoxLayout(rollout);
layout->setContentsMargins(4,4,4,4);
layout->setSpacing(4);
QGroupBox* optionsBox = new QGroupBox(tr("Options"), rollout);
QVBoxLayout* sublayout = new QVBoxLayout(optionsBox);
sublayout->setContentsMargins(4,4,4,4);
layout->addWidget(optionsBox);
// Sort particles
BooleanParameterUI* sortParticlesUI = new BooleanParameterUI(this, PROPERTY_FIELD(ParticleImporter::sortParticles));
sublayout->addWidget(sortParticlesUI->checkBox());
}
OVITO_END_INLINE_NAMESPACE
OVITO_END_INLINE_NAMESPACE
OVITO_END_INLINE_NAMESPACE
} // End of namespace
} // End of namespace
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (2018) Alexander Stukowski
//
// This file is part of OVITO (Open Visualization Tool).
//
// OVITO is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// OVITO is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
///////////////////////////////////////////////////////////////////////////////
#pragma once
#include <plugins/particles/gui/ParticlesGui.h>
#include <gui/dataset/io/FileImporterEditor.h>
namespace Ovito { namespace Particles { OVITO_BEGIN_INLINE_NAMESPACE(Import) OVITO_BEGIN_INLINE_NAMESPACE(Formats) OVITO_BEGIN_INLINE_NAMESPACE(Internal)
/**
* \brief A properties editor for the CFGImporter class.
*/
class CFGImporterEditor : public FileImporterEditor
{
OVITO_CLASS(CFGImporterEditor)
Q_OBJECT
public:
/// Constructor.
Q_INVOKABLE CFGImporterEditor() {}
protected:
/// Creates the user interface controls for the editor.
virtual void createUI(const RolloutInsertionParameters& rolloutParams) override;
};
OVITO_END_INLINE_NAMESPACE
OVITO_END_INLINE_NAMESPACE
OVITO_END_INLINE_NAMESPACE
} // End of namespace
} // End of namespace
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (2018) Alexander Stukowski
//
// This file is part of OVITO (Open Visualization Tool).
//
// OVITO is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// OVITO is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
///////////////////////////////////////////////////////////////////////////////
#include <plugins/particles/gui/ParticlesGui.h>
#include <plugins/particles/import/imd/IMDImporter.h>
#include <gui/properties/BooleanParameterUI.h>
#include "IMDImporterEditor.h"
namespace Ovito { namespace Particles { OVITO_BEGIN_INLINE_NAMESPACE(Import) OVITO_BEGIN_INLINE_NAMESPACE(Formats) OVITO_BEGIN_INLINE_NAMESPACE(Internal)
IMPLEMENT_OVITO_CLASS(IMDImporterEditor);
SET_OVITO_OBJECT_EDITOR(IMDImporter, IMDImporterEditor);
/******************************************************************************
* Sets up the UI widgets of the editor.
******************************************************************************/
void IMDImporterEditor::createUI(const RolloutInsertionParameters& rolloutParams)
{
// Create a rollout.
QWidget* rollout = createRollout(tr("IMD reader"), rolloutParams);
// Create the rollout contents.
QVBoxLayout* layout = new QVBoxLayout(rollout);
layout->setContentsMargins(4,4,4,4);
layout->setSpacing(4);
QGroupBox* optionsBox = new QGroupBox(tr("Options"), rollout);
QVBoxLayout* sublayout = new QVBoxLayout(optionsBox);
sublayout->setContentsMargins(4,4,4,4);
layout->addWidget(optionsBox);
// Sort particles
BooleanParameterUI* sortParticlesUI = new BooleanParameterUI(this, PROPERTY_FIELD(ParticleImporter::sortParticles));
sublayout->addWidget(sortParticlesUI->checkBox());
}
OVITO_END_INLINE_NAMESPACE
OVITO_END_INLINE_NAMESPACE
OVITO_END_INLINE_NAMESPACE
} // End of namespace
} // End of namespace
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (2018) Alexander Stukowski
//
// This file is part of OVITO (Open Visualization Tool).
//
// OVITO is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// OVITO is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
///////////////////////////////////////////////////////////////////////////////
#pragma once
#include <plugins/particles/gui/ParticlesGui.h>
#include <gui/dataset/io/FileImporterEditor.h>
namespace Ovito { namespace Particles { OVITO_BEGIN_INLINE_NAMESPACE(Import) OVITO_BEGIN_INLINE_NAMESPACE(Formats) OVITO_BEGIN_INLINE_NAMESPACE(Internal)
/**
* \brief A properties editor for the IMDImporter class.
*/
class IMDImporterEditor : public FileImporterEditor
{
OVITO_CLASS(IMDImporterEditor)
Q_OBJECT
public:
/// Constructor.
Q_INVOKABLE IMDImporterEditor() {}
protected:
/// Creates the user interface controls for the editor.
virtual void createUI(const RolloutInsertionParameters& rolloutParams) override;
};
OVITO_END_INLINE_NAMESPACE
OVITO_END_INLINE_NAMESPACE
OVITO_END_INLINE_NAMESPACE
} // End of namespace
} // End of namespace
......@@ -105,22 +105,26 @@ bool LAMMPSBinaryDumpImporterEditor::showEditColumnMappingDialog(LAMMPSBinaryDum
void LAMMPSBinaryDumpImporterEditor::createUI(const RolloutInsertionParameters& rolloutParams)
{
// Create a rollout.
QWidget* rollout = createRollout(tr("LAMMPS binary dump"), rolloutParams);
QWidget* rollout = createRollout(tr("LAMMPS binary dump reader"), rolloutParams);
// Create the rollout contents.
QVBoxLayout* layout = new QVBoxLayout(rollout);
layout->setContentsMargins(4,4,4,4);
layout->setSpacing(4);
QGroupBox* animFramesBox = new QGroupBox(tr("Timesteps"), rollout);
QVBoxLayout* sublayout = new QVBoxLayout(animFramesBox);
QGroupBox* optionsBox = new QGroupBox(tr("Options"), rollout);
QVBoxLayout* sublayout = new QVBoxLayout(optionsBox);
sublayout->setContentsMargins(4,4,4,4);
layout->addWidget(animFramesBox);
layout->addWidget(optionsBox);
// Multi-timestep file
BooleanParameterUI* multitimestepUI = new BooleanParameterUI(this, PROPERTY_FIELD(ParticleImporter::isMultiTimestepFile));
sublayout->addWidget(multitimestepUI->checkBox());
// Sort particles
BooleanParameterUI* sortParticlesUI = new BooleanParameterUI(this, PROPERTY_FIELD(ParticleImporter::sortParticles));
sublayout->addWidget(sortParticlesUI->checkBox());
QGroupBox* columnMappingBox = new QGroupBox(tr("File columns"), rollout);
sublayout = new QVBoxLayout(columnMappingBox);
sublayout->setContentsMargins(4,4,4,4);
......
......@@ -22,6 +22,7 @@
#include <plugins/particles/gui/ParticlesGui.h>
#include <plugins/particles/import/lammps/LAMMPSDataImporter.h>
#include <core/app/PluginManager.h>
#include <gui/properties/BooleanParameterUI.h>
#include "LAMMPSDataImporterEditor.h"
namespace Ovito { namespace Particles { OVITO_BEGIN_INLINE_NAMESPACE(Import) OVITO_BEGIN_INLINE_NAMESPACE(Formats) OVITO_BEGIN_INLINE_NAMESPACE(Internal)
......@@ -90,7 +91,22 @@ bool LAMMPSDataImporterEditor::inspectNewFile(FileImporter* importer, const QUrl
******************************************************************************/
void LAMMPSDataImporterEditor::createUI(const RolloutInsertionParameters& rolloutParams)
{
// This editor class provides to UI.
// Create a rollout.
QWidget* rollout = createRollout(tr("LAMMPS data reader"), rolloutParams);
// Create the rollout contents.
QVBoxLayout* layout = new QVBoxLayout(rollout);
layout->setContentsMargins(4,4,4,4);
layout->setSpacing(4);
QGroupBox* optionsBox = new QGroupBox(tr("Options"), rollout);
QVBoxLayout* sublayout = new QVBoxLayout(optionsBox);
sublayout->setContentsMargins(4,4,4,4);
layout->addWidget(optionsBox);
// Sort particles
BooleanParameterUI* sortParticlesUI = new BooleanParameterUI(this, PROPERTY_FIELD(ParticleImporter::sortParticles));
sublayout->addWidget(sortParticlesUI->checkBox());
}
OVITO_END_INLINE_NAMESPACE
......
......@@ -69,22 +69,26 @@ bool LAMMPSTextDumpImporterEditor::showEditColumnMappingDialog(LAMMPSTextDumpImp
void LAMMPSTextDumpImporterEditor::createUI(const RolloutInsertionParameters& rolloutParams)
{
// Create a rollout.
QWidget* rollout = createRollout(tr("LAMMPS dump"), rolloutParams);
QWidget* rollout = createRollout(tr("LAMMPS dump reader"), rolloutParams);
// Create the rollout contents.
QVBoxLayout* layout = new QVBoxLayout(rollout);
layout->setContentsMargins(4,4,4,4);
layout->setSpacing(4);
QGroupBox* animFramesBox = new QGroupBox(tr("Timesteps"), rollout);
QVBoxLayout* sublayout = new QVBoxLayout(animFramesBox);
QGroupBox* optionsBox = new QGroupBox(tr("Options"), rollout);
QVBoxLayout* sublayout = new QVBoxLayout(optionsBox);
sublayout->setContentsMargins(4,4,4,4);
layout->addWidget(animFramesBox);
layout->addWidget(optionsBox);
// Multi-timestep file
BooleanParameterUI* multitimestepUI = new BooleanParameterUI(this, PROPERTY_FIELD(ParticleImporter::isMultiTimestepFile));
sublayout->addWidget(multitimestepUI->checkBox());
// Sort particles
BooleanParameterUI* sortParticlesUI = new BooleanParameterUI(this, PROPERTY_FIELD(ParticleImporter::sortParticles));
sublayout->addWidget(sortParticlesUI->checkBox());
QGroupBox* columnMappingBox = new QGroupBox(tr("File columns"), rollout);
sublayout = new QVBoxLayout(columnMappingBox);
sublayout->setContentsMargins(4,4,4,4);
......
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (2018) Alexander Stukowski
//
// This file is part of OVITO (Open Visualization Tool).
//
// OVITO is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// OVITO is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
///////////////////////////////////////////////////////////////////////////////
#include <plugins/particles/gui/ParticlesGui.h>
#include <plugins/particles/import/parcas/ParcasFileImporter.h>
#include <gui/properties/BooleanParameterUI.h>
#include "ParcasFileImporterEditor.h"
namespace Ovito { namespace Particles { OVITO_BEGIN_INLINE_NAMESPACE(Import) OVITO_BEGIN_INLINE_NAMESPACE(Formats) OVITO_BEGIN_INLINE_NAMESPACE(Internal)
IMPLEMENT_OVITO_CLASS(ParcasFileImporterEditor);
SET_OVITO_OBJECT_EDITOR(ParcasFileImporter, ParcasFileImporterEditor);
/******************************************************************************
* Sets up the UI widgets of the editor.
******************************************************************************/
void ParcasFileImporterEditor::createUI(const RolloutInsertionParameters& rolloutParams)
{
// Create a rollout.
QWidget* rollout = createRollout(tr("Parcas reader"), rolloutParams);
// Create the rollout contents.
QVBoxLayout* layout = new QVBoxLayout(rollout);
layout->setContentsMargins(4,4,4,4);
layout->setSpacing(4);
QGroupBox* optionsBox = new QGroupBox(tr("Options"), rollout);
QVBoxLayout* sublayout = new QVBoxLayout(optionsBox);
sublayout->setContentsMargins(4,4,4,4);
layout->addWidget(optionsBox);
// Sort particles
BooleanParameterUI* sortParticlesUI = new BooleanParameterUI(this, PROPERTY_FIELD(ParticleImporter::sortParticles));
sublayout->addWidget(sortParticlesUI->checkBox());
}
OVITO_END_INLINE_NAMESPACE
OVITO_END_INLINE_NAMESPACE
OVITO_END_INLINE_NAMESPACE
} // End of namespace
} // End of namespace
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (2018) Alexander Stukowski
//
// This file is part of OVITO (Open Visualization Tool).
//
// OVITO is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// OVITO is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
///////////////////////////////////////////////////////////////////////////////
#pragma once
#include <plugins/particles/gui/ParticlesGui.h>
#include <gui/dataset/io/FileImporterEditor.h>
namespace Ovito { namespace Particles { OVITO_BEGIN_INLINE_NAMESPACE(Import) OVITO_BEGIN_INLINE_NAMESPACE(Formats) OVITO_BEGIN_INLINE_NAMESPACE(Internal)
/**
* \brief A properties editor for the ParcasFileImporter class.
*/
class ParcasFileImporterEditor : public FileImporterEditor
{
OVITO_CLASS(ParcasFileImporterEditor)
Q_OBJECT
public:
/// Constructor.
Q_INVOKABLE ParcasFileImporterEditor() {}
protected:
/// Creates the user interface controls for the editor.
virtual void createUI(const RolloutInsertionParameters& rolloutParams) override;
};
OVITO_END_INLINE_NAMESPACE
OVITO_END_INLINE_NAMESPACE
OVITO_END_INLINE_NAMESPACE
} // End of namespace
} // End of namespace
......@@ -124,22 +124,30 @@ bool XYZImporterEditor::showEditColumnMappingDialog(XYZImporter* importer, const
void XYZImporterEditor::createUI(const RolloutInsertionParameters& rolloutParams)
{
// Create a rollout.
QWidget* rollout = createRollout(tr("XYZ"), rolloutParams);
QWidget* rollout = createRollout(tr("XYZ reader"), rolloutParams);
// Create the rollout contents.
QVBoxLayout* layout = new QVBoxLayout(rollout);
layout->setContentsMargins(4,4,4,4);
layout->setSpacing(4);
QGroupBox* animFramesBox = new QGroupBox(tr("Timesteps"), rollout);
QVBoxLayout* sublayout = new QVBoxLayout(animFramesBox);
QGroupBox* optionsBox = new QGroupBox(tr("Options"), rollout);
QVBoxLayout* sublayout = new QVBoxLayout(optionsBox);
sublayout->setContentsMargins(4,4,4,4);
layout->addWidget(animFramesBox);
layout->addWidget(optionsBox);
// Multi-timestep file
BooleanParameterUI* multitimestepUI = new BooleanParameterUI(this, PROPERTY_FIELD(ParticleImporter::isMultiTimestepFile));
sublayout->addWidget(multitimestepUI->checkBox());
// Auto-rescale reduced coordinates.
BooleanParameterUI* rescaleReducedUI = new BooleanParameterUI(this, PROPERTY_FIELD(XYZImporter::autoRescaleCoordinates));
sublayout->addWidget(rescaleReducedUI->checkBox());
// Sort particles
BooleanParameterUI* sortParticlesUI = new BooleanParameterUI(this, PROPERTY_FIELD(ParticleImporter::sortParticles));
sublayout->addWidget(sortParticlesUI->checkBox());
QGroupBox* columnMappingBox = new QGroupBox(tr("File columns"), rollout);
sublayout = new QVBoxLayout(columnMappingBox);
sublayout->setContentsMargins(4,4,4,4);
......@@ -148,15 +156,6 @@ void XYZImporterEditor::createUI(const RolloutInsertionParameters& rolloutParams
QPushButton* editMappingButton = new QPushButton(tr("Edit column mapping..."));
sublayout->addWidget(editMappingButton);
connect(editMappingButton, &QPushButton::clicked, this, &XYZImporterEditor::onEditColumnMapping);
QGroupBox* settingsBox = new QGroupBox(tr("Settings"), rollout);
sublayout = new QVBoxLayout(settingsBox);
sublayout->setContentsMargins(4,4,4,4);
layout->addWidget(settingsBox);
// Auto-rescale reduced coordinates.
BooleanParameterUI* rescaleReducedUI = new BooleanParameterUI(this, PROPERTY_FIELD(XYZImporter::autoRescaleCoordinates));
sublayout->addWidget(rescaleReducedUI->checkBox());
}
/******************************************************************************
......
......@@ -337,6 +337,44 @@ void ParticleFrameData::insertTypes(PropertyObject* typeProperty, TypeList* type
}
}
/******************************************************************************
* Sorts the particles list with respect to particle IDs.
* Does nothing if particles do not have IDs.
******************************************************************************/
void ParticleFrameData::sortParticlesById()
{
PropertyPtr ids = findStandardParticleProperty(ParticleProperty::IdentifierProperty);
if(!ids) return;
// Determine new permutation of particles where they are sorted by ascending ID.
std::vector<size_t> permutation(ids->size());
std::iota(permutation.begin(), permutation.end(), (size_t)0);
std::sort(permutation.begin(), permutation.end(), [id = ids->constDataInt64()](size_t a, size_t b) { return id[a] < id[b]; });
std::vector<size_t> invertedPermutation(ids->size());
bool isAlreadySorted = true;
for(size_t i = 0; i < permutation.size(); i++) {
invertedPermutation[permutation[i]] = i;
if(permutation[i] != i) isAlreadySorted = false;
}
if(isAlreadySorted) return;
// Reorder all values in the particle property arrays.
for(const PropertyPtr& prop : particleProperties()) {
PropertyStorage copy(*prop);
prop->mappedCopy(copy, invertedPermutation);
}
// Update bond topology data to match new particle ordering.
if(PropertyPtr bondTopology = findStandardBondProperty(BondProperty::TopologyProperty)) {
auto particleIndex = bondTopology->dataInt64();
auto particleIndexEnd = particleIndex + bondTopology->size() * 2;
for(; particleIndex != particleIndexEnd; ++particleIndex) {
if(*particleIndex >= 0 && *particleIndex < invertedPermutation.size())
*particleIndex = invertedPermutation[*particleIndex];
}
}
}
OVITO_END_INLINE_NAMESPACE
} // End of namespace
} // End of namespace
......@@ -256,10 +256,14 @@ public:
/// Returns the metadata read from the file header.
QVariantMap& attributes() { return _attributes; }
/// Indicates that the file parser found additional frames
/// in the input file stored back to back with the frame currently being loaded.
/// Parsers call this method to indicate that the input file contains
/// additional frames stored back to back with the currently loaded one.
void signalAdditionalFrames() { _detectedAdditionalFrames = true; }
/// Sorts the particles list with respect to particle IDs.
/// Does nothing if particles do not have IDs.
void sortParticlesById();
private:
/// Inserts the stored particle or bond types into the given property object.
......@@ -288,8 +292,7 @@ private:
/// The metadata read from the file header.
QVariantMap _attributes;
/// Flag that indicates that the file parser has found additional frames
/// in the input file stored back to back with the currently loaded frame.
/// Flag that is set by the parser to indicate that the input file contains more than one frame.
bool _detectedAdditionalFrames = false;
};
......
......@@ -26,7 +26,9 @@ namespace Ovito { namespace Particles { OVITO_BEGIN_INLINE_NAMESPACE(Import)
IMPLEMENT_OVITO_CLASS(ParticleImporter);
DEFINE_PROPERTY_FIELD(ParticleImporter, isMultiTimestepFile);
SET_PROPERTY_FIELD_LABEL(ParticleImporter, isMultiTimestepFile, "Contains multiple timesteps");
DEFINE_PROPERTY_FIELD(ParticleImporter, sortParticles);
SET_PROPERTY_FIELD_LABEL(ParticleImporter, isMultiTimestepFile, "File contains multiple timesteps");
SET_PROPERTY_FIELD_LABEL(ParticleImporter, sortParticles, "Sort particles by ID");
/******************************************************************************
* Is called when the value of a property of this object has changed.
......@@ -37,6 +39,10 @@ void ParticleImporter::propertyChanged(const PropertyFieldDescriptor& field)
// Automatically rescan input file for animation frames when this option has been changed.
requestFramesUpdate();
}
else if(field == PROPERTY_FIELD(sortParticles)) {
// Automatically reload input file when this option has been changed.