add support for near-interactive image processing

This commit is contained in:
Axel Kohlmeyer
2023-08-10 23:27:04 -04:00
parent 4afd5f9661
commit 2e0e3d9204
6 changed files with 181 additions and 60 deletions

View File

@ -2,9 +2,6 @@ LAMMPS-GUI TODO list:
# Short term goals
- add option to image viewer to select a group and rerender, similar for the two rotate options with +/- buttons and +/- zoom buttons.
add checkbutton for HQ rendering (i.e. SSAO)
also move the image setting preferences there and remove scrollwheel zoom support.
- use qgetenv, qputenv for portability
- use QFile/QDir/QFileInto for portable file and directory operations.
- write LAMMPS GUI Howto showing/explaining options -> simplify docs and readme

View File

@ -36,9 +36,11 @@
#include <QWheelEvent>
#include <QWidgetAction>
static const QString blank(" ");
ImageViewer::ImageViewer(const QString &fileName, LammpsWrapper *_lammps, QWidget *parent) :
QDialog(parent), imageLabel(new QLabel), scrollArea(new QScrollArea), menuBar(new QMenuBar),
lammps(_lammps), group("all")
lammps(_lammps), group("all"), filename(fileName)
{
imageLabel->setBackgroundRole(QPalette::Base);
imageLabel->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
@ -55,40 +57,56 @@ ImageViewer::ImageViewer(const QString &fileName, LammpsWrapper *_lammps, QWidge
connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
QVBoxLayout *mainLayout = new QVBoxLayout;
auto *zoomin = new QPushButton("Zoom In");
auto *zoomout = new QPushButton("Zoom Out");
auto *rotleft = new QPushButton("Rotate Left");
auto *rotright = new QPushButton("Rotate Right");
auto *rotup = new QPushButton("Rotate Up");
auto *rotdown = new QPushButton("Rotate Down");
auto *combo = new QComboBox;
combo->setObjectName("group");
int ngroup = lammps->id_count("group");
char gname[64];
for (int i = 0; i < ngroup; ++i) {
lammps->id_name("group", i, gname, 64);
combo->addItem(gname);
}
QHBoxLayout *menuLayout = new QHBoxLayout;
menuLayout->addWidget(menuBar);
menuLayout->addWidget(new QPushButton("Zoom Out"));
menuLayout->addWidget(new QPushButton("Zoom In"));
menuLayout->addWidget(new QPushButton("Rotate Left"));
menuLayout->addWidget(new QPushButton("Rotate Right"));
menuLayout->addWidget(new QPushButton("Rotate Up"));
menuLayout->addWidget(new QPushButton("Rotate Down"));
menuLayout->addWidget(new QComboBox);
menuLayout->addWidget(zoomin);
menuLayout->addWidget(zoomout);
menuLayout->addWidget(rotleft);
menuLayout->addWidget(rotright);
menuLayout->addWidget(rotup);
menuLayout->addWidget(rotdown);
menuLayout->addWidget(new QLabel(" Group: "));
menuLayout->addWidget(combo);
connect(zoomin, &QPushButton::released, this, &ImageViewer::do_zoom_in);
connect(zoomout, &QPushButton::released, this, &ImageViewer::do_zoom_out);
connect(rotleft, &QPushButton::released, this, &ImageViewer::do_rot_left);
connect(rotright, &QPushButton::released, this, &ImageViewer::do_rot_right);
connect(rotup, &QPushButton::released, this, &ImageViewer::do_rot_up);
connect(rotdown, &QPushButton::released, this, &ImageViewer::do_rot_down);
connect(combo, SIGNAL(currentIndexChanged(int)), this, SLOT(change_group(int)));
mainLayout->addLayout(menuLayout);
mainLayout->addWidget(scrollArea);
mainLayout->addWidget(buttonBox);
setWindowTitle(QString("Image Viewer: ") + QFileInfo(fileName).completeBaseName());
createActions();
QImageReader reader(fileName);
reader.setAutoTransform(true);
const QImage newImage = reader.read();
if (newImage.isNull()) {
QMessageBox::warning(this, QGuiApplication::applicationDisplayName(),
tr("Cannot load %1: %2").arg(fileName, reader.errorString()));
return;
}
QSettings settings;
settings.beginGroup("snapshot");
int xsize = settings.value("xsize", 800).toInt();
int ysize = settings.value("ysize", 600).toInt();
zoom = settings.value("zoom", 1.0).toDouble();
hrot = settings.value("hrot", 60).toInt();
vrot = settings.value("vrot", 30).toInt();
settings.endGroup();
// scale back to achieve antialiasing
image = newImage.scaled(xsize, ysize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
imageLabel->setPixmap(QPixmap::fromImage(image));
createActions();
createImage();
scaleFactor = 1.0;
resize(image.width() + 20, image.height() + 50);
@ -99,6 +117,102 @@ ImageViewer::ImageViewer(const QString &fileName, LammpsWrapper *_lammps, QWidge
setLayout(mainLayout);
}
void ImageViewer::do_zoom_in()
{
zoom = zoom * 1.1;
if (zoom > 5.0) zoom = 5.0;
createImage();
}
void ImageViewer::do_zoom_out()
{
zoom = zoom / 1.1;
if (zoom < 0.5) zoom = 0.5;
createImage();
}
void ImageViewer::do_rot_right()
{
vrot -= 15;
if (vrot < 0) vrot += 360;
createImage();
}
void ImageViewer::do_rot_left()
{
vrot += 15;
if (vrot > 360) vrot -= 360;
createImage();
}
void ImageViewer::do_rot_down()
{
hrot -= 15;
if (hrot < 0) hrot += 360;
createImage();
}
void ImageViewer::do_rot_up()
{
hrot += 15;
if (hrot > 360) hrot -= 360;
createImage();
}
void ImageViewer::change_group(int idx)
{
QComboBox *box = findChild<QComboBox *>("group");
if (box) group = box->currentText();
createImage();
}
void ImageViewer::createImage()
{
QSettings settings;
QString dumpcmd = QString("write_dump ") + group + " image ";
QDir dumpdir = settings.value("tempdir").toString();
QFile dumpfile(dumpdir.absoluteFilePath(filename + ".ppm"));
dumpcmd += dumpfile.fileName();
settings.beginGroup("snapshot");
int aa = settings.value("antialias", 0).toInt() + 1;
int xsize = settings.value("xsize", 800).toInt() * aa;
int ysize = settings.value("ysize", 600).toInt() * aa;
dumpcmd += blank + settings.value("color", "type").toString();
dumpcmd += blank + settings.value("diameter", "type").toString();
dumpcmd += QString(" size ") + QString::number(xsize) + blank + QString::number(ysize);
dumpcmd += QString(" zoom ") + QString::number(zoom);
lammps->command(dumpcmd.toLocal8Bit());
if (lammps->extract_setting("dimension") == 3) {
dumpcmd += QString(" view ") + QString::number(hrot) + blank + QString::number(vrot);
}
if (settings.value("ssao", false).toBool()) dumpcmd += QString(" ssao yes 453983 0.6");
settings.endGroup();
lammps->command(dumpcmd.toLocal8Bit());
QImageReader reader(dumpfile.fileName());
reader.setAutoTransform(true);
const QImage newImage = reader.read();
if (newImage.isNull()) {
QMessageBox::warning(
this, QGuiApplication::applicationDisplayName(),
tr("Cannot load %1: %2").arg(dumpfile.fileName(), reader.errorString()));
return;
}
dumpfile.remove();
settings.beginGroup("snapshot");
xsize = settings.value("xsize", 800).toInt();
ysize = settings.value("ysize", 600).toInt();
settings.endGroup();
// scale back to achieve antialiasing
image = newImage.scaled(xsize, ysize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
imageLabel->setPixmap(QPixmap::fromImage(image));
}
void ImageViewer::saveAs()
{
QString fileName = QFileDialog::getSaveFileName(this, "Save Image File As", QString(),

View File

@ -45,8 +45,17 @@ private slots:
void normalSize();
void fitToWindow();
void do_zoom_in();
void do_zoom_out();
void do_rot_left();
void do_rot_right();
void do_rot_up();
void do_rot_down();
void change_group(int);
private:
void createActions();
void createImage();
void updateActions();
void saveFile(const QString &fileName);
void scaleImage(double factor);
@ -69,6 +78,9 @@ private:
LammpsWrapper *lammps;
QString group;
QString filename;
int hrot, vrot;
double zoom;
};
#endif

View File

@ -230,7 +230,6 @@ LammpsGui::LammpsGui(QWidget *parent, const char *filename) :
// none of the plugin paths could load, remove key
settings.remove("plugin_path");
QMessageBox::critical(this, "Error", "Cannot open LAMMPS shared library file");
// QCoreApplication::quit();
exit(1);
}
#endif
@ -715,38 +714,7 @@ void LammpsGui::view_image()
"Cannot create snapshot image without a system box");
return;
}
QSettings settings;
QString dumpcmd = "write_dump all image ";
QString dumpfile = settings.value("tempdir").toString();
#if defined(_WIN32)
dumpfile += '\\';
#else
dumpfile += '/';
#endif
dumpfile += current_file + ".ppm";
dumpcmd += dumpfile;
settings.beginGroup("snapshot");
int aa = settings.value("antialias", 0).toInt() + 1;
int xsize = settings.value("xsize", 800).toInt() * aa;
int ysize = settings.value("ysize", 800).toInt() * aa;
dumpcmd += blank + settings.value("color", "type").toString();
dumpcmd += blank + settings.value("diameter", "type").toString();
dumpcmd += QString(" size ") + QString::number(xsize) + blank + QString::number(ysize);
dumpcmd += QString(" zoom ") + settings.value("zoom", "1.0").toString();
if (settings.value("ssao", false).toBool()) dumpcmd += QString(" ssao yes 453983 0.6");
settings.endGroup();
dirstatus->setText(" Rendering Snapshot Image... ");
status->repaint();
lammps.command(dumpcmd.toLocal8Bit());
dirstatus->setText(QString(" Directory: ") + current_dir);
status->repaint();
imagewindow = new ImageViewer(dumpfile, &lammps);
QFile::remove(dumpfile);
imagewindow = new ImageViewer(current_file, &lammps);
} else {
QMessageBox::warning(this, "ImageViewer Error",
"Cannot create snapshot image while LAMMPS is running");

View File

@ -45,6 +45,33 @@ int LammpsWrapper::extract_setting(const char *keyword)
return val;
}
int LammpsWrapper::id_count(const char *keyword)
{
int val = 0;
if (lammps_handle) {
#if defined(LAMMPS_GUI_USE_PLUGIN)
val = ((liblammpsplugin_t *)plugin_handle)->id_count(lammps_handle, keyword);
#else
val = lammps_id_count(lammps_handle, keyword);
#endif
}
return val;
}
int LammpsWrapper::id_name(const char *keyword, int idx, char *buf, int buflen)
{
int val = 0;
if (lammps_handle) {
#if defined(LAMMPS_GUI_USE_PLUGIN)
val =
((liblammpsplugin_t *)plugin_handle)->id_name(lammps_handle, keyword, idx, buf, buflen);
#else
val = lammps_id_name(lammps_handle, keyword, idx, buf, buflen);
#endif
}
return val;
}
double LammpsWrapper::get_thermo(const char *keyword)
{
double val = 0.0;

View File

@ -29,6 +29,9 @@ public:
void force_timeout();
int extract_setting(const char *keyword);
int id_count(const char *idtype);
int id_name(const char *idtype, int idx, char *buf, int buflen);
double get_thermo(const char *keyword);
void *last_thermo(const char *keyword, int idx);
bool is_open() const { return lammps_handle != nullptr; }