add support for near-interactive image processing
This commit is contained in:
@ -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
|
||||
|
||||
@ -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(),
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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");
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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; }
|
||||
|
||||
Reference in New Issue
Block a user