add support for near-interactive image processing
This commit is contained in:
@ -2,9 +2,6 @@ LAMMPS-GUI TODO list:
|
|||||||
|
|
||||||
# Short term goals
|
# 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 qgetenv, qputenv for portability
|
||||||
- use QFile/QDir/QFileInto for portable file and directory operations.
|
- use QFile/QDir/QFileInto for portable file and directory operations.
|
||||||
- write LAMMPS GUI Howto showing/explaining options -> simplify docs and readme
|
- write LAMMPS GUI Howto showing/explaining options -> simplify docs and readme
|
||||||
|
|||||||
@ -36,9 +36,11 @@
|
|||||||
#include <QWheelEvent>
|
#include <QWheelEvent>
|
||||||
#include <QWidgetAction>
|
#include <QWidgetAction>
|
||||||
|
|
||||||
|
static const QString blank(" ");
|
||||||
|
|
||||||
ImageViewer::ImageViewer(const QString &fileName, LammpsWrapper *_lammps, QWidget *parent) :
|
ImageViewer::ImageViewer(const QString &fileName, LammpsWrapper *_lammps, QWidget *parent) :
|
||||||
QDialog(parent), imageLabel(new QLabel), scrollArea(new QScrollArea), menuBar(new QMenuBar),
|
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->setBackgroundRole(QPalette::Base);
|
||||||
imageLabel->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
|
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);
|
connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||||
|
|
||||||
QVBoxLayout *mainLayout = new QVBoxLayout;
|
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;
|
QHBoxLayout *menuLayout = new QHBoxLayout;
|
||||||
menuLayout->addWidget(menuBar);
|
menuLayout->addWidget(menuBar);
|
||||||
menuLayout->addWidget(new QPushButton("Zoom Out"));
|
menuLayout->addWidget(zoomin);
|
||||||
menuLayout->addWidget(new QPushButton("Zoom In"));
|
menuLayout->addWidget(zoomout);
|
||||||
menuLayout->addWidget(new QPushButton("Rotate Left"));
|
menuLayout->addWidget(rotleft);
|
||||||
menuLayout->addWidget(new QPushButton("Rotate Right"));
|
menuLayout->addWidget(rotright);
|
||||||
menuLayout->addWidget(new QPushButton("Rotate Up"));
|
menuLayout->addWidget(rotup);
|
||||||
menuLayout->addWidget(new QPushButton("Rotate Down"));
|
menuLayout->addWidget(rotdown);
|
||||||
menuLayout->addWidget(new QComboBox);
|
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->addLayout(menuLayout);
|
||||||
mainLayout->addWidget(scrollArea);
|
mainLayout->addWidget(scrollArea);
|
||||||
mainLayout->addWidget(buttonBox);
|
mainLayout->addWidget(buttonBox);
|
||||||
setWindowTitle(QString("Image Viewer: ") + QFileInfo(fileName).completeBaseName());
|
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;
|
QSettings settings;
|
||||||
settings.beginGroup("snapshot");
|
settings.beginGroup("snapshot");
|
||||||
int xsize = settings.value("xsize", 800).toInt();
|
zoom = settings.value("zoom", 1.0).toDouble();
|
||||||
int ysize = settings.value("ysize", 600).toInt();
|
hrot = settings.value("hrot", 60).toInt();
|
||||||
|
vrot = settings.value("vrot", 30).toInt();
|
||||||
settings.endGroup();
|
settings.endGroup();
|
||||||
// scale back to achieve antialiasing
|
|
||||||
image = newImage.scaled(xsize, ysize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
|
createActions();
|
||||||
imageLabel->setPixmap(QPixmap::fromImage(image));
|
createImage();
|
||||||
|
|
||||||
scaleFactor = 1.0;
|
scaleFactor = 1.0;
|
||||||
resize(image.width() + 20, image.height() + 50);
|
resize(image.width() + 20, image.height() + 50);
|
||||||
|
|
||||||
@ -99,6 +117,102 @@ ImageViewer::ImageViewer(const QString &fileName, LammpsWrapper *_lammps, QWidge
|
|||||||
setLayout(mainLayout);
|
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()
|
void ImageViewer::saveAs()
|
||||||
{
|
{
|
||||||
QString fileName = QFileDialog::getSaveFileName(this, "Save Image File As", QString(),
|
QString fileName = QFileDialog::getSaveFileName(this, "Save Image File As", QString(),
|
||||||
|
|||||||
@ -45,8 +45,17 @@ private slots:
|
|||||||
void normalSize();
|
void normalSize();
|
||||||
void fitToWindow();
|
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:
|
private:
|
||||||
void createActions();
|
void createActions();
|
||||||
|
void createImage();
|
||||||
void updateActions();
|
void updateActions();
|
||||||
void saveFile(const QString &fileName);
|
void saveFile(const QString &fileName);
|
||||||
void scaleImage(double factor);
|
void scaleImage(double factor);
|
||||||
@ -69,6 +78,9 @@ private:
|
|||||||
|
|
||||||
LammpsWrapper *lammps;
|
LammpsWrapper *lammps;
|
||||||
QString group;
|
QString group;
|
||||||
|
QString filename;
|
||||||
|
int hrot, vrot;
|
||||||
|
double zoom;
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@ -230,7 +230,6 @@ LammpsGui::LammpsGui(QWidget *parent, const char *filename) :
|
|||||||
// none of the plugin paths could load, remove key
|
// none of the plugin paths could load, remove key
|
||||||
settings.remove("plugin_path");
|
settings.remove("plugin_path");
|
||||||
QMessageBox::critical(this, "Error", "Cannot open LAMMPS shared library file");
|
QMessageBox::critical(this, "Error", "Cannot open LAMMPS shared library file");
|
||||||
// QCoreApplication::quit();
|
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -715,38 +714,7 @@ void LammpsGui::view_image()
|
|||||||
"Cannot create snapshot image without a system box");
|
"Cannot create snapshot image without a system box");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
imagewindow = new ImageViewer(current_file, &lammps);
|
||||||
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);
|
|
||||||
} else {
|
} else {
|
||||||
QMessageBox::warning(this, "ImageViewer Error",
|
QMessageBox::warning(this, "ImageViewer Error",
|
||||||
"Cannot create snapshot image while LAMMPS is running");
|
"Cannot create snapshot image while LAMMPS is running");
|
||||||
|
|||||||
@ -45,6 +45,33 @@ int LammpsWrapper::extract_setting(const char *keyword)
|
|||||||
return val;
|
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 LammpsWrapper::get_thermo(const char *keyword)
|
||||||
{
|
{
|
||||||
double val = 0.0;
|
double val = 0.0;
|
||||||
|
|||||||
@ -29,6 +29,9 @@ public:
|
|||||||
void force_timeout();
|
void force_timeout();
|
||||||
|
|
||||||
int extract_setting(const char *keyword);
|
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);
|
double get_thermo(const char *keyword);
|
||||||
void *last_thermo(const char *keyword, int idx);
|
void *last_thermo(const char *keyword, int idx);
|
||||||
bool is_open() const { return lammps_handle != nullptr; }
|
bool is_open() const { return lammps_handle != nullptr; }
|
||||||
|
|||||||
Reference in New Issue
Block a user