From 3fbf9b8a1ae9b8199db69146063788d0ba96b3f5 Mon Sep 17 00:00:00 2001 From: badarsh2 Date: Wed, 20 Jun 2018 08:31:31 +0530 Subject: [PATCH 01/68] VASP trajectory support --- avogadro/io/CMakeLists.txt | 4 +- avogadro/io/fileformatmanager.cpp | 9 +- .../io/{poscarformat.cpp => vaspformat.cpp} | 159 +++++++++++++++++- avogadro/io/{poscarformat.h => vaspformat.h} | 38 ++++- avogadro/qtgui/fileformatdialog.cpp | 33 ++-- 5 files changed, 209 insertions(+), 34 deletions(-) rename avogadro/io/{poscarformat.cpp => vaspformat.cpp} (64%) rename avogadro/io/{poscarformat.h => vaspformat.h} (63%) diff --git a/avogadro/io/CMakeLists.txt b/avogadro/io/CMakeLists.txt index 3d432dc3be..f47d4dfba5 100644 --- a/avogadro/io/CMakeLists.txt +++ b/avogadro/io/CMakeLists.txt @@ -30,7 +30,7 @@ set(HEADERS fileformatmanager.h gromacsformat.h mdlformat.h - poscarformat.h + vaspformat.h xyzformat.h lammpsformat.h ) @@ -42,7 +42,7 @@ set(SOURCES fileformatmanager.cpp gromacsformat.cpp mdlformat.cpp - poscarformat.cpp + vaspformat.cpp xyzformat.cpp lammpsformat.cpp ) diff --git a/avogadro/io/fileformatmanager.cpp b/avogadro/io/fileformatmanager.cpp index 222507c75a..f4622d130b 100644 --- a/avogadro/io/fileformatmanager.cpp +++ b/avogadro/io/fileformatmanager.cpp @@ -23,7 +23,7 @@ #include "gromacsformat.h" #include "lammpsformat.h" #include "mdlformat.h" -#include "poscarformat.h" +#include "vaspformat.h" #include "xyzformat.h" #include @@ -159,7 +159,7 @@ bool FileFormatManager::addFormat(FileFormat* format) namespace { // Lookup each key from "keys" in "map", and remove "val" from the Map's // data value (which is a vector of ValueType) -template +template void removeFromMap(Map& map, const VectorOfKeys& keys, const ValueType& val) { typedef typename VectorOfKeys::const_iterator KeysIter; @@ -249,8 +249,8 @@ std::vector FileFormatManager::fileFormats( { std::vector result; - for (std::vector::const_iterator it = m_formats.begin(), - itEnd = m_formats.end(); + for (std::vector::const_iterator it = m_formats.begin(), + itEnd = m_formats.end(); it != itEnd; ++it) { if (filter == FileFormat::None || (filter & (*it)->supportedOperations()) == filter) { @@ -289,6 +289,7 @@ FileFormatManager::FileFormatManager() addFormat(new CjsonFormat); addFormat(new GromacsFormat); addFormat(new MdlFormat); + addFormat(new OutcarFormat); addFormat(new PoscarFormat); addFormat(new XyzFormat); addFormat(new LammpsFormat); diff --git a/avogadro/io/poscarformat.cpp b/avogadro/io/vaspformat.cpp similarity index 64% rename from avogadro/io/poscarformat.cpp rename to avogadro/io/vaspformat.cpp index 1bd7acf4ff..a05e311b08 100644 --- a/avogadro/io/poscarformat.cpp +++ b/avogadro/io/vaspformat.cpp @@ -14,7 +14,7 @@ ******************************************************************************/ -#include "poscarformat.h" +#include "vaspformat.h" #include // for atomicNumberFromSymbol() #include // for matrix3 @@ -31,25 +31,22 @@ namespace Avogadro { namespace Io { using std::getline; +using std::map; using std::string; using std::vector; using Core::Array; using Core::Atom; using Core::Elements; -using Core::Molecule; -using Core::UnitCell; using Core::lexicalCast; +using Core::Molecule; using Core::split; using Core::trimmed; +using Core::UnitCell; -PoscarFormat::PoscarFormat() -{ -} +PoscarFormat::PoscarFormat() {} -PoscarFormat::~PoscarFormat() -{ -} +PoscarFormat::~PoscarFormat() {} bool PoscarFormat::read(std::istream& inStream, Core::Molecule& mol) { @@ -338,5 +335,149 @@ std::vector PoscarFormat::mimeTypes() const return mime; } +OutcarFormat::OutcarFormat() {} + +OutcarFormat::~OutcarFormat() {} + +bool OutcarFormat::read(std::istream& inStream, Core::Molecule& mol) +{ + std::string buffer, dashedStr, positionStr, latticeStr; + positionStr = " POSITION"; + latticeStr = " Lattice vectors:"; + dashedStr = " -----------"; + std::vector stringSplit; + int coordSet = 0, natoms = 0; + Array positions; + Vector3 ax1, ax2, ax3; + bool ax1Set = false, ax2Set = false, ax3Set = false; + + typedef map AtomTypeMap; + AtomTypeMap atomTypes; + unsigned char customElementCounter = CustomElementMin; + + while (getline(inStream, buffer)) { + // Checks whether the buffer object contains the lattice vectors keyword + if (strncmp(buffer.c_str(), latticeStr.c_str(), latticeStr.size()) == 0) { + // Checks whether lattice vectors have been already set. Reason being that + // only the first occurrence denotes the true lattice vectors, and the + // ones following these are vectors of the primitive cell. + if (!(ax1Set && ax2Set && ax3Set)) { + getline(inStream, buffer); + for (int i = 0; i < 3; ++i) { + getline(inStream, buffer); + stringSplit = split(buffer, ' '); + if (stringSplit[0] == "A1") { + ax1 = Vector3(lexicalCast(stringSplit.at(3).substr( + 0, stringSplit.at(3).size() - 1)), + lexicalCast(stringSplit.at(4).substr( + 0, stringSplit.at(4).size() - 1)), + lexicalCast(stringSplit.at(5).substr( + 0, stringSplit.at(5).size() - 1))); + ax1Set = true; + } else if (stringSplit[0] == "A2") { + ax2 = Vector3(lexicalCast(stringSplit.at(3).substr( + 0, stringSplit.at(3).size() - 1)), + lexicalCast(stringSplit.at(4).substr( + 0, stringSplit.at(4).size() - 1)), + lexicalCast(stringSplit.at(5).substr( + 0, stringSplit.at(5).size() - 1))); + ax2Set = true; + } else if (stringSplit[0] == "A3") { + ax3 = Vector3(lexicalCast(stringSplit.at(3).substr( + 0, stringSplit.at(3).size() - 1)), + lexicalCast(stringSplit.at(4).substr( + 0, stringSplit.at(4).size() - 1)), + lexicalCast(stringSplit.at(5).substr( + 0, stringSplit.at(5).size() - 1))); + ax3Set = true; + } + } + // Checks whether all the three axis vectors have been read + if (ax1Set && ax2Set && ax3Set) { + mol.setUnitCell(new UnitCell(ax1, ax2, ax3)); + } + } + } + + // Checks whether the buffer object contains the POSITION keyword + else if (strncmp(buffer.c_str(), positionStr.c_str(), positionStr.size()) == + 0) { + getline(inStream, buffer); + // Double checks whether the succeeding line is a sequence of dashes + if (strncmp(buffer.c_str(), dashedStr.c_str(), dashedStr.size()) == 0) { + // natoms is not known, so the loop proceeds till the bottom dashed line + // is encountered + while (true) { + getline(inStream, buffer); + // Condition for encountering dashed line + if (strncmp(buffer.c_str(), dashedStr.c_str(), dashedStr.size()) == + 0) { + if (coordSet == 0) { + mol.setCoordinate3d(mol.atomPositions3d(), coordSet++); + positions.reserve(natoms); + } else { + mol.setCoordinate3d(positions, coordSet++); + positions.clear(); + } + break; + } + // Parsing the coordinates + stringSplit = split(buffer, ' '); + Vector3 tmpAtom(lexicalCast(stringSplit.at(0)), + lexicalCast(stringSplit.at(1)), + lexicalCast(stringSplit.at(2))); + if (coordSet == 0) { + AtomTypeMap::const_iterator it; + atomTypes.insert( + std::make_pair(std::to_string(natoms), customElementCounter++)); + it = atomTypes.find(std::to_string(natoms)); + // if (customElementCounter > CustomElementMax) { + // appendError("Custom element type limit exceeded."); + // return false; + // } + Atom newAtom = mol.addAtom(it->second); + newAtom.setPosition3d(tmpAtom); + natoms++; + } else { + positions.push_back(tmpAtom); + } + } + } + } + } + + // Set the custom element map if needed: + if (!atomTypes.empty()) { + Molecule::CustomElementMap elementMap; + for (AtomTypeMap::const_iterator it = atomTypes.begin(), + itEnd = atomTypes.end(); + it != itEnd; ++it) { + elementMap.insert(std::make_pair(it->second, "Atom " + it->first)); + } + mol.setCustomElementMap(elementMap); + } + + return true; +} + +bool OutcarFormat::write(std::ostream& outStream, const Core::Molecule& mol) +{ + return false; +} + +std::vector OutcarFormat::fileExtensions() const +{ + std::vector ext; + ext.push_back("OUTCAR"); + return ext; +} + +std::vector OutcarFormat::mimeTypes() const +{ + std::vector mime; + mime.push_back("N/A"); + return mime; +} + } // end Io namespace } // end Avogadro namespace diff --git a/avogadro/io/poscarformat.h b/avogadro/io/vaspformat.h similarity index 63% rename from avogadro/io/poscarformat.h rename to avogadro/io/vaspformat.h index a96b162ad3..f5b5281dfc 100644 --- a/avogadro/io/poscarformat.h +++ b/avogadro/io/vaspformat.h @@ -14,8 +14,8 @@ ******************************************************************************/ -#ifndef AVOGADRO_IO_POSCARFORMAT_H -#define AVOGADRO_IO_POSCARFORMAT_H +#ifndef AVOGADRO_IO_VASPFORMAT_H +#define AVOGADRO_IO_VASPFORMAT_H #include "fileformat.h" @@ -59,7 +59,39 @@ class AVOGADROIO_EXPORT PoscarFormat : public FileFormat bool write(std::ostream& outStream, const Core::Molecule& mol); }; +class AVOGADROIO_EXPORT OutcarFormat : public FileFormat +{ +public: + OutcarFormat(); + ~OutcarFormat() override; + + Operations supportedOperations() const override + { + return Read | File | Stream | String; + } + + FileFormat* newInstance() const override { return new OutcarFormat; } + std::string identifier() const override { return "Avogadro: OUTCAR"; } + std::string name() const override { return "OUTCAR"; } + std::string description() const override + { + return "Format used by VASP that contains trajectory output of a DFT/MD " + "calculation."; + } + + std::string specificationUrl() const override + { + return "https://cms.mpi.univie.ac.at/wiki/index.php/OUTCAR"; + } + + std::vector fileExtensions() const override; + std::vector mimeTypes() const override; + + bool read(std::istream& inStream, Core::Molecule& mol); + bool write(std::ostream& outStream, const Core::Molecule& mol); +}; + } // end Io namespace } // end Avogadro namespace -#endif // AVOGADRO_IO_POSCARFORMAT_H +#endif // AVOGADRO_IO_VASPFORMAT_H diff --git a/avogadro/qtgui/fileformatdialog.cpp b/avogadro/qtgui/fileformatdialog.cpp index 4612556c6e..9a02519d73 100644 --- a/avogadro/qtgui/fileformatdialog.cpp +++ b/avogadro/qtgui/fileformatdialog.cpp @@ -26,20 +26,18 @@ #include -using std::vector; -using Avogadro::Io::FileFormatManager; using Avogadro::Io::FileFormat; +using Avogadro::Io::FileFormatManager; +using std::vector; namespace Avogadro { namespace QtGui { -FileFormatDialog::FileFormatDialog(QWidget* parentW) : QFileDialog(parentW) -{ -} +FileFormatDialog::FileFormatDialog(QWidget* parentW) + : QFileDialog(parentW) +{} -FileFormatDialog::~FileFormatDialog() -{ -} +FileFormatDialog::~FileFormatDialog() {} FileFormatDialog::FormatFilePair FileFormatDialog::fileToRead( QWidget* parent, const QString& caption, const QString& dir, @@ -63,8 +61,9 @@ FileFormatDialog::FormatFilePair FileFormatDialog::fileToRead( // If none found, give user the option to retry. if (!format) { QMessageBox::StandardButton reply = QMessageBox::question( - parent, caption, tr("Unable to find a suitable file reader for " - "the selected file."), + parent, caption, + tr("Unable to find a suitable file reader for " + "the selected file."), QMessageBox::Abort | QMessageBox::Retry, QMessageBox::Retry); switch (reply) { default: @@ -105,8 +104,9 @@ FileFormatDialog::FormatFilePair FileFormatDialog::fileToWrite( // If none found, give user the option to retry. if (!format) { QMessageBox::StandardButton reply = QMessageBox::question( - parentWidget, caption, tr("Unable to find a suitable file writer for " - "the selected format."), + parentWidget, caption, + tr("Unable to find a suitable file writer for " + "the selected format."), QMessageBox::Abort | QMessageBox::Retry, QMessageBox::Retry); switch (reply) { default: @@ -212,8 +212,8 @@ QString FileFormatDialog::generateFilterString( QString filterString; // Create a map that groups the file extensions by name: QMap formatMap; - for (std::vector::const_iterator it = ffs.begin(), - itEnd = ffs.end(); + for (std::vector::const_iterator it = ffs.begin(), + itEnd = ffs.end(); it != itEnd; ++it) { QString name(QString::fromStdString((*it)->name())); std::vector exts = (*it)->fileExtensions(); @@ -234,6 +234,7 @@ QString FileFormatDialog::generateFilterString( QStringList nonExtensions; nonExtensions << "POSCAR" // VASP input geometry << "CONTCAR" // VASP output geometry + << "OUTCAR" // VASP output full-precision << "HISTORY" // DL-POLY history file << "CONFIG" // DL-POLY config file ; @@ -276,8 +277,8 @@ const Io::FileFormat* FileFormatDialog::selectFileFormat( // If more than one format found, prompt user to select one. QStringList idents; - for (std::vector::const_iterator it = ffs.begin(), - itEnd = ffs.end(); + for (std::vector::const_iterator it = ffs.begin(), + itEnd = ffs.end(); it != itEnd; ++it) { idents << QString::fromStdString((*it)->identifier()); } From 42949787dc84dc84b7d917c5a2ae2fb904b7fb0d Mon Sep 17 00:00:00 2001 From: badarsh2 Date: Sat, 23 Jun 2018 02:50:34 +0530 Subject: [PATCH 02/68] Adds GIF header library for native GIF export support --- avogadro/qtplugins/CMakeLists.txt | 2 + avogadro/qtplugins/playertool/playertool.cpp | 98 ++- thirdparty/gif-h/LICENSE | 24 + thirdparty/gif-h/README.md | 23 + thirdparty/gif-h/gif.h | 843 +++++++++++++++++++ 5 files changed, 956 insertions(+), 34 deletions(-) create mode 100644 thirdparty/gif-h/LICENSE create mode 100644 thirdparty/gif-h/README.md create mode 100644 thirdparty/gif-h/gif.h diff --git a/avogadro/qtplugins/CMakeLists.txt b/avogadro/qtplugins/CMakeLists.txt index 898f5ea841..3b7dcb49a9 100644 --- a/avogadro/qtplugins/CMakeLists.txt +++ b/avogadro/qtplugins/CMakeLists.txt @@ -5,6 +5,8 @@ find_package(Qt5 COMPONENTS Widgets Network Concurrent REQUIRED) include_directories(SYSTEM ${Qt5Widgets_INCLUDE_DIRS}) add_definitions(${Qt5Widgets_DEFINITIONS}) +include_directories("${AvogadroLibs_SOURCE_DIR}/thirdparty/gif-h") + # Modify the output directory for the build tree. set(original_library_output_dir "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}") set(CMAKE_LIBRARY_OUTPUT_DIRECTORY diff --git a/avogadro/qtplugins/playertool/playertool.cpp b/avogadro/qtplugins/playertool/playertool.cpp index fabc950d1a..887c6640a0 100644 --- a/avogadro/qtplugins/playertool/playertool.cpp +++ b/avogadro/qtplugins/playertool/playertool.cpp @@ -15,10 +15,12 @@ ******************************************************************************/ #include "playertool.h" +#include "gif.h" #include #include +#include #include #include #include @@ -44,17 +46,19 @@ namespace QtPlugins { using QtGui::Molecule; PlayerTool::PlayerTool(QObject* parent_) - : QtGui::ToolPlugin(parent_), m_activateAction(new QAction(this)), - m_molecule(nullptr), m_renderer(nullptr), m_currentFrame(0), - m_toolWidget(nullptr), m_info(nullptr) + : QtGui::ToolPlugin(parent_) + , m_activateAction(new QAction(this)) + , m_molecule(nullptr) + , m_renderer(nullptr) + , m_currentFrame(0) + , m_toolWidget(nullptr) + , m_info(nullptr) { m_activateAction->setText(tr("Player")); m_activateAction->setIcon(QIcon(":/icons/player.png")); } -PlayerTool::~PlayerTool() -{ -} +PlayerTool::~PlayerTool() {} QWidget* PlayerTool::toolWidget() const { @@ -185,6 +189,7 @@ void PlayerTool::animate(int advance) void PlayerTool::recordMovie() { + int EXPORT_WIDTH = 800, EXPORT_HEIGHT = 600; if (m_timer.isActive()) m_timer.stop(); @@ -193,19 +198,27 @@ void PlayerTool::recordMovie() baseFileName = m_molecule->data("fileName").toString().c_str(); QFileInfo info(baseFileName); + QString selfFilter = tr("Movie (*.mp4)"); QString baseName = QFileDialog::getSaveFileName( qobject_cast(parent()), tr("Export Bitmap Graphics"), "", - "Movie (*.mp4)"); + tr("Movie (*.mp4);;GIF (*.gif)"), &selfFilter); if (baseName.isEmpty()) return; if (!QFileInfo(baseName).suffix().isEmpty()) - baseName = QFileInfo(baseName).baseName(); + baseName = + QFileInfo(baseName).absolutePath() + "/" + QFileInfo(baseName).baseName(); bool bonding = m_dynamicBonding->isChecked(); int numberLength = static_cast( ceil(log10(static_cast(m_molecule->coordinate3dCount()) + 1))); - m_glWidget->resize(800, 600); + m_glWidget->resize(EXPORT_WIDTH, EXPORT_HEIGHT); + + GifWriter writer; + if (selfFilter == tr("GIF (*.gif)")) + GifBegin(&writer, (baseName + ".gif").toLatin1().data(), EXPORT_WIDTH, + EXPORT_HEIGHT, 100); + for (int i = 0; i < m_molecule->coordinate3dCount(); ++i) { m_molecule->setCoordinate3d(i); if (bonding) { @@ -229,33 +242,50 @@ void PlayerTool::recordMovie() exportImage = pixmap.toImage(); } - if (!exportImage.save(fileName)) { - QMessageBox::warning(qobject_cast(parent()), tr("Avogadro"), - tr("Cannot save file %1.").arg(fileName)); - return; + if (selfFilter == tr("GIF (*.gif)")) { + int frameWidth = exportImage.width(); + int frameHeight = exportImage.height(); + int numbPixels = frameWidth * frameHeight; + + uint8_t* imageData = new uint8_t[numbPixels * 4]; + int imageIndex = 0; + for (int j = 0; j < frameHeight; ++j) { + for (int k = 0; k < frameWidth; ++k) { + QColor color = exportImage.pixel(k, j); + imageData[imageIndex] = (uint8_t)color.red(); + imageData[imageIndex + 1] = (uint8_t)color.green(); + imageData[imageIndex + 2] = (uint8_t)color.blue(); + imageData[imageIndex + 3] = (uint8_t)color.alpha(); + imageIndex += 4; + } + } + + GifWriteFrame(&writer, imageData, EXPORT_WIDTH, EXPORT_HEIGHT, 10); + } else if (selfFilter == tr("Movie (*.mp4)")) { + if (!exportImage.save(fileName)) { + QMessageBox::warning(qobject_cast(parent()), tr("Avogadro"), + tr("Cannot save file %1.").arg(fileName)); + return; + } } } - QProcess proc; - QStringList args; - args << "-y" - << "-r" << QString::number(m_animationFPS->value()) << "-i" - << baseName + "%0" + QString::number(numberLength) + "d.png" - << "-c:v" - << "libx264" - << "-r" - << "30" - << "-pix_fmt" - << "yuv420p" << baseName + ".mp4"; - proc.execute("avconv", args); - - args.clear(); - args << "-dispose" - << "Background" - << "-delay" << QString::number(100 / m_animationFPS->value()) - << baseName + "%0" + QString::number(numberLength) + "d.png[0-" + - QString::number(m_molecule->coordinate3dCount() - 1) + "]" - << baseName + ".gif"; - proc.execute("convert", args); + + if (selfFilter == tr("GIF (*.gif)")) { + GifEnd(&writer); + } else if (selfFilter == tr("Movie (*.mp4)")) { + QProcess proc; + QStringList args; + args << "-y" + << "-r" << QString::number(m_animationFPS->value()) << "-i" + << baseName + "%0" + QString::number(numberLength) + "d.png" + << "-c:v" + << "libx264" + << "-r" + << "30" + << "-pix_fmt" + << "yuv420p" << baseName + ".mp4"; + proc.execute("avconv", args); + } } } // namespace QtPlugins diff --git a/thirdparty/gif-h/LICENSE b/thirdparty/gif-h/LICENSE new file mode 100644 index 0000000000..cf1ab25da0 --- /dev/null +++ b/thirdparty/gif-h/LICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to diff --git a/thirdparty/gif-h/README.md b/thirdparty/gif-h/README.md new file mode 100644 index 0000000000..ab4bc34651 --- /dev/null +++ b/thirdparty/gif-h/README.md @@ -0,0 +1,23 @@ +gif-h +===== + +This one-header library offers a simple, very limited way to create animated GIFs directly in code. +Those looking for particular cleverness are likely to be disappointed; it's pretty much a straight-ahead +implementation of the GIF format with optional Floyd-Steinberg dithering. (It does at least use delta +encoding - only the changed portions of each frame are saved.) + +So resulting files are often quite large. The hope is that it will be handy nonetheless as a quick and easily-integrated way for programs to spit out animations. + +Only RGBA8 is currently supported as an input format. (The alpha is ignored.) + +Email me : ctangora -at- gmail -dot- com + +Usage: +------------------- +Create a GifWriter struct. + +Pass the struct to GifBegin() to initialize values and write the file header. + +Pass frames of the animation to GifWriteFrame(). + +Finally, call GifEnd() to close the file handle and free memory. diff --git a/thirdparty/gif-h/gif.h b/thirdparty/gif-h/gif.h new file mode 100644 index 0000000000..d03ae8519a --- /dev/null +++ b/thirdparty/gif-h/gif.h @@ -0,0 +1,843 @@ +// +// gif.h +// by Charlie Tangora +// Public domain. +// Email me : ctangora -at- gmail -dot- com +// +// This file offers a simple, very limited way to create animated GIFs directly +// in code. +// +// Those looking for particular cleverness are likely to be disappointed; it's +// pretty much a straight-ahead implementation of the GIF format with optional +// Floyd-Steinberg dithering. (It does at least use delta encoding - only the +// changed portions of each frame are saved.) +// +// So resulting files are often quite large. The hope is that it will be handy +// nonetheless as a quick and easily-integrated way for programs to spit out +// animations. +// +// Only RGBA8 is currently supported as an input format. (The alpha is ignored.) +// +// USAGE: +// Create a GifWriter struct. Pass it to GifBegin() to initialize and write the +// header. Pass subsequent frames to GifWriteFrame(). Finally, call GifEnd() to +// close the file handle and free memory. +// + +#ifndef gif_h +#define gif_h + +#include // for integer typedefs +#include // for FILE* +#include // for memcpy and bzero + +// Define these macros to hook into a custom memory allocator. +// TEMP_MALLOC and TEMP_FREE will only be called in stack fashion - frees in the +// reverse order of mallocs and any temp memory allocated by a function will be +// freed before it exits. MALLOC and FREE are used only by GifBegin and GifEnd +// respectively (to allocate a buffer the size of the image, which is used to +// find changed pixels for delta-encoding.) + +#ifndef GIF_TEMP_MALLOC +#include +#define GIF_TEMP_MALLOC malloc +#endif + +#ifndef GIF_TEMP_FREE +#include +#define GIF_TEMP_FREE free +#endif + +#ifndef GIF_MALLOC +#include +#define GIF_MALLOC malloc +#endif + +#ifndef GIF_FREE +#include +#define GIF_FREE free +#endif + +const int kGifTransIndex = 0; + +struct GifPalette +{ + int bitDepth; + + uint8_t r[256]; + uint8_t g[256]; + uint8_t b[256]; + + // k-d tree over RGB space, organized in heap fashion + // i.e. left child of node i is node i*2, right child is node i*2+1 + // nodes 256-511 are implicitly the leaves, containing a color + uint8_t treeSplitElt[255]; + uint8_t treeSplit[255]; +}; + +// max, min, and abs functions +int GifIMax(int l, int r) +{ + return l > r ? l : r; +} +int GifIMin(int l, int r) +{ + return l < r ? l : r; +} +int GifIAbs(int i) +{ + return i < 0 ? -i : i; +} + +// walks the k-d tree to pick the palette entry for a desired color. +// Takes as in/out parameters the current best color and its error - +// only changes them if it finds a better color in its subtree. +// this is the major hotspot in the code at the moment. +void GifGetClosestPaletteColor(GifPalette* pPal, int r, int g, int b, + int& bestInd, int& bestDiff, int treeRoot = 1) +{ + // base case, reached the bottom of the tree + if (treeRoot > (1 << pPal->bitDepth) - 1) { + int ind = treeRoot - (1 << pPal->bitDepth); + if (ind == kGifTransIndex) + return; + + // check whether this color is better than the current winner + int r_err = r - ((int32_t)pPal->r[ind]); + int g_err = g - ((int32_t)pPal->g[ind]); + int b_err = b - ((int32_t)pPal->b[ind]); + int diff = GifIAbs(r_err) + GifIAbs(g_err) + GifIAbs(b_err); + + if (diff < bestDiff) { + bestInd = ind; + bestDiff = diff; + } + + return; + } + + // take the appropriate color (r, g, or b) for this node of the k-d tree + int comps[3]; + comps[0] = r; + comps[1] = g; + comps[2] = b; + int splitComp = comps[pPal->treeSplitElt[treeRoot]]; + + int splitPos = pPal->treeSplit[treeRoot]; + if (splitPos > splitComp) { + // check the left subtree + GifGetClosestPaletteColor(pPal, r, g, b, bestInd, bestDiff, treeRoot * 2); + if (bestDiff > splitPos - splitComp) { + // cannot prove there's not a better value in the right subtree, check + // that too + GifGetClosestPaletteColor(pPal, r, g, b, bestInd, bestDiff, + treeRoot * 2 + 1); + } + } else { + GifGetClosestPaletteColor(pPal, r, g, b, bestInd, bestDiff, + treeRoot * 2 + 1); + if (bestDiff > splitComp - splitPos) { + GifGetClosestPaletteColor(pPal, r, g, b, bestInd, bestDiff, treeRoot * 2); + } + } +} + +void GifSwapPixels(uint8_t* image, int pixA, int pixB) +{ + uint8_t rA = image[pixA * 4]; + uint8_t gA = image[pixA * 4 + 1]; + uint8_t bA = image[pixA * 4 + 2]; + uint8_t aA = image[pixA * 4 + 3]; + + uint8_t rB = image[pixB * 4]; + uint8_t gB = image[pixB * 4 + 1]; + uint8_t bB = image[pixB * 4 + 2]; + uint8_t aB = image[pixA * 4 + 3]; + + image[pixA * 4] = rB; + image[pixA * 4 + 1] = gB; + image[pixA * 4 + 2] = bB; + image[pixA * 4 + 3] = aB; + + image[pixB * 4] = rA; + image[pixB * 4 + 1] = gA; + image[pixB * 4 + 2] = bA; + image[pixB * 4 + 3] = aA; +} + +// just the partition operation from quicksort +int GifPartition(uint8_t* image, const int left, const int right, const int elt, + int pivotIndex) +{ + const int pivotValue = image[(pivotIndex)*4 + elt]; + GifSwapPixels(image, pivotIndex, right - 1); + int storeIndex = left; + bool split = 0; + for (int ii = left; ii < right - 1; ++ii) { + int arrayVal = image[ii * 4 + elt]; + if (arrayVal < pivotValue) { + GifSwapPixels(image, ii, storeIndex); + ++storeIndex; + } else if (arrayVal == pivotValue) { + if (split) { + GifSwapPixels(image, ii, storeIndex); + ++storeIndex; + } + split = !split; + } + } + GifSwapPixels(image, storeIndex, right - 1); + return storeIndex; +} + +// Perform an incomplete sort, finding all elements above and below the desired +// median +void GifPartitionByMedian(uint8_t* image, int left, int right, int com, + int neededCenter) +{ + if (left < right - 1) { + int pivotIndex = left + (right - left) / 2; + + pivotIndex = GifPartition(image, left, right, com, pivotIndex); + + // Only "sort" the section of the array that contains the median + if (pivotIndex > neededCenter) + GifPartitionByMedian(image, left, pivotIndex, com, neededCenter); + + if (pivotIndex < neededCenter) + GifPartitionByMedian(image, pivotIndex + 1, right, com, neededCenter); + } +} + +// Builds a palette by creating a balanced k-d tree of all pixels in the image +void GifSplitPalette(uint8_t* image, int numPixels, int firstElt, int lastElt, + int splitElt, int splitDist, int treeNode, + bool buildForDither, GifPalette* pal) +{ + if (lastElt <= firstElt || numPixels == 0) + return; + + // base case, bottom of the tree + if (lastElt == firstElt + 1) { + if (buildForDither) { + // Dithering needs at least one color as dark as anything + // in the image and at least one brightest color - + // otherwise it builds up error and produces strange artifacts + if (firstElt == 1) { + // special case: the darkest color in the image + uint32_t r = 255, g = 255, b = 255; + for (int ii = 0; ii < numPixels; ++ii) { + r = (uint32_t)GifIMin((int32_t)r, image[ii * 4 + 0]); + g = (uint32_t)GifIMin((int32_t)g, image[ii * 4 + 1]); + b = (uint32_t)GifIMin((int32_t)b, image[ii * 4 + 2]); + } + + pal->r[firstElt] = (uint8_t)r; + pal->g[firstElt] = (uint8_t)g; + pal->b[firstElt] = (uint8_t)b; + + return; + } + + if (firstElt == (1 << pal->bitDepth) - 1) { + // special case: the lightest color in the image + uint32_t r = 0, g = 0, b = 0; + for (int ii = 0; ii < numPixels; ++ii) { + r = (uint32_t)GifIMax((int32_t)r, image[ii * 4 + 0]); + g = (uint32_t)GifIMax((int32_t)g, image[ii * 4 + 1]); + b = (uint32_t)GifIMax((int32_t)b, image[ii * 4 + 2]); + } + + pal->r[firstElt] = (uint8_t)r; + pal->g[firstElt] = (uint8_t)g; + pal->b[firstElt] = (uint8_t)b; + + return; + } + } + + // otherwise, take the average of all colors in this subcube + uint64_t r = 0, g = 0, b = 0; + for (int ii = 0; ii < numPixels; ++ii) { + r += image[ii * 4 + 0]; + g += image[ii * 4 + 1]; + b += image[ii * 4 + 2]; + } + + r += (uint64_t)numPixels / 2; // round to nearest + g += (uint64_t)numPixels / 2; + b += (uint64_t)numPixels / 2; + + r /= (uint64_t)numPixels; + g /= (uint64_t)numPixels; + b /= (uint64_t)numPixels; + + pal->r[firstElt] = (uint8_t)r; + pal->g[firstElt] = (uint8_t)g; + pal->b[firstElt] = (uint8_t)b; + + return; + } + + // Find the axis with the largest range + int minR = 255, maxR = 0; + int minG = 255, maxG = 0; + int minB = 255, maxB = 0; + for (int ii = 0; ii < numPixels; ++ii) { + int r = image[ii * 4 + 0]; + int g = image[ii * 4 + 1]; + int b = image[ii * 4 + 2]; + + if (r > maxR) + maxR = r; + if (r < minR) + minR = r; + + if (g > maxG) + maxG = g; + if (g < minG) + minG = g; + + if (b > maxB) + maxB = b; + if (b < minB) + minB = b; + } + + int rRange = maxR - minR; + int gRange = maxG - minG; + int bRange = maxB - minB; + + // and split along that axis. (incidentally, this means this isn't a "proper" + // k-d tree but I don't know what else to call it) + int splitCom = 1; + if (bRange > gRange) + splitCom = 2; + if (rRange > bRange && rRange > gRange) + splitCom = 0; + + int subPixelsA = numPixels * (splitElt - firstElt) / (lastElt - firstElt); + int subPixelsB = numPixels - subPixelsA; + + GifPartitionByMedian(image, 0, numPixels, splitCom, subPixelsA); + + pal->treeSplitElt[treeNode] = (uint8_t)splitCom; + pal->treeSplit[treeNode] = image[subPixelsA * 4 + splitCom]; + + GifSplitPalette(image, subPixelsA, firstElt, splitElt, splitElt - splitDist, + splitDist / 2, treeNode * 2, buildForDither, pal); + GifSplitPalette(image + subPixelsA * 4, subPixelsB, splitElt, lastElt, + splitElt + splitDist, splitDist / 2, treeNode * 2 + 1, + buildForDither, pal); +} + +// Finds all pixels that have changed from the previous image and +// moves them to the fromt of th buffer. +// This allows us to build a palette optimized for the colors of the +// changed pixels only. +int GifPickChangedPixels(const uint8_t* lastFrame, uint8_t* frame, + int numPixels) +{ + int numChanged = 0; + uint8_t* writeIter = frame; + + for (int ii = 0; ii < numPixels; ++ii) { + if (lastFrame[0] != frame[0] || lastFrame[1] != frame[1] || + lastFrame[2] != frame[2]) { + writeIter[0] = frame[0]; + writeIter[1] = frame[1]; + writeIter[2] = frame[2]; + ++numChanged; + writeIter += 4; + } + lastFrame += 4; + frame += 4; + } + + return numChanged; +} + +// Creates a palette by placing all the image pixels in a k-d tree and then +// averaging the blocks at the bottom. This is known as the "modified median +// split" technique +void GifMakePalette(const uint8_t* lastFrame, const uint8_t* nextFrame, + uint32_t width, uint32_t height, int bitDepth, + bool buildForDither, GifPalette* pPal) +{ + pPal->bitDepth = bitDepth; + + // SplitPalette is destructive (it sorts the pixels by color) so + // we must create a copy of the image for it to destroy + size_t imageSize = (size_t)(width * height * 4 * sizeof(uint8_t)); + uint8_t* destroyableImage = (uint8_t*)GIF_TEMP_MALLOC(imageSize); + memcpy(destroyableImage, nextFrame, imageSize); + + int numPixels = (int)(width * height); + if (lastFrame) + numPixels = GifPickChangedPixels(lastFrame, destroyableImage, numPixels); + + const int lastElt = 1 << bitDepth; + const int splitElt = lastElt / 2; + const int splitDist = splitElt / 2; + + GifSplitPalette(destroyableImage, numPixels, 1, lastElt, splitElt, splitDist, + 1, buildForDither, pPal); + + GIF_TEMP_FREE(destroyableImage); + + // add the bottom node for the transparency index + pPal->treeSplit[1 << (bitDepth - 1)] = 0; + pPal->treeSplitElt[1 << (bitDepth - 1)] = 0; + + pPal->r[0] = pPal->g[0] = pPal->b[0] = 0; +} + +// Implements Floyd-Steinberg dithering, writes palette value to alpha +void GifDitherImage(const uint8_t* lastFrame, const uint8_t* nextFrame, + uint8_t* outFrame, uint32_t width, uint32_t height, + GifPalette* pPal) +{ + int numPixels = (int)(width * height); + + // quantPixels initially holds color*256 for all pixels + // The extra 8 bits of precision allow for sub-single-color error values + // to be propagated + int32_t* quantPixels = + (int32_t*)GIF_TEMP_MALLOC(sizeof(int32_t) * (size_t)numPixels * 4); + + for (int ii = 0; ii < numPixels * 4; ++ii) { + uint8_t pix = nextFrame[ii]; + int32_t pix16 = int32_t(pix) * 256; + quantPixels[ii] = pix16; + } + + for (uint32_t yy = 0; yy < height; ++yy) { + for (uint32_t xx = 0; xx < width; ++xx) { + int32_t* nextPix = quantPixels + 4 * (yy * width + xx); + const uint8_t* lastPix = + lastFrame ? lastFrame + 4 * (yy * width + xx) : NULL; + + // Compute the colors we want (rounding to nearest) + int32_t rr = (nextPix[0] + 127) / 256; + int32_t gg = (nextPix[1] + 127) / 256; + int32_t bb = (nextPix[2] + 127) / 256; + + // if it happens that we want the color from last frame, then just write + // out a transparent pixel + if (lastFrame && lastPix[0] == rr && lastPix[1] == gg && + lastPix[2] == bb) { + nextPix[0] = rr; + nextPix[1] = gg; + nextPix[2] = bb; + nextPix[3] = kGifTransIndex; + continue; + } + + int32_t bestDiff = 1000000; + int32_t bestInd = kGifTransIndex; + + // Search the palete + GifGetClosestPaletteColor(pPal, rr, gg, bb, bestInd, bestDiff); + + // Write the result to the temp buffer + int32_t r_err = nextPix[0] - int32_t(pPal->r[bestInd]) * 256; + int32_t g_err = nextPix[1] - int32_t(pPal->g[bestInd]) * 256; + int32_t b_err = nextPix[2] - int32_t(pPal->b[bestInd]) * 256; + + nextPix[0] = pPal->r[bestInd]; + nextPix[1] = pPal->g[bestInd]; + nextPix[2] = pPal->b[bestInd]; + nextPix[3] = bestInd; + + // Propagate the error to the four adjacent locations + // that we haven't touched yet + int quantloc_7 = (int)(yy * width + xx + 1); + int quantloc_3 = (int)(yy * width + width + xx - 1); + int quantloc_5 = (int)(yy * width + width + xx); + int quantloc_1 = (int)(yy * width + width + xx + 1); + + if (quantloc_7 < numPixels) { + int32_t* pix7 = quantPixels + 4 * quantloc_7; + pix7[0] += GifIMax(-pix7[0], r_err * 7 / 16); + pix7[1] += GifIMax(-pix7[1], g_err * 7 / 16); + pix7[2] += GifIMax(-pix7[2], b_err * 7 / 16); + } + + if (quantloc_3 < numPixels) { + int32_t* pix3 = quantPixels + 4 * quantloc_3; + pix3[0] += GifIMax(-pix3[0], r_err * 3 / 16); + pix3[1] += GifIMax(-pix3[1], g_err * 3 / 16); + pix3[2] += GifIMax(-pix3[2], b_err * 3 / 16); + } + + if (quantloc_5 < numPixels) { + int32_t* pix5 = quantPixels + 4 * quantloc_5; + pix5[0] += GifIMax(-pix5[0], r_err * 5 / 16); + pix5[1] += GifIMax(-pix5[1], g_err * 5 / 16); + pix5[2] += GifIMax(-pix5[2], b_err * 5 / 16); + } + + if (quantloc_1 < numPixels) { + int32_t* pix1 = quantPixels + 4 * quantloc_1; + pix1[0] += GifIMax(-pix1[0], r_err / 16); + pix1[1] += GifIMax(-pix1[1], g_err / 16); + pix1[2] += GifIMax(-pix1[2], b_err / 16); + } + } + } + + // Copy the palettized result to the output buffer + for (int ii = 0; ii < numPixels * 4; ++ii) { + outFrame[ii] = (uint8_t)quantPixels[ii]; + } + + GIF_TEMP_FREE(quantPixels); +} + +// Picks palette colors for the image using simple thresholding, no dithering +void GifThresholdImage(const uint8_t* lastFrame, const uint8_t* nextFrame, + uint8_t* outFrame, uint32_t width, uint32_t height, + GifPalette* pPal) +{ + uint32_t numPixels = width * height; + for (uint32_t ii = 0; ii < numPixels; ++ii) { + // if a previous color is available, and it matches the current color, + // set the pixel to transparent + if (lastFrame && lastFrame[0] == nextFrame[0] && + lastFrame[1] == nextFrame[1] && lastFrame[2] == nextFrame[2]) { + outFrame[0] = lastFrame[0]; + outFrame[1] = lastFrame[1]; + outFrame[2] = lastFrame[2]; + outFrame[3] = kGifTransIndex; + } else { + // palettize the pixel + int32_t bestDiff = 1000000; + int32_t bestInd = 1; + GifGetClosestPaletteColor(pPal, nextFrame[0], nextFrame[1], nextFrame[2], + bestInd, bestDiff); + + // Write the resulting color to the output buffer + outFrame[0] = pPal->r[bestInd]; + outFrame[1] = pPal->g[bestInd]; + outFrame[2] = pPal->b[bestInd]; + outFrame[3] = (uint8_t)bestInd; + } + + if (lastFrame) + lastFrame += 4; + outFrame += 4; + nextFrame += 4; + } +} + +// Simple structure to write out the LZW-compressed portion of the image +// one bit at a time +struct GifBitStatus +{ + uint8_t bitIndex; // how many bits in the partial byte written so far + uint8_t byte; // current partial byte + + uint32_t chunkIndex; + uint8_t chunk[256]; // bytes are written in here until we have 256 of them, + // then written to the file +}; + +// insert a single bit +void GifWriteBit(GifBitStatus& stat, uint32_t bit) +{ + bit = bit & 1; + bit = bit << stat.bitIndex; + stat.byte |= bit; + + ++stat.bitIndex; + if (stat.bitIndex > 7) { + // move the newly-finished byte to the chunk buffer + stat.chunk[stat.chunkIndex++] = stat.byte; + // and start a new byte + stat.bitIndex = 0; + stat.byte = 0; + } +} + +// write all bytes so far to the file +void GifWriteChunk(FILE* f, GifBitStatus& stat) +{ + fputc((int)stat.chunkIndex, f); + fwrite(stat.chunk, 1, stat.chunkIndex, f); + + stat.bitIndex = 0; + stat.byte = 0; + stat.chunkIndex = 0; +} + +void GifWriteCode(FILE* f, GifBitStatus& stat, uint32_t code, uint32_t length) +{ + for (uint32_t ii = 0; ii < length; ++ii) { + GifWriteBit(stat, code); + code = code >> 1; + + if (stat.chunkIndex == 255) { + GifWriteChunk(f, stat); + } + } +} + +// The LZW dictionary is a 256-ary tree constructed as the file is encoded, +// this is one node +struct GifLzwNode +{ + uint16_t m_next[256]; +}; + +// write a 256-color (8-bit) image palette to the file +void GifWritePalette(const GifPalette* pPal, FILE* f) +{ + fputc(0, f); // first color: transparency + fputc(0, f); + fputc(0, f); + + for (int ii = 1; ii < (1 << pPal->bitDepth); ++ii) { + uint32_t r = pPal->r[ii]; + uint32_t g = pPal->g[ii]; + uint32_t b = pPal->b[ii]; + + fputc((int)r, f); + fputc((int)g, f); + fputc((int)b, f); + } +} + +// write the image header, LZW-compress and write out the image +void GifWriteLzwImage(FILE* f, uint8_t* image, uint32_t left, uint32_t top, + uint32_t width, uint32_t height, uint32_t delay, + GifPalette* pPal) +{ + // graphics control extension + fputc(0x21, f); + fputc(0xf9, f); + fputc(0x04, f); + fputc(0x05, f); // leave prev frame in place, this frame has transparency + fputc(delay & 0xff, f); + fputc((delay >> 8) & 0xff, f); + fputc(kGifTransIndex, f); // transparent color index + fputc(0, f); + + fputc(0x2c, f); // image descriptor block + + fputc(left & 0xff, f); // corner of image in canvas space + fputc((left >> 8) & 0xff, f); + fputc(top & 0xff, f); + fputc((top >> 8) & 0xff, f); + + fputc(width & 0xff, f); // width and height of image + fputc((width >> 8) & 0xff, f); + fputc(height & 0xff, f); + fputc((height >> 8) & 0xff, f); + + // fputc(0, f); // no local color table, no transparency + // fputc(0x80, f); // no local color table, but transparency + + fputc(0x80 + pPal->bitDepth - 1, + f); // local color table present, 2 ^ bitDepth entries + GifWritePalette(pPal, f); + + const int minCodeSize = pPal->bitDepth; + const uint32_t clearCode = 1 << pPal->bitDepth; + + fputc(minCodeSize, f); // min code size 8 bits + + GifLzwNode* codetree = + (GifLzwNode*)GIF_TEMP_MALLOC(sizeof(GifLzwNode) * 4096); + + memset(codetree, 0, sizeof(GifLzwNode) * 4096); + int32_t curCode = -1; + uint32_t codeSize = (uint32_t)minCodeSize + 1; + uint32_t maxCode = clearCode + 1; + + GifBitStatus stat; + stat.byte = 0; + stat.bitIndex = 0; + stat.chunkIndex = 0; + + GifWriteCode(f, stat, clearCode, + codeSize); // start with a fresh LZW dictionary + + for (uint32_t yy = 0; yy < height; ++yy) { + for (uint32_t xx = 0; xx < width; ++xx) { + uint8_t nextValue = image[(yy * width + xx) * 4 + 3]; + + // "loser mode" - no compression, every single code is followed + // immediately by a clear + // WriteCode( f, stat, nextValue, codeSize ); + // WriteCode( f, stat, 256, codeSize ); + + if (curCode < 0) { + // first value in a new run + curCode = nextValue; + } else if (codetree[curCode].m_next[nextValue]) { + // current run already in the dictionary + curCode = codetree[curCode].m_next[nextValue]; + } else { + // finish the current run, write a code + GifWriteCode(f, stat, (uint32_t)curCode, codeSize); + + // insert the new run into the dictionary + codetree[curCode].m_next[nextValue] = (uint16_t)++maxCode; + + if (maxCode >= (1ul << codeSize)) { + // dictionary entry count has broken a size barrier, + // we need more bits for codes + codeSize++; + } + if (maxCode == 4095) { + // the dictionary is full, clear it out and begin anew + GifWriteCode(f, stat, clearCode, codeSize); // clear tree + + memset(codetree, 0, sizeof(GifLzwNode) * 4096); + codeSize = (uint32_t)(minCodeSize + 1); + maxCode = clearCode + 1; + } + + curCode = nextValue; + } + } + } + + // compression footer + GifWriteCode(f, stat, (uint32_t)curCode, codeSize); + GifWriteCode(f, stat, clearCode, codeSize); + GifWriteCode(f, stat, clearCode + 1, (uint32_t)minCodeSize + 1); + + // write out the last partial chunk + while (stat.bitIndex) + GifWriteBit(stat, 0); + if (stat.chunkIndex) + GifWriteChunk(f, stat); + + fputc(0, f); // image block terminator + + GIF_TEMP_FREE(codetree); +} + +struct GifWriter +{ + FILE* f; + uint8_t* oldImage; + bool firstFrame; +}; + +// Creates a gif file. +// The input GIFWriter is assumed to be uninitialized. +// The delay value is the time between frames in hundredths of a second - note +// that not all viewers pay much attention to this value. +bool GifBegin(GifWriter* writer, const char* filename, uint32_t width, + uint32_t height, uint32_t delay, int32_t bitDepth = 8, + bool dither = false) +{ + (void)bitDepth; + (void)dither; // Mute "Unused argument" warnings +#if defined(_MSC_VER) && (_MSC_VER >= 1400) + writer->f = 0; + fopen_s(&writer->f, filename, "wb"); +#else + writer->f = fopen(filename, "wb"); +#endif + if (!writer->f) + return false; + + writer->firstFrame = true; + + // allocate + writer->oldImage = (uint8_t*)GIF_MALLOC(width * height * 4); + + fputs("GIF89a", writer->f); + + // screen descriptor + fputc(width & 0xff, writer->f); + fputc((width >> 8) & 0xff, writer->f); + fputc(height & 0xff, writer->f); + fputc((height >> 8) & 0xff, writer->f); + + fputc(0xf0, + writer->f); // there is an unsorted global color table of 2 entries + fputc(0, writer->f); // background color + fputc( + 0, + writer->f); // pixels are square (we need to specify this because it's 1989) + + // now the "global" palette (really just a dummy palette) + // color 0: black + fputc(0, writer->f); + fputc(0, writer->f); + fputc(0, writer->f); + // color 1: also black + fputc(0, writer->f); + fputc(0, writer->f); + fputc(0, writer->f); + + if (delay != 0) { + // animation header + fputc(0x21, writer->f); // extension + fputc(0xff, writer->f); // application specific + fputc(11, writer->f); // length 11 + fputs("NETSCAPE2.0", writer->f); // yes, really + fputc(3, writer->f); // 3 bytes of NETSCAPE2.0 data + + fputc(1, writer->f); // JUST BECAUSE + fputc(0, writer->f); // loop infinitely (byte 0) + fputc(0, writer->f); // loop infinitely (byte 1) + + fputc(0, writer->f); // block terminator + } + + return true; +} + +// Writes out a new frame to a GIF in progress. +// The GIFWriter should have been created by GIFBegin. +// AFAIK, it is legal to use different bit depths for different frames of an +// image - this may be handy to save bits in animations that don't change much. +bool GifWriteFrame(GifWriter* writer, const uint8_t* image, uint32_t width, + uint32_t height, uint32_t delay, int bitDepth = 8, + bool dither = false) +{ + if (!writer->f) + return false; + + const uint8_t* oldImage = writer->firstFrame ? NULL : writer->oldImage; + writer->firstFrame = false; + + GifPalette pal; + GifMakePalette((dither ? NULL : oldImage), image, width, height, bitDepth, + dither, &pal); + + if (dither) + GifDitherImage(oldImage, image, writer->oldImage, width, height, &pal); + else + GifThresholdImage(oldImage, image, writer->oldImage, width, height, &pal); + + GifWriteLzwImage(writer->f, writer->oldImage, 0, 0, width, height, delay, + &pal); + + return true; +} + +// Writes the EOF code, closes the file handle, and frees temp memory used by a +// GIF. Many if not most viewers will still display a GIF properly if the EOF +// code is missing, but it's still a good idea to write it out. +bool GifEnd(GifWriter* writer) +{ + if (!writer->f) + return false; + + fputc(0x3b, writer->f); // end of file + fclose(writer->f); + GIF_FREE(writer->oldImage); + + writer->f = NULL; + writer->oldImage = NULL; + + return true; +} + +#endif From ee452ddc97d4c2dbcd53726112afdf40a0609ce7 Mon Sep 17 00:00:00 2001 From: badarsh2 Date: Sat, 23 Jun 2018 10:19:01 +0530 Subject: [PATCH 03/68] Adds support for AVI export --- avogadro/qtplugins/playertool/CMakeLists.txt | 4 + avogadro/qtplugins/playertool/playertool.cpp | 143 +++-- thirdparty/CMakeLists.txt | 1 + thirdparty/libgwavi/AUTHORS.md | 8 + thirdparty/libgwavi/CMakeLists.txt | 8 + thirdparty/libgwavi/LICENSE | 28 + thirdparty/libgwavi/README.md | 100 ++++ thirdparty/libgwavi/avi-utils.c | 554 +++++++++++++++++++ thirdparty/libgwavi/avi-utils.h | 64 +++ thirdparty/libgwavi/fileio.c | 83 +++ thirdparty/libgwavi/fileio.h | 53 ++ thirdparty/libgwavi/gwavi.c | 502 +++++++++++++++++ thirdparty/libgwavi/gwavi.h | 70 +++ thirdparty/libgwavi/gwavi_private.h | 111 ++++ 14 files changed, 1682 insertions(+), 47 deletions(-) create mode 100644 thirdparty/libgwavi/AUTHORS.md create mode 100644 thirdparty/libgwavi/CMakeLists.txt create mode 100644 thirdparty/libgwavi/LICENSE create mode 100644 thirdparty/libgwavi/README.md create mode 100644 thirdparty/libgwavi/avi-utils.c create mode 100644 thirdparty/libgwavi/avi-utils.h create mode 100644 thirdparty/libgwavi/fileio.c create mode 100644 thirdparty/libgwavi/fileio.h create mode 100644 thirdparty/libgwavi/gwavi.c create mode 100644 thirdparty/libgwavi/gwavi.h create mode 100644 thirdparty/libgwavi/gwavi_private.h diff --git a/avogadro/qtplugins/playertool/CMakeLists.txt b/avogadro/qtplugins/playertool/CMakeLists.txt index f17bcaca74..f27ef9a54f 100644 --- a/avogadro/qtplugins/playertool/CMakeLists.txt +++ b/avogadro/qtplugins/playertool/CMakeLists.txt @@ -1,3 +1,5 @@ +include_directories(SYSTEM "${AvogadroLibs_SOURCE_DIR}/thirdparty/libgwavi") + avogadro_plugin(PlayerTool "Player tool" ToolPlugin @@ -7,3 +9,5 @@ avogadro_plugin(PlayerTool "" playertool.qrc ) + +target_link_libraries(PlayerTool LINK_PRIVATE libgwavi) \ No newline at end of file diff --git a/avogadro/qtplugins/playertool/playertool.cpp b/avogadro/qtplugins/playertool/playertool.cpp index 887c6640a0..11b9260706 100644 --- a/avogadro/qtplugins/playertool/playertool.cpp +++ b/avogadro/qtplugins/playertool/playertool.cpp @@ -17,6 +17,8 @@ #include "playertool.h" #include "gif.h" +#include "gwavi.h" + #include #include @@ -201,7 +203,7 @@ void PlayerTool::recordMovie() QString selfFilter = tr("Movie (*.mp4)"); QString baseName = QFileDialog::getSaveFileName( qobject_cast(parent()), tr("Export Bitmap Graphics"), "", - tr("Movie (*.mp4);;GIF (*.gif)"), &selfFilter); + tr("Movie (*.mp4);;Movie (*.avi);;GIF (*.gif)"), &selfFilter); if (baseName.isEmpty()) return; @@ -214,35 +216,28 @@ void PlayerTool::recordMovie() ceil(log10(static_cast(m_molecule->coordinate3dCount()) + 1))); m_glWidget->resize(EXPORT_WIDTH, EXPORT_HEIGHT); - GifWriter writer; - if (selfFilter == tr("GIF (*.gif)")) + if (selfFilter == tr("GIF (*.gif)")) { + GifWriter writer; GifBegin(&writer, (baseName + ".gif").toLatin1().data(), EXPORT_WIDTH, - EXPORT_HEIGHT, 100); - - for (int i = 0; i < m_molecule->coordinate3dCount(); ++i) { - m_molecule->setCoordinate3d(i); - if (bonding) { - m_molecule->clearBonds(); - m_molecule->perceiveBondsSimple(); - } - m_molecule->emitChanged(Molecule::Atoms | Molecule::Modified); - QString fileName = QString::number(i); - while (fileName.length() < numberLength) - fileName.prepend('0'); - fileName.prepend(baseName); - fileName.append(".png"); - - QImage exportImage; - m_glWidget->raise(); - m_glWidget->repaint(); - if (QOpenGLFramebufferObject::hasOpenGLFramebufferObjects()) { - exportImage = m_glWidget->grabFramebuffer(); - } else { - QPixmap pixmap = QPixmap::grabWindow(m_glWidget->winId()); - exportImage = pixmap.toImage(); - } + EXPORT_HEIGHT, 100 / m_animationFPS->value()); + for (int i = 0; i < m_molecule->coordinate3dCount(); ++i) { + m_molecule->setCoordinate3d(i); + if (bonding) { + m_molecule->clearBonds(); + m_molecule->perceiveBondsSimple(); + } + m_molecule->emitChanged(Molecule::Atoms | Molecule::Modified); + + QImage exportImage; + m_glWidget->raise(); + m_glWidget->repaint(); + if (QOpenGLFramebufferObject::hasOpenGLFramebufferObjects()) { + exportImage = m_glWidget->grabFramebuffer(); + } else { + QPixmap pixmap = QPixmap::grabWindow(m_glWidget->winId()); + exportImage = pixmap.toImage(); + } - if (selfFilter == tr("GIF (*.gif)")) { int frameWidth = exportImage.width(); int frameHeight = exportImage.height(); int numbPixels = frameWidth * frameHeight; @@ -259,33 +254,87 @@ void PlayerTool::recordMovie() imageIndex += 4; } } + GifWriteFrame(&writer, imageData, EXPORT_WIDTH, EXPORT_HEIGHT, + 100 / m_animationFPS->value()); + } + GifEnd(&writer); + } else if (selfFilter == tr("Movie (*.avi)")) { + gwavi_t* gwavi; + gwavi = gwavi_open((baseName + ".avi").toLatin1().data(), EXPORT_WIDTH, + EXPORT_HEIGHT, "MJPG", m_animationFPS->value(), NULL); + for (int i = 0; i < m_molecule->coordinate3dCount(); ++i) { + m_molecule->setCoordinate3d(i); + if (bonding) { + m_molecule->clearBonds(); + m_molecule->perceiveBondsSimple(); + } + m_molecule->emitChanged(Molecule::Atoms | Molecule::Modified); + + QImage exportImage; + m_glWidget->raise(); + m_glWidget->repaint(); + if (QOpenGLFramebufferObject::hasOpenGLFramebufferObjects()) { + exportImage = m_glWidget->grabFramebuffer(); + } else { + QPixmap pixmap = QPixmap::grabWindow(m_glWidget->winId()); + exportImage = pixmap.toImage(); + } + QByteArray ba; + QBuffer buffer(&ba); + buffer.open(QIODevice::WriteOnly); + exportImage.save(&buffer, "JPG"); + + if (gwavi_add_frame( + gwavi, reinterpret_cast(buffer.data().data()), + buffer.size()) == -1) { + QMessageBox::warning(qobject_cast(parent()), tr("Avogadro"), + tr("Error: cannot add frame to video.")); + } + } + gwavi_close(gwavi); + } else if (selfFilter == tr("Movie (*.mp4)")) { + for (int i = 0; i < m_molecule->coordinate3dCount(); ++i) { + m_molecule->setCoordinate3d(i); + if (bonding) { + m_molecule->clearBonds(); + m_molecule->perceiveBondsSimple(); + } + m_molecule->emitChanged(Molecule::Atoms | Molecule::Modified); + QString fileName = QString::number(i); + while (fileName.length() < numberLength) + fileName.prepend('0'); + fileName.prepend(baseName); + fileName.append(".png"); + + QImage exportImage; + m_glWidget->raise(); + m_glWidget->repaint(); + if (QOpenGLFramebufferObject::hasOpenGLFramebufferObjects()) { + exportImage = m_glWidget->grabFramebuffer(); + } else { + QPixmap pixmap = QPixmap::grabWindow(m_glWidget->winId()); + exportImage = pixmap.toImage(); + } - GifWriteFrame(&writer, imageData, EXPORT_WIDTH, EXPORT_HEIGHT, 10); - } else if (selfFilter == tr("Movie (*.mp4)")) { if (!exportImage.save(fileName)) { QMessageBox::warning(qobject_cast(parent()), tr("Avogadro"), tr("Cannot save file %1.").arg(fileName)); return; } + QProcess proc; + QStringList args; + args << "-y" + << "-r" << QString::number(m_animationFPS->value()) << "-i" + << baseName + "%0" + QString::number(numberLength) + "d.png" + << "-c:v" + << "libx264" + << "-r" + << "30" + << "-pix_fmt" + << "yuv420p" << baseName + ".mp4"; + proc.execute("avconv", args); } } - - if (selfFilter == tr("GIF (*.gif)")) { - GifEnd(&writer); - } else if (selfFilter == tr("Movie (*.mp4)")) { - QProcess proc; - QStringList args; - args << "-y" - << "-r" << QString::number(m_animationFPS->value()) << "-i" - << baseName + "%0" + QString::number(numberLength) + "d.png" - << "-c:v" - << "libx264" - << "-r" - << "30" - << "-pix_fmt" - << "yuv420p" << baseName + ".mp4"; - proc.execute("avconv", args); - } } } // namespace QtPlugins diff --git a/thirdparty/CMakeLists.txt b/thirdparty/CMakeLists.txt index aafab700ca..1416ac4e54 100644 --- a/thirdparty/CMakeLists.txt +++ b/thirdparty/CMakeLists.txt @@ -1,2 +1,3 @@ add_subdirectory(jsoncpp) add_subdirectory(struct) +add_subdirectory(libgwavi) diff --git a/thirdparty/libgwavi/AUTHORS.md b/thirdparty/libgwavi/AUTHORS.md new file mode 100644 index 0000000000..6fd36a876c --- /dev/null +++ b/thirdparty/libgwavi/AUTHORS.md @@ -0,0 +1,8 @@ +## AUTHORS + + * Michael Kohn (2008-2011, original author of libkohn-avi) + + * Robin Hahling "Rolinh" (2013, gwavi fork + of libkohn-avi) + + diff --git a/thirdparty/libgwavi/CMakeLists.txt b/thirdparty/libgwavi/CMakeLists.txt new file mode 100644 index 0000000000..7ed2531eaf --- /dev/null +++ b/thirdparty/libgwavi/CMakeLists.txt @@ -0,0 +1,8 @@ +add_library(libgwavi STATIC gwavi.c fileio.c avi-utils.c) +set_target_properties(libgwavi PROPERTIES POSITION_INDEPENDENT_CODE TRUE) + +install(TARGETS libgwavi + EXPORT "AvogadroLibsTargets" + RUNTIME DESTINATION "${INSTALL_RUNTIME_DIR}" + LIBRARY DESTINATION "${INSTALL_LIBRARY_DIR}" + ARCHIVE DESTINATION "${INSTALL_ARCHIVE_DIR}") \ No newline at end of file diff --git a/thirdparty/libgwavi/LICENSE b/thirdparty/libgwavi/LICENSE new file mode 100644 index 0000000000..d36a216068 --- /dev/null +++ b/thirdparty/libgwavi/LICENSE @@ -0,0 +1,28 @@ +Copyright (c) 2008-2011, Michael Kohn +Copyright (c) 2013, Robin Hahling +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/thirdparty/libgwavi/README.md b/thirdparty/libgwavi/README.md new file mode 100644 index 0000000000..d844c14161 --- /dev/null +++ b/thirdparty/libgwavi/README.md @@ -0,0 +1,100 @@ +# DISCLAIMER + +Even though you can already generate AVI files, this library has not reached a +final version yet and is still a work in progress. You've been warned... ;) + +# SYNOPSIS + +`libgwavi` is a fork of `libkohn-avi`. It is a tiny C library aimed at creating +AVI files. + +Original credits go to Michael Kohn, who released his library under the LGPL +license. He, however, allowed me to release my forked version under the less +restrictive 3-clause BSD license so... Thanks to him! + +Anyway, why the fork you might ask? I used it in an application that needed the +library to be reliable. So here is what has already changed from `libkohn-avi`: + + * added library documentation + + * removed dead code + + * improved error checking + + * added unit tests + +# BUILD + +This library has no dependencies, you only need the standard C library. +To generate `libgwavi.so`, just type the following from the root's directory: + + make + +To generate the documentation of the library functions, type the following: + + make doc + +The code includes a demo application that uses `libgwavi`. You can build it +using this command: + + make examples + +# HOW TO USE IT + +For a complete example, have a look at the demo application in the examples +folder. + +If your in a hurry, here is a small explanation on how to use it. + +First, you need to include the header file. + + #include "gwavi.h" + +There is basically four main function that you will need to use: + + * `gwavi_open()` + + * `gwavi_add_frame()` + + * `gwavi_add_audio()` + + * `gwavi_close()` + +Please, note that error checking has been voluntarily omitted int the examples +below for the sake of the clarification. + +So first, you should declare a `gwavi_t` structure and initialize it. You can +optionally declare a `gwavi_audio_t` structure if you need to add an audio +channel to your AVI file. + + struct gwavi_t *gwavi; + struct gwavi_audio_t audio; + + gwavi = gwavi_open("foo.avi", + 1920, + 1080, + "MJPG", + 30, + &audio); + +Note that the audio channel is optional and that you can pass `NULL` as the last +argument of `gwavi_open()` if you don't need it. + +Then you add your video frames: + + gwavi_add_frame(gwavi, buffer, buffer_length); + +You can also add audio with `gwavi_add_audio()`. + +And at the end, you can close the output file and free the allocated memory by +calling the `gwavi_close()` function. + + gwavi_close(gwavi); + +# DOCUMENTATION + +The library documentation can be generated with `make doc` if you have +`doxygen` installed. Otherwise, you can just visit +http://doc.gw-computing.net/libgwavi. + + diff --git a/thirdparty/libgwavi/avi-utils.c b/thirdparty/libgwavi/avi-utils.c new file mode 100644 index 0000000000..8efd042c5b --- /dev/null +++ b/thirdparty/libgwavi/avi-utils.c @@ -0,0 +1,554 @@ +/* + * Copyright (c) 2008-2011, Michael Kohn + * Copyright (c) 2013, Robin Hahling + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of the author nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Set of functions useful to create an AVI file. It is used to write things + * such as AVI header and so on. + */ + +#include +#include + +#include "avi-utils.h" +#include "fileio.h" + +int write_avi_header(FILE* out, struct gwavi_header_t* avi_header) +{ + long marker, t; + + if (write_chars_bin(out, "avih", 4) == -1) { + (void)fprintf(stderr, "write_avi_header: write_chars_bin() " + "failed\n"); + return -1; + } + if ((marker = ftell(out)) == -1) { + perror("write_avi_header (ftell)"); + return -1; + } + if (write_int(out, 0) == -1) + goto write_int_failed; + + if (write_int(out, avi_header->time_delay) == -1) + goto write_int_failed; + if (write_int(out, avi_header->data_rate) == -1) + goto write_int_failed; + if (write_int(out, avi_header->reserved) == -1) + goto write_int_failed; + /* dwFlags */ + if (write_int(out, avi_header->flags) == -1) + goto write_int_failed; + /* dwTotalFrames */ + if (write_int(out, avi_header->number_of_frames) == -1) + goto write_int_failed; + if (write_int(out, avi_header->initial_frames) == -1) + goto write_int_failed; + if (write_int(out, avi_header->data_streams) == -1) + goto write_int_failed; + if (write_int(out, avi_header->buffer_size) == -1) + goto write_int_failed; + if (write_int(out, avi_header->width) == -1) + goto write_int_failed; + if (write_int(out, avi_header->height) == -1) + goto write_int_failed; + if (write_int(out, avi_header->time_scale) == -1) + goto write_int_failed; + if (write_int(out, avi_header->playback_data_rate) == -1) + goto write_int_failed; + if (write_int(out, avi_header->starting_time) == -1) + goto write_int_failed; + if (write_int(out, avi_header->data_length) == -1) + goto write_int_failed; + + if ((t = ftell(out)) == -1) { + perror("write_avi_header (ftell)"); + return -1; + } + if (fseek(out, marker, SEEK_SET) == -1) { + perror("write_avi_header (fseek)"); + return -1; + } + if (write_int(out, (unsigned int)(t - marker - 4)) == -1) + goto write_int_failed; + if (fseek(out, t, SEEK_SET) == -1) { + perror("write_avi_header (fseek)"); + return -1; + } + + return 0; + +write_int_failed: + (void)fprintf(stderr, "write_avi_header: write_int() failed\n"); + return -1; +} + +int write_stream_header(FILE* out, struct gwavi_stream_header_t* stream_header) +{ + long marker, t; + + if (write_chars_bin(out, "strh", 4) == -1) + goto write_chars_bin_failed; + if ((marker = ftell(out)) == -1) { + perror("write_stream_header (ftell)"); + return -1; + } + if (write_int(out, 0) == -1) + goto write_int_failed; + + if (write_chars_bin(out, stream_header->data_type, 4) == -1) + goto write_chars_bin_failed; + if (write_chars_bin(out, stream_header->codec, 4) == -1) + goto write_chars_bin_failed; + if (write_int(out, stream_header->flags) == -1) + goto write_int_failed; + if (write_int(out, stream_header->priority) == -1) + goto write_int_failed; + if (write_int(out, stream_header->initial_frames) == -1) + goto write_int_failed; + if (write_int(out, stream_header->time_scale) == -1) + goto write_int_failed; + if (write_int(out, stream_header->data_rate) == -1) + goto write_int_failed; + if (write_int(out, stream_header->start_time) == -1) + goto write_int_failed; + if (write_int(out, stream_header->data_length) == -1) + goto write_int_failed; + if (write_int(out, stream_header->buffer_size) == -1) + goto write_int_failed; + if (write_int(out, stream_header->video_quality) == -1) + goto write_int_failed; + if (write_int(out, stream_header->sample_size) == -1) + goto write_int_failed; + if (write_int(out, 0) == -1) + goto write_int_failed; + if (write_int(out, 0) == -1) + goto write_int_failed; + + if ((t = ftell(out)) == -1) { + perror("write_stream_header (ftell)"); + return -1; + } + if (fseek(out, marker, SEEK_SET) == -1) { + perror("write_stream_header (fseek)"); + return -1; + } + write_int(out, (unsigned int)(t - marker - 4)); + if (fseek(out, t, SEEK_SET) == -1) { + perror("write_stream_header (fseek)"); + return -1; + } + + return 0; + +write_int_failed: + (void)fprintf(stderr, "write_stream_header: write_int() failed\n"); + return -1; + +write_chars_bin_failed: + (void)fprintf(stderr, "write_stream_header: write_chars_bin() failed\n"); + return -1; +} + +int write_stream_format_v(FILE* out, + struct gwavi_stream_format_v_t* stream_format_v) +{ + long marker, t; + unsigned int i; + + if (write_chars_bin(out, "strf", 4) == -1) { + (void)fprintf(stderr, "write_stream_format_v: write_chars_bin()" + " failed\n"); + return -1; + } + if ((marker = ftell(out)) == -1) { + perror("write_stream_format_v (ftell)"); + return -1; + } + if (write_int(out, 0) == -1) + goto write_int_failed; + + if (write_int(out, stream_format_v->header_size) == -1) + goto write_int_failed; + if (write_int(out, stream_format_v->width) == -1) + goto write_int_failed; + if (write_int(out, stream_format_v->height) == -1) + goto write_int_failed; + if (write_short(out, stream_format_v->num_planes) == -1) { + (void)fprintf(stderr, "write_stream_format_v: write_short() " + "failed\n"); + return -1; + } + if (write_short(out, stream_format_v->bits_per_pixel) == -1) { + (void)fprintf(stderr, "write_stream_format_v: write_short() " + "failed\n"); + return -1; + } + if (write_int(out, stream_format_v->compression_type) == -1) + goto write_int_failed; + if (write_int(out, stream_format_v->image_size) == -1) + goto write_int_failed; + if (write_int(out, stream_format_v->x_pels_per_meter) == -1) + goto write_int_failed; + if (write_int(out, stream_format_v->y_pels_per_meter) == -1) + goto write_int_failed; + if (write_int(out, stream_format_v->colors_used) == -1) + goto write_int_failed; + if (write_int(out, stream_format_v->colors_important) == -1) + goto write_int_failed; + + if (stream_format_v->colors_used != 0) + for (i = 0; i < stream_format_v->colors_used; i++) { + if (fputc(stream_format_v->palette[i] & 255, out) == EOF) + goto fputc_failed; + if (fputc((stream_format_v->palette[i] >> 8) & 255, out) == EOF) + goto fputc_failed; + if (fputc((stream_format_v->palette[i] >> 16) & 255, out) == EOF) + goto fputc_failed; + if (fputc(0, out) == EOF) + goto fputc_failed; + } + + if ((t = ftell(out)) == -1) { + perror("write_stream_format_v (ftell)"); + return -1; + } + if (fseek(out, marker, SEEK_SET) == -1) { + perror("write_stream_format_v (fseek)"); + return -1; + } + if (write_int(out, (unsigned int)(t - marker - 4)) == -1) + goto write_int_failed; + if (fseek(out, t, SEEK_SET) == -1) { + perror("write_stream_format_v (fseek)"); + return -1; + } + + return 0; + +write_int_failed: + (void)fprintf(stderr, "write_stream_format_v: write_int() failed\n"); + return -1; + +fputc_failed: + (void)fprintf(stderr, "write_stream_format_v: fputc() failed\n"); + return -1; +} + +int write_stream_format_a(FILE* out, + struct gwavi_stream_format_a_t* stream_format_a) +{ + long marker, t; + + if (write_chars_bin(out, "strf", 4) == -1) { + (void)fprintf(stderr, "write_stream_format_a: write_chars_bin()" + " failed\n"); + return -1; + } + if ((marker = ftell(out)) == -1) { + perror("write_stream_format_a (ftell)"); + return -1; + } + if (write_int(out, 0) == -1) + goto write_int_failed; + + if (write_short(out, stream_format_a->format_type) == -1) + goto write_short_failed; + if (write_short(out, stream_format_a->channels) == -1) + goto write_short_failed; + if (write_int(out, stream_format_a->sample_rate) == -1) + goto write_int_failed; + if (write_int(out, stream_format_a->bytes_per_second) == -1) + goto write_int_failed; + if (write_short(out, stream_format_a->block_align) == -1) + goto write_short_failed; + if (write_short(out, stream_format_a->bits_per_sample) == -1) + goto write_short_failed; + if (write_short(out, stream_format_a->size) == -1) + goto write_short_failed; + + if ((t = ftell(out)) == -1) { + perror("write_stream_format_a (ftell)"); + return -1; + } + if (fseek(out, marker, SEEK_SET) == -1) { + perror("write_stream_format_a (fseek)"); + return -1; + } + if (write_int(out, (unsigned int)(t - marker - 4)) == -1) + goto write_int_failed; + if (fseek(out, t, SEEK_SET) == -1) { + perror("write_stream_format_a (fseek)"); + return -1; + } + + return 0; + +write_int_failed: + (void)fprintf(stderr, "write_stream_format_a: write_int() failed\n"); + return -1; + +write_short_failed: + (void)fprintf(stderr, "write_stream_format_a: write_short() failed\n"); + return -1; +} + +int write_avi_header_chunk(struct gwavi_t* gwavi) +{ + long marker, t; + long sub_marker; + FILE* out = gwavi->out; + + if (write_chars_bin(out, "LIST", 4) == -1) + goto write_chars_bin_failed; + if ((marker = ftell(out)) == -1) + goto ftell_failed; + if (write_int(out, 0) == -1) + goto write_int_failed; + if (write_chars_bin(out, "hdrl", 4) == -1) + goto write_chars_bin_failed; + if (write_avi_header(out, &gwavi->avi_header) == -1) { + (void)fprintf(stderr, "write_avi_header_chunk: " + "write_avi_header() failed\n"); + return -1; + } + + if (write_chars_bin(out, "LIST", 4) == -1) + goto write_chars_bin_failed; + if ((sub_marker = ftell(out)) == -1) + goto ftell_failed; + if (write_int(out, 0) == -1) + goto write_int_failed; + if (write_chars_bin(out, "strl", 4) == -1) + goto write_chars_bin_failed; + if (write_stream_header(out, &gwavi->stream_header_v) == -1) { + (void)fprintf(stderr, "write_avi_header_chunk: " + "write_stream_header failed\n"); + return -1; + } + if (write_stream_format_v(out, &gwavi->stream_format_v) == -1) { + (void)fprintf(stderr, "write_avi_header_chunk: " + "write_stream_format_v failed\n"); + return -1; + } + + if ((t = ftell(out)) == -1) + goto ftell_failed; + + if (fseek(out, sub_marker, SEEK_SET) == -1) + goto fseek_failed; + if (write_int(out, (unsigned int)(t - sub_marker - 4)) == -1) + goto write_int_failed; + if (fseek(out, t, SEEK_SET) == -1) + goto fseek_failed; + + if (gwavi->avi_header.data_streams == 2) { + if (write_chars_bin(out, "LIST", 4) == -1) + goto write_chars_bin_failed; + if ((sub_marker = ftell(out)) == -1) + goto ftell_failed; + if (write_int(out, 0) == -1) + goto write_int_failed; + if (write_chars_bin(out, "strl", 4) == -1) + goto write_chars_bin_failed; + if (write_stream_header(out, &gwavi->stream_header_a) == -1) { + (void)fprintf(stderr, "write_avi_header_chunk: " + "write_stream_header failed\n"); + return -1; + } + if (write_stream_format_a(out, &gwavi->stream_format_a) == -1) { + (void)fprintf(stderr, "write_avi_header_chunk: " + "write_stream_format_a failed\n"); + return -1; + } + + if ((t = ftell(out)) == -1) + goto ftell_failed; + if (fseek(out, sub_marker, SEEK_SET) == -1) + goto fseek_failed; + if (write_int(out, (unsigned int)(t - sub_marker - 4)) == -1) + goto write_int_failed; + if (fseek(out, t, SEEK_SET) == -1) + goto fseek_failed; + } + + if ((t = ftell(out)) == -1) + goto ftell_failed; + if (fseek(out, marker, SEEK_SET) == -1) + goto fseek_failed; + if (write_int(out, (unsigned int)(t - marker - 4)) == -1) + goto write_int_failed; + if (fseek(out, t, SEEK_SET) == -1) + goto fseek_failed; + + return 0; + +ftell_failed: + perror("write_avi_header_chunk (ftell)"); + return -1; + +fseek_failed: + perror("write_avi_header_chunk (fseek)"); + return -1; + +write_int_failed: + (void)fprintf(stderr, "write_avi_header_chunk: write_int() failed\n"); + return -1; + +write_chars_bin_failed: + (void)fprintf(stderr, "write_avi_header_chunk: write_chars_bin() failed\n"); + return -1; +} + +int write_index(FILE* out, int count, unsigned int* offsets) +{ + long marker, t; + unsigned int offset = 4; + + if (offsets == 0) + return -1; + + if (write_chars_bin(out, "idx1", 4) == -1) { + (void)fprintf(stderr, "write_index: write_chars_bin) failed\n"); + return -1; + } + if ((marker = ftell(out)) == -1) { + perror("write_index (ftell)"); + return -1; + } + if (write_int(out, 0) == -1) + goto write_int_failed; + + for (t = 0; t < count; t++) { + if ((offsets[t] & 0x80000000) == 0) + write_chars(out, "00dc"); + else { + write_chars(out, "01wb"); + offsets[t] &= 0x7fffffff; + } + if (write_int(out, 0x10) == -1) + goto write_int_failed; + if (write_int(out, offset) == -1) + goto write_int_failed; + if (write_int(out, offsets[t]) == -1) + goto write_int_failed; + + offset = offset + offsets[t] + 8; + } + + if ((t = ftell(out)) == -1) { + perror("write_index (ftell)"); + return -1; + } + if (fseek(out, marker, SEEK_SET) == -1) { + perror("write_index (fseek)"); + return -1; + } + if (write_int(out, (unsigned int)(t - marker - 4)) == -1) + goto write_int_failed; + if (fseek(out, t, SEEK_SET) == -1) { + perror("write_index (fseek)"); + return -1; + } + + return 0; + +write_int_failed: + (void)fprintf(stderr, "write_index: write_int() failed\n"); + return -1; +} + +/** + * Return 0 if fourcc is valid, 1 non-valid or -1 in case of errors. + */ +int check_fourcc(const char* fourcc) +{ + int ret = 0; + /* list of fourccs from http://fourcc.org/codecs.php */ + const char valid_fourcc[] = + "3IV1 3IV2 8BPS" + "AASC ABYR ADV1 ADVJ AEMI AFLC AFLI AJPG AMPG ANIM AP41 ASLC" + "ASV1 ASV2 ASVX AUR2 AURA AVC1 AVRN" + "BA81 BINK BLZ0 BT20 BTCV BW10 BYR1 BYR2" + "CC12 CDVC CFCC CGDI CHAM CJPG CMYK CPLA CRAM CSCD CTRX CVID" + "CWLT CXY1 CXY2 CYUV CYUY" + "D261 D263 DAVC DCL1 DCL2 DCL3 DCL4 DCL5 DIV3 DIV4 DIV5 DIVX" + "DM4V DMB1 DMB2 DMK2 DSVD DUCK DV25 DV50 DVAN DVCS DVE2 DVH1" + "DVHD DVSD DVSL DVX1 DVX2 DVX3 DX50 DXGM DXTC DXTN" + "EKQ0 ELK0 EM2V ES07 ESCP ETV1 ETV2 ETVC" + "FFV1 FLJP FMP4 FMVC FPS1 FRWA FRWD FVF1" + "GEOX GJPG GLZW GPEG GWLT" + "H260 H261 H262 H263 H264 H265 H266 H267 H268 H269" + "HDYC HFYU HMCR HMRR" + "I263 ICLB IGOR IJPG ILVC ILVR IPDV IR21 IRAW ISME" + "IV30 IV31 IV32 IV33 IV34 IV35 IV36 IV37 IV38 IV39 IV40 IV41" + "IV41 IV43 IV44 IV45 IV46 IV47 IV48 IV49 IV50" + "JBYR JPEG JPGL" + "KMVC" + "L261 L263 LBYR LCMW LCW2 LEAD LGRY LJ11 LJ22 LJ2K LJ44 LJPG" + "LMP2 LMP4 LSVC LSVM LSVX LZO1" + "M261 M263 M4CC M4S2 MC12 MCAM MJ2C MJPG MMES MP2A MP2T MP2V" + "MP42 MP43 MP4A MP4S MP4T MP4V MPEG MPG4 MPGI MR16 MRCA MRLE" + "MSVC MSZH" + "MTX1 MTX2 MTX3 MTX4 MTX5 MTX6 MTX7 MTX8 MTX9" + "MVI1 MVI2 MWV1" + "NAVI NDSC NDSM NDSP NDSS NDXC NDXH NDXP NDXS NHVU NTN1 NTN2" + "NVDS NVHS" + "NVS0 NVS1 NVS2 NVS3 NVS4 NVS5" + "NVT0 NVT1 NVT2 NVT3 NVT4 NVT5" + "PDVC PGVV PHMO PIM1 PIM2 PIMJ PIXL PJPG PVEZ PVMM PVW2" + "QPEG QPEQ" + "RGBT RLE RLE4 RLE8 RMP4 RPZA RT21 RV20 RV30 RV40 S422 SAN3" + "SDCC SEDG SFMC SMP4 SMSC SMSD SMSV SP40 SP44 SP54 SPIG SQZ2" + "STVA STVB STVC STVX STVY SV10 SVQ1 SVQ3" + "TLMS TLST TM20 TM2X TMIC TMOT TR20 TSCC TV10 TVJP TVMJ TY0N" + "TY2C TY2N" + "UCOD ULTI" + "V210 V261 V655 VCR1 VCR2 VCR3 VCR4 VCR5 VCR6 VCR7 VCR8 VCR9" + "VDCT VDOM VDTZ VGPX VIDS VIFP VIVO VIXL VLV1 VP30 VP31 VP40" + "VP50 VP60 VP61 VP62 VP70 VP80 VQC1 VQC2 VQJC VSSV VUUU VX1K" + "VX2K VXSP VYU9 VYUY" + "WBVC WHAM WINX WJPG WMV1 WMV2 WMV3 WMVA WNV1 WVC1" + "X263 X264 XLV0 XMPG XVID" + "XWV0 XWV1 XWV2 XWV3 XWV4 XWV5 XWV6 XWV7 XWV8 XWV9" + "XXAN" + "Y16 Y411 Y41P Y444 Y8 YC12 YUV8 YUV9 YUVP YUY2 YUYV YV12 YV16" + "YV92" + "ZLIB ZMBV ZPEG ZYGO ZYYY"; + + if (!fourcc) { + (void)fputs("fourcc cannot be NULL", stderr); + return -1; + } + if (strchr(fourcc, ' ') || !strstr(valid_fourcc, fourcc)) + ret = 1; + + return ret; +} diff --git a/thirdparty/libgwavi/avi-utils.h b/thirdparty/libgwavi/avi-utils.h new file mode 100644 index 0000000000..0e7604dca8 --- /dev/null +++ b/thirdparty/libgwavi/avi-utils.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2008-2011, Michael Kohn + * Copyright (c) 2013, Robin Hahling + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of the author nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef H_GWAVI_UTILS +#define H_GWAVI_UTILS + +#include "gwavi.h" +#include "gwavi_private.h" + +/* + * Utility functions for gwavi library. + */ + +#ifdef __cplusplus +extern "C" +{ +#endif + + /* Functions declaration */ + int write_avi_header(FILE* out, struct gwavi_header_t* avi_header); + int write_stream_header(FILE* out, + struct gwavi_stream_header_t* stream_header); + int write_stream_format_v(FILE* out, + struct gwavi_stream_format_v_t* stream_format_v); + int write_stream_format_a(FILE* out, + struct gwavi_stream_format_a_t* stream_format_a); + int write_avi_header_chunk(struct gwavi_t* gwavi); + int write_index(FILE* out, int count, unsigned int* offsets); + int check_fourcc(const char* fourcc); + +#ifdef __cplusplus +} +#endif + +#endif /* ndef GWAVI_UTILS_H */ diff --git a/thirdparty/libgwavi/fileio.c b/thirdparty/libgwavi/fileio.c new file mode 100644 index 0000000000..e31c481827 --- /dev/null +++ b/thirdparty/libgwavi/fileio.c @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2008-2011, Michael Kohn + * Copyright (c) 2013, Robin Hahling + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of the author nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Usefull IO functions. + */ + +#include + +int write_int(FILE* out, unsigned int n) +{ + if (fputc((n & 255), out) == EOF) + return -1; + if (fputc(((n >> 8) & 255), out) == EOF) + return -1; + if (fputc(((n >> 16) & 255), out) == EOF) + return -1; + if (fputc(((n >> 24) & 255), out) == EOF) + return -1; + + return 0; +} + +int write_short(FILE* out, unsigned int n) +{ + if (fputc((n & 255), out) == EOF) + return -1; + if (fputc(((n >> 8) & 255), out) == EOF) + return -1; + + return 0; +} + +int write_chars(FILE* out, char* s) +{ + int t = 0; + + while (s[t] != 0 && t < 255) + if (fputc(s[t++], out) == EOF) + return -1; + + return 0; +} + +int write_chars_bin(FILE* out, char* s, int count) +{ + int t; + + for (t = 0; t < count; t++) + if (fputc(s[t], out) == EOF) + return -1; + + return 0; +} diff --git a/thirdparty/libgwavi/fileio.h b/thirdparty/libgwavi/fileio.h new file mode 100644 index 0000000000..d2b9394886 --- /dev/null +++ b/thirdparty/libgwavi/fileio.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2008-2011, Michael Kohn + * Copyright (c) 2013, Robin Hahling + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of the author nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Header file for fileio.c + */ +#ifndef H_FILEIO +#define H_FILEIO + +#ifdef __cplusplus +extern "C" +{ +#endif + /* Function prototypes */ + int write_int(FILE* out, unsigned int n); + int write_short(FILE* out, unsigned int n); + int write_chars(FILE* out, char* s); + int write_chars_bin(FILE* out, char* s, int count); + +#ifdef __cplusplus +} +#endif + +#endif /* ndef H_FILEIO */ diff --git a/thirdparty/libgwavi/gwavi.c b/thirdparty/libgwavi/gwavi.c new file mode 100644 index 0000000000..7c1e57c8ab --- /dev/null +++ b/thirdparty/libgwavi/gwavi.c @@ -0,0 +1,502 @@ +/* + * Copyright (c) 2008-2011, Michael Kohn + * Copyright (c) 2013, Robin Hahling + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of the author nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * This is the file containing gwavi library functions. + */ + +#include +#include +#include + +#include "avi-utils.h" +#include "fileio.h" +#include "gwavi.h" +#include "gwavi_private.h" + +/** + * This is the first function you should call when using gwavi library. + * It allocates memory for a gwavi_t structure and returns it and takes care of + * initializing the AVI header with the provided information. + * + * When you're done creating your AVI file, you should call gwavi_close() + * function to free memory allocated for the gwavi_t structure and properly + * close the output file. + * + * @param filename This is the name of the AVI file which will be generated by + * this library. + * @param width Width of a frame. + * @param height Height of a frame. + * @param fourcc FourCC representing the codec of the video encoded stream. a + * FourCC is a sequence of four chars used to uniquely identify data formats. + * For more information, you can visit www.fourcc.org. + * @param fps Number of frames per second of your video. It needs to be > 0. + * @param audio This parameter is optionnal. It is used for the audio track. If + * you do not want to add an audio track to your AVI file, simply pass NULL for + * this argument. + * + * @return Structure containing required information in order to create the AVI + * file. If an error occured, NULL is returned. + */ +struct gwavi_t* gwavi_open(const char* filename, unsigned int width, + unsigned int height, const char* fourcc, + unsigned int fps, struct gwavi_audio_t* audio) +{ + struct gwavi_t* gwavi; + FILE* out; + + if (check_fourcc(fourcc) != 0) + (void)fprintf(stderr, + "WARNING: given fourcc does not seem to " + "be valid: %s\n", + fourcc); + if (fps < 1) + return NULL; + if ((out = fopen(filename, "wb+")) == NULL) { + perror("gwavi_open: failed to open file for writing"); + return NULL; + } + + if ((gwavi = malloc(sizeof(struct gwavi_t))) == NULL) { + (void)fprintf(stderr, "gwavi_open: could not allocate memoryi " + "for gwavi structure\n"); + return NULL; + } + memset(gwavi, 0, sizeof(struct gwavi_t)); + + gwavi->out = out; + + /* set avi header */ + gwavi->avi_header.time_delay = 1000000 / fps; + gwavi->avi_header.data_rate = width * height * 3; + gwavi->avi_header.flags = 0x10; + + if (audio) + gwavi->avi_header.data_streams = 2; + else + gwavi->avi_header.data_streams = 1; + + /* this field gets updated when calling gwavi_close() */ + gwavi->avi_header.number_of_frames = 0; + gwavi->avi_header.width = width; + gwavi->avi_header.height = height; + gwavi->avi_header.buffer_size = (width * height * 3); + + /* set stream header */ + (void)strcpy(gwavi->stream_header_v.data_type, "vids"); + (void)memcpy(gwavi->stream_header_v.codec, fourcc, 4); + gwavi->stream_header_v.time_scale = 1; + gwavi->stream_header_v.data_rate = fps; + gwavi->stream_header_v.buffer_size = (width * height * 3); + gwavi->stream_header_v.data_length = 0; + + /* set stream format */ + gwavi->stream_format_v.header_size = 40; + gwavi->stream_format_v.width = width; + gwavi->stream_format_v.height = height; + gwavi->stream_format_v.num_planes = 1; + gwavi->stream_format_v.bits_per_pixel = 24; + gwavi->stream_format_v.compression_type = + ((unsigned int)fourcc[3] << 24) + ((unsigned int)fourcc[2] << 16) + + ((unsigned int)fourcc[1] << 8) + ((unsigned int)fourcc[0]); + gwavi->stream_format_v.image_size = width * height * 3; + gwavi->stream_format_v.colors_used = 0; + gwavi->stream_format_v.colors_important = 0; + + gwavi->stream_format_v.palette = 0; + gwavi->stream_format_v.palette_count = 0; + + if (audio) { + /* set stream header */ + memcpy(gwavi->stream_header_a.data_type, "auds", 4); + gwavi->stream_header_a.codec[0] = 1; + gwavi->stream_header_a.codec[1] = 0; + gwavi->stream_header_a.codec[2] = 0; + gwavi->stream_header_a.codec[3] = 0; + gwavi->stream_header_a.time_scale = 1; + gwavi->stream_header_a.data_rate = audio->samples_per_second; + gwavi->stream_header_a.buffer_size = + audio->channels * (audio->bits / 8) * audio->samples_per_second; + /* when set to -1, drivers use default quality value */ + gwavi->stream_header_a.audio_quality = -1; + gwavi->stream_header_a.sample_size = (audio->bits / 8) * audio->channels; + + /* set stream format */ + gwavi->stream_format_a.format_type = 1; + gwavi->stream_format_a.channels = audio->channels; + gwavi->stream_format_a.sample_rate = audio->samples_per_second; + gwavi->stream_format_a.bytes_per_second = + audio->channels * (audio->bits / 8) * audio->samples_per_second; + gwavi->stream_format_a.block_align = audio->channels * (audio->bits / 8); + gwavi->stream_format_a.bits_per_sample = audio->bits; + gwavi->stream_format_a.size = 0; + } + + if (write_chars_bin(out, "RIFF", 4) == -1) + goto write_chars_bin_failed; + if (write_int(out, 0) == -1) { + (void)fprintf(stderr, "gwavi_info: write_int() failed\n"); + return NULL; + } + if (write_chars_bin(out, "AVI ", 4) == -1) + goto write_chars_bin_failed; + + if (write_avi_header_chunk(gwavi) == -1) { + (void)fprintf(stderr, "gwavi_info: write_avi_header_chunk " + "failed\n"); + return NULL; + } + + if (write_chars_bin(out, "LIST", 4) == -1) + goto write_chars_bin_failed; + if ((gwavi->marker = ftell(out)) == -1) { + perror("gwavi_info (ftell)"); + return NULL; + } + if (write_int(out, 0) == -1) { + (void)fprintf(stderr, "gwavi_info: write_int() failed\n"); + return NULL; + } + if (write_chars_bin(out, "movi", 4) == -1) + goto write_chars_bin_failed; + + gwavi->offsets_len = 1024; + if ((gwavi->offsets = + malloc((size_t)gwavi->offsets_len * sizeof(unsigned int))) == NULL) { + (void)fprintf(stderr, "gwavi_info: could not allocate memory " + "for gwavi offsets table\n"); + return NULL; + } + + gwavi->offsets_ptr = 0; + + return gwavi; + +write_chars_bin_failed: + (void)fprintf(stderr, "gwavi_open: write_chars_bin() failed\n"); + return NULL; +} + +/** + * This function allows you to add an encoded video frame to the AVI file. + * + * @param gwavi Main gwavi structure initialized with gwavi_open()- + * @param buffer Video buffer size. + * @param len Video buffer length. + * + * @return 0 on success, -1 on error. + */ +int gwavi_add_frame(struct gwavi_t* gwavi, const unsigned char* buffer, + size_t len) +{ + size_t maxi_pad; /* if your frame is raggin, give it some paddin' */ + size_t t; + + if (!gwavi || !buffer) { + (void)fputs("gwavi and/or buffer argument cannot be NULL", stderr); + return -1; + } + if (len < 256) + (void)fprintf(stderr, + "WARNING: specified buffer len seems " + "rather small: %d. Are you sure about this?\n", + (int)len); + + gwavi->offset_count++; + gwavi->stream_header_v.data_length++; + + maxi_pad = len % 4; + if (maxi_pad > 0) + maxi_pad = 4 - maxi_pad; + + if (gwavi->offset_count >= gwavi->offsets_len) { + gwavi->offsets_len += 1024; + gwavi->offsets = realloc(gwavi->offsets, + (size_t)gwavi->offsets_len * sizeof(unsigned int)); + } + + gwavi->offsets[gwavi->offsets_ptr++] = (unsigned int)(len + maxi_pad); + + if (write_chars_bin(gwavi->out, "00dc", 4) == -1) { + (void)fprintf(stderr, "gwavi_add_frame: write_chars_bin() " + "failed\n"); + return -1; + } + if (write_int(gwavi->out, (unsigned int)(len + maxi_pad)) == -1) { + (void)fprintf(stderr, "gwavi_add_frame: write_int() failed\n"); + return -1; + } + + if ((t = fwrite(buffer, 1, len, gwavi->out)) != len) { + (void)fprintf(stderr, "gwavi_add_frame: fwrite() failed\n"); + return -1; + } + + for (t = 0; t < maxi_pad; t++) + if (fputc(0, gwavi->out) == EOF) { + (void)fprintf(stderr, "gwavi_add_frame: fputc() failed\n"); + return -1; + } + + return 0; +} + +/** + * This function allows you to add the audio track to your AVI file. + * + * @param gwavi Main gwavi structure initialized with gwavi_open()- + * @param buffer Audio buffer size. + * @param len Audio buffer length. + * + * @return 0 on success, -1 on error. + */ +int gwavi_add_audio(struct gwavi_t* gwavi, const unsigned char* buffer, + size_t len) +{ + size_t maxi_pad; /* in case audio bleeds over the 4 byte boundary */ + size_t t; + + if (!gwavi || !buffer) { + (void)fputs("gwavi and/or buffer argument cannot be NULL", stderr); + return -1; + } + + gwavi->offset_count++; + + maxi_pad = len % 4; + if (maxi_pad > 0) + maxi_pad = 4 - maxi_pad; + + if (gwavi->offset_count >= gwavi->offsets_len) { + gwavi->offsets_len += 1024; + gwavi->offsets = realloc(gwavi->offsets, + (size_t)gwavi->offsets_len * sizeof(unsigned int)); + } + + gwavi->offsets[gwavi->offsets_ptr++] = + (unsigned int)((len + maxi_pad) | 0x80000000); + + if (write_chars_bin(gwavi->out, "01wb", 4) == -1) { + (void)fprintf(stderr, "gwavi_add_audio: write_chars_bin() " + "failed\n"); + return -1; + } + if (write_int(gwavi->out, (unsigned int)(len + maxi_pad)) == -1) { + (void)fprintf(stderr, "gwavi_add_audio: write_int() failed\n"); + return -1; + } + + if ((t = fwrite(buffer, 1, len, gwavi->out)) != len) { + (void)fprintf(stderr, "gwavi_add_audio: fwrite() failed\n"); + return -1; + } + + for (t = 0; t < maxi_pad; t++) + if (fputc(0, gwavi->out) == EOF) { + (void)fprintf(stderr, "gwavi_add_audio: fputc() failed\n"); + return -1; + } + + gwavi->stream_header_a.data_length += (unsigned int)(len + maxi_pad); + + return 0; +} + +/** + * This function should be called when the program is done adding video and/or + * audio frames to the AVI file. It frees memory allocated for gwavi_open() for + * the main gwavi_t structure. It also properly closes the output file. + * + * @param gwavi Main gwavi structure initialized with gwavi_open()- + * + * @return 0 on success, -1 on error. + */ +int gwavi_close(struct gwavi_t* gwavi) +{ + long t; + + if (!gwavi) { + (void)fputs("gwavi argument cannot be NULL", stderr); + return -1; + } + + if ((t = ftell(gwavi->out)) == -1) + goto ftell_failed; + if (fseek(gwavi->out, gwavi->marker, SEEK_SET) == -1) + goto fseek_failed; + if (write_int(gwavi->out, (unsigned int)(t - gwavi->marker - 4)) == -1) { + (void)fprintf(stderr, "gwavi_close: write_int() failed\n"); + return -1; + } + if (fseek(gwavi->out, t, SEEK_SET) == -1) + goto fseek_failed; + + if (write_index(gwavi->out, gwavi->offset_count, gwavi->offsets) == -1) { + (void)fprintf(stderr, "gwavi_close: write_index() failed\n"); + return -1; + } + + free(gwavi->offsets); + + /* reset some avi header fields */ + gwavi->avi_header.number_of_frames = gwavi->stream_header_v.data_length; + + if ((t = ftell(gwavi->out)) == -1) + goto ftell_failed; + if (fseek(gwavi->out, 12, SEEK_SET) == -1) + goto fseek_failed; + if (write_avi_header_chunk(gwavi) == -1) { + (void)fprintf(stderr, "gwavi_close: write_avi_header_chunk() " + "failed\n"); + return -1; + } + if (fseek(gwavi->out, t, SEEK_SET) == -1) + goto fseek_failed; + + if ((t = ftell(gwavi->out)) == -1) + goto ftell_failed; + if (fseek(gwavi->out, 4, SEEK_SET) == -1) + goto fseek_failed; + if (write_int(gwavi->out, (unsigned int)(t - 8)) == -1) { + (void)fprintf(stderr, "gwavi_close: write_int() failed\n"); + return -1; + } + if (fseek(gwavi->out, t, SEEK_SET) == -1) + goto fseek_failed; + + if (gwavi->stream_format_v.palette != 0) + free(gwavi->stream_format_v.palette); + + if (fclose(gwavi->out) == EOF) { + perror("gwavi_close (fclose)"); + return -1; + } + free(gwavi); + + return 0; + +ftell_failed: + perror("gwavi_close: (ftell)"); + return -1; + +fseek_failed: + perror("gwavi_close (fseek)"); + return -1; +} + +/** + * This function allows you to reset the framerate. In a standard use case, you + * should not need to call it. However, if you need to, you can call it to reset + * the framerate after you are done adding frames to your AVI file and before + * you call gwavi_close(). + * + * @param gwavi Main gwavi structure initialized with gwavi_open()- + * @param fps Number of frames per second of your video. + * + * @return 0 on success, -1 on error. + */ +int gwavi_set_framerate(struct gwavi_t* gwavi, unsigned int fps) +{ + if (!gwavi) { + (void)fputs("gwavi argument cannot be NULL", stderr); + return -1; + } + gwavi->stream_header_v.data_rate = fps; + gwavi->avi_header.time_delay = (10000000 / fps); + + return 0; +} + +/** + * This function allows you to reset the video codec. In a standard use case, + * you should not need to call it. However, if you need to, you can call it to + * reset the video codec after you are done adding frames to your AVI file and + * before you call gwavi_close(). + * + * @param gwavi Main gwavi structure initialized with gwavi_open()- + * @param fourcc FourCC representing the codec of the video encoded stream. a + * + * @return 0 on success, -1 on error. + */ +int gwavi_set_codec(struct gwavi_t* gwavi, char* fourcc) +{ + if (!gwavi) { + (void)fputs("gwavi argument cannot be NULL", stderr); + return -1; + } + if (check_fourcc(fourcc) != 0) + (void)fprintf(stderr, + "WARNING: given fourcc does not seem to " + "be valid: %s\n", + fourcc); + + memcpy(gwavi->stream_header_v.codec, fourcc, 4); + gwavi->stream_format_v.compression_type = + ((unsigned int)fourcc[3] << 24) + ((unsigned int)fourcc[2] << 16) + + ((unsigned int)fourcc[1] << 8) + ((unsigned int)fourcc[0]); + + return 0; +} + +/** + * This function allows you to reset the video size. In a standard use case, you + * should not need to call it. However, if you need to, you can call it to reset + * the video height and width set in the AVI file after you are done adding + * frames to your AVI file and before you call gwavi_close(). + * + * @param gwavi Main gwavi structure initialized with gwavi_open()- + * @param width Width of a frame. + * @param height Height of a frame. + * + * @return 0 on success, -1 on error. + */ +int gwavi_set_size(struct gwavi_t* gwavi, unsigned int width, + unsigned int height) +{ + unsigned int size = (width * height * 3); + + if (!gwavi) { + (void)fputs("gwavi argument cannot be NULL", stderr); + return -1; + } + + gwavi->avi_header.data_rate = size; + gwavi->avi_header.width = width; + gwavi->avi_header.height = height; + gwavi->avi_header.buffer_size = size; + gwavi->stream_header_v.buffer_size = size; + gwavi->stream_format_v.width = width; + gwavi->stream_format_v.height = height; + gwavi->stream_format_v.image_size = size; + + return 0; +} diff --git a/thirdparty/libgwavi/gwavi.h b/thirdparty/libgwavi/gwavi.h new file mode 100644 index 0000000000..fdeb4e4c9e --- /dev/null +++ b/thirdparty/libgwavi/gwavi.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2008-2011, Michael Kohn + * Copyright (c) 2013, Robin Hahling + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of the author nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef H_GWAVI +#define H_GWAVI + +#ifdef __cplusplus +extern "C" +{ +#endif + + /* structures */ + struct gwavi_t; + struct gwavi_audio_t; + + /* Main library functions */ + struct gwavi_t* gwavi_open(const char* filename, unsigned int width, + unsigned int height, const char* fourcc, + unsigned int fps, struct gwavi_audio_t* audio); + int gwavi_add_frame(struct gwavi_t* gwavi, const unsigned char* buffer, + size_t len); + int gwavi_add_audio(struct gwavi_t* gwavi, const unsigned char* buffer, + size_t len); + int gwavi_close(struct gwavi_t* gwavi); + + /* + * If needed, these functions can be called before closing the file to + * change the framerate, codec, size. + * Note: AVI can only have a single frame rate, codec, size for the whole file + * so this affects anything recorded before these functions are called. + */ + int gwavi_set_framerate(struct gwavi_t* gwavi, unsigned int fps); + int gwavi_set_codec(struct gwavi_t* gwavi, char* fourcc); + int gwavi_set_size(struct gwavi_t* gwavi, unsigned int width, + unsigned int height); + +#ifdef __cplusplus +} +#endif + +#endif /* ndef H_GWAVI */ diff --git a/thirdparty/libgwavi/gwavi_private.h b/thirdparty/libgwavi/gwavi_private.h new file mode 100644 index 0000000000..de5fc62960 --- /dev/null +++ b/thirdparty/libgwavi/gwavi_private.h @@ -0,0 +1,111 @@ +#ifndef GWAVI_PRIVATE_H +#define GWAVI_PRIVATE_H +/* + * gwavi_private.h + * + * gwavi declarations that shall remain private :-) + */ + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + /* structures */ + struct gwavi_header_t + { + unsigned int time_delay; /* dwMicroSecPerFrame */ + unsigned int data_rate; /* dwMaxBytesPerSec */ + unsigned int reserved; + unsigned int flags; /* dwFlags */ + unsigned int number_of_frames; /* dwTotalFrames */ + unsigned int initial_frames; /* dwInitialFrames */ + unsigned int data_streams; /* dwStreams */ + unsigned int buffer_size; /* dwSuggestedBufferSize */ + unsigned int width; /* dwWidth */ + unsigned int height; /* dwHeight */ + unsigned int time_scale; + unsigned int playback_data_rate; + unsigned int starting_time; + unsigned int data_length; + }; + + struct gwavi_stream_header_t + { + char data_type[5]; /* fccType */ + char codec[5]; /* fccHandler */ + unsigned int flags; /* dwFlags */ + unsigned int priority; + unsigned int initial_frames; /* dwInitialFrames */ + unsigned int time_scale; /* dwScale */ + unsigned int data_rate; /* dwRate */ + unsigned int start_time; /* dwStart */ + unsigned int data_length; /* dwLength */ + unsigned int buffer_size; /* dwSuggestedBufferSize */ + unsigned int video_quality; /* dwQuality */ + /** + * Value between 0-10000. If set to -1, drivers use default quality + * value. + */ + int audio_quality; + unsigned int sample_size; /* dwSampleSize */ + }; + + struct gwavi_stream_format_v_t + { + unsigned int header_size; + unsigned int width; + unsigned int height; + unsigned short int num_planes; + unsigned short int bits_per_pixel; + unsigned int compression_type; + unsigned int image_size; + unsigned int x_pels_per_meter; + unsigned int y_pels_per_meter; + unsigned int colors_used; + unsigned int colors_important; + unsigned int* palette; + unsigned int palette_count; + }; + + struct gwavi_stream_format_a_t + { + unsigned short format_type; + unsigned int channels; + unsigned int sample_rate; + unsigned int bytes_per_second; + unsigned int block_align; + unsigned int bits_per_sample; + unsigned short size; + }; + + struct gwavi_t + { + FILE* out; + struct gwavi_header_t avi_header; + struct gwavi_stream_header_t stream_header_v; + struct gwavi_stream_format_v_t stream_format_v; + struct gwavi_stream_header_t stream_header_a; + struct gwavi_stream_format_a_t stream_format_a; + long marker; + int offsets_ptr; + int offsets_len; + long offsets_start; + unsigned int* offsets; + int offset_count; + }; + + struct gwavi_audio_t + { + unsigned int channels; + unsigned int bits; + unsigned int samples_per_second; + }; + +#ifdef __cplusplus +} +#endif + +#endif /* ndef GWAVI_PRIVATE_H */ From 95f200453ff79d6477208f2b570b9aa915c01b90 Mon Sep 17 00:00:00 2001 From: badarsh2 Date: Tue, 10 Jul 2018 18:14:06 +0530 Subject: [PATCH 04/68] Basic force rendering scheme --- avogadro/qtplugins/CMakeLists.txt | 1 + avogadro/qtplugins/force/CMakeLists.txt | 9 + avogadro/qtplugins/force/force.cpp | 75 +++++++++ avogadro/qtplugins/force/force.h | 58 +++++++ avogadro/rendering/CMakeLists.txt | 3 + avogadro/rendering/arrow_vs.glsl | 10 ++ avogadro/rendering/arrowgeometry.cpp | 212 ++++++++++++++++++++++++ avogadro/rendering/arrowgeometry.h | 114 +++++++++++++ 8 files changed, 482 insertions(+) create mode 100644 avogadro/qtplugins/force/CMakeLists.txt create mode 100644 avogadro/qtplugins/force/force.cpp create mode 100644 avogadro/qtplugins/force/force.h create mode 100644 avogadro/rendering/arrow_vs.glsl create mode 100644 avogadro/rendering/arrowgeometry.cpp create mode 100644 avogadro/rendering/arrowgeometry.h diff --git a/avogadro/qtplugins/CMakeLists.txt b/avogadro/qtplugins/CMakeLists.txt index ab10bcaed2..4422601c36 100644 --- a/avogadro/qtplugins/CMakeLists.txt +++ b/avogadro/qtplugins/CMakeLists.txt @@ -146,6 +146,7 @@ add_subdirectory(ballandstick) add_subdirectory(licorice) add_subdirectory(vanderwaals) add_subdirectory(wireframe) +add_subdirectory(force) add_subdirectory(meshes) add_subdirectory(overlayaxes) add_subdirectory(vanderwaalsao) diff --git a/avogadro/qtplugins/force/CMakeLists.txt b/avogadro/qtplugins/force/CMakeLists.txt new file mode 100644 index 0000000000..d38c82201a --- /dev/null +++ b/avogadro/qtplugins/force/CMakeLists.txt @@ -0,0 +1,9 @@ +avogadro_plugin(Force + "Force rendering scheme" + ScenePlugin + force.h + Force + force.cpp + "") + +target_link_libraries(Force LINK_PRIVATE AvogadroRendering) diff --git a/avogadro/qtplugins/force/force.cpp b/avogadro/qtplugins/force/force.cpp new file mode 100644 index 0000000000..6d6c801aa6 --- /dev/null +++ b/avogadro/qtplugins/force/force.cpp @@ -0,0 +1,75 @@ +/****************************************************************************** + + This source file is part of the Avogadro project. + + Copyright 2018 Kitware, Inc. + + This source code is released under the New BSD License, (the "License"). + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +******************************************************************************/ + +#include "force.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace Avogadro { +namespace QtPlugins { + +using Core::Array; +using Core::Elements; +using Core::Molecule; +using Rendering::ArrowGeometry; +using Rendering::GeometryNode; +using Rendering::GroupNode; + +Force::Force(QObject* p) + : ScenePlugin(p) + , m_enabled(false) +{} + +Force::~Force() {} + +void Force::process(const Molecule& molecule, Rendering::GroupNode& node) +{ + GeometryNode* geometry = new GeometryNode; + node.addChild(geometry); + + ArrowGeometry* arrows = new ArrowGeometry; + arrows->identifier().molecule = &molecule; + geometry->addDrawable(arrows); + for (Index i = 0; i < molecule.atomCount(); ++i) { + Core::Atom atom1 = molecule.atom(i); + Vector3f pos1 = atom1.position3d().cast(); + Vector3f forceVector(2.0, 2.0, 2.0); + arrows->addSingleArrow(pos1, pos1 + forceVector); + } +} + +bool Force::isEnabled() const +{ + return m_enabled; +} + +void Force::setEnabled(bool enable) +{ + m_enabled = enable; +} +} +} diff --git a/avogadro/qtplugins/force/force.h b/avogadro/qtplugins/force/force.h new file mode 100644 index 0000000000..ac98f17753 --- /dev/null +++ b/avogadro/qtplugins/force/force.h @@ -0,0 +1,58 @@ +/****************************************************************************** + + This source file is part of the Avogadro project. + + Copyright 2012 Kitware, Inc. + + This source code is released under the New BSD License, (the "License"). + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +******************************************************************************/ + +#ifndef AVOGADRO_QTPLUGINS_WIREFRAME_H +#define AVOGADRO_QTPLUGINS_WIREFRAME_H + +#include + +namespace Avogadro { +namespace QtPlugins { + +/** + * @brief Render a molecule in the wireframe style. + */ +class Force : public QtGui::ScenePlugin +{ + Q_OBJECT + +public: + explicit Force(QObject* parent = 0); + ~Force() override; + + void process(const Core::Molecule& molecule, + Rendering::GroupNode& node) override; + + QString name() const override { return tr("Force"); } + + QString description() const override + { + return tr( + "Render the force field visualizations for the atoms of the molecule."); + } + + bool isEnabled() const override; + + void setEnabled(bool enable) override; + +private: + bool m_enabled; +}; + +} // end namespace QtPlugins +} // end namespace Avogadro + +#endif // AVOGADRO_QTPLUGINS_WIREFRAME_H diff --git a/avogadro/rendering/CMakeLists.txt b/avogadro/rendering/CMakeLists.txt index 1d8c22e0bc..516f4c7db6 100644 --- a/avogadro/rendering/CMakeLists.txt +++ b/avogadro/rendering/CMakeLists.txt @@ -11,6 +11,7 @@ if(WIN32 AND NOT BUILD_SHARED_LIBS) endif() set(HEADERS + arrowgeometry.h avogadrogl.h avogadrorendering.h bufferobject.h @@ -44,6 +45,7 @@ set(HEADERS ) set(SOURCES + arrowgeometry.cpp bufferobject.cpp camera.cpp cylindergeometry.cpp @@ -75,6 +77,7 @@ set(SOURCES ) set(shader_files + "arrow_vs.glsl" "cylinders_fs.glsl" "cylinders_vs.glsl" "linestrip_fs.glsl" diff --git a/avogadro/rendering/arrow_vs.glsl b/avogadro/rendering/arrow_vs.glsl new file mode 100644 index 0000000000..3bdb5fb822 --- /dev/null +++ b/avogadro/rendering/arrow_vs.glsl @@ -0,0 +1,10 @@ +attribute vec4 vertex; + +uniform mat4 modelView; +uniform mat4 projection; + +void main() +{ + gl_FrontColor = vec4(0.0, 1.0, 0.0, 1.0); + gl_Position = projection * modelView * vertex; +} diff --git a/avogadro/rendering/arrowgeometry.cpp b/avogadro/rendering/arrowgeometry.cpp new file mode 100644 index 0000000000..5fbc7b5182 --- /dev/null +++ b/avogadro/rendering/arrowgeometry.cpp @@ -0,0 +1,212 @@ +/****************************************************************************** + + This source file is part of the Avogadro project. + + Copyright 2018 Kitware, Inc. + + This source code is released under the New BSD License, (the "License"). + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +******************************************************************************/ + +#include "arrowgeometry.h" + +#include "avogadrogl.h" +#include "bufferobject.h" +#include "camera.h" +#include "scene.h" +#include "shader.h" +#include "shaderprogram.h" +#include "visitor.h" + +#include +#include + +#include +#include + +namespace { +#include "arrow_vs.h" +} + +using Avogadro::Vector3f; +using Avogadro::Vector3ub; +using Avogadro::Vector4ub; +using Avogadro::Core::Array; + +using std::cout; +using std::endl; + +namespace Avogadro { +namespace Rendering { + +class ArrowGeometry::Private +{ +public: + Private() {} + + Shader vertexShader; + ShaderProgram program; +}; + +ArrowGeometry::ArrowGeometry() + : m_dirty(false) + , d(new Private) +{} + +ArrowGeometry::ArrowGeometry(const ArrowGeometry& other) + : Drawable(other) + , m_vertices(other.m_vertices) + , m_lineStarts(other.m_lineStarts) + , m_dirty(true) + , d(new Private) +{} + +ArrowGeometry::~ArrowGeometry() +{ + delete d; +} + +void ArrowGeometry::accept(Visitor& visitor) +{ + visitor.visit(*this); +} + +void ArrowGeometry::update() +{ + if (m_vertices.empty()) + return; + + // Build and link the shader if it has not been used yet. + if (d->vertexShader.type() == Shader::Unknown) { + d->vertexShader.setType(Shader::Vertex); + d->vertexShader.setSource(arrow_vs); + if (!d->vertexShader.compile()) + cout << d->vertexShader.error() << endl; + d->program.attachShader(d->vertexShader); + if (!d->program.link()) + cout << d->program.error() << endl; + } +} + +void ArrowGeometry::render(const Camera& camera) +{ + if (m_vertices.empty()) + return; + + // Prepare the shader program if necessary. + update(); + + if (!d->program.bind()) + cout << d->program.error() << endl; + + // Set up our uniforms (model-view and projection matrices right now). + if (!d->program.setUniformValue("modelView", camera.modelView().matrix())) { + cout << d->program.error() << endl; + } + if (!d->program.setUniformValue("projection", camera.projection().matrix())) { + cout << d->program.error() << endl; + } + + // Render the arrows using the shader. + for (unsigned int startIndex = 0; startIndex < m_vertices.size(); + ++startIndex) { + Vector3f v3 = + m_vertices[startIndex].first + + 0.8 * (m_vertices[startIndex].second - m_vertices[startIndex].first); + drawLine(m_vertices[startIndex].first, v3, 2); + drawCone(v3, m_vertices[startIndex].second, 0.05, 1.0); + } + + d->program.release(); +} + +void ArrowGeometry::clear() +{ + m_vertices.clear(); + m_lineStarts.clear(); + m_dirty = true; +} + +void ArrowGeometry::drawLine(const Vector3f& start, const Vector3f& end, + double lineWidth) +{ + // Draw a line between two points of the specified thickness + + glPushAttrib(GL_LIGHTING_BIT); + glDisable(GL_LIGHTING); + + glLineWidth(lineWidth); + + // Draw the line + glBegin(GL_LINE_STRIP); + glVertex3fv(start.data()); + glVertex3fv(end.data()); + glEnd(); + + glPopAttrib(); +} + +void ArrowGeometry::drawCone(const Vector3f& base, const Vector3f& cap, + double baseRadius, double) +{ + const int CONE_TESS_LEVEL = 30; + // This draws a cone which will be most useful for drawing arrows etc. + Vector3f axis = cap - base; + Vector3f axisNormalized = axis.normalized(); + Vector3f ortho1, ortho2; + ortho1 = axisNormalized.unitOrthogonal(); + ortho1 *= baseRadius; + ortho2 = axisNormalized.cross(ortho1); + + // Draw the cone + // unfortunately we can't use a GL_TRIANGLE_FAN because this would force + // having a common normal vector at the tip. + for (int j = 0; j < CONE_TESS_LEVEL; j++) { + const double alphaStep = 2.0 * M_PI / CONE_TESS_LEVEL; + double alpha = j * alphaStep; + double alphaNext = alpha + alphaStep; + double alphaPrec = alpha - alphaStep; + Vector3f v = sin(alpha) * ortho1 + cos(alpha) * ortho2 + base; + Vector3f vNext = sin(alphaNext) * ortho1 + cos(alphaNext) * ortho2 + base; + Vector3f vPrec = sin(alphaPrec) * ortho1 + cos(alphaPrec) * ortho2 + base; + Vector3f n = (cap - v).cross(v - vPrec).normalized(); + Vector3f nNext = (cap - vNext).cross(vNext - v).normalized(); + glBegin(GL_TRIANGLES); + glColor3ub(0, 255, 0); + glNormal3fv((n + nNext).normalized().data()); + glVertex3fv(cap.data()); + glNormal3fv(nNext.data()); + glVertex3fv(vNext.data()); + glNormal3fv(n.data()); + glVertex3fv(v.data()); + glEnd(); + } + + // Now to draw the base + glBegin(GL_TRIANGLE_FAN); + glNormal3fv((-axisNormalized).eval().data()); + glVertex3fv(base.data()); + for (int j = 0; j <= CONE_TESS_LEVEL; j++) { + double alpha = -j * M_PI / (CONE_TESS_LEVEL / 2.0); + Vector3f v = cos(alpha) * ortho1 + sin(alpha) * ortho2 + base; + glVertex3fv(v.data()); + } + glEnd(); +} + +void ArrowGeometry::addSingleArrow(const Vector3f& pos1, const Vector3f& pos2) +{ + m_vertices.reserve(m_vertices.size() + 1); + m_vertices.push_back(std::pair(pos1, pos2)); + + m_dirty = true; +} + +} // End namespace Rendering +} // End namespace Avogadro diff --git a/avogadro/rendering/arrowgeometry.h b/avogadro/rendering/arrowgeometry.h new file mode 100644 index 0000000000..a16df9dacb --- /dev/null +++ b/avogadro/rendering/arrowgeometry.h @@ -0,0 +1,114 @@ +/****************************************************************************** + + This source file is part of the Avogadro project. + + Copyright 2018 Kitware, Inc. + + This source code is released under the New BSD License, (the "License"). + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +******************************************************************************/ + +#ifndef AVOGADRO_RENDERING_ARROWGEOMETRY_H +#define AVOGADRO_RENDERING_ARROWGEOMETRY_H + +#include "drawable.h" + +#include + +namespace Avogadro { +namespace Rendering { + +/** + * @class ArrowGeometry arrowgeometry.h + * + * @brief The ArrowGeometry class is used to store sets of line strips. + */ + +class AVOGADRORENDERING_EXPORT ArrowGeometry : public Drawable +{ +public: + static const size_t InvalidIndex; + + ArrowGeometry(); + ArrowGeometry(const ArrowGeometry& other); + ~ArrowGeometry(); + + ArrowGeometry& operator=(ArrowGeometry); + friend void swap(ArrowGeometry& lhs, ArrowGeometry& rhs); + + /** + * Accept a visit from our friendly visitor. + */ + void accept(Visitor&) override; + + /** + * @brief Render the arrows. + * @param camera The current camera to be used for rendering. + */ + void render(const Camera& camera); + + /** + * Clear the contents of the node. + */ + void clear(); + + void drawLine(const Vector3f& start, const Vector3f& end, double lineWidth); + void drawCone(const Vector3f& base, const Vector3f& cap, double baseRadius, + double); + + /** + * Add a single arrow object. + * @param pos1 The start coordinate of the arrow. + * @param pos2 The end coordinate of the arrow. + * @param lineWidth The width of the line strip. + * @{ + */ + void addSingleArrow(const Vector3f& pos1, const Vector3f& pos2); + /** @} */ + + /** The vertex array. */ + Core::Array> vertices() const + { + return m_vertices; + } + +private: + /** + * @brief Update the shaders ready for rendering. + */ + void update(); + + Core::Array> m_vertices; + Core::Array m_lineStarts; + + bool m_dirty; + + class Private; + Private* d; +}; + +inline ArrowGeometry& ArrowGeometry::operator=(ArrowGeometry other) +{ + using std::swap; + swap(*this, other); + return *this; +} + +inline void swap(ArrowGeometry& lhs, ArrowGeometry& rhs) +{ + using std::swap; + swap(static_cast(lhs), static_cast(rhs)); + swap(lhs.m_vertices, rhs.m_vertices); + lhs.m_dirty = rhs.m_dirty = true; +} + +} // End namespace Rendering +} // End namespace Avogadro + +#endif // AVOGADRO_RENDERING_ARROWGEOMETRY_H From a86e26ff06d0fea5b4ecae7e05493ec8adefc21c Mon Sep 17 00:00:00 2001 From: Adarsh Balasubramanian Date: Sun, 22 Jul 2018 03:38:08 +0530 Subject: [PATCH 05/68] LAMMPS Input plugin ported from Avogadro 1 Signed-off-by: Adarsh Balasubramanian --- avogadro/qtplugins/CMakeLists.txt | 1 + avogadro/qtplugins/lammpsinput/CMakeLists.txt | 16 + .../qtplugins/lammpsinput/lammpsinput.cpp | 97 ++ avogadro/qtplugins/lammpsinput/lammpsinput.h | 76 ++ .../lammpsinput/lammpsinputdialog.cpp | 876 ++++++++++++++ .../qtplugins/lammpsinput/lammpsinputdialog.h | 227 ++++ .../lammpsinput/lammpsinputdialog.ui | 1020 +++++++++++++++++ 7 files changed, 2313 insertions(+) create mode 100644 avogadro/qtplugins/lammpsinput/CMakeLists.txt create mode 100644 avogadro/qtplugins/lammpsinput/lammpsinput.cpp create mode 100644 avogadro/qtplugins/lammpsinput/lammpsinput.h create mode 100644 avogadro/qtplugins/lammpsinput/lammpsinputdialog.cpp create mode 100644 avogadro/qtplugins/lammpsinput/lammpsinputdialog.h create mode 100644 avogadro/qtplugins/lammpsinput/lammpsinputdialog.ui diff --git a/avogadro/qtplugins/CMakeLists.txt b/avogadro/qtplugins/CMakeLists.txt index 20e22aed7f..a3a2fc361c 100644 --- a/avogadro/qtplugins/CMakeLists.txt +++ b/avogadro/qtplugins/CMakeLists.txt @@ -101,6 +101,7 @@ add_subdirectory(customelements) add_subdirectory(editor) add_subdirectory(hydrogens) add_subdirectory(importpqr) +add_subdirectory(lammpsinput) add_subdirectory(lineformatinput) add_subdirectory(manipulator) add_subdirectory(measuretool) diff --git a/avogadro/qtplugins/lammpsinput/CMakeLists.txt b/avogadro/qtplugins/lammpsinput/CMakeLists.txt new file mode 100644 index 0000000000..32dbdfda5d --- /dev/null +++ b/avogadro/qtplugins/lammpsinput/CMakeLists.txt @@ -0,0 +1,16 @@ +# Extension +set(gamessinput_srcs + lammpsinputdialog.cpp + lammpsinput.cpp +) + +avogadro_plugin(LammpsInput + "LAMMPS input file generation" + ExtensionPlugin + lammpsinput.h + LammpsInput + "${gamessinput_srcs}" + lammpsinputdialog.ui +) + +target_link_libraries(LammpsInput) diff --git a/avogadro/qtplugins/lammpsinput/lammpsinput.cpp b/avogadro/qtplugins/lammpsinput/lammpsinput.cpp new file mode 100644 index 0000000000..36e239aeb1 --- /dev/null +++ b/avogadro/qtplugins/lammpsinput/lammpsinput.cpp @@ -0,0 +1,97 @@ +/****************************************************************************** + + This source file is part of the Avogadro project. + + Copyright 2018 Kitware, Inc. + + This source code is released under the New BSD License, (the "License"). + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +******************************************************************************/ + +#include "lammpsinput.h" + +#include "lammpsinputdialog.h" + +#include +#include +#include + +#include + +#include +#include + +namespace Avogadro { +namespace Core { +class Molecule; +} +namespace QtPlugins { + +LammpsInput::LammpsInput(QObject* parent_) + : ExtensionPlugin(parent_) + , m_action(new QAction(this)) + , m_molecule(nullptr) + , m_dialog(nullptr) + , m_outputFormat(nullptr) +{ + m_action->setEnabled(true); + m_action->setText(tr("&LAMMPS Input")); + connect(m_action, SIGNAL(triggered()), SLOT(menuActivated())); +} + +LammpsInput::~LammpsInput() {} + +QList LammpsInput::actions() const +{ + QList actions_; + actions_.append(m_action); + return actions_; +} + +QStringList LammpsInput::menuPath(QAction*) const +{ + QStringList path; + path << tr("&Extensions") << tr("Molecular Dynamics"); + return path; +} + +void LammpsInput::setMolecule(QtGui::Molecule* mol) +{ + if (m_dialog) + m_dialog->setMolecule(mol); + m_molecule = mol; +} + +bool LammpsInput::readMolecule(QtGui::Molecule& mol) +{ + Io::FileFormat* reader = m_outputFormat->newInstance(); + bool success = reader->readFile(m_outputFileName.toStdString(), mol); + if (!success) { + QMessageBox::information(qobject_cast(parent()), tr("Error"), + tr("Error reading output file '%1':\n%2") + .arg(m_outputFileName) + .arg(QString::fromStdString(reader->error()))); + } + + m_outputFormat = nullptr; + m_outputFileName.clear(); + + return success; +} + +void LammpsInput::menuActivated() +{ + if (!m_dialog) { + m_dialog = new LammpsInputDialog(qobject_cast(parent())); + } + m_dialog->setMolecule(m_molecule); + m_dialog->show(); +} +} +} diff --git a/avogadro/qtplugins/lammpsinput/lammpsinput.h b/avogadro/qtplugins/lammpsinput/lammpsinput.h new file mode 100644 index 0000000000..50446ea563 --- /dev/null +++ b/avogadro/qtplugins/lammpsinput/lammpsinput.h @@ -0,0 +1,76 @@ +/****************************************************************************** + + This source file is part of the Avogadro project. + + Copyright 2018 Kitware, Inc. + + This source code is released under the New BSD License, (the "License"). + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +******************************************************************************/ + +#ifndef AVOGADRO_QTPLUGINS_LAMMPSINPUT_H +#define AVOGADRO_QTPLUGINS_LAMMPSINPUT_H + +#include + +class QAction; +class QDialog; + +namespace Avogadro { +namespace Io { +class FileFormat; +} + +namespace QtPlugins { + +class LammpsInputDialog; + +class LammpsInput : public QtGui::ExtensionPlugin +{ + Q_OBJECT + +public: + explicit LammpsInput(QObject* parent = 0); + ~LammpsInput() override; + + QString name() const override { return tr("LAMMPS input"); } + + QString description() const override + { + return tr("Generate input for LAMMPS."); + } + + QList actions() const override; + + QStringList menuPath(QAction*) const override; + + void setMolecule(QtGui::Molecule* mol) override; + +public slots: + /** + * Emitted when the user requests that a job's output be loaded in Avogadro. + */ + // void openJobOutput(const MoleQueue::JobObject& job); + + bool readMolecule(QtGui::Molecule& mol) override; + +private slots: + void menuActivated(); + +private: + QAction* m_action; + QtGui::Molecule* m_molecule; + LammpsInputDialog* m_dialog; + const Io::FileFormat* m_outputFormat; + QString m_outputFileName; +}; +} +} + +#endif // AVOGADRO_QTPLUGINS_LAMMPSINPUT_H diff --git a/avogadro/qtplugins/lammpsinput/lammpsinputdialog.cpp b/avogadro/qtplugins/lammpsinput/lammpsinputdialog.cpp new file mode 100644 index 0000000000..f73e27ae7d --- /dev/null +++ b/avogadro/qtplugins/lammpsinput/lammpsinputdialog.cpp @@ -0,0 +1,876 @@ +/****************************************************************************** + + This source file is part of the Avogadro project. + + Copyright 2018 Kitware, Inc. + + This source code is released under the New BSD License, (the "License"). + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +******************************************************************************/ + +#include "lammpsinputdialog.h" + +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace Avogadro { +namespace QtPlugins { + +LammpsInputDialog::LammpsInputDialog(QWidget* parent, Qt::WindowFlags flag) + : QDialog(parent, flag) + , m_molecule(nullptr) + , + + m_unitType(real) + , m_title("Title") + , m_savePath("") + , m_dimensionType(d3) + , m_xBoundaryType(p) + , m_yBoundaryType(p) + , m_zBoundaryType(p) + , + + m_atomStyle(full) + , + + m_waterPotential(NONE) + , + + m_ensemble(NVT) + , m_temperature(298.15) + , m_nhChain(1) + , + + m_timeStep(2.0) + , m_runSteps(50) + , m_xReplicate(1) + , m_yReplicate(1) + , m_zReplicate(1) + , + + m_dumpStep(1) + , + + m_velocityDist(gaussian) + , m_velocityTemp(298.15) + , m_zeroMOM(true) + , m_zeroL(true) + , m_thermoStyle(one) + , m_thermoInterval(50) + , + + m_output() + , m_dirty(false) + , m_warned(false) + , readData(false) +{ + ui.setupUi(this); + // Connect the GUI elements to the correct slots + connect(ui.titleLine, SIGNAL(editingFinished()), this, SLOT(setTitle())); + + // now for something useful + connect(ui.unitsCombo, SIGNAL(currentIndexChanged(int)), this, + SLOT(setUnits(int))); + connect(ui.atomStyleCombo, SIGNAL(currentIndexChanged(int)), this, + SLOT(setAtomStyle(int))); + connect(ui.dimensionCombo, SIGNAL(currentIndexChanged(int)), this, + SLOT(setDimensionType(int))); + connect(ui.xBoundaryCombo, SIGNAL(currentIndexChanged(int)), this, + SLOT(setXBoundaryType(int))); + connect(ui.yBoundaryCombo, SIGNAL(currentIndexChanged(int)), this, + SLOT(setYBoundaryType(int))); + connect(ui.zBoundaryCombo, SIGNAL(currentIndexChanged(int)), this, + SLOT(setZBoundaryType(int))); + connect(ui.waterPotentialCombo, SIGNAL(currentIndexChanged(int)), this, + SLOT(setWaterPotential(int))); + connect(ui.readDataLine, SIGNAL(editingFinished()), this, + SLOT(setReadData())); + connect(ui.ensembleCombo, SIGNAL(currentIndexChanged(int)), this, + SLOT(setEnsemble(int))); + connect(ui.tempSpin, SIGNAL(valueChanged(double)), this, + SLOT(setTemperature(double))); + connect(ui.nhChainSpin, SIGNAL(valueChanged(int)), this, + SLOT(setNHChain(int))); + connect(ui.stepSpin, SIGNAL(valueChanged(double)), this, + SLOT(setTimeStep(double))); + connect(ui.runSpin, SIGNAL(valueChanged(int)), this, SLOT(setRunSteps(int))); + connect(ui.xReplicateSpin, SIGNAL(valueChanged(int)), this, + SLOT(setXReplicate(int))); + connect(ui.yReplicateSpin, SIGNAL(valueChanged(int)), this, + SLOT(setYReplicate(int))); + connect(ui.zReplicateSpin, SIGNAL(valueChanged(int)), this, + SLOT(setZReplicate(int))); + connect(ui.dumpXYZEdit, SIGNAL(editingFinished()), this, SLOT(setDumpXYZ())); + connect(ui.dumpStepSpin, SIGNAL(valueChanged(int)), this, + SLOT(setDumpStep(int))); + connect(ui.velocityDistCombo, SIGNAL(currentIndexChanged(int)), this, + SLOT(setVelocityDist(int))); + connect(ui.velocityTempSpin, SIGNAL(valueChanged(double)), this, + SLOT(setVelocityTemp(double))); + connect(ui.zeroMOMCheck, SIGNAL(toggled(bool)), this, SLOT(setZeroMOM(bool))); + connect(ui.zeroLCheck, SIGNAL(toggled(bool)), this, SLOT(setZeroL(bool))); + connect(ui.thermoStyleCombo, SIGNAL(currentIndexChanged(int)), this, + SLOT(setThermoStyle(int))); + connect(ui.thermoSpin, SIGNAL(valueChanged(int)), this, + SLOT(setThermoInterval(int))); + + connect(ui.previewText, SIGNAL(cursorPositionChanged()), this, + SLOT(previewEdited())); + connect(ui.generateButton, SIGNAL(clicked()), this, SLOT(generateClicked())); + connect(ui.resetButton, SIGNAL(clicked()), this, SLOT(resetClicked())); + + connect(ui.moreButton, SIGNAL(clicked()), this, SLOT(moreClicked())); + connect(ui.enableFormButton, SIGNAL(clicked()), this, + SLOT(enableFormClicked())); + + QSettings settings; + readSettings(settings); + + // Generate an initial preview of the input deck + updatePreviewText(); +} + +LammpsInputDialog::~LammpsInputDialog() +{ + QSettings settings; + writeSettings(settings); +} + +void LammpsInputDialog::showEvent(QShowEvent*) +{ + updatePreviewText(); +} + +void LammpsInputDialog::updatePreviewText() +{ + if (!isVisible()) + return; + // Generate the input deck and display it + if (m_dirty && !m_warned) { + m_warned = true; + QMessageBox msgBox; + + msgBox.setWindowTitle(tr("Lammps Input Deck Generator Warning")); + msgBox.setText(tr("Would you like to update the preview text, losing all " + "changes made in the Lammps input deck preview pane?")); + msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); + + switch (msgBox.exec()) { + case QMessageBox::Yes: + // yes was clicked + deckDirty(false); + ui.previewText->setText(generateInputDeck()); + ui.previewText->document()->setModified(false); + m_warned = false; + break; + case QMessageBox::No: + // no was clicked + m_warned = false; + break; + default: + // should never be reached + break; + } + } else if (!m_dirty) { + ui.previewText->setText(generateInputDeck()); + ui.previewText->document()->setModified(false); + } +} + +void LammpsInputDialog::resetClicked() +{ + // Reset the form to defaults + deckDirty(false); + + ui.unitsCombo->setCurrentIndex(1); + ui.atomStyleCombo->setCurrentIndex(7); + ui.dimensionCombo->setCurrentIndex(1); + ui.xBoundaryCombo->setCurrentIndex(0); + ui.yBoundaryCombo->setCurrentIndex(0); + ui.zBoundaryCombo->setCurrentIndex(0); + ui.waterPotentialCombo->setCurrentIndex(0); + ui.ensembleCombo->setCurrentIndex(0); + ui.tempSpin->setValue(298.15); + ui.nhChainSpin->setValue(1); + ui.stepSpin->setValue(2.0); + ui.runSpin->setValue(50); + ui.xReplicateSpin->setValue(1); + ui.yReplicateSpin->setValue(1); + ui.zReplicateSpin->setValue(1); + ui.dumpStepSpin->setValue(1); + ui.thermoStyleCombo->setCurrentIndex(0); + ui.thermoSpin->setValue(50); + + ui.previewText->setText(generateInputDeck()); + ui.previewText->document()->setModified(false); +} + +void LammpsInputDialog::generateClicked() +{ + QSettings settings; + QString fileName = + (ui.baseNameEdit->text().isEmpty() ? ui.baseNameEdit->placeholderText() + : ui.baseNameEdit->text()) + + ".lmp"; + QString targetFile = + settings.value("lammpsInput/outputDirectory", QDir::homePath()).toString(); + targetFile = + QDir(QFileInfo(targetFile).absoluteDir()).absoluteFilePath(fileName); + + fileName = QFileDialog::getSaveFileName(this, tr("Save LAMMPS input file"), + targetFile); + + // User cancel: + if (fileName.isNull()) + return; + + settings.setValue("lammpsInput/outputDirectory", fileName); + + QFile file(fileName); + bool success = false; + if (file.open(QFile::WriteOnly | QFile::Text)) { + if (file.write(ui.previewText->toPlainText().toLocal8Bit()) > 0) { + success = true; + } + file.close(); + } + + if (!success) { + QMessageBox::critical(this, tr("Output Error"), + tr("Failed to write to file %1.").arg(fileName)); + } +} + +void LammpsInputDialog::moreClicked() +{ + // If the more button is clicked hide/show the preview text + if (ui.previewText->isVisible()) { + ui.previewText->hide(); + ui.moreButton->setText(tr("Show Preview")); + } else { + ui.previewText->show(); + ui.moreButton->setText(tr("Hide Preview")); + } +} + +void LammpsInputDialog::enableFormClicked() +{ + updatePreviewText(); +} + +void LammpsInputDialog::previewEdited() +{ + // Determine if the preview text has changed from the form generated + if (ui.previewText->document()->isModified()) + deckDirty(true); +} + +void LammpsInputDialog::setTitle() +{ + m_title = ui.titleLine->text(); + updatePreviewText(); +} + +void LammpsInputDialog::setUnits(int n) +{ + m_unitType = (LammpsInputDialog::unitType)n; + ui.unitsCombo->setEnabled(true); + updatePreviewText(); +} + +void LammpsInputDialog::setAtomStyle(int n) +{ + m_atomStyle = (LammpsInputDialog::atomStyle)n; + ui.atomStyleCombo->setEnabled(true); + updatePreviewText(); +} + +void LammpsInputDialog::setDimensionType(int n) +{ + m_dimensionType = static_cast(n); + ui.dimensionCombo->setEnabled(true); + if (n == 0) { + setZBoundaryType(0); + ui.zBoundaryCombo->setCurrentIndex(0); + ui.zBoundaryCombo->setEnabled(false); + ui.zReplicateSpin->setValue(1); + ui.zReplicateSpin->setEnabled(false); + } + if (n == 1) { + ui.zBoundaryCombo->setEnabled(true); + ui.zReplicateSpin->setEnabled(true); + } + updatePreviewText(); +} + +void LammpsInputDialog::setXBoundaryType(int n) +{ + m_xBoundaryType = static_cast(n); + ui.xBoundaryCombo->setEnabled(true); + updatePreviewText(); +} + +void LammpsInputDialog::setYBoundaryType(int n) +{ + m_yBoundaryType = static_cast(n); + ui.yBoundaryCombo->setEnabled(true); + updatePreviewText(); +} + +void LammpsInputDialog::setZBoundaryType(int n) +{ + m_zBoundaryType = static_cast(n); + // should be careful here + // z boundary must be p for 2d!!! + ui.zBoundaryCombo->setEnabled(true); + updatePreviewText(); +} + +void LammpsInputDialog::setWaterPotential(int n) +{ + m_waterPotential = static_cast(n); + ui.waterPotentialCombo->setEnabled(true); + if (n == 1) { + setAtomStyle(7); + ui.atomStyleCombo->setCurrentIndex(7); + ui.atomStyleCombo->setEnabled(false); + } + if (n == 0) { + ui.atomStyleCombo->setEnabled(true); + } + updatePreviewText(); +} + +void LammpsInputDialog::setReadData() +{ + m_readData = ui.readDataLine->text(); + if (m_readData != "") + readData = true; + else + readData = false; + updatePreviewText(); +} + +void LammpsInputDialog::setMolecule(QtGui::Molecule* molecule) +{ + // Disconnect the old molecule first... + if (molecule == m_molecule) + return; + + if (m_molecule) + m_molecule->disconnect(this); + + m_molecule = molecule; + // Update the preview text whenever primitives are changed + connect(molecule, SIGNAL(changed(unsigned int)), SLOT(updatePreviewText())); + updatePreviewText(); +} + +void LammpsInputDialog::setEnsemble(int n) +{ + m_ensemble = static_cast(n); + ui.ensembleCombo->setEnabled(true); + if (n == 1) { + ui.tempSpin->setValue(0.0); + ui.tempSpin->setEnabled(false); + ui.nhChainSpin->setValue(0); + ui.nhChainSpin->setEnabled(false); + } else if (n == 0) { + ui.tempSpin->setEnabled(true); + ui.nhChainSpin->setEnabled(true); + ui.nhChainSpin->setValue(1); + } + updatePreviewText(); +} + +void LammpsInputDialog::setTemperature(double n) +{ + m_temperature = n; + ui.tempSpin->setEnabled(true); + updatePreviewText(); +} + +void LammpsInputDialog::setNHChain(int n) +{ + m_nhChain = n; + ui.nhChainSpin->setEnabled(true); + updatePreviewText(); +} + +void LammpsInputDialog::setTimeStep(double n) +{ + m_timeStep = n; + ui.stepSpin->setEnabled(true); + updatePreviewText(); +} + +void LammpsInputDialog::setRunSteps(int n) +{ + m_runSteps = n; + ui.runSpin->setEnabled(true); + updatePreviewText(); +} + +void LammpsInputDialog::setXReplicate(int n) +{ + m_xReplicate = n; + ui.xReplicateSpin->setEnabled(true); + updatePreviewText(); +} + +void LammpsInputDialog::setYReplicate(int n) +{ + m_yReplicate = n; + ui.yReplicateSpin->setEnabled(true); + updatePreviewText(); +} + +void LammpsInputDialog::setZReplicate(int n) +{ + m_zReplicate = n; + ui.zReplicateSpin->setEnabled(true); + updatePreviewText(); +} + +void LammpsInputDialog::setDumpStep(int n) +{ + m_dumpStep = n; + ui.dumpStepSpin->setEnabled(true); + updatePreviewText(); +} + +void LammpsInputDialog::setDumpXYZ() +{ + m_dumpXYZ = ui.dumpXYZEdit->text(); + updatePreviewText(); +} + +void LammpsInputDialog::setVelocityDist(int n) +{ + m_velocityDist = static_cast(n); + ui.velocityDistCombo->setEnabled(true); + updatePreviewText(); +} + +void LammpsInputDialog::setVelocityTemp(double n) +{ + m_velocityTemp = n; + ui.velocityTempSpin->setEnabled(true); + updatePreviewText(); +} + +void LammpsInputDialog::setZeroMOM(bool state) +{ + m_zeroMOM = state; + ui.zeroMOMCheck->setEnabled(true); + updatePreviewText(); +} + +void LammpsInputDialog::setZeroL(bool state) +{ + m_zeroL = state; + ui.zeroLCheck->setEnabled(true); + updatePreviewText(); +} + +void LammpsInputDialog::setThermoStyle(int n) +{ + m_thermoStyle = static_cast(n); + ui.thermoStyleCombo->setEnabled(true); + updatePreviewText(); +} + +void LammpsInputDialog::setThermoInterval(int n) +{ + m_thermoInterval = n; + ui.thermoSpin->setEnabled(true); + updatePreviewText(); +} + +QString LammpsInputDialog::generateInputDeck() +{ + // Generate an input deck based on the settings of the dialog + QString buffer; + QTextStream mol(&buffer); + + mol << "#LAMMPS Input file generated by Avogadro\n"; + mol << "# " << m_title << "\n\n"; + + mol << "# Intialization\n"; + mol << "units " << getUnitType(m_unitType) << "\n"; + mol << "dimension " << getDimensionType(m_dimensionType) << "\n"; + mol << "boundary " << getXBoundaryType(m_xBoundaryType) << " " + << getYBoundaryType(m_yBoundaryType) << " " + << getZBoundaryType(m_zBoundaryType) << "\n"; + mol << "atom_style " << getAtomStyle(m_atomStyle) << "\n"; + mol << "\n"; + + mol << "# Atom Definition\n"; + if (readData) + mol << "read_data " << m_readData << "\n"; + mol << "replicate " << m_xReplicate << " " << m_yReplicate << " " + << m_zReplicate << "\n"; + + mol << "\n" << getWaterPotential(m_waterPotential) << "\n"; + + mol << "# Settings\n"; + mol << "velocity all create " << fixed << qSetRealNumberPrecision(2) + << m_velocityTemp << " " + << "4928459 " + << "rot " << getZeroL() << " " + << "mom " << getZeroMOM() << " " + << "dist " << getVelocityDist(m_velocityDist) << "\n"; + mol << getEnsemble(m_ensemble) << "\n"; + mol << "timestep " << fixed << qSetRealNumberPrecision(1) << m_timeStep + << "\n"; + mol << "\n"; + + mol << "# Output\n"; + if (m_dumpXYZ != "") { + mol << "dump dumpXYZ all xyz " << m_dumpStep << " " << m_dumpXYZ + << "\n"; + } + mol << "thermo_style " << getThermoStyle(m_thermoStyle) << "\n"; + mol << "thermo " << m_thermoInterval << "\n"; + mol << "\n"; + + mol << "# Run the simulation\n"; + mol << "run " << m_runSteps << "\n"; + mol << "\n"; + + return buffer; +} + +QString LammpsInputDialog::getUnitType(unitType t) +{ + // Translate the enum to text for the output generation + switch (t) { + case lj: + return "lj"; + case real: + return "real"; + case metal: + return "metal"; + case si: + return "si"; + case cgs: + return "cgs"; + case u_electron: + return "electron"; + default: + return "lj"; + } +} + +QString LammpsInputDialog::getAtomStyle(atomStyle t) +{ + switch (t) { + case angle: + return "angle"; + case atomic: + return "atomic"; + case bond: + return "bond"; + case charge: + return "charge"; + case dipole: + return "dipole"; + case a_electron: + return "electron"; + case ellipsoid: + return "ellipsoid"; + case full: + return "full"; + case line: + return "line"; + case meso: + return "meso"; + case molecular: + return "molecular"; + case peri: + return "peri"; + case sphere: + return "sphere"; + case tri: + return "tri"; + case wavepacket: + return "wavepacket"; + default: + return "full"; + } +} + +QString LammpsInputDialog::getDimensionType(dimensionType t) +{ + switch (t) { + case d2: + return "2d"; + case d3: + return "3d"; + default: + return "3d"; + } +} + +QString LammpsInputDialog::getXBoundaryType(boundaryType t) +{ + switch (t) { + case p: + return "p"; + case f: + return "f"; + case s: + return "s"; + case m: + return "m"; + case fs: + return "fs"; + case fm: + return "fm"; + default: + return "p"; + } +} + +QString LammpsInputDialog::getYBoundaryType(boundaryType t) +{ + switch (t) { + case p: + return "p"; + case f: + return "f"; + case s: + return "s"; + case m: + return "m"; + case fs: + return "fs"; + case fm: + return "fm"; + default: + return "p"; + } +} + +QString LammpsInputDialog::getZBoundaryType(boundaryType t) +{ + switch (t) { + case p: + return "p"; + case f: + return "f"; + case s: + return "s"; + case m: + return "m"; + case fs: + return "fs"; + case fm: + return "fm"; + default: + return "p"; + } +} + +QString LammpsInputDialog::getWaterPotential(waterPotential t) +{ + switch (t) { + case NONE: { + QString waterPotentialInput; + QTextStream water(&waterPotentialInput); + water << ""; + return waterPotentialInput; + } + case SPC: { + QString waterPotentialInput; + QTextStream water(&waterPotentialInput); + int Hydrogen; + int Oxygen; + determineAtomTypesSPC(Hydrogen, Oxygen); + water << "#The SPC water potential\n" + << "pair_style lj/cut/coul/cut 9.8 9.8\n" + << "pair_coeff " << Oxygen << " " << Oxygen + << " 0.15535 3.5533\n" + << "pair_coeff " + << "* " << Hydrogen << " 0.00000 0.0000\n" + << "bond_style harmonic\n" + << "angle_style harmonic\n" + << "dihedral_style none\n" + << "improper_style none\n" + << "bond_coeff 1 100.00 1.000\n" + << "angle_coeff 1 100.00 109.47\n" + << "special_bonds lj/coul 0.0 0.0 0.5\n" + << "fix RigidOHBonds all shake 0.0001 20 0 b 1 a 1\n"; + return waterPotentialInput; + } + case SPCE: { + QString waterPotentialInput; + QTextStream water(&waterPotentialInput); + int Hydrogen; + int Oxygen; + determineAtomTypesSPC(Hydrogen, Oxygen); + water << "#The SPC/E water potential\n" + << "pair_style lj/cut/coul/long 9.8 9.8\n" + << "kspace_style pppm 1.0e-4\n" + << "pair_coeff " << Oxygen << " " << Oxygen + << " 0.15535 3.5533\n" + << "pair_coeff " + << "* " << Hydrogen << " 0.00000 0.0000\n" + << "bond_style harmonic\n" + << "angle_style harmonic\n" + << "dihedral_style none\n" + << "improper_style none\n" + << "bond_coeff 1 100.00 1.000\n" + << "angle_coeff 1 100.00 109.47\n" + << "special_bonds lj/coul 0.0 0.0 0.5\n" + << "fix RigidOHBonds all shake 0.0001 20 0 b 1 a 1\n"; + return waterPotentialInput; + } + default: { + QString waterPotentialInput; + QTextStream water(&waterPotentialInput); + water << "\n"; + return waterPotentialInput; + } + } +} + +QString LammpsInputDialog::getEnsemble(ensemble t) +{ + switch (t) { + case NVT: { + QString ensembleInput; + QTextStream fix(&ensembleInput); + fix << "fix ensemble all nvt" + << " temp " << fixed << qSetRealNumberPrecision(2) << m_temperature + << " " << fixed << qSetRealNumberPrecision(2) << m_temperature + << " 100 " + << "tchain " << m_nhChain << "\n"; + return ensembleInput; + } + case NVE: { + QString ensembleInput; + QTextStream fix(&ensembleInput); + fix << "fix ensemble all nve\n"; + return ensembleInput; + } + default: { + QString ensembleInput; + QTextStream fix(&ensembleInput); + fix << "fix ensemble all nvt" + << " temp " << fixed << qSetRealNumberPrecision(2) << m_temperature + << " " << fixed << qSetRealNumberPrecision(2) << m_temperature + << " 100 " + << "tchain " << m_nhChain << "\n"; + return ensembleInput; + } + } +} + +QString LammpsInputDialog::getVelocityDist(velocityDist t) +{ + switch (t) { + case gaussian: + return "gaussian"; + case uniform: + return "uniform"; + default: + return "gaussian"; + } +} + +QString LammpsInputDialog::getZeroMOM() +{ + if (m_zeroMOM) + return "yes"; + else + return "no"; +} + +QString LammpsInputDialog::getZeroL() +{ + if (m_zeroL) + return "yes"; + else + return "no"; +} + +QString LammpsInputDialog::getThermoStyle(thermoStyle t) +{ + switch (t) { + case one: + return "one"; + case multi: + return "multi"; + default: + return "one"; + } +} + +void LammpsInputDialog::deckDirty(bool dirty) +{ + m_dirty = dirty; + ui.titleLine->setEnabled(!dirty); + // ui.calculationCombo->setEnabled(!dirty); + // ui.theoryCombo->setEnabled(!dirty); + // ui.basisCombo->setEnabled(!dirty); + // ui.multiplicitySpin->setEnabled(!dirty); + // ui.chargeSpin->setEnabled(!dirty); + ui.enableFormButton->setEnabled(dirty); +} + +void LammpsInputDialog::readSettings(QSettings& settings) +{ + m_savePath = settings.value("lammps/savepath").toString(); +} + +void LammpsInputDialog::writeSettings(QSettings& settings) const +{ + settings.setValue("lammps/savepath", m_savePath); +} + +void LammpsInputDialog::determineAtomTypesSPC(int& hyd, int& oxy) +{ + double ThisMass; + QString ThisAtom; + + // QList atoms = m_molecule->atoms(); + for (size_t i = 0; i < m_molecule->atomCount(); ++i) { + Core::Atom atom = m_molecule->atom(i); + ThisMass = Core::Elements::mass(atom.atomicNumber()); + ThisAtom = Core::Elements::symbol(atom.atomicNumber()); + AtomMass[ThisAtom] = ThisMass; + } + int AtomIndex = 0; + // Set AtomType integer + for (itr = AtomMass.begin(); itr != AtomMass.end(); ++itr) { + AtomIndex++; + AtomType[itr.key()] = AtomIndex; + } + // this is on purpose due to the use of + // unordered_map in OpenBabel, which + // returns a different order for O and H. + hyd = AtomType.value("O"); + oxy = AtomType.value("H"); +} +} +} diff --git a/avogadro/qtplugins/lammpsinput/lammpsinputdialog.h b/avogadro/qtplugins/lammpsinput/lammpsinputdialog.h new file mode 100644 index 0000000000..2d5a01a2d1 --- /dev/null +++ b/avogadro/qtplugins/lammpsinput/lammpsinputdialog.h @@ -0,0 +1,227 @@ +/****************************************************************************** + + This source file is part of the Avogadro project. + + Copyright 2018 Kitware, Inc. + + This source code is released under the New BSD License, (the "License"). + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +******************************************************************************/ + +#ifndef LAMMPSINPUTDIALOG_H +#define LAMMPSINPUTDIALOG_H + +#include "ui_lammpsinputdialog.h" + +#include +#include + +class QJsonObject; + +namespace Avogadro { +namespace QtGui { +class Molecule; +} + +namespace QtPlugins { +class LammpsInputDialog : public QDialog +{ + Q_OBJECT + +public: + explicit LammpsInputDialog(QWidget* parent = 0, Qt::WindowFlags flag = 0); + ~LammpsInputDialog(); + + void readSettings(QSettings&); + void writeSettings(QSettings&) const; + + enum unitType + { + lj, + real, + metal, + si, + cgs, + u_electron + }; + enum dimensionType + { + d2, + d3 + }; + enum boundaryType + { + p, + s, + f, + m, + fs, + fm + }; + enum atomStyle + { + angle, + atomic, + bond, + charge, + dipole, + a_electron, + ellipsoid, + full, + line, + meso, + molecular, + peri, + sphere, + tri, + wavepacket + }; + enum waterPotential + { + NONE, + SPC, + SPCE + }; + void setMolecule(QtGui::Molecule* molecule); + enum ensemble + { + NVT, + NVE + }; + enum velocityDist + { + gaussian, + uniform + }; + enum thermoStyle + { + one, + multi + }; + +protected: + /** + * Reimplemented to update the dialog when it is shown + */ + void showEvent(QShowEvent* event); + +private: + Ui::LammpsInputDialog ui; + QtGui::Molecule* m_molecule; + + // QString m_title; + QString m_readData; + unitType m_unitType; + QString m_title; + QString m_savePath; + dimensionType m_dimensionType; + boundaryType m_xBoundaryType; + boundaryType m_yBoundaryType; + boundaryType m_zBoundaryType; + atomStyle m_atomStyle; + waterPotential m_waterPotential; + + // coordType m_coordType; + ensemble m_ensemble; + double m_temperature; + int m_nhChain; + double m_timeStep; + int m_runSteps; + int m_xReplicate; + int m_yReplicate; + int m_zReplicate; + QString m_dumpXYZ; + int m_dumpStep; + velocityDist m_velocityDist; + double m_velocityTemp; + bool m_zeroMOM; + bool m_zeroL; + thermoStyle m_thermoStyle; + int m_thermoInterval; + + QString m_output; + bool m_dirty; + bool m_warned; + bool readData; + + // Generate an input deck as a string + QString generateInputDeck(); + QString getUnitType(unitType t); + QString getAtomStyle(atomStyle t); + QString getDimensionType(dimensionType t); + QString getXBoundaryType(boundaryType t); + QString getYBoundaryType(boundaryType t); + QString getZBoundaryType(boundaryType t); + QString getWaterPotential(waterPotential t); + QString getEnsemble(ensemble t); + QString getVelocityDist(velocityDist t); + QString getZeroMOM(); + QString getZeroL(); + QString getThermoStyle(thermoStyle t); + // Translate enums to strings + // QString getCalculationType(calculationType t); + // QString getWavefunction(void); + // QString getTheoryType(theoryType t); + // QString getBasisType(basisType t); + + // Enable/disable form elements + void deckDirty(bool); + void determineAtomTypesSPC(int& hyd, int& oxy); + + // system typing + QHash AtomType; + QHash AtomMass; + QHash::iterator itr; + +public Q_SLOTS: + void updatePreviewText(); + +private Q_SLOTS: + //! Button Slots + void resetClicked(); + void generateClicked(); + void enableFormClicked(); + void moreClicked(); + void previewEdited(); + + void setTitle(); + void setReadData(); + + void setUnits(int); + void setAtomStyle(int); + void setDimensionType(int); + void setXBoundaryType(int); + void setYBoundaryType(int); + void setZBoundaryType(int); + + void setWaterPotential(int); + + void setEnsemble(int); + void setTemperature(double); + void setNHChain(int); + + void setTimeStep(double); + void setRunSteps(int); + void setXReplicate(int); + void setYReplicate(int); + void setZReplicate(int); + void setDumpXYZ(); + void setDumpStep(int); + + void setVelocityDist(int); + void setVelocityTemp(double); + void setZeroMOM(bool); + void setZeroL(bool); + void setThermoStyle(int); + void setThermoInterval(int); +}; +} +} + +#endif diff --git a/avogadro/qtplugins/lammpsinput/lammpsinputdialog.ui b/avogadro/qtplugins/lammpsinput/lammpsinputdialog.ui new file mode 100644 index 0000000000..20a5a1b640 --- /dev/null +++ b/avogadro/qtplugins/lammpsinput/lammpsinputdialog.ui @@ -0,0 +1,1020 @@ + + + LammpsInputDialog + + + + 0 + 0 + 774 + 697 + + + + + 0 + 0 + + + + LAMMPS Input + + + true + + + + QLayout::SetNoConstraint + + + + + QLayout::SetDefaultConstraint + + + + + Input file comments + + + Title: + + + titleLine + + + + + + + Input file comments + + + Title + + + + + + + Filename Base: + + + + + + + + + + job + + + + + + + Select the unit style to be used during the simulation. + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:10pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://lammps.sandia.gov/doc/units.html"><span style=" text-decoration: underline; color:#0057ae;">http://lammps.sandia.gov/doc/units.html</span></a></p></body></html> + + + Units + + + unitsCombo + + + + + + + Select the unit style to be used during the simulation. + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:10pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://lammps.sandia.gov/doc/units.html"><span style=" text-decoration: underline; color:#0057ae;">http://lammps.sandia.gov/doc/units.html</span></a></p></body></html> + + + 1 + + + + lj + + + + + real + + + + + metal + + + + + si + + + + + cgs + + + + + electron + + + + + + + + Water Potential + + + + + + + + NONE + + + + + SPC + + + + + SPC/E + + + + + + + + Qt::Horizontal + + + + + + + Select atom_style used by the data file. + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:10pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://lammps.sandia.gov/doc/atom_style.html"><span style=" text-decoration: underline; color:#0057ae;">http://lammps.sandia.gov/doc/atom_style.html</span></a></p></body></html> + + + Atom Style + + + atomStyleCombo + + + + + + + Select atom_style used by the data file. + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:10pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://lammps.sandia.gov/doc/atom_style.html"><span style=" text-decoration: underline; color:#0057ae;">http://lammps.sandia.gov/doc/atom_style.html</span></a></p></body></html> + + + 7 + + + + angle + + + + + atomic + + + + + bond + + + + + charge + + + + + dipole + + + + + electron + + + + + ellipsoid + + + + + full + + + + + line + + + + + meso + + + + + molecular + + + + + peri + + + + + sphere + + + + + tri + + + + + wavepacket + + + + + + + + Specify the name to be used for the coordinate file. + + + Coordinate Data File + + + + + + + Specify the name to be used for the coordinate file. + + + + + + + Ensemble + + + + + + + + NVT + + + + + NVE + + + + + + + + Temperature + + + + + + + 2 + + + 20000.000000000000000 + + + 298.149999999999977 + + + + + + + Select the number of Nosé-Hoover chains in the NVT ensemble. + + + NH Chains + + + + + + + Select the number of Nosé-Hoover chains in the NVT ensemble. + + + 0 + + + 1 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + 1 + + + Qt::Horizontal + + + + + + + Time step for the simulation in units according to "Units" specification. + + + Time Step + + + + + + + Time step for the simulation in units according to "Units" specification. + + + 0.500000000000000 + + + 2.000000000000000 + + + + + + + Filename of the XYZ file to write during the simulation. + + + Dump XYZ + + + + + + + Qt::Horizontal + + + + + + + Number of dimensions in the system. + + + Dimensions + + + dimensionCombo + + + + + + + Change Z boundary style. + + + 0 + + + + p + + + + + s + + + + + f + + + + + m + + + + + fs + + + + + fm + + + + + + + + Change Y boundary style. + + + 0 + + + + p + + + + + s + + + + + f + + + + + m + + + + + fs + + + + + fm + + + + + + + + Change X boundary style. + + + 0 + + + + p + + + + + s + + + + + f + + + + + m + + + + + fs + + + + + fm + + + + + + + + Select bondary Styles in X, Y and Z directions. + + + Boundary + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Number of replicants in X, Y and Z directions. + + + Replicate + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Replicate the X direction. + + + 1 + + + + + + + Replicate the Y direction. + + + 1 + + + + + + + Replicate the Z direction. + + + 1 + + + + + + + Filename of the XYZ file to write during the simulation. + + + + + + + Total number of timesteps to run the simulation. + + + Total Steps + + + + + + + Total number of timesteps to run the simulation. + + + 1000000000 + + + 50 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Dump Interval + + + + + + + 10000 + + + 1 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Set the initial atom velocities for the simulation. + + + Initial Velocities + + + + + + + Select the distribution of initial atom velocities. + + + + gaussian + + + + + uniform + + + + + + + + Set the initial atom velocities to match this temperature. + + + Temperature + + + + + + + Set the initial atom velocities to match this temperature. + + + 20000.000000000000000 + + + 0.500000000000000 + + + 298.149999999999977 + + + + + + + Remove system linear momentum from initial velocities. + + + Zero Linear Momentum + + + true + + + + + + + Remove system angular momentum from initial velocities. + + + Zero Angular Momentum + + + true + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Control the thermodynamic output during the simulation. + + + Output + + + + + + + Output Interval + + + + + + + 10000 + + + 50 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Number of dimensions in the system. + + + 1 + + + + 2d + + + + + 3d + + + + + + + + Thermodynamic output style. + + + + One Line + + + + + Multi Line + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + Hide Preview + + + + + + + + + true + + + + Monospace + 12 + + + + false + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Monospace'; font-size:12pt; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Courier New,courier'; font-size:10pt;"></p></body></html> + + + false + + + + + + + QLayout::SetFixedSize + + + + + Reset + + + + + + + false + + + Use Form + + + + + + + Qt::Horizontal + + + + 48 + 26 + + + + + + + + Generate... + + + + + + + Close + + + + + + + + + titleLine + moreButton + previewText + generateButton + closeButton + resetButton + enableFormButton + + + + + closeButton + clicked() + LammpsInputDialog + close() + + + 451 + 411 + + + 258 + 243 + + + + + From c2be11ef98ee1457d8a8b08cfb4312b228e99c5b Mon Sep 17 00:00:00 2001 From: Adarsh Balasubramanian Date: Sun, 22 Jul 2018 15:38:14 +0530 Subject: [PATCH 06/68] Fixing header in POSCAR test Signed-off-by: Adarsh Balasubramanian --- tests/io/poscartest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/io/poscartest.cpp b/tests/io/poscartest.cpp index 2693c6ea0d..f7078f93f5 100644 --- a/tests/io/poscartest.cpp +++ b/tests/io/poscartest.cpp @@ -24,7 +24,7 @@ #include #include -#include +#include #include #include From 4faddb8dc77adce76cf4a1334eb1f03a7a07bc43 Mon Sep 17 00:00:00 2001 From: Adarsh Balasubramanian Date: Wed, 25 Jul 2018 23:39:14 +0530 Subject: [PATCH 07/68] LAMMPS data writer Signed-off-by: Adarsh Balasubramanian --- avogadro/io/fileformatmanager.cpp | 3 +- avogadro/io/lammpsformat.cpp | 139 ++++++++++++++++++++++++++++-- avogadro/io/lammpsformat.h | 49 +++++++++-- tests/io/lammpstest.cpp | 6 +- 4 files changed, 181 insertions(+), 16 deletions(-) diff --git a/avogadro/io/fileformatmanager.cpp b/avogadro/io/fileformatmanager.cpp index 057f6bfd2c..486fef58e8 100644 --- a/avogadro/io/fileformatmanager.cpp +++ b/avogadro/io/fileformatmanager.cpp @@ -295,7 +295,8 @@ FileFormatManager::FileFormatManager() addFormat(new TrrFormat); addFormat(new XyzFormat); addFormat(new DcdFormat); - addFormat(new LammpsFormat); + addFormat(new LammpsTrajectoryFormat); + addFormat(new LammpsDataFormat); } FileFormatManager::~FileFormatManager() diff --git a/avogadro/io/lammpsformat.cpp b/avogadro/io/lammpsformat.cpp index 536740ae9f..8dc8987f85 100644 --- a/avogadro/io/lammpsformat.cpp +++ b/avogadro/io/lammpsformat.cpp @@ -40,6 +40,7 @@ namespace Io { using Core::Array; using Core::Atom; +using Core::Bond; using Core::Elements; using Core::lexicalCast; using Core::Molecule; @@ -51,11 +52,11 @@ using Core::UnitCell; using std::isalpha; #endif -LammpsFormat::LammpsFormat() {} +LammpsTrajectoryFormat::LammpsTrajectoryFormat() {} -LammpsFormat::~LammpsFormat() {} +LammpsTrajectoryFormat::~LammpsTrajectoryFormat() {} -bool LammpsFormat::read(std::istream& inStream, Core::Molecule& mol) +bool LammpsTrajectoryFormat::read(std::istream& inStream, Core::Molecule& mol) { size_t numAtoms = 0, timestep = 0, x_idx = -1, y_idx = -1, z_idx = -1, type_idx = -1, id_idx = -1; @@ -391,24 +392,150 @@ bool LammpsFormat::read(std::istream& inStream, Core::Molecule& mol) return true; } -bool LammpsFormat::write(std::ostream& outStream, const Core::Molecule& mol) +bool LammpsTrajectoryFormat::write(std::ostream& outStream, + const Core::Molecule& mol) { return false; } -std::vector LammpsFormat::fileExtensions() const +std::vector LammpsTrajectoryFormat::fileExtensions() const { std::vector ext; ext.push_back("dump"); return ext; } -std::vector LammpsFormat::mimeTypes() const +std::vector LammpsTrajectoryFormat::mimeTypes() const { std::vector mime; mime.push_back("text/lammps"); return mime; } +LammpsDataFormat::LammpsDataFormat() {} + +LammpsDataFormat::~LammpsDataFormat() {} + +bool LammpsDataFormat::read(std::istream& inStream, Core::Molecule& mol) +{ + return false; +} + +bool LammpsDataFormat::write(std::ostream& outStream, const Core::Molecule& mol) +{ + // Title + if (mol.data("name").toString().length()) + outStream << mol.data("name").toString() << std::endl; + else + outStream << "LAMMPS data file generated by Avogadro" << std::endl; + + std::ostringstream massStream, atomStream, bondStream; + double xmin, xmax, ymin, ymax, zmin, zmax; + + size_t numAtoms = mol.atomCount(); + outStream << to_string(numAtoms) << " atoms\n"; + + size_t numBonds = mol.bondCount(); + outStream << to_string(numBonds) << " bonds\n"; + + // A map of atomic symbols to their quantity. + size_t idx = 1; + Array atomicNumbers = mol.atomicNumbers(); + std::map composition; + for (Array::const_iterator it = atomicNumbers.begin(), + itEnd = atomicNumbers.end(); + it != itEnd; ++it) { + if (composition.find(*it) == composition.end()) { + composition[*it] = idx++; + } + } + + outStream << composition.size() << " atom types\n"; + + // Masses + massStream << "Masses\n\n"; + std::map::iterator iter = composition.begin(); + while (iter != composition.end()) { + massStream << iter->second << " " << Elements::mass(iter->first); + ++iter; + } + massStream << std::endl << std::endl << std::endl; + + if (numAtoms) { + // Atomic coordinates + atomStream << "Atoms\n\n"; + for (Index i = 0; i < numAtoms; ++i) { + Atom atom = mol.atom(i); + if (!atom.isValid()) { + appendError("Internal error: Atom invalid."); + return false; + } + Vector3 coords = atom.position3d(); + if (i == 0) { + xmin = coords[0]; + xmax = coords[0]; + ymin = coords[1]; + ymax = coords[1]; + zmin = coords[2]; + zmax = coords[2]; + } else { + xmin = std::min(coords[0], xmin); + xmax = std::max(coords[0], xmax); + ymin = std::min(coords[1], ymin); + ymax = std::max(coords[1], ymax); + zmin = std::min(coords[2], zmin); + zmax = std::max(coords[2], zmax); + } + + atomStream << std::setw(static_cast(log(numAtoms)) + 1) + << std::left << to_string(i + 1) << " " + << to_string(composition[atomicNumbers[i]]) << " " + << std::setw(10) << std::right << std::fixed << coords.x() + << " " << std::setw(10) << std::right << std::fixed + << coords.y() << " " << std::setw(10) << std::right + << std::fixed << coords.z() << "\n"; + } + + atomStream << std::endl << std::endl; + } + + if (numBonds) { + // Bonds + bondStream << "Bonds\n\n"; + for (Index i = 0; i < numBonds; ++i) { + Bond b = mol.bond(i); + bondStream << b.atom1().index() + 1 << " " << b.atom2().index() + 1 << " " + << b.order() << endl; + } + } + + outStream << std::setw(10) << xmin - 0.5 << " " << std::setw(10) << xmax + 0.5 + << " xlo xhi" << endl + << std::setw(10) << ymin - 0.5 << " " << std::setw(10) << ymax + 0.5 + << " ylo yhi" << endl + << std::setw(10) << zmin - 0.5 << " " << std::setw(10) << zmax + 0.5 + << " zlo zhi" << endl; + outStream << std::endl << std::endl << std::endl; + outStream << massStream.str(); + outStream << atomStream.str(); + outStream << bondStream.str(); + + return true; +} + +std::vector LammpsDataFormat::fileExtensions() const +{ + std::vector ext; + ext.push_back("lmpdat"); + return ext; +} + +std::vector LammpsDataFormat::mimeTypes() const +{ + std::vector mime; + mime.push_back("N/A"); + return mime; +} + } // end Io namespace } // end Avogadro namespace diff --git a/avogadro/io/lammpsformat.h b/avogadro/io/lammpsformat.h index 076e814cdf..bbabe26879 100644 --- a/avogadro/io/lammpsformat.h +++ b/avogadro/io/lammpsformat.h @@ -23,24 +23,30 @@ namespace Avogadro { namespace Io { /** - * @class LammpsFormat lammpsformat.h + * @class LammpsTrajectoryFormat lammpsformat.h * @brief Implementation of the generic lammps trajectory format. * @author Adarsh B */ -class AVOGADROIO_EXPORT LammpsFormat : public FileFormat +class AVOGADROIO_EXPORT LammpsTrajectoryFormat : public FileFormat { public: - LammpsFormat(); - ~LammpsFormat() override; + LammpsTrajectoryFormat(); + ~LammpsTrajectoryFormat() override; Operations supportedOperations() const override { return ReadWrite | MultiMolecule | File | Stream | String; } - FileFormat* newInstance() const override { return new LammpsFormat; } - std::string identifier() const override { return "Avogadro: LAMMPS"; } + FileFormat* newInstance() const override + { + return new LammpsTrajectoryFormat; + } + std::string identifier() const override + { + return "Avogadro: LAMMPS Trajectory dump"; + } std::string name() const override { return "LAMMPS"; } std::string description() const override { @@ -59,6 +65,37 @@ class AVOGADROIO_EXPORT LammpsFormat : public FileFormat bool write(std::ostream& outStream, const Core::Molecule& molecule) override; }; +class AVOGADROIO_EXPORT LammpsDataFormat : public FileFormat +{ +public: + LammpsDataFormat(); + ~LammpsDataFormat() override; + + Operations supportedOperations() const override + { + return ReadWrite | MultiMolecule | File | Stream | String; + } + + FileFormat* newInstance() const override { return new LammpsDataFormat; } + std::string identifier() const override { return "Avogadro: LAMMPS Data"; } + std::string name() const override { return "LAMMPS"; } + std::string description() const override + { + return "Generic LAMMPS Data format."; + } + + std::string specificationUrl() const override + { + return "http://lammps.sandia.gov/"; + } + + std::vector fileExtensions() const override; + std::vector mimeTypes() const override; + + bool read(std::istream& inStream, Core::Molecule& molecule) override; + bool write(std::ostream& outStream, const Core::Molecule& molecule) override; +}; + } // end Io namespace } // end Avogadro namespace diff --git a/tests/io/lammpstest.cpp b/tests/io/lammpstest.cpp index 182576ecdc..03a7d32797 100644 --- a/tests/io/lammpstest.cpp +++ b/tests/io/lammpstest.cpp @@ -34,11 +34,11 @@ using Avogadro::Core::Atom; using Avogadro::Core::Molecule; using Avogadro::Core::UnitCell; using Avogadro::Io::FileFormat; -using Avogadro::Io::LammpsFormat; +using Avogadro::Io::LammpsTrajectoryFormat; TEST(LammpsTest, read) { - LammpsFormat multi; + LammpsTrajectoryFormat multi; multi.open(AVOGADRO_DATA "/data/silicon_bulk.dump", FileFormat::Read | FileFormat::MultiMolecule); Molecule molecule, molecule2; @@ -102,7 +102,7 @@ TEST(LammpsTest, read) TEST(LammpsTest, modes) { // This tests some of the mode setting/checking code - LammpsFormat format; + LammpsTrajectoryFormat format; format.open(AVOGADRO_DATA "/data/silicon_bulk.dump", FileFormat::Read); EXPECT_TRUE(format.isMode(FileFormat::Read)); EXPECT_TRUE(format.mode() & FileFormat::Read); From 91f1adfba0186521b09f34ca8f1500d790dd3e66 Mon Sep 17 00:00:00 2001 From: Adarsh Balasubramanian Date: Fri, 27 Jul 2018 21:18:15 +0530 Subject: [PATCH 08/68] Setting simulation box params from unitcell vectors Signed-off-by: Adarsh Balasubramanian --- avogadro/io/lammpsformat.cpp | 95 +++++++++++++++++++++++++++--------- 1 file changed, 72 insertions(+), 23 deletions(-) diff --git a/avogadro/io/lammpsformat.cpp b/avogadro/io/lammpsformat.cpp index 8dc8987f85..17b820df37 100644 --- a/avogadro/io/lammpsformat.cpp +++ b/avogadro/io/lammpsformat.cpp @@ -16,6 +16,7 @@ #include "lammpsformat.h" +#include #include #include #include @@ -41,6 +42,7 @@ namespace Io { using Core::Array; using Core::Atom; using Core::Bond; +using Core::CrystalTools; using Core::Elements; using Core::lexicalCast; using Core::Molecule; @@ -423,24 +425,27 @@ bool LammpsDataFormat::read(std::istream& inStream, Core::Molecule& mol) bool LammpsDataFormat::write(std::ostream& outStream, const Core::Molecule& mol) { + Core::Molecule mol2(mol); + CrystalTools::rotateToStandardOrientation(mol2, CrystalTools::TransformAtoms); + // Title - if (mol.data("name").toString().length()) - outStream << mol.data("name").toString() << std::endl; + if (mol2.data("name").toString().length()) + outStream << mol2.data("name").toString() << std::endl; else outStream << "LAMMPS data file generated by Avogadro" << std::endl; std::ostringstream massStream, atomStream, bondStream; double xmin, xmax, ymin, ymax, zmin, zmax; - size_t numAtoms = mol.atomCount(); + size_t numAtoms = mol2.atomCount(); outStream << to_string(numAtoms) << " atoms\n"; - size_t numBonds = mol.bondCount(); + size_t numBonds = mol2.bondCount(); outStream << to_string(numBonds) << " bonds\n"; // A map of atomic symbols to their quantity. size_t idx = 1; - Array atomicNumbers = mol.atomicNumbers(); + Array atomicNumbers = mol2.atomicNumbers(); std::map composition; for (Array::const_iterator it = atomicNumbers.begin(), itEnd = atomicNumbers.end(); @@ -456,7 +461,7 @@ bool LammpsDataFormat::write(std::ostream& outStream, const Core::Molecule& mol) massStream << "Masses\n\n"; std::map::iterator iter = composition.begin(); while (iter != composition.end()) { - massStream << iter->second << " " << Elements::mass(iter->first); + massStream << iter->second << " " << Elements::mass(iter->first) << "\n"; ++iter; } massStream << std::endl << std::endl << std::endl; @@ -465,7 +470,7 @@ bool LammpsDataFormat::write(std::ostream& outStream, const Core::Molecule& mol) // Atomic coordinates atomStream << "Atoms\n\n"; for (Index i = 0; i < numAtoms; ++i) { - Atom atom = mol.atom(i); + Atom atom = mol2.atom(i); if (!atom.isValid()) { appendError("Internal error: Atom invalid."); return false; @@ -487,13 +492,12 @@ bool LammpsDataFormat::write(std::ostream& outStream, const Core::Molecule& mol) zmax = std::max(coords[2], zmax); } - atomStream << std::setw(static_cast(log(numAtoms)) + 1) - << std::left << to_string(i + 1) << " " - << to_string(composition[atomicNumbers[i]]) << " " - << std::setw(10) << std::right << std::fixed << coords.x() - << " " << std::setw(10) << std::right << std::fixed - << coords.y() << " " << std::setw(10) << std::right - << std::fixed << coords.z() << "\n"; + char atomline[200]; + sprintf(atomline, "%-*d %d %10f %10f %10f\n", + static_cast(log(numAtoms)) + 1, static_cast(i + 1), + static_cast(composition[atomicNumbers[i]]), coords.x(), + coords.y(), coords.z()); + atomStream << atomline; } atomStream << std::endl << std::endl; @@ -501,20 +505,65 @@ bool LammpsDataFormat::write(std::ostream& outStream, const Core::Molecule& mol) if (numBonds) { // Bonds + std::map, int> bondIds; + int bondItr = 1; bondStream << "Bonds\n\n"; for (Index i = 0; i < numBonds; ++i) { - Bond b = mol.bond(i); - bondStream << b.atom1().index() + 1 << " " << b.atom2().index() + 1 << " " - << b.order() << endl; + char bondline[200]; + Bond b = mol2.bond(i); + if (bondIds.find(std::make_pair(b.atom1().atomicNumber(), + b.atom2().atomicNumber())) != + bondIds.end()) { + sprintf(bondline, "%-*d %7d %7d %7d\n", + static_cast(log(numAtoms) + 1), static_cast(i + 1), + bondIds[std::make_pair(b.atom1().atomicNumber(), + b.atom2().atomicNumber())], + static_cast(b.atom1().index() + 1), + static_cast(b.atom2().index() + 1)); + bondStream << bondline; + } else if (bondIds.find(std::make_pair(b.atom2().atomicNumber(), + b.atom1().atomicNumber())) != + bondIds.end()) { + sprintf(bondline, "%-*d %7d %7d %7d\n", + static_cast(log(numAtoms) + 1), static_cast(i + 1), + bondIds[std::make_pair(b.atom1().atomicNumber(), + b.atom2().atomicNumber())], + static_cast(b.atom2().index() + 1), + static_cast(b.atom1().index() + 1)); + bondStream << bondline; + } else { + bondIds.insert(std::make_pair( + std::make_pair(b.atom1().atomicNumber(), b.atom2().atomicNumber()), + bondItr++)); + sprintf(bondline, "%-*d %7d %7d %7d\n", + static_cast(log(numAtoms) + 1), static_cast(i + 1), + bondIds[std::make_pair(b.atom1().atomicNumber(), + b.atom2().atomicNumber())], + static_cast(b.atom1().index() + 1), + static_cast(b.atom2().index() + 1)); + bondStream << bondline; + } } } - outStream << std::setw(10) << xmin - 0.5 << " " << std::setw(10) << xmax + 0.5 - << " xlo xhi" << endl - << std::setw(10) << ymin - 0.5 << " " << std::setw(10) << ymax + 0.5 - << " ylo yhi" << endl - << std::setw(10) << zmin - 0.5 << " " << std::setw(10) << zmax + 0.5 - << " zlo zhi" << endl; + UnitCell* unitcell = mol2.unitCell(); + char simBoxBlock[200]; + if (unitcell) { + const Matrix3& mat = unitcell->cellMatrix().transpose(); + sprintf(simBoxBlock, + "%10f %10f xlo xhi\n%10f %10f ylo yhi\n%10f %10f zlo zhi\n%10f " + "%10f %10f xy xz yz", + 0.0, mat(0, 0), 0.0, mat(1, 1), 0.0, mat(2, 2), mat(1, 0), + mat(2, 0), mat(2, 1)); + outStream << simBoxBlock; + } else { + sprintf(simBoxBlock, + "%10f %10f xlo xhi\n%10f %10f ylo yhi\n%10f %10f zlo zhi\n%10f " + "%10f %10f xy xz yz", + xmin - 0.5, xmax - 0.5, ymin - 0.5, ymax - 0.5, zmin - 0.5, + zmax - 0.5, 0.0, 0.0, 0.0); + outStream << simBoxBlock; + } outStream << std::endl << std::endl << std::endl; outStream << massStream.str(); outStream << atomStream.str(); From 4fae58e472ef560b85fa182277ab8b7309e597ff Mon Sep 17 00:00:00 2001 From: Geoff Hutchison Date: Fri, 27 Jul 2018 11:50:39 -0400 Subject: [PATCH 09/68] Add a script to download residue/ligand data from PDB Uses LigandExpo (http://ligand-expo.rcsb.org) to get common residues and ligands. Grabs SDF (for bond orders) and PDB (for atom names) to generate residue data. Currently grabs all ligands with >1000 occurrences, which seems to include most obvious cases. Signed-off-by: Geoff Hutchison --- avogadro/core/residuedata.h | 1681 +++++++++++++++++++++++------------ scripts/getresdata.py | 179 ++++ 2 files changed, 1286 insertions(+), 574 deletions(-) create mode 100644 scripts/getresdata.py diff --git a/avogadro/core/residuedata.h b/avogadro/core/residuedata.h index b0b7814518..0055e49b2e 100644 --- a/avogadro/core/residuedata.h +++ b/avogadro/core/residuedata.h @@ -1,3 +1,4 @@ + #ifndef AVOGADRO_CORE_RESIDUE_DATA #define AVOGADRO_CORE_RESIDUE_DATA @@ -55,717 +56,1249 @@ class ResidueData ResidueData ALAData("ALA", // Atoms - { "CA", "N", "CB", "C", "O" }, + { "N", "CA", "C", "O", "CB", "OXT", "H", "H2", "HA", "HB1", + "HB2", "HB3", "HXT" }, // Single Bonds - { { "CA", "N" }, - { "CA", "CB" }, - { "CA", "C" }, + { { "N", "CA" }, { "N", "H" }, - { "N", "HN" }, - { "HA", "CA" }, - { "HB1", "CB" }, - { "HB2", "CB" }, - { "HB3", "CB" } }, + { "N", "H2" }, + { "CA", "C" }, + { "CA", "CB" }, + { "CA", "HA" }, + { "C", "OXT" }, + { "CB", "HB1" }, + { "CB", "HB2" }, + { "CB", "HB3" }, + { "OXT", "HXT" } }, // Double Bonds { { "C", "O" } }); - -ResidueData ARGData( - "ARG", - // Atoms - { "CA", "N", "CB", "C", "O", "CG", "CD", "NE", "CZ", "NH2", "NH1" }, - // Single Bonds - { { "CA", "N" }, { "CA", "CB" }, { "CA", "C" }, { "CB", "CG" }, - { "CG", "CD" }, { "CD", "NE" }, { "NE", "CZ" }, { "CZ", "NH1" }, - { "N", "H" }, { "HN", "N" }, { "NH1", "HH11" }, { "NH1", "HH12" }, - { "NE", "HE" }, { "NH2", "HH21" }, { "NH2", "HH22" }, { "NH1", "HH1" }, - { "NH2", "HH2" }, { "HB1", "CB" }, { "HB2", "CB" }, { "HD1", "CD" }, - { "HD2", "CD" }, { "HG1", "CG" }, { "HG2", "CG" } }, - // Double Bonds - { { "C", "O" }, { "CZ", "NH2" } }); - -ResidueData ARZData("ARZ", +ResidueData CYSData("CYS", // Atoms - { "CA", "N", "CB", "C", "O", "CG", "CD", "NE", "CZ", "NH2", - "NH1" }, + { "N", "CA", "C", "O", "CB", "SG", "OXT", "H", "H2", "HA", + "HB2", "HB3", "HG", "HXT" }, // Single Bonds - { { "CA", "N" }, - { "CA", "CB" }, - { "CA", "C" }, - { "CB", "CG" }, - { "CG", "CD" }, - { "CD", "NE" }, - { "NE", "CZ" }, - { "CZ", "NH2" }, + { { "N", "CA" }, { "N", "H" }, - { "N", "HN" }, - { "NH1", "HH1" }, - { "NE", "HE" }, - { "NH2", "HH21" }, - { "NH2", "HH22" } }, + { "N", "H2" }, + { "CA", "C" }, + { "CA", "CB" }, + { "CA", "HA" }, + { "C", "OXT" }, + { "CB", "SG" }, + { "CB", "HB2" }, + { "CB", "HB3" }, + { "SG", "HG" }, + { "OXT", "HXT" } }, // Double Bonds - { { "C", "O" }, { "CZ", "NH1" } }); - -ResidueData ASNData("ASN", + { { "C", "O" } }); +ResidueData ASPData("ASP", // Atoms - { "CA", "N", "CB", "C", "O", "CG", "ND2", "OD1" }, + { "N", "CA", "C", "O", "CB", "CG", "OD1", "OD2", "OXT", "H", + "H2", "HA", "HB2", "HB3", "HD2", "HXT" }, // Single Bonds - { { "CA", "N" }, - { "CA", "CB" }, + { { "N", "CA" }, + { "N", "H" }, + { "N", "H2" }, { "CA", "C" }, + { "CA", "CB" }, + { "CA", "HA" }, + { "C", "OXT" }, { "CB", "CG" }, - { "CG", "ND2" }, - { "N", "H" }, - { "N", "HN" }, - { "HA", "CA" }, - { "HB1", "CB" }, - { "HB2", "CB" }, - { "ND2", "HD21" }, - { "ND2", "HD22" }, - { "ND2", "HD2" } }, + { "CB", "HB2" }, + { "CB", "HB3" }, + { "CG", "OD2" }, + { "OD2", "HD2" }, + { "OXT", "HXT" } }, // Double Bonds { { "C", "O" }, { "CG", "OD1" } }); - -ResidueData ASPData("ASP", +ResidueData GLUData("GLU", // Atoms - { "CA", "N", "CB", "C", "O", "CG", "OD2", "OD1" }, + { "N", "CA", "C", "O", "CB", "CG", "CD", "OE1", "OE2", + "OXT", "H", "H2", "HA", "HB2", "HB3", "HG2", "HG3", "HE2", + "HXT" }, // Single Bonds - { { "CA", "N" }, - { "CA", "CB" }, + { { "N", "CA" }, + { "N", "H" }, + { "N", "H2" }, { "CA", "C" }, + { "CA", "CB" }, + { "CA", "HA" }, + { "C", "OXT" }, { "CB", "CG" }, - { "CG", "OD1" }, + { "CB", "HB2" }, + { "CB", "HB3" }, + { "CG", "CD" }, + { "CG", "HG2" }, + { "CG", "HG3" }, + { "CD", "OE2" }, + { "OE2", "HE2" }, + { "OXT", "HXT" } }, + // Double Bonds + { { "C", "O" }, { "CD", "OE1" } }); +ResidueData PHEData( + "PHE", + // Atoms + { "N", "CA", "C", "O", "CB", "CG", "CD1", "CD2", + "CE1", "CE2", "CZ", "OXT", "H", "H2", "HA", "HB2", + "HB3", "HD1", "HD2", "HE1", "HE2", "HZ", "HXT" }, + // Single Bonds + { { "N", "CA" }, + { "N", "H" }, + { "N", "H2" }, + { "CA", "C" }, + { "CA", "CB" }, + { "CA", "HA" }, + { "C", "OXT" }, + { "CB", "CG" }, + { "CB", "HB2" }, + { "CB", "HB3" }, + { "CG", "CD2" }, + { "CD1", "CE1" }, + { "CD1", "HD1" }, + { "CD2", "HD2" }, + { "CE1", "HE1" }, + { "CE2", "CZ" }, + { "CE2", "HE2" }, + { "CZ", "HZ" }, + { "OXT", "HXT" } }, + // Double Bonds + { { "C", "O" }, { "CG", "CD1" }, { "CD2", "CE2" }, { "CE1", "CZ" } }); +ResidueData GLYData("GLY", + // Atoms + { "N", "CA", "C", "O", "OXT", "H", "H2", "HA2", "HA3", + "HXT" }, + // Single Bonds + { { "N", "CA" }, { "N", "H" }, - { "N", "HN" }, - { "HA", "CA" }, - { "HB1", "CB" }, - { "HB2", "CB" } }, + { "N", "H2" }, + { "CA", "C" }, + { "CA", "HA2" }, + { "CA", "HA3" }, + { "C", "OXT" }, + { "OXT", "HXT" } }, // Double Bonds - { { "C", "O" }, { "CG", "OD2" } }); - -ResidueData ASHData("ASH", + { { "C", "O" } }); +ResidueData HISData("HIS", // Atoms - { "CA", "N", "CB", "C", "O", "CG", "OD2", "OD1" }, + { "N", "CA", "C", "O", "CB", "CG", "ND1", + "CD2", "CE1", "NE2", "OXT", "H", "H2", "HA", + "HB2", "HB3", "HD1", "HD2", "HE1", "HE2", "HXT" }, // Single Bonds - { { "CA", "N" }, - { "CA", "CB" }, + { { "N", "CA" }, + { "N", "H" }, + { "N", "H2" }, { "CA", "C" }, + { "CA", "CB" }, + { "CA", "HA" }, + { "C", "OXT" }, { "CB", "CG" }, - { "CG", "OD2" }, - { "N", "H" }, - { "N", "HN" }, - { "OD2", "HD2" } }, + { "CB", "HB2" }, + { "CB", "HB3" }, + { "CG", "ND1" }, + { "ND1", "HD1" }, + { "CD2", "NE2" }, + { "CD2", "HD2" }, + { "CE1", "NE2" }, + { "CE1", "HE1" }, + { "NE2", "HE2" }, + { "OXT", "HXT" } }, // Double Bonds - { { "C", "O" }, { "CG", "OD1" } }); - -ResidueData CYSData("CYS", + { { "C", "O" }, { "CG", "CD2" }, { "ND1", "CE1" } }); +ResidueData ILEData( + "ILE", + // Atoms + { "N", "CA", "C", "O", "CB", "CG1", "CG2", "CD1", + "OXT", "H", "H2", "HA", "HB", "HG12", "HG13", "HG21", + "HG22", "HG23", "HD11", "HD12", "HD13", "HXT" }, + // Single Bonds + { { "N", "CA" }, { "N", "H" }, { "N", "H2" }, { "CA", "C" }, + { "CA", "CB" }, { "CA", "HA" }, { "C", "OXT" }, { "CB", "CG1" }, + { "CB", "CG2" }, { "CB", "HB" }, { "CG1", "CD1" }, { "CG1", "HG12" }, + { "CG1", "HG13" }, { "CG2", "HG21" }, { "CG2", "HG22" }, { "CG2", "HG23" }, + { "CD1", "HD11" }, { "CD1", "HD12" }, { "CD1", "HD13" }, { "OXT", "HXT" } }, + // Double Bonds + { { "C", "O" } }); +ResidueData LYSData( + "LYS", + // Atoms + { "N", "CA", "C", "O", "CB", "CG", "CD", "CE", "NZ", + "OXT", "H", "H2", "HA", "HB2", "HB3", "HG2", "HG3", "HD2", + "HD3", "HE2", "HE3", "HZ1", "HZ2", "HZ3", "HXT" }, + // Single Bonds + { { "N", "CA" }, { "N", "H" }, { "N", "H2" }, { "CA", "C" }, + { "CA", "CB" }, { "CA", "HA" }, { "C", "OXT" }, { "CB", "CG" }, + { "CB", "HB2" }, { "CB", "HB3" }, { "CG", "CD" }, { "CG", "HG2" }, + { "CG", "HG3" }, { "CD", "CE" }, { "CD", "HD2" }, { "CD", "HD3" }, + { "CE", "NZ" }, { "CE", "HE2" }, { "CE", "HE3" }, { "NZ", "HZ1" }, + { "NZ", "HZ2" }, { "NZ", "HZ3" }, { "OXT", "HXT" } }, + // Double Bonds + { { "C", "O" } }); +ResidueData LEUData( + "LEU", + // Atoms + { "N", "CA", "C", "O", "CB", "CG", "CD1", "CD2", + "OXT", "H", "H2", "HA", "HB2", "HB3", "HG", "HD11", + "HD12", "HD13", "HD21", "HD22", "HD23", "HXT" }, + // Single Bonds + { { "N", "CA" }, { "N", "H" }, { "N", "H2" }, { "CA", "C" }, + { "CA", "CB" }, { "CA", "HA" }, { "C", "OXT" }, { "CB", "CG" }, + { "CB", "HB2" }, { "CB", "HB3" }, { "CG", "CD1" }, { "CG", "CD2" }, + { "CG", "HG" }, { "CD1", "HD11" }, { "CD1", "HD12" }, { "CD1", "HD13" }, + { "CD2", "HD21" }, { "CD2", "HD22" }, { "CD2", "HD23" }, { "OXT", "HXT" } }, + // Double Bonds + { { "C", "O" } }); +ResidueData METData("MET", // Atoms - { "CA", "N", "CB", "C", "O", "SG" }, + { "N", "CA", "C", "O", "CB", "CG", "SD", + "CE", "OXT", "H", "H2", "HA", "HB2", "HB3", + "HG2", "HG3", "HE1", "HE2", "HE3", "HXT" }, // Single Bonds - { { "SG", "CB" }, - { "CA", "N" }, - { "CA", "CB" }, - { "CA", "C" }, - { "CB", "SG" }, + { { "N", "CA" }, { "N", "H" }, - { "N", "HN" }, + { "N", "H2" }, + { "CA", "C" }, + { "CA", "CB" }, { "CA", "HA" }, - { "HB1", "CB" }, - { "HB2", "CB" }, - { "SG", "HG" } }, + { "C", "OXT" }, + { "CB", "CG" }, + { "CB", "HB2" }, + { "CB", "HB3" }, + { "CG", "SD" }, + { "CG", "HG2" }, + { "CG", "HG3" }, + { "SD", "CE" }, + { "CE", "HE1" }, + { "CE", "HE2" }, + { "CE", "HE3" }, + { "OXT", "HXT" } }, // Double Bonds { { "C", "O" } }); - -ResidueData CYXData("CYX", +ResidueData ASNData("ASN", // Atoms - { "CA", "N", "CB", "C", "O", "SG" }, + { "N", "CA", "C", "O", "CB", "CG", "OD1", "ND2", "OXT", "H", + "H2", "HA", "HB2", "HB3", "HD21", "HD22", "HXT" }, // Single Bonds - { { "CA", "N" }, + { { "N", "CA" }, + { "N", "H" }, + { "N", "H2" }, + { "CA", "C" }, { "CA", "CB" }, + { "CA", "HA" }, + { "C", "OXT" }, + { "CB", "CG" }, + { "CB", "HB2" }, + { "CB", "HB3" }, + { "CG", "ND2" }, + { "ND2", "HD21" }, + { "ND2", "HD22" }, + { "OXT", "HXT" } }, + // Double Bonds + { { "C", "O" }, { "CG", "OD1" } }); +ResidueData PROData("PRO", + // Atoms + { "N", "CA", "C", "O", "CB", "CG", "CD", "OXT", "H", "HA", + "HB2", "HB3", "HG2", "HG3", "HD2", "HD3", "HXT" }, + // Single Bonds + { { "N", "CA" }, + { "N", "CD" }, + { "N", "H" }, { "CA", "C" }, - { "CB", "SG" }, - { "N", "H" } }, + { "CA", "CB" }, + { "CA", "HA" }, + { "C", "OXT" }, + { "CB", "CG" }, + { "CB", "HB2" }, + { "CB", "HB3" }, + { "CG", "CD" }, + { "CG", "HG2" }, + { "CG", "HG3" }, + { "CD", "HD2" }, + { "CD", "HD3" }, + { "OXT", "HXT" } }, // Double Bonds { { "C", "O" } }); - ResidueData GLNData("GLN", // Atoms - { "CA", "N", "CB", "C", "O", "CG", "CD", "NE2", "OE1" }, + { "N", "CA", "C", "O", "CB", "CG", "CD", + "OE1", "NE2", "OXT", "H", "H2", "HA", "HB2", + "HB3", "HG2", "HG3", "HE21", "HE22", "HXT" }, // Single Bonds - { { "CA", "N" }, - { "CA", "CB" }, + { { "N", "CA" }, + { "N", "H" }, + { "N", "H2" }, { "CA", "C" }, + { "CA", "CB" }, + { "CA", "HA" }, + { "C", "OXT" }, { "CB", "CG" }, + { "CB", "HB2" }, + { "CB", "HB3" }, { "CG", "CD" }, + { "CG", "HG2" }, + { "CG", "HG3" }, { "CD", "NE2" }, - { "N", "H" }, - { "N", "HN" }, - { "CA", "HA" }, - { "HB1", "CB" }, - { "HB2", "CB" }, - { "HG1", "CG" }, - { "HG2", "CG" }, { "NE2", "HE21" }, { "NE2", "HE22" }, - { "NE2", "HE2" } }, + { "OXT", "HXT" } }, // Double Bonds { { "C", "O" }, { "CD", "OE1" } }); - -ResidueData GLUData("GLU", +ResidueData ARGData( + "ARG", + // Atoms + { "N", "CA", "C", "O", "CB", "CG", "CD", "NE", "CZ", + "NH1", "NH2", "OXT", "H", "H2", "HA", "HB2", "HB3", "HG2", + "HG3", "HD2", "HD3", "HE", "HH11", "HH12", "HH21", "HH22", "HXT" }, + // Single Bonds + { { "N", "CA" }, { "N", "H" }, { "N", "H2" }, { "CA", "C" }, + { "CA", "CB" }, { "CA", "HA" }, { "C", "OXT" }, { "CB", "CG" }, + { "CB", "HB2" }, { "CB", "HB3" }, { "CG", "CD" }, { "CG", "HG2" }, + { "CG", "HG3" }, { "CD", "NE" }, { "CD", "HD2" }, { "CD", "HD3" }, + { "NE", "CZ" }, { "NE", "HE" }, { "CZ", "NH1" }, { "NH1", "HH11" }, + { "NH1", "HH12" }, { "NH2", "HH21" }, { "NH2", "HH22" }, { "OXT", "HXT" } }, + // Double Bonds + { { "C", "O" }, { "CZ", "NH2" } }); +ResidueData SERData("SER", // Atoms - { "CA", "N", "CB", "C", "O", "CG", "CD", "OE2", "OE1" }, + { "N", "CA", "C", "O", "CB", "OG", "OXT", "H", "H2", "HA", + "HB2", "HB3", "HG", "HXT" }, // Single Bonds - { { "CA", "N" }, - { "CA", "CB" }, - { "CA", "C" }, - { "CB", "CG" }, - { "CG", "CD" }, - { "CD", "OE2" }, + { { "N", "CA" }, { "N", "H" }, - { "N", "H1" }, { "N", "H2" }, - { "N", "H3" }, - { "HA", "CA" }, - { "HB1", "CB" }, - { "HB2", "CB" }, - { "HG1", "CG" }, - { "HG2", "CG" } }, + { "CA", "C" }, + { "CA", "CB" }, + { "CA", "HA" }, + { "C", "OXT" }, + { "CB", "OG" }, + { "CB", "HB2" }, + { "CB", "HB3" }, + { "OG", "HG" }, + { "OXT", "HXT" } }, // Double Bonds - { { "C", "O" }, { "CD", "OE1" } }); - -ResidueData GLYData("GLY", + { { "C", "O" } }); +ResidueData THRData("THR", // Atoms - { "CA", "N", "C", "O" }, + { "N", "CA", "C", "O", "CB", "OG1", "CG2", "OXT", "H", "H2", + "HA", "HB", "HG1", "HG21", "HG22", "HG23", "HXT" }, // Single Bonds - { { "CA", "N" }, - { "CA", "C" }, + { { "N", "CA" }, { "N", "H" }, - { "N", "HN" }, - { "HA1", "CA" }, - { "HA2", "CA" } }, + { "N", "H2" }, + { "CA", "C" }, + { "CA", "CB" }, + { "CA", "HA" }, + { "C", "OXT" }, + { "CB", "OG1" }, + { "CB", "CG2" }, + { "CB", "HB" }, + { "OG1", "HG1" }, + { "CG2", "HG21" }, + { "CG2", "HG22" }, + { "CG2", "HG23" }, + { "OXT", "HXT" } }, // Double Bonds { { "C", "O" } }); - -ResidueData GLZData("GLZ", +ResidueData VALData("VAL", // Atoms - { "CA", "N", "CB", "C", "O", "CG", "CD", "OE2", "OE1" }, + { "N", "CA", "C", "O", "CB", "CG1", "CG2", "OXT", "H", "H2", + "HA", "HB", "HG11", "HG12", "HG13", "HG21", "HG22", + "HG23", "HXT" }, // Single Bonds - { { "CA", "N" }, - { "CA", "CB" }, - { "CA", "C" }, - { "CB", "CG" }, - { "CG", "CD" }, - { "CD", "OE2" }, + { { "N", "CA" }, { "N", "H" }, - { "OE2", "HE2" } }, + { "N", "H2" }, + { "CA", "C" }, + { "CA", "CB" }, + { "CA", "HA" }, + { "C", "OXT" }, + { "CB", "CG1" }, + { "CB", "CG2" }, + { "CB", "HB" }, + { "CG1", "HG11" }, + { "CG1", "HG12" }, + { "CG1", "HG13" }, + { "CG2", "HG21" }, + { "CG2", "HG22" }, + { "CG2", "HG23" }, + { "OXT", "HXT" } }, // Double Bonds - { { "C", "O" }, { "CD", "OE1" } }); - -ResidueData HIDData("HID", + { { "C", "O" } }); +ResidueData TRPData( + "TRP", + // Atoms + { "N", "CA", "C", "O", "CB", "CG", "CD1", "CD2", "NE1", + "CE2", "CE3", "CZ2", "CZ3", "CH2", "OXT", "H", "H2", "HA", + "HB2", "HB3", "HD1", "HE1", "HE3", "HZ2", "HZ3", "HH2", "HXT" }, + // Single Bonds + { { "N", "CA" }, { "N", "H" }, { "N", "H2" }, { "CA", "C" }, + { "CA", "CB" }, { "CA", "HA" }, { "C", "OXT" }, { "CB", "CG" }, + { "CB", "HB2" }, { "CB", "HB3" }, { "CG", "CD2" }, { "CD1", "NE1" }, + { "CD1", "HD1" }, { "CD2", "CE3" }, { "NE1", "CE2" }, { "NE1", "HE1" }, + { "CE2", "CZ2" }, { "CE3", "HE3" }, { "CZ2", "HZ2" }, { "CZ3", "CH2" }, + { "CZ3", "HZ3" }, { "CH2", "HH2" }, { "OXT", "HXT" } }, + // Double Bonds + { { "C", "O" }, + { "CG", "CD1" }, + { "CD2", "CE2" }, + { "CE3", "CZ3" }, + { "CZ2", "CH2" } }); +ResidueData TYRData( + "TYR", + // Atoms + { "N", "CA", "C", "O", "CB", "CG", "CD1", "CD2", + "CE1", "CE2", "CZ", "OH", "OXT", "H", "H2", "HA", + "HB2", "HB3", "HD1", "HD2", "HE1", "HE2", "HH", "HXT" }, + // Single Bonds + { { "N", "CA" }, { "N", "H" }, { "N", "H2" }, { "CA", "C" }, + { "CA", "CB" }, { "CA", "HA" }, { "C", "OXT" }, { "CB", "CG" }, + { "CB", "HB2" }, { "CB", "HB3" }, { "CG", "CD2" }, { "CD1", "CE1" }, + { "CD1", "HD1" }, { "CD2", "HD2" }, { "CE1", "HE1" }, { "CE2", "CZ" }, + { "CE2", "HE2" }, { "CZ", "OH" }, { "OH", "HH" }, { "OXT", "HXT" } }, + // Double Bonds + { { "C", "O" }, { "CG", "CD1" }, { "CD2", "CE2" }, { "CE1", "CZ" } }); +ResidueData DAData( + "DA", + // Atoms + { "OP3", "P", "OP1", "OP2", "O5'", "C5'", "C4'", "O4'", "C3'", + "O3'", "C2'", "C1'", "N9", "C8", "N7", "C5", "C6", "N6", + "N1", "C2", "N3", "C4", "HOP3", "HOP2", "H5'", "H5''", "H4'", + "H3'", "HO3'", "H2'", "H2''", "H1'", "H8", "H61", "H62", "H2" }, + // Single Bonds + { { "OP3", "P" }, { "OP3", "HOP3" }, { "P", "OP2" }, { "P", "O5'" }, + { "OP2", "HOP2" }, { "O5'", "C5'" }, { "C5'", "C4'" }, { "C5'", "H5'" }, + { "C5'", "H5''" }, { "C4'", "O4'" }, { "C4'", "C3'" }, { "C4'", "H4'" }, + { "O4'", "C1'" }, { "C3'", "O3'" }, { "C3'", "C2'" }, { "C3'", "H3'" }, + { "O3'", "HO3'" }, { "C2'", "C1'" }, { "C2'", "H2'" }, { "C2'", "H2''" }, + { "C1'", "N9" }, { "C1'", "H1'" }, { "N9", "C8" }, { "N9", "C4" }, + { "C8", "H8" }, { "N7", "C5" }, { "C5", "C6" }, { "C6", "N6" }, + { "N6", "H61" }, { "N6", "H62" }, { "N1", "C2" }, { "C2", "H2" }, + { "N3", "C4" } }, + // Double Bonds + { { "P", "OP1" }, + { "C8", "N7" }, + { "C5", "C4" }, + { "C6", "N1" }, + { "C2", "N3" } }); +ResidueData DCData( + "DC", + // Atoms + { "OP3", "P", "OP1", "OP2", "O5'", "C5'", "C4'", "O4'", "C3'", + "O3'", "C2'", "C1'", "N1", "C2", "O2", "N3", "C4", "N4", + "C5", "C6", "HOP3", "HOP2", "H5'", "H5''", "H4'", "H3'", "HO3'", + "H2'", "H2''", "H1'", "H41", "H42", "H5", "H6" }, + // Single Bonds + { { "OP3", "P" }, { "OP3", "HOP3" }, { "P", "OP2" }, { "P", "O5'" }, + { "OP2", "HOP2" }, { "O5'", "C5'" }, { "C5'", "C4'" }, { "C5'", "H5'" }, + { "C5'", "H5''" }, { "C4'", "O4'" }, { "C4'", "C3'" }, { "C4'", "H4'" }, + { "O4'", "C1'" }, { "C3'", "O3'" }, { "C3'", "C2'" }, { "C3'", "H3'" }, + { "O3'", "HO3'" }, { "C2'", "C1'" }, { "C2'", "H2'" }, { "C2'", "H2''" }, + { "C1'", "N1" }, { "C1'", "H1'" }, { "N1", "C2" }, { "N1", "C6" }, + { "C2", "N3" }, { "C4", "N4" }, { "C4", "C5" }, { "N4", "H41" }, + { "N4", "H42" }, { "C5", "H5" }, { "C6", "H6" } }, + // Double Bonds + { { "P", "OP1" }, { "C2", "O2" }, { "N3", "C4" }, { "C5", "C6" } }); +ResidueData DGData( + "DG", + // Atoms + { "OP3", "P", "OP1", "OP2", "O5'", "C5'", "C4'", "O4'", "C3'", "O3'", + "C2'", "C1'", "N9", "C8", "N7", "C5", "C6", "O6", "N1", "C2", + "N2", "N3", "C4", "HOP3", "HOP2", "H5'", "H5''", "H4'", "H3'", "HO3'", + "H2'", "H2''", "H1'", "H8", "H1", "H21", "H22" }, + // Single Bonds + { { "OP3", "P" }, { "OP3", "HOP3" }, { "P", "OP2" }, { "P", "O5'" }, + { "OP2", "HOP2" }, { "O5'", "C5'" }, { "C5'", "C4'" }, { "C5'", "H5'" }, + { "C5'", "H5''" }, { "C4'", "O4'" }, { "C4'", "C3'" }, { "C4'", "H4'" }, + { "O4'", "C1'" }, { "C3'", "O3'" }, { "C3'", "C2'" }, { "C3'", "H3'" }, + { "O3'", "HO3'" }, { "C2'", "C1'" }, { "C2'", "H2'" }, { "C2'", "H2''" }, + { "C1'", "N9" }, { "C1'", "H1'" }, { "N9", "C8" }, { "N9", "C4" }, + { "C8", "H8" }, { "N7", "C5" }, { "C5", "C6" }, { "C6", "N1" }, + { "N1", "C2" }, { "N1", "H1" }, { "C2", "N2" }, { "N2", "H21" }, + { "N2", "H22" }, { "N3", "C4" } }, + // Double Bonds + { { "P", "OP1" }, + { "C8", "N7" }, + { "C5", "C4" }, + { "C6", "O6" }, + { "C2", "N3" } }); +ResidueData DTData( + "DT", + // Atoms + { "OP3", "P", "OP1", "OP2", "O5'", "C5'", "C4'", "O4'", "C3'", + "O3'", "C2'", "C1'", "N1", "C2", "O2", "N3", "C4", "O4", + "C5", "C7", "C6", "HOP3", "HOP2", "H5'", "H5''", "H4'", "H3'", + "HO3'", "H2'", "H2''", "H1'", "H3", "H71", "H72", "H73", "H6" }, + // Single Bonds + { { "OP3", "P" }, { "OP3", "HOP3" }, { "P", "OP2" }, { "P", "O5'" }, + { "OP2", "HOP2" }, { "O5'", "C5'" }, { "C5'", "C4'" }, { "C5'", "H5'" }, + { "C5'", "H5''" }, { "C4'", "O4'" }, { "C4'", "C3'" }, { "C4'", "H4'" }, + { "O4'", "C1'" }, { "C3'", "O3'" }, { "C3'", "C2'" }, { "C3'", "H3'" }, + { "O3'", "HO3'" }, { "C2'", "C1'" }, { "C2'", "H2'" }, { "C2'", "H2''" }, + { "C1'", "N1" }, { "C1'", "H1'" }, { "N1", "C2" }, { "N1", "C6" }, + { "C2", "N3" }, { "N3", "C4" }, { "N3", "H3" }, { "C4", "C5" }, + { "C5", "C7" }, { "C7", "H71" }, { "C7", "H72" }, { "C7", "H73" }, + { "C6", "H6" } }, + // Double Bonds + { { "P", "OP1" }, { "C2", "O2" }, { "C4", "O4" }, { "C5", "C6" } }); +ResidueData DIData( + "DI", + // Atoms + { "OP3", "P", "OP1", "OP2", "O5'", "C5'", "C4'", "O4'", "C3'", + "O3'", "C2'", "C1'", "N9", "C8", "N7", "C5", "C6", "O6", + "N1", "C2", "N3", "C4", "HOP3", "HOP2", "H5'", "H5''", "H4'", + "H3'", "HO3'", "H2'", "H2''", "H1'", "H8", "H1", "H2" }, + // Single Bonds + { { "OP3", "P" }, { "OP3", "HOP3" }, { "P", "OP2" }, { "P", "O5'" }, + { "OP2", "HOP2" }, { "O5'", "C5'" }, { "C5'", "C4'" }, { "C5'", "H5'" }, + { "C5'", "H5''" }, { "C4'", "O4'" }, { "C4'", "C3'" }, { "C4'", "H4'" }, + { "O4'", "C1'" }, { "C3'", "O3'" }, { "C3'", "C2'" }, { "C3'", "H3'" }, + { "O3'", "HO3'" }, { "C2'", "C1'" }, { "C2'", "H2'" }, { "C2'", "H2''" }, + { "C1'", "N9" }, { "C1'", "H1'" }, { "N9", "C8" }, { "N9", "C4" }, + { "C8", "H8" }, { "N7", "C5" }, { "C5", "C6" }, { "C6", "N1" }, + { "N1", "C2" }, { "N1", "H1" }, { "C2", "H2" }, { "N3", "C4" } }, + // Double Bonds + { { "P", "OP1" }, + { "C8", "N7" }, + { "C5", "C4" }, + { "C6", "O6" }, + { "C2", "N3" } }); +ResidueData AData( + "A", + // Atoms + { "OP3", "P", "OP1", "OP2", "O5'", "C5'", "C4'", "O4'", "C3'", "O3'", + "C2'", "O2'", "C1'", "N9", "C8", "N7", "C5", "C6", "N6", "N1", + "C2", "N3", "C4", "HOP3", "HOP2", "H5'", "H5''", "H4'", "H3'", "HO3'", + "H2'", "HO2'", "H1'", "H8", "H61", "H62", "H2" }, + // Single Bonds + { { "OP3", "P" }, { "OP3", "HOP3" }, { "P", "OP2" }, { "P", "O5'" }, + { "OP2", "HOP2" }, { "O5'", "C5'" }, { "C5'", "C4'" }, { "C5'", "H5'" }, + { "C5'", "H5''" }, { "C4'", "O4'" }, { "C4'", "C3'" }, { "C4'", "H4'" }, + { "O4'", "C1'" }, { "C3'", "O3'" }, { "C3'", "C2'" }, { "C3'", "H3'" }, + { "O3'", "HO3'" }, { "C2'", "O2'" }, { "C2'", "C1'" }, { "C2'", "H2'" }, + { "O2'", "HO2'" }, { "C1'", "N9" }, { "C1'", "H1'" }, { "N9", "C8" }, + { "N9", "C4" }, { "C8", "H8" }, { "N7", "C5" }, { "C5", "C6" }, + { "C6", "N6" }, { "N6", "H61" }, { "N6", "H62" }, { "N1", "C2" }, + { "C2", "H2" }, { "N3", "C4" } }, + // Double Bonds + { { "P", "OP1" }, + { "C8", "N7" }, + { "C5", "C4" }, + { "C6", "N1" }, + { "C2", "N3" } }); +ResidueData CData( + "C", + // Atoms + { "OP3", "P", "OP1", "OP2", "O5'", "C5'", "C4'", "O4'", "C3'", + "O3'", "C2'", "O2'", "C1'", "N1", "C2", "O2", "N3", "C4", + "N4", "C5", "C6", "HOP3", "HOP2", "H5'", "H5''", "H4'", "H3'", + "HO3'", "H2'", "HO2'", "H1'", "H41", "H42", "H5", "H6" }, + // Single Bonds + { { "OP3", "P" }, { "OP3", "HOP3" }, { "P", "OP2" }, { "P", "O5'" }, + { "OP2", "HOP2" }, { "O5'", "C5'" }, { "C5'", "C4'" }, { "C5'", "H5'" }, + { "C5'", "H5''" }, { "C4'", "O4'" }, { "C4'", "C3'" }, { "C4'", "H4'" }, + { "O4'", "C1'" }, { "C3'", "O3'" }, { "C3'", "C2'" }, { "C3'", "H3'" }, + { "O3'", "HO3'" }, { "C2'", "O2'" }, { "C2'", "C1'" }, { "C2'", "H2'" }, + { "O2'", "HO2'" }, { "C1'", "N1" }, { "C1'", "H1'" }, { "N1", "C2" }, + { "N1", "C6" }, { "C2", "N3" }, { "C4", "N4" }, { "C4", "C5" }, + { "N4", "H41" }, { "N4", "H42" }, { "C5", "H5" }, { "C6", "H6" } }, + // Double Bonds + { { "P", "OP1" }, { "C2", "O2" }, { "N3", "C4" }, { "C5", "C6" } }); +ResidueData GData( + "G", + // Atoms + { "OP3", "P", "OP1", "OP2", "O5'", "C5'", "C4'", "O4'", "C3'", "O3'", + "C2'", "O2'", "C1'", "N9", "C8", "N7", "C5", "C6", "O6", "N1", + "C2", "N2", "N3", "C4", "HOP3", "HOP2", "H5'", "H5''", "H4'", "H3'", + "HO3'", "H2'", "HO2'", "H1'", "H8", "H1", "H21", "H22" }, + // Single Bonds + { { "OP3", "P" }, { "OP3", "HOP3" }, { "P", "OP2" }, { "P", "O5'" }, + { "OP2", "HOP2" }, { "O5'", "C5'" }, { "C5'", "C4'" }, { "C5'", "H5'" }, + { "C5'", "H5''" }, { "C4'", "O4'" }, { "C4'", "C3'" }, { "C4'", "H4'" }, + { "O4'", "C1'" }, { "C3'", "O3'" }, { "C3'", "C2'" }, { "C3'", "H3'" }, + { "O3'", "HO3'" }, { "C2'", "O2'" }, { "C2'", "C1'" }, { "C2'", "H2'" }, + { "O2'", "HO2'" }, { "C1'", "N9" }, { "C1'", "H1'" }, { "N9", "C8" }, + { "N9", "C4" }, { "C8", "H8" }, { "N7", "C5" }, { "C5", "C6" }, + { "C6", "N1" }, { "N1", "C2" }, { "N1", "H1" }, { "C2", "N2" }, + { "N2", "H21" }, { "N2", "H22" }, { "N3", "C4" } }, + // Double Bonds + { { "P", "OP1" }, + { "C8", "N7" }, + { "C5", "C4" }, + { "C6", "O6" }, + { "C2", "N3" } }); +ResidueData UData( + "U", + // Atoms + { "OP3", "P", "OP1", "OP2", "O5'", "C5'", "C4'", "O4'", "C3'", + "O3'", "C2'", "O2'", "C1'", "N1", "C2", "O2", "N3", "C4", + "O4", "C5", "C6", "HOP3", "HOP2", "H5'", "H5''", "H4'", "H3'", + "HO3'", "H2'", "HO2'", "H1'", "H3", "H5", "H6" }, + // Single Bonds + { { "OP3", "P" }, { "OP3", "HOP3" }, { "P", "OP2" }, { "P", "O5'" }, + { "OP2", "HOP2" }, { "O5'", "C5'" }, { "C5'", "C4'" }, { "C5'", "H5'" }, + { "C5'", "H5''" }, { "C4'", "O4'" }, { "C4'", "C3'" }, { "C4'", "H4'" }, + { "O4'", "C1'" }, { "C3'", "O3'" }, { "C3'", "C2'" }, { "C3'", "H3'" }, + { "O3'", "HO3'" }, { "C2'", "O2'" }, { "C2'", "C1'" }, { "C2'", "H2'" }, + { "O2'", "HO2'" }, { "C1'", "N1" }, { "C1'", "H1'" }, { "N1", "C2" }, + { "N1", "C6" }, { "C2", "N3" }, { "N3", "C4" }, { "N3", "H3" }, + { "C4", "C5" }, { "C5", "H5" }, { "C6", "H6" } }, + // Double Bonds + { { "P", "OP1" }, { "C2", "O2" }, { "C4", "O4" }, { "C5", "C6" } }); +ResidueData IData( + "I", + // Atoms + { "OP3", "P", "OP1", "OP2", "O5'", "C5'", "C4'", "O4'", "C3'", + "O3'", "C2'", "O2'", "C1'", "N9", "C8", "N7", "C5", "C6", + "O6", "N1", "C2", "N3", "C4", "HOP3", "HOP2", "H5'", "H5''", + "H4'", "H3'", "HO3'", "H2'", "HO2'", "H1'", "H8", "H1", "H2" }, + // Single Bonds + { { "OP3", "P" }, { "OP3", "HOP3" }, { "P", "OP2" }, { "P", "O5'" }, + { "OP2", "HOP2" }, { "O5'", "C5'" }, { "C5'", "C4'" }, { "C5'", "H5'" }, + { "C5'", "H5''" }, { "C4'", "O4'" }, { "C4'", "C3'" }, { "C4'", "H4'" }, + { "O4'", "C1'" }, { "C3'", "O3'" }, { "C3'", "C2'" }, { "C3'", "H3'" }, + { "O3'", "HO3'" }, { "C2'", "O2'" }, { "C2'", "C1'" }, { "C2'", "H2'" }, + { "O2'", "HO2'" }, { "C1'", "N9" }, { "C1'", "H1'" }, { "N9", "C8" }, + { "N9", "C4" }, { "C8", "H8" }, { "N7", "C5" }, { "C5", "C6" }, + { "C6", "N1" }, { "N1", "C2" }, { "N1", "H1" }, { "C2", "H2" }, + { "N3", "C4" } }, + // Double Bonds + { { "P", "OP1" }, + { "C8", "N7" }, + { "C5", "C4" }, + { "C6", "O6" }, + { "C2", "N3" } }); +ResidueData HEMData( + "HEM", + // Atoms + { "CHA", "CHB", "CHC", "CHD", "C1A", "C2A", "C3A", "C4A", "CMA", + "CAA", "CBA", "CGA", "O1A", "O2A", "C1B", "C2B", "C3B", "C4B", + "CMB", "CAB", "CBB", "C1C", "C2C", "C3C", "C4C", "CMC", "CAC", + "CBC", "C1D", "C2D", "C3D", "C4D", "CMD", "CAD", "CBD", "CGD", + "O1D", "O2D", "NA", "NB", "NC", "ND", "FE", "HHB", "HHC", + "HHD", "HMA", "HMAA", "HMAB", "HAA", "HAAA", "HBA", "HBAA", "HMB", + "HMBA", "HMBB", "HAB", "HBB", "HBBA", "HMC", "HMCA", "HMCB", "HAC", + "HBC", "HBCA", "HMD", "HMDA", "HMDB", "HAD", "HADA", "HBD", "HBDA", + "H2A", "H2D", "HHA" }, + // Single Bonds + { { "CHA", "C1A" }, { "CHA", "HHA" }, { "CHB", "C4A" }, { "CHB", "HHB" }, + { "CHC", "C4B" }, { "CHC", "HHC" }, { "CHD", "C1D" }, { "CHD", "HHD" }, + { "C1A", "NA" }, { "C2A", "C3A" }, { "C2A", "CAA" }, { "C3A", "CMA" }, + { "C4A", "NA" }, { "CMA", "HMA" }, { "CMA", "HMAA" }, { "CMA", "HMAB" }, + { "CAA", "CBA" }, { "CAA", "HAA" }, { "CAA", "HAAA" }, { "CBA", "CGA" }, + { "CBA", "HBA" }, { "CBA", "HBAA" }, { "CGA", "O2A" }, { "O2A", "H2A" }, + { "C1B", "C2B" }, { "C1B", "NB" }, { "C2B", "CMB" }, { "C3B", "C4B" }, + { "C3B", "CAB" }, { "CMB", "HMB" }, { "CMB", "HMBA" }, { "CMB", "HMBB" }, + { "CAB", "HAB" }, { "CBB", "HBB" }, { "CBB", "HBBA" }, { "C1C", "C2C" }, + { "C1C", "NC" }, { "C2C", "CMC" }, { "C3C", "C4C" }, { "C3C", "CAC" }, + { "C4C", "NC" }, { "CMC", "HMC" }, { "CMC", "HMCA" }, { "CMC", "HMCB" }, + { "CAC", "HAC" }, { "CBC", "HBC" }, { "CBC", "HBCA" }, { "C1D", "C2D" }, + { "C2D", "CMD" }, { "C3D", "C4D" }, { "C3D", "CAD" }, { "C4D", "ND" }, + { "CMD", "HMD" }, { "CMD", "HMDA" }, { "CMD", "HMDB" }, { "CAD", "CBD" }, + { "CAD", "HAD" }, { "CAD", "HADA" }, { "CBD", "CGD" }, { "CBD", "HBD" }, + { "CBD", "HBDA" }, { "CGD", "O2D" }, { "O2D", "H2D" }, { "FE", "NA" }, + { "FE", "NB" }, { "FE", "NC" }, { "FE", "ND" } }, + // Double Bonds + { { "CHA", "C4D" }, + { "CHB", "C1B" }, + { "CHC", "C1C" }, + { "CHD", "C4C" }, + { "C1A", "C2A" }, + { "C3A", "C4A" }, + { "CGA", "O1A" }, + { "C2B", "C3B" }, + { "C4B", "NB" }, + { "CAB", "CBB" }, + { "C2C", "C3C" }, + { "CAC", "CBC" }, + { "C1D", "ND" }, + { "C2D", "C3D" }, + { "CGD", "O1D" } }); +ResidueData HOHData("HOH", // Atoms - { "CA", "N", "CB", "C", "O", "CG", "ND1", "CD2", "NE2", - "CE1" }, + { "O", "H1", "H2" }, // Single Bonds - { { "CA", "N" }, - { "CA", "CB" }, - { "CA", "C" }, - { "CB", "CG" }, - { "CG", "ND1" }, - { "CD2", "NE2" }, - { "CE1", "ND1" }, - { "N", "H" }, - { "ND1", "HD1" } }, + { { "O", "H1" }, { "O", "H2" } }, // Double Bonds - { { "C", "O" }, { "CG", "CD2" }, { "NE2", "CE1" } }); - -ResidueData HIEData("HIE", + {}); +ResidueData SO4Data("SO4", // Atoms - { "CA", "N", "CB", "C", "O", "CG", "ND1", "CD2", "NE2", - "CE1" }, + { "S", "O1", "O2", "O3", "O4" }, // Single Bonds - { { "CA", "N" }, - { "CA", "CB" }, - { "CA", "C" }, - { "CB", "CG" }, - { "CG", "ND1" }, - { "CD2", "NE2" }, - { "NE2", "CE1" }, - { "CE1", "ND1" }, - { "N", "H" }, - { "NE2", "HE2" } }, + { { "S", "O3" }, { "S", "O4" } }, // Double Bonds - { { "C", "O" }, { "CG", "CD2" } }); - -ResidueData HIPData("HIP", + { { "S", "O1" }, { "S", "O2" } }); +ResidueData GOLData("GOL", // Atoms - { "CA", "N", "CB", "C", "O", "CG", "ND1", "CD2", "NE2", - "CE1" }, + { "C1", "O1", "C2", "O2", "C3", "O3", "H11", "H12", "HO1", + "H2", "HO2", "H31", "H32", "HO3" }, // Single Bonds - { { "CA", "N" }, - { "CA", "CB" }, - { "CA", "C" }, - { "CB", "CG" }, - { "CG", "ND1" }, - { "CD2", "NE2" }, - { "NE2", "CE1" }, - { "CE1", "ND1" }, - { "N", "H" }, - { "ND1", "HD1" }, - { "NE2", "HE2" } }, + { { "C1", "O1" }, + { "C1", "C2" }, + { "C1", "H11" }, + { "C1", "H12" }, + { "O1", "HO1" }, + { "C2", "O2" }, + { "C2", "C3" }, + { "C2", "H2" }, + { "O2", "HO2" }, + { "C3", "O3" }, + { "C3", "H31" }, + { "C3", "H32" }, + { "O3", "HO3" } }, // Double Bonds - { { "C", "O" }, { "CG", "CD2" } }); - -ResidueData HISData("HIS", + {}); +ResidueData MSEData("MSE", // Atoms - { "CA", "N", "CB", "C", "O", "CG", "ND1", "CD2", "NE2", - "CE1" }, + { "N", "CA", "C", "O", "OXT", "CB", "CG", + "SE", "CE", "H", "HN2", "HA", "HXT", "HB2", + "HB3", "HG2", "HG3", "HE1", "HE2", "HE3" }, // Single Bonds - { { "CA", "N" }, - { "CA", "CB" }, + { { "N", "CA" }, + { "N", "H" }, + { "N", "HN2" }, { "CA", "C" }, + { "CA", "CB" }, + { "CA", "HA" }, + { "C", "OXT" }, + { "OXT", "HXT" }, { "CB", "CG" }, - { "CG", "ND1" }, - { "CD2", "NE2" }, - { "CE1", "ND1" }, - { "N", "H" }, - { "N", "HN" }, - { "HA", "CA" }, - { "HB1", "CB" }, - { "HB2", "CB" }, - { "HD1", "ND1" }, - { "HD2", "CD2" }, - { "HE1", "CE1" }, - { "ND1", "HD1" }, - { "NE2", "HE2" } }, + { "CB", "HB2" }, + { "CB", "HB3" }, + { "CG", "SE" }, + { "CG", "HG2" }, + { "CG", "HG3" }, + { "SE", "CE" }, + { "CE", "HE1" }, + { "CE", "HE2" }, + { "CE", "HE3" } }, // Double Bonds - { { "C", "O" }, { "CG", "CD2" }, { "NE2", "CE1" } }); - -ResidueData ILEData("ILE", + { { "C", "O" } }); +ResidueData EDOData("EDO", // Atoms - { "CA", "N", "CB", "C", "O", "CG2", "CG1", "CD1" }, + { "C1", "O1", "C2", "O2", "H11", "H12", "HO1", "H21", "H22", + "HO2" }, // Single Bonds - { { "CA", "N" }, - { "CA", "CB" }, - { "CA", "C" }, - { "CB", "CG2" }, - { "CB", "CG1" }, - { "CG1", "CD1" }, - { "N", "H" }, - { "N", "HN" }, - { "CA", "HA" }, - { "HB", "CB" }, - { "HG11", "CG1" }, - { "HG12", "CG1" }, - { "HG21", "CG2" }, - { "HG22", "CG2" }, - { "HG23", "CG2" }, - { "HD11", "CD1" }, - { "HD12", "CD1" }, - { "HD13", "CD1" } }, + { { "C1", "O1" }, + { "C1", "C2" }, + { "C1", "H11" }, + { "C1", "H12" }, + { "O1", "HO1" }, + { "C2", "O2" }, + { "C2", "H21" }, + { "C2", "H22" }, + { "O2", "HO2" } }, // Double Bonds - { { "C", "O" } }); - -ResidueData LEUData("LEU", + {}); +ResidueData NAGData( + "NAG", + // Atoms + { "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "N2", "O1", + "O3", "O4", "O5", "O6", "O7", "H1", "H2", "H3", "H4", "H5", + "H61", "H62", "H81", "H82", "H83", "HN2", "HO1", "HO3", "HO4", "HO6" }, + // Single Bonds + { { "C1", "C2" }, { "C1", "O1" }, { "C1", "O5" }, { "C1", "H1" }, + { "C2", "C3" }, { "C2", "N2" }, { "C2", "H2" }, { "C3", "C4" }, + { "C3", "O3" }, { "C3", "H3" }, { "C4", "C5" }, { "C4", "O4" }, + { "C4", "H4" }, { "C5", "C6" }, { "C5", "O5" }, { "C5", "H5" }, + { "C6", "O6" }, { "C6", "H61" }, { "C6", "H62" }, { "C7", "C8" }, + { "C7", "N2" }, { "C8", "H81" }, { "C8", "H82" }, { "C8", "H83" }, + { "N2", "HN2" }, { "O1", "HO1" }, { "O3", "HO3" }, { "O4", "HO4" }, + { "O6", "HO6" } }, + // Double Bonds + { { "C7", "O7" } }); +ResidueData PO4Data("PO4", // Atoms - { "CA", "N", "CB", "C", "O", "CG", "CD1", "CD2" }, + { "P", "O1", "O2", "O3", "O4" }, // Single Bonds - { { "CA", "N" }, - { "CA", "CB" }, - { "CA", "C" }, - { "CB", "CG" }, - { "CG", "CD1" }, - { "CG", "CD2" }, - { "N", "H" }, - { "N", "HN" }, - { "HA", "CA" }, - { "HB1", "CB" }, - { "HB2", "CB" }, - { "HD11", "CD1" }, - { "HD12", "CD1" }, - { "HD13", "CD1" }, - { "HD21", "CD2" }, - { "HD22", "CD2" }, - { "HD23", "CD2" }, - { "HG", "CG" } }, + { { "P", "O2" }, { "P", "O3" }, { "P", "O4" } }, // Double Bonds - { { "C", "O" } }); - -ResidueData LYSData("LYS", + { { "P", "O1" } }); +ResidueData ACTData("ACT", // Atoms - { "CA", "N", "CB", "C", "O", "CG", "CD", "CE", "NZ" }, + { "C", "O", "OXT", "CH3", "H1", "H2", "H3" }, // Single Bonds - { { "CA", "N" }, { "CA", "CB" }, { "CA", "C" }, - { "CB", "CG" }, { "CG", "CD" }, { "CD", "CE" }, - { "CE", "NZ" }, { "N", "H" }, { "N", "HN" }, - { "HA", "CA" }, { "HB1", "CB" }, { "HB2", "CB" }, - { "HD1", "CD" }, { "HD2", "CD" }, { "HG1", "CG" }, - { "HG2", "CG" }, { "HE1", "CE" }, { "HE2", "CE" }, - { "NZ", "HZ3" }, { "NZ", "HZ3" }, { "NZ", "HZ2" }, - { "NZ", "HZ2" }, { "NZ", "HZ1" }, { "NZ", "HZ1" } }, + { { "C", "OXT" }, + { "C", "CH3" }, + { "CH3", "H1" }, + { "CH3", "H2" }, + { "CH3", "H3" } }, // Double Bonds { { "C", "O" } }); - -ResidueData LYZData("LYZ", +ResidueData PEGData("PEG", // Atoms - { "CA", "N", "CB", "C", "O", "CG", "CD", "CE", "NZ" }, + { "C1", "O1", "C2", "O2", "C3", "C4", "O4", "H11", "H12", + "HO1", "H21", "H22", "H31", "H32", "H41", "H42", "HO4" }, // Single Bonds - { { "CA", "N" }, - { "CA", "CB" }, - { "CA", "C" }, - { "CB", "CG" }, - { "CG", "CD" }, - { "CD", "CE" }, - { "CE", "NZ" }, - { "N", "H" }, - { "NZ", "HZ2" }, - { "NZ", "HZ1" } }, + { { "C1", "O1" }, + { "C1", "C2" }, + { "C1", "H11" }, + { "C1", "H12" }, + { "O1", "HO1" }, + { "C2", "O2" }, + { "C2", "H21" }, + { "C2", "H22" }, + { "O2", "C3" }, + { "C3", "C4" }, + { "C3", "H31" }, + { "C3", "H32" }, + { "C4", "O4" }, + { "C4", "H41" }, + { "C4", "H42" }, + { "O4", "HO4" } }, // Double Bonds - { { "C", "O" } }); - -ResidueData METData("MET", + {}); +ResidueData MANData("MAN", // Atoms - { "CA", "N", "CB", "C", "O", "CG", "SD", "CE" }, + { "C1", "C2", "C3", "C4", "C5", "C6", "O1", "O2", + "O3", "O4", "O5", "O6", "H1", "H2", "H3", "H4", + "H5", "H61", "H62", "HO1", "HO2", "HO3", "HO4", "HO6" }, // Single Bonds - { { "CA", "N" }, - { "CA", "CB" }, - { "CA", "C" }, - { "CB", "CG" }, - { "CG", "SD" }, - { "SD", "CE" }, - { "N", "H" }, - { "N", "HN" }, - { "HA", "CA" }, - { "HB1", "CB" }, - { "HB2", "CB" }, - { "HG1", "CG" }, - { "HG2", "CG" }, - { "HE1", "CE" }, - { "HE2", "CE" }, - { "HE3", "CE" } }, + { { "C1", "C2" }, { "C1", "O1" }, { "C1", "O5" }, + { "C1", "H1" }, { "C2", "C3" }, { "C2", "O2" }, + { "C2", "H2" }, { "C3", "C4" }, { "C3", "O3" }, + { "C3", "H3" }, { "C4", "C5" }, { "C4", "O4" }, + { "C4", "H4" }, { "C5", "C6" }, { "C5", "O5" }, + { "C5", "H5" }, { "C6", "O6" }, { "C6", "H61" }, + { "C6", "H62" }, { "O1", "HO1" }, { "O2", "HO2" }, + { "O3", "HO3" }, { "O4", "HO4" }, { "O6", "HO6" } }, // Double Bonds - { { "C", "O" } }); - -ResidueData PHEData( - "PHE", + {}); +ResidueData BMAData("BMA", + // Atoms + { "C1", "C2", "C3", "C4", "C5", "C6", "O1", "O2", + "O3", "O4", "O5", "O6", "H1", "H2", "H3", "H4", + "H5", "H61", "H62", "HO1", "HO2", "HO3", "HO4", "HO6" }, + // Single Bonds + { { "C1", "C2" }, { "C1", "O1" }, { "C1", "O5" }, + { "C1", "H1" }, { "C2", "C3" }, { "C2", "O2" }, + { "C2", "H2" }, { "C3", "C4" }, { "C3", "O3" }, + { "C3", "H3" }, { "C4", "C5" }, { "C4", "O4" }, + { "C4", "H4" }, { "C5", "C6" }, { "C5", "O5" }, + { "C5", "H5" }, { "C6", "O6" }, { "C6", "H61" }, + { "C6", "H62" }, { "O1", "HO1" }, { "O2", "HO2" }, + { "O3", "HO3" }, { "O4", "HO4" }, { "O6", "HO6" } }, + // Double Bonds + {}); +ResidueData FADData( + "FAD", // Atoms - { "CA", "N", "CB", "C", "O", "CG", "CD1", "CD2", "CE2", "CZ", "CE1" }, + { "PA", "O1A", "O2A", "O5B", "C5B", "C4B", "O4B", "C3B", "O3B", + "C2B", "O2B", "C1B", "N9A", "C8A", "N7A", "C5A", "C6A", "N6A", + "N1A", "C2A", "N3A", "C4A", "N1", "C2", "O2", "N3", "C4", + "O4", "C4X", "N5", "C5X", "C6", "C7", "C7M", "C8", "C8M", + "C9", "C9A", "N10", "C10", "C1'", "C2'", "O2'", "C3'", "O3'", + "C4'", "O4'", "C5'", "O5'", "P", "O1P", "O2P", "O3P", "HOA2", + "H51A", "H52A", "H4B", "H3B", "HO3A", "H2B", "HO2A", "H1B", "H8A", + "H61A", "H62A", "H2A", "HN3", "H6", "HM71", "HM72", "HM73", "HM81", + "HM82", "HM83", "H9", "H1'1", "H1'2", "H2'", "HO2'", "H3'", "HO3'", + "H4'", "HO4'", "H5'1", "H5'2", "HOP2" }, // Single Bonds - { { "CA", "N" }, - { "CA", "CB" }, - { "CA", "C" }, - { "CB", "CG" }, - { "CG", "CD1" }, - { "CD2", "CE2" }, - { "CZ", "CE1" }, - { "N", "H" }, - { "N", "HN" }, - { "HA", "CA" }, - { "HB1", "CB" }, - { "HB2", "CB" }, - { "HD1", "CD1" }, - { "HD2", "CD2" }, - { "HE1", "CE1" }, - { "HE2", "CE2" }, - { "HZ", "CZ" } }, + { { "PA", "O2A" }, { "PA", "O5B" }, { "PA", "O3P" }, { "O2A", "HOA2" }, + { "O5B", "C5B" }, { "C5B", "C4B" }, { "C5B", "H51A" }, { "C5B", "H52A" }, + { "C4B", "O4B" }, { "C4B", "C3B" }, { "C4B", "H4B" }, { "O4B", "C1B" }, + { "C3B", "O3B" }, { "C3B", "C2B" }, { "C3B", "H3B" }, { "O3B", "HO3A" }, + { "C2B", "O2B" }, { "C2B", "C1B" }, { "C2B", "H2B" }, { "O2B", "HO2A" }, + { "C1B", "N9A" }, { "C1B", "H1B" }, { "N9A", "C8A" }, { "N9A", "C4A" }, + { "C8A", "H8A" }, { "N7A", "C5A" }, { "C5A", "C6A" }, { "C6A", "N6A" }, + { "N6A", "H61A" }, { "N6A", "H62A" }, { "N1A", "C2A" }, { "C2A", "H2A" }, + { "N3A", "C4A" }, { "N1", "C2" }, { "C2", "N3" }, { "N3", "C4" }, + { "N3", "HN3" }, { "C4", "C4X" }, { "C4X", "C10" }, { "N5", "C5X" }, + { "C5X", "C9A" }, { "C6", "C7" }, { "C6", "H6" }, { "C7", "C7M" }, + { "C7M", "HM71" }, { "C7M", "HM72" }, { "C7M", "HM73" }, { "C8", "C8M" }, + { "C8", "C9" }, { "C8M", "HM81" }, { "C8M", "HM82" }, { "C8M", "HM83" }, + { "C9", "H9" }, { "C9A", "N10" }, { "N10", "C10" }, { "N10", "C1'" }, + { "C1'", "C2'" }, { "C1'", "H1'1" }, { "C1'", "H1'2" }, { "C2'", "O2'" }, + { "C2'", "C3'" }, { "C2'", "H2'" }, { "O2'", "HO2'" }, { "C3'", "O3'" }, + { "C3'", "C4'" }, { "C3'", "H3'" }, { "O3'", "HO3'" }, { "C4'", "O4'" }, + { "C4'", "C5'" }, { "C4'", "H4'" }, { "O4'", "HO4'" }, { "C5'", "O5'" }, + { "C5'", "H5'1" }, { "C5'", "H5'2" }, { "O5'", "P" }, { "P", "O2P" }, + { "P", "O3P" }, { "O2P", "HOP2" } }, // Double Bonds - { { "C", "O" }, { "CG", "CD2" }, { "CE2", "CZ" }, { "CE1", "CD1" } }); - -ResidueData PROData("PRO", + { { "PA", "O1A" }, + { "C8A", "N7A" }, + { "C5A", "C4A" }, + { "C6A", "N1A" }, + { "C2A", "N3A" }, + { "N1", "C10" }, + { "C2", "O2" }, + { "C4", "O4" }, + { "C4X", "N5" }, + { "C5X", "C6" }, + { "C7", "C8" }, + { "C9", "C9A" }, + { "P", "O1P" } }); +ResidueData ADPData( + "ADP", + // Atoms + { "PB", "O1B", "O2B", "O3B", "PA", "O1A", "O2A", "O3A", "O5'", + "C5'", "C4'", "O4'", "C3'", "O3'", "C2'", "O2'", "C1'", "N9", + "C8", "N7", "C5", "C6", "N6", "N1", "C2", "N3", "C4", + "HOB2", "HOB3", "HOA2", "H5'1", "H5'2", "H4'", "H3'", "HO3'", "H2'", + "HO2'", "H1'", "H8", "HN61", "HN62", "H2" }, + // Single Bonds + { { "PB", "O2B" }, { "PB", "O3B" }, { "PB", "O3A" }, { "O2B", "HOB2" }, + { "O3B", "HOB3" }, { "PA", "O2A" }, { "PA", "O3A" }, { "PA", "O5'" }, + { "O2A", "HOA2" }, { "O5'", "C5'" }, { "C5'", "C4'" }, { "C5'", "H5'1" }, + { "C5'", "H5'2" }, { "C4'", "O4'" }, { "C4'", "C3'" }, { "C4'", "H4'" }, + { "O4'", "C1'" }, { "C3'", "O3'" }, { "C3'", "C2'" }, { "C3'", "H3'" }, + { "O3'", "HO3'" }, { "C2'", "O2'" }, { "C2'", "C1'" }, { "C2'", "H2'" }, + { "O2'", "HO2'" }, { "C1'", "N9" }, { "C1'", "H1'" }, { "N9", "C8" }, + { "N9", "C4" }, { "C8", "H8" }, { "N7", "C5" }, { "C5", "C6" }, + { "C6", "N6" }, { "N6", "HN61" }, { "N6", "HN62" }, { "N1", "C2" }, + { "C2", "H2" }, { "N3", "C4" } }, + // Double Bonds + { { "PB", "O1B" }, + { "PA", "O1A" }, + { "C8", "N7" }, + { "C5", "C4" }, + { "C6", "N1" }, + { "C2", "N3" } }); +ResidueData DMSData("DMS", // Atoms - { "CA", "C", "CB", "N", "CD", "CG", "O" }, + { "S", "O", "C1", "C2", "H11", "H12", "H13", "H21", "H22", + "H23" }, // Single Bonds - { { "CA", "C" }, - { "CA", "CB" }, - { "CA", "N" }, - { "N", "CD" }, - { "CD", "CG" }, - { "CG", "CB" }, - { "HB1", "CB" }, - { "HB2", "CB" }, - { "HG1", "CG" }, - { "HG2", "CG" }, - { "HD1", "CD" }, - { "HD2", "CD" }, - { "HA", "CA" }, - { "HN", "N" } }, + { { "S", "C1" }, + { "S", "C2" }, + { "C1", "H11" }, + { "C1", "H12" }, + { "C1", "H13" }, + { "C2", "H21" }, + { "C2", "H22" }, + { "C2", "H23" } }, // Double Bonds - { { "C", "O" } }); - -ResidueData PSEData("PSE", + { { "S", "O" } }); +ResidueData ACEData("ACE", // Atoms - { "CA", "N", "CB", "C", "O", "OG", "PD", "OE2", "OE3", - "OE1" }, + { "C", "O", "CH3", "H", "H1", "H2", "H3" }, // Single Bonds - { { "CA", "N" }, - { "CA", "CB" }, - { "CA", "C" }, - { "CB", "OG" }, - { "OG", "PD" }, - { "PD", "OE2" }, - { "PD", "OE3" }, - { "PD", "OE1" }, - { "N", "H" } }, + { { "C", "CH3" }, + { "C", "H" }, + { "CH3", "H1" }, + { "CH3", "H2" }, + { "CH3", "H3" } }, // Double Bonds { { "C", "O" } }); - -ResidueData PSMData("PSM", +ResidueData MPDData("MPD", // Atoms - { "CA", "N", "CB", "C", "O", "OG", "PD", "OE2", "OE3", - "OE1" }, + { "C1", "C2", "O2", "CM", "C3", "C4", "O4", "C5", + "H11", "H12", "H13", "HO2", "HM1", "HM2", "HM3", "H31", + "H32", "H4", "HO4", "H51", "H52", "H53" }, // Single Bonds - { { "CA", "N" }, - { "CA", "CB" }, - { "CA", "C" }, - { "CB", "OG" }, - { "OG", "PD" }, - { "PD", "OE2" }, - { "PD", "OE3" }, - { "PD", "OE1" }, - { "N", "H" }, - { "OE3", "HE3" } }, + { { "C1", "C2" }, { "C1", "H11" }, { "C1", "H12" }, + { "C1", "H13" }, { "C2", "O2" }, { "C2", "CM" }, + { "C2", "C3" }, { "O2", "HO2" }, { "CM", "HM1" }, + { "CM", "HM2" }, { "CM", "HM3" }, { "C3", "C4" }, + { "C3", "H31" }, { "C3", "H32" }, { "C4", "O4" }, + { "C4", "C5" }, { "C4", "H4" }, { "O4", "HO4" }, + { "C5", "H51" }, { "C5", "H52" }, { "C5", "H53" } }, // Double Bonds - { { "C", "O" } }); - -ResidueData PTMData( - "PTM", + {}); +ResidueData MESData( + "MES", // Atoms - { "CA", "N", "CB", "C", "O", "CG", "CD1", "CD2", "CE2", "CZ", "OH", "CE1", - "PQ", "OI3", "OI2", "OI1" }, + { "O1", "C2", "C3", "N4", "C5", "C6", "C7", "C8", "S", + "O1S", "O2S", "O3S", "H21", "H22", "H31", "H32", "HN4", "H51", + "H52", "H61", "H62", "H71", "H72", "H81", "H82" }, // Single Bonds - { { "CA", "N" }, - { "CA", "CB" }, - { "CA", "C" }, - { "CB", "CG" }, - { "CG", "CD2" }, - { "CE2", "CZ" }, - { "CZ", "OH" }, - { "CE1", "CD1" }, - { "OH", "PQ" }, - { "PQ", "OI3" }, - { "PQ", "OI2" }, - { "PQ", "OI1" }, - { "N", "H" }, - { "OI2", "HI2" } }, + { { "O1", "C2" }, { "O1", "C6" }, { "C2", "C3" }, { "C2", "H21" }, + { "C2", "H22" }, { "C3", "N4" }, { "C3", "H31" }, { "C3", "H32" }, + { "N4", "C5" }, { "N4", "C7" }, { "N4", "HN4" }, { "C5", "C6" }, + { "C5", "H51" }, { "C5", "H52" }, { "C6", "H61" }, { "C6", "H62" }, + { "C7", "C8" }, { "C7", "H71" }, { "C7", "H72" }, { "C8", "S" }, + { "C8", "H81" }, { "C8", "H82" }, { "S", "O3S" } }, // Double Bonds - { { "C", "O" }, { "CG", "CD1" }, { "CD2", "CE2" }, { "CZ", "CE1" } }); - -ResidueData PTYData( - "PTY", + { { "S", "O1S" }, { "S", "O2S" } }); +ResidueData NADData( + "NAD", // Atoms - { "CA", "N", "CB", "C", "O", "CG", "CD1", "CD2", "CE2", "CZ", "OH", "CE1", - "PQ", "OI3", "OI2", "OI1" }, + { "PA", "O1A", "O2A", "O5B", "C5B", "C4B", "O4B", "C3B", "O3B", + "C2B", "O2B", "C1B", "N9A", "C8A", "N7A", "C5A", "C6A", "N6A", + "N1A", "C2A", "N3A", "C4A", "O3", "PN", "O1N", "O2N", "O5D", + "C5D", "C4D", "O4D", "C3D", "O3D", "C2D", "O2D", "C1D", "N1N", + "C2N", "C3N", "C7N", "O7N", "N7N", "C4N", "C5N", "C6N", "HOA2", + "H51A", "H52A", "H4B", "H3B", "HO3A", "H2B", "HO2A", "H1B", "H8A", + "H61A", "H62A", "H2A", "H51N", "H52N", "H4D", "H3D", "HO3N", "H2D", + "HO2N", "H1D", "H2N", "H71N", "H72N", "H4N", "H5N", "H6N" }, // Single Bonds - { { "CA", "N" }, - { "CA", "CB" }, - { "CA", "C" }, - { "CB", "CG" }, - { "CG", "CD2" }, - { "CE2", "CZ" }, - { "CZ", "OH" }, - { "CE1", "CD1" }, - { "OH", "PQ" }, - { "PQ", "OI3" }, - { "PQ", "OI2" }, - { "PQ", "OI1" }, - { "N", "H" } }, + { { "PA", "O2A" }, { "PA", "O5B" }, { "PA", "O3" }, { "O2A", "HOA2" }, + { "O5B", "C5B" }, { "C5B", "C4B" }, { "C5B", "H51A" }, { "C5B", "H52A" }, + { "C4B", "O4B" }, { "C4B", "C3B" }, { "C4B", "H4B" }, { "O4B", "C1B" }, + { "C3B", "O3B" }, { "C3B", "C2B" }, { "C3B", "H3B" }, { "O3B", "HO3A" }, + { "C2B", "O2B" }, { "C2B", "C1B" }, { "C2B", "H2B" }, { "O2B", "HO2A" }, + { "C1B", "N9A" }, { "C1B", "H1B" }, { "N9A", "C8A" }, { "N9A", "C4A" }, + { "C8A", "H8A" }, { "N7A", "C5A" }, { "C5A", "C6A" }, { "C6A", "N6A" }, + { "N6A", "H61A" }, { "N6A", "H62A" }, { "N1A", "C2A" }, { "C2A", "H2A" }, + { "N3A", "C4A" }, { "O3", "PN" }, { "PN", "O2N" }, { "PN", "O5D" }, + { "O5D", "C5D" }, { "C5D", "C4D" }, { "C5D", "H51N" }, { "C5D", "H52N" }, + { "C4D", "O4D" }, { "C4D", "C3D" }, { "C4D", "H4D" }, { "O4D", "C1D" }, + { "C3D", "O3D" }, { "C3D", "C2D" }, { "C3D", "H3D" }, { "O3D", "HO3N" }, + { "C2D", "O2D" }, { "C2D", "C1D" }, { "C2D", "H2D" }, { "O2D", "HO2N" }, + { "C1D", "N1N" }, { "C1D", "H1D" }, { "N1N", "C2N" }, { "C2N", "H2N" }, + { "C3N", "C7N" }, { "C3N", "C4N" }, { "C7N", "N7N" }, { "N7N", "H71N" }, + { "N7N", "H72N" }, { "C4N", "H4N" }, { "C5N", "C6N" }, { "C5N", "H5N" }, + { "C6N", "H6N" } }, // Double Bonds - { { "C", "O" }, { "CG", "CD1" }, { "CD2", "CE2" }, { "CZ", "CE1" } }); - -ResidueData SERData("SER", + { { "PA", "O1A" }, + { "C8A", "N7A" }, + { "C5A", "C4A" }, + { "C6A", "N1A" }, + { "C2A", "N3A" }, + { "PN", "O1N" }, + { "N1N", "C6N" }, + { "C2N", "C3N" }, + { "C7N", "O7N" }, + { "C4N", "C5N" } }); +ResidueData NAPData( + "NAP", + // Atoms + { "PA", "O1A", "O2A", "O5B", "C5B", "C4B", "O4B", "C3B", "O3B", + "C2B", "O2B", "C1B", "N9A", "C8A", "N7A", "C5A", "C6A", "N6A", + "N1A", "C2A", "N3A", "C4A", "O3", "PN", "O1N", "O2N", "O5D", + "C5D", "C4D", "O4D", "C3D", "O3D", "C2D", "O2D", "C1D", "N1N", + "C2N", "C3N", "C7N", "O7N", "N7N", "C4N", "C5N", "C6N", "P2B", + "O1X", "O2X", "O3X", "HOA2", "H51A", "H52A", "H4B", "H3B", "HO3A", + "H2B", "H1B", "H8A", "H61A", "H62A", "H2A", "H51N", "H52N", "H4D", + "H3D", "HO3N", "H2D", "HO2N", "H1D", "H2N", "H71N", "H72N", "H4N", + "H5N", "H6N", "HOP2", "HOP3" }, + // Single Bonds + { { "PA", "O2A" }, { "PA", "O5B" }, { "PA", "O3" }, { "O2A", "HOA2" }, + { "O5B", "C5B" }, { "C5B", "C4B" }, { "C5B", "H51A" }, { "C5B", "H52A" }, + { "C4B", "O4B" }, { "C4B", "C3B" }, { "C4B", "H4B" }, { "O4B", "C1B" }, + { "C3B", "O3B" }, { "C3B", "C2B" }, { "C3B", "H3B" }, { "O3B", "HO3A" }, + { "C2B", "O2B" }, { "C2B", "C1B" }, { "C2B", "H2B" }, { "O2B", "P2B" }, + { "C1B", "N9A" }, { "C1B", "H1B" }, { "N9A", "C8A" }, { "N9A", "C4A" }, + { "C8A", "H8A" }, { "N7A", "C5A" }, { "C5A", "C6A" }, { "C6A", "N6A" }, + { "N6A", "H61A" }, { "N6A", "H62A" }, { "N1A", "C2A" }, { "C2A", "H2A" }, + { "N3A", "C4A" }, { "O3", "PN" }, { "PN", "O2N" }, { "PN", "O5D" }, + { "O5D", "C5D" }, { "C5D", "C4D" }, { "C5D", "H51N" }, { "C5D", "H52N" }, + { "C4D", "O4D" }, { "C4D", "C3D" }, { "C4D", "H4D" }, { "O4D", "C1D" }, + { "C3D", "O3D" }, { "C3D", "C2D" }, { "C3D", "H3D" }, { "O3D", "HO3N" }, + { "C2D", "O2D" }, { "C2D", "C1D" }, { "C2D", "H2D" }, { "O2D", "HO2N" }, + { "C1D", "N1N" }, { "C1D", "H1D" }, { "N1N", "C2N" }, { "C2N", "H2N" }, + { "C3N", "C7N" }, { "C3N", "C4N" }, { "C7N", "N7N" }, { "N7N", "H71N" }, + { "N7N", "H72N" }, { "C4N", "H4N" }, { "C5N", "C6N" }, { "C5N", "H5N" }, + { "C6N", "H6N" }, { "P2B", "O2X" }, { "P2B", "O3X" }, { "O2X", "HOP2" }, + { "O3X", "HOP3" } }, + // Double Bonds + { { "PA", "O1A" }, + { "C8A", "N7A" }, + { "C5A", "C4A" }, + { "C6A", "N1A" }, + { "C2A", "N3A" }, + { "PN", "O1N" }, + { "N1N", "C6N" }, + { "C2N", "C3N" }, + { "C7N", "O7N" }, + { "C4N", "C5N" }, + { "P2B", "O1X" } }); +ResidueData TRSData("TRS", // Atoms - { "CA", "N", "CB", "C", "O", "OG" }, + { "C", "C1", "C2", "C3", "N", "O1", "O2", + "O3", "H11", "H12", "H21", "H22", "H31", "H32", + "HN1", "HN2", "HN3", "HO1", "HO2", "HO3" }, // Single Bonds - { { "CA", "N" }, - { "CA", "CB" }, - { "CA", "C" }, - { "CB", "OG" }, - { "N", "H" }, - { "N", "HN" }, - { "HA", "CA" }, - { "HB1", "CB" }, - { "HB2", "CB" }, - { "OG", "HG" } }, + { { "C", "C1" }, + { "C", "C2" }, + { "C", "C3" }, + { "C", "N" }, + { "C1", "O1" }, + { "C1", "H11" }, + { "C1", "H12" }, + { "C2", "O2" }, + { "C2", "H21" }, + { "C2", "H22" }, + { "C3", "O3" }, + { "C3", "H31" }, + { "C3", "H32" }, + { "N", "HN1" }, + { "N", "HN2" }, + { "N", "HN3" }, + { "O1", "HO1" }, + { "O2", "HO2" }, + { "O3", "HO3" } }, // Double Bonds - { { "C", "O" } }); - -ResidueData THRData("THR", + {}); +ResidueData ATPData( + "ATP", + // Atoms + { "PG", "O1G", "O2G", "O3G", "PB", "O1B", "O2B", "O3B", "PA", "O1A", + "O2A", "O3A", "O5'", "C5'", "C4'", "O4'", "C3'", "O3'", "C2'", "O2'", + "C1'", "N9", "C8", "N7", "C5", "C6", "N6", "N1", "C2", "N3", + "C4", "HOG2", "HOG3", "HOB2", "HOA2", "H5'1", "H5'2", "H4'", "H3'", "HO3'", + "H2'", "HO2'", "H1'", "H8", "HN61", "HN62", "H2" }, + // Single Bonds + { { "PG", "O2G" }, { "PG", "O3G" }, { "PG", "O3B" }, { "O2G", "HOG2" }, + { "O3G", "HOG3" }, { "PB", "O2B" }, { "PB", "O3B" }, { "PB", "O3A" }, + { "O2B", "HOB2" }, { "PA", "O2A" }, { "PA", "O3A" }, { "PA", "O5'" }, + { "O2A", "HOA2" }, { "O5'", "C5'" }, { "C5'", "C4'" }, { "C5'", "H5'1" }, + { "C5'", "H5'2" }, { "C4'", "O4'" }, { "C4'", "C3'" }, { "C4'", "H4'" }, + { "O4'", "C1'" }, { "C3'", "O3'" }, { "C3'", "C2'" }, { "C3'", "H3'" }, + { "O3'", "HO3'" }, { "C2'", "O2'" }, { "C2'", "C1'" }, { "C2'", "H2'" }, + { "O2'", "HO2'" }, { "C1'", "N9" }, { "C1'", "H1'" }, { "N9", "C8" }, + { "N9", "C4" }, { "C8", "H8" }, { "N7", "C5" }, { "C5", "C6" }, + { "C6", "N6" }, { "N6", "HN61" }, { "N6", "HN62" }, { "N1", "C2" }, + { "C2", "H2" }, { "N3", "C4" } }, + // Double Bonds + { { "PG", "O1G" }, + { "PB", "O1B" }, + { "PA", "O1A" }, + { "C8", "N7" }, + { "C5", "C4" }, + { "C6", "N1" }, + { "C2", "N3" } }); +ResidueData NH2Data("NH2", // Atoms - { "CA", "N", "CB", "C", "O", "CG2", "OG1" }, + { "N", "HN1", "HN2" }, // Single Bonds - { { "CA", "N" }, - { "CA", "CB" }, - { "CA", "C" }, - { "CB", "CG2" }, - { "CB", "OG1" }, - { "N", "H" }, - { "HN", "N" }, - { "N", "H1" }, - { "N", "H2" }, - { "N", "H3" }, - { "OG1", "HG1" }, - { "OG1", "HG1" }, - { "HB", "CB" }, - { "HA", "CA" }, - { "HG21", "CG2" }, - { "HG22", "CG2" }, - { "HG23", "CG2" } }, + { { "N", "HN1" }, { "N", "HN2" } }, // Double Bonds - { { "C", "O" } }); - -ResidueData TRPData("TRP", - // Atoms - { "CA", "N", "CB", "C", "O", "CG", "CD1", "CD2", "CE3", - "CE2", "CZ2", "NE1", "CH2", "CZ3" }, - // Single Bonds - { { "CA", "N" }, { "CA", "CB" }, { "CA", "C" }, - { "CB", "CG" }, { "CG", "CD2" }, { "CD2", "CE2" }, - { "CE2", "NE1" }, { "NE1", "CD1" }, { "CZ2", "CH2" }, - { "CZ3", "CE3" }, { "N", "H" }, { "N", "HN" }, - { "HA", "CA" }, { "HB1", "CB" }, { "HB2", "CB" }, - { "HD1", "CD1" }, { "HE1", "CE1" }, { "HZ2", "CZ2" }, - { "HZ3", "CZ3" }, { "HE3", "CE3" }, { "HH2", "CH2" }, - { "NE1", "HE1" }, { "NE1", "HE1" } }, - // Double Bonds - { { "C", "O" }, - { "CG", "CD1" }, - { "CD2", "CE3" }, - { "CE2", "CZ2" }, - { "CH2", "CZ3" } }); - -ResidueData TYRData( - "TYR", + {}); +ResidueData PG4Data( + "PG4", // Atoms - { "CA", "N", "CB", "C", "O", "CG", "CD1", "CD2", "CE2", "CZ", "OH", "CE1" }, + { "O1", "C1", "C2", "O2", "C3", "C4", "O3", "C5", "C6", "O4", "C7", + "C8", "O5", "HO1", "H11", "H12", "H21", "H22", "H31", "H32", "H41", "H42", + "H51", "H52", "H61", "H62", "H71", "H72", "H81", "H82", "HO5" }, // Single Bonds - { { "CA", "N" }, - { "CA", "CB" }, - { "CA", "C" }, - { "CB", "CG" }, - { "CG", "CD2" }, - { "CE2", "CZ" }, - { "CZ", "OH" }, - { "CE1", "CD1" }, - { "N", "H" }, - { "OH", "HH" }, - { "N", "HN" }, - { "HA", "CA" }, - { "HB1", "CB" }, - { "HB2", "CB" }, - { "HD1", "CD1" }, - { "HD2", "CD2" }, - { "HE1", "CE1" }, - { "HE2", "CE2" }, - { "HZ", "CZ" } }, + { { "O1", "C1" }, { "O1", "HO1" }, { "C1", "C2" }, { "C1", "H11" }, + { "C1", "H12" }, { "C2", "O2" }, { "C2", "H21" }, { "C2", "H22" }, + { "O2", "C3" }, { "C3", "C4" }, { "C3", "H31" }, { "C3", "H32" }, + { "C4", "O3" }, { "C4", "H41" }, { "C4", "H42" }, { "O3", "C5" }, + { "C5", "C6" }, { "C5", "H51" }, { "C5", "H52" }, { "C6", "O4" }, + { "C6", "H61" }, { "C6", "H62" }, { "O4", "C7" }, { "C7", "C8" }, + { "C7", "H71" }, { "C7", "H72" }, { "C8", "O5" }, { "C8", "H81" }, + { "C8", "H82" }, { "O5", "HO5" } }, // Double Bonds - { { "C", "O" }, { "CG", "CD1" }, { "CD2", "CE2" }, { "CZ", "CE1" } }); - -ResidueData VALData("VAL", + {}); +ResidueData FMTData("FMT", // Atoms - { "CA", "N", "CB", "C", "O", "CG2", "CG1" }, + { "C", "O1", "O2", "H", "HO2" }, // Single Bonds - { { "CA", "N" }, - { "CA", "CB" }, - { "CA", "C" }, - { "CB", "CG2" }, - { "CB", "CG1" }, - { "N", "H" }, - { "N", "HN" }, - { "HA", "CA" }, - { "HB", "CB" }, - { "HG11", "CG1" }, - { "HG12", "CG1" }, - { "HG13", "CG1" }, - { "HG21", "CG2" }, - { "HG22", "CG2" }, - { "HG23", "CG2" } }, + { { "C", "O2" }, { "C", "H" }, { "O2", "HO2" } }, // Double Bonds - { { "C", "O" } }); - -ResidueData TIPData("TIP", + { { "C", "O1" } }); +ResidueData GDPData( + "GDP", + // Atoms + { "PB", "O1B", "O2B", "O3B", "O3A", "PA", "O1A", "O2A", "O5'", + "C5'", "C4'", "O4'", "C3'", "O3'", "C2'", "O2'", "C1'", "N9", + "C8", "N7", "C5", "C6", "O6", "N1", "C2", "N2", "N3", + "C4", "HOB2", "HOB3", "HOA2", "H5'", "H5''", "H4'", "H3'", "HO3'", + "H2'", "HO2'", "H1'", "H8", "HN1", "HN21", "HN22" }, + // Single Bonds + { { "PB", "O2B" }, { "PB", "O3B" }, { "PB", "O3A" }, { "O2B", "HOB2" }, + { "O3B", "HOB3" }, { "O3A", "PA" }, { "PA", "O2A" }, { "PA", "O5'" }, + { "O2A", "HOA2" }, { "O5'", "C5'" }, { "C5'", "C4'" }, { "C5'", "H5'" }, + { "C5'", "H5''" }, { "C4'", "O4'" }, { "C4'", "C3'" }, { "C4'", "H4'" }, + { "O4'", "C1'" }, { "C3'", "O3'" }, { "C3'", "C2'" }, { "C3'", "H3'" }, + { "O3'", "HO3'" }, { "C2'", "O2'" }, { "C2'", "C1'" }, { "C2'", "H2'" }, + { "O2'", "HO2'" }, { "C1'", "N9" }, { "C1'", "H1'" }, { "N9", "C8" }, + { "N9", "C4" }, { "C8", "H8" }, { "N7", "C5" }, { "C5", "C6" }, + { "C6", "N1" }, { "N1", "C2" }, { "N1", "HN1" }, { "C2", "N2" }, + { "N2", "HN21" }, { "N2", "HN22" }, { "N3", "C4" } }, + // Double Bonds + { { "PB", "O1B" }, + { "PA", "O1A" }, + { "C8", "N7" }, + { "C5", "C4" }, + { "C6", "O6" }, + { "C2", "N3" } }); +ResidueData FUCData("FUC", // Atoms - { "OH2" }, + { "C1", "C2", "C3", "C4", "C5", "C6", "O1", "O2", + "O3", "O4", "O5", "H1", "H2", "H3", "H4", "H5", + "H61", "H62", "H63", "HO1", "HO2", "HO3", "HO4" }, // Single Bonds - { { "OH2", "H1" }, { "OH2", "H2" } }, + { { "C1", "C2" }, { "C1", "O1" }, { "C1", "O5" }, + { "C1", "H1" }, { "C2", "C3" }, { "C2", "O2" }, + { "C2", "H2" }, { "C3", "C4" }, { "C3", "O3" }, + { "C3", "H3" }, { "C4", "C5" }, { "C4", "O4" }, + { "C4", "H4" }, { "C5", "C6" }, { "C5", "O5" }, + { "C5", "H5" }, { "C6", "H61" }, { "C6", "H62" }, + { "C6", "H63" }, { "O1", "HO1" }, { "O2", "HO2" }, + { "O3", "HO3" }, { "O4", "HO4" } }, // Double Bonds {}); - -ResidueData HOHData("HOH", +ResidueData SEPData("SEP", // Atoms - { "O", "H1", "H2" }, + { "N", "CA", "CB", "OG", "C", "O", "OXT", "P", "O1P", "O2P", + "O3P", "H", "H2", "HA", "HB2", "HB3", "HXT", "HOP2", + "HOP3" }, // Single Bonds - { { "O", "H1" }, { "O", "H2" } }, + { { "N", "CA" }, + { "N", "H" }, + { "N", "H2" }, + { "CA", "CB" }, + { "CA", "C" }, + { "CA", "HA" }, + { "CB", "OG" }, + { "CB", "HB2" }, + { "CB", "HB3" }, + { "OG", "P" }, + { "C", "OXT" }, + { "OXT", "HXT" }, + { "P", "O2P" }, + { "P", "O3P" }, + { "O2P", "HOP2" }, + { "O3P", "HOP3" } }, // Double Bonds - {}); - -ResidueData WATData("WAT", + { { "C", "O" }, { "P", "O1P" } }); +ResidueData GALData("GAL", // Atoms - { "O", "H1", "H2" }, + { "C1", "C2", "C3", "C4", "C5", "C6", "O1", "O2", + "O3", "O4", "O5", "O6", "H1", "H2", "H3", "H4", + "H5", "H61", "H62", "HO1", "HO2", "HO3", "HO4", "HO6" }, // Single Bonds - { { "O", "H1" }, { "O", "H2" } }, + { { "C1", "C2" }, { "C1", "O1" }, { "C1", "O5" }, + { "C1", "H1" }, { "C2", "C3" }, { "C2", "O2" }, + { "C2", "H2" }, { "C3", "C4" }, { "C3", "O3" }, + { "C3", "H3" }, { "C4", "C5" }, { "C4", "O4" }, + { "C4", "H4" }, { "C5", "C6" }, { "C5", "O5" }, + { "C5", "H5" }, { "C6", "O6" }, { "C6", "H61" }, + { "C6", "H62" }, { "O1", "HO1" }, { "O2", "HO2" }, + { "O3", "HO3" }, { "O4", "HO4" }, { "O6", "HO6" } }, // Double Bonds {}); - -ResidueData INHData( - "INH", - // Atoms - { "P", "O1P", "O2P", "O3P", "O5", "C5", "C4", "O4", "C3", "C1", - "O3", "C2", "O2", "N9", "C8", "N7", "C6", "O6", "N1", "N3" }, - // Single Bonds - { { "P", "O2P" }, { "P", "O3P" }, { "P", "O5" }, { "O5", "C5" }, - { "C5", "C4" }, { "C4", "O4" }, { "C4", "C3" }, { "O4", "C1" }, - { "C3", "O3" }, { "C3", "C2" }, { "O3", "H1" }, { "C2", "O2" }, - { "C2", "C1" }, { "O2", "H2" }, { "C1", "N9" }, { "N9", "C8" }, - { "N9", "C4" }, { "N7", "C5" }, { "C5", "C6" }, { "C6", "N1" }, - { "N1", "C2" }, { "N1", "H3" }, { "N3", "C4" } }, - // Double Bonds - { { "P", "O1P" }, { "C8", "N7" }, { "C6", "O6" }, { "C2", "N3" } }); - -ResidueData UMPData("UMP", - // Atoms - { "N1", "C2", "C6", "C1", "N3", "O2", "C4", "C5", "O4", - "C3", "O3", "O5", "P", "O1P", "O2P", "O3P" }, - // Single Bonds - { { "N1", "C2" }, { "N1", "C6" }, { "N1", "C1" }, - { "C2", "N3" }, { "C2", "O2" }, { "C2", "H5" }, - { "N3", "C4" }, { "N3", "H1" }, { "C4", "C5" }, - { "C4", "O4" }, { "C4", "H6" }, { "C5", "C6" }, - { "C5", "H7" }, { "C5", "H8" }, { "C6", "H9" }, - { "C6", "H10" }, { "O2", "H2" }, { "O4", "H3" }, - { "C1", "C2" }, { "C1", "O4" }, { "C1", "H11" }, - { "C2", "C3" }, { "C2", "H12" }, { "C2", "H13" }, - { "C3", "C4" }, { "C3", "O3" }, { "C3", "H14" }, - { "C4", "H15" }, { "O3", "H4" }, { "C5", "O5" }, - { "C5", "H16" }, { "C5", "H17" }, { "O5", "P" } }, - // Double Bonds - { { "P", "O1P" }, { "P", "O2P" }, { "P", "O3P" } }); - -ResidueData HEDData("HED", +ResidueData PGEData("PGE", // Atoms - { "C1", "O1", "C2", "S3", "S4", "C5", "C6", "O6" }, + { "C1", "O1", "C2", "O2", "C3", "C4", "O4", "C6", + "C5", "O3", "H1", "H12", "HO1", "H2", "H22", "H3", + "H32", "H4", "H42", "HO4", "H6", "H62", "H5", "H52" }, // Single Bonds - { { "C1", "C2" }, - { "C2", "S3" }, - { "S3", "S4" }, - { "S4", "C5" }, - { "C5", "C6" } }, + { { "C1", "O1" }, { "C1", "C2" }, { "C1", "H1" }, + { "C1", "H12" }, { "O1", "HO1" }, { "C2", "O2" }, + { "C2", "H2" }, { "C2", "H22" }, { "O2", "C3" }, + { "C3", "C4" }, { "C3", "H3" }, { "C3", "H32" }, + { "C4", "O3" }, { "C4", "H4" }, { "C4", "H42" }, + { "O4", "C6" }, { "O4", "HO4" }, { "C6", "C5" }, + { "C6", "H6" }, { "C6", "H62" }, { "C5", "O3" }, + { "C5", "H5" }, { "C5", "H52" } }, // Double Bonds - { { "C1", "O1" }, { "C6", "O6" } }); - + {}); std::map residueDict = { - { "ALA", ALAData }, { "ARG", ARGData }, { "ARZ", ARZData }, - { "ASN", ASNData }, { "ASP", ASPData }, { "ASH", ASHData }, - { "CYS", CYSData }, { "CYX", CYXData }, { "GLN", GLNData }, - { "GLU", GLUData }, { "GLY", GLYData }, { "GLZ", GLZData }, - { "HID", HIDData }, { "HIE", HIEData }, { "HIP", HIPData }, - { "HIS", HISData }, { "ILE", ILEData }, { "LEU", LEUData }, - { "LYS", LYSData }, { "LYZ", LYZData }, { "MET", METData }, - { "PHE", PHEData }, { "PRO", PROData }, { "PSE", PSEData }, - { "PSM", PSMData }, { "PTM", PTMData }, { "PTY", PTYData }, - { "SER", SERData }, { "THR", THRData }, { "TRP", TRPData }, - { "TYR", TYRData }, { "VAL", VALData }, { "TIP", TIPData }, - { "HOH", HOHData }, { "WAT", WATData }, { "INH", INHData }, - { "UMP", UMPData }, { "HED", HEDData } + { "ALA", ALAData }, { "CYS", CYSData }, { "ASP", ASPData }, + { "GLU", GLUData }, { "PHE", PHEData }, { "GLY", GLYData }, + { "HIS", HISData }, { "ILE", ILEData }, { "LYS", LYSData }, + { "LEU", LEUData }, { "MET", METData }, { "ASN", ASNData }, + { "PRO", PROData }, { "GLN", GLNData }, { "ARG", ARGData }, + { "SER", SERData }, { "THR", THRData }, { "VAL", VALData }, + { "TRP", TRPData }, { "TYR", TYRData }, { "DA", DAData }, + { "DC", DCData }, { "DG", DGData }, { "DT", DTData }, + { "DI", DIData }, { "A", AData }, { "C", CData }, + { "G", GData }, { "U", UData }, { "I", IData }, + { "HEM", HEMData }, { "HOH", HOHData }, { "SO4", SO4Data }, + { "GOL", GOLData }, { "MSE", MSEData }, { "EDO", EDOData }, + { "NAG", NAGData }, { "PO4", PO4Data }, { "ACT", ACTData }, + { "PEG", PEGData }, { "MAN", MANData }, { "BMA", BMAData }, + { "FAD", FADData }, { "ADP", ADPData }, { "DMS", DMSData }, + { "ACE", ACEData }, { "MPD", MPDData }, { "MES", MESData }, + { "NAD", NADData }, { "NAP", NAPData }, { "TRS", TRSData }, + { "ATP", ATPData }, { "NH2", NH2Data }, { "PG4", PG4Data }, + { "FMT", FMTData }, { "GDP", GDPData }, { "FUC", FUCData }, + { "SEP", SEPData }, { "GAL", GALData }, { "PGE", PGEData }, + }; -} -} +} // namespace Core +} // namespace Avogadro -#endif \ No newline at end of file +#endif diff --git a/scripts/getresdata.py b/scripts/getresdata.py new file mode 100644 index 0000000000..732ed0591b --- /dev/null +++ b/scripts/getresdata.py @@ -0,0 +1,179 @@ +#!/usr/bin/env python + +import requests +import pybel +import openbabel as ob +import os + +# the location of the LigandExpo list by count +ligandURL = "http://ligand-expo.rcsb.org/dictionaries/cc-counts.tdd" +# URL for the ideal geometry +# e.g http://ligand-expo.rcsb.org/reports/H/HEM/HEM_ideal.pdb +sdfTemplate = "http://ligand-expo.rcsb.org/reports/{}/{}/{}_ideal.sdf" +# URL for the ideal geometry (PDB) +pdbTemplate = "http://ligand-expo.rcsb.org/reports/{}/{}/{}_ideal.pdb" +# save ligands with at least this # of occurrences +ligandThresh = 1000 + +# default ligand list +ligands = [ +# amino acids +"ALA", "CYS", "ASP", "GLU", "PHE", "GLY", "HIS", "ILE", "LYS", "LEU", +"MET", "ASN", "PRO", "GLN", "ARG", "SER", "THR", "VAL", "TRP", "TYR", +# DNA nucleic +"DA", "DC", "DG", "DT", "DI", +# RNA nucleic +"A", "C", "G", "U", "I", +# misc +"HEM", "HOH" +] + +# okay, we build up the list of ligands to fetch +r = requests.get(ligandURL, stream=True) +for line in r.iter_lines(decode_unicode=True): + if 'count' in str(line): + continue # skip first line + + name, count = line.split() + if (int(count) < ligandThresh): + # too rare, we'll skip the rest of the list + break + if str(name) not in ligands: + ligands.append(str(name)) + +print( +''' +#ifndef AVOGADRO_CORE_RESIDUE_DATA +#define AVOGADRO_CORE_RESIDUE_DATA + +#include +#include +#include +namespace Avogadro { +namespace Core { + +class ResidueData +{ +private: + std::string m_residueName; + std::vector m_residueAtomNames; + std::vector> m_residueSingleBonds; + std::vector> m_residueDoubleBonds; + +public: + ResidueData() {} + ResidueData(std::string name, std::vector atomNames, + std::vector> singleBonds, + std::vector> doubleBonds) + { + m_residueName = name; + m_residueAtomNames = atomNames; + m_residueSingleBonds = singleBonds; + m_residueDoubleBonds = doubleBonds; + } + + ResidueData(const ResidueData& other) + { + m_residueName = other.m_residueName; + m_residueAtomNames = other.m_residueAtomNames; + m_residueSingleBonds = other.m_residueSingleBonds; + m_residueDoubleBonds = other.m_residueDoubleBonds; + } + + ResidueData& operator=(ResidueData other) + { + using std::swap; + swap(*this, other); + return *this; + } + + std::vector> residueSingleBonds() + { + return m_residueSingleBonds; + } + + std::vector> residueDoubleBonds() + { + return m_residueDoubleBonds; + } +}; +''' +) + +final_ligands = [] +for ligand in ligands: + sdf = requests.get(sdfTemplate.format(ligand[0], ligand, ligand)) + # there *must* be a way to do this from a requests buffer, but this works + with open('temp.sdf', 'wb') as handle: + for block in sdf.iter_content(1024): + handle.write(block) + + mol_sdf = next(pybel.readfile("sdf", 'temp.sdf')) + if len(mol_sdf.atoms) < 2: + continue + final_ligands.append(ligand) + + pdb = requests.get(pdbTemplate.format(ligand[0], ligand, ligand)) + with open('temp.pdb', 'wb') as handle: + for block in pdb.iter_content(1024): + handle.write(block) + + mol_pdb = next(pybel.readfile("pdb", 'temp.pdb')) + atom_map = {} + for i in range(len(mol_sdf.atoms)): + idx = mol_sdf.atoms[i].idx + atom = mol_pdb.atoms[i].OBAtom + res = atom.GetResidue() + # build up a map between atom index and atom ID + atom_map[idx] = res.GetAtomID(atom).strip().rstrip() + + # go through bonds + single_bonds = [] + double_bonds = [] + for bond in ob.OBMolBondIter(mol_sdf.OBMol): + begin = bond.GetBeginAtomIdx() + end = bond.GetEndAtomIdx() + if bond.GetBO() == 2: + double_bonds.append((atom_map[begin], atom_map[end])) + elif bond.GetBO() == 1: + single_bonds.append((atom_map[begin], atom_map[end])) + + # print out the residue data + print('ResidueData %sData("%s",' % (ligand, ligand)) + print('// Atoms') + print('{') + for atom in atom_map.values(): + print('"%s", ' % atom) + print('},') + + print('// Single Bonds') + print('{') + for bond in single_bonds: + print('{ "%s", "%s" },' % bond) + print('},') + + print('// Double Bonds') + print('{') + if len(double_bonds): + for bond in double_bonds: + print('{ "%s", "%s" },' % bond) + print('},') + + print(');') + +print('''std::map residueDict = {''') + +# print the list of ligands +for ligand in final_ligands: + print('{ "%s", %sData },' % (ligand, ligand)) + +print(''' +}; +} +} + +#endif +''' +) +os.remove("temp.sdf") +os.remove('temp.pdb') From 902412282788a38ae33a5daf2ec9538d7e68d5e1 Mon Sep 17 00:00:00 2001 From: Adarsh Balasubramanian Date: Sat, 28 Jul 2018 02:13:19 +0530 Subject: [PATCH 10/68] Force vector field in Atom/Molecule class; Integrating force plugin Signed-off-by: Adarsh Balasubramanian --- avogadro/core/atom.h | 82 +++++++++++++++++++----------- avogadro/core/molecule.cpp | 10 ++++ avogadro/core/molecule.h | 55 ++++++++++++++++++++ avogadro/qtplugins/force/force.cpp | 2 +- 4 files changed, 118 insertions(+), 31 deletions(-) diff --git a/avogadro/core/atom.h b/avogadro/core/atom.h index 60f31f1c9f..39d844d0e8 100644 --- a/avogadro/core/atom.h +++ b/avogadro/core/atom.h @@ -46,7 +46,7 @@ enum AtomHybridization * To use the appropriate atom implementation for a specific molecule * implementation, use the [MoleculeClass]::AtomType typedef. */ -template +template class AtomTemplate { public: @@ -163,103 +163,111 @@ class AtomTemplate bool selected() const; /** @} */ + /** + * The force on this atom. + * {@ + */ + void setForceVector(const Vector3& force); + Vector3 forceVector() const; + /** @} */ + private: MoleculeType* m_molecule; Index m_index; }; -template +template AtomTemplate::AtomTemplate() - : m_molecule(nullptr), m_index(MaxIndex) -{ -} + : m_molecule(nullptr) + , m_index(MaxIndex) +{} -template +template AtomTemplate::AtomTemplate(MoleculeType* m, Index i) - : m_molecule(m), m_index(i) -{ -} + : m_molecule(m) + , m_index(i) +{} -template +template bool AtomTemplate::operator==( const AtomTemplate& other) const { return m_molecule == other.m_molecule && m_index == other.m_index; } -template +template bool AtomTemplate::operator!=( const AtomTemplate& other) const { return m_molecule != other.m_molecule || m_index != other.m_index; } -template +template AtomTemplate& AtomTemplate::operator++() { ++m_index; return *this; } -template +template AtomTemplate AtomTemplate::operator++(int) { AtomTemplate result(m_molecule, m_index++); return result; } -template +template AtomTemplate& AtomTemplate::operator--() { --m_index; return *this; } -template +template AtomTemplate AtomTemplate::operator--(int) { AtomTemplate result(m_molecule, m_index--); return result; } -template +template bool AtomTemplate::isValid() const { return m_molecule && m_index < m_molecule->atomCount(); } -template +template typename AtomTemplate::MoleculeType* AtomTemplate::molecule() const { return m_molecule; } -template +template Index AtomTemplate::index() const { return m_index; } -template +template void AtomTemplate::setAtomicNumber(unsigned char num) { m_molecule->setAtomicNumber(m_index, num); } -template +template unsigned char AtomTemplate::atomicNumber() const { return m_molecule->atomicNumber(m_index); } -template +template void AtomTemplate::setPosition2d(const Vector2& pos) { m_molecule->setAtomPosition2d(m_index, pos); } -template +template Vector2 AtomTemplate::position2d() const { return m_molecule->atomPositions2d().size() > 0 @@ -267,13 +275,13 @@ Vector2 AtomTemplate::position2d() const : Vector2::Zero(); } -template +template void AtomTemplate::setPosition3d(const Vector3& pos) { m_molecule->setAtomPosition3d(m_index, pos); } -template +template Vector3 AtomTemplate::position3d() const { return m_molecule->atomPositions3d().size() > 0 @@ -281,42 +289,56 @@ Vector3 AtomTemplate::position3d() const : Vector3::Zero(); } -template +template void AtomTemplate::setHybridization(AtomHybridization hyb) { m_molecule->setHybridization(m_index, hyb); } -template +template AtomHybridization AtomTemplate::hybridization() const { return m_molecule->hybridization(m_index); } -template +template void AtomTemplate::setFormalCharge(signed char charge) { m_molecule->setFormalCharge(m_index, charge); } -template +template signed char AtomTemplate::formalCharge() const { return m_molecule->formalCharge(m_index); } -template +template void AtomTemplate::setSelected(bool selected) { m_molecule->setAtomSelected(m_index, selected); } -template +template bool AtomTemplate::selected() const { return m_molecule->atomSelected(m_index); } +template +void AtomTemplate::setForceVector(const Vector3& force) +{ + m_molecule->setForceVector(m_index, force); +} + +template +Vector3 AtomTemplate::forceVector() const +{ + return m_molecule->forceVectors().size() > 0 + ? m_molecule->forceVectors()[m_index] + : Vector3::Zero(); +} + } // end Core namespace } // end Avogadro namespace diff --git a/avogadro/core/molecule.cpp b/avogadro/core/molecule.cpp index b256743450..847212c2fe 100644 --- a/avogadro/core/molecule.cpp +++ b/avogadro/core/molecule.cpp @@ -814,5 +814,15 @@ void Molecule::updateGraph() const } } +Array& Molecule::forceVectors() +{ + return m_forceVectors; +} + +const Array& Molecule::forceVectors() const +{ + return m_forceVectors; +} + } // end Core namespace } // end Avogadro namespace diff --git a/avogadro/core/molecule.h b/avogadro/core/molecule.h index 2badc4ef85..40e3060aed 100644 --- a/avogadro/core/molecule.h +++ b/avogadro/core/molecule.h @@ -539,6 +539,35 @@ class AVOGADROCORE_EXPORT Molecule bool setTimeStep(double timestep, int index); double timeStep(int index, bool& status); + /** Returns a vector of forces for the atoms in the molecule. */ + const Array& forceVectors() const; + + /** \overload */ + Array& forceVectors(); + + /** + * Get the force of a single atom. + * @param atomId The index of the atom. + * @return The force vector of the atom, or Vector3::Zero() if no force + * information has been set. + */ + Vector3 forceVector(Index atomId) const; + + /** + * Replace the current array of force vectors. + * @param pos The new coordinate array. Must be of length atomCount(). + * @return True on success, false otherwise. + */ + bool setForceVectors(const Core::Array& forces); + + /** + * Set the 3D position of a single atom. + * @param atomId The index of the atom to modify. + * @param pos The new position of the atom. + * @return True on success, false otherwise. + */ + bool setForceVector(Index atomId, const Vector3& force); + protected: mutable Graph m_graph; // A transformation of the molecule to a graph. mutable bool m_graphDirty; // Should the graph be rebuilt before returning it? @@ -551,6 +580,7 @@ class AVOGADROCORE_EXPORT Molecule Array m_timesteps; Array m_hybridizations; Array m_formalCharges; + Array m_forceVectors; // Vibration data if available. Array m_vibrationFrequencies; @@ -795,6 +825,31 @@ inline bool Molecule::setBondOrder(Index bondId, unsigned char order) return false; } +inline Vector3 Molecule::forceVector(Index atomId) const +{ + return atomId < m_forceVectors.size() ? m_forceVectors[atomId] : Vector3(); +} + +inline bool Molecule::setForceVectors(const Core::Array& forces) +{ + if (forces.size() == atomCount() || forces.size() == 0) { + m_forceVectors = forces; + return true; + } + return false; +} + +inline bool Molecule::setForceVector(Index atomId, const Vector3& force) +{ + if (atomId < atomCount()) { + if (atomId >= m_forceVectors.size()) + m_forceVectors.resize(atomCount(), Vector3::Zero()); + m_forceVectors[atomId] = force; + return true; + } + return false; +} + } // end Core namespace } // end Avogadro namespace diff --git a/avogadro/qtplugins/force/force.cpp b/avogadro/qtplugins/force/force.cpp index 6d6c801aa6..8344e75bf9 100644 --- a/avogadro/qtplugins/force/force.cpp +++ b/avogadro/qtplugins/force/force.cpp @@ -57,7 +57,7 @@ void Force::process(const Molecule& molecule, Rendering::GroupNode& node) for (Index i = 0; i < molecule.atomCount(); ++i) { Core::Atom atom1 = molecule.atom(i); Vector3f pos1 = atom1.position3d().cast(); - Vector3f forceVector(2.0, 2.0, 2.0); + Vector3f forceVector = atom1.forceVector().cast(); arrows->addSingleArrow(pos1, pos1 + forceVector); } } From ae264d4c1efc60d272f7d0df7562b4f2b31c4ab8 Mon Sep 17 00:00:00 2001 From: Adarsh Balasubramanian Date: Sat, 28 Jul 2018 02:59:00 +0530 Subject: [PATCH 11/68] clang-format Signed-off-by: Adarsh Balasubramanian --- avogadro/core/atom.h | 62 ++++++++++++++-------------- avogadro/qtplugins/force/force.cpp | 9 ++-- avogadro/rendering/arrowgeometry.cpp | 12 ++---- 3 files changed, 36 insertions(+), 47 deletions(-) diff --git a/avogadro/core/atom.h b/avogadro/core/atom.h index 39d844d0e8..68792e850b 100644 --- a/avogadro/core/atom.h +++ b/avogadro/core/atom.h @@ -46,7 +46,7 @@ enum AtomHybridization * To use the appropriate atom implementation for a specific molecule * implementation, use the [MoleculeClass]::AtomType typedef. */ -template +template class AtomTemplate { public: @@ -176,98 +176,96 @@ class AtomTemplate Index m_index; }; -template +template AtomTemplate::AtomTemplate() - : m_molecule(nullptr) - , m_index(MaxIndex) + : m_molecule(nullptr), m_index(MaxIndex) {} -template +template AtomTemplate::AtomTemplate(MoleculeType* m, Index i) - : m_molecule(m) - , m_index(i) + : m_molecule(m), m_index(i) {} -template +template bool AtomTemplate::operator==( const AtomTemplate& other) const { return m_molecule == other.m_molecule && m_index == other.m_index; } -template +template bool AtomTemplate::operator!=( const AtomTemplate& other) const { return m_molecule != other.m_molecule || m_index != other.m_index; } -template +template AtomTemplate& AtomTemplate::operator++() { ++m_index; return *this; } -template +template AtomTemplate AtomTemplate::operator++(int) { AtomTemplate result(m_molecule, m_index++); return result; } -template +template AtomTemplate& AtomTemplate::operator--() { --m_index; return *this; } -template +template AtomTemplate AtomTemplate::operator--(int) { AtomTemplate result(m_molecule, m_index--); return result; } -template +template bool AtomTemplate::isValid() const { return m_molecule && m_index < m_molecule->atomCount(); } -template +template typename AtomTemplate::MoleculeType* AtomTemplate::molecule() const { return m_molecule; } -template +template Index AtomTemplate::index() const { return m_index; } -template +template void AtomTemplate::setAtomicNumber(unsigned char num) { m_molecule->setAtomicNumber(m_index, num); } -template +template unsigned char AtomTemplate::atomicNumber() const { return m_molecule->atomicNumber(m_index); } -template +template void AtomTemplate::setPosition2d(const Vector2& pos) { m_molecule->setAtomPosition2d(m_index, pos); } -template +template Vector2 AtomTemplate::position2d() const { return m_molecule->atomPositions2d().size() > 0 @@ -275,13 +273,13 @@ Vector2 AtomTemplate::position2d() const : Vector2::Zero(); } -template +template void AtomTemplate::setPosition3d(const Vector3& pos) { m_molecule->setAtomPosition3d(m_index, pos); } -template +template Vector3 AtomTemplate::position3d() const { return m_molecule->atomPositions3d().size() > 0 @@ -289,49 +287,49 @@ Vector3 AtomTemplate::position3d() const : Vector3::Zero(); } -template +template void AtomTemplate::setHybridization(AtomHybridization hyb) { m_molecule->setHybridization(m_index, hyb); } -template +template AtomHybridization AtomTemplate::hybridization() const { return m_molecule->hybridization(m_index); } -template +template void AtomTemplate::setFormalCharge(signed char charge) { m_molecule->setFormalCharge(m_index, charge); } -template +template signed char AtomTemplate::formalCharge() const { return m_molecule->formalCharge(m_index); } -template +template void AtomTemplate::setSelected(bool selected) { m_molecule->setAtomSelected(m_index, selected); } -template +template bool AtomTemplate::selected() const { return m_molecule->atomSelected(m_index); } -template +template void AtomTemplate::setForceVector(const Vector3& force) { m_molecule->setForceVector(m_index, force); } -template +template Vector3 AtomTemplate::forceVector() const { return m_molecule->forceVectors().size() > 0 @@ -339,7 +337,7 @@ Vector3 AtomTemplate::forceVector() const : Vector3::Zero(); } -} // end Core namespace -} // end Avogadro namespace +} // namespace Core +} // namespace Avogadro #endif // AVOGADRO_CORE_ATOM_H diff --git a/avogadro/qtplugins/force/force.cpp b/avogadro/qtplugins/force/force.cpp index 8344e75bf9..e3db4eb0da 100644 --- a/avogadro/qtplugins/force/force.cpp +++ b/avogadro/qtplugins/force/force.cpp @@ -39,10 +39,7 @@ using Rendering::ArrowGeometry; using Rendering::GeometryNode; using Rendering::GroupNode; -Force::Force(QObject* p) - : ScenePlugin(p) - , m_enabled(false) -{} +Force::Force(QObject* p) : ScenePlugin(p), m_enabled(false) {} Force::~Force() {} @@ -71,5 +68,5 @@ void Force::setEnabled(bool enable) { m_enabled = enable; } -} -} +} // namespace QtPlugins +} // namespace Avogadro diff --git a/avogadro/rendering/arrowgeometry.cpp b/avogadro/rendering/arrowgeometry.cpp index 5fbc7b5182..2ffba9c5d3 100644 --- a/avogadro/rendering/arrowgeometry.cpp +++ b/avogadro/rendering/arrowgeometry.cpp @@ -54,17 +54,11 @@ class ArrowGeometry::Private ShaderProgram program; }; -ArrowGeometry::ArrowGeometry() - : m_dirty(false) - , d(new Private) -{} +ArrowGeometry::ArrowGeometry() : m_dirty(false), d(new Private) {} ArrowGeometry::ArrowGeometry(const ArrowGeometry& other) - : Drawable(other) - , m_vertices(other.m_vertices) - , m_lineStarts(other.m_lineStarts) - , m_dirty(true) - , d(new Private) + : Drawable(other), m_vertices(other.m_vertices), + m_lineStarts(other.m_lineStarts), m_dirty(true), d(new Private) {} ArrowGeometry::~ArrowGeometry() From 623920d29c0ae9691fc949938c7191fc376ac319 Mon Sep 17 00:00:00 2001 From: Geoff Hutchison Date: Sat, 28 Jul 2018 00:27:38 -0400 Subject: [PATCH 12/68] Make sure to properly hide/delete dialogs and options on each call Fixes a bug where multiple calls would multiply buttons, etc. Signed-off-by: Geoff Hutchison --- avogadro/qtplugins/workflows/workflow.cpp | 42 ++++++++++++++--------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/avogadro/qtplugins/workflows/workflow.cpp b/avogadro/qtplugins/workflows/workflow.cpp index 6dd9004f91..49874d55d8 100644 --- a/avogadro/qtplugins/workflows/workflow.cpp +++ b/avogadro/qtplugins/workflows/workflow.cpp @@ -47,11 +47,8 @@ using Avogadro::QtGui::InterfaceScript; using Avogadro::QtGui::InterfaceWidget; Workflow::Workflow(QObject* parent_) - : ExtensionPlugin(parent_) - , m_molecule(nullptr) - , m_currentDialog(nullptr) - , m_currentInterface(nullptr) - , m_outputFormat(nullptr) + : ExtensionPlugin(parent_), m_molecule(nullptr), m_currentDialog(nullptr), + m_currentInterface(nullptr), m_outputFormat(nullptr) { refreshScripts(); } @@ -133,6 +130,14 @@ void Workflow::menuActivated() QString scriptFileName = theSender->data().toString(); QWidget* theParent = qobject_cast(parent()); + + if (m_currentDialog) { + delete m_currentDialog->layout(); + if (m_currentInterface) + m_currentInterface->hide(); + } + + // check if there are any options before this song-and-dance InterfaceWidget* widget = m_dialogs.value(scriptFileName, nullptr); if (!widget) { @@ -140,19 +145,20 @@ void Workflow::menuActivated() m_dialogs.insert(scriptFileName, widget); } widget->setMolecule(m_molecule); - - if (!m_currentDialog) { - m_currentDialog = new QDialog(theParent); - } else { - delete m_currentDialog->layout(); + m_currentInterface = widget; // remember this when we get the run() signal + if (widget->isEmpty()) { + run(); // no options, do it immediately + return; } + + m_currentDialog = new QDialog(theParent); QString title; QtGui::ScriptLoader::queryProgramName(scriptFileName, title); m_currentDialog->setWindowTitle(title); QVBoxLayout* vbox = new QVBoxLayout(); + widget->show(); vbox->addWidget(widget); - m_currentInterface = widget; // remember this when we get the run() signal QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); @@ -175,6 +181,9 @@ void Workflow::run() InterfaceScript gen(scriptFilePath); gen.runWorkflow(options, m_molecule); // collect errors + if (gen.hasErrors()) { + qWarning() << gen.errorList(); + } } } @@ -238,9 +247,9 @@ void Workflow::updateActions() { m_actions.clear(); - QAction* action = new QAction(tr("Set Python Path..."), this); - connect(action, SIGNAL(triggered()), SLOT(configurePython())); - m_actions << action; + // QAction* action = new QAction(tr("Set Python Path..."), this); + // connect(action, SIGNAL(triggered()), SLOT(configurePython())); + // m_actions << action; foreach (const QString& programName, m_workflowScripts.uniqueKeys()) { QStringList scripts = m_workflowScripts.values(programName); @@ -264,5 +273,6 @@ void Workflow::addAction(const QString& label, const QString& scriptFilePath) connect(action, SIGNAL(triggered()), SLOT(menuActivated())); m_actions << action; } -} -} + +} // namespace QtPlugins +} // namespace Avogadro From 7fef383606d55573549960334843dcf9daa7ba93 Mon Sep 17 00:00:00 2001 From: Geoff Hutchison Date: Sat, 28 Jul 2018 00:29:28 -0400 Subject: [PATCH 13/68] Allow workflows to use "append", "bond", and "moleculeFormat" - Append new molecules (instead of replace) - Auto-create bonds (if needed - most formats have them) - Allow multiple formats (e.g., returning XYZ) Signed-off-by: Geoff Hutchison --- avogadro/qtgui/interfacescript.cpp | 83 +++++++++++++++++------------- 1 file changed, 48 insertions(+), 35 deletions(-) diff --git a/avogadro/qtgui/interfacescript.cpp b/avogadro/qtgui/interfacescript.cpp index 3ccc439610..bbe21ee587 100644 --- a/avogadro/qtgui/interfacescript.cpp +++ b/avogadro/qtgui/interfacescript.cpp @@ -1,17 +1,7 @@ /****************************************************************************** - This source file is part of the Avogadro project. - Copyright 2013 Kitware, Inc. - This source code is released under the New BSD License, (the "License"). - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - ******************************************************************************/ #include "interfacescript.h" @@ -40,15 +30,13 @@ using QtGui::PythonScript; InterfaceScript::InterfaceScript(const QString& scriptFilePath_, QObject* parent_) - : QObject(parent_) - , m_interpreter(new PythonScript(scriptFilePath_, this)) - , m_moleculeExtension(QStringLiteral("cjson")) + : QObject(parent_), m_interpreter(new PythonScript(scriptFilePath_, this)), + m_moleculeExtension(QStringLiteral("cjson")) {} InterfaceScript::InterfaceScript(QObject* parent_) - : QObject(parent_) - , m_interpreter(new PythonScript(this)) - , m_moleculeExtension(QStringLiteral("cjson")) + : QObject(parent_), m_interpreter(new PythonScript(this)), + m_moleculeExtension(QStringLiteral("cjson")) {} InterfaceScript::~InterfaceScript() {} @@ -186,8 +174,10 @@ bool InterfaceScript::runWorkflow(const QJsonObject& options_, } QJsonDocument doc; - if (!parseJson(json, doc)) + if (!parseJson(json, doc)) { + qDebug() << " can't parse "; return false; + } // Update cache bool result = true; @@ -208,27 +198,50 @@ bool InterfaceScript::runWorkflow(const QJsonObject& options_, } } - // TODO: add smart updates + m_moleculeExtension = "cjson"; + if (obj.contains("moleculeFormat") && obj["moleculeFormat"].isString()) { + m_moleculeExtension = obj["moleculeFormat"].toString(); + } + Io::FileFormatManager& formats = Io::FileFormatManager::instance(); QScopedPointer format( - formats.newFormatFromFileExtension("cjson")); - // convert the "cjson" field to a string - QJsonObject cjsonObj = obj[QStringLiteral("cjson")].toObject(); - QJsonDocument doc(cjsonObj); - QString strCJSON(doc.toJson(QJsonDocument::Compact)); - if (!strCJSON.isEmpty()) { - QtGui::Molecule* guiMol = static_cast(mol); - QtGui::Molecule newMol(guiMol->parent()); - result = format->readString(strCJSON.toStdString(), newMol); - - if (obj[QStringLiteral("append")].toBool()) { // just append some new bits - guiMol->undoMolecule()->appendMolecule(newMol, m_displayName); - } else { // replace the whole molecule - Molecule::MoleculeChanges changes = - (Molecule::Atoms | Molecule::Bonds | Molecule::Added | - Molecule::Removed); - guiMol->undoMolecule()->modifyMolecule(newMol, changes, m_displayName); + formats.newFormatFromFileExtension(m_moleculeExtension.toStdString())); + + if (format.isNull()) { + m_errors << tr("Error reading molecule representation: " + "Unrecognized file format: %1") + .arg(m_moleculeExtension); + return false; + } + + QtGui::Molecule* guiMol = static_cast(mol); + QtGui::Molecule newMol(guiMol->parent()); + if (m_moleculeExtension == "cjson") { + // convert the "cjson" field to a string + QJsonObject cjsonObj = obj["cjson"].toObject(); + QJsonDocument doc(cjsonObj); + QString strCJSON(doc.toJson(QJsonDocument::Compact)); + if (!strCJSON.isEmpty()) { + result = format->readString(strCJSON.toStdString(), newMol); } + } else if (obj.contains(m_moleculeExtension) && + obj[m_moleculeExtension].isString()) { + QString strFile = obj[m_moleculeExtension].toString(); + result = format->readString(strFile.toStdString(), newMol); + } + + // check if the script wants us to perceive bonds first + if (obj["bond"].toBool()) { + newMol.perceiveBondsSimple(); + } + + if (obj["append"].toBool()) { // just append some new bits + qDebug() << " appending " << newMol.atomCount(); + guiMol->undoMolecule()->appendMolecule(newMol, m_displayName); + } else { // replace the whole molecule + Molecule::MoleculeChanges changes = (Molecule::Atoms | Molecule::Bonds | + Molecule::Added | Molecule::Removed); + guiMol->undoMolecule()->modifyMolecule(newMol, changes, m_displayName); } } return result; From 3375c5d9ccc4a81454b849159c46535e525199fb Mon Sep 17 00:00:00 2001 From: Geoff Hutchison Date: Sat, 28 Jul 2018 00:30:40 -0400 Subject: [PATCH 14/68] Add two enhancements for JSON interfaces - Allow interfaces to have no options (e.g., workflows that just run) - Allow options to set labels different from the key (e.g., for translation purposes) Signed-off-by: Geoff Hutchison --- avogadro/qtgui/interfacewidget.cpp | 48 ++++++++++++++---------------- avogadro/qtgui/interfacewidget.h | 4 +++ 2 files changed, 27 insertions(+), 25 deletions(-) diff --git a/avogadro/qtgui/interfacewidget.cpp b/avogadro/qtgui/interfacewidget.cpp index 198fbe330a..c8cbb8f64b 100644 --- a/avogadro/qtgui/interfacewidget.cpp +++ b/avogadro/qtgui/interfacewidget.cpp @@ -1,17 +1,7 @@ /****************************************************************************** - This source file is part of the Avogadro project. - Copyright 2013 Kitware, Inc. - This source code is released under the New BSD License, (the "License"). - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - ******************************************************************************/ #include "interfacewidget.h" @@ -43,9 +33,7 @@ namespace QtGui { InterfaceWidget::InterfaceWidget(const QString& scriptFilePath, QWidget* parent_) - : QWidget(parent_) - , m_molecule(nullptr) - , m_interfaceScript(QString()) + : QWidget(parent_), m_molecule(nullptr), m_interfaceScript(QString()) { this->setInterfaceScript(scriptFilePath); } @@ -158,22 +146,24 @@ void InterfaceWidget::updateOptions() void InterfaceWidget::buildOptionGui() { - // Clear old widgets from the layout m_widgets.clear(); delete layout(); // kill my layout - QFormLayout* form = new QFormLayout; - setLayout(form); + m_empty = true; if (!m_options.contains(QStringLiteral("userOptions")) || !m_options[QStringLiteral("userOptions")].isObject()) { - showError(tr("'userOptions' missing, or not an object:\n%1") - .arg(QString(QJsonDocument(m_options).toJson()))); return; } + // Clear old widgets from the layout + QFormLayout* form = new QFormLayout; + setLayout(form); + QJsonObject userOptions = m_options.value(QStringLiteral("userOptions")).toObject(); + m_empty = false; + // Title first if (userOptions.contains(QStringLiteral("Title"))) addOptionRow(tr("Title"), userOptions.take(QStringLiteral("Title"))); @@ -254,7 +244,7 @@ void InterfaceWidget::buildOptionGui() } } -void InterfaceWidget::addOptionRow(const QString& label, +void InterfaceWidget::addOptionRow(const QString& name, const QJsonValue& option) { QWidget* widget = createOptionWidget(option); @@ -263,17 +253,25 @@ void InterfaceWidget::addOptionRow(const QString& label, QFormLayout* form = qobject_cast(this->layout()); if (!form) { - qWarning() << "Cannot add option" << label + qWarning() << "Cannot add option" << name << "to GUI -- layout is not a form."; widget->deleteLater(); return; } // For lookups during unit testing: - widget->setObjectName(label); + widget->setObjectName(name); + QString label(name); + + QJsonObject obj = option.toObject(); + + if (obj.contains(QStringLiteral("label")) && + obj.value(QStringLiteral("label")).isString()) { + label = obj[QStringLiteral("label")].toString(); + } form->addRow(label + ":", widget); - m_widgets.insert(label, widget); + m_widgets.insert(name, widget); } QWidget* InterfaceWidget::createOptionWidget(const QJsonValue& option) @@ -310,7 +308,7 @@ QWidget* InterfaceWidget::createStringListWidget(const QJsonObject& obj) { if (!obj.contains(QStringLiteral("values")) || !obj[QStringLiteral("values")].isArray()) { - qDebug() << "QuantumInputDialog::createStringListWidget()" + qDebug() << "InterfaceWidget::createStringListWidget()" "values missing, or not array!"; return nullptr; } @@ -438,8 +436,8 @@ void InterfaceWidget::setOptionDefaults() { if (!m_options.contains(QStringLiteral("userOptions")) || !m_options[QStringLiteral("userOptions")].isObject()) { - showError(tr("'userOptions' missing, or not an object:\n%1") - .arg(QString(QJsonDocument(m_options).toJson()))); + // showError(tr("'userOptions' missing, or not an object:\n%1") + // .arg(QString(QJsonDocument(m_options).toJson()))); return; } diff --git a/avogadro/qtgui/interfacewidget.h b/avogadro/qtgui/interfacewidget.h index 7d25818231..1eeccdd721 100644 --- a/avogadro/qtgui/interfacewidget.h +++ b/avogadro/qtgui/interfacewidget.h @@ -88,6 +88,9 @@ class AVOGADROQTGUI_EXPORT InterfaceWidget : public QWidget */ void applyOptions(const QJsonObject& opts); + bool isEmpty() const + { return m_empty; } + private slots: /** * Triggered when the user resets the default values. @@ -179,6 +182,7 @@ private slots: QJsonObject m_optionCache; // For reverting changes QList m_dirtyTextEdits; + bool m_empty; QMap m_widgets; QMap m_textEdits; From 6c43bf6f76fdbc98d7b96268ce8f6df390b2e6ec Mon Sep 17 00:00:00 2001 From: Geoff Hutchison Date: Sat, 28 Jul 2018 00:47:51 -0400 Subject: [PATCH 15/68] Fixup clang-format Signed-off-by: Geoff Hutchison --- avogadro/qtgui/interfacewidget.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/avogadro/qtgui/interfacewidget.h b/avogadro/qtgui/interfacewidget.h index 1eeccdd721..04a536244f 100644 --- a/avogadro/qtgui/interfacewidget.h +++ b/avogadro/qtgui/interfacewidget.h @@ -88,8 +88,7 @@ class AVOGADROQTGUI_EXPORT InterfaceWidget : public QWidget */ void applyOptions(const QJsonObject& opts); - bool isEmpty() const - { return m_empty; } + bool isEmpty() const { return m_empty; } private slots: /** From bf6e4d4a7fc9d645997130b99c1986fa5b147d31 Mon Sep 17 00:00:00 2001 From: Geoff Hutchison Date: Sat, 28 Jul 2018 17:47:06 -0400 Subject: [PATCH 16/68] Ensure inputMoleculeFormat works for workflows Not sure if this ever worked for generators, but I validated with an SDF exchange to RDKit's ETKDG conformer code. Signed-off-by: Geoff Hutchison --- avogadro/qtgui/interfacescript.cpp | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/avogadro/qtgui/interfacescript.cpp b/avogadro/qtgui/interfacescript.cpp index bbe21ee587..30f4bdd300 100644 --- a/avogadro/qtgui/interfacescript.cpp +++ b/avogadro/qtgui/interfacescript.cpp @@ -31,12 +31,12 @@ using QtGui::PythonScript; InterfaceScript::InterfaceScript(const QString& scriptFilePath_, QObject* parent_) : QObject(parent_), m_interpreter(new PythonScript(scriptFilePath_, this)), - m_moleculeExtension(QStringLiteral("cjson")) + m_moleculeExtension(QStringLiteral("Unknown")) {} InterfaceScript::InterfaceScript(QObject* parent_) : QObject(parent_), m_interpreter(new PythonScript(this)), - m_moleculeExtension(QStringLiteral("cjson")) + m_moleculeExtension(QStringLiteral("Unknown")) {} InterfaceScript::~InterfaceScript() {} @@ -75,14 +75,6 @@ QJsonObject InterfaceScript::options() const m_options = doc.object(); - // Check if the generator needs to read a molecule. - m_moleculeExtension = QLatin1String("cjson"); - if (m_options.contains(QStringLiteral("inputMoleculeFormat")) && - m_options[QStringLiteral("inputMoleculeFormat")].isString()) { - m_moleculeExtension = - m_options[QStringLiteral("inputMoleculeFormat")].toString(); - } - if (m_options.contains(QStringLiteral("highlightStyles")) && m_options.value(QStringLiteral("highlightStyles")).isArray()) { if (!parseHighlightStyles( @@ -92,6 +84,14 @@ QJsonObject InterfaceScript::options() const } } + // Check if the generator needs to read a molecule. + m_moleculeExtension = QLatin1String("cjson"); + if (m_options.contains(QStringLiteral("inputMoleculeFormat")) && + m_options[QStringLiteral("inputMoleculeFormat")].isString()) { + m_moleculeExtension = + m_options[QStringLiteral("inputMoleculeFormat")].toString(); + } + return m_options; } @@ -175,7 +175,6 @@ bool InterfaceScript::runWorkflow(const QJsonObject& options_, QJsonDocument doc; if (!parseJson(json, doc)) { - qDebug() << " can't parse "; return false; } @@ -236,7 +235,6 @@ bool InterfaceScript::runWorkflow(const QJsonObject& options_, } if (obj["append"].toBool()) { // just append some new bits - qDebug() << " appending " << newMol.atomCount(); guiMol->undoMolecule()->appendMolecule(newMol, m_displayName); } else { // replace the whole molecule Molecule::MoleculeChanges changes = (Molecule::Atoms | Molecule::Bonds | From 3af90c993fe3e9dfe381eec0631fdf40ddf5550b Mon Sep 17 00:00:00 2001 From: Adarsh Balasubramanian Date: Sun, 29 Jul 2018 15:39:11 +0530 Subject: [PATCH 17/68] Adding tabs for job script and molecule preview Signed-off-by: Adarsh Balasubramanian --- .../qtplugins/lammpsinput/lammpsinput.cpp | 11 +- .../lammpsinput/lammpsinputdialog.cpp | 342 ++++++++++++------ .../qtplugins/lammpsinput/lammpsinputdialog.h | 10 +- .../lammpsinput/lammpsinputdialog.ui | 41 +-- 4 files changed, 242 insertions(+), 162 deletions(-) diff --git a/avogadro/qtplugins/lammpsinput/lammpsinput.cpp b/avogadro/qtplugins/lammpsinput/lammpsinput.cpp index 36e239aeb1..03f41cb9f1 100644 --- a/avogadro/qtplugins/lammpsinput/lammpsinput.cpp +++ b/avogadro/qtplugins/lammpsinput/lammpsinput.cpp @@ -34,18 +34,17 @@ class Molecule; namespace QtPlugins { LammpsInput::LammpsInput(QObject* parent_) - : ExtensionPlugin(parent_) - , m_action(new QAction(this)) - , m_molecule(nullptr) - , m_dialog(nullptr) - , m_outputFormat(nullptr) + : ExtensionPlugin(parent_), m_action(new QAction(this)), m_molecule(nullptr), + m_dialog(nullptr), m_outputFormat(nullptr) { m_action->setEnabled(true); m_action->setText(tr("&LAMMPS Input")); connect(m_action, SIGNAL(triggered()), SLOT(menuActivated())); } -LammpsInput::~LammpsInput() {} +LammpsInput::~LammpsInput() +{ +} QList LammpsInput::actions() const { diff --git a/avogadro/qtplugins/lammpsinput/lammpsinputdialog.cpp b/avogadro/qtplugins/lammpsinput/lammpsinputdialog.cpp index f73e27ae7d..80e65ea545 100644 --- a/avogadro/qtplugins/lammpsinput/lammpsinputdialog.cpp +++ b/avogadro/qtplugins/lammpsinput/lammpsinputdialog.cpp @@ -20,15 +20,20 @@ #include #include +#include +#include + #include #include #include +#include #include #include #include #include +#include #include #include @@ -36,52 +41,28 @@ namespace Avogadro { namespace QtPlugins { LammpsInputDialog::LammpsInputDialog(QWidget* parent, Qt::WindowFlags flag) - : QDialog(parent, flag) - , m_molecule(nullptr) - , - - m_unitType(real) - , m_title("Title") - , m_savePath("") - , m_dimensionType(d3) - , m_xBoundaryType(p) - , m_yBoundaryType(p) - , m_zBoundaryType(p) - , - - m_atomStyle(full) - , - - m_waterPotential(NONE) - , - - m_ensemble(NVT) - , m_temperature(298.15) - , m_nhChain(1) - , - - m_timeStep(2.0) - , m_runSteps(50) - , m_xReplicate(1) - , m_yReplicate(1) - , m_zReplicate(1) - , - - m_dumpStep(1) - , - - m_velocityDist(gaussian) - , m_velocityTemp(298.15) - , m_zeroMOM(true) - , m_zeroL(true) - , m_thermoStyle(one) - , m_thermoInterval(50) - , - - m_output() - , m_dirty(false) - , m_warned(false) - , readData(false) + : QDialog(parent, flag), m_molecule(nullptr), + + m_unitType(real), m_title("Title"), m_savePath(""), m_dimensionType(d3), + m_xBoundaryType(p), m_yBoundaryType(p), m_zBoundaryType(p), + + m_atomStyle(full), + + m_waterPotential(NONE), + + m_ensemble(NVT), m_temperature(298.15), m_nhChain(1), + + m_timeStep(2.0), m_runSteps(50), m_xReplicate(1), m_yReplicate(1), + m_zReplicate(1), + + m_dumpStep(1), + + m_velocityDist(gaussian), m_velocityTemp(298.15), m_zeroMOM(true), + m_zeroL(true), m_thermoStyle(one), m_thermoInterval(50), + + m_output(), m_dirty(false), m_warned(false), readData(false), + + m_jobEdit(nullptr), m_moleculeEdit(nullptr) { ui.setupUi(this); // Connect the GUI elements to the correct slots @@ -133,12 +114,9 @@ LammpsInputDialog::LammpsInputDialog(QWidget* parent, Qt::WindowFlags flag) connect(ui.thermoSpin, SIGNAL(valueChanged(int)), this, SLOT(setThermoInterval(int))); - connect(ui.previewText, SIGNAL(cursorPositionChanged()), this, - SLOT(previewEdited())); connect(ui.generateButton, SIGNAL(clicked()), this, SLOT(generateClicked())); connect(ui.resetButton, SIGNAL(clicked()), this, SLOT(resetClicked())); - connect(ui.moreButton, SIGNAL(clicked()), this, SLOT(moreClicked())); connect(ui.enableFormButton, SIGNAL(clicked()), this, SLOT(enableFormClicked())); @@ -147,6 +125,7 @@ LammpsInputDialog::LammpsInputDialog(QWidget* parent, Qt::WindowFlags flag) // Generate an initial preview of the input deck updatePreviewText(); + addMoleculeDataTab(); } LammpsInputDialog::~LammpsInputDialog() @@ -158,41 +137,82 @@ LammpsInputDialog::~LammpsInputDialog() void LammpsInputDialog::showEvent(QShowEvent*) { updatePreviewText(); + addMoleculeDataTab(); } void LammpsInputDialog::updatePreviewText() { if (!isVisible()) return; + + int jobTabPosition = 0; + + // Store the currently displayed tab + int currIndex = ui.tabWidget->currentIndex(); + // Generate the input deck and display it - if (m_dirty && !m_warned) { - m_warned = true; - QMessageBox msgBox; - - msgBox.setWindowTitle(tr("Lammps Input Deck Generator Warning")); - msgBox.setText(tr("Would you like to update the preview text, losing all " - "changes made in the Lammps input deck preview pane?")); - msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); - - switch (msgBox.exec()) { - case QMessageBox::Yes: - // yes was clicked - deckDirty(false); - ui.previewText->setText(generateInputDeck()); - ui.previewText->document()->setModified(false); - m_warned = false; - break; - case QMessageBox::No: - // no was clicked - m_warned = false; - break; - default: - // should never be reached - break; + if (m_dirty) { + QString message = + tr("Would you like to update the preview text, losing all " + "changes made in the Lammps input deck preview pane?"); + int response = QMessageBox::question( + this, tr("Overwrite modified input files?"), message, + QMessageBox::Yes | QMessageBox::No, QMessageBox::No); + + if (static_cast(response) == QMessageBox::No) { + return; + } + } + + ui.tabWidget->removeTab(jobTabPosition); + + m_jobFileName = + (ui.baseNameEdit->text().isEmpty() ? ui.baseNameEdit->placeholderText() + : ui.baseNameEdit->text()) + + ".lmp"; + m_jobEdit = new QTextEdit(this); + m_jobEdit->setObjectName(m_jobFileName); + m_jobEdit->setFontFamily("monospace"); + connect(m_jobEdit, SIGNAL(textChanged()), this, SLOT(textEditModified())); + m_jobEdit->setText(generateInputDeck()); + ui.tabWidget->insertTab(jobTabPosition, m_jobEdit, m_jobFileName); + deckDirty(false); + + // Restore current tab + ui.tabWidget->setCurrentIndex(currIndex); +} + +void LammpsInputDialog::addMoleculeDataTab() +{ + int molTabPosition = 1; + if (m_molecule) { + ui.tabWidget->removeTab(molTabPosition); + std::string molOutput, extension = "lmpdat"; + m_moleculeFileName = + (ui.baseNameEdit->text().isEmpty() ? ui.baseNameEdit->placeholderText() + : ui.baseNameEdit->text()) + + "." + QString::fromStdString(extension); + bool writeSDF = Io::FileFormatManager::instance().writeString( + *m_molecule, molOutput, extension); + if (writeSDF) { + m_moleculeEdit = new QTextEdit(this); + m_moleculeEdit->setObjectName(m_moleculeFileName); + m_moleculeEdit->setFontFamily("monospace"); + m_moleculeEdit->setText(QString::fromStdString(molOutput)); + ui.tabWidget->insertTab(molTabPosition, m_moleculeEdit, + m_moleculeFileName); + } + } +} + +void LammpsInputDialog::textEditModified() +{ + if (QTextEdit* edit = qobject_cast(sender())) { + if (edit->document()->isModified()) { + deckDirty(true); + } else { + deckDirty(false); } - } else if (!m_dirty) { - ui.previewText->setText(generateInputDeck()); - ui.previewText->document()->setModified(false); } } @@ -220,55 +240,146 @@ void LammpsInputDialog::resetClicked() ui.thermoStyleCombo->setCurrentIndex(0); ui.thermoSpin->setValue(50); - ui.previewText->setText(generateInputDeck()); - ui.previewText->document()->setModified(false); + updatePreviewText(); + addMoleculeDataTab(); } void LammpsInputDialog::generateClicked() { QSettings settings; - QString fileName = - (ui.baseNameEdit->text().isEmpty() ? ui.baseNameEdit->placeholderText() - : ui.baseNameEdit->text()) + - ".lmp"; - QString targetFile = + QString directory = settings.value("lammpsInput/outputDirectory", QDir::homePath()).toString(); - targetFile = - QDir(QFileInfo(targetFile).absoluteDir()).absoluteFilePath(fileName); - - fileName = QFileDialog::getSaveFileName(this, tr("Save LAMMPS input file"), - targetFile); + if (directory.isEmpty()) + directory = QDir::homePath(); + directory = QFileDialog::getExistingDirectory( + this, tr("Select output directory"), directory); // User cancel: - if (fileName.isNull()) + if (directory.isNull()) return; - settings.setValue("lammpsInput/outputDirectory", fileName); + settings.setValue("lammpsInput/outputDirectory", directory); + QDir dir(directory); - QFile file(fileName); - bool success = false; - if (file.open(QFile::WriteOnly | QFile::Text)) { - if (file.write(ui.previewText->toPlainText().toLocal8Bit()) > 0) { - success = true; + // Check for problems: + QStringList errors; + bool fatalError = false; + + do { // Do/while to break on fatal errors + if (!dir.exists()) { + errors << tr("%1: Directory does not exist!").arg(dir.absolutePath()); + fatalError = true; + break; + } + + if (!dir.isReadable()) { + errors << tr("%1: Directory cannot be read!").arg(dir.absolutePath()); + fatalError = true; + break; + } + + QFileInfo jobFileInfo(dir.absoluteFilePath(m_jobFileName)); + + if (jobFileInfo.exists()) { + errors << tr("%1: File will be overwritten.") + .arg(jobFileInfo.absoluteFilePath()); + } + + // Attempt to open the file for writing + if (!QFile(jobFileInfo.absoluteFilePath()).open(QFile::WriteOnly)) { + errors + << tr("%1: File is not writable.").arg(jobFileInfo.absoluteFilePath()); + fatalError = true; + break; + } + + QFileInfo molFileInfo(dir.absoluteFilePath(m_moleculeFileName)); + + if (molFileInfo.exists()) { + errors << tr("%1: File will be overwritten.") + .arg(molFileInfo.absoluteFilePath()); + } + + // Attempt to open the file for writing + if (!QFile(molFileInfo.absoluteFilePath()).open(QFile::WriteOnly)) { + errors + << tr("%1: File is not writable.").arg(molFileInfo.absoluteFilePath()); + fatalError = true; + break; + } + } while (false); // only run once + + // Handle fatal errors: + if (fatalError) { + QString formattedError; + switch (errors.size()) { + case 0: + formattedError = + tr("The input files cannot be written due to an unknown error."); + break; + case 1: + formattedError = + tr("The input files cannot be written:\n\n%1").arg(errors.first()); + break; + default: { + // If a fatal error occured, it will be last one in the list. Pop it off + // and tell the user that it was the reason we had to stop. + QString fatal = errors.last(); + QStringList tmp(errors); + tmp.pop_back(); + formattedError = + tr("The input files cannot be written:\n\n%1\n\nWarnings:\n\n%2") + .arg(fatal, tmp.join("\n")); + break; + } } - file.close(); + QMessageBox::critical(this, tr("Output Error"), formattedError); + return; } - if (!success) { - QMessageBox::critical(this, tr("Output Error"), - tr("Failed to write to file %1.").arg(fileName)); + // Non-fatal errors: + if (!errors.isEmpty()) { + QString formattedError = tr("Warning:\n\n%1\n\nWould you like to continue?") + .arg(errors.join("\n")); + + QMessageBox::StandardButton reply = + QMessageBox::warning(this, tr("Write input files"), formattedError, + QMessageBox::Yes | QMessageBox::No, QMessageBox::No); + + if (reply != QMessageBox::Yes) + return; } -} -void LammpsInputDialog::moreClicked() -{ - // If the more button is clicked hide/show the preview text - if (ui.previewText->isVisible()) { - ui.previewText->hide(); - ui.moreButton->setText(tr("Show Preview")); - } else { - ui.previewText->show(); - ui.moreButton->setText(tr("Hide Preview")); + bool success = false; + + if (m_jobEdit && m_moleculeEdit) { + QFile jobFile(dir.absoluteFilePath(m_jobFileName)); + if (jobFile.open(QFile::WriteOnly | QFile::Text)) { + if (jobFile.write(m_jobEdit->toPlainText().toLocal8Bit()) > 0) { + success = true; + } + jobFile.close(); + } + + if (!success) { + QMessageBox::critical( + this, tr("Output Error"), + tr("Failed to write to file %1.").arg(jobFile.fileName())); + } + + QFile molFile(dir.absoluteFilePath(m_moleculeFileName)); + if (molFile.open(QFile::WriteOnly | QFile::Text)) { + if (molFile.write(m_moleculeEdit->toPlainText().toLocal8Bit()) > 0) { + success = true; + } + molFile.close(); + } + + if (!success) { + QMessageBox::critical( + this, tr("Output Error"), + tr("Failed to write to file %1.").arg(molFile.fileName())); + } } } @@ -277,13 +388,6 @@ void LammpsInputDialog::enableFormClicked() updatePreviewText(); } -void LammpsInputDialog::previewEdited() -{ - // Determine if the preview text has changed from the form generated - if (ui.previewText->document()->isModified()) - deckDirty(true); -} - void LammpsInputDialog::setTitle() { m_title = ui.titleLine->text(); @@ -512,7 +616,7 @@ QString LammpsInputDialog::generateInputDeck() QString buffer; QTextStream mol(&buffer); - mol << "#LAMMPS Input file generated by Avogadro\n"; + mol << "# LAMMPS Input file generated by Avogadro\n"; mol << "# " << m_title << "\n\n"; mol << "# Intialization\n"; @@ -706,7 +810,7 @@ QString LammpsInputDialog::getWaterPotential(waterPotential t) int Hydrogen; int Oxygen; determineAtomTypesSPC(Hydrogen, Oxygen); - water << "#The SPC water potential\n" + water << "# The SPC water potential\n" << "pair_style lj/cut/coul/cut 9.8 9.8\n" << "pair_coeff " << Oxygen << " " << Oxygen << " 0.15535 3.5533\n" @@ -728,7 +832,7 @@ QString LammpsInputDialog::getWaterPotential(waterPotential t) int Hydrogen; int Oxygen; determineAtomTypesSPC(Hydrogen, Oxygen); - water << "#The SPC/E water potential\n" + water << "# The SPC/E water potential\n" << "pair_style lj/cut/coul/long 9.8 9.8\n" << "kspace_style pppm 1.0e-4\n" << "pair_coeff " << Oxygen << " " << Oxygen diff --git a/avogadro/qtplugins/lammpsinput/lammpsinputdialog.h b/avogadro/qtplugins/lammpsinput/lammpsinputdialog.h index 2d5a01a2d1..c9a5fee039 100644 --- a/avogadro/qtplugins/lammpsinput/lammpsinputdialog.h +++ b/avogadro/qtplugins/lammpsinput/lammpsinputdialog.h @@ -23,6 +23,7 @@ #include class QJsonObject; +class QTextEdit; namespace Avogadro { namespace QtGui { @@ -150,6 +151,11 @@ class LammpsInputDialog : public QDialog bool m_warned; bool readData; + QTextEdit* m_jobEdit; + QTextEdit* m_moleculeEdit; + QString m_moleculeFileName; + QString m_jobFileName; + // Generate an input deck as a string QString generateInputDeck(); QString getUnitType(unitType t); @@ -173,6 +179,7 @@ class LammpsInputDialog : public QDialog // Enable/disable form elements void deckDirty(bool); void determineAtomTypesSPC(int& hyd, int& oxy); + void addMoleculeDataTab(); // system typing QHash AtomType; @@ -184,11 +191,10 @@ public Q_SLOTS: private Q_SLOTS: //! Button Slots + void textEditModified(); void resetClicked(); void generateClicked(); void enableFormClicked(); - void moreClicked(); - void previewEdited(); void setTitle(); void setReadData(); diff --git a/avogadro/qtplugins/lammpsinput/lammpsinputdialog.ui b/avogadro/qtplugins/lammpsinput/lammpsinputdialog.ui index 20a5a1b640..d32cdcd814 100644 --- a/avogadro/qtplugins/lammpsinput/lammpsinputdialog.ui +++ b/avogadro/qtplugins/lammpsinput/lammpsinputdialog.ui @@ -895,44 +895,15 @@ p, li { white-space: pre-wrap; } - - - - - 0 - 0 - - - - Hide Preview - - - - - - true - - - - Monospace - 12 - - - - false - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Monospace'; font-size:12pt; font-weight:400; font-style:normal;"> -<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Courier New,courier'; font-size:10pt;"></p></body></html> - - - false + + + + 0 + 0 + From 27a9cc7ffd00836f41951bf33918ee1789e1d5b6 Mon Sep 17 00:00:00 2001 From: Adarsh Balasubramanian Date: Thu, 2 Aug 2018 04:41:34 +0530 Subject: [PATCH 18/68] Adding the corresponding Molecule class functions to RWMolecule Signed-off-by: Adarsh Balasubramanian --- avogadro/qtgui/rwmolecule.cpp | 232 ++++++++++++++++++++-------------- avogadro/qtgui/rwmolecule.h | 34 +++-- 2 files changed, 161 insertions(+), 105 deletions(-) diff --git a/avogadro/qtgui/rwmolecule.cpp b/avogadro/qtgui/rwmolecule.cpp index c4762c0110..9632349f44 100644 --- a/avogadro/qtgui/rwmolecule.cpp +++ b/avogadro/qtgui/rwmolecule.cpp @@ -45,10 +45,7 @@ using Core::UnitCell; class RWMolecule::UndoCommand : public QUndoCommand { public: - UndoCommand(RWMolecule& m) - : QUndoCommand(tr("Modify Molecule")) - , m_mol(m) - {} + UndoCommand(RWMolecule& m) : QUndoCommand(tr("Modify Molecule")), m_mol(m) {} protected: Array& atomUniqueIds() { return m_mol.m_molecule.atomUniqueIds(); } @@ -71,6 +68,7 @@ class RWMolecule::UndoCommand : public QUndoCommand return m_mol.m_molecule.bondPairs(); } Array& bondOrders() { return m_mol.m_molecule.bondOrders(); } + Array& forceVectors() { return m_mol.m_molecule.forceVectors(); } RWMolecule& m_mol; }; @@ -79,6 +77,7 @@ enum MergeIds { SetPositions3dMergeId = 0, SetPosition3dMergeId, + SetForceVectorMergeId, SetBondOrderMergeId }; @@ -88,25 +87,20 @@ enum MergeIds // To add a new class, add a new entry to the MergeIds enum above and use that // symbolic value as the template parameter. Implement the mergeWith() method // to update the "after" state. See SetPositions3dCommand for an example. -template +template class MergeUndoCommand : public RWMolecule::UndoCommand { bool m_canMerge; public: - MergeUndoCommand(RWMolecule& m) - : UndoCommand(m) - , m_canMerge(false) - {} + MergeUndoCommand(RWMolecule& m) : UndoCommand(m), m_canMerge(false) {} void setCanMerge(bool merge) { m_canMerge = merge; } bool canMerge() const { return m_canMerge; } int id() const override { return m_canMerge ? Id : -1; } }; -} // end anon namespace +} // namespace -RWMolecule::RWMolecule(Molecule& mol, QObject* p) - : QObject(p) - , m_molecule(mol) +RWMolecule::RWMolecule(Molecule& mol, QObject* p) : QObject(p), m_molecule(mol) {} RWMolecule::~RWMolecule() {} @@ -122,11 +116,8 @@ class AddAtomCommand : public RWMolecule::UndoCommand public: AddAtomCommand(RWMolecule& m, unsigned char aN, bool usingPositions, Index atomId, Index uid) - : UndoCommand(m) - , m_atomicNumber(aN) - , m_usingPositions(usingPositions) - , m_atomId(atomId) - , m_uniqueId(uid) + : UndoCommand(m), m_atomicNumber(aN), m_usingPositions(usingPositions), + m_atomId(atomId), m_uniqueId(uid) {} void redo() override @@ -149,7 +140,7 @@ class AddAtomCommand : public RWMolecule::UndoCommand atomUniqueIds()[m_uniqueId] = MaxIndex; } }; -} // end anon namespace +} // namespace RWMolecule::AtomType RWMolecule::addAtom(unsigned char num, bool usingPositions) { @@ -190,11 +181,8 @@ class RemoveAtomCommand : public RWMolecule::UndoCommand public: RemoveAtomCommand(RWMolecule& m, Index atomId, Index uid, unsigned char aN, const Vector3& pos) - : UndoCommand(m) - , m_atomId(atomId) - , m_atomUid(uid) - , m_atomicNumber(aN) - , m_position3d(pos) + : UndoCommand(m), m_atomId(atomId), m_atomUid(uid), m_atomicNumber(aN), + m_position3d(pos) {} void redo() override @@ -270,7 +258,7 @@ class RemoveAtomCommand : public RWMolecule::UndoCommand atomUniqueIds()[m_atomUid] = m_atomId; } }; -} // end anon namespace +} // namespace bool RWMolecule::removeAtom(Index atomId) { @@ -344,16 +332,15 @@ class SetAtomicNumbersCommand : public RWMolecule::UndoCommand SetAtomicNumbersCommand(RWMolecule& m, const Core::Array& oldAtomicNumbers, const Core::Array& newAtomicNumbers) - : UndoCommand(m) - , m_oldAtomicNumbers(oldAtomicNumbers) - , m_newAtomicNumbers(newAtomicNumbers) + : UndoCommand(m), m_oldAtomicNumbers(oldAtomicNumbers), + m_newAtomicNumbers(newAtomicNumbers) {} void redo() override { atomicNumbers() = m_newAtomicNumbers; } void undo() override { atomicNumbers() = m_oldAtomicNumbers; } }; -} // end anon namespace +} // namespace bool RWMolecule::setAtomicNumbers(const Core::Array& nums) { @@ -378,17 +365,15 @@ class SetAtomicNumberCommand : public RWMolecule::UndoCommand SetAtomicNumberCommand(RWMolecule& m, Index atomId, unsigned char oldAtomicNumber, unsigned char newAtomicNumber) - : UndoCommand(m) - , m_atomId(atomId) - , m_oldAtomicNumber(oldAtomicNumber) - , m_newAtomicNumber(newAtomicNumber) + : UndoCommand(m), m_atomId(atomId), m_oldAtomicNumber(oldAtomicNumber), + m_newAtomicNumber(newAtomicNumber) {} void redo() override { atomicNumbers()[m_atomId] = m_newAtomicNumber; } void undo() override { atomicNumbers()[m_atomId] = m_oldAtomicNumber; } }; -} // end anon namespace +} // namespace bool RWMolecule::setAtomicNumber(Index atomId, unsigned char num) { @@ -412,9 +397,8 @@ class SetPositions3dCommand : public MergeUndoCommand SetPositions3dCommand(RWMolecule& m, const Core::Array& oldPositions3d, const Core::Array& newPositions3d) - : MergeUndoCommand(m) - , m_oldPositions3d(oldPositions3d) - , m_newPositions3d(newPositions3d) + : MergeUndoCommand(m), + m_oldPositions3d(oldPositions3d), m_newPositions3d(newPositions3d) {} void redo() override { positions3d() = m_newPositions3d; } @@ -432,7 +416,7 @@ class SetPositions3dCommand : public MergeUndoCommand return false; } }; -} // end anon namespace +} // namespace bool RWMolecule::setAtomPositions3d(const Core::Array& pos, const QString& undoText) @@ -459,10 +443,8 @@ class SetPosition3dCommand : public MergeUndoCommand SetPosition3dCommand(RWMolecule& m, Index atomId, const Vector3& oldPosition3d, const Vector3& newPosition3d) - : MergeUndoCommand(m) - , m_atomIds(1, atomId) - , m_oldPosition3ds(1, oldPosition3d) - , m_newPosition3ds(1, newPosition3d) + : MergeUndoCommand(m), m_atomIds(1, atomId), + m_oldPosition3ds(1, oldPosition3d), m_newPosition3ds(1, newPosition3d) {} void redo() override @@ -515,7 +497,7 @@ class SetPosition3dCommand : public MergeUndoCommand return true; } }; -} // end anon namespace +} // namespace bool RWMolecule::setAtomPosition3d(Index atomId, const Vector3& pos, const QString& undoText) @@ -557,17 +539,15 @@ class SetAtomHybridizationCommand : public RWMolecule::UndoCommand SetAtomHybridizationCommand(RWMolecule& m, Index atomId, Core::AtomHybridization oldHybridization, Core::AtomHybridization newHybridization) - : UndoCommand(m) - , m_atomId(atomId) - , m_oldHybridization(oldHybridization) - , m_newHybridization(newHybridization) + : UndoCommand(m), m_atomId(atomId), m_oldHybridization(oldHybridization), + m_newHybridization(newHybridization) {} void redo() override { hybridizations()[m_atomId] = m_newHybridization; } void undo() override { hybridizations()[m_atomId] = m_oldHybridization; } }; -} // end anon namespace +} // namespace bool RWMolecule::setHybridization(Index atomId, Core::AtomHybridization hyb) { @@ -591,17 +571,15 @@ class SetAtomFormalChargeCommand : public RWMolecule::UndoCommand public: SetAtomFormalChargeCommand(RWMolecule& m, Index atomId, signed char oldCharge, signed char newCharge) - : UndoCommand(m) - , m_atomId(atomId) - , m_oldCharge(oldCharge) - , m_newCharge(newCharge) + : UndoCommand(m), m_atomId(atomId), m_oldCharge(oldCharge), + m_newCharge(newCharge) {} void redo() override { formalCharges()[m_atomId] = m_newCharge; } void undo() override { formalCharges()[m_atomId] = m_oldCharge; } }; -} // end anon namespace +} // namespace bool RWMolecule::setFormalCharge(Index atomId, signed char charge) { @@ -627,11 +605,8 @@ class AddBondCommand : public RWMolecule::UndoCommand AddBondCommand(RWMolecule& m, unsigned char order, const std::pair& bondPair, Index bondId, Index uid) - : UndoCommand(m) - , m_bondOrder(order) - , m_bondPair(bondPair) - , m_bondId(bondId) - , m_uniqueId(uid) + : UndoCommand(m), m_bondOrder(order), m_bondPair(bondPair), + m_bondId(bondId), m_uniqueId(uid) {} void redo() override @@ -662,7 +637,7 @@ inline std::pair makeBondPair(Index a, Index b) { return a < b ? std::make_pair(a, b) : std::make_pair(b, a); } -} // end anon namespace +} // namespace RWMolecule::BondType RWMolecule::addBond(Index atom1, Index atom2, unsigned char order) @@ -701,11 +676,8 @@ class RemoveBondCommand : public RWMolecule::UndoCommand RemoveBondCommand(RWMolecule& m, Index bondId, Index bondUid, const std::pair& bondPair, unsigned char bondOrder) - : UndoCommand(m) - , m_bondId(bondId) - , m_bondUid(bondUid) - , m_bondPair(bondPair) - , m_bondOrder(bondOrder) + : UndoCommand(m), m_bondId(bondId), m_bondUid(bondUid), + m_bondPair(bondPair), m_bondOrder(bondOrder) {} void redo() override @@ -751,7 +723,7 @@ class RemoveBondCommand : public RWMolecule::UndoCommand bondUniqueIds()[m_bondUid] = m_bondId; } }; -} // end anon namespace +} // namespace bool RWMolecule::removeBond(Index bondId) { @@ -789,16 +761,15 @@ class SetBondOrdersCommand : public RWMolecule::UndoCommand public: SetBondOrdersCommand(RWMolecule& m, const Array& oldBondOrders, const Array& newBondOrders) - : UndoCommand(m) - , m_oldBondOrders(oldBondOrders) - , m_newBondOrders(newBondOrders) + : UndoCommand(m), m_oldBondOrders(oldBondOrders), + m_newBondOrders(newBondOrders) {} void redo() override { bondOrders() = m_newBondOrders; } void undo() override { bondOrders() = m_oldBondOrders; } }; -} // end anon namespace +} // namespace bool RWMolecule::setBondOrders(const Core::Array& orders) { @@ -822,10 +793,8 @@ class SetBondOrderCommand : public MergeUndoCommand public: SetBondOrderCommand(RWMolecule& m, Index bondId, unsigned char oldBondOrder, unsigned char newBondOrder) - : MergeUndoCommand(m) - , m_bondId(bondId) - , m_oldBondOrder(oldBondOrder) - , m_newBondOrder(newBondOrder) + : MergeUndoCommand(m), m_bondId(bondId), + m_oldBondOrder(oldBondOrder), m_newBondOrder(newBondOrder) {} void redo() override { bondOrders()[m_bondId] = m_newBondOrder; } @@ -844,7 +813,7 @@ class SetBondOrderCommand : public MergeUndoCommand return false; } }; -} // end anon namespace +} // namespace bool RWMolecule::setBondOrder(Index bondId, unsigned char order) { @@ -870,16 +839,14 @@ class SetBondPairsCommand : public RWMolecule::UndoCommand SetBondPairsCommand(RWMolecule& m, const Array>& oldBondPairs, const Array>& newBondPairs) - : UndoCommand(m) - , m_oldBondPairs(oldBondPairs) - , m_newBondPairs(newBondPairs) + : UndoCommand(m), m_oldBondPairs(oldBondPairs), m_newBondPairs(newBondPairs) {} void redo() override { bondPairs() = m_newBondPairs; } void undo() override { bondPairs() = m_oldBondPairs; } }; -} // end anon namespace +} // namespace bool RWMolecule::setBondPairs(const Array>& pairs) { @@ -914,17 +881,15 @@ class SetBondPairCommand : public RWMolecule::UndoCommand SetBondPairCommand(RWMolecule& m, Index bondId, const std::pair& oldBondPair, const std::pair& newBondPair) - : UndoCommand(m) - , m_bondId(bondId) - , m_oldBondPair(oldBondPair) - , m_newBondPair(newBondPair) + : UndoCommand(m), m_bondId(bondId), m_oldBondPair(oldBondPair), + m_newBondPair(newBondPair) {} void redo() override { bondPairs()[m_bondId] = m_newBondPair; } void undo() override { bondPairs()[m_bondId] = m_oldBondPair; } }; -} // end anon namespace +} // namespace bool RWMolecule::setBondPair(Index bondId, const std::pair& pair) { @@ -951,8 +916,7 @@ class AddUnitCellCommand : public RWMolecule::UndoCommand public: AddUnitCellCommand(RWMolecule& m, const UnitCell& newUnitCell) - : UndoCommand(m) - , m_newUnitCell(newUnitCell) + : UndoCommand(m), m_newUnitCell(newUnitCell) {} void redo() override @@ -962,7 +926,7 @@ class AddUnitCellCommand : public RWMolecule::UndoCommand void undo() override { m_mol.molecule().setUnitCell(nullptr); } }; -} // end anon namespace +} // namespace void RWMolecule::addUnitCell() { @@ -991,8 +955,7 @@ class RemoveUnitCellCommand : public RWMolecule::UndoCommand public: RemoveUnitCellCommand(RWMolecule& m, const UnitCell& oldUnitCell) - : UndoCommand(m) - , m_oldUnitCell(oldUnitCell) + : UndoCommand(m), m_oldUnitCell(oldUnitCell) {} void redo() override { m_mol.molecule().setUnitCell(nullptr); } @@ -1002,7 +965,7 @@ class RemoveUnitCellCommand : public RWMolecule::UndoCommand m_mol.molecule().setUnitCell(new UnitCell(m_oldUnitCell)); } }; -} // end anon namespace +} // namespace void RWMolecule::removeUnitCell() { @@ -1028,16 +991,14 @@ class ModifyMoleculeCommand : public RWMolecule::UndoCommand public: ModifyMoleculeCommand(RWMolecule& m, const Molecule& oldMolecule, const Molecule& newMolecule) - : UndoCommand(m) - , m_oldMolecule(oldMolecule) - , m_newMolecule(newMolecule) + : UndoCommand(m), m_oldMolecule(oldMolecule), m_newMolecule(newMolecule) {} void redo() override { m_mol.molecule() = m_newMolecule; } void undo() override { m_mol.molecule() = m_oldMolecule; } }; -} // end anon namespace +} // namespace void RWMolecule::modifyMolecule(const Molecule& newMolecule, Molecule::MoleculeChanges changes, @@ -1336,5 +1297,90 @@ Index RWMolecule::findBondUniqueId(Index bondId) const return m_molecule.findBondUniqueId(bondId); } +namespace { +class SetForceVectorCommand : public MergeUndoCommand +{ + Array m_atomIds; + Array m_oldForceVectors; + Array m_newForceVectors; + +public: + SetForceVectorCommand(RWMolecule& m, Index atomId, + const Vector3& oldForceVector, + const Vector3& newForceVector) + : MergeUndoCommand(m), m_atomIds(1, atomId), + m_oldForceVectors(1, oldForceVector), m_newForceVectors(1, newForceVector) + {} + + void redo() override + { + for (size_t i = 0; i < m_atomIds.size(); ++i) + forceVectors()[m_atomIds[i]] = m_newForceVectors[i]; + } + + void undo() override + { + for (size_t i = 0; i < m_atomIds.size(); ++i) + forceVectors()[m_atomIds[i]] = m_oldForceVectors[i]; + } + + bool mergeWith(const QUndoCommand* o) override + { + const SetForceVectorCommand* other = + dynamic_cast(o); + if (!other) + return false; + + size_t numAtoms = other->m_atomIds.size(); + if (numAtoms != other->m_oldForceVectors.size() || + numAtoms != other->m_newForceVectors.size()) { + return false; + } + + for (size_t i = 0; i < numAtoms; ++i) { + const Index& atomId = other->m_atomIds[i]; + const Vector3& oldPos = other->m_oldForceVectors[i]; + const Vector3& newPos = other->m_newForceVectors[i]; + + Array::const_iterator idsBegin = m_atomIds.begin(); + Array::const_iterator idsEnd = m_atomIds.end(); + Array::const_iterator match = std::find(idsBegin, idsEnd, atomId); + + if (match == idsEnd) { + // Append a new atom: + m_atomIds.push_back(atomId); + m_oldForceVectors.push_back(oldPos); + m_newForceVectors.push_back(newPos); + } else { + // Overwrite the existing movement: + size_t offset = std::distance(idsBegin, match); + assert(m_atomIds[offset] == atomId); + m_newForceVectors[offset] = newPos; + } + } + + return true; + } +}; +} // namespace + +bool RWMolecule::setForceVector(Index atomId, const Vector3& forces, + const QString& undoText) +{ + if (atomId >= atomCount()) + return false; + + if (m_molecule.m_positions3d.size() != m_molecule.m_atomicNumbers.size()) + m_molecule.m_positions3d.resize(m_molecule.m_atomicNumbers.size(), + Vector3::Zero()); + + SetForceVectorCommand* comm = new SetForceVectorCommand( + *this, atomId, m_molecule.m_positions3d[atomId], forces); + comm->setText(undoText); + comm->setCanMerge(m_interactive); + m_undoStack.push(comm); + return true; +} + } // namespace QtGui } // namespace Avogadro diff --git a/avogadro/qtgui/rwmolecule.h b/avogadro/qtgui/rwmolecule.h index ffb87e3417..843d0e958f 100644 --- a/avogadro/qtgui/rwmolecule.h +++ b/avogadro/qtgui/rwmolecule.h @@ -607,6 +607,19 @@ class AVOGADROQTGUI_EXPORT RWMolecule : public QObject class UndoCommand; friend class UndoCommand; + /** Returns a vector of forces for the atoms in the molecule. */ + const Core::Array& forceVectors() const; + + /** + * Replace the current array of force vectors. + * @param pos The new force vector array. Must be of length atomCount(). + * @param undoText The undo text to be displayed for undo commands. + * @return True on success, false otherwise. + */ + bool setForceVector( + Index atomId, const Vector3& pos, + const QString& undoText = QStringLiteral("Change Force Vectors")); + public slots: /** * @brief Force the molecule to emit the changed() signal. @@ -644,23 +657,15 @@ public slots: class AVOGADROQTGUI_EXPORT RWAtom : public Core::AtomTemplate { public: - RWAtom() - : Core::AtomTemplate() - {} - RWAtom(RWMolecule* m, Index i) - : Core::AtomTemplate(m, i) - {} + RWAtom() : Core::AtomTemplate() {} + RWAtom(RWMolecule* m, Index i) : Core::AtomTemplate(m, i) {} }; class AVOGADROQTGUI_EXPORT RWBond : public Core::BondTemplate { public: - RWBond() - : Core::BondTemplate() - {} - RWBond(RWMolecule* m, Index i) - : Core::BondTemplate(m, i) - {} + RWBond() : Core::BondTemplate() {} + RWBond(RWMolecule* m, Index i) : Core::BondTemplate(m, i) {} }; inline RWMolecule::AtomType RWMolecule::atom(Index atomId) const @@ -858,6 +863,11 @@ inline const QUndoStack& RWMolecule::undoStack() const return m_undoStack; } +inline const Core::Array& RWMolecule::forceVectors() const +{ + return m_molecule.forceVectors(); +} + } // namespace QtGui } // namespace Avogadro From 11699b972304a632ff2178258cfcad5158c82f9e Mon Sep 17 00:00:00 2001 From: Geoff Hutchison Date: Thu, 2 Aug 2018 17:06:12 -0400 Subject: [PATCH 19/68] Manually add in non-standard residues Signed-off-by: Geoff Hutchison --- avogadro/core/residuedata.h | 85 +++++++++++++++++++++++++++++++++++++ scripts/getresdata.py | 35 ++++++++++++--- 2 files changed, 113 insertions(+), 7 deletions(-) diff --git a/avogadro/core/residuedata.h b/avogadro/core/residuedata.h index 0055e49b2e..fa0ba72086 100644 --- a/avogadro/core/residuedata.h +++ b/avogadro/core/residuedata.h @@ -1275,6 +1275,88 @@ ResidueData PGEData("PGE", { "C5", "H5" }, { "C5", "H52" } }, // Double Bonds {}); + +ResidueData ASHData("ASH", + // Atoms + { "CA", "N", "CB", "C", "O", "CG", "OD2", "OD1" }, + // Single Bonds + { { "CA", "N" }, + { "CA", "CB" }, + { "CA", "C" }, + { "CB", "CG" }, + { "CG", "OD2" }, + { "N", "H" }, + { "N", "HN" }, + { "OD2", "HD2" } }, + // Double Bonds + { { "C", "O" }, { "CG", "OD1" } }); + +ResidueData CYXData("CYX", + // Atoms + { "CA", "N", "CB", "C", "O", "SG" }, + // Single Bonds + { { "CA", "N" }, + { "CA", "CB" }, + { "CA", "C" }, + { "CB", "SG" }, + { "N", "H" } }, + // Double Bonds + { { "C", "O" } }); + +ResidueData HIPData("HIP", + // Atoms + { "CA", "N", "CB", "C", "O", "CG", "ND1", "CD2", "NE2", + "CE1" }, + // Single Bonds + { { "CA", "N" }, + { "CA", "CB" }, + { "CA", "C" }, + { "CB", "CG" }, + { "CG", "ND1" }, + { "CD2", "NE2" }, + { "NE2", "CE1" }, + { "CE1", "ND1" }, + { "N", "H" }, + { "ND1", "HD1" }, + { "NE2", "HE2" } }, + // Double Bonds + { { "C", "O" }, { "CG", "CD2" } }); + +ResidueData HIDData("HID", + // Atoms + { "CA", "N", "CB", "C", "O", "CG", "ND1", "CD2", "NE2", + "CE1" }, + // Single Bonds + { { "CA", "N" }, + { "CA", "CB" }, + { "CA", "C" }, + { "CB", "CG" }, + { "CG", "ND1" }, + { "CD2", "NE2" }, + { "CE1", "ND1" }, + { "N", "H" }, + { "ND1", "HD1" } }, + // Double Bonds + { { "C", "O" }, { "CG", "CD2" }, { "NE2", "CE1" } }); + +ResidueData HIEData("HIE", + // Atoms + { "CA", "N", "CB", "C", "O", "CG", "ND1", "CD2", "NE2", + "CE1" }, + // Single Bonds + { { "CA", "N" }, + { "CA", "CB" }, + { "CA", "C" }, + { "CB", "CG" }, + { "CG", "ND1" }, + { "CD2", "NE2" }, + { "NE2", "CE1" }, + { "CE1", "ND1" }, + { "N", "H" }, + { "NE2", "HE2" } }, + // Double Bonds + { { "C", "O" }, { "CG", "CD2" } }); + std::map residueDict = { { "ALA", ALAData }, { "CYS", CYSData }, { "ASP", ASPData }, { "GLU", GLUData }, { "PHE", PHEData }, { "GLY", GLYData }, @@ -1296,6 +1378,9 @@ std::map residueDict = { { "ATP", ATPData }, { "NH2", NH2Data }, { "PG4", PG4Data }, { "FMT", FMTData }, { "GDP", GDPData }, { "FUC", FUCData }, { "SEP", SEPData }, { "GAL", GALData }, { "PGE", PGEData }, + { "ASH", ASHData }, { "CYX", CYXData }, { "HIP", HIPData }, + { "HID", HIDData }, { "HIE", HIEData }, +} }; } // namespace Core diff --git a/scripts/getresdata.py b/scripts/getresdata.py index 732ed0591b..89bdb97c35 100644 --- a/scripts/getresdata.py +++ b/scripts/getresdata.py @@ -1,9 +1,26 @@ #!/usr/bin/env python +from __future__ import print_function + import requests import pybel import openbabel as ob import os +import sys + +# TODO: process Open Babel resdata.txt +# if we can find certain non-standard residues +mdLigands = [ +"ASH", # Neutral ASP +"CYX", # SS-bonded CYS +"CYM", # Negative CYS +"GLH", # Neutral GLU +"HIP", # Positive HIS +"HID", # Neutral HIS, proton HD1 present +"HIE", # Neutral HIS, proton HE2 present +"LYN", # Neutral LYS +"TYM", # Negative TYR +] # the location of the LigandExpo list by count ligandURL = "http://ligand-expo.rcsb.org/dictionaries/cc-counts.tdd" @@ -142,22 +159,26 @@ class ResidueData print('ResidueData %sData("%s",' % (ligand, ligand)) print('// Atoms') print('{') - for atom in atom_map.values(): - print('"%s", ' % atom) + for atom in atom_map.values()[:-1]: + print('"%s", ' % (atom), end='') + print('"%s"' % atom_map.values()[-1]) print('},') print('// Single Bonds') print('{') - for bond in single_bonds: - print('{ "%s", "%s" },' % bond) + for bond in single_bonds[:-1]: + print('{ "%s", "%s" },' % bond, end='') + print('{ "%s", "%s" }' % single_bonds[-1]) print('},') print('// Double Bonds') print('{') if len(double_bonds): - for bond in double_bonds: - print('{ "%s", "%s" },' % bond) - print('},') + for bond in double_bonds[:-1]: + print('{ "%s", "%s" },' % bond, end='') + print('{ "%s", "%s" }' % double_bonds[-1]) + + print('}') print(');') From 89996245573a4d784cb6e978bc97146f2cb17948 Mon Sep 17 00:00:00 2001 From: Adarsh Balasubramanian Date: Fri, 3 Aug 2018 02:43:20 +0530 Subject: [PATCH 20/68] Adding VASP OUTCAR test Signed-off-by: Adarsh Balasubramanian --- tests/io/CMakeLists.txt | 2 +- tests/io/{poscartest.cpp => vasptest.cpp} | 82 +++++++++++++++++++++-- 2 files changed, 78 insertions(+), 6 deletions(-) rename tests/io/{poscartest.cpp => vasptest.cpp} (59%) diff --git a/tests/io/CMakeLists.txt b/tests/io/CMakeLists.txt index 0ab66032f4..1f7394df84 100644 --- a/tests/io/CMakeLists.txt +++ b/tests/io/CMakeLists.txt @@ -5,7 +5,7 @@ set(tests FileFormatManager Lammps Mdl - Poscar + Vasp Xyz ) diff --git a/tests/io/poscartest.cpp b/tests/io/vasptest.cpp similarity index 59% rename from tests/io/poscartest.cpp rename to tests/io/vasptest.cpp index f7078f93f5..4378c12e86 100644 --- a/tests/io/poscartest.cpp +++ b/tests/io/vasptest.cpp @@ -30,15 +30,16 @@ #include #include +using Avogadro::Matrix3; +using Avogadro::Vector3; using Avogadro::Core::Atom; using Avogadro::Core::Molecule; using Avogadro::Core::UnitCell; using Avogadro::Io::FileFormat; +using Avogadro::Io::OutcarFormat; using Avogadro::Io::PoscarFormat; -using Avogadro::Matrix3; -using Avogadro::Vector3; -TEST(PoscarTest, read) +TEST(VaspTest, readPoscar) { PoscarFormat poscar; Molecule molecule; @@ -76,7 +77,7 @@ TEST(PoscarTest, read) EXPECT_DOUBLE_EQ(pos5.z(), 0.5); } -TEST(PoscarTest, write) +TEST(VaspTest, writePoscar) { PoscarFormat poscar; Molecule molecule; @@ -121,7 +122,7 @@ TEST(PoscarTest, write) EXPECT_TRUE(checkedSomething); } -TEST(PoscarTest, modes) +TEST(VaspTest, PoscarModes) { // This tests some of the mode setting/checking code, not explicitly Poscar // but @@ -132,3 +133,74 @@ TEST(PoscarTest, modes) EXPECT_TRUE(format.mode() & FileFormat::Read); EXPECT_FALSE(format.isMode(FileFormat::Write)); } + +TEST(VaspTest, readOutcar) +{ + OutcarFormat multi; + multi.open(AVOGADRO_DATA "/data/ti_bulk.OUTCAR", + FileFormat::Read | FileFormat::MultiMolecule); + Molecule molecule; + + // Read in the structure. + EXPECT_TRUE(multi.readMolecule(molecule)); + ASSERT_EQ(multi.error(), ""); + + // First, let's check the unit cell + UnitCell* uc = molecule.unitCell(); + + EXPECT_EQ(uc->aVector(), Vector3(5.8783178329, 0.0000000000, 0.0000000000)); + EXPECT_EQ(uc->bVector(), Vector3(-2.9391589165, 5.0907725749, 0.0000000000)); + EXPECT_EQ(uc->cVector(), Vector3(0.0000000000, 0.0000000000, 9.2823419571)); + + // Check that the number of atoms per step and number of steps in the + // trajectory were read correctly + EXPECT_EQ(molecule.atomCount(), 16); + EXPECT_EQ(molecule.coordinate3dCount(), 10); + + // Check a couple of positions to make sure they were read correctly + EXPECT_EQ(molecule.atom(1).position3d().x(), -0.00000); + EXPECT_EQ(molecule.atom(1).position3d().y(), 1.69693); + EXPECT_EQ(molecule.atom(1).position3d().z(), 5.80146); + EXPECT_EQ(molecule.atom(4).position3d().x(), 2.93916); + EXPECT_EQ(molecule.atom(4).position3d().y(), 1.69693); + EXPECT_EQ(molecule.atom(4).position3d().z(), 1.16029); + + // Switching to second frame + EXPECT_TRUE(molecule.setCoordinate3d(1)); + + // Check a couple of positions to make sure they were read correctly + EXPECT_EQ(molecule.atom(1).position3d().x(), -0.00091); + EXPECT_EQ(molecule.atom(1).position3d().y(), 1.70362); + EXPECT_EQ(molecule.atom(1).position3d().z(), 5.80402); + EXPECT_EQ(molecule.atom(4).position3d().x(), 2.93439); + EXPECT_EQ(molecule.atom(4).position3d().y(), 1.69969); + EXPECT_EQ(molecule.atom(4).position3d().z(), 1.16202); + + // Switching to last frame + EXPECT_TRUE(molecule.setCoordinate3d(9)); + + // Check a couple of positions to make sure they were read correctly + EXPECT_EQ(molecule.atom(1).position3d().x(), -0.00813); + EXPECT_EQ(molecule.atom(1).position3d().y(), 1.75426); + EXPECT_EQ(molecule.atom(1).position3d().z(), 5.82452); + EXPECT_EQ(molecule.atom(4).position3d().x(), 2.89744); + EXPECT_EQ(molecule.atom(4).position3d().y(), 1.72157); + EXPECT_EQ(molecule.atom(4).position3d().z(), 1.17499); +} + +TEST(VaspTest, OutcarModes) +{ + // This tests some of the mode setting/checking code + OutcarFormat format; + format.open(AVOGADRO_DATA "/data/ti_bulk.OUTCAR", FileFormat::Read); + EXPECT_TRUE(format.isMode(FileFormat::Read)); + EXPECT_TRUE(format.mode() & FileFormat::Read); + EXPECT_FALSE(format.isMode(FileFormat::Write)); + + // Try some combinations now. + format.open(AVOGADRO_DATA "/data/ti_bulk.OUTCAR", + FileFormat::Read | FileFormat::MultiMolecule); + EXPECT_TRUE(format.isMode(FileFormat::Read)); + EXPECT_TRUE(format.isMode(FileFormat::Read | FileFormat::MultiMolecule)); + EXPECT_TRUE(format.isMode(FileFormat::MultiMolecule)); +} From 83c9d7ac154d8b61a171b9806497a74041068b6a Mon Sep 17 00:00:00 2001 From: Geoff Hutchison Date: Thu, 2 Aug 2018 17:21:37 -0400 Subject: [PATCH 21/68] Fix header and clang-format Signed-off-by: Geoff Hutchison --- avogadro/core/residuedata.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/avogadro/core/residuedata.h b/avogadro/core/residuedata.h index fa0ba72086..c67ba5d557 100644 --- a/avogadro/core/residuedata.h +++ b/avogadro/core/residuedata.h @@ -1380,9 +1380,8 @@ std::map residueDict = { { "SEP", SEPData }, { "GAL", GALData }, { "PGE", PGEData }, { "ASH", ASHData }, { "CYX", CYXData }, { "HIP", HIPData }, { "HID", HIDData }, { "HIE", HIEData }, -} - }; + } // namespace Core } // namespace Avogadro From e1f726ce27409bc5fd28c4d7165bc7c266773252 Mon Sep 17 00:00:00 2001 From: Geoff Hutchison Date: Thu, 2 Aug 2018 23:02:08 -0400 Subject: [PATCH 22/68] Minor fix - make sure to detect residue bonds *after* single bonds This ensures that C=O appear, etc. Signed-off-by: Geoff Hutchison --- avogadro/io/pdbformat.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/avogadro/io/pdbformat.cpp b/avogadro/io/pdbformat.cpp index 1cee083c71..8296542ebe 100644 --- a/avogadro/io/pdbformat.cpp +++ b/avogadro/io/pdbformat.cpp @@ -162,8 +162,8 @@ bool PdbFormat::read(std::istream& in, Core::Molecule& mol) } } } // End while loop - mol.perceiveBondsFromResidueData(); mol.perceiveBondsSimple(); + mol.perceiveBondsFromResidueData(); return true; } // End read @@ -182,4 +182,4 @@ std::vector PdbFormat::mimeTypes() const } } // namespace Io -} // namespace Avogadro \ No newline at end of file +} // namespace Avogadro From 5838e21c4ab9a7264e064042cdc306498338c600 Mon Sep 17 00:00:00 2001 From: Patrick Avery Date: Sun, 5 Aug 2018 19:13:47 -0400 Subject: [PATCH 23/68] QtGui::Molecule: Append m_bondUniqueIds only once This prevents a complex call sequence of: QtGui::Molecule::addBond() // atom types Core::Molecule::addBond() // atom types QtGui::Molecule::addBond() // atom indices In this complex call sequence, two different QtGui::Molecule::addBond() functions get called, and this results in m_bondUniqueIds being appended to twice. This fix explicitly calls Core::Molecule::addBond() for atom indices and ensures that only one QtGui::Molecule::addBond() gets called, so that m_bondUniqueIds is only appended once. Signed-off-by: Patrick Avery --- avogadro/qtgui/molecule.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/avogadro/qtgui/molecule.cpp b/avogadro/qtgui/molecule.cpp index 301d07d880..b998adc34a 100644 --- a/avogadro/qtgui/molecule.cpp +++ b/avogadro/qtgui/molecule.cpp @@ -185,7 +185,10 @@ Molecule::BondType Molecule::addBond(const AtomType& a, const AtomType& b, unsigned char order) { m_bondUniqueIds.push_back(bondCount()); - BondType bond_ = Core::Molecule::addBond(a, b, order); + assert(a.isValid() && a.molecule() == this); + assert(b.isValid() && b.molecule() == this); + + BondType bond_ = Core::Molecule::addBond(a.index(), b.index(), order); return bond_; } From e28ecf144963036fc049018b06fc7c4b79b4970a Mon Sep 17 00:00:00 2001 From: Adarsh Balasubramanian Date: Wed, 8 Aug 2018 00:53:27 +0530 Subject: [PATCH 24/68] Trajectory support in PDB reader Signed-off-by: Adarsh Balasubramanian --- avogadro/io/pdbformat.cpp | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/avogadro/io/pdbformat.cpp b/avogadro/io/pdbformat.cpp index 8296542ebe..8ae187a0a2 100644 --- a/avogadro/io/pdbformat.cpp +++ b/avogadro/io/pdbformat.cpp @@ -9,6 +9,7 @@ #include #include +using Avogadro::Core::Array; using Avogadro::Core::Atom; using Avogadro::Core::Bond; using Avogadro::Core::Elements; @@ -37,11 +38,20 @@ bool PdbFormat::read(std::istream& in, Core::Molecule& mol) Residue* r; size_t currentResidueId = 0; bool ok(false); + int coordSet = 0; + Array positions; while (getline(in, buffer)) { // Read Each line one by one - if (startsWith(buffer, "ENDMDL")) - break; + if (startsWith(buffer, "ENDMDL")) { + if (coordSet == 0) { + mol.setCoordinate3d(mol.atomPositions3d(), coordSet++); + positions.reserve(mol.atomCount()); + } else { + mol.setCoordinate3d(positions, coordSet++); + positions.clear(); + } + } else if (startsWith(buffer, "ATOM") || startsWith(buffer, "HETATM")) { // First we initialize the residue instance @@ -106,10 +116,14 @@ bool PdbFormat::read(std::istream& in, Core::Molecule& mol) if (atomicNum == 255) appendError("Invalid element"); - Atom newAtom = mol.addAtom(atomicNum); - newAtom.setPosition3d(pos); - if (r) { - r->addResidueAtom(atomName, newAtom); + if (coordSet == 0) { + Atom newAtom = mol.addAtom(atomicNum); + newAtom.setPosition3d(pos); + if (r) { + r->addResidueAtom(atomName, newAtom); + } + } else { + positions.push_back(pos); } } From 2e559867ec52e17236f6219bf70fb81cb658d510 Mon Sep 17 00:00:00 2001 From: "Marcus D. Hanwell" Date: Sat, 11 Aug 2018 11:46:14 -0400 Subject: [PATCH 25/68] Only add includes to plugin that needs them There is no need for all plugins to see the gif-h headers. Signed-off-by: Marcus D. Hanwell --- avogadro/qtplugins/CMakeLists.txt | 2 -- avogadro/qtplugins/playertool/CMakeLists.txt | 3 ++- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/avogadro/qtplugins/CMakeLists.txt b/avogadro/qtplugins/CMakeLists.txt index 8a6f73d4b0..20e22aed7f 100644 --- a/avogadro/qtplugins/CMakeLists.txt +++ b/avogadro/qtplugins/CMakeLists.txt @@ -5,8 +5,6 @@ find_package(Qt5 COMPONENTS Widgets Network Concurrent REQUIRED) include_directories(SYSTEM ${Qt5Widgets_INCLUDE_DIRS}) add_definitions(${Qt5Widgets_DEFINITIONS}) -include_directories("${AvogadroLibs_SOURCE_DIR}/thirdparty/gif-h") - # Modify the output directory for the build tree. set(original_library_output_dir "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}") set(CMAKE_LIBRARY_OUTPUT_DIRECTORY diff --git a/avogadro/qtplugins/playertool/CMakeLists.txt b/avogadro/qtplugins/playertool/CMakeLists.txt index f27ef9a54f..a7c256d19f 100644 --- a/avogadro/qtplugins/playertool/CMakeLists.txt +++ b/avogadro/qtplugins/playertool/CMakeLists.txt @@ -1,4 +1,5 @@ -include_directories(SYSTEM "${AvogadroLibs_SOURCE_DIR}/thirdparty/libgwavi") +include_directories(SYSTEM "${AvogadroLibs_SOURCE_DIR}/thirdparty/libgwavi" + "${AvogadroLibs_SOURCE_DIR}/thirdparty/gif-h") avogadro_plugin(PlayerTool "Player tool" From 71ddc996713e7f1f6be3cfff8f7152fc036df586 Mon Sep 17 00:00:00 2001 From: "Marcus D. Hanwell" Date: Sat, 11 Aug 2018 11:47:13 -0400 Subject: [PATCH 26/68] Fix compile failure - m_info not a member Guessing this was a leftover, but was causing the build to fail on all platforms. Signed-off-by: Marcus D. Hanwell --- avogadro/qtplugins/playertool/playertool.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/avogadro/qtplugins/playertool/playertool.cpp b/avogadro/qtplugins/playertool/playertool.cpp index afaee1d4c8..c5d0547712 100644 --- a/avogadro/qtplugins/playertool/playertool.cpp +++ b/avogadro/qtplugins/playertool/playertool.cpp @@ -55,7 +55,6 @@ PlayerTool::PlayerTool(QObject* parent_) , m_renderer(nullptr) , m_currentFrame(0) , m_toolWidget(nullptr) - , m_info(nullptr) , m_frameIdx(nullptr) , m_slider(nullptr) { From 1899661e86f92413533e9c2355fc3cbe16f5e45d Mon Sep 17 00:00:00 2001 From: "Marcus D. Hanwell" Date: Thu, 26 Jul 2018 16:18:26 -0400 Subject: [PATCH 27/68] Added initial support for reading coordinate sets Coordinate sets are used to store conformers, trajectories, and other situations where the atomic coordinates vary across some step. This reuses functionality that was initially added for MD trajectories. Signed-off-by: Marcus D. Hanwell --- avogadro/io/cjsonformat.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/avogadro/io/cjsonformat.cpp b/avogadro/io/cjsonformat.cpp index abb76a8fad..0501c2ef5c 100644 --- a/avogadro/io/cjsonformat.cpp +++ b/avogadro/io/cjsonformat.cpp @@ -58,7 +58,6 @@ bool setJsonKey(json& j, Molecule& m, const std::string& key) m.setData(key, j.value(key, "undefined")); return true; } - std::cout << key << " not found." << std::endl; return false; } @@ -146,6 +145,22 @@ bool CjsonFormat::read(std::istream& file, Molecule& molecule) } } + // Check for coordinate sets, and read them in if found, e.g. trajectories. + json coordSets = atoms["coordSets"]; + if (coordSets.is_array() && coordSets.size()) { + for (unsigned int i = 0; i < coordSets.size(); ++i) { + Array setArray; + json set = coordSets[i]; + if (isNumericArray(set)) { + for (unsigned int j = 0; j < set.size() / 3; ++j) { + setArray.push_back(Vector3(set[3 * j], set[3 * j + 1], + set[3 * j + 2])); + } + molecule.setCoordinate3d(setArray, i); + } + } + } + // Selection is optional, but if present should be loaded. json selection = atoms["selected"]; if (isBooleanArray(selection) && selection.size() == atomCount) From e04a5761f8fb8b16a46a52006e2ad67ad408f4f6 Mon Sep 17 00:00:00 2001 From: "Marcus D. Hanwell" Date: Sat, 11 Aug 2018 12:53:56 -0400 Subject: [PATCH 28/68] Add support for molecular orbital sets This adds a new container for molecular orbital coefficients, and some code to read them in from a Chemical JSON file. Signed-off-by: Marcus D. Hanwell --- avogadro/core/gaussianset.cpp | 41 +++++++++++++++++++++++++++++++++++ avogadro/core/gaussianset.h | 28 ++++++++++++++++++++++++ avogadro/io/cjsonformat.cpp | 26 ++++++++++++++++++++++ 3 files changed, 95 insertions(+) diff --git a/avogadro/core/gaussianset.cpp b/avogadro/core/gaussianset.cpp index 732a8232fe..b8657bea64 100644 --- a/avogadro/core/gaussianset.cpp +++ b/avogadro/core/gaussianset.cpp @@ -116,6 +116,47 @@ void GaussianSet::setMolecularOrbitals(const vector& MOs, m_moMatrix[index].coeffRef(i, j) = MOs[i + j * m_numMOs]; } +void GaussianSet::setMolecularOrbitals(const vector& MOs, + ElectronType type, Index idx) +{ + if (!m_numMOs) + return; + + size_t index = 0; + if (type == Beta) + index = 1; + + unsigned int columns = static_cast(MOs.size()) / m_numMOs; + + MatrixX moMatrix; + moMatrix.resize(m_numMOs, columns); + + for (unsigned int j = 0; j < columns; ++j) + for (unsigned int i = 0; i < m_numMOs; ++i) + moMatrix.coeffRef(i, j) = MOs[i + j * m_numMOs]; + + if (idx <= m_moMatrixSet[index].size()) + m_moMatrixSet[index].resize(idx + 1); + + m_moMatrixSet[index][idx] = moMatrix; +} + +bool GaussianSet::setActiveSetStep(int index) +{ + if (index >= static_cast(m_moMatrixSet[0].size()) || + index >= static_cast(m_moMatrixSet[1].size())) { + return false; + } + + if (index >= m_molecule->coordinate3dCount()) + return false; + + m_moMatrix[0] = m_moMatrixSet[0][index]; + m_moMatrix[1] = m_moMatrixSet[1][index]; + m_molecule->setCoordinate3d(index); + return true; +} + void GaussianSet::setMolecularOrbitalEnergy(const vector& energies, ElectronType type) { diff --git a/avogadro/core/gaussianset.h b/avogadro/core/gaussianset.h index 4601acc632..c22e6a65be 100644 --- a/avogadro/core/gaussianset.h +++ b/avogadro/core/gaussianset.h @@ -122,6 +122,27 @@ class AVOGADROCORE_EXPORT GaussianSet : public BasisSet void setMolecularOrbitals(const std::vector& MOs, ElectronType type = Paired); + /** + * Set the molecular orbital (MO) coefficients for a given index. Note + * that this must be used with coordinate sets to work correctly. + * @param MOs Vector containing the MO coefficients for the GaussianSet. + * @param type The type of the MOs (Paired, Alpha, Beta). + * @param index The index of the MO in the sequence. + */ + void setMolecularOrbitals(const std::vector& MOs, + ElectronType type, Index index); + + /** + * Get the number of elements in the set. + */ + int setCount() { return static_cast(m_moMatrixSet[0].size()); } + + /** + * Set the active element in the set, this expects a corresponding + * coordinate set element, and will change the active MO matrix. + */ + bool setActiveSetStep(int index); + /** * @brief Set the molecular orbtial energies, expected in Hartrees. * @param energies The vector containing energies for the MOs of type @@ -314,6 +335,13 @@ class AVOGADROCORE_EXPORT GaussianSet : public BasisSet */ MatrixX m_moMatrix[2]; //! MO coefficient matrix + /** + * @brief If there are a sequence of related MOs, they are stored here, and + * set as the active MOs upon demand. Alpha will store Paired or the Alpha, + * Beta will store Beta coefficients for the appropriate calculation types. + */ + std::vector m_moMatrixSet[2]; + /** * @brief This block stores energies for the molecular orbitals (same * convention as the molecular orbital coefficients). diff --git a/avogadro/io/cjsonformat.cpp b/avogadro/io/cjsonformat.cpp index 0501c2ef5c..016616f659 100644 --- a/avogadro/io/cjsonformat.cpp +++ b/avogadro/io/cjsonformat.cpp @@ -285,6 +285,32 @@ bool CjsonFormat::read(std::istream& file, Molecule& molecule) } else { std::cout << "No orbital cofficients found!" << std::endl; } + // Check for orbital coefficient sets, these are paired with coordinates + // when they exist, but have constant basis set, atom types, etc. + if (orbitals["sets"].is_array()) { + json orbSets = orbitals["sets"]; + for (unsigned int idx = 0; idx < orbSets.size(); ++idx) { + moCoefficients = orbSets[idx]["moCoefficients"]; + moCoefficientsA = orbSets[idx]["alphaCoefficients"]; + moCoefficientsB = orbSets[idx]["betaCoefficients"]; + if (isNumericArray(moCoefficients)) { + std::vector coeffs; + for (unsigned int i = 0; i < moCoefficients.size(); ++i) + coeffs.push_back(static_cast(moCoefficients[i])); + basis->setMolecularOrbitals(coeffs, BasisSet::Paired, idx); + } else if (isNumericArray(moCoefficientsA) && + isNumericArray(moCoefficientsB)) { + std::vector coeffsA; + for (unsigned int i = 0; i < moCoefficientsA.size(); ++i) + coeffsA.push_back(static_cast(moCoefficientsA[i])); + std::vector coeffsB; + for (unsigned int i = 0; i < moCoefficientsB.size(); ++i) + coeffsB.push_back(static_cast(moCoefficientsB[i])); + basis->setMolecularOrbitals(coeffsA, BasisSet::Alpha, idx); + basis->setMolecularOrbitals(coeffsB, BasisSet::Beta, idx); + } + } + } } molecule.setBasisSet(basis); } From 52764af5aa9a06d3ff101fa563fb02c0788eb595 Mon Sep 17 00:00:00 2001 From: "Marcus D. Hanwell" Date: Sat, 11 Aug 2018 13:05:57 -0400 Subject: [PATCH 29/68] Put sets inside coords, set active step This moves coordSets to be within coords as 3dSets, following previous naming conventions. Also ensure we set an active step so that the initial view is sane. Signed-off-by: Marcus D. Hanwell --- avogadro/io/cjsonformat.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/avogadro/io/cjsonformat.cpp b/avogadro/io/cjsonformat.cpp index 016616f659..244b7ffe5a 100644 --- a/avogadro/io/cjsonformat.cpp +++ b/avogadro/io/cjsonformat.cpp @@ -146,7 +146,7 @@ bool CjsonFormat::read(std::istream& file, Molecule& molecule) } // Check for coordinate sets, and read them in if found, e.g. trajectories. - json coordSets = atoms["coordSets"]; + json coordSets = atoms["coords"]["3dSets"]; if (coordSets.is_array() && coordSets.size()) { for (unsigned int i = 0; i < coordSets.size(); ++i) { Array setArray; @@ -159,6 +159,8 @@ bool CjsonFormat::read(std::istream& file, Molecule& molecule) molecule.setCoordinate3d(setArray, i); } } + // Make sure the first step is active once we are done loading the sets. + molecule.setCoordinate3d(0); } // Selection is optional, but if present should be loaded. @@ -287,7 +289,7 @@ bool CjsonFormat::read(std::istream& file, Molecule& molecule) } // Check for orbital coefficient sets, these are paired with coordinates // when they exist, but have constant basis set, atom types, etc. - if (orbitals["sets"].is_array()) { + if (orbitals["sets"].is_array() && orbitals["sets"].size()) { json orbSets = orbitals["sets"]; for (unsigned int idx = 0; idx < orbSets.size(); ++idx) { moCoefficients = orbSets[idx]["moCoefficients"]; @@ -310,6 +312,8 @@ bool CjsonFormat::read(std::istream& file, Molecule& molecule) basis->setMolecularOrbitals(coeffsB, BasisSet::Beta, idx); } } + // Set the first step as active. + basis->setActiveSetStep(0); } } molecule.setBasisSet(basis); From ff14a4a26214f31c19a7242c6b4ee26c91c58f8d Mon Sep 17 00:00:00 2001 From: "Marcus D. Hanwell" Date: Sat, 11 Aug 2018 13:07:49 -0400 Subject: [PATCH 30/68] Added an active objects class to Avogadro This enables us to avoid calling functions for every plugin, they can query for active objects. Currently just one object as a proof of concept, this can be expanded out. This lets us keep the API reasonably clean, and have a singleton manage access to some of the useful global objects within a running application. Signed-off-by: Marcus D. Hanwell --- avogadro/qtopengl/CMakeLists.txt | 2 + avogadro/qtopengl/activeobjects.cpp | 33 ++++++++++++++++ avogadro/qtopengl/activeobjects.h | 58 +++++++++++++++++++++++++++++ 3 files changed, 93 insertions(+) create mode 100644 avogadro/qtopengl/activeobjects.cpp create mode 100644 avogadro/qtopengl/activeobjects.h diff --git a/avogadro/qtopengl/CMakeLists.txt b/avogadro/qtopengl/CMakeLists.txt index 28a473e48e..e66dc41bf4 100644 --- a/avogadro/qtopengl/CMakeLists.txt +++ b/avogadro/qtopengl/CMakeLists.txt @@ -6,11 +6,13 @@ include_directories(SYSTEM ${EIGEN3_INCLUDE_DIR}) find_package(Qt5 COMPONENTS Widgets REQUIRED) set(HEADERS + activeobjects.h glwidget.h qttextrenderstrategy.h ) set(SOURCES + activeobjects.cpp glwidget.cpp qttextrenderstrategy.cpp ) diff --git a/avogadro/qtopengl/activeobjects.cpp b/avogadro/qtopengl/activeobjects.cpp new file mode 100644 index 0000000000..220bbe2e12 --- /dev/null +++ b/avogadro/qtopengl/activeobjects.cpp @@ -0,0 +1,33 @@ +/****************************************************************************** + This source file is part of the Avogadro project. + This source code is released under the 3-Clause BSD License, (see "LICENSE"). +******************************************************************************/ + +#include "activeobjects.h" + +#include "glwidget.h" + +namespace Avogadro { +namespace QtOpenGL { + +ActiveObjects::ActiveObjects() = default; +ActiveObjects::~ActiveObjects() = default; + +ActiveObjects& ActiveObjects::instance() +{ + static ActiveObjects singletonInstance; + return singletonInstance; +} + +GLWidget* ActiveObjects::activeGLWidget() const +{ + return m_glWidget; +} + +void ActiveObjects::setActiveGLWidget(GLWidget* glWidget) +{ + m_glWidget = glWidget; +} + +} // End QtOpenGL namespace +} // End Avogadro namespace \ No newline at end of file diff --git a/avogadro/qtopengl/activeobjects.h b/avogadro/qtopengl/activeobjects.h new file mode 100644 index 0000000000..3e48cfb58f --- /dev/null +++ b/avogadro/qtopengl/activeobjects.h @@ -0,0 +1,58 @@ +/****************************************************************************** + This source file is part of the Avogadro project. + This source code is released under the 3-Clause BSD License, (see "LICENSE"). +******************************************************************************/ + +#ifndef AVOGADRO_QTOPENGL_ACTIVEOBJECTS_H +#define AVOGADRO_QTOPENGL_ACTIVEOBJECTS_H + +#include "avogadroqtopenglexport.h" + +#include + +#include + +namespace Avogadro { +namespace QtOpenGL { + +class GLWidget; + +/** + * @class ActiveObjects activeobjects.h + * @brief Singleton to provide access to active objects. + * + * This class provides access to the active objects in the running application. + * If you write an application using the Avogadro libraries you need to keep + * this class updated with changes in active objects in order for built in + * features to work as expected. + * + * All returned objects are owned by the running application, nullptr indicates + * that there is no currently active object of that type. + */ +class AVOGADROQTOPENGL_EXPORT ActiveObjects : public QObject +{ + Q_OBJECT + +public: + /** Return a reference to the singleton instance that can be queried. */ + static ActiveObjects& instance(); + + /** Get the active GLWidget. **/ + GLWidget* activeGLWidget() const; + +public slots: + /** Set the active GLWidget. **/ + void setActiveGLWidget(GLWidget* glWidget); + +private: + ActiveObjects(); + ~ActiveObjects() override; + Q_DISABLE_COPY(ActiveObjects) + + QPointer m_glWidget = nullptr; +}; + +} // End QtOpenGL namespace +} // End Avogadro namespace + +#endif // AVOGADRO_QTOPENGL_ACTIVEOBJECTS_H \ No newline at end of file From 260294a2a4845a78161b100b7e64086a891cbf2e Mon Sep 17 00:00:00 2001 From: "Marcus D. Hanwell" Date: Sat, 11 Aug 2018 13:09:27 -0400 Subject: [PATCH 31/68] Meshes on by default, need to improve in future This is easier, and we are doing it for other display types, but we should get better at letting plugins turn these on when it makes sense. Signed-off-by: Marcus D. Hanwell --- avogadro/qtplugins/meshes/meshes.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/avogadro/qtplugins/meshes/meshes.cpp b/avogadro/qtplugins/meshes/meshes.cpp index 5f14c09d34..610fcf8113 100644 --- a/avogadro/qtplugins/meshes/meshes.cpp +++ b/avogadro/qtplugins/meshes/meshes.cpp @@ -36,7 +36,7 @@ using Rendering::GeometryNode; using Rendering::GroupNode; using Rendering::MeshGeometry; -Meshes::Meshes(QObject* p) : ScenePlugin(p), m_enabled(false) +Meshes::Meshes(QObject* p) : ScenePlugin(p), m_enabled(true) { } From f07075069880e5f3f37984bfac4148c2f377e6ea Mon Sep 17 00:00:00 2001 From: "Marcus D. Hanwell" Date: Sat, 11 Aug 2018 13:12:51 -0400 Subject: [PATCH 32/68] Improve signal-slot connection in these objects They can be persistent for the life of the object, connecting and disconnecting was causing situations where the calculationComplete was not always being triggered as expected. Signed-off-by: Marcus D. Hanwell --- avogadro/qtplugins/surfaces/gaussiansetconcurrent.cpp | 6 ++---- avogadro/qtplugins/surfaces/slatersetconcurrent.cpp | 6 ++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/avogadro/qtplugins/surfaces/gaussiansetconcurrent.cpp b/avogadro/qtplugins/surfaces/gaussiansetconcurrent.cpp index 3ece4d1c73..71d7492e79 100644 --- a/avogadro/qtplugins/surfaces/gaussiansetconcurrent.cpp +++ b/avogadro/qtplugins/surfaces/gaussiansetconcurrent.cpp @@ -54,6 +54,8 @@ struct GaussianShell GaussianSetConcurrent::GaussianSetConcurrent(QObject* p) : QObject(p), m_gaussianShells(nullptr), m_set(nullptr), m_tools(nullptr) { + // Watch for the future + connect(&m_watcher, SIGNAL(finished()), this, SLOT(calculationComplete())); } GaussianSetConcurrent::~GaussianSetConcurrent() @@ -96,7 +98,6 @@ bool GaussianSetConcurrent::calculateSpinDensity(Core::Cube* cube) void GaussianSetConcurrent::calculationComplete() { - disconnect(&m_watcher, SIGNAL(finished()), this, SLOT(calculationComplete())); (*m_gaussianShells)[0].tCube->lock()->unlock(); delete m_gaussianShells; m_gaussianShells = 0; @@ -126,9 +127,6 @@ bool GaussianSetConcurrent::setUpCalculation(Core::Cube* cube, // Lock the cube until we are done. cube->lock()->lock(); - // Watch for the future - connect(&m_watcher, SIGNAL(finished()), this, SLOT(calculationComplete())); - // The main part of the mapped reduced function... m_future = QtConcurrent::map(*m_gaussianShells, func); // Connect our watcher to our future diff --git a/avogadro/qtplugins/surfaces/slatersetconcurrent.cpp b/avogadro/qtplugins/surfaces/slatersetconcurrent.cpp index 922d06ba95..aae0eaed0b 100644 --- a/avogadro/qtplugins/surfaces/slatersetconcurrent.cpp +++ b/avogadro/qtplugins/surfaces/slatersetconcurrent.cpp @@ -43,6 +43,8 @@ struct SlaterShell SlaterSetConcurrent::SlaterSetConcurrent(QObject* p) : QObject(p), m_shells(nullptr), m_set(nullptr), m_tools(nullptr) { + // Watch for the future + connect(&m_watcher, SIGNAL(finished()), this, SLOT(calculationComplete())); } SlaterSetConcurrent::~SlaterSetConcurrent() @@ -78,7 +80,6 @@ bool SlaterSetConcurrent::calculateSpinDensity(Core::Cube* cube) void SlaterSetConcurrent::calculationComplete() { - disconnect(&m_watcher, SIGNAL(finished()), this, SLOT(calculationComplete())); (*m_shells)[0].tCube->lock()->unlock(); delete m_shells; m_shells = 0; @@ -106,9 +107,6 @@ bool SlaterSetConcurrent::setUpCalculation(Core::Cube* cube, unsigned int state, // Lock the cube until we are done. cube->lock()->lock(); - // Watch for the future - connect(&m_watcher, SIGNAL(finished()), this, SLOT(calculationComplete())); - // The main part of the mapped reduced function... m_future = QtConcurrent::map(*m_shells, func); // Connect our watcher to our future From 2b4fe2cdfb74f6abdc614530a6f0e09444bf6020 Mon Sep 17 00:00:00 2001 From: "Marcus D. Hanwell" Date: Sat, 11 Aug 2018 15:58:01 -0400 Subject: [PATCH 33/68] Add ability to animate through orbitals This augments the dialog to make it possible to animate through a sequence of electronic structure calculations. It is still at an early stage, but is quite robust and makes a number of improvements and bug fixes. The mesh and cube management is vastly improved, locking, and triggering are all more robust. Switching between detail levels, or between molecules, or between frames is all far more robust. Reuse some of the player tool code, but coordinate an asynchronous rendering of frames. Signed-off-by: Marcus D. Hanwell --- avogadro/qtplugins/surfaces/CMakeLists.txt | 3 + avogadro/qtplugins/surfaces/surfacedialog.cpp | 58 ++++ avogadro/qtplugins/surfaces/surfacedialog.h | 8 + avogadro/qtplugins/surfaces/surfacedialog.ui | 264 ++++++++++------ avogadro/qtplugins/surfaces/surfaces.cpp | 288 ++++++++++++++++-- avogadro/qtplugins/surfaces/surfaces.h | 42 ++- 6 files changed, 531 insertions(+), 132 deletions(-) diff --git a/avogadro/qtplugins/surfaces/CMakeLists.txt b/avogadro/qtplugins/surfaces/CMakeLists.txt index 1e7a90ac19..99b7cc8770 100644 --- a/avogadro/qtplugins/surfaces/CMakeLists.txt +++ b/avogadro/qtplugins/surfaces/CMakeLists.txt @@ -1,3 +1,6 @@ +include_directories(SYSTEM "${AvogadroLibs_SOURCE_DIR}/thirdparty/libgwavi" + "${AvogadroLibs_SOURCE_DIR}/thirdparty/gif-h") + set(surfaces_srcs gaussiansetconcurrent.cpp slatersetconcurrent.cpp diff --git a/avogadro/qtplugins/surfaces/surfacedialog.cpp b/avogadro/qtplugins/surfaces/surfacedialog.cpp index e7e8b63d98..25971e80ef 100644 --- a/avogadro/qtplugins/surfaces/surfacedialog.cpp +++ b/avogadro/qtplugins/surfaces/surfacedialog.cpp @@ -28,9 +28,12 @@ SurfaceDialog::SurfaceDialog(QWidget* parent_, Qt::WindowFlags f) { m_ui->setupUi(this); + setupSteps(1); + m_ui->orbitalCombo->setVisible(false); m_ui->spinCombo->setVisible(false); m_ui->chargeCombo->setVisible(false); + m_ui->recordButton->setVisible(false); // set the data for the default items /* Don't add surface types that aren't available yet, uncomment once they are. @@ -45,7 +48,10 @@ SurfaceDialog::SurfaceDialog(QWidget* parent_, Qt::WindowFlags f) SLOT(surfaceComboChanged(int))); connect(m_ui->resolutionCombo, SIGNAL(currentIndexChanged(int)), SLOT(resolutionComboChanged(int))); + connect(m_ui->stepValue, SIGNAL(valueChanged(int)), + SIGNAL(stepChanged(int))); connect(m_ui->calculateButton, SIGNAL(clicked()), SLOT(calculateClicked())); + connect(m_ui->recordButton, SIGNAL(clicked()), SLOT(record())); } SurfaceDialog::~SurfaceDialog() @@ -156,6 +162,35 @@ void SurfaceDialog::setupCubes(QStringList cubeNames) m_ui->orbitalCombo->setCurrentIndex(0); } +void SurfaceDialog::setupSteps(int stepCount) +{ + if (stepCount < 2) { + m_ui->stepValue->setEnabled(false); + m_ui->recordButton->setEnabled(false); + m_ui->recordButton->setVisible(false); + m_ui->vcrBack->setEnabled(false); + m_ui->vcrBack->setVisible(false); + m_ui->vcrPlay->setEnabled(false); + m_ui->vcrPlay->setVisible(false); + m_ui->vcrForward->setEnabled(false); + m_ui->vcrForward->setVisible(false); + } else { + m_ui->stepValue->setEnabled(true); + m_ui->stepValue->setRange(1, stepCount); + m_ui->stepValue->setSuffix(tr(" of %0").arg(stepCount)); + m_ui->recordButton->setEnabled(true); + m_ui->recordButton->setVisible(true); + /* Disable for now, this would be nice in future. + m_ui->vcrBack->setEnabled(true); + m_ui->vcrBack->setVisible(true); + m_ui->vcrPlay->setEnabled(true); + m_ui->vcrPlay->setVisible(true); + m_ui->vcrForward->setEnabled(true); + m_ui->vcrForward->setVisible(true); + */ + } +} + Surfaces::Type SurfaceDialog::surfaceType() { return static_cast(m_ui->surfaceCombo->currentData().toInt()); @@ -181,6 +216,16 @@ float SurfaceDialog::resolution() return static_cast(m_ui->resolutionDoubleSpinBox->value()); } +int SurfaceDialog::step() +{ + return m_ui->stepValue->value(); +} + +void SurfaceDialog::setStep(int step) +{ + m_ui->stepValue->setValue(step); +} + void SurfaceDialog::calculateClicked() { m_ui->calculateButton->setEnabled(false); @@ -192,5 +237,18 @@ void SurfaceDialog::reenableCalculateButton() m_ui->calculateButton->setEnabled(true); } +void SurfaceDialog::record() +{ + m_ui->calculateButton->setEnabled(false); + m_ui->recordButton->setEnabled(false); + emit recordClicked(); +} + +void SurfaceDialog::enableRecord() +{ + m_ui->calculateButton->setEnabled(true); + m_ui->recordButton->setEnabled(true); +} + } // End namespace QtPlugins } // End namespace Avogadro diff --git a/avogadro/qtplugins/surfaces/surfacedialog.h b/avogadro/qtplugins/surfaces/surfacedialog.h index 42c5ed3989..af71272452 100644 --- a/avogadro/qtplugins/surfaces/surfacedialog.h +++ b/avogadro/qtplugins/surfaces/surfacedialog.h @@ -45,7 +45,9 @@ class SurfaceDialog : public QDialog void setupBasis(int numElectrons, int numMOs, bool beta); void setupCubes(QStringList cubeNames); + void setupSteps(int stepCount); void reenableCalculateButton(); + void enableRecord(); Surfaces::Type surfaceType(); @@ -63,15 +65,21 @@ class SurfaceDialog : public QDialog float resolution(); + int step(); + void setStep(int step); + public slots: protected slots: void surfaceComboChanged(int n); void resolutionComboChanged(int n); void calculateClicked(); + void record(); signals: + void stepChanged(int n); void calculateClickedSignal(); + void recordClicked(); private: Ui::SurfaceDialog* m_ui; diff --git a/avogadro/qtplugins/surfaces/surfacedialog.ui b/avogadro/qtplugins/surfaces/surfacedialog.ui index 5f38c7a90c..1c1733857d 100644 --- a/avogadro/qtplugins/surfaces/surfacedialog.ui +++ b/avogadro/qtplugins/surfaces/surfacedialog.ui @@ -12,8 +12,8 @@ 0 0 - 515 - 216 + 610 + 337 @@ -31,26 +31,6 @@ - - - - Resolution: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Isosurface Value: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - @@ -61,29 +41,41 @@ - - + + - - - 4 - - - 0.000100000000000 - - - 0.999000000000000 + + + true - - 0.001000000000000 + + + + + + false - - 0.030000000000000 + + + + + + false + + + alpha + + + + + beta + + - + Qt::Horizontal @@ -107,6 +99,49 @@ + + + + + + + None + + + + + + + + false + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Resolution: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + @@ -189,41 +224,39 @@ - - + + + + Isosurface Value: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + - - - true + + + 4 - - - - - - false + + 0.000100000000000 - - - - - - false + + 0.999000000000000 + + + 0.001000000000000 + + + 0.030000000000000 - - - alpha - - - - - beta - - - + Qt::Horizontal @@ -237,26 +270,66 @@ - - + + + + Frame: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + - - - - None - - + + + false + - + false + + + + + + - + + + false + + + + + + + + + + + + + false + + + + + + + + + + + Qt::Horizontal @@ -272,6 +345,19 @@ + + + + Qt::Vertical + + + + 20 + 40 + + + + @@ -287,6 +373,19 @@ + + + + false + + + Record Movie... + + + true + + + @@ -296,19 +395,6 @@ - - - - Qt::Vertical - - - - 20 - 40 - - - - diff --git a/avogadro/qtplugins/surfaces/surfaces.cpp b/avogadro/qtplugins/surfaces/surfaces.cpp index 1dade007d2..43cfea5274 100644 --- a/avogadro/qtplugins/surfaces/surfaces.cpp +++ b/avogadro/qtplugins/surfaces/surfaces.cpp @@ -20,12 +20,21 @@ #include "gaussiansetconcurrent.h" #include "slatersetconcurrent.h" +// Header only, but duplicte symbols if included globally... +namespace{ +#include +} + +#include + #include #include #include #include #include +#include +#include #include #include @@ -39,9 +48,14 @@ #include #include +#include #include +#include +#include +#include #include #include +#include #include namespace Avogadro { @@ -49,22 +63,18 @@ namespace QtPlugins { using Core::Cube; using Core::GaussianSet; +using QtGui::Molecule; -Surfaces::Surfaces(QObject* p) - : ExtensionPlugin(p) - , m_progressDialog(nullptr) - , m_molecule(nullptr) - , m_basis(nullptr) - , m_gaussianConcurrent(nullptr) - , m_slaterConcurrent(nullptr) - , m_cube(nullptr) - , m_mesh1(nullptr) - , m_mesh2(nullptr) - , m_meshGenerator1(nullptr) - , m_meshGenerator2(nullptr) - , m_dialog(nullptr) +class Surfaces::PIMPL { - QAction* action = new QAction(this); +public: + GifWriter* gifWriter = nullptr; + gwavi_t* gwaviWriter = nullptr; +}; + +Surfaces::Surfaces(QObject* p) : ExtensionPlugin(p), d(new PIMPL()) +{ + auto action = new QAction(this); action->setText(tr("Create Surfaces...")); connect(action, SIGNAL(triggered()), SLOT(surfacesActivated())); m_actions.push_back(action); @@ -81,6 +91,7 @@ Surfaces::Surfaces(QObject* p) Surfaces::~Surfaces() { + delete d; delete m_cube; } @@ -92,6 +103,9 @@ void Surfaces::setMolecule(QtGui::Molecule* mol) m_cubes = mol->cubes(); } + m_cube = nullptr; + m_mesh1 = nullptr; + m_mesh2 = nullptr; m_molecule = mol; } @@ -113,6 +127,9 @@ void Surfaces::surfacesActivated() m_dialog = new SurfaceDialog(qobject_cast(parent())); connect(m_dialog, SIGNAL(calculateClickedSignal()), SLOT(calculateSurface())); + connect(m_dialog, SIGNAL(recordClicked()), + SLOT(recordMovie())); + connect(m_dialog, SIGNAL(stepChanged(int)), SLOT(stepChanged(int))); } if (m_basis) { @@ -132,9 +149,9 @@ void Surfaces::surfacesActivated() for (unsigned int i = 0; i < m_cubes.size(); ++i) { cubeNames << m_cubes[i]->name().c_str(); } - m_dialog->setupCubes(cubeNames); } + m_dialog->setupSteps(m_molecule->coordinate3dCount()); m_dialog->show(); } @@ -183,14 +200,27 @@ void Surfaces::calculateQM() if (!m_basis || !m_dialog) return; // nothing to do + // Reset state a little more frequently, minimal cost, avoid bugs. + m_molecule->clearCubes(); + m_molecule->clearMeshes(); + m_cube = nullptr; + m_mesh1 = nullptr; + m_mesh2 = nullptr; + m_molecule->emitChanged(Molecule::Atoms | Molecule::Added); + bool connectSlots = false; + // set up QtConcurrent calculators for Gaussian or Slater basis sets if (dynamic_cast(m_basis)) { - if (!m_gaussianConcurrent) + if (!m_gaussianConcurrent) { m_gaussianConcurrent = new GaussianSetConcurrent(this); + connectSlots = true; + } m_gaussianConcurrent->setMolecule(m_molecule); } else { - if (!m_slaterConcurrent) + if (!m_slaterConcurrent) { m_slaterConcurrent = new SlaterSetConcurrent(this); + connectSlots = true; + } m_slaterConcurrent->setMolecule(m_molecule); } @@ -199,6 +229,7 @@ void Surfaces::calculateQM() m_progressDialog = new QProgressDialog(qobject_cast(parent())); m_progressDialog->setCancelButtonText(nullptr); m_progressDialog->setWindowModality(Qt::NonModal); + connectSlots = true; } if (!m_cube) @@ -238,13 +269,14 @@ void Surfaces::calculateQM() m_progressDialog->setValue(m_gaussianConcurrent->watcher().progressValue()); m_progressDialog->show(); - connect(&m_gaussianConcurrent->watcher(), SIGNAL(progressValueChanged(int)), - m_progressDialog, SLOT(setValue(int))); - connect(&m_gaussianConcurrent->watcher(), - SIGNAL(progressRangeChanged(int, int)), m_progressDialog, - SLOT(setRange(int, int))); - connect(&m_gaussianConcurrent->watcher(), SIGNAL(finished()), - SLOT(displayMesh())); + if (connectSlots) { + connect(&m_gaussianConcurrent->watcher(), SIGNAL(progressValueChanged(int)), + m_progressDialog, SLOT(setValue(int))); + connect(&m_gaussianConcurrent->watcher(), + SIGNAL(progressRangeChanged(int, int)), m_progressDialog, + SLOT(setRange(int, int))); + connect(m_gaussianConcurrent, SIGNAL(finished()), SLOT(displayMesh())); + } } else { // slaters m_progressDialog->setWindowTitle(progressText); @@ -258,8 +290,7 @@ void Surfaces::calculateQM() connect(&m_slaterConcurrent->watcher(), SIGNAL(progressRangeChanged(int, int)), m_progressDialog, SLOT(setRange(int, int))); - connect(&m_slaterConcurrent->watcher(), SIGNAL(finished()), - SLOT(displayMesh())); + connect(m_slaterConcurrent, SIGNAL(finished()), SLOT(displayMesh())); } } @@ -274,6 +305,24 @@ void Surfaces::calculateCube() displayMesh(); } +void Surfaces::stepChanged(int n) +{ + if (!m_molecule || !m_basis) + return; + + qDebug() << "\n\t==== Step changed to" << n << "===="; + auto g = dynamic_cast(m_basis); + if (g) { + g->setActiveSetStep(n - 1); + m_molecule->clearCubes(); + m_molecule->clearMeshes(); + m_cube = nullptr; + m_mesh1 = nullptr; + m_mesh2 = nullptr; + m_molecule->emitChanged(Molecule::Atoms | Molecule::Added); + } +} + void Surfaces::displayMesh() { if (!m_cube) @@ -286,7 +335,6 @@ void Surfaces::displayMesh() connect(m_meshGenerator1, SIGNAL(finished()), SLOT(meshFinished())); } m_meshGenerator1->initialize(m_cube, m_mesh1, m_isoValue); - m_meshGenerator1->start(); // TODO - only do this if we're generating an orbital // and we need two meshes @@ -298,15 +346,197 @@ void Surfaces::displayMesh() connect(m_meshGenerator2, SIGNAL(finished()), SLOT(meshFinished())); } m_meshGenerator2->initialize(m_cube, m_mesh2, -m_isoValue, true); + + // Start the mesh generation - this needs an improved mutex with a read lock + // to function as expected. Write locks are exclusive, read locks can have + // many read locks but no write lock. + m_meshGenerator1->start(); m_meshGenerator2->start(); + + // Track how many meshes are left to show. + m_meshesLeft = 2; } void Surfaces::meshFinished() { - m_dialog->reenableCalculateButton(); - m_molecule->emitChanged(QtGui::Molecule::Added); + --m_meshesLeft; + if (m_meshesLeft == 0) { + if (m_recordingMovie) { + // Move to the next frame. + qDebug() << "Let's get to the next frame..."; + m_molecule->emitChanged(QtGui::Molecule::Added); + movieFrame(); + } else { + m_dialog->reenableCalculateButton(); + m_molecule->emitChanged(QtGui::Molecule::Added); + } + } // TODO: enable the mesh display type } +void Surfaces::recordMovie() +{ + QString baseFileName; + if (m_molecule) + baseFileName = m_molecule->data("fileName").toString().c_str(); + + QString selectedFilter = tr("Movie AVI (*.avi)"); + QString baseName = QFileDialog::getSaveFileName( + qobject_cast(parent()), tr("Export Movie"), "", + tr("Movie MP4 (*.mp4);;Movie AVI (*.avi);;GIF (*.gif)"), &selectedFilter); + + if (baseName.isEmpty()) { + m_dialog->enableRecord(); + return; + } + + QFileInfo fileInfo(baseName); + if (!fileInfo.suffix().isEmpty()) + baseName = fileInfo.canonicalPath() + "/" + fileInfo.baseName(); + + m_baseFileName = baseName; + m_numberLength = static_cast( + ceil(log10(static_cast(m_molecule->coordinate3dCount()) + 1))); + + m_recordingMovie = true; + m_currentFrame = 1; + m_frameCount = m_molecule->coordinate3dCount(); + + // Figure out the save type, and work accordingly... + if (selectedFilter == tr("GIF (*.gif)")) { + d->gwaviWriter = nullptr; + d->gifWriter = new GifWriter; + GifBegin(d->gifWriter, (baseName + ".gif").toLatin1().data(), 800, + 600, 100 / 4); + } else if (selectedFilter == tr("Movie AVI (*.avi)")) { + d->gifWriter = nullptr; + d->gwaviWriter = gwavi_open((baseName + ".avi").toLatin1().data(), 800, + 600, "MJPG", 4, NULL); + } else { + d->gwaviWriter = nullptr; + d->gifWriter = nullptr; + } + + stepChanged(m_currentFrame); + m_dialog->setStep(m_currentFrame); + calculateSurface(); +} + +void Surfaces::movieFrame() +{ + // Not ideal, need to let things update asynchronously, complete, before we + // capture the frame. When appropriate move to the next frame or complete. + QCoreApplication::sendPostedEvents(); + QCoreApplication::processEvents(); + + auto glWidget = QtOpenGL::ActiveObjects::instance().activeGLWidget(); + if (!glWidget) { + QMessageBox::warning(qobject_cast(parent()), tr("Avogadro"), + "Couldn't find the active render widget, failing."); + m_recordingMovie = false; + m_dialog->enableRecord(); + return; + } + glWidget->resize(800 / glWidget->devicePixelRatio(), + 600 / glWidget->devicePixelRatio()); + QImage exportImage; + glWidget->raise(); + glWidget->repaint(); + if (QOpenGLFramebufferObject::hasOpenGLFramebufferObjects()) { + exportImage = glWidget->grabFramebuffer(); + } else { + QPixmap pixmap = QPixmap::grabWindow(glWidget->winId()); + exportImage = pixmap.toImage(); + } + + if (d->gifWriter) { + int pixelCount = exportImage.width() * exportImage.height(); + uint8_t* imageData = new uint8_t[pixelCount * 4]; + int imageIndex = 0; + for (int j = 0; j < exportImage.height(); ++j) { + for (int k = 0; k < exportImage.width(); ++k) { + QColor color = exportImage.pixel(k, j); + imageData[imageIndex] = static_cast(color.red()); + imageData[imageIndex + 1] = static_cast(color.green()); + imageData[imageIndex + 2] = static_cast(color.blue()); + imageData[imageIndex + 3] = static_cast(color.alpha()); + imageIndex += 4; + } + } + GifWriteFrame(d->gifWriter, imageData, 800, 600, 100 / 4); + delete[] imageData; + } else if (d->gwaviWriter) { + QByteArray ba; + QBuffer buffer(&ba); + buffer.open(QIODevice::WriteOnly); + exportImage.save(&buffer, "JPG"); + if (gwavi_add_frame( + d->gwaviWriter, + reinterpret_cast(buffer.data().data()), + buffer.size()) == -1) { + QMessageBox::warning(qobject_cast(parent()), tr("Avogadro"), + tr("Error: cannot add frame to video.")); + } + } else { + QString fileName = QString::number(m_currentFrame); + while (fileName.length() < m_numberLength) + fileName.prepend('0'); + fileName.prepend(m_baseFileName); + fileName.append(".png"); + qDebug() << "Writing to" << fileName; + + if (!exportImage.save(fileName)) { + QMessageBox::warning(qobject_cast(parent()), tr("Avogadro"), + tr("Cannot save file %1.").arg(fileName)); + return; + } + } + + // Increment current frame. + ++m_currentFrame; + if (m_currentFrame <= m_frameCount) { + qDebug() << "Starting next frame..."; + stepChanged(m_currentFrame); + m_dialog->setStep(m_currentFrame); + calculateSurface(); + } else { + qDebug() << "We are done! Make some movies."; + if (d->gifWriter) { + GifEnd(d->gifWriter); + delete d->gifWriter; + d->gifWriter = nullptr; + } else if (d->gwaviWriter) { + gwavi_close(d->gwaviWriter); + d->gwaviWriter = nullptr; + } else { + QProcess proc; + QStringList args; + args << "-y" + << "-r" << QString::number(10) << "-i" + << m_baseFileName + "%0" + QString::number(m_numberLength) + "d.png" + << "-c:v" + << "libx264" + << "-r" + << "30" + << "-pix_fmt" + << "yuv420p" << m_baseFileName + ".mp4"; + proc.execute("avconv", args); + } + /* + args.clear(); + args << "-dispose" + << "Background" + << "-delay" << QString::number(100 / 10) + << m_baseFileName + "%0" + QString::number(m_numberLength) + "d.png[0-" + + QString::number(m_molecule->coordinate3dCount() - 1) + "]" + << m_baseFileName + ".gif"; + proc.execute("convert", args); + */ + + m_recordingMovie = false; + m_dialog->enableRecord(); + } +} + } // namespace QtPlugins } // namespace Avogadro diff --git a/avogadro/qtplugins/surfaces/surfaces.h b/avogadro/qtplugins/surfaces/surfaces.h index e7c4ebe09d..3b3319de68 100644 --- a/avogadro/qtplugins/surfaces/surfaces.h +++ b/avogadro/qtplugins/surfaces/surfaces.h @@ -39,8 +39,7 @@ namespace QtPlugins { /** * @brief The Surfaces plugin registers quantum file formats, adds several - * menu entries to calculate surfaces, including QM ones - * @author Marcus D. Hanwell + * menu entries to calculate surfaces, including QM ones. */ class GaussianSetConcurrent; @@ -84,29 +83,44 @@ private slots: void calculateQM(); void calculateCube(); + void stepChanged(int); + void displayMesh(); void meshFinished(); + void recordMovie(); + void movieFrame(); + private: QList m_actions; - QProgressDialog* m_progressDialog; + QProgressDialog* m_progressDialog = nullptr; - QtGui::Molecule* m_molecule; - Core::BasisSet* m_basis; + QtGui::Molecule* m_molecule = nullptr; + Core::BasisSet* m_basis = nullptr; - GaussianSetConcurrent* m_gaussianConcurrent; - SlaterSetConcurrent* m_slaterConcurrent; + GaussianSetConcurrent* m_gaussianConcurrent = nullptr; + SlaterSetConcurrent* m_slaterConcurrent = nullptr; - Core::Cube* m_cube; + Core::Cube* m_cube = nullptr; std::vector m_cubes; - Core::Mesh* m_mesh1; - Core::Mesh* m_mesh2; - QtGui::MeshGenerator* m_meshGenerator1; - QtGui::MeshGenerator* m_meshGenerator2; + Core::Mesh* m_mesh1 = nullptr; + Core::Mesh* m_mesh2 = nullptr; + QtGui::MeshGenerator* m_meshGenerator1 = nullptr; + QtGui::MeshGenerator* m_meshGenerator2 = nullptr; + + float m_isoValue = 0.01; + int m_meshesLeft = 0; + + bool m_recordingMovie = false; + int m_currentFrame = 0; + int m_frameCount = 1; + QString m_baseFileName; + int m_numberLength = 1; - float m_isoValue; + SurfaceDialog* m_dialog = nullptr; - SurfaceDialog* m_dialog; + class PIMPL; + PIMPL* d = nullptr; }; } } From a1ba5adf7029d8f36ab48fdc2926bf1a6217bb75 Mon Sep 17 00:00:00 2001 From: "Marcus D. Hanwell" Date: Sat, 11 Aug 2018 17:22:11 -0400 Subject: [PATCH 34/68] Fixed a memory leak in the player tool Signed-off-by: Marcus D. Hanwell --- avogadro/qtplugins/playertool/playertool.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/avogadro/qtplugins/playertool/playertool.cpp b/avogadro/qtplugins/playertool/playertool.cpp index c5d0547712..f0006a9b98 100644 --- a/avogadro/qtplugins/playertool/playertool.cpp +++ b/avogadro/qtplugins/playertool/playertool.cpp @@ -295,6 +295,7 @@ void PlayerTool::recordMovie() } GifWriteFrame(&writer, imageData, EXPORT_WIDTH, EXPORT_HEIGHT, 100 / m_animationFPS->value()); + delete[] imageData; } GifEnd(&writer); } else if (selfFilter == tr("Movie (*.avi)")) { From f2f00967ded8acd6762c312a999a2b895513b053 Mon Sep 17 00:00:00 2001 From: "Marcus D. Hanwell" Date: Sat, 11 Aug 2018 20:05:13 -0400 Subject: [PATCH 35/68] Applied clang-format fixes Need to remember to just run this as I make commits... Signed-off-by: Marcus D. Hanwell --- avogadro/core/gaussianset.h | 4 +-- avogadro/io/cjsonformat.cpp | 4 +-- avogadro/qtopengl/activeobjects.cpp | 4 +-- avogadro/qtopengl/activeobjects.h | 6 ++--- avogadro/qtplugins/meshes/meshes.cpp | 8 ++---- avogadro/qtplugins/surfaces/surfacedialog.cpp | 6 ++--- avogadro/qtplugins/surfaces/surfaces.cpp | 27 ++++++++++--------- 7 files changed, 27 insertions(+), 32 deletions(-) diff --git a/avogadro/core/gaussianset.h b/avogadro/core/gaussianset.h index c22e6a65be..9ec93a4f92 100644 --- a/avogadro/core/gaussianset.h +++ b/avogadro/core/gaussianset.h @@ -129,8 +129,8 @@ class AVOGADROCORE_EXPORT GaussianSet : public BasisSet * @param type The type of the MOs (Paired, Alpha, Beta). * @param index The index of the MO in the sequence. */ - void setMolecularOrbitals(const std::vector& MOs, - ElectronType type, Index index); + void setMolecularOrbitals(const std::vector& MOs, ElectronType type, + Index index); /** * Get the number of elements in the set. diff --git a/avogadro/io/cjsonformat.cpp b/avogadro/io/cjsonformat.cpp index 244b7ffe5a..2ffb932e63 100644 --- a/avogadro/io/cjsonformat.cpp +++ b/avogadro/io/cjsonformat.cpp @@ -153,8 +153,8 @@ bool CjsonFormat::read(std::istream& file, Molecule& molecule) json set = coordSets[i]; if (isNumericArray(set)) { for (unsigned int j = 0; j < set.size() / 3; ++j) { - setArray.push_back(Vector3(set[3 * j], set[3 * j + 1], - set[3 * j + 2])); + setArray.push_back( + Vector3(set[3 * j], set[3 * j + 1], set[3 * j + 2])); } molecule.setCoordinate3d(setArray, i); } diff --git a/avogadro/qtopengl/activeobjects.cpp b/avogadro/qtopengl/activeobjects.cpp index 220bbe2e12..ee62aa6891 100644 --- a/avogadro/qtopengl/activeobjects.cpp +++ b/avogadro/qtopengl/activeobjects.cpp @@ -29,5 +29,5 @@ void ActiveObjects::setActiveGLWidget(GLWidget* glWidget) m_glWidget = glWidget; } -} // End QtOpenGL namespace -} // End Avogadro namespace \ No newline at end of file +} // namespace QtOpenGL +} // namespace Avogadro diff --git a/avogadro/qtopengl/activeobjects.h b/avogadro/qtopengl/activeobjects.h index 3e48cfb58f..669f41d137 100644 --- a/avogadro/qtopengl/activeobjects.h +++ b/avogadro/qtopengl/activeobjects.h @@ -52,7 +52,7 @@ public slots: QPointer m_glWidget = nullptr; }; -} // End QtOpenGL namespace -} // End Avogadro namespace +} // namespace QtOpenGL +} // namespace Avogadro -#endif // AVOGADRO_QTOPENGL_ACTIVEOBJECTS_H \ No newline at end of file +#endif // AVOGADRO_QTOPENGL_ACTIVEOBJECTS_H diff --git a/avogadro/qtplugins/meshes/meshes.cpp b/avogadro/qtplugins/meshes/meshes.cpp index 610fcf8113..6a64d0a021 100644 --- a/avogadro/qtplugins/meshes/meshes.cpp +++ b/avogadro/qtplugins/meshes/meshes.cpp @@ -36,13 +36,9 @@ using Rendering::GeometryNode; using Rendering::GroupNode; using Rendering::MeshGeometry; -Meshes::Meshes(QObject* p) : ScenePlugin(p), m_enabled(true) -{ -} +Meshes::Meshes(QObject* p) : ScenePlugin(p), m_enabled(true) {} -Meshes::~Meshes() -{ -} +Meshes::~Meshes() {} // Generator for std::generate call below: namespace { diff --git a/avogadro/qtplugins/surfaces/surfacedialog.cpp b/avogadro/qtplugins/surfaces/surfacedialog.cpp index 25971e80ef..0362189dac 100644 --- a/avogadro/qtplugins/surfaces/surfacedialog.cpp +++ b/avogadro/qtplugins/surfaces/surfacedialog.cpp @@ -23,8 +23,7 @@ namespace Avogadro { namespace QtPlugins { SurfaceDialog::SurfaceDialog(QWidget* parent_, Qt::WindowFlags f) - : QDialog(parent_, f) - , m_ui(new Ui::SurfaceDialog) + : QDialog(parent_, f), m_ui(new Ui::SurfaceDialog) { m_ui->setupUi(this); @@ -48,8 +47,7 @@ SurfaceDialog::SurfaceDialog(QWidget* parent_, Qt::WindowFlags f) SLOT(surfaceComboChanged(int))); connect(m_ui->resolutionCombo, SIGNAL(currentIndexChanged(int)), SLOT(resolutionComboChanged(int))); - connect(m_ui->stepValue, SIGNAL(valueChanged(int)), - SIGNAL(stepChanged(int))); + connect(m_ui->stepValue, SIGNAL(valueChanged(int)), SIGNAL(stepChanged(int))); connect(m_ui->calculateButton, SIGNAL(clicked()), SLOT(calculateClicked())); connect(m_ui->recordButton, SIGNAL(clicked()), SLOT(record())); } diff --git a/avogadro/qtplugins/surfaces/surfaces.cpp b/avogadro/qtplugins/surfaces/surfaces.cpp index 43cfea5274..4a41173f81 100644 --- a/avogadro/qtplugins/surfaces/surfaces.cpp +++ b/avogadro/qtplugins/surfaces/surfaces.cpp @@ -21,7 +21,7 @@ #include "slatersetconcurrent.h" // Header only, but duplicte symbols if included globally... -namespace{ +namespace { #include } @@ -49,8 +49,8 @@ namespace{ #include #include -#include #include +#include #include #include #include @@ -127,8 +127,7 @@ void Surfaces::surfacesActivated() m_dialog = new SurfaceDialog(qobject_cast(parent())); connect(m_dialog, SIGNAL(calculateClickedSignal()), SLOT(calculateSurface())); - connect(m_dialog, SIGNAL(recordClicked()), - SLOT(recordMovie())); + connect(m_dialog, SIGNAL(recordClicked()), SLOT(recordMovie())); connect(m_dialog, SIGNAL(stepChanged(int)), SLOT(stepChanged(int))); } @@ -270,8 +269,9 @@ void Surfaces::calculateQM() m_progressDialog->show(); if (connectSlots) { - connect(&m_gaussianConcurrent->watcher(), SIGNAL(progressValueChanged(int)), - m_progressDialog, SLOT(setValue(int))); + connect(&m_gaussianConcurrent->watcher(), + SIGNAL(progressValueChanged(int)), m_progressDialog, + SLOT(setValue(int))); connect(&m_gaussianConcurrent->watcher(), SIGNAL(progressRangeChanged(int, int)), m_progressDialog, SLOT(setRange(int, int))); @@ -406,12 +406,12 @@ void Surfaces::recordMovie() if (selectedFilter == tr("GIF (*.gif)")) { d->gwaviWriter = nullptr; d->gifWriter = new GifWriter; - GifBegin(d->gifWriter, (baseName + ".gif").toLatin1().data(), 800, - 600, 100 / 4); + GifBegin(d->gifWriter, (baseName + ".gif").toLatin1().data(), 800, 600, + 100 / 4); } else if (selectedFilter == tr("Movie AVI (*.avi)")) { d->gifWriter = nullptr; - d->gwaviWriter = gwavi_open((baseName + ".avi").toLatin1().data(), 800, - 600, "MJPG", 4, NULL); + d->gwaviWriter = gwavi_open((baseName + ".avi").toLatin1().data(), 800, 600, + "MJPG", 4, NULL); } else { d->gwaviWriter = nullptr; d->gifWriter = nullptr; @@ -456,7 +456,7 @@ void Surfaces::movieFrame() for (int j = 0; j < exportImage.height(); ++j) { for (int k = 0; k < exportImage.width(); ++k) { QColor color = exportImage.pixel(k, j); - imageData[imageIndex] = static_cast(color.red()); + imageData[imageIndex] = static_cast(color.red()); imageData[imageIndex + 1] = static_cast(color.green()); imageData[imageIndex + 2] = static_cast(color.blue()); imageData[imageIndex + 3] = static_cast(color.alpha()); @@ -475,7 +475,7 @@ void Surfaces::movieFrame() reinterpret_cast(buffer.data().data()), buffer.size()) == -1) { QMessageBox::warning(qobject_cast(parent()), tr("Avogadro"), - tr("Error: cannot add frame to video.")); + tr("Error: cannot add frame to video.")); } } else { QString fileName = QString::number(m_currentFrame); @@ -527,7 +527,8 @@ void Surfaces::movieFrame() args << "-dispose" << "Background" << "-delay" << QString::number(100 / 10) - << m_baseFileName + "%0" + QString::number(m_numberLength) + "d.png[0-" + + << m_baseFileName + "%0" + QString::number(m_numberLength) + "d.png[0-" + + QString::number(m_molecule->coordinate3dCount() - 1) + "]" << m_baseFileName + ".gif"; proc.execute("convert", args); From b92902ea90d70e761295ed886329f98e0a0a6db6 Mon Sep 17 00:00:00 2001 From: "Marcus D. Hanwell" Date: Sun, 12 Aug 2018 12:01:32 -0400 Subject: [PATCH 36/68] Fix issue with multi view widget and button text Some window managers, such as KDE, seem to add the & to the button text automatically, breaking string comparisons. We should try to use properties and similar to store unique strings that won't be changed by translation, the window manager, etc. Signed-off-by: Marcus D. Hanwell --- avogadro/qtgui/multiviewwidget.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/avogadro/qtgui/multiviewwidget.cpp b/avogadro/qtgui/multiviewwidget.cpp index 60f6f26465..3b8f13a51e 100644 --- a/avogadro/qtgui/multiviewwidget.cpp +++ b/avogadro/qtgui/multiviewwidget.cpp @@ -19,6 +19,7 @@ #include "viewfactory.h" #include +#include #include #include #include @@ -131,7 +132,7 @@ void MultiViewWidget::createView() ContainerWidget* container = qobject_cast(optionsWidget->parentWidget()); if (container) { - QWidget* widget = m_factory->createView(button->text()); + auto widget = m_factory->createView(button->property("name").toString()); if (widget) { widget->installEventFilter(m_activeFilter); container->layout()->removeWidget(optionsWidget); @@ -198,6 +199,7 @@ ContainerWidget* MultiViewWidget::createContainer(QWidget* widget) v->addStretch(); foreach (const QString& name, m_factory->views()) { QPushButton* button = new QPushButton(name); + button->setProperty("name", name); button->setToolTip(tr("Create a new view")); connect(button, SIGNAL(clicked()), SLOT(createView())); QHBoxLayout* h = new QHBoxLayout; From 467b1f2e51ee08c225add02d707decc65dd702c9 Mon Sep 17 00:00:00 2001 From: Patrick Avery Date: Mon, 13 Aug 2018 10:21:43 -0400 Subject: [PATCH 37/68] Plugin Downloader: move to nlohmann json Part of the transfer to use nlohmann json instead of cpp json, this eliminates the cpp json usage in the plugin downloader to use nlohmann json instead. I also fixed a few memory leaks that were present. Signed-off-by: Patrick Avery --- .../qtplugins/plugindownloader/CMakeLists.txt | 4 +- .../plugindownloader/downloaderwidget.cpp | 62 +++++++++++-------- .../plugindownloader/downloaderwidget.h | 20 +++--- 3 files changed, 49 insertions(+), 37 deletions(-) diff --git a/avogadro/qtplugins/plugindownloader/CMakeLists.txt b/avogadro/qtplugins/plugindownloader/CMakeLists.txt index 4b07a53a85..ded1c2ed8b 100644 --- a/avogadro/qtplugins/plugindownloader/CMakeLists.txt +++ b/avogadro/qtplugins/plugindownloader/CMakeLists.txt @@ -1,4 +1,4 @@ -include_directories(SYSTEM "${AvogadroLibs_SOURCE_DIR}/thirdparty/jsoncpp") +include_directories(SYSTEM "${AvogadroLibs_SOURCE_DIR}/thirdparty") find_package(LibArchive REQUIRED) include_directories(SYSTEM ${LIBARCHIVE_INCLUDE_DIRS}) @@ -20,4 +20,4 @@ avogadro_plugin(PluginDownloader ) target_link_libraries(PluginDownloader LINK_PRIVATE ${Qt5Network_LIBRARIES} - ${LIBARCHIVE_LIBRARIES} jsoncpp) + ${LIBARCHIVE_LIBRARIES}) diff --git a/avogadro/qtplugins/plugindownloader/downloaderwidget.cpp b/avogadro/qtplugins/plugindownloader/downloaderwidget.cpp index b8ba4f1ffc..b219ca5639 100644 --- a/avogadro/qtplugins/plugindownloader/downloaderwidget.cpp +++ b/avogadro/qtplugins/plugindownloader/downloaderwidget.cpp @@ -32,13 +32,14 @@ #include #include +using json = nlohmann::json; + namespace Avogadro { namespace QtPlugins { DownloaderWidget::DownloaderWidget(QWidget* parent) : QDialog(parent), m_ui(new Ui::DownloaderWidget) { - m_numRepos = 0; m_filePath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); m_NetworkAccessManager = new QNetworkAccessManager(this); @@ -64,8 +65,6 @@ DownloaderWidget::DownloaderWidget(QWidget* parent) DownloaderWidget::~DownloaderWidget() { delete m_ui; - delete m_repoList; - delete m_read; } // download master plugin.json from Avogadro.cc @@ -89,28 +88,36 @@ void DownloaderWidget::getRepoData() void DownloaderWidget::updateRepoData() { if (m_reply->error() == QNetworkReply::NoError) { - m_read = new Json::Reader(); // Reading the data from the response QByteArray bytes = m_reply->readAll(); - QString jsonString(bytes); // parse the json - m_read->parse(jsonString.toStdString().c_str(), m_root); - m_numRepos = m_root.size(); - m_repoList = new repo[m_numRepos]; - m_ui->repoTable->setRowCount(m_numRepos); - for (int i = 0; i < m_numRepos; i++) { - m_repoList[i].name = m_root[i].get("name", "Error").asCString(); - m_repoList[i].description = - m_root[i].get("description", "Error").asCString(); - m_repoList[i].releaseVersion = - m_root[i].get("release_version", "Error").asCString(); - m_repoList[i].type = m_root[i].get("type", "other").asCString(); - m_repoList[i].updatedAt = - m_root[i].get("updated_at", "Error").asCString(); - m_repoList[i].zipballUrl = - m_root[i].get("zipball_url", "Error").asCString(); - m_repoList[i].hasRelease = m_root[i].get("has_release", false).asBool(); + m_root = json::parse(bytes.data()); + int numRepos = m_root.size(); + m_ui->repoTable->setRowCount(numRepos); + m_repoList.clear(); + for (int i = 0; i < numRepos; i++) { + m_repoList.push_back(repo()); + + const auto& currentRoot = m_root[i]; + + // Loop through the keys + for (auto it = currentRoot.cbegin(); it != currentRoot.cend(); ++it) { + if (it.key() == "name" && it.value().is_string()) + m_repoList[i].name = it.value().get().c_str(); + else if (it.key() == "description" && it.value().is_string()) + m_repoList[i].description = it.value().get().c_str(); + else if (it.key() == "release_version" && it.value().is_string()) + m_repoList[i].releaseVersion = it.value().get().c_str(); + else if (it.key() == "type" && it.value().is_string()) + m_repoList[i].type = it.value().get().c_str(); + else if (it.key() == "updated_at" && it.value().is_string()) + m_repoList[i].updatedAt = it.value().get().c_str(); + else if (it.key() == "zipball_url" && it.value().is_string()) + m_repoList[i].zipballUrl = it.value().get().c_str(); + else if (it.key() == "has_release" && it.value().is_boolean()) + m_repoList[i].hasRelease = it.value().get(); + } // readme should be included or at least the repo url so we don't have to // do this @@ -161,16 +168,17 @@ void DownloaderWidget::downloadREADME(int row, int col) void DownloaderWidget::showREADME() { if (m_reply->error() == QNetworkReply::NoError) { - m_read = new Json::Reader(); // Reading the data from the response QByteArray bytes = m_reply->readAll(); - QString jsonString(bytes); // parse the json - m_read->parse(jsonString.toStdString().c_str(), m_root); + m_root = json::parse(bytes.data()); - int resultSize = m_root.size(); - QByteArray content = m_root.get("content", "ERROR").asCString(); + QByteArray content("ERROR"); + if (m_root.find("content") != m_root.end() && + m_root["content"].is_string()) { + content = m_root["content"].get().c_str(); + } m_ui->readmeBrowser->append(QByteArray::fromBase64(content).data()); } } @@ -180,7 +188,7 @@ void DownloaderWidget::getCheckedRepos() { m_ui->readmeBrowser->clear(); m_downloadList.clear(); - for (int i = 0; i < m_numRepos; i++) { + for (size_t i = 0; i < m_repoList.size(); i++) { if (m_ui->repoTable->item(i, 0)->checkState() == Qt::Checked) { downloadEntry newEntry; newEntry.url = m_repoList[i].zipballUrl; diff --git a/avogadro/qtplugins/plugindownloader/downloaderwidget.h b/avogadro/qtplugins/plugindownloader/downloaderwidget.h index 0395425fdf..31faaf24bc 100644 --- a/avogadro/qtplugins/plugindownloader/downloaderwidget.h +++ b/avogadro/qtplugins/plugindownloader/downloaderwidget.h @@ -23,7 +23,7 @@ #include -#include +#include class QNetworkAccessManager; class QNetworkReply; @@ -63,6 +63,13 @@ public slots: QString zipballUrl; QString readmeUrl; bool hasRelease; + + // Default constructor + repo() + : name("Error"), description("Error"), releaseVersion("Error"), + type("other"), updatedAt("Error"), zipballUrl("Error"), + readmeUrl("Error"), hasRelease(false) + {} }; struct downloadEntry @@ -77,22 +84,19 @@ public slots: void downloadNext(); bool checkSHA1(QByteArray); - struct repo* m_repoList; + std::vector m_repoList; Ui::DownloaderWidget* m_ui; QNetworkAccessManager* m_NetworkAccessManager; QNetworkReply* m_reply; - /** Jsoncpp reader to read JSON results */ - Json::Reader* m_read; /** Holds a node of JSON results */ - Json::Value m_root; + nlohmann::json m_root; /** Used to parse JSON results */ QVariantMap m_jsonResult; QString m_filePath; QList m_downloadList; - int m_numRepos; }; -} -} +} // namespace QtPlugins +} // namespace Avogadro #endif // AVOGADRO_DOWNLOADERWIDGET_H From 459ca389b3d8c64ea01080e85c5dec98b82b683a Mon Sep 17 00:00:00 2001 From: Patrick Avery Date: Mon, 13 Aug 2018 10:53:10 -0400 Subject: [PATCH 38/68] Avogadro io: remove unused jsoncpp linking The header file was also removed, as it is unused as well. Signed-off-by: Patrick Avery --- avogadro/io/CMakeLists.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/avogadro/io/CMakeLists.txt b/avogadro/io/CMakeLists.txt index ceed559b44..b683c5d439 100644 --- a/avogadro/io/CMakeLists.txt +++ b/avogadro/io/CMakeLists.txt @@ -15,7 +15,6 @@ endif() # compilers that support that notion. include_directories(SYSTEM "${EIGEN3_INCLUDE_DIR}" "${AvogadroLibs_SOURCE_DIR}/thirdparty/pugixml" - "${AvogadroLibs_SOURCE_DIR}/thirdparty/jsoncpp" "${AvogadroLibs_SOURCE_DIR}/thirdparty/struct" "${AvogadroLibs_SOURCE_DIR}/thirdparty") @@ -63,7 +62,7 @@ avogadro_add_library(AvogadroIO ${HEADERS} ${SOURCES}) target_link_libraries(AvogadroIO LINK_PUBLIC AvogadroCore - LINK_PRIVATE jsoncpp struct) + LINK_PRIVATE struct) if(USE_HDF5) target_link_libraries(AvogadroIO LINK_PRIVATE ${HDF5_LIBRARIES}) endif() From edc65efbbd7ea86540fae9c24596d54f9f3e7582 Mon Sep 17 00:00:00 2001 From: Patrick Avery Date: Mon, 13 Aug 2018 10:50:30 -0400 Subject: [PATCH 39/68] Remove unused jsoncpp header in spectra plugin Signed-off-by: Patrick Avery --- avogadro/qtplugins/spectra/CMakeLists.txt | 2 -- avogadro/qtplugins/spectra/spectra.cpp | 2 -- 2 files changed, 4 deletions(-) diff --git a/avogadro/qtplugins/spectra/CMakeLists.txt b/avogadro/qtplugins/spectra/CMakeLists.txt index a2216b8b4c..6de1349ff8 100644 --- a/avogadro/qtplugins/spectra/CMakeLists.txt +++ b/avogadro/qtplugins/spectra/CMakeLists.txt @@ -1,5 +1,3 @@ -include_directories(SYSTEM "${AvogadroLibs_SOURCE_DIR}/thirdparty/jsoncpp") - set(plugin_srcs vibrationdialog.cpp vibrationmodel.cpp diff --git a/avogadro/qtplugins/spectra/spectra.cpp b/avogadro/qtplugins/spectra/spectra.cpp index 043b52e5ef..aa9c641b9a 100644 --- a/avogadro/qtplugins/spectra/spectra.cpp +++ b/avogadro/qtplugins/spectra/spectra.cpp @@ -26,8 +26,6 @@ #include #include -#include - namespace Avogadro { namespace QtPlugins { From c4b9859fcca271fda700beb9b651c4b10d6ad4f3 Mon Sep 17 00:00:00 2001 From: Patrick Avery Date: Mon, 13 Aug 2018 13:14:59 -0400 Subject: [PATCH 40/68] ImportPQR: move to nlohmann json Part of the transfer to use nlohmann json instead of cpp json, this eliminates the cpp json usage in the import pqr plugin to use nlohmann json instead. I also fixed a few memory leaks that were present. Signed-off-by: Patrick Avery --- avogadro/qtplugins/importpqr/CMakeLists.txt | 4 +-- avogadro/qtplugins/importpqr/pqrrequest.cpp | 36 +++++++++++++-------- avogadro/qtplugins/importpqr/pqrrequest.h | 18 +++++------ 3 files changed, 33 insertions(+), 25 deletions(-) diff --git a/avogadro/qtplugins/importpqr/CMakeLists.txt b/avogadro/qtplugins/importpqr/CMakeLists.txt index ee27da941c..5858bc51e2 100644 --- a/avogadro/qtplugins/importpqr/CMakeLists.txt +++ b/avogadro/qtplugins/importpqr/CMakeLists.txt @@ -1,4 +1,4 @@ -include_directories(SYSTEM "${AvogadroLibs_SOURCE_DIR}/thirdparty/jsoncpp") +include_directories(SYSTEM "${AvogadroLibs_SOURCE_DIR}/thirdparty") # Extension set(importpqr_srcs @@ -17,4 +17,4 @@ avogadro_plugin(ImportPQR "" ) -target_link_libraries(ImportPQR LINK_PRIVATE ${Qt5Network_LIBRARIES} jsoncpp) +target_link_libraries(ImportPQR LINK_PRIVATE ${Qt5Network_LIBRARIES}) diff --git a/avogadro/qtplugins/importpqr/pqrrequest.cpp b/avogadro/qtplugins/importpqr/pqrrequest.cpp index 8877b24c6e..1b61f612d1 100644 --- a/avogadro/qtplugins/importpqr/pqrrequest.cpp +++ b/avogadro/qtplugins/importpqr/pqrrequest.cpp @@ -3,6 +3,10 @@ #include +#include + +using json = nlohmann::json; + namespace Avogadro { namespace QtPlugins { /** @@ -28,8 +32,6 @@ PQRRequest::PQRRequest(QTableWidget* tw, QLabel* gv, QLineEdit* nd, QLabel* fd, */ PQRRequest::~PQRRequest() { - delete results; - delete read; delete oNetworkAccessManager; } @@ -75,7 +77,7 @@ void PQRRequest::sendPNGRequest(QString url) */ QString PQRRequest::molSelected(int num) { - if (results == nullptr) + if (results.empty() || num > results.size()) return QString("N/A"); QString mol2 = results[num].mol2url; @@ -94,30 +96,36 @@ QString PQRRequest::molSelected(int num) void PQRRequest::parseJson() { if (reply->error() == QNetworkReply::NoError) { - read = new Json::Reader(); // Reading the data from the response QByteArray bytes = reply->readAll(); - QString jsonString(bytes); // parse the json - read->parse(jsonString.toStdString().c_str(), root); + json root = json::parse(bytes.data()); int resultSize = root.size(); + results.clear(); if (resultSize == 0) { table->setRowCount(1); table->setItem(0, 0, new QTableWidgetItem("No Results!")); table->setCellWidget(0, 1, new QLabel()); table->setItem(0, 2, new QTableWidgetItem("N/A")); - results = nullptr; } else { - results = new result[root.size()]; table->setRowCount(resultSize); for (int i = 0; i < resultSize; i++) { - results[i].formula = root[i].get("formula", "Error").asCString(); - results[i].inchikey = root[i].get("inchikey", "Error").asCString(); - results[i].mol2url = root[i].get("mol2url", "Error").asCString(); - results[i].name = root[i].get("name", "Error").asCString(); + results.push_back(result()); + + // Loop through the keys + for (auto it = root[i].cbegin(); it != root[i].cend(); ++it) { + if (it.key() == "formula" && it.value().is_string()) + results[i].formula = it.value().get().c_str(); + else if (it.key() == "inchikey" && it.value().is_string()) + results[i].inchikey = it.value().get().c_str(); + else if (it.key() == "mol2url" && it.value().is_string()) + results[i].mol2url = it.value().get().c_str(); + else if (it.key() == "name" && it.value().is_string()) + results[i].name = it.value().get().c_str(); + } results[i].mass = getMolMass(results[i].formula); table->setItem(i, 0, new QTableWidgetItem(results[i].name)); @@ -239,5 +247,5 @@ float PQRRequest::getMolMass(QString formula) } return totalMass; } -} -} +} // namespace QtPlugins +} // namespace Avogadro diff --git a/avogadro/qtplugins/importpqr/pqrrequest.h b/avogadro/qtplugins/importpqr/pqrrequest.h index 142564fe87..396155217c 100644 --- a/avogadro/qtplugins/importpqr/pqrrequest.h +++ b/avogadro/qtplugins/importpqr/pqrrequest.h @@ -19,8 +19,6 @@ #include -#include - /** * @brief The PQRRequest class sends and receives network requests to PQR and * updates ui elements from the widget. @@ -104,16 +102,18 @@ private slots: QString mol2url; QString formula; float mass; + + // Default constructor + result() + : inchikey("Error"), name("Error"), mol2url("Error"), formula("Error"), + mass(-1.0) + {} }; /** An array to hold all results from a query */ - result* results; + std::vector results; /** Holds a reply from a network request */ QNetworkReply* reply; - /** Jsoncpp reader to read JSON results */ - Json::Reader* read; - /** Holds a node of JSON results */ - Json::Value root; /** Used to send/receive network request */ QNetworkAccessManager* oNetworkAccessManager; /** Used to parse JSON results */ @@ -144,6 +144,6 @@ private slots: */ float getMolMass(QString); }; -} -} +} // namespace QtPlugins +} // namespace Avogadro #endif // PQRRequest_H From 3bc839dd97e29cf2e86237ad5f01fc3fc8978901 Mon Sep 17 00:00:00 2001 From: Patrick Avery Date: Mon, 13 Aug 2018 14:17:28 -0400 Subject: [PATCH 41/68] NWChemJson: Use nlohmann json Part of the transfer to use nlohmann json instead of cpp json, this eliminates the cpp json usage in quantumio to use nlohmann json instead. Signed-off-by: Patrick Avery --- avogadro/quantumio/CMakeLists.txt | 4 +- avogadro/quantumio/nwchemjson.cpp | 240 ++++++++++++++++-------------- 2 files changed, 127 insertions(+), 117 deletions(-) diff --git a/avogadro/quantumio/CMakeLists.txt b/avogadro/quantumio/CMakeLists.txt index 15073e8d56..886942f6ed 100644 --- a/avogadro/quantumio/CMakeLists.txt +++ b/avogadro/quantumio/CMakeLists.txt @@ -2,7 +2,7 @@ find_package(Eigen3 REQUIRED) # Add as "system headers" to avoid warnings generated by them with # compilers that support that notion. include_directories(SYSTEM "${EIGEN3_INCLUDE_DIR}" - "${AvogadroLibs_SOURCE_DIR}/thirdparty/jsoncpp") + "${AvogadroLibs_SOURCE_DIR}/thirdparty") include_directories(${CMAKE_CURRENT_BINARY_DIR}) @@ -30,4 +30,4 @@ set(SOURCES ) avogadro_add_library(AvogadroQuantumIO ${HEADERS} ${SOURCES}) -target_link_libraries(AvogadroQuantumIO LINK_PUBLIC AvogadroIO LINK_PRIVATE jsoncpp) +target_link_libraries(AvogadroQuantumIO LINK_PUBLIC AvogadroIO) diff --git a/avogadro/quantumio/nwchemjson.cpp b/avogadro/quantumio/nwchemjson.cpp index 9d93d6d683..c97bbba9dd 100644 --- a/avogadro/quantumio/nwchemjson.cpp +++ b/avogadro/quantumio/nwchemjson.cpp @@ -23,21 +23,19 @@ #include #include -#include +#include #include namespace Avogadro { namespace QuantumIO { -using std::string; -using std::vector; using std::cout; using std::endl; +using std::string; +using std::vector; -using Json::Value; -using Json::Reader; -using Json::StyledStreamWriter; +using nlohmann::json; using Core::Array; using Core::Atom; @@ -47,112 +45,116 @@ using Core::CrystalTools; using Core::Elements; using Core::GaussianSet; using Core::Molecule; -using Core::Variant; using Core::split; +using Core::Variant; -NWChemJson::NWChemJson() -{ -} +NWChemJson::NWChemJson() {} -NWChemJson::~NWChemJson() -{ -} +NWChemJson::~NWChemJson() {} bool NWChemJson::read(std::istream& file, Molecule& molecule) { - Value root; - Reader reader; - bool ok = reader.parse(file, root); - if (!ok) { - appendError("Error parsing JSON: " + reader.getFormatedErrorMessages()); + json root; + try { + file >> root; + } catch (json::parse_error& e) { + appendError("Error parsing JSON: " + string(e.what())); return false; } - if (!root.isObject()) { + if (!root.is_object()) { appendError("Error: Input is not a JSON object."); return false; } - Value simulation = root["simulation"]; - if (simulation.empty()) { + if (root.find("simulation") == root.end()) { appendError("Error: no \"simulation\" key found."); return false; } - // Scan the calculations array for calculationSetup.molecule objects. - Value calculations = simulation["calculations"]; - if (calculations.empty() || !calculations.isArray()) { + json simulation = root["simulation"]; + + if (simulation.find("calculations") == simulation.end() || + !simulation["calculations"].is_array()) { appendError("Error: no \"calculations\" array found."); return false; } + // Scan the calculations array for calculationSetup.molecule objects. + json calculations = simulation["calculations"]; + // Iterate through the objects in the array, and print out any molecules. - Value moleculeArray(Json::arrayValue); - Value basisSetArray(Json::arrayValue); - Value calculationVib; - Value molecularOrbitals; + json moleculeArray = json::array(); + json basisSetArray = json::array(); + json calculationVib; + json molecularOrbitals; int numberOfElectrons = 0; string theory; string xcFunctional; for (size_t i = 0; i < calculations.size(); ++i) { - Value calcObj = calculations.get(i, ""); - if (calcObj.isObject()) { - string calcType = calcObj["calculationType"].asString(); + json calcObj = calculations[i]; + if (calcObj.is_object()) { + string calcType = calcObj.value("calculationType", ""); // Store the last vibrational frequencies calculation object. if (calcType == "vibrationalModes") calculationVib = calcObj; - Value calcSetup = calcObj["calculationSetup"]; - Value calcMol = calcSetup["molecule"]; - numberOfElectrons = calcSetup["numberOfElectrons"].asInt(); - if (calcSetup.isMember("exchangeCorrelationFunctional")) { - Value functional = calcSetup["exchangeCorrelationFunctional"].get( - Value::ArrayIndex(0), ""); - if (functional.isObject()) { - xcFunctional = functional["xcName"].asString(); + json calcSetup = calcObj.value("calculationSetup", json()); + json calcMol = calcSetup.value("molecule", json()); + numberOfElectrons = calcSetup.value("numberOfElectrons", -1); + if (calcSetup.count("exchangeCorrelationFunctional") && + calcSetup["exchangeCorrelationFunctional"].is_array() && + !calcSetup["exchangeCorrelationFunctional"].empty()) { + json functional = calcSetup["exchangeCorrelationFunctional"][0]; + if (functional.is_object()) { + xcFunctional = functional.value("xcName", ""); } if (xcFunctional == "B3LYP Method XC Potential") { xcFunctional = "b3lyp"; } } - if (calcSetup.isMember("waveFunctionTheory")) { - theory = calcSetup["waveFunctionTheory"].asString(); + if (calcSetup.count("waveFunctionTheory")) { + theory = calcSetup["waveFunctionTheory"]; if (theory == "Density Functional Theory") { theory = "dft"; } } - if (!calcMol.isNull() && calcMol.isObject()) - moleculeArray.append(calcMol); - Value basisSet = calcSetup["basisSet"]; - if (!basisSet.isNull() && basisSet.isObject()) - basisSetArray.append(basisSet); - - Value calcResults = calcObj["calculationResults"]; - calcMol = calcResults["molecule"]; - if (!calcMol.isNull() && calcMol.isObject()) - moleculeArray.append(calcMol); + if (!calcMol.is_null() && calcMol.is_object()) + moleculeArray.push_back(calcMol); + json basisSet = calcSetup.value("basisSet", json()); + if (!basisSet.is_null() && basisSet.is_object()) + basisSetArray.push_back(basisSet); + + json calcResults = calcObj.value("calculationResults", json()); + calcMol = calcResults.value("molecule", json()); + if (!calcMol.is_null() && calcMol.is_object()) + moleculeArray.push_back(calcMol); // There is currently one id for all, just get the last one we find. - if (!calcResults["molecularOrbitals"].isNull() && - calcResults["molecularOrbitals"].isObject()) + if (calcResults.count("molecularOrbitals") && + calcResults["molecularOrbitals"].is_object()) { molecularOrbitals = calcResults["molecularOrbitals"]; + } } } // For now, we are just grabbing the "last" molecule, and using that. This // needs more complex logic to step through the file and do it properly. - Value finalMol = moleculeArray.get(moleculeArray.size() - 1, 0); - Value atoms = finalMol["atoms"]; - if (atoms.isArray()) { + json atoms; + if (!moleculeArray.empty()) { + json finalMol = moleculeArray.back(); + atoms = finalMol.value("atoms", json()); + } + if (atoms.is_array()) { for (size_t i = 0; i < atoms.size(); ++i) { - Value jsonAtom = atoms.get(i, 0); - if (jsonAtom.isNull() || !jsonAtom.isObject()) + json jsonAtom = atoms[i]; + if (jsonAtom.is_null() || !jsonAtom.is_object()) continue; Atom a = molecule.addAtom( - static_cast(jsonAtom["elementNumber"].asInt())); - Value pos = jsonAtom["cartesianCoordinates"]["value"]; - Vector3 position(pos.get(Json::Value::ArrayIndex(0), 0.0).asDouble(), - pos.get(Json::Value::ArrayIndex(1), 0.0).asDouble(), - pos.get(Json::Value::ArrayIndex(2), 0.0).asDouble()); - string units = jsonAtom["cartesianCoordinates"]["units"].asString(); + static_cast(jsonAtom.value("elementNumber", 0))); + json pos = jsonAtom["cartesianCoordinates"]["value"]; + Vector3 position; + if (pos.is_array() && pos.size() >= 3) + position = Vector3(pos[0], pos[1], pos[2]); + string units = jsonAtom["cartesianCoordinates"]["units"]; if (units == "bohr") position *= BOHR_TO_ANGSTROM_D; a.setPosition3d(position); @@ -162,16 +164,18 @@ bool NWChemJson::read(std::istream& file, Molecule& molecule) molecule.perceiveBondsSimple(); // Add in the electronic structure information if available. - if (molecularOrbitals.isObject() && - molecularOrbitals["atomicOrbitalDescriptions"].isArray()) { - Value basisSet = basisSetArray.get(basisSetArray.size() - 1, 0); - Value orbDesc = molecularOrbitals["atomicOrbitalDescriptions"]; + if (molecularOrbitals.is_object() && + molecularOrbitals["atomicOrbitalDescriptions"].is_array()) { + json basisSet; + if (!basisSetArray.empty()) + basisSet = basisSetArray.back(); + json orbDesc = molecularOrbitals.value("atomicOrbitalDescriptions", json()); // Figure out the mapping of basis set to molecular orbitals. Array atomNumber; Array atomSymbol; for (size_t i = 0; i < orbDesc.size(); ++i) { - string desc = orbDesc.get(i, 0).asString(); + string desc = orbDesc[i]; vector parts = split(desc, ' '); assert(parts.size() == 3); int num = Core::lexicalCast(parts[0]); @@ -187,46 +191,47 @@ bool NWChemJson::read(std::istream& file, Molecule& molecule) string basisSetName; for (size_t i = 0; i < atomSymbol.size(); ++i) { string symbol = atomSymbol[i]; - Value basisFunctions = basisSet["basisFunctions"]; - Value currentFunction; + json basisFunctions = basisSet.value("basisFunctions", json()); + json currentFunction; for (size_t j = 0; j < basisFunctions.size(); ++j) { - currentFunction = basisFunctions.get(j, 0); + currentFunction = basisFunctions[j]; string elementType; - if (currentFunction.isMember("elementLabel")) - elementType = currentFunction["elementLabel"].asString(); - else if (currentFunction.isMember("elementType")) - elementType = currentFunction["elementType"].asString(); + if (currentFunction.count("elementLabel")) + elementType = currentFunction["elementLabel"]; + else if (currentFunction.count("elementType")) + elementType = currentFunction["elementType"]; if (elementType == symbol) break; - currentFunction = Json::nullValue; + currentFunction = json(); } - if (currentFunction.isNull()) + if (currentFunction.is_null()) break; - if (currentFunction.isMember("basisSetName")) { + if (currentFunction.count("basisSetName")) { if (basisSetName.empty()) { - basisSetName = currentFunction["basisSetName"].asString(); - } else if (basisSetName != currentFunction["basisSetName"].asString()) { + basisSetName = currentFunction["basisSetName"]; + } else if (basisSetName != currentFunction["basisSetName"]) { basisSetName = "Custom"; } } - Value contraction = currentFunction["basisSetContraction"]; + json contraction = currentFunction.value("basisSetContraction", json()); bool spherical = - currentFunction["basisSetHarmonicType"].asString() == "spherical"; + currentFunction.value("basisSetHarmonicType", "") == "spherical"; for (size_t j = 0; j < contraction.size(); ++j) { - Value contractionShell = contraction.get(j, Json::nullValue); + json contractionShell = contraction[j]; string shellType; - if (contractionShell.isMember("basisSetShell")) - shellType = contractionShell["basisSetShell"].asString(); - else if (contractionShell.isMember("basisSetShellType")) - shellType = contractionShell["basisSetShellType"].asString(); - Value exponent = contractionShell["basisSetExponent"]; - Value coefficient = contractionShell["basisSetCoefficient"]; + if (contractionShell.count("basisSetShell")) + shellType = contractionShell["basisSetShell"]; + else if (contractionShell.count("basisSetShellType")) + shellType = contractionShell["basisSetShellType"]; + json exponent = contractionShell.value("basisSetExponent", json()); + json coefficient = + contractionShell.value("basisSetCoefficient", json()); assert(exponent.size() == coefficient.size()); GaussianSet::orbital type = GaussianSet::UU; if (shellType == "s") @@ -244,32 +249,35 @@ bool NWChemJson::read(std::istream& file, Molecule& molecule) if (type != GaussianSet::UU) { int b = basis->addBasis(i, type); - for (size_t k = 0; k < exponent.size(); ++k) { - basis->addGto(b, coefficient.get(k, 0).asDouble(), - exponent.get(k, 0).asDouble()); + for (size_t k = 0; k < exponent.size() && k < coefficient.size(); + ++k) { + basis->addGto(b, coefficient[k], exponent[k]); } } } } // Now to add the molecular orbital coefficients. - Value moCoeffs = molecularOrbitals["molecularOrbital"]; + json moCoeffs = molecularOrbitals.value("molecularOrbital", json()); vector coeffArray; vector energyArray; vector occArray; vector numArray; for (size_t i = 0; i < moCoeffs.size(); ++i) { - Value currentMO = moCoeffs.get(i, Json::nullValue); - Value coeff = currentMO["moCoefficients"]; + json currentMO = moCoeffs[i]; + json coeff = currentMO.value("moCoefficients", json()); for (size_t j = 0; j < coeff.size(); ++j) - coeffArray.push_back(coeff.get(j, 0).asDouble()); - if (currentMO.isMember("orbitalEnergy")) - energyArray.push_back(currentMO["orbitalEnergy"]["value"].asDouble()); - if (currentMO.isMember("orbitalOccupancy")) + coeffArray.push_back(coeff[j]); + if (currentMO.count("orbitalEnergy")) { + energyArray.push_back(currentMO["orbitalEnergy"].value("value", 0.0)); + } + if (currentMO.count("orbitalOccupancy")) { occArray.push_back( - static_cast(currentMO["orbitalOccupancy"].asInt())); - if (currentMO.isMember("orbitalNumber")) + static_cast(currentMO["orbitalOccupancy"])); + } + if (currentMO.count("orbitalNumber")) { numArray.push_back( - static_cast(currentMO["orbitalNumber"].asInt())); + static_cast(currentMO["orbitalNumber"])); + } } basis->setMolecularOrbitals(coeffArray); basis->setMolecularOrbitalEnergy(energyArray); @@ -283,23 +291,25 @@ bool NWChemJson::read(std::istream& file, Molecule& molecule) } // Now to see if there was a vibrational frequencies calculation. - if (!calculationVib.isNull() && calculationVib.isObject()) { - Value normalModes = calculationVib["calculationResults"]["normalModes"]; - if (!normalModes.isNull() && normalModes.isArray()) { + if (!calculationVib.is_null() && calculationVib.is_object()) { + json normalModes = calculationVib.value("calculationResults", json()) + .value("normalModes", json()); + if (!normalModes.is_null() && normalModes.is_array()) { Array frequencies; Array intensities; Array> Lx; for (size_t i = 0; i < normalModes.size(); ++i) { - Value mode = normalModes.get(i, ""); - frequencies.push_back(mode["normalModeFrequency"]["value"].asDouble()); - intensities.push_back( - mode["normalModeInfraRedIntensity"]["value"].asDouble()); - Value lx = mode["normalModeVector"]["value"]; - if (!lx.empty() && lx.isArray()) { + json mode = normalModes[i]; + frequencies.push_back( + mode.value("normalModeFrequency", json()).value("value", 0.0)); + intensities.push_back(mode.value("normalModeInfraRedIntensity", json()) + .value("value", 0.0)); + json lx = mode.value("normalModeVector", json()).value("value", json()); + if (!lx.empty() && lx.is_array()) { Array modeLx; modeLx.resize(lx.size() / 3); for (size_t k = 0; k < lx.size(); ++k) - modeLx[k / 3][k % 3] = lx.get(k, 0).asDouble(); + modeLx[k / 3][k % 3] = lx[k]; Lx.push_back(modeLx); } } @@ -332,5 +342,5 @@ vector NWChemJson::mimeTypes() const return mime; } -} // end QuantumIO namespace -} // end Avogadro namespace +} // namespace QuantumIO +} // namespace Avogadro From ea895eb4ecbc76e8bcb46dd8108200ccaf939b2b Mon Sep 17 00:00:00 2001 From: "Marcus D. Hanwell" Date: Tue, 21 Aug 2018 11:39:26 -0400 Subject: [PATCH 42/68] Fix a bug with file paths and movies The canonicalPath method returns an empty string if the file does not exist, causing a number of issues when used in the context of saving a movie. Switch to use absolutePath which does not care whether the file exists or not. Signed-off-by: Marcus D. Hanwell --- avogadro/qtplugins/playertool/playertool.cpp | 2 +- avogadro/qtplugins/surfaces/surfaces.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/avogadro/qtplugins/playertool/playertool.cpp b/avogadro/qtplugins/playertool/playertool.cpp index f0006a9b98..743e45e909 100644 --- a/avogadro/qtplugins/playertool/playertool.cpp +++ b/avogadro/qtplugins/playertool/playertool.cpp @@ -248,7 +248,7 @@ void PlayerTool::recordMovie() QFileInfo fileInfo(baseName); if (!fileInfo.suffix().isEmpty()) - baseName = fileInfo.canonicalPath() + "/" + fileInfo.baseName(); + baseName = fileInfo.absolutePath() + "/" + fileInfo.baseName(); bool bonding = m_dynamicBonding->isChecked(); int numberLength = static_cast( diff --git a/avogadro/qtplugins/surfaces/surfaces.cpp b/avogadro/qtplugins/surfaces/surfaces.cpp index 4a41173f81..8642aa20dd 100644 --- a/avogadro/qtplugins/surfaces/surfaces.cpp +++ b/avogadro/qtplugins/surfaces/surfaces.cpp @@ -392,7 +392,7 @@ void Surfaces::recordMovie() QFileInfo fileInfo(baseName); if (!fileInfo.suffix().isEmpty()) - baseName = fileInfo.canonicalPath() + "/" + fileInfo.baseName(); + baseName = fileInfo.absolutePath() + "/" + fileInfo.baseName(); m_baseFileName = baseName; m_numberLength = static_cast( From 2dea44bea4f2a2feb2a09ec7782fd4f6a49d9e3c Mon Sep 17 00:00:00 2001 From: Geoff Hutchison Date: Fri, 24 Aug 2018 11:09:14 -0400 Subject: [PATCH 43/68] Changes for unit cell systems - always save real-space & unit axes Signed-off-by: Geoff Hutchison --- avogadro/io/cjsonformat.cpp | 38 ++++++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/avogadro/io/cjsonformat.cpp b/avogadro/io/cjsonformat.cpp index 2ffb932e63..884e26c991 100644 --- a/avogadro/io/cjsonformat.cpp +++ b/avogadro/io/cjsonformat.cpp @@ -380,6 +380,20 @@ bool CjsonFormat::write(std::ostream& file, const Molecule& molecule) unitCell["beta"] = molecule.unitCell()->beta() * RAD_TO_DEG; unitCell["gamma"] = molecule.unitCell()->gamma() * RAD_TO_DEG; root["unit cell"] = unitCell; + + json vectors; + vectors.push_back(molecule.unitCell()->aVector().x()); + vectors.push_back(molecule.unitCell()->aVector().y()); + vectors.push_back(molecule.unitCell()->aVector().z()); + + vectors.push_back(molecule.unitCell()->bVector().x()); + vectors.push_back(molecule.unitCell()->bVector().y()); + vectors.push_back(molecule.unitCell()->bVector().z()); + + vectors.push_back(molecule.unitCell()->cVector().x()); + vectors.push_back(molecule.unitCell()->cVector().y()); + vectors.push_back(molecule.unitCell()->cVector().z()); + root["cell vectors"] = vectors; } // Create a basis set/MO matrix we can round trip. @@ -505,6 +519,19 @@ bool CjsonFormat::write(std::ostream& file, const Molecule& molecule) // 3d positions: if (molecule.atomPositions3d().size() == molecule.atomCount()) { + // everything gets real-space Cartesians + json coords3d; + for (vector::const_iterator + it = molecule.atomPositions3d().begin(), + itEnd = molecule.atomPositions3d().end(); + it != itEnd; ++it) { + coords3d.push_back(it->x()); + coords3d.push_back(it->y()); + coords3d.push_back(it->z()); + } + root["atoms"]["coords"]["3d"] = coords3d; + + // if the unit cell exists, also write fractional coords if (molecule.unitCell()) { json coordsFractional; Array fcoords; @@ -518,17 +545,6 @@ bool CjsonFormat::write(std::ostream& file, const Molecule& molecule) coordsFractional.push_back(it->z()); } root["atoms"]["coords"]["3d fractional"] = coordsFractional; - } else { - json coords3d; - for (vector::const_iterator - it = molecule.atomPositions3d().begin(), - itEnd = molecule.atomPositions3d().end(); - it != itEnd; ++it) { - coords3d.push_back(it->x()); - coords3d.push_back(it->y()); - coords3d.push_back(it->z()); - } - root["atoms"]["coords"]["3d"] = coords3d; } } From ecac03c800366d6244eef63f1332e06ff063491e Mon Sep 17 00:00:00 2001 From: Heiko Becker Date: Fri, 24 Aug 2018 22:35:14 +0200 Subject: [PATCH 44/68] Include to fix the build with json-3.2.0 That version dropped the include (where std::setw() is defined) from its header. Signed-off-by: Heiko Becker --- avogadro/io/cjsonformat.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/avogadro/io/cjsonformat.cpp b/avogadro/io/cjsonformat.cpp index 2ffb932e63..a12bdd157f 100644 --- a/avogadro/io/cjsonformat.cpp +++ b/avogadro/io/cjsonformat.cpp @@ -25,6 +25,7 @@ #include +#include #include using json = nlohmann::json; From a0b2b6f66414b9cf1f4ac55b2ad0e6e9311d4f45 Mon Sep 17 00:00:00 2001 From: Patrick Avery Date: Mon, 27 Aug 2018 09:31:57 -0400 Subject: [PATCH 45/68] Removed jsoncpp as it is no longer used Signed-off-by: Patrick Avery --- thirdparty/CMakeLists.txt | 1 - thirdparty/jsoncpp/CMakeLists.txt | 13 - thirdparty/jsoncpp/json/json-forwards.h | 249 -- thirdparty/jsoncpp/json/json.h | 1855 ---------- thirdparty/jsoncpp/jsoncpp.cpp | 4236 ----------------------- 5 files changed, 6354 deletions(-) delete mode 100644 thirdparty/jsoncpp/CMakeLists.txt delete mode 100644 thirdparty/jsoncpp/json/json-forwards.h delete mode 100644 thirdparty/jsoncpp/json/json.h delete mode 100644 thirdparty/jsoncpp/jsoncpp.cpp diff --git a/thirdparty/CMakeLists.txt b/thirdparty/CMakeLists.txt index 1416ac4e54..f3bed85b7d 100644 --- a/thirdparty/CMakeLists.txt +++ b/thirdparty/CMakeLists.txt @@ -1,3 +1,2 @@ -add_subdirectory(jsoncpp) add_subdirectory(struct) add_subdirectory(libgwavi) diff --git a/thirdparty/jsoncpp/CMakeLists.txt b/thirdparty/jsoncpp/CMakeLists.txt deleted file mode 100644 index 644736c576..0000000000 --- a/thirdparty/jsoncpp/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -add_library(jsoncpp STATIC jsoncpp.cpp) -set_target_properties(jsoncpp PROPERTIES POSITION_INDEPENDENT_CODE TRUE) -# The code below is necessary for Windows if building a DLL for JsonCpp -#if(WIN32) -# target_compile_definitions(jsoncpp -# PRIVATE JSON_DLL_BUILD -# INTERFACE JSON_DLL) -#endif() -install(TARGETS jsoncpp - EXPORT "AvogadroLibsTargets" - RUNTIME DESTINATION "${INSTALL_RUNTIME_DIR}" - LIBRARY DESTINATION "${INSTALL_LIBRARY_DIR}" - ARCHIVE DESTINATION "${INSTALL_ARCHIVE_DIR}") diff --git a/thirdparty/jsoncpp/json/json-forwards.h b/thirdparty/jsoncpp/json/json-forwards.h deleted file mode 100644 index 3cf84c00bc..0000000000 --- a/thirdparty/jsoncpp/json/json-forwards.h +++ /dev/null @@ -1,249 +0,0 @@ -/// Json-cpp amalgated forward header (http://jsoncpp.sourceforge.net/). -/// It is intented to be used with #include -/// This header provides forward declaration for all JsonCpp types. - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: LICENSE -// ////////////////////////////////////////////////////////////////////// - -/* -The JsonCpp library's source code, including accompanying documentation, -tests and demonstration applications, are licensed under the following -conditions... - -The author (Baptiste Lepilleur) explicitly disclaims copyright in all -jurisdictions which recognize such a disclaimer. In such jurisdictions, -this software is released into the Public Domain. - -In jurisdictions which do not recognize Public Domain property (e.g. Germany as of -2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur, and is -released under the terms of the MIT License (see below). - -In jurisdictions which recognize Public Domain property, the user of this -software may choose to accept it either as 1) Public Domain, 2) under the -conditions of the MIT License (see below), or 3) under the terms of dual -Public Domain/MIT License conditions described here, as they choose. - -The MIT License is about as close to Public Domain as a license can get, and is -described in clear, concise terms at: - - http://en.wikipedia.org/wiki/MIT_License - -The full text of the MIT License follows: - -======================================================================== -Copyright (c) 2007-2010 Baptiste Lepilleur - -Permission is hereby granted, free of charge, to any person -obtaining a copy of this software and associated documentation -files (the "Software"), to deal in the Software without -restriction, including without limitation the rights to use, copy, -modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -======================================================================== -(END LICENSE TEXT) - -The MIT license is compatible with both the GPL and commercial -software, affording one all of the rights of Public Domain with the -minor nuisance of being required to keep the above copyright notice -and license text in the source code. Note also that by accepting the -Public Domain "license" you can re-license your copy using whatever -license you like. - -*/ - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: LICENSE -// ////////////////////////////////////////////////////////////////////// - - - - - -#ifndef JSON_FORWARD_AMALGATED_H_INCLUDED -# define JSON_FORWARD_AMALGATED_H_INCLUDED -/// If defined, indicates that the source file is amalgated -/// to prevent private header inclusion. -#define JSON_IS_AMALGAMATION - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: include/json/config.h -// ////////////////////////////////////////////////////////////////////// - -// Copyright 2007-2010 Baptiste Lepilleur -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#ifndef JSON_CONFIG_H_INCLUDED -# define JSON_CONFIG_H_INCLUDED - -/// If defined, indicates that json library is embedded in CppTL library. -//# define JSON_IN_CPPTL 1 - -/// If defined, indicates that json may leverage CppTL library -//# define JSON_USE_CPPTL 1 -/// If defined, indicates that cpptl vector based map should be used instead of std::map -/// as Value container. -//# define JSON_USE_CPPTL_SMALLMAP 1 -/// If defined, indicates that Json specific container should be used -/// (hash table & simple deque container with customizable allocator). -/// THIS FEATURE IS STILL EXPERIMENTAL! There is know bugs: See #3177332 -//# define JSON_VALUE_USE_INTERNAL_MAP 1 -/// Force usage of standard new/malloc based allocator instead of memory pool based allocator. -/// The memory pools allocator used optimization (initializing Value and ValueInternalLink -/// as if it was a POD) that may cause some validation tool to report errors. -/// Only has effects if JSON_VALUE_USE_INTERNAL_MAP is defined. -//# define JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 1 - -/// If defined, indicates that Json use exception to report invalid type manipulation -/// instead of C assert macro. -# define JSON_USE_EXCEPTION 1 - -/// If defined, indicates that the source file is amalgated -/// to prevent private header inclusion. -/// Remarks: it is automatically defined in the generated amalgated header. -// #define JSON_IS_AMALGAMATION - - -# ifdef JSON_IN_CPPTL -# include -# ifndef JSON_USE_CPPTL -# define JSON_USE_CPPTL 1 -# endif -# endif - -# ifdef JSON_IN_CPPTL -# define JSON_API CPPTL_API -# elif defined(JSON_DLL_BUILD) -# define JSON_API __declspec(dllexport) -# elif defined(JSON_DLL) -# define JSON_API __declspec(dllimport) -# else -# define JSON_API -# endif - -// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for integer -// Storages, and 64 bits integer support is disabled. -// #define JSON_NO_INT64 1 - -#if defined(_MSC_VER) && _MSC_VER <= 1200 // MSVC 6 -// Microsoft Visual Studio 6 only support conversion from __int64 to double -// (no conversion from unsigned __int64). -#define JSON_USE_INT64_DOUBLE_CONVERSION 1 -#endif // if defined(_MSC_VER) && _MSC_VER < 1200 // MSVC 6 - -#if defined(_MSC_VER) && _MSC_VER >= 1500 // MSVC 2008 -/// Indicates that the following function is deprecated. -# define JSONCPP_DEPRECATED(message) __declspec(deprecated(message)) -#endif - -#if !defined(JSONCPP_DEPRECATED) -# define JSONCPP_DEPRECATED(message) -#endif // if !defined(JSONCPP_DEPRECATED) - -namespace Json { - typedef int Int; - typedef unsigned int UInt; -# if defined(JSON_NO_INT64) - typedef int LargestInt; - typedef unsigned int LargestUInt; -# undef JSON_HAS_INT64 -# else // if defined(JSON_NO_INT64) - // For Microsoft Visual use specific types as long long is not supported -# if defined(_MSC_VER) // Microsoft Visual Studio - typedef __int64 Int64; - typedef unsigned __int64 UInt64; -# else // if defined(_MSC_VER) // Other platforms, use long long - typedef long long int Int64; - typedef unsigned long long int UInt64; -# endif // if defined(_MSC_VER) - typedef Int64 LargestInt; - typedef UInt64 LargestUInt; -# define JSON_HAS_INT64 -# endif // if defined(JSON_NO_INT64) -} // end namespace Json - - -#endif // JSON_CONFIG_H_INCLUDED - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: include/json/config.h -// ////////////////////////////////////////////////////////////////////// - - - - - - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: include/json/forwards.h -// ////////////////////////////////////////////////////////////////////// - -// Copyright 2007-2010 Baptiste Lepilleur -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#ifndef JSON_FORWARDS_H_INCLUDED -# define JSON_FORWARDS_H_INCLUDED - -#if !defined(JSON_IS_AMALGAMATION) -# include "config.h" -#endif // if !defined(JSON_IS_AMALGAMATION) - -namespace Json { - - // writer.h - class FastWriter; - class StyledWriter; - - // reader.h - class Reader; - - // features.h - class Features; - - // value.h - typedef unsigned int ArrayIndex; - class StaticString; - class Path; - class PathArgument; - class Value; - class ValueIteratorBase; - class ValueIterator; - class ValueConstIterator; -#ifdef JSON_VALUE_USE_INTERNAL_MAP - class ValueMapAllocator; - class ValueInternalLink; - class ValueInternalArray; - class ValueInternalMap; -#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP - -} // namespace Json - - -#endif // JSON_FORWARDS_H_INCLUDED - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: include/json/forwards.h -// ////////////////////////////////////////////////////////////////////// - - - - - -#endif //ifndef JSON_FORWARD_AMALGATED_H_INCLUDED diff --git a/thirdparty/jsoncpp/json/json.h b/thirdparty/jsoncpp/json/json.h deleted file mode 100644 index 0ab8e50d88..0000000000 --- a/thirdparty/jsoncpp/json/json.h +++ /dev/null @@ -1,1855 +0,0 @@ -/// Json-cpp amalgated header (http://jsoncpp.sourceforge.net/). -/// It is intented to be used with #include - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: LICENSE -// ////////////////////////////////////////////////////////////////////// - -/* -The JsonCpp library's source code, including accompanying documentation, -tests and demonstration applications, are licensed under the following -conditions... - -The author (Baptiste Lepilleur) explicitly disclaims copyright in all -jurisdictions which recognize such a disclaimer. In such jurisdictions, -this software is released into the Public Domain. - -In jurisdictions which do not recognize Public Domain property (e.g. Germany as of -2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur, and is -released under the terms of the MIT License (see below). - -In jurisdictions which recognize Public Domain property, the user of this -software may choose to accept it either as 1) Public Domain, 2) under the -conditions of the MIT License (see below), or 3) under the terms of dual -Public Domain/MIT License conditions described here, as they choose. - -The MIT License is about as close to Public Domain as a license can get, and is -described in clear, concise terms at: - - http://en.wikipedia.org/wiki/MIT_License - -The full text of the MIT License follows: - -======================================================================== -Copyright (c) 2007-2010 Baptiste Lepilleur - -Permission is hereby granted, free of charge, to any person -obtaining a copy of this software and associated documentation -files (the "Software"), to deal in the Software without -restriction, including without limitation the rights to use, copy, -modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -======================================================================== -(END LICENSE TEXT) - -The MIT license is compatible with both the GPL and commercial -software, affording one all of the rights of Public Domain with the -minor nuisance of being required to keep the above copyright notice -and license text in the source code. Note also that by accepting the -Public Domain "license" you can re-license your copy using whatever -license you like. - -*/ - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: LICENSE -// ////////////////////////////////////////////////////////////////////// - - - - - -#ifndef JSON_AMALGATED_H_INCLUDED -# define JSON_AMALGATED_H_INCLUDED -/// If defined, indicates that the source file is amalgated -/// to prevent private header inclusion. -#define JSON_IS_AMALGATED - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: include/json/config.h -// ////////////////////////////////////////////////////////////////////// - -// Copyright 2007-2010 Baptiste Lepilleur -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#ifndef JSON_CONFIG_H_INCLUDED -# define JSON_CONFIG_H_INCLUDED - -/// If defined, indicates that json library is embedded in CppTL library. -//# define JSON_IN_CPPTL 1 - -/// If defined, indicates that json may leverage CppTL library -//# define JSON_USE_CPPTL 1 -/// If defined, indicates that cpptl vector based map should be used instead of std::map -/// as Value container. -//# define JSON_USE_CPPTL_SMALLMAP 1 -/// If defined, indicates that Json specific container should be used -/// (hash table & simple deque container with customizable allocator). -/// THIS FEATURE IS STILL EXPERIMENTAL! There is know bugs: See #3177332 -//# define JSON_VALUE_USE_INTERNAL_MAP 1 -/// Force usage of standard new/malloc based allocator instead of memory pool based allocator. -/// The memory pools allocator used optimization (initializing Value and ValueInternalLink -/// as if it was a POD) that may cause some validation tool to report errors. -/// Only has effects if JSON_VALUE_USE_INTERNAL_MAP is defined. -//# define JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 1 - -/// If defined, indicates that Json use exception to report invalid type manipulation -/// instead of C assert macro. -# define JSON_USE_EXCEPTION 1 - -/// If defined, indicates that the source file is amalgated -/// to prevent private header inclusion. -/// Remarks: it is automatically defined in the generated amalgated header. -#define JSON_IS_AMALGAMATION - - -# ifdef JSON_IN_CPPTL -# include -# ifndef JSON_USE_CPPTL -# define JSON_USE_CPPTL 1 -# endif -# endif - -# ifdef JSON_IN_CPPTL -# define JSON_API CPPTL_API -# elif defined(JSON_DLL_BUILD) -# define JSON_API __declspec(dllexport) -# elif defined(JSON_DLL) -# define JSON_API __declspec(dllimport) -# else -# define JSON_API -# endif - -// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for integer -// Storages, and 64 bits integer support is disabled. -// #define JSON_NO_INT64 1 - -#if defined(_MSC_VER) && _MSC_VER <= 1200 // MSVC 6 -// Microsoft Visual Studio 6 only support conversion from __int64 to double -// (no conversion from unsigned __int64). -#define JSON_USE_INT64_DOUBLE_CONVERSION 1 -#endif // if defined(_MSC_VER) && _MSC_VER < 1200 // MSVC 6 - -#if defined(_MSC_VER) && _MSC_VER >= 1500 // MSVC 2008 -/// Indicates that the following function is deprecated. -# define JSONCPP_DEPRECATED(message) __declspec(deprecated(message)) -#endif - -#if !defined(JSONCPP_DEPRECATED) -# define JSONCPP_DEPRECATED(message) -#endif // if !defined(JSONCPP_DEPRECATED) - -namespace Json { - typedef int Int; - typedef unsigned int UInt; -# if defined(JSON_NO_INT64) - typedef int LargestInt; - typedef unsigned int LargestUInt; -# undef JSON_HAS_INT64 -# else // if defined(JSON_NO_INT64) - // For Microsoft Visual use specific types as long long is not supported -# if defined(_MSC_VER) // Microsoft Visual Studio - typedef __int64 Int64; - typedef unsigned __int64 UInt64; -# else // if defined(_MSC_VER) // Other platforms, use long long - typedef long long int Int64; - typedef unsigned long long int UInt64; -# endif // if defined(_MSC_VER) - typedef Int64 LargestInt; - typedef UInt64 LargestUInt; -# define JSON_HAS_INT64 -# endif // if defined(JSON_NO_INT64) -} // end namespace Json - - -#endif // JSON_CONFIG_H_INCLUDED - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: include/json/config.h -// ////////////////////////////////////////////////////////////////////// - - - - - - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: include/json/forwards.h -// ////////////////////////////////////////////////////////////////////// - -// Copyright 2007-2010 Baptiste Lepilleur -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#ifndef JSON_FORWARDS_H_INCLUDED -# define JSON_FORWARDS_H_INCLUDED - -#if !defined(JSON_IS_AMALGAMATION) -# include "config.h" -#endif // if !defined(JSON_IS_AMALGAMATION) - -namespace Json { - - // writer.h - class FastWriter; - class StyledWriter; - - // reader.h - class Reader; - - // features.h - class Features; - - // value.h - typedef unsigned int ArrayIndex; - class StaticString; - class Path; - class PathArgument; - class Value; - class ValueIteratorBase; - class ValueIterator; - class ValueConstIterator; -#ifdef JSON_VALUE_USE_INTERNAL_MAP - class ValueMapAllocator; - class ValueInternalLink; - class ValueInternalArray; - class ValueInternalMap; -#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP - -} // namespace Json - - -#endif // JSON_FORWARDS_H_INCLUDED - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: include/json/forwards.h -// ////////////////////////////////////////////////////////////////////// - - - - - - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: include/json/features.h -// ////////////////////////////////////////////////////////////////////// - -// Copyright 2007-2010 Baptiste Lepilleur -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#ifndef CPPTL_JSON_FEATURES_H_INCLUDED -# define CPPTL_JSON_FEATURES_H_INCLUDED - -#if !defined(JSON_IS_AMALGAMATION) -# include "forwards.h" -#endif // if !defined(JSON_IS_AMALGAMATION) - -namespace Json { - - /** \brief Configuration passed to reader and writer. - * This configuration object can be used to force the Reader or Writer - * to behave in a standard conforming way. - */ - class JSON_API Features - { - public: - /** \brief A configuration that allows all features and assumes all strings are UTF-8. - * - C & C++ comments are allowed - * - Root object can be any JSON value - * - Assumes Value strings are encoded in UTF-8 - */ - static Features all(); - - /** \brief A configuration that is strictly compatible with the JSON specification. - * - Comments are forbidden. - * - Root object must be either an array or an object value. - * - Assumes Value strings are encoded in UTF-8 - */ - static Features strictMode(); - - /** \brief Initialize the configuration like JsonConfig::allFeatures; - */ - Features(); - - /// \c true if comments are allowed. Default: \c true. - bool allowComments_; - - /// \c true if root must be either an array or an object value. Default: \c false. - bool strictRoot_; - }; - -} // namespace Json - -#endif // CPPTL_JSON_FEATURES_H_INCLUDED - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: include/json/features.h -// ////////////////////////////////////////////////////////////////////// - - - - - - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: include/json/value.h -// ////////////////////////////////////////////////////////////////////// - -// Copyright 2007-2010 Baptiste Lepilleur -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#ifndef CPPTL_JSON_H_INCLUDED -# define CPPTL_JSON_H_INCLUDED - -#if !defined(JSON_IS_AMALGAMATION) -# include "forwards.h" -#endif // if !defined(JSON_IS_AMALGAMATION) -# include -# include - -# ifndef JSON_USE_CPPTL_SMALLMAP -# include -# else -# include -# endif -# ifdef JSON_USE_CPPTL -# include -# endif - -/** \brief JSON (JavaScript Object Notation). - */ -namespace Json { - - /** \brief Type of the value held by a Value object. - */ - enum ValueType - { - nullValue = 0, ///< 'null' value - intValue, ///< signed integer value - uintValue, ///< unsigned integer value - realValue, ///< double value - stringValue, ///< UTF-8 string value - booleanValue, ///< bool value - arrayValue, ///< array value (ordered list) - objectValue ///< object value (collection of name/value pairs). - }; - - enum CommentPlacement - { - commentBefore = 0, ///< a comment placed on the line before a value - commentAfterOnSameLine, ///< a comment just after a value on the same line - commentAfter, ///< a comment on the line after a value (only make sense for root value) - numberOfCommentPlacement - }; - -//# ifdef JSON_USE_CPPTL -// typedef CppTL::AnyEnumerator EnumMemberNames; -// typedef CppTL::AnyEnumerator EnumValues; -//# endif - - /** \brief Lightweight wrapper to tag static string. - * - * Value constructor and objectValue member assignement takes advantage of the - * StaticString and avoid the cost of string duplication when storing the - * string or the member name. - * - * Example of usage: - * \code - * Json::Value aValue( StaticString("some text") ); - * Json::Value object; - * static const StaticString code("code"); - * object[code] = 1234; - * \endcode - */ - class JSON_API StaticString - { - public: - explicit StaticString( const char *czstring ) - : str_( czstring ) - { - } - - operator const char *() const - { - return str_; - } - - const char *c_str() const - { - return str_; - } - - private: - const char *str_; - }; - - /** \brief Represents a JSON value. - * - * This class is a discriminated union wrapper that can represents a: - * - signed integer [range: Value::minInt - Value::maxInt] - * - unsigned integer (range: 0 - Value::maxUInt) - * - double - * - UTF-8 string - * - boolean - * - 'null' - * - an ordered list of Value - * - collection of name/value pairs (javascript object) - * - * The type of the held value is represented by a #ValueType and - * can be obtained using type(). - * - * values of an #objectValue or #arrayValue can be accessed using operator[]() methods. - * Non const methods will automatically create the a #nullValue element - * if it does not exist. - * The sequence of an #arrayValue will be automatically resize and initialized - * with #nullValue. resize() can be used to enlarge or truncate an #arrayValue. - * - * The get() methods can be used to obtanis default value in the case the required element - * does not exist. - * - * It is possible to iterate over the list of a #objectValue values using - * the getMemberNames() method. - */ - class JSON_API Value - { - friend class ValueIteratorBase; -# ifdef JSON_VALUE_USE_INTERNAL_MAP - friend class ValueInternalLink; - friend class ValueInternalMap; -# endif - public: - typedef std::vector Members; - typedef ValueIterator iterator; - typedef ValueConstIterator const_iterator; - typedef Json::UInt UInt; - typedef Json::Int Int; -# if defined(JSON_HAS_INT64) - typedef Json::UInt64 UInt64; - typedef Json::Int64 Int64; -#endif // defined(JSON_HAS_INT64) - typedef Json::LargestInt LargestInt; - typedef Json::LargestUInt LargestUInt; - typedef Json::ArrayIndex ArrayIndex; - - static const Value null; - /// Minimum signed integer value that can be stored in a Json::Value. - static const LargestInt minLargestInt; - /// Maximum signed integer value that can be stored in a Json::Value. - static const LargestInt maxLargestInt; - /// Maximum unsigned integer value that can be stored in a Json::Value. - static const LargestUInt maxLargestUInt; - - /// Minimum signed int value that can be stored in a Json::Value. - static const Int minInt; - /// Maximum signed int value that can be stored in a Json::Value. - static const Int maxInt; - /// Maximum unsigned int value that can be stored in a Json::Value. - static const UInt maxUInt; - - /// Minimum signed 64 bits int value that can be stored in a Json::Value. - static const Int64 minInt64; - /// Maximum signed 64 bits int value that can be stored in a Json::Value. - static const Int64 maxInt64; - /// Maximum unsigned 64 bits int value that can be stored in a Json::Value. - static const UInt64 maxUInt64; - - private: -#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION -# ifndef JSON_VALUE_USE_INTERNAL_MAP - class CZString - { - public: - enum DuplicationPolicy - { - noDuplication = 0, - duplicate, - duplicateOnCopy - }; - CZString( ArrayIndex index ); - CZString( const char *cstr, DuplicationPolicy allocate ); - CZString( const CZString &other ); - ~CZString(); - CZString &operator =( const CZString &other ); - bool operator<( const CZString &other ) const; - bool operator==( const CZString &other ) const; - ArrayIndex index() const; - const char *c_str() const; - bool isStaticString() const; - private: - void swap( CZString &other ); - const char *cstr_; - ArrayIndex index_; - }; - - public: -# ifndef JSON_USE_CPPTL_SMALLMAP - typedef std::map ObjectValues; -# else - typedef CppTL::SmallMap ObjectValues; -# endif // ifndef JSON_USE_CPPTL_SMALLMAP -# endif // ifndef JSON_VALUE_USE_INTERNAL_MAP -#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION - - public: - /** \brief Create a default Value of the given type. - - This is a very useful constructor. - To create an empty array, pass arrayValue. - To create an empty object, pass objectValue. - Another Value can then be set to this one by assignment. - This is useful since clear() and resize() will not alter types. - - Examples: - \code - Json::Value null_value; // null - Json::Value arr_value(Json::arrayValue); // [] - Json::Value obj_value(Json::objectValue); // {} - \endcode - */ - Value( ValueType type = nullValue ); - Value( Int value ); - Value( UInt value ); -#if defined(JSON_HAS_INT64) - Value( Int64 value ); - Value( UInt64 value ); -#endif // if defined(JSON_HAS_INT64) - Value( double value ); - Value( const char *value ); - Value( const char *beginValue, const char *endValue ); - /** \brief Constructs a value from a static string. - - * Like other value string constructor but do not duplicate the string for - * internal storage. The given string must remain alive after the call to this - * constructor. - * Example of usage: - * \code - * Json::Value aValue( StaticString("some text") ); - * \endcode - */ - Value( const StaticString &value ); - Value( const std::string &value ); -# ifdef JSON_USE_CPPTL - Value( const CppTL::ConstString &value ); -# endif - Value( bool value ); - Value( const Value &other ); - ~Value(); - - Value &operator=( const Value &other ); - /// Swap values. - /// \note Currently, comments are intentionally not swapped, for - /// both logic and efficiency. - void swap( Value &other ); - - ValueType type() const; - - bool operator <( const Value &other ) const; - bool operator <=( const Value &other ) const; - bool operator >=( const Value &other ) const; - bool operator >( const Value &other ) const; - - bool operator ==( const Value &other ) const; - bool operator !=( const Value &other ) const; - - int compare( const Value &other ) const; - - const char *asCString() const; - std::string asString() const; -# ifdef JSON_USE_CPPTL - CppTL::ConstString asConstString() const; -# endif - Int asInt() const; - UInt asUInt() const; - Int64 asInt64() const; - UInt64 asUInt64() const; - LargestInt asLargestInt() const; - LargestUInt asLargestUInt() const; - float asFloat() const; - double asDouble() const; - bool asBool() const; - - bool isNull() const; - bool isBool() const; - bool isInt() const; - bool isUInt() const; - bool isIntegral() const; - bool isDouble() const; - bool isNumeric() const; - bool isString() const; - bool isArray() const; - bool isObject() const; - - bool isConvertibleTo( ValueType other ) const; - - /// Number of values in array or object - ArrayIndex size() const; - - /// \brief Return true if empty array, empty object, or null; - /// otherwise, false. - bool empty() const; - - /// Return isNull() - bool operator!() const; - - /// Remove all object members and array elements. - /// \pre type() is arrayValue, objectValue, or nullValue - /// \post type() is unchanged - void clear(); - - /// Resize the array to size elements. - /// New elements are initialized to null. - /// May only be called on nullValue or arrayValue. - /// \pre type() is arrayValue or nullValue - /// \post type() is arrayValue - void resize( ArrayIndex size ); - - /// Access an array element (zero based index ). - /// If the array contains less than index element, then null value are inserted - /// in the array so that its size is index+1. - /// (You may need to say 'value[0u]' to get your compiler to distinguish - /// this from the operator[] which takes a string.) - Value &operator[]( ArrayIndex index ); - - /// Access an array element (zero based index ). - /// If the array contains less than index element, then null value are inserted - /// in the array so that its size is index+1. - /// (You may need to say 'value[0u]' to get your compiler to distinguish - /// this from the operator[] which takes a string.) - Value &operator[]( int index ); - - /// Access an array element (zero based index ) - /// (You may need to say 'value[0u]' to get your compiler to distinguish - /// this from the operator[] which takes a string.) - const Value &operator[]( ArrayIndex index ) const; - - /// Access an array element (zero based index ) - /// (You may need to say 'value[0u]' to get your compiler to distinguish - /// this from the operator[] which takes a string.) - const Value &operator[]( int index ) const; - - /// If the array contains at least index+1 elements, returns the element value, - /// otherwise returns defaultValue. - Value get( ArrayIndex index, - const Value &defaultValue ) const; - /// Return true if index < size(). - bool isValidIndex( ArrayIndex index ) const; - /// \brief Append value to array at the end. - /// - /// Equivalent to jsonvalue[jsonvalue.size()] = value; - Value &append( const Value &value ); - - /// Access an object value by name, create a null member if it does not exist. - Value &operator[]( const char *key ); - /// Access an object value by name, returns null if there is no member with that name. - const Value &operator[]( const char *key ) const; - /// Access an object value by name, create a null member if it does not exist. - Value &operator[]( const std::string &key ); - /// Access an object value by name, returns null if there is no member with that name. - const Value &operator[]( const std::string &key ) const; - /** \brief Access an object value by name, create a null member if it does not exist. - - * If the object as no entry for that name, then the member name used to store - * the new entry is not duplicated. - * Example of use: - * \code - * Json::Value object; - * static const StaticString code("code"); - * object[code] = 1234; - * \endcode - */ - Value &operator[]( const StaticString &key ); -# ifdef JSON_USE_CPPTL - /// Access an object value by name, create a null member if it does not exist. - Value &operator[]( const CppTL::ConstString &key ); - /// Access an object value by name, returns null if there is no member with that name. - const Value &operator[]( const CppTL::ConstString &key ) const; -# endif - /// Return the member named key if it exist, defaultValue otherwise. - Value get( const char *key, - const Value &defaultValue ) const; - /// Return the member named key if it exist, defaultValue otherwise. - Value get( const std::string &key, - const Value &defaultValue ) const; -# ifdef JSON_USE_CPPTL - /// Return the member named key if it exist, defaultValue otherwise. - Value get( const CppTL::ConstString &key, - const Value &defaultValue ) const; -# endif - /// \brief Remove and return the named member. - /// - /// Do nothing if it did not exist. - /// \return the removed Value, or null. - /// \pre type() is objectValue or nullValue - /// \post type() is unchanged - Value removeMember( const char* key ); - /// Same as removeMember(const char*) - Value removeMember( const std::string &key ); - - /// Return true if the object has a member named key. - bool isMember( const char *key ) const; - /// Return true if the object has a member named key. - bool isMember( const std::string &key ) const; -# ifdef JSON_USE_CPPTL - /// Return true if the object has a member named key. - bool isMember( const CppTL::ConstString &key ) const; -# endif - - /// \brief Return a list of the member names. - /// - /// If null, return an empty list. - /// \pre type() is objectValue or nullValue - /// \post if type() was nullValue, it remains nullValue - Members getMemberNames() const; - -//# ifdef JSON_USE_CPPTL -// EnumMemberNames enumMemberNames() const; -// EnumValues enumValues() const; -//# endif - - /// Comments must be //... or /* ... */ - void setComment( const char *comment, - CommentPlacement placement ); - /// Comments must be //... or /* ... */ - void setComment( const std::string &comment, - CommentPlacement placement ); - bool hasComment( CommentPlacement placement ) const; - /// Include delimiters and embedded newlines. - std::string getComment( CommentPlacement placement ) const; - - std::string toStyledString() const; - - const_iterator begin() const; - const_iterator end() const; - - iterator begin(); - iterator end(); - - private: - Value &resolveReference( const char *key, - bool isStatic ); - -# ifdef JSON_VALUE_USE_INTERNAL_MAP - inline bool isItemAvailable() const - { - return itemIsUsed_ == 0; - } - - inline void setItemUsed( bool isUsed = true ) - { - itemIsUsed_ = isUsed ? 1 : 0; - } - - inline bool isMemberNameStatic() const - { - return memberNameIsStatic_ == 0; - } - - inline void setMemberNameIsStatic( bool isStatic ) - { - memberNameIsStatic_ = isStatic ? 1 : 0; - } -# endif // # ifdef JSON_VALUE_USE_INTERNAL_MAP - - private: - struct CommentInfo - { - CommentInfo(); - ~CommentInfo(); - - void setComment( const char *text ); - - char *comment_; - }; - - //struct MemberNamesTransform - //{ - // typedef const char *result_type; - // const char *operator()( const CZString &name ) const - // { - // return name.c_str(); - // } - //}; - - union ValueHolder - { - LargestInt int_; - LargestUInt uint_; - double real_; - bool bool_; - char *string_; -# ifdef JSON_VALUE_USE_INTERNAL_MAP - ValueInternalArray *array_; - ValueInternalMap *map_; -#else - ObjectValues *map_; -# endif - } value_; - ValueType type_ : 8; - int allocated_ : 1; // Notes: if declared as bool, bitfield is useless. -# ifdef JSON_VALUE_USE_INTERNAL_MAP - unsigned int itemIsUsed_ : 1; // used by the ValueInternalMap container. - int memberNameIsStatic_ : 1; // used by the ValueInternalMap container. -# endif - CommentInfo *comments_; - }; - - - /** \brief Experimental and untested: represents an element of the "path" to access a node. - */ - class PathArgument - { - public: - friend class Path; - - PathArgument(); - PathArgument( ArrayIndex index ); - PathArgument( const char *key ); - PathArgument( const std::string &key ); - - private: - enum Kind - { - kindNone = 0, - kindIndex, - kindKey - }; - std::string key_; - ArrayIndex index_; - Kind kind_; - }; - - /** \brief Experimental and untested: represents a "path" to access a node. - * - * Syntax: - * - "." => root node - * - ".[n]" => elements at index 'n' of root node (an array value) - * - ".name" => member named 'name' of root node (an object value) - * - ".name1.name2.name3" - * - ".[0][1][2].name1[3]" - * - ".%" => member name is provided as parameter - * - ".[%]" => index is provied as parameter - */ - class Path - { - public: - Path( const std::string &path, - const PathArgument &a1 = PathArgument(), - const PathArgument &a2 = PathArgument(), - const PathArgument &a3 = PathArgument(), - const PathArgument &a4 = PathArgument(), - const PathArgument &a5 = PathArgument() ); - - const Value &resolve( const Value &root ) const; - Value resolve( const Value &root, - const Value &defaultValue ) const; - /// Creates the "path" to access the specified node and returns a reference on the node. - Value &make( Value &root ) const; - - private: - typedef std::vector InArgs; - typedef std::vector Args; - - void makePath( const std::string &path, - const InArgs &in ); - void addPathInArg( const std::string &path, - const InArgs &in, - InArgs::const_iterator &itInArg, - PathArgument::Kind kind ); - void invalidPath( const std::string &path, - int location ); - - Args args_; - }; - - - -#ifdef JSON_VALUE_USE_INTERNAL_MAP - /** \brief Allocator to customize Value internal map. - * Below is an example of a simple implementation (default implementation actually - * use memory pool for speed). - * \code - class DefaultValueMapAllocator : public ValueMapAllocator - { - public: // overridden from ValueMapAllocator - virtual ValueInternalMap *newMap() - { - return new ValueInternalMap(); - } - - virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other ) - { - return new ValueInternalMap( other ); - } - - virtual void destructMap( ValueInternalMap *map ) - { - delete map; - } - - virtual ValueInternalLink *allocateMapBuckets( unsigned int size ) - { - return new ValueInternalLink[size]; - } - - virtual void releaseMapBuckets( ValueInternalLink *links ) - { - delete [] links; - } - - virtual ValueInternalLink *allocateMapLink() - { - return new ValueInternalLink(); - } - - virtual void releaseMapLink( ValueInternalLink *link ) - { - delete link; - } - }; - * \endcode - */ - class JSON_API ValueMapAllocator - { - public: - virtual ~ValueMapAllocator(); - virtual ValueInternalMap *newMap() = 0; - virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other ) = 0; - virtual void destructMap( ValueInternalMap *map ) = 0; - virtual ValueInternalLink *allocateMapBuckets( unsigned int size ) = 0; - virtual void releaseMapBuckets( ValueInternalLink *links ) = 0; - virtual ValueInternalLink *allocateMapLink() = 0; - virtual void releaseMapLink( ValueInternalLink *link ) = 0; - }; - - /** \brief ValueInternalMap hash-map bucket chain link (for internal use only). - * \internal previous_ & next_ allows for bidirectional traversal. - */ - class JSON_API ValueInternalLink - { - public: - enum { itemPerLink = 6 }; // sizeof(ValueInternalLink) = 128 on 32 bits architecture. - enum InternalFlags { - flagAvailable = 0, - flagUsed = 1 - }; - - ValueInternalLink(); - - ~ValueInternalLink(); - - Value items_[itemPerLink]; - char *keys_[itemPerLink]; - ValueInternalLink *previous_; - ValueInternalLink *next_; - }; - - - /** \brief A linked page based hash-table implementation used internally by Value. - * \internal ValueInternalMap is a tradional bucket based hash-table, with a linked - * list in each bucket to handle collision. There is an addional twist in that - * each node of the collision linked list is a page containing a fixed amount of - * value. This provides a better compromise between memory usage and speed. - * - * Each bucket is made up of a chained list of ValueInternalLink. The last - * link of a given bucket can be found in the 'previous_' field of the following bucket. - * The last link of the last bucket is stored in tailLink_ as it has no following bucket. - * Only the last link of a bucket may contains 'available' item. The last link always - * contains at least one element unless is it the bucket one very first link. - */ - class JSON_API ValueInternalMap - { - friend class ValueIteratorBase; - friend class Value; - public: - typedef unsigned int HashKey; - typedef unsigned int BucketIndex; - -# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION - struct IteratorState - { - IteratorState() - : map_(0) - , link_(0) - , itemIndex_(0) - , bucketIndex_(0) - { - } - ValueInternalMap *map_; - ValueInternalLink *link_; - BucketIndex itemIndex_; - BucketIndex bucketIndex_; - }; -# endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION - - ValueInternalMap(); - ValueInternalMap( const ValueInternalMap &other ); - ValueInternalMap &operator =( const ValueInternalMap &other ); - ~ValueInternalMap(); - - void swap( ValueInternalMap &other ); - - BucketIndex size() const; - - void clear(); - - bool reserveDelta( BucketIndex growth ); - - bool reserve( BucketIndex newItemCount ); - - const Value *find( const char *key ) const; - - Value *find( const char *key ); - - Value &resolveReference( const char *key, - bool isStatic ); - - void remove( const char *key ); - - void doActualRemove( ValueInternalLink *link, - BucketIndex index, - BucketIndex bucketIndex ); - - ValueInternalLink *&getLastLinkInBucket( BucketIndex bucketIndex ); - - Value &setNewItem( const char *key, - bool isStatic, - ValueInternalLink *link, - BucketIndex index ); - - Value &unsafeAdd( const char *key, - bool isStatic, - HashKey hashedKey ); - - HashKey hash( const char *key ) const; - - int compare( const ValueInternalMap &other ) const; - - private: - void makeBeginIterator( IteratorState &it ) const; - void makeEndIterator( IteratorState &it ) const; - static bool equals( const IteratorState &x, const IteratorState &other ); - static void increment( IteratorState &iterator ); - static void incrementBucket( IteratorState &iterator ); - static void decrement( IteratorState &iterator ); - static const char *key( const IteratorState &iterator ); - static const char *key( const IteratorState &iterator, bool &isStatic ); - static Value &value( const IteratorState &iterator ); - static int distance( const IteratorState &x, const IteratorState &y ); - - private: - ValueInternalLink *buckets_; - ValueInternalLink *tailLink_; - BucketIndex bucketsSize_; - BucketIndex itemCount_; - }; - - /** \brief A simplified deque implementation used internally by Value. - * \internal - * It is based on a list of fixed "page", each page contains a fixed number of items. - * Instead of using a linked-list, a array of pointer is used for fast item look-up. - * Look-up for an element is as follow: - * - compute page index: pageIndex = itemIndex / itemsPerPage - * - look-up item in page: pages_[pageIndex][itemIndex % itemsPerPage] - * - * Insertion is amortized constant time (only the array containing the index of pointers - * need to be reallocated when items are appended). - */ - class JSON_API ValueInternalArray - { - friend class Value; - friend class ValueIteratorBase; - public: - enum { itemsPerPage = 8 }; // should be a power of 2 for fast divide and modulo. - typedef Value::ArrayIndex ArrayIndex; - typedef unsigned int PageIndex; - -# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION - struct IteratorState // Must be a POD - { - IteratorState() - : array_(0) - , currentPageIndex_(0) - , currentItemIndex_(0) - { - } - ValueInternalArray *array_; - Value **currentPageIndex_; - unsigned int currentItemIndex_; - }; -# endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION - - ValueInternalArray(); - ValueInternalArray( const ValueInternalArray &other ); - ValueInternalArray &operator =( const ValueInternalArray &other ); - ~ValueInternalArray(); - void swap( ValueInternalArray &other ); - - void clear(); - void resize( ArrayIndex newSize ); - - Value &resolveReference( ArrayIndex index ); - - Value *find( ArrayIndex index ) const; - - ArrayIndex size() const; - - int compare( const ValueInternalArray &other ) const; - - private: - static bool equals( const IteratorState &x, const IteratorState &other ); - static void increment( IteratorState &iterator ); - static void decrement( IteratorState &iterator ); - static Value &dereference( const IteratorState &iterator ); - static Value &unsafeDereference( const IteratorState &iterator ); - static int distance( const IteratorState &x, const IteratorState &y ); - static ArrayIndex indexOf( const IteratorState &iterator ); - void makeBeginIterator( IteratorState &it ) const; - void makeEndIterator( IteratorState &it ) const; - void makeIterator( IteratorState &it, ArrayIndex index ) const; - - void makeIndexValid( ArrayIndex index ); - - Value **pages_; - ArrayIndex size_; - PageIndex pageCount_; - }; - - /** \brief Experimental: do not use. Allocator to customize Value internal array. - * Below is an example of a simple implementation (actual implementation use - * memory pool). - \code -class DefaultValueArrayAllocator : public ValueArrayAllocator -{ -public: // overridden from ValueArrayAllocator - virtual ~DefaultValueArrayAllocator() - { - } - - virtual ValueInternalArray *newArray() - { - return new ValueInternalArray(); - } - - virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other ) - { - return new ValueInternalArray( other ); - } - - virtual void destruct( ValueInternalArray *array ) - { - delete array; - } - - virtual void reallocateArrayPageIndex( Value **&indexes, - ValueInternalArray::PageIndex &indexCount, - ValueInternalArray::PageIndex minNewIndexCount ) - { - ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1; - if ( minNewIndexCount > newIndexCount ) - newIndexCount = minNewIndexCount; - void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount ); - if ( !newIndexes ) - throw std::bad_alloc(); - indexCount = newIndexCount; - indexes = static_cast( newIndexes ); - } - virtual void releaseArrayPageIndex( Value **indexes, - ValueInternalArray::PageIndex indexCount ) - { - if ( indexes ) - free( indexes ); - } - - virtual Value *allocateArrayPage() - { - return static_cast( malloc( sizeof(Value) * ValueInternalArray::itemsPerPage ) ); - } - - virtual void releaseArrayPage( Value *value ) - { - if ( value ) - free( value ); - } -}; - \endcode - */ - class JSON_API ValueArrayAllocator - { - public: - virtual ~ValueArrayAllocator(); - virtual ValueInternalArray *newArray() = 0; - virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other ) = 0; - virtual void destructArray( ValueInternalArray *array ) = 0; - /** \brief Reallocate array page index. - * Reallocates an array of pointer on each page. - * \param indexes [input] pointer on the current index. May be \c NULL. - * [output] pointer on the new index of at least - * \a minNewIndexCount pages. - * \param indexCount [input] current number of pages in the index. - * [output] number of page the reallocated index can handle. - * \b MUST be >= \a minNewIndexCount. - * \param minNewIndexCount Minimum number of page the new index must be able to - * handle. - */ - virtual void reallocateArrayPageIndex( Value **&indexes, - ValueInternalArray::PageIndex &indexCount, - ValueInternalArray::PageIndex minNewIndexCount ) = 0; - virtual void releaseArrayPageIndex( Value **indexes, - ValueInternalArray::PageIndex indexCount ) = 0; - virtual Value *allocateArrayPage() = 0; - virtual void releaseArrayPage( Value *value ) = 0; - }; -#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP - - - /** \brief base class for Value iterators. - * - */ - class ValueIteratorBase - { - public: - typedef unsigned int size_t; - typedef int difference_type; - typedef ValueIteratorBase SelfType; - - ValueIteratorBase(); -#ifndef JSON_VALUE_USE_INTERNAL_MAP - explicit ValueIteratorBase( const Value::ObjectValues::iterator ¤t ); -#else - ValueIteratorBase( const ValueInternalArray::IteratorState &state ); - ValueIteratorBase( const ValueInternalMap::IteratorState &state ); -#endif - - bool operator ==( const SelfType &other ) const - { - return isEqual( other ); - } - - bool operator !=( const SelfType &other ) const - { - return !isEqual( other ); - } - - difference_type operator -( const SelfType &other ) const - { - return computeDistance( other ); - } - - /// Return either the index or the member name of the referenced value as a Value. - Value key() const; - - /// Return the index of the referenced Value. -1 if it is not an arrayValue. - UInt index() const; - - /// Return the member name of the referenced Value. "" if it is not an objectValue. - const char *memberName() const; - - protected: - Value &deref() const; - - void increment(); - - void decrement(); - - difference_type computeDistance( const SelfType &other ) const; - - bool isEqual( const SelfType &other ) const; - - void copy( const SelfType &other ); - - private: -#ifndef JSON_VALUE_USE_INTERNAL_MAP - Value::ObjectValues::iterator current_; - // Indicates that iterator is for a null value. - bool isNull_; -#else - union - { - ValueInternalArray::IteratorState array_; - ValueInternalMap::IteratorState map_; - } iterator_; - bool isArray_; -#endif - }; - - /** \brief const iterator for object and array value. - * - */ - class ValueConstIterator : public ValueIteratorBase - { - friend class Value; - public: - typedef unsigned int size_t; - typedef int difference_type; - typedef const Value &reference; - typedef const Value *pointer; - typedef ValueConstIterator SelfType; - - ValueConstIterator(); - private: - /*! \internal Use by Value to create an iterator. - */ -#ifndef JSON_VALUE_USE_INTERNAL_MAP - explicit ValueConstIterator( const Value::ObjectValues::iterator ¤t ); -#else - ValueConstIterator( const ValueInternalArray::IteratorState &state ); - ValueConstIterator( const ValueInternalMap::IteratorState &state ); -#endif - public: - SelfType &operator =( const ValueIteratorBase &other ); - - SelfType operator++( int ) - { - SelfType temp( *this ); - ++*this; - return temp; - } - - SelfType operator--( int ) - { - SelfType temp( *this ); - --*this; - return temp; - } - - SelfType &operator--() - { - decrement(); - return *this; - } - - SelfType &operator++() - { - increment(); - return *this; - } - - reference operator *() const - { - return deref(); - } - }; - - - /** \brief Iterator for object and array value. - */ - class ValueIterator : public ValueIteratorBase - { - friend class Value; - public: - typedef unsigned int size_t; - typedef int difference_type; - typedef Value &reference; - typedef Value *pointer; - typedef ValueIterator SelfType; - - ValueIterator(); - ValueIterator( const ValueConstIterator &other ); - ValueIterator( const ValueIterator &other ); - private: - /*! \internal Use by Value to create an iterator. - */ -#ifndef JSON_VALUE_USE_INTERNAL_MAP - explicit ValueIterator( const Value::ObjectValues::iterator ¤t ); -#else - ValueIterator( const ValueInternalArray::IteratorState &state ); - ValueIterator( const ValueInternalMap::IteratorState &state ); -#endif - public: - - SelfType &operator =( const SelfType &other ); - - SelfType operator++( int ) - { - SelfType temp( *this ); - ++*this; - return temp; - } - - SelfType operator--( int ) - { - SelfType temp( *this ); - --*this; - return temp; - } - - SelfType &operator--() - { - decrement(); - return *this; - } - - SelfType &operator++() - { - increment(); - return *this; - } - - reference operator *() const - { - return deref(); - } - }; - - -} // namespace Json - - -#endif // CPPTL_JSON_H_INCLUDED - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: include/json/value.h -// ////////////////////////////////////////////////////////////////////// - - - - - - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: include/json/reader.h -// ////////////////////////////////////////////////////////////////////// - -// Copyright 2007-2010 Baptiste Lepilleur -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#ifndef CPPTL_JSON_READER_H_INCLUDED -# define CPPTL_JSON_READER_H_INCLUDED - -#if !defined(JSON_IS_AMALGAMATION) -# include "features.h" -# include "value.h" -#endif // if !defined(JSON_IS_AMALGAMATION) -# include -# include -# include -# include - -namespace Json { - - /** \brief Unserialize a JSON document into a Value. - * - */ - class JSON_API Reader - { - public: - typedef char Char; - typedef const Char *Location; - - /** \brief Constructs a Reader allowing all features - * for parsing. - */ - Reader(); - - /** \brief Constructs a Reader allowing the specified feature set - * for parsing. - */ - Reader( const Features &features ); - - /** \brief Read a Value from a JSON document. - * \param document UTF-8 encoded string containing the document to read. - * \param root [out] Contains the root value of the document if it was - * successfully parsed. - * \param collectComments \c true to collect comment and allow writing them back during - * serialization, \c false to discard comments. - * This parameter is ignored if Features::allowComments_ - * is \c false. - * \return \c true if the document was successfully parsed, \c false if an error occurred. - */ - bool parse( const std::string &document, - Value &root, - bool collectComments = true ); - - /** \brief Read a Value from a JSON document. - * \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the document to read. - * \param endDoc Pointer on the end of the UTF-8 encoded string of the document to read. - \ Must be >= beginDoc. - * \param root [out] Contains the root value of the document if it was - * successfully parsed. - * \param collectComments \c true to collect comment and allow writing them back during - * serialization, \c false to discard comments. - * This parameter is ignored if Features::allowComments_ - * is \c false. - * \return \c true if the document was successfully parsed, \c false if an error occurred. - */ - bool parse( const char *beginDoc, const char *endDoc, - Value &root, - bool collectComments = true ); - - /// \brief Parse from input stream. - /// \see Json::operator>>(std::istream&, Json::Value&). - bool parse( std::istream &is, - Value &root, - bool collectComments = true ); - - /** \brief Returns a user friendly string that list errors in the parsed document. - * \return Formatted error message with the list of errors with their location in - * the parsed document. An empty string is returned if no error occurred - * during parsing. - * \deprecated Use getFormattedErrorMessages() instead (typo fix). - */ - JSONCPP_DEPRECATED("Use getFormattedErrorMessages instead") - std::string getFormatedErrorMessages() const; - - /** \brief Returns a user friendly string that list errors in the parsed document. - * \return Formatted error message with the list of errors with their location in - * the parsed document. An empty string is returned if no error occurred - * during parsing. - */ - std::string getFormattedErrorMessages() const; - - private: - enum TokenType - { - tokenEndOfStream = 0, - tokenObjectBegin, - tokenObjectEnd, - tokenArrayBegin, - tokenArrayEnd, - tokenString, - tokenNumber, - tokenTrue, - tokenFalse, - tokenNull, - tokenArraySeparator, - tokenMemberSeparator, - tokenComment, - tokenError - }; - - class Token - { - public: - TokenType type_; - Location start_; - Location end_; - }; - - class ErrorInfo - { - public: - Token token_; - std::string message_; - Location extra_; - }; - - typedef std::deque Errors; - - bool expectToken( TokenType type, Token &token, const char *message ); - bool readToken( Token &token ); - void skipSpaces(); - bool match( Location pattern, - int patternLength ); - bool readComment(); - bool readCStyleComment(); - bool readCppStyleComment(); - bool readString(); - void readNumber(); - bool readValue(); - bool readObject( Token &token ); - bool readArray( Token &token ); - bool decodeNumber( Token &token ); - bool decodeString( Token &token ); - bool decodeString( Token &token, std::string &decoded ); - bool decodeDouble( Token &token ); - bool decodeUnicodeCodePoint( Token &token, - Location ¤t, - Location end, - unsigned int &unicode ); - bool decodeUnicodeEscapeSequence( Token &token, - Location ¤t, - Location end, - unsigned int &unicode ); - bool addError( const std::string &message, - Token &token, - Location extra = 0 ); - bool recoverFromError( TokenType skipUntilToken ); - bool addErrorAndRecover( const std::string &message, - Token &token, - TokenType skipUntilToken ); - void skipUntilSpace(); - Value ¤tValue(); - Char getNextChar(); - void getLocationLineAndColumn( Location location, - int &line, - int &column ) const; - std::string getLocationLineAndColumn( Location location ) const; - void addComment( Location begin, - Location end, - CommentPlacement placement ); - void skipCommentTokens( Token &token ); - - typedef std::stack Nodes; - Nodes nodes_; - Errors errors_; - std::string document_; - Location begin_; - Location end_; - Location current_; - Location lastValueEnd_; - Value *lastValue_; - std::string commentsBefore_; - Features features_; - bool collectComments_; - }; - - /** \brief Read from 'sin' into 'root'. - - Always keep comments from the input JSON. - - This can be used to read a file into a particular sub-object. - For example: - \code - Json::Value root; - cin >> root["dir"]["file"]; - cout << root; - \endcode - Result: - \verbatim - { - "dir": { - "file": { - // The input stream JSON would be nested here. - } - } - } - \endverbatim - \throw std::exception on parse error. - \see Json::operator<<() - */ - std::istream& operator>>( std::istream&, Value& ); - -} // namespace Json - -#endif // CPPTL_JSON_READER_H_INCLUDED - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: include/json/reader.h -// ////////////////////////////////////////////////////////////////////// - - - - - - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: include/json/writer.h -// ////////////////////////////////////////////////////////////////////// - -// Copyright 2007-2010 Baptiste Lepilleur -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#ifndef JSON_WRITER_H_INCLUDED -# define JSON_WRITER_H_INCLUDED - -#if !defined(JSON_IS_AMALGAMATION) -# include "value.h" -#endif // if !defined(JSON_IS_AMALGAMATION) -# include -# include -# include - -namespace Json { - - class Value; - - /** \brief Abstract class for writers. - */ - class JSON_API Writer - { - public: - virtual ~Writer(); - - virtual std::string write( const Value &root ) = 0; - }; - - /** \brief Outputs a Value in JSON format without formatting (not human friendly). - * - * The JSON document is written in a single line. It is not intended for 'human' consumption, - * but may be usefull to support feature such as RPC where bandwith is limited. - * \sa Reader, Value - */ - class JSON_API FastWriter : public Writer - { - public: - FastWriter(); - virtual ~FastWriter(){} - - void enableYAMLCompatibility(); - - public: // overridden from Writer - virtual std::string write( const Value &root ); - - private: - void writeValue( const Value &value ); - - std::string document_; - bool yamlCompatiblityEnabled_; - }; - - /** \brief Writes a Value in JSON format in a human friendly way. - * - * The rules for line break and indent are as follow: - * - Object value: - * - if empty then print {} without indent and line break - * - if not empty the print '{', line break & indent, print one value per line - * and then unindent and line break and print '}'. - * - Array value: - * - if empty then print [] without indent and line break - * - if the array contains no object value, empty array or some other value types, - * and all the values fit on one lines, then print the array on a single line. - * - otherwise, it the values do not fit on one line, or the array contains - * object or non empty array, then print one value per line. - * - * If the Value have comments then they are outputed according to their #CommentPlacement. - * - * \sa Reader, Value, Value::setComment() - */ - class JSON_API StyledWriter: public Writer - { - public: - StyledWriter(); - virtual ~StyledWriter(){} - - public: // overridden from Writer - /** \brief Serialize a Value in JSON format. - * \param root Value to serialize. - * \return String containing the JSON document that represents the root value. - */ - virtual std::string write( const Value &root ); - - private: - void writeValue( const Value &value ); - void writeArrayValue( const Value &value ); - bool isMultineArray( const Value &value ); - void pushValue( const std::string &value ); - void writeIndent(); - void writeWithIndent( const std::string &value ); - void indent(); - void unindent(); - void writeCommentBeforeValue( const Value &root ); - void writeCommentAfterValueOnSameLine( const Value &root ); - bool hasCommentForValue( const Value &value ); - static std::string normalizeEOL( const std::string &text ); - - typedef std::vector ChildValues; - - ChildValues childValues_; - std::string document_; - std::string indentString_; - int rightMargin_; - int indentSize_; - bool addChildValues_; - }; - - /** \brief Writes a Value in JSON format in a human friendly way, - to a stream rather than to a string. - * - * The rules for line break and indent are as follow: - * - Object value: - * - if empty then print {} without indent and line break - * - if not empty the print '{', line break & indent, print one value per line - * and then unindent and line break and print '}'. - * - Array value: - * - if empty then print [] without indent and line break - * - if the array contains no object value, empty array or some other value types, - * and all the values fit on one lines, then print the array on a single line. - * - otherwise, it the values do not fit on one line, or the array contains - * object or non empty array, then print one value per line. - * - * If the Value have comments then they are outputed according to their #CommentPlacement. - * - * \param indentation Each level will be indented by this amount extra. - * \sa Reader, Value, Value::setComment() - */ - class JSON_API StyledStreamWriter - { - public: - StyledStreamWriter( std::string indentation="\t" ); - ~StyledStreamWriter(){} - - public: - /** \brief Serialize a Value in JSON format. - * \param out Stream to write to. (Can be ostringstream, e.g.) - * \param root Value to serialize. - * \note There is no point in deriving from Writer, since write() should not return a value. - */ - void write( std::ostream &out, const Value &root ); - - private: - void writeValue( const Value &value ); - void writeArrayValue( const Value &value ); - bool isMultineArray( const Value &value ); - void pushValue( const std::string &value ); - void writeIndent(); - void writeWithIndent( const std::string &value ); - void indent(); - void unindent(); - void writeCommentBeforeValue( const Value &root ); - void writeCommentAfterValueOnSameLine( const Value &root ); - bool hasCommentForValue( const Value &value ); - static std::string normalizeEOL( const std::string &text ); - - typedef std::vector ChildValues; - - ChildValues childValues_; - std::ostream* document_; - std::string indentString_; - int rightMargin_; - std::string indentation_; - bool addChildValues_; - }; - -# if defined(JSON_HAS_INT64) - std::string JSON_API valueToString( Int value ); - std::string JSON_API valueToString( UInt value ); -# endif // if defined(JSON_HAS_INT64) - std::string JSON_API valueToString( LargestInt value ); - std::string JSON_API valueToString( LargestUInt value ); - std::string JSON_API valueToString( double value ); - std::string JSON_API valueToString( bool value ); - std::string JSON_API valueToQuotedString( const char *value ); - - /// \brief Output using the StyledStreamWriter. - /// \see Json::operator>>() - std::ostream& operator<<( std::ostream&, const Value &root ); - -} // namespace Json - - - -#endif // JSON_WRITER_H_INCLUDED - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: include/json/writer.h -// ////////////////////////////////////////////////////////////////////// - - - - - -#endif //ifndef JSON_AMALGATED_H_INCLUDED diff --git a/thirdparty/jsoncpp/jsoncpp.cpp b/thirdparty/jsoncpp/jsoncpp.cpp deleted file mode 100644 index be153f9055..0000000000 --- a/thirdparty/jsoncpp/jsoncpp.cpp +++ /dev/null @@ -1,4236 +0,0 @@ -/// Json-cpp amalgated source (http://jsoncpp.sourceforge.net/). -/// It is intented to be used with #include - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: LICENSE -// ////////////////////////////////////////////////////////////////////// - -/* -The JsonCpp library's source code, including accompanying documentation, -tests and demonstration applications, are licensed under the following -conditions... - -The author (Baptiste Lepilleur) explicitly disclaims copyright in all -jurisdictions which recognize such a disclaimer. In such jurisdictions, -this software is released into the Public Domain. - -In jurisdictions which do not recognize Public Domain property (e.g. Germany as of -2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur, and is -released under the terms of the MIT License (see below). - -In jurisdictions which recognize Public Domain property, the user of this -software may choose to accept it either as 1) Public Domain, 2) under the -conditions of the MIT License (see below), or 3) under the terms of dual -Public Domain/MIT License conditions described here, as they choose. - -The MIT License is about as close to Public Domain as a license can get, and is -described in clear, concise terms at: - - http://en.wikipedia.org/wiki/MIT_License - -The full text of the MIT License follows: - -======================================================================== -Copyright (c) 2007-2010 Baptiste Lepilleur - -Permission is hereby granted, free of charge, to any person -obtaining a copy of this software and associated documentation -files (the "Software"), to deal in the Software without -restriction, including without limitation the rights to use, copy, -modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -======================================================================== -(END LICENSE TEXT) - -The MIT license is compatible with both the GPL and commercial -software, affording one all of the rights of Public Domain with the -minor nuisance of being required to keep the above copyright notice -and license text in the source code. Note also that by accepting the -Public Domain "license" you can re-license your copy using whatever -license you like. - -*/ - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: LICENSE -// ////////////////////////////////////////////////////////////////////// - - -// ignore some warnings -#pragma GCC diagnostic ignored "-Woverflow" -#pragma GCC diagnostic ignored "-Wunused-parameter" - - - -#include "json/json.h" - - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: src/lib_json/json_tool.h -// ////////////////////////////////////////////////////////////////////// - -// Copyright 2007-2010 Baptiste Lepilleur -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#ifndef LIB_JSONCPP_JSON_TOOL_H_INCLUDED -# define LIB_JSONCPP_JSON_TOOL_H_INCLUDED - -/* This header provides common string manipulation support, such as UTF-8, - * portable conversion from/to string... - * - * It is an internal header that must not be exposed. - */ - -namespace Json { - -/// Converts a unicode code-point to UTF-8. -static inline std::string -codePointToUTF8(unsigned int cp) -{ - std::string result; - - // based on description from http://en.wikipedia.org/wiki/UTF-8 - - if (cp <= 0x7f) - { - result.resize(1); - result[0] = static_cast(cp); - } - else if (cp <= 0x7FF) - { - result.resize(2); - result[1] = static_cast(0x80 | (0x3f & cp)); - result[0] = static_cast(0xC0 | (0x1f & (cp >> 6))); - } - else if (cp <= 0xFFFF) - { - result.resize(3); - result[2] = static_cast(0x80 | (0x3f & cp)); - result[1] = 0x80 | static_cast((0x3f & (cp >> 6))); - result[0] = 0xE0 | static_cast((0xf & (cp >> 12))); - } - else if (cp <= 0x10FFFF) - { - result.resize(4); - result[3] = static_cast(0x80 | (0x3f & cp)); - result[2] = static_cast(0x80 | (0x3f & (cp >> 6))); - result[1] = static_cast(0x80 | (0x3f & (cp >> 12))); - result[0] = static_cast(0xF0 | (0x7 & (cp >> 18))); - } - - return result; -} - - -/// Returns true if ch is a control character (in range [0,32[). -static inline bool -isControlCharacter(char ch) -{ - return ch > 0 && ch <= 0x1F; -} - - -enum { - /// Constant that specify the size of the buffer that must be passed to uintToString. - uintToStringBufferSize = 3*sizeof(LargestUInt)+1 -}; - -// Defines a char buffer for use with uintToString(). -typedef char UIntToStringBuffer[uintToStringBufferSize]; - - -/** Converts an unsigned integer to string. - * @param value Unsigned interger to convert to string - * @param current Input/Output string buffer. - * Must have at least uintToStringBufferSize chars free. - */ -static inline void -uintToString( LargestUInt value, - char *¤t ) -{ - *--current = 0; - do - { - *--current = char(value % 10) + '0'; - value /= 10; - } - while ( value != 0 ); -} - -} // namespace Json { - -#endif // LIB_JSONCPP_JSON_TOOL_H_INCLUDED - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: src/lib_json/json_tool.h -// ////////////////////////////////////////////////////////////////////// - - - - - - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: src/lib_json/json_reader.cpp -// ////////////////////////////////////////////////////////////////////// - -// Copyright 2007-2010 Baptiste Lepilleur -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#if !defined(JSON_IS_AMALGAMATION) -# include -# include -# include "json_tool.h" -#endif // if !defined(JSON_IS_AMALGAMATION) -#include -#include -#include -#include -#include -#include - -#if _MSC_VER >= 1400 // VC++ 8.0 -#pragma warning( disable : 4996 ) // disable warning about strdup being deprecated. -#endif - -namespace Json { - -// Implementation of class Features -// //////////////////////////////// - -Features::Features() - : allowComments_( true ) - , strictRoot_( false ) -{ -} - - -Features -Features::all() -{ - return Features(); -} - - -Features -Features::strictMode() -{ - Features features; - features.allowComments_ = false; - features.strictRoot_ = true; - return features; -} - -// Implementation of class Reader -// //////////////////////////////// - - -static inline bool -in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4 ) -{ - return c == c1 || c == c2 || c == c3 || c == c4; -} - -static inline bool -in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4, Reader::Char c5 ) -{ - return c == c1 || c == c2 || c == c3 || c == c4 || c == c5; -} - - -static bool -containsNewLine( Reader::Location begin, - Reader::Location end ) -{ - for ( ;begin < end; ++begin ) - if ( *begin == '\n' || *begin == '\r' ) - return true; - return false; -} - - -// Class Reader -// ////////////////////////////////////////////////////////////////// - -Reader::Reader() - : features_( Features::all() ) -{ -} - - -Reader::Reader( const Features &features ) - : features_( features ) -{ -} - - -bool -Reader::parse( const std::string &document, - Value &root, - bool collectComments ) -{ - document_ = document; - const char *begin = document_.c_str(); - const char *end = begin + document_.length(); - return parse( begin, end, root, collectComments ); -} - - -bool -Reader::parse( std::istream& sin, - Value &root, - bool collectComments ) -{ - //std::istream_iterator begin(sin); - //std::istream_iterator end; - // Those would allow streamed input from a file, if parse() were a - // template function. - - // Since std::string is reference-counted, this at least does not - // create an extra copy. - std::string doc; - std::getline(sin, doc, (char)EOF); - return parse( doc, root, collectComments ); -} - -bool -Reader::parse( const char *beginDoc, const char *endDoc, - Value &root, - bool collectComments ) -{ - if ( !features_.allowComments_ ) - { - collectComments = false; - } - - begin_ = beginDoc; - end_ = endDoc; - collectComments_ = collectComments; - current_ = begin_; - lastValueEnd_ = 0; - lastValue_ = 0; - commentsBefore_ = ""; - errors_.clear(); - while ( !nodes_.empty() ) - nodes_.pop(); - nodes_.push( &root ); - - bool successful = readValue(); - Token token; - skipCommentTokens( token ); - if ( collectComments_ && !commentsBefore_.empty() ) - root.setComment( commentsBefore_, commentAfter ); - if ( features_.strictRoot_ ) - { - if ( !root.isArray() && !root.isObject() ) - { - // Set error location to start of doc, ideally should be first token found in doc - token.type_ = tokenError; - token.start_ = beginDoc; - token.end_ = endDoc; - addError( "A valid JSON document must be either an array or an object value.", - token ); - return false; - } - } - return successful; -} - - -bool -Reader::readValue() -{ - Token token; - skipCommentTokens( token ); - bool successful = true; - - if ( collectComments_ && !commentsBefore_.empty() ) - { - currentValue().setComment( commentsBefore_, commentBefore ); - commentsBefore_ = ""; - } - - - switch ( token.type_ ) - { - case tokenObjectBegin: - successful = readObject( token ); - break; - case tokenArrayBegin: - successful = readArray( token ); - break; - case tokenNumber: - successful = decodeNumber( token ); - break; - case tokenString: - successful = decodeString( token ); - break; - case tokenTrue: - currentValue() = true; - break; - case tokenFalse: - currentValue() = false; - break; - case tokenNull: - currentValue() = Value(); - break; - default: - return addError( "Syntax error: value, object or array expected.", token ); - } - - if ( collectComments_ ) - { - lastValueEnd_ = current_; - lastValue_ = ¤tValue(); - } - - return successful; -} - - -void -Reader::skipCommentTokens( Token &token ) -{ - if ( features_.allowComments_ ) - { - do - { - readToken( token ); - } - while ( token.type_ == tokenComment ); - } - else - { - readToken( token ); - } -} - - -bool -Reader::expectToken( TokenType type, Token &token, const char *message ) -{ - readToken( token ); - if ( token.type_ != type ) - return addError( message, token ); - return true; -} - - -bool -Reader::readToken( Token &token ) -{ - skipSpaces(); - token.start_ = current_; - Char c = getNextChar(); - bool ok = true; - switch ( c ) - { - case '{': - token.type_ = tokenObjectBegin; - break; - case '}': - token.type_ = tokenObjectEnd; - break; - case '[': - token.type_ = tokenArrayBegin; - break; - case ']': - token.type_ = tokenArrayEnd; - break; - case '"': - token.type_ = tokenString; - ok = readString(); - break; - case '/': - token.type_ = tokenComment; - ok = readComment(); - break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case '-': - token.type_ = tokenNumber; - readNumber(); - break; - case 't': - token.type_ = tokenTrue; - ok = match( "rue", 3 ); - break; - case 'f': - token.type_ = tokenFalse; - ok = match( "alse", 4 ); - break; - case 'n': - token.type_ = tokenNull; - ok = match( "ull", 3 ); - break; - case ',': - token.type_ = tokenArraySeparator; - break; - case ':': - token.type_ = tokenMemberSeparator; - break; - case 0: - token.type_ = tokenEndOfStream; - break; - default: - ok = false; - break; - } - if ( !ok ) - token.type_ = tokenError; - token.end_ = current_; - return true; -} - - -void -Reader::skipSpaces() -{ - while ( current_ != end_ ) - { - Char c = *current_; - if ( c == ' ' || c == '\t' || c == '\r' || c == '\n' ) - ++current_; - else - break; - } -} - - -bool -Reader::match( Location pattern, - int patternLength ) -{ - if ( end_ - current_ < patternLength ) - return false; - int index = patternLength; - while ( index-- ) - if ( current_[index] != pattern[index] ) - return false; - current_ += patternLength; - return true; -} - - -bool -Reader::readComment() -{ - Location commentBegin = current_ - 1; - Char c = getNextChar(); - bool successful = false; - if ( c == '*' ) - successful = readCStyleComment(); - else if ( c == '/' ) - successful = readCppStyleComment(); - if ( !successful ) - return false; - - if ( collectComments_ ) - { - CommentPlacement placement = commentBefore; - if ( lastValueEnd_ && !containsNewLine( lastValueEnd_, commentBegin ) ) - { - if ( c != '*' || !containsNewLine( commentBegin, current_ ) ) - placement = commentAfterOnSameLine; - } - - addComment( commentBegin, current_, placement ); - } - return true; -} - - -void -Reader::addComment( Location begin, - Location end, - CommentPlacement placement ) -{ - assert( collectComments_ ); - if ( placement == commentAfterOnSameLine ) - { - assert( lastValue_ != 0 ); - lastValue_->setComment( std::string( begin, end ), placement ); - } - else - { - if ( !commentsBefore_.empty() ) - commentsBefore_ += "\n"; - commentsBefore_ += std::string( begin, end ); - } -} - - -bool -Reader::readCStyleComment() -{ - while ( current_ != end_ ) - { - Char c = getNextChar(); - if ( c == '*' && *current_ == '/' ) - break; - } - return getNextChar() == '/'; -} - - -bool -Reader::readCppStyleComment() -{ - while ( current_ != end_ ) - { - Char c = getNextChar(); - if ( c == '\r' || c == '\n' ) - break; - } - return true; -} - - -void -Reader::readNumber() -{ - while ( current_ != end_ ) - { - if ( !(*current_ >= '0' && *current_ <= '9') && - !in( *current_, '.', 'e', 'E', '+', '-' ) ) - break; - ++current_; - } -} - -bool -Reader::readString() -{ - Char c = 0; - while ( current_ != end_ ) - { - c = getNextChar(); - if ( c == '\\' ) - getNextChar(); - else if ( c == '"' ) - break; - } - return c == '"'; -} - - -bool -Reader::readObject( Token &/*tokenStart*/ ) -{ - Token tokenName; - std::string name; - currentValue() = Value( objectValue ); - while ( readToken( tokenName ) ) - { - bool initialTokenOk = true; - while ( tokenName.type_ == tokenComment && initialTokenOk ) - initialTokenOk = readToken( tokenName ); - if ( !initialTokenOk ) - break; - if ( tokenName.type_ == tokenObjectEnd && name.empty() ) // empty object - return true; - if ( tokenName.type_ != tokenString ) - break; - - name = ""; - if ( !decodeString( tokenName, name ) ) - return recoverFromError( tokenObjectEnd ); - - Token colon; - if ( !readToken( colon ) || colon.type_ != tokenMemberSeparator ) - { - return addErrorAndRecover( "Missing ':' after object member name", - colon, - tokenObjectEnd ); - } - Value &value = currentValue()[ name ]; - nodes_.push( &value ); - bool ok = readValue(); - nodes_.pop(); - if ( !ok ) // error already set - return recoverFromError( tokenObjectEnd ); - - Token comma; - if ( !readToken( comma ) - || ( comma.type_ != tokenObjectEnd && - comma.type_ != tokenArraySeparator && - comma.type_ != tokenComment ) ) - { - return addErrorAndRecover( "Missing ',' or '}' in object declaration", - comma, - tokenObjectEnd ); - } - bool finalizeTokenOk = true; - while ( comma.type_ == tokenComment && - finalizeTokenOk ) - finalizeTokenOk = readToken( comma ); - if ( comma.type_ == tokenObjectEnd ) - return true; - } - return addErrorAndRecover( "Missing '}' or object member name", - tokenName, - tokenObjectEnd ); -} - - -bool -Reader::readArray( Token &/*tokenStart*/ ) -{ - currentValue() = Value( arrayValue ); - skipSpaces(); - if ( *current_ == ']' ) // empty array - { - Token endArray; - readToken( endArray ); - return true; - } - int index = 0; - for (;;) - { - Value &value = currentValue()[ index++ ]; - nodes_.push( &value ); - bool ok = readValue(); - nodes_.pop(); - if ( !ok ) // error already set - return recoverFromError( tokenArrayEnd ); - - Token token; - // Accept Comment after last item in the array. - ok = readToken( token ); - while ( token.type_ == tokenComment && ok ) - { - ok = readToken( token ); - } - bool badTokenType = ( token.type_ != tokenArraySeparator && - token.type_ != tokenArrayEnd ); - if ( !ok || badTokenType ) - { - return addErrorAndRecover( "Missing ',' or ']' in array declaration", - token, - tokenArrayEnd ); - } - if ( token.type_ == tokenArrayEnd ) - break; - } - return true; -} - - -bool -Reader::decodeNumber( Token &token ) -{ - bool isDouble = false; - for ( Location inspect = token.start_; inspect != token.end_; ++inspect ) - { - isDouble = isDouble - || in( *inspect, '.', 'e', 'E', '+' ) - || ( *inspect == '-' && inspect != token.start_ ); - } - if ( isDouble ) - return decodeDouble( token ); - // Attempts to parse the number as an integer. If the number is - // larger than the maximum supported value of an integer then - // we decode the number as a double. - Location current = token.start_; - bool isNegative = *current == '-'; - if ( isNegative ) - ++current; - Value::LargestUInt maxIntegerValue = isNegative ? Value::LargestUInt(-Value::minLargestInt) - : Value::maxLargestUInt; - Value::LargestUInt threshold = maxIntegerValue / 10; - Value::UInt lastDigitThreshold = Value::UInt( maxIntegerValue % 10 ); - assert( lastDigitThreshold >=0 && lastDigitThreshold <= 9 ); - Value::LargestUInt value = 0; - while ( current < token.end_ ) - { - Char c = *current++; - if ( c < '0' || c > '9' ) - return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token ); - Value::UInt digit(c - '0'); - if ( value >= threshold ) - { - // If the current digit is not the last one, or if it is - // greater than the last digit of the maximum integer value, - // the parse the number as a double. - if ( current != token.end_ || digit > lastDigitThreshold ) - { - return decodeDouble( token ); - } - } - value = value * 10 + digit; - } - if ( isNegative ) - currentValue() = -Value::LargestInt( value ); - else if ( value <= Value::LargestUInt(Value::maxInt) ) - currentValue() = Value::LargestInt( value ); - else - currentValue() = value; - return true; -} - - -bool -Reader::decodeDouble( Token &token ) -{ - double value = 0; - const int bufferSize = 32; - int count; - int length = int(token.end_ - token.start_); - if ( length <= bufferSize ) - { - Char buffer[bufferSize+1]; - memcpy( buffer, token.start_, length ); - buffer[length] = 0; - count = sscanf( buffer, "%lf", &value ); - } - else - { - std::string buffer( token.start_, token.end_ ); - count = sscanf( buffer.c_str(), "%lf", &value ); - } - - if ( count != 1 ) - return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token ); - currentValue() = value; - return true; -} - - -bool -Reader::decodeString( Token &token ) -{ - std::string decoded; - if ( !decodeString( token, decoded ) ) - return false; - currentValue() = decoded; - return true; -} - - -bool -Reader::decodeString( Token &token, std::string &decoded ) -{ - decoded.reserve( token.end_ - token.start_ - 2 ); - Location current = token.start_ + 1; // skip '"' - Location end = token.end_ - 1; // do not include '"' - while ( current != end ) - { - Char c = *current++; - if ( c == '"' ) - break; - else if ( c == '\\' ) - { - if ( current == end ) - return addError( "Empty escape sequence in string", token, current ); - Char escape = *current++; - switch ( escape ) - { - case '"': decoded += '"'; break; - case '/': decoded += '/'; break; - case '\\': decoded += '\\'; break; - case 'b': decoded += '\b'; break; - case 'f': decoded += '\f'; break; - case 'n': decoded += '\n'; break; - case 'r': decoded += '\r'; break; - case 't': decoded += '\t'; break; - case 'u': - { - unsigned int unicode; - if ( !decodeUnicodeCodePoint( token, current, end, unicode ) ) - return false; - decoded += codePointToUTF8(unicode); - } - break; - default: - return addError( "Bad escape sequence in string", token, current ); - } - } - else - { - decoded += c; - } - } - return true; -} - -bool -Reader::decodeUnicodeCodePoint( Token &token, - Location ¤t, - Location end, - unsigned int &unicode ) -{ - - if ( !decodeUnicodeEscapeSequence( token, current, end, unicode ) ) - return false; - if (unicode >= 0xD800 && unicode <= 0xDBFF) - { - // surrogate pairs - if (end - current < 6) - return addError( "additional six characters expected to parse unicode surrogate pair.", token, current ); - unsigned int surrogatePair; - if (*(current++) == '\\' && *(current++)== 'u') - { - if (decodeUnicodeEscapeSequence( token, current, end, surrogatePair )) - { - unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF); - } - else - return false; - } - else - return addError( "expecting another \\u token to begin the second half of a unicode surrogate pair", token, current ); - } - return true; -} - -bool -Reader::decodeUnicodeEscapeSequence( Token &token, - Location ¤t, - Location end, - unsigned int &unicode ) -{ - if ( end - current < 4 ) - return addError( "Bad unicode escape sequence in string: four digits expected.", token, current ); - unicode = 0; - for ( int index =0; index < 4; ++index ) - { - Char c = *current++; - unicode *= 16; - if ( c >= '0' && c <= '9' ) - unicode += c - '0'; - else if ( c >= 'a' && c <= 'f' ) - unicode += c - 'a' + 10; - else if ( c >= 'A' && c <= 'F' ) - unicode += c - 'A' + 10; - else - return addError( "Bad unicode escape sequence in string: hexadecimal digit expected.", token, current ); - } - return true; -} - - -bool -Reader::addError( const std::string &message, - Token &token, - Location extra ) -{ - ErrorInfo info; - info.token_ = token; - info.message_ = message; - info.extra_ = extra; - errors_.push_back( info ); - return false; -} - - -bool -Reader::recoverFromError( TokenType skipUntilToken ) -{ - int errorCount = int(errors_.size()); - Token skip; - for (;;) - { - if ( !readToken(skip) ) - errors_.resize( errorCount ); // discard errors caused by recovery - if ( skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream ) - break; - } - errors_.resize( errorCount ); - return false; -} - - -bool -Reader::addErrorAndRecover( const std::string &message, - Token &token, - TokenType skipUntilToken ) -{ - addError( message, token ); - return recoverFromError( skipUntilToken ); -} - - -Value & -Reader::currentValue() -{ - return *(nodes_.top()); -} - - -Reader::Char -Reader::getNextChar() -{ - if ( current_ == end_ ) - return 0; - return *current_++; -} - - -void -Reader::getLocationLineAndColumn( Location location, - int &line, - int &column ) const -{ - Location current = begin_; - Location lastLineStart = current; - line = 0; - while ( current < location && current != end_ ) - { - Char c = *current++; - if ( c == '\r' ) - { - if ( *current == '\n' ) - ++current; - lastLineStart = current; - ++line; - } - else if ( c == '\n' ) - { - lastLineStart = current; - ++line; - } - } - // column & line start at 1 - column = int(location - lastLineStart) + 1; - ++line; -} - - -std::string -Reader::getLocationLineAndColumn( Location location ) const -{ - int line, column; - getLocationLineAndColumn( location, line, column ); - char buffer[18+16+16+1]; - sprintf( buffer, "Line %d, Column %d", line, column ); - return buffer; -} - - -// Deprecated. Preserved for backward compatibility -std::string -Reader::getFormatedErrorMessages() const -{ - return getFormattedErrorMessages(); -} - - -std::string -Reader::getFormattedErrorMessages() const -{ - std::string formattedMessage; - for ( Errors::const_iterator itError = errors_.begin(); - itError != errors_.end(); - ++itError ) - { - const ErrorInfo &error = *itError; - formattedMessage += "* " + getLocationLineAndColumn( error.token_.start_ ) + "\n"; - formattedMessage += " " + error.message_ + "\n"; - if ( error.extra_ ) - formattedMessage += "See " + getLocationLineAndColumn( error.extra_ ) + " for detail.\n"; - } - return formattedMessage; -} - - -std::istream& operator>>( std::istream &sin, Value &root ) -{ - Json::Reader reader; - bool ok = reader.parse(sin, root, true); - //JSON_ASSERT( ok ); - if (!ok) throw std::runtime_error(reader.getFormattedErrorMessages()); - return sin; -} - - -} // namespace Json - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: src/lib_json/json_reader.cpp -// ////////////////////////////////////////////////////////////////////// - - - - - - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: src/lib_json/json_batchallocator.h -// ////////////////////////////////////////////////////////////////////// - -// Copyright 2007-2010 Baptiste Lepilleur -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#ifndef JSONCPP_BATCHALLOCATOR_H_INCLUDED -# define JSONCPP_BATCHALLOCATOR_H_INCLUDED - -# include -# include - -# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION - -namespace Json { - -/* Fast memory allocator. - * - * This memory allocator allocates memory for a batch of object (specified by - * the page size, the number of object in each page). - * - * It does not allow the destruction of a single object. All the allocated objects - * can be destroyed at once. The memory can be either released or reused for future - * allocation. - * - * The in-place new operator must be used to construct the object using the pointer - * returned by allocate. - */ -template -class BatchAllocator -{ -public: - typedef AllocatedType Type; - - BatchAllocator( unsigned int objectsPerPage = 255 ) - : freeHead_( 0 ) - , objectsPerPage_( objectsPerPage ) - { -// printf( "Size: %d => %s\n", sizeof(AllocatedType), typeid(AllocatedType).name() ); - assert( sizeof(AllocatedType) * objectPerAllocation >= sizeof(AllocatedType *) ); // We must be able to store a slist in the object free space. - assert( objectsPerPage >= 16 ); - batches_ = allocateBatch( 0 ); // allocated a dummy page - currentBatch_ = batches_; - } - - ~BatchAllocator() - { - for ( BatchInfo *batch = batches_; batch; ) - { - BatchInfo *nextBatch = batch->next_; - free( batch ); - batch = nextBatch; - } - } - - /// allocate space for an array of objectPerAllocation object. - /// @warning it is the responsability of the caller to call objects constructors. - AllocatedType *allocate() - { - if ( freeHead_ ) // returns node from free list. - { - AllocatedType *object = freeHead_; - freeHead_ = *(AllocatedType **)object; - return object; - } - if ( currentBatch_->used_ == currentBatch_->end_ ) - { - currentBatch_ = currentBatch_->next_; - while ( currentBatch_ && currentBatch_->used_ == currentBatch_->end_ ) - currentBatch_ = currentBatch_->next_; - - if ( !currentBatch_ ) // no free batch found, allocate a new one - { - currentBatch_ = allocateBatch( objectsPerPage_ ); - currentBatch_->next_ = batches_; // insert at the head of the list - batches_ = currentBatch_; - } - } - AllocatedType *allocated = currentBatch_->used_; - currentBatch_->used_ += objectPerAllocation; - return allocated; - } - - /// Release the object. - /// @warning it is the responsability of the caller to actually destruct the object. - void release( AllocatedType *object ) - { - assert( object != 0 ); - *(AllocatedType **)object = freeHead_; - freeHead_ = object; - } - -private: - struct BatchInfo - { - BatchInfo *next_; - AllocatedType *used_; - AllocatedType *end_; - AllocatedType buffer_[objectPerAllocation]; - }; - - // disabled copy constructor and assignement operator. - BatchAllocator( const BatchAllocator & ); - void operator =( const BatchAllocator &); - - static BatchInfo *allocateBatch( unsigned int objectsPerPage ) - { - const unsigned int mallocSize = sizeof(BatchInfo) - sizeof(AllocatedType)* objectPerAllocation - + sizeof(AllocatedType) * objectPerAllocation * objectsPerPage; - BatchInfo *batch = static_cast( malloc( mallocSize ) ); - batch->next_ = 0; - batch->used_ = batch->buffer_; - batch->end_ = batch->buffer_ + objectsPerPage; - return batch; - } - - BatchInfo *batches_; - BatchInfo *currentBatch_; - /// Head of a single linked list within the allocated space of freeed object - AllocatedType *freeHead_; - unsigned int objectsPerPage_; -}; - - -} // namespace Json - -# endif // ifndef JSONCPP_DOC_INCLUDE_IMPLEMENTATION - -#endif // JSONCPP_BATCHALLOCATOR_H_INCLUDED - - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: src/lib_json/json_batchallocator.h -// ////////////////////////////////////////////////////////////////////// - - - - - - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: src/lib_json/json_valueiterator.inl -// ////////////////////////////////////////////////////////////////////// - -// Copyright 2007-2010 Baptiste Lepilleur -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -// included by json_value.cpp - -namespace Json { - -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// class ValueIteratorBase -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// - -ValueIteratorBase::ValueIteratorBase() -#ifndef JSON_VALUE_USE_INTERNAL_MAP - : current_() - , isNull_( true ) -{ -} -#else - : isArray_( true ) - , isNull_( true ) -{ - iterator_.array_ = ValueInternalArray::IteratorState(); -} -#endif - - -#ifndef JSON_VALUE_USE_INTERNAL_MAP -ValueIteratorBase::ValueIteratorBase( const Value::ObjectValues::iterator ¤t ) - : current_( current ) - , isNull_( false ) -{ -} -#else -ValueIteratorBase::ValueIteratorBase( const ValueInternalArray::IteratorState &state ) - : isArray_( true ) -{ - iterator_.array_ = state; -} - - -ValueIteratorBase::ValueIteratorBase( const ValueInternalMap::IteratorState &state ) - : isArray_( false ) -{ - iterator_.map_ = state; -} -#endif - -Value & -ValueIteratorBase::deref() const -{ -#ifndef JSON_VALUE_USE_INTERNAL_MAP - return current_->second; -#else - if ( isArray_ ) - return ValueInternalArray::dereference( iterator_.array_ ); - return ValueInternalMap::value( iterator_.map_ ); -#endif -} - - -void -ValueIteratorBase::increment() -{ -#ifndef JSON_VALUE_USE_INTERNAL_MAP - ++current_; -#else - if ( isArray_ ) - ValueInternalArray::increment( iterator_.array_ ); - ValueInternalMap::increment( iterator_.map_ ); -#endif -} - - -void -ValueIteratorBase::decrement() -{ -#ifndef JSON_VALUE_USE_INTERNAL_MAP - --current_; -#else - if ( isArray_ ) - ValueInternalArray::decrement( iterator_.array_ ); - ValueInternalMap::decrement( iterator_.map_ ); -#endif -} - - -ValueIteratorBase::difference_type -ValueIteratorBase::computeDistance( const SelfType &other ) const -{ -#ifndef JSON_VALUE_USE_INTERNAL_MAP -# ifdef JSON_USE_CPPTL_SMALLMAP - return current_ - other.current_; -# else - // Iterator for null value are initialized using the default - // constructor, which initialize current_ to the default - // std::map::iterator. As begin() and end() are two instance - // of the default std::map::iterator, they can not be compared. - // To allow this, we handle this comparison specifically. - if ( isNull_ && other.isNull_ ) - { - return 0; - } - - - // Usage of std::distance is not portable (does not compile with Sun Studio 12 RogueWave STL, - // which is the one used by default). - // Using a portable hand-made version for non random iterator instead: - // return difference_type( std::distance( current_, other.current_ ) ); - difference_type myDistance = 0; - for ( Value::ObjectValues::iterator it = current_; it != other.current_; ++it ) - { - ++myDistance; - } - return myDistance; -# endif -#else - if ( isArray_ ) - return ValueInternalArray::distance( iterator_.array_, other.iterator_.array_ ); - return ValueInternalMap::distance( iterator_.map_, other.iterator_.map_ ); -#endif -} - - -bool -ValueIteratorBase::isEqual( const SelfType &other ) const -{ -#ifndef JSON_VALUE_USE_INTERNAL_MAP - if ( isNull_ ) - { - return other.isNull_; - } - return current_ == other.current_; -#else - if ( isArray_ ) - return ValueInternalArray::equals( iterator_.array_, other.iterator_.array_ ); - return ValueInternalMap::equals( iterator_.map_, other.iterator_.map_ ); -#endif -} - - -void -ValueIteratorBase::copy( const SelfType &other ) -{ -#ifndef JSON_VALUE_USE_INTERNAL_MAP - current_ = other.current_; -#else - if ( isArray_ ) - iterator_.array_ = other.iterator_.array_; - iterator_.map_ = other.iterator_.map_; -#endif -} - - -Value -ValueIteratorBase::key() const -{ -#ifndef JSON_VALUE_USE_INTERNAL_MAP - const Value::CZString czstring = (*current_).first; - if ( czstring.c_str() ) - { - if ( czstring.isStaticString() ) - return Value( StaticString( czstring.c_str() ) ); - return Value( czstring.c_str() ); - } - return Value( czstring.index() ); -#else - if ( isArray_ ) - return Value( ValueInternalArray::indexOf( iterator_.array_ ) ); - bool isStatic; - const char *memberName = ValueInternalMap::key( iterator_.map_, isStatic ); - if ( isStatic ) - return Value( StaticString( memberName ) ); - return Value( memberName ); -#endif -} - - -UInt -ValueIteratorBase::index() const -{ -#ifndef JSON_VALUE_USE_INTERNAL_MAP - const Value::CZString czstring = (*current_).first; - if ( !czstring.c_str() ) - return czstring.index(); - return Value::UInt( -1 ); -#else - if ( isArray_ ) - return Value::UInt( ValueInternalArray::indexOf( iterator_.array_ ) ); - return Value::UInt( -1 ); -#endif -} - - -const char * -ValueIteratorBase::memberName() const -{ -#ifndef JSON_VALUE_USE_INTERNAL_MAP - const char *name = (*current_).first.c_str(); - return name ? name : ""; -#else - if ( !isArray_ ) - return ValueInternalMap::key( iterator_.map_ ); - return ""; -#endif -} - - -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// class ValueConstIterator -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// - -ValueConstIterator::ValueConstIterator() -{ -} - - -#ifndef JSON_VALUE_USE_INTERNAL_MAP -ValueConstIterator::ValueConstIterator( const Value::ObjectValues::iterator ¤t ) - : ValueIteratorBase( current ) -{ -} -#else -ValueConstIterator::ValueConstIterator( const ValueInternalArray::IteratorState &state ) - : ValueIteratorBase( state ) -{ -} - -ValueConstIterator::ValueConstIterator( const ValueInternalMap::IteratorState &state ) - : ValueIteratorBase( state ) -{ -} -#endif - -ValueConstIterator & -ValueConstIterator::operator =( const ValueIteratorBase &other ) -{ - copy( other ); - return *this; -} - - -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// class ValueIterator -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// - -ValueIterator::ValueIterator() -{ -} - - -#ifndef JSON_VALUE_USE_INTERNAL_MAP -ValueIterator::ValueIterator( const Value::ObjectValues::iterator ¤t ) - : ValueIteratorBase( current ) -{ -} -#else -ValueIterator::ValueIterator( const ValueInternalArray::IteratorState &state ) - : ValueIteratorBase( state ) -{ -} - -ValueIterator::ValueIterator( const ValueInternalMap::IteratorState &state ) - : ValueIteratorBase( state ) -{ -} -#endif - -ValueIterator::ValueIterator( const ValueConstIterator &other ) - : ValueIteratorBase( other ) -{ -} - -ValueIterator::ValueIterator( const ValueIterator &other ) - : ValueIteratorBase( other ) -{ -} - -ValueIterator & -ValueIterator::operator =( const SelfType &other ) -{ - copy( other ); - return *this; -} - -} // namespace Json - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: src/lib_json/json_valueiterator.inl -// ////////////////////////////////////////////////////////////////////// - - - - - - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: src/lib_json/json_value.cpp -// ////////////////////////////////////////////////////////////////////// - -// Copyright 2007-2010 Baptiste Lepilleur -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#if !defined(JSON_IS_AMALGAMATION) -# include -# include -# ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR -# include "json_batchallocator.h" -# endif // #ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR -#endif // if !defined(JSON_IS_AMALGAMATION) -#include -#include -#include -#include -#include -#ifdef JSON_USE_CPPTL -# include -#endif -#include // size_t - -#define JSON_ASSERT_UNREACHABLE assert( false ) -#define JSON_ASSERT( condition ) assert( condition ); // @todo <= change this into an exception throw -#define JSON_FAIL_MESSAGE( message ) throw std::runtime_error( message ); -#define JSON_ASSERT_MESSAGE( condition, message ) if (!( condition )) JSON_FAIL_MESSAGE( message ) - -namespace Json { - -const Value Value::null; -const Int Value::minInt = Int( ~(UInt(-1)/2) ); -const Int Value::maxInt = Int( UInt(-1)/2 ); -const UInt Value::maxUInt = UInt(-1); -const Int64 Value::minInt64 = Int64( ~(UInt64(-1)/2) ); -const Int64 Value::maxInt64 = Int64( UInt64(-1)/2 ); -const UInt64 Value::maxUInt64 = UInt64(-1); -const LargestInt Value::minLargestInt = LargestInt( ~(LargestUInt(-1)/2) ); -const LargestInt Value::maxLargestInt = LargestInt( LargestUInt(-1)/2 ); -const LargestUInt Value::maxLargestUInt = LargestUInt(-1); - - -/// Unknown size marker -static const unsigned int unknown = (unsigned)-1; - - -/** Duplicates the specified string value. - * @param value Pointer to the string to duplicate. Must be zero-terminated if - * length is "unknown". - * @param length Length of the value. if equals to unknown, then it will be - * computed using strlen(value). - * @return Pointer on the duplicate instance of string. - */ -static inline char * -duplicateStringValue( const char *value, - unsigned int length = unknown ) -{ - if ( length == unknown ) - length = (unsigned int)strlen(value); - char *newString = static_cast( malloc( length + 1 ) ); - JSON_ASSERT_MESSAGE( newString != 0, "Failed to allocate string value buffer" ); - memcpy( newString, value, length ); - newString[length] = 0; - return newString; -} - - -/** Free the string duplicated by duplicateStringValue(). - */ -static inline void -releaseStringValue( char *value ) -{ - if ( value ) - free( value ); -} - -} // namespace Json - - -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ValueInternals... -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -#if !defined(JSON_IS_AMALGAMATION) -# ifdef JSON_VALUE_USE_INTERNAL_MAP -# include "json_internalarray.inl" -# include "json_internalmap.inl" -# endif // JSON_VALUE_USE_INTERNAL_MAP - -# include "json_valueiterator.inl" -#endif // if !defined(JSON_IS_AMALGAMATION) - -namespace Json { - -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// class Value::CommentInfo -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// - - -Value::CommentInfo::CommentInfo() - : comment_( 0 ) -{ -} - -Value::CommentInfo::~CommentInfo() -{ - if ( comment_ ) - releaseStringValue( comment_ ); -} - - -void -Value::CommentInfo::setComment( const char *text ) -{ - if ( comment_ ) - releaseStringValue( comment_ ); - JSON_ASSERT( text != 0 ); - JSON_ASSERT_MESSAGE( text[0]=='\0' || text[0]=='/', "Comments must start with /"); - // It seems that /**/ style comments are acceptable as well. - comment_ = duplicateStringValue( text ); -} - - -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// class Value::CZString -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -# ifndef JSON_VALUE_USE_INTERNAL_MAP - -// Notes: index_ indicates if the string was allocated when -// a string is stored. - -Value::CZString::CZString( ArrayIndex index ) - : cstr_( 0 ) - , index_( index ) -{ -} - -Value::CZString::CZString( const char *cstr, DuplicationPolicy allocate ) - : cstr_( allocate == duplicate ? duplicateStringValue(cstr) - : cstr ) - , index_( allocate ) -{ -} - -Value::CZString::CZString( const CZString &other ) -: cstr_( other.index_ != noDuplication && other.cstr_ != 0 - ? duplicateStringValue( other.cstr_ ) - : other.cstr_ ) -{ - if(other.cstr_){ - if(other.index_ == noDuplication){ - index_ = noDuplication; - } - else{ - index_ = duplicate; - } - } - else{ - index_ = other.index_; - } -} - -Value::CZString::~CZString() -{ - if ( cstr_ && index_ == duplicate ) - releaseStringValue( const_cast( cstr_ ) ); -} - -void -Value::CZString::swap( CZString &other ) -{ - std::swap( cstr_, other.cstr_ ); - std::swap( index_, other.index_ ); -} - -Value::CZString & -Value::CZString::operator =( const CZString &other ) -{ - CZString temp( other ); - swap( temp ); - return *this; -} - -bool -Value::CZString::operator<( const CZString &other ) const -{ - if ( cstr_ ) - return strcmp( cstr_, other.cstr_ ) < 0; - return index_ < other.index_; -} - -bool -Value::CZString::operator==( const CZString &other ) const -{ - if ( cstr_ ) - return strcmp( cstr_, other.cstr_ ) == 0; - return index_ == other.index_; -} - - -ArrayIndex -Value::CZString::index() const -{ - return index_; -} - - -const char * -Value::CZString::c_str() const -{ - return cstr_; -} - -bool -Value::CZString::isStaticString() const -{ - return index_ == noDuplication; -} - -#endif // ifndef JSON_VALUE_USE_INTERNAL_MAP - - -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// class Value::Value -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// - -/*! \internal Default constructor initialization must be equivalent to: - * memset( this, 0, sizeof(Value) ) - * This optimization is used in ValueInternalMap fast allocator. - */ -Value::Value( ValueType type ) - : type_( type ) - , allocated_( 0 ) - , comments_( 0 ) -# ifdef JSON_VALUE_USE_INTERNAL_MAP - , itemIsUsed_( 0 ) -#endif -{ - switch ( type ) - { - case nullValue: - break; - case intValue: - case uintValue: - value_.int_ = 0; - break; - case realValue: - value_.real_ = 0.0; - break; - case stringValue: - value_.string_ = 0; - break; -#ifndef JSON_VALUE_USE_INTERNAL_MAP - case arrayValue: - case objectValue: - value_.map_ = new ObjectValues(); - break; -#else - case arrayValue: - value_.array_ = arrayAllocator()->newArray(); - break; - case objectValue: - value_.map_ = mapAllocator()->newMap(); - break; -#endif - case booleanValue: - value_.bool_ = false; - break; - default: - JSON_ASSERT_UNREACHABLE; - } -} - - -#if defined(JSON_HAS_INT64) -Value::Value( UInt value ) - : type_( uintValue ) - , comments_( 0 ) -# ifdef JSON_VALUE_USE_INTERNAL_MAP - , itemIsUsed_( 0 ) -#endif -{ - value_.uint_ = value; -} - -Value::Value( Int value ) - : type_( intValue ) - , comments_( 0 ) -# ifdef JSON_VALUE_USE_INTERNAL_MAP - , itemIsUsed_( 0 ) -#endif -{ - value_.int_ = value; -} - -#endif // if defined(JSON_HAS_INT64) - - -Value::Value( Int64 value ) - : type_( intValue ) - , comments_( 0 ) -# ifdef JSON_VALUE_USE_INTERNAL_MAP - , itemIsUsed_( 0 ) -#endif -{ - value_.int_ = value; -} - - -Value::Value( UInt64 value ) - : type_( uintValue ) - , comments_( 0 ) -# ifdef JSON_VALUE_USE_INTERNAL_MAP - , itemIsUsed_( 0 ) -#endif -{ - value_.uint_ = value; -} - -Value::Value( double value ) - : type_( realValue ) - , comments_( 0 ) -# ifdef JSON_VALUE_USE_INTERNAL_MAP - , itemIsUsed_( 0 ) -#endif -{ - value_.real_ = value; -} - -Value::Value( const char *value ) - : type_( stringValue ) - , allocated_( true ) - , comments_( 0 ) -# ifdef JSON_VALUE_USE_INTERNAL_MAP - , itemIsUsed_( 0 ) -#endif -{ - value_.string_ = duplicateStringValue( value ); -} - - -Value::Value( const char *beginValue, - const char *endValue ) - : type_( stringValue ) - , allocated_( true ) - , comments_( 0 ) -# ifdef JSON_VALUE_USE_INTERNAL_MAP - , itemIsUsed_( 0 ) -#endif -{ - value_.string_ = duplicateStringValue( beginValue, - (unsigned int)(endValue - beginValue) ); -} - - -Value::Value( const std::string &value ) - : type_( stringValue ) - , allocated_( true ) - , comments_( 0 ) -# ifdef JSON_VALUE_USE_INTERNAL_MAP - , itemIsUsed_( 0 ) -#endif -{ - value_.string_ = duplicateStringValue( value.c_str(), - (unsigned int)value.length() ); - -} - -Value::Value( const StaticString &value ) - : type_( stringValue ) - , allocated_( false ) - , comments_( 0 ) -# ifdef JSON_VALUE_USE_INTERNAL_MAP - , itemIsUsed_( 0 ) -#endif -{ - value_.string_ = const_cast( value.c_str() ); -} - - -# ifdef JSON_USE_CPPTL -Value::Value( const CppTL::ConstString &value ) - : type_( stringValue ) - , allocated_( true ) - , comments_( 0 ) -# ifdef JSON_VALUE_USE_INTERNAL_MAP - , itemIsUsed_( 0 ) -#endif -{ - value_.string_ = duplicateStringValue( value, value.length() ); -} -# endif - -Value::Value( bool value ) - : type_( booleanValue ) - , comments_( 0 ) -# ifdef JSON_VALUE_USE_INTERNAL_MAP - , itemIsUsed_( 0 ) -#endif -{ - value_.bool_ = value; -} - - -Value::Value( const Value &other ) - : type_( other.type_ ) - , comments_( 0 ) -# ifdef JSON_VALUE_USE_INTERNAL_MAP - , itemIsUsed_( 0 ) -#endif -{ - switch ( type_ ) - { - case nullValue: - case intValue: - case uintValue: - case realValue: - case booleanValue: - value_ = other.value_; - break; - case stringValue: - if ( other.value_.string_ ) - { - value_.string_ = duplicateStringValue( other.value_.string_ ); - allocated_ = true; - } - else - value_.string_ = 0; - break; -#ifndef JSON_VALUE_USE_INTERNAL_MAP - case arrayValue: - case objectValue: - value_.map_ = new ObjectValues( *other.value_.map_ ); - break; -#else - case arrayValue: - value_.array_ = arrayAllocator()->newArrayCopy( *other.value_.array_ ); - break; - case objectValue: - value_.map_ = mapAllocator()->newMapCopy( *other.value_.map_ ); - break; -#endif - default: - JSON_ASSERT_UNREACHABLE; - } - if ( other.comments_ ) - { - comments_ = new CommentInfo[numberOfCommentPlacement]; - for ( int comment =0; comment < numberOfCommentPlacement; ++comment ) - { - const CommentInfo &otherComment = other.comments_[comment]; - if ( otherComment.comment_ ) - comments_[comment].setComment( otherComment.comment_ ); - } - } -} - - -Value::~Value() -{ - switch ( type_ ) - { - case nullValue: - case intValue: - case uintValue: - case realValue: - case booleanValue: - break; - case stringValue: - if ( allocated_ ) - releaseStringValue( value_.string_ ); - break; -#ifndef JSON_VALUE_USE_INTERNAL_MAP - case arrayValue: - case objectValue: - delete value_.map_; - break; -#else - case arrayValue: - arrayAllocator()->destructArray( value_.array_ ); - break; - case objectValue: - mapAllocator()->destructMap( value_.map_ ); - break; -#endif - default: - JSON_ASSERT_UNREACHABLE; - } - - if ( comments_ ) - delete[] comments_; -} - -Value & -Value::operator=( const Value &other ) -{ - Value temp( other ); - swap( temp ); - return *this; -} - -void -Value::swap( Value &other ) -{ - ValueType temp = type_; - type_ = other.type_; - other.type_ = temp; - std::swap( value_, other.value_ ); - int temp2 = allocated_; - allocated_ = other.allocated_; - other.allocated_ = temp2; -} - -ValueType -Value::type() const -{ - return type_; -} - - -int -Value::compare( const Value &other ) const -{ - if ( *this < other ) - return -1; - if ( *this > other ) - return 1; - return 0; -} - - -bool -Value::operator <( const Value &other ) const -{ - int typeDelta = type_ - other.type_; - if ( typeDelta ) - return typeDelta < 0 ? true : false; - switch ( type_ ) - { - case nullValue: - return false; - case intValue: - return value_.int_ < other.value_.int_; - case uintValue: - return value_.uint_ < other.value_.uint_; - case realValue: - return value_.real_ < other.value_.real_; - case booleanValue: - return value_.bool_ < other.value_.bool_; - case stringValue: - return ( value_.string_ == 0 && other.value_.string_ ) - || ( other.value_.string_ - && value_.string_ - && strcmp( value_.string_, other.value_.string_ ) < 0 ); -#ifndef JSON_VALUE_USE_INTERNAL_MAP - case arrayValue: - case objectValue: - { - int delta = int( value_.map_->size() - other.value_.map_->size() ); - if ( delta ) - return delta < 0; - return (*value_.map_) < (*other.value_.map_); - } -#else - case arrayValue: - return value_.array_->compare( *(other.value_.array_) ) < 0; - case objectValue: - return value_.map_->compare( *(other.value_.map_) ) < 0; -#endif - default: - JSON_ASSERT_UNREACHABLE; - } - return false; // unreachable -} - -bool -Value::operator <=( const Value &other ) const -{ - return !(other < *this); -} - -bool -Value::operator >=( const Value &other ) const -{ - return !(*this < other); -} - -bool -Value::operator >( const Value &other ) const -{ - return other < *this; -} - -bool -Value::operator ==( const Value &other ) const -{ - //if ( type_ != other.type_ ) - // GCC 2.95.3 says: - // attempt to take address of bit-field structure member `Json::Value::type_' - // Beats me, but a temp solves the problem. - int temp = other.type_; - if ( type_ != temp ) - return false; - switch ( type_ ) - { - case nullValue: - return true; - case intValue: - return value_.int_ == other.value_.int_; - case uintValue: - return value_.uint_ == other.value_.uint_; - case realValue: - return value_.real_ == other.value_.real_; - case booleanValue: - return value_.bool_ == other.value_.bool_; - case stringValue: - return ( value_.string_ == other.value_.string_ ) - || ( other.value_.string_ - && value_.string_ - && strcmp( value_.string_, other.value_.string_ ) == 0 ); -#ifndef JSON_VALUE_USE_INTERNAL_MAP - case arrayValue: - case objectValue: - return value_.map_->size() == other.value_.map_->size() - && (*value_.map_) == (*other.value_.map_); -#else - case arrayValue: - return value_.array_->compare( *(other.value_.array_) ) == 0; - case objectValue: - return value_.map_->compare( *(other.value_.map_) ) == 0; -#endif - default: - JSON_ASSERT_UNREACHABLE; - } - return false; // unreachable -} - -bool -Value::operator !=( const Value &other ) const -{ - return !( *this == other ); -} - -const char * -Value::asCString() const -{ - JSON_ASSERT( type_ == stringValue ); - return value_.string_; -} - - -std::string -Value::asString() const -{ - switch ( type_ ) - { - case nullValue: - return ""; - case stringValue: - return value_.string_ ? value_.string_ : ""; - case booleanValue: - return value_.bool_ ? "true" : "false"; - case intValue: - case uintValue: - case realValue: - case arrayValue: - case objectValue: - JSON_FAIL_MESSAGE( "Type is not convertible to string" ); - default: - JSON_ASSERT_UNREACHABLE; - } - return ""; // unreachable -} - -# ifdef JSON_USE_CPPTL -CppTL::ConstString -Value::asConstString() const -{ - return CppTL::ConstString( asString().c_str() ); -} -# endif - - -Value::Int -Value::asInt() const -{ - switch ( type_ ) - { - case nullValue: - return 0; - case intValue: - JSON_ASSERT_MESSAGE( value_.int_ >= minInt && value_.int_ <= maxInt, "unsigned integer out of signed int range" ); - return Int(value_.int_); - case uintValue: - JSON_ASSERT_MESSAGE( value_.uint_ <= UInt(maxInt), "unsigned integer out of signed int range" ); - return Int(value_.uint_); - case realValue: - JSON_ASSERT_MESSAGE( value_.real_ >= minInt && value_.real_ <= maxInt, "Real out of signed integer range" ); - return Int( value_.real_ ); - case booleanValue: - return value_.bool_ ? 1 : 0; - case stringValue: - case arrayValue: - case objectValue: - JSON_FAIL_MESSAGE( "Type is not convertible to int" ); - default: - JSON_ASSERT_UNREACHABLE; - } - return 0; // unreachable; -} - - -Value::UInt -Value::asUInt() const -{ - switch ( type_ ) - { - case nullValue: - return 0; - case intValue: - JSON_ASSERT_MESSAGE( value_.int_ >= 0, "Negative integer can not be converted to unsigned integer" ); - JSON_ASSERT_MESSAGE( value_.int_ <= maxUInt, "signed integer out of UInt range" ); - return UInt(value_.int_); - case uintValue: - JSON_ASSERT_MESSAGE( value_.uint_ <= maxUInt, "unsigned integer out of UInt range" ); - return UInt(value_.uint_); - case realValue: - JSON_ASSERT_MESSAGE( value_.real_ >= 0 && value_.real_ <= maxUInt, "Real out of unsigned integer range" ); - return UInt( value_.real_ ); - case booleanValue: - return value_.bool_ ? 1 : 0; - case stringValue: - case arrayValue: - case objectValue: - JSON_FAIL_MESSAGE( "Type is not convertible to uint" ); - default: - JSON_ASSERT_UNREACHABLE; - } - return 0; // unreachable; -} - - -# if defined(JSON_HAS_INT64) - -Value::Int64 -Value::asInt64() const -{ - switch ( type_ ) - { - case nullValue: - return 0; - case intValue: - return value_.int_; - case uintValue: - JSON_ASSERT_MESSAGE( value_.uint_ <= UInt64(maxInt64), "unsigned integer out of Int64 range" ); - return value_.uint_; - case realValue: - JSON_ASSERT_MESSAGE( value_.real_ >= minInt64 && value_.real_ <= maxInt64, "Real out of Int64 range" ); - return Int( value_.real_ ); - case booleanValue: - return value_.bool_ ? 1 : 0; - case stringValue: - case arrayValue: - case objectValue: - JSON_FAIL_MESSAGE( "Type is not convertible to Int64" ); - default: - JSON_ASSERT_UNREACHABLE; - } - return 0; // unreachable; -} - - -Value::UInt64 -Value::asUInt64() const -{ - switch ( type_ ) - { - case nullValue: - return 0; - case intValue: - JSON_ASSERT_MESSAGE( value_.int_ >= 0, "Negative integer can not be converted to UInt64" ); - return value_.int_; - case uintValue: - return value_.uint_; - case realValue: - JSON_ASSERT_MESSAGE( value_.real_ >= 0 && value_.real_ <= maxUInt64, "Real out of UInt64 range" ); - return UInt( value_.real_ ); - case booleanValue: - return value_.bool_ ? 1 : 0; - case stringValue: - case arrayValue: - case objectValue: - JSON_FAIL_MESSAGE( "Type is not convertible to UInt64" ); - default: - JSON_ASSERT_UNREACHABLE; - } - return 0; // unreachable; -} -# endif // if defined(JSON_HAS_INT64) - - -LargestInt -Value::asLargestInt() const -{ -#if defined(JSON_NO_INT64) - return asInt(); -#else - return asInt64(); -#endif -} - - -LargestUInt -Value::asLargestUInt() const -{ -#if defined(JSON_NO_INT64) - return asUInt(); -#else - return asUInt64(); -#endif -} - - -double -Value::asDouble() const -{ - switch ( type_ ) - { - case nullValue: - return 0.0; - case intValue: - return static_cast( value_.int_ ); - case uintValue: -#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) - return static_cast( value_.uint_ ); -#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) - return static_cast( Int(value_.uint_/2) ) * 2 + Int(value_.uint_ & 1); -#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) - case realValue: - return value_.real_; - case booleanValue: - return value_.bool_ ? 1.0 : 0.0; - case stringValue: - case arrayValue: - case objectValue: - JSON_FAIL_MESSAGE( "Type is not convertible to double" ); - default: - JSON_ASSERT_UNREACHABLE; - } - return 0; // unreachable; -} - -float -Value::asFloat() const -{ - switch ( type_ ) - { - case nullValue: - return 0.0f; - case intValue: - return static_cast( value_.int_ ); - case uintValue: -#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) - return static_cast( value_.uint_ ); -#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) - return static_cast( Int(value_.uint_/2) ) * 2 + Int(value_.uint_ & 1); -#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) - case realValue: - return static_cast( value_.real_ ); - case booleanValue: - return value_.bool_ ? 1.0f : 0.0f; - case stringValue: - case arrayValue: - case objectValue: - JSON_FAIL_MESSAGE( "Type is not convertible to float" ); - default: - JSON_ASSERT_UNREACHABLE; - } - return 0.0f; // unreachable; -} - -bool -Value::asBool() const -{ - switch ( type_ ) - { - case nullValue: - return false; - case intValue: - case uintValue: - return value_.int_ != 0; - case realValue: - return value_.real_ != 0.0; - case booleanValue: - return value_.bool_; - case stringValue: - return value_.string_ && value_.string_[0] != 0; - case arrayValue: - case objectValue: - return value_.map_->size() != 0; - default: - JSON_ASSERT_UNREACHABLE; - } - return false; // unreachable; -} - - -bool -Value::isConvertibleTo( ValueType other ) const -{ - switch ( type_ ) - { - case nullValue: - return true; - case intValue: - return ( other == nullValue && value_.int_ == 0 ) - || other == intValue - || ( other == uintValue && value_.int_ >= 0 ) - || other == realValue - || other == stringValue - || other == booleanValue; - case uintValue: - return ( other == nullValue && value_.uint_ == 0 ) - || ( other == intValue && value_.uint_ <= (unsigned)maxInt ) - || other == uintValue - || other == realValue - || other == stringValue - || other == booleanValue; - case realValue: - return ( other == nullValue && value_.real_ == 0.0 ) - || ( other == intValue && value_.real_ >= minInt && value_.real_ <= maxInt ) - || ( other == uintValue && value_.real_ >= 0 && value_.real_ <= maxUInt ) - || other == realValue - || other == stringValue - || other == booleanValue; - case booleanValue: - return ( other == nullValue && value_.bool_ == false ) - || other == intValue - || other == uintValue - || other == realValue - || other == stringValue - || other == booleanValue; - case stringValue: - return other == stringValue - || ( other == nullValue && (!value_.string_ || value_.string_[0] == 0) ); - case arrayValue: - return other == arrayValue - || ( other == nullValue && value_.map_->size() == 0 ); - case objectValue: - return other == objectValue - || ( other == nullValue && value_.map_->size() == 0 ); - default: - JSON_ASSERT_UNREACHABLE; - } - return false; // unreachable; -} - - -/// Number of values in array or object -ArrayIndex -Value::size() const -{ - switch ( type_ ) - { - case nullValue: - case intValue: - case uintValue: - case realValue: - case booleanValue: - case stringValue: - return 0; -#ifndef JSON_VALUE_USE_INTERNAL_MAP - case arrayValue: // size of the array is highest index + 1 - if ( !value_.map_->empty() ) - { - ObjectValues::const_iterator itLast = value_.map_->end(); - --itLast; - return (*itLast).first.index()+1; - } - return 0; - case objectValue: - return ArrayIndex( value_.map_->size() ); -#else - case arrayValue: - return Int( value_.array_->size() ); - case objectValue: - return Int( value_.map_->size() ); -#endif - default: - JSON_ASSERT_UNREACHABLE; - } - return 0; // unreachable; -} - - -bool -Value::empty() const -{ - if ( isNull() || isArray() || isObject() ) - return size() == 0u; - else - return false; -} - - -bool -Value::operator!() const -{ - return isNull(); -} - - -void -Value::clear() -{ - JSON_ASSERT( type_ == nullValue || type_ == arrayValue || type_ == objectValue ); - - switch ( type_ ) - { -#ifndef JSON_VALUE_USE_INTERNAL_MAP - case arrayValue: - case objectValue: - value_.map_->clear(); - break; -#else - case arrayValue: - value_.array_->clear(); - break; - case objectValue: - value_.map_->clear(); - break; -#endif - default: - break; - } -} - -void -Value::resize( ArrayIndex newSize ) -{ - JSON_ASSERT( type_ == nullValue || type_ == arrayValue ); - if ( type_ == nullValue ) - *this = Value( arrayValue ); -#ifndef JSON_VALUE_USE_INTERNAL_MAP - ArrayIndex oldSize = size(); - if ( newSize == 0 ) - clear(); - else if ( newSize > oldSize ) - (*this)[ newSize - 1 ]; - else - { - for ( ArrayIndex index = newSize; index < oldSize; ++index ) - { - value_.map_->erase( index ); - } - assert( size() == newSize ); - } -#else - value_.array_->resize( newSize ); -#endif -} - - -Value & -Value::operator[]( ArrayIndex index ) -{ - JSON_ASSERT( type_ == nullValue || type_ == arrayValue ); - if ( type_ == nullValue ) - *this = Value( arrayValue ); -#ifndef JSON_VALUE_USE_INTERNAL_MAP - CZString key( index ); - ObjectValues::iterator it = value_.map_->lower_bound( key ); - if ( it != value_.map_->end() && (*it).first == key ) - return (*it).second; - - ObjectValues::value_type defaultValue( key, null ); - it = value_.map_->insert( it, defaultValue ); - return (*it).second; -#else - return value_.array_->resolveReference( index ); -#endif -} - - -Value & -Value::operator[]( int index ) -{ - JSON_ASSERT( index >= 0 ); - return (*this)[ ArrayIndex(index) ]; -} - - -const Value & -Value::operator[]( ArrayIndex index ) const -{ - JSON_ASSERT( type_ == nullValue || type_ == arrayValue ); - if ( type_ == nullValue ) - return null; -#ifndef JSON_VALUE_USE_INTERNAL_MAP - CZString key( index ); - ObjectValues::const_iterator it = value_.map_->find( key ); - if ( it == value_.map_->end() ) - return null; - return (*it).second; -#else - Value *value = value_.array_->find( index ); - return value ? *value : null; -#endif -} - - -const Value & -Value::operator[]( int index ) const -{ - JSON_ASSERT( index >= 0 ); - return (*this)[ ArrayIndex(index) ]; -} - - -Value & -Value::operator[]( const char *key ) -{ - return resolveReference( key, false ); -} - - -Value & -Value::resolveReference( const char *key, - bool isStatic ) -{ - JSON_ASSERT( type_ == nullValue || type_ == objectValue ); - if ( type_ == nullValue ) - *this = Value( objectValue ); -#ifndef JSON_VALUE_USE_INTERNAL_MAP - CZString actualKey( key, isStatic ? CZString::noDuplication - : CZString::duplicateOnCopy ); - ObjectValues::iterator it = value_.map_->lower_bound( actualKey ); - if ( it != value_.map_->end() && (*it).first == actualKey ) - return (*it).second; - - ObjectValues::value_type defaultValue( actualKey, null ); - it = value_.map_->insert( it, defaultValue ); - Value &value = (*it).second; - return value; -#else - return value_.map_->resolveReference( key, isStatic ); -#endif -} - - -Value -Value::get( ArrayIndex index, - const Value &defaultValue ) const -{ - const Value *value = &((*this)[index]); - return value == &null ? defaultValue : *value; -} - - -bool -Value::isValidIndex( ArrayIndex index ) const -{ - return index < size(); -} - - - -const Value & -Value::operator[]( const char *key ) const -{ - JSON_ASSERT( type_ == nullValue || type_ == objectValue ); - if ( type_ == nullValue ) - return null; -#ifndef JSON_VALUE_USE_INTERNAL_MAP - CZString actualKey( key, CZString::noDuplication ); - ObjectValues::const_iterator it = value_.map_->find( actualKey ); - if ( it == value_.map_->end() ) - return null; - return (*it).second; -#else - const Value *value = value_.map_->find( key ); - return value ? *value : null; -#endif -} - - -Value & -Value::operator[]( const std::string &key ) -{ - return (*this)[ key.c_str() ]; -} - - -const Value & -Value::operator[]( const std::string &key ) const -{ - return (*this)[ key.c_str() ]; -} - -Value & -Value::operator[]( const StaticString &key ) -{ - return resolveReference( key, true ); -} - - -# ifdef JSON_USE_CPPTL -Value & -Value::operator[]( const CppTL::ConstString &key ) -{ - return (*this)[ key.c_str() ]; -} - - -const Value & -Value::operator[]( const CppTL::ConstString &key ) const -{ - return (*this)[ key.c_str() ]; -} -# endif - - -Value & -Value::append( const Value &value ) -{ - return (*this)[size()] = value; -} - - -Value -Value::get( const char *key, - const Value &defaultValue ) const -{ - const Value *value = &((*this)[key]); - return value == &null ? defaultValue : *value; -} - - -Value -Value::get( const std::string &key, - const Value &defaultValue ) const -{ - return get( key.c_str(), defaultValue ); -} - -Value -Value::removeMember( const char* key ) -{ - JSON_ASSERT( type_ == nullValue || type_ == objectValue ); - if ( type_ == nullValue ) - return null; -#ifndef JSON_VALUE_USE_INTERNAL_MAP - CZString actualKey( key, CZString::noDuplication ); - ObjectValues::iterator it = value_.map_->find( actualKey ); - if ( it == value_.map_->end() ) - return null; - Value old(it->second); - value_.map_->erase(it); - return old; -#else - Value *value = value_.map_->find( key ); - if (value){ - Value old(*value); - value_.map_.remove( key ); - return old; - } else { - return null; - } -#endif -} - -Value -Value::removeMember( const std::string &key ) -{ - return removeMember( key.c_str() ); -} - -# ifdef JSON_USE_CPPTL -Value -Value::get( const CppTL::ConstString &key, - const Value &defaultValue ) const -{ - return get( key.c_str(), defaultValue ); -} -# endif - -bool -Value::isMember( const char *key ) const -{ - const Value *value = &((*this)[key]); - return value != &null; -} - - -bool -Value::isMember( const std::string &key ) const -{ - return isMember( key.c_str() ); -} - - -# ifdef JSON_USE_CPPTL -bool -Value::isMember( const CppTL::ConstString &key ) const -{ - return isMember( key.c_str() ); -} -#endif - -Value::Members -Value::getMemberNames() const -{ - JSON_ASSERT( type_ == nullValue || type_ == objectValue ); - if ( type_ == nullValue ) - return Value::Members(); - Members members; - members.reserve( value_.map_->size() ); -#ifndef JSON_VALUE_USE_INTERNAL_MAP - ObjectValues::const_iterator it = value_.map_->begin(); - ObjectValues::const_iterator itEnd = value_.map_->end(); - for ( ; it != itEnd; ++it ) - members.push_back( std::string( (*it).first.c_str() ) ); -#else - ValueInternalMap::IteratorState it; - ValueInternalMap::IteratorState itEnd; - value_.map_->makeBeginIterator( it ); - value_.map_->makeEndIterator( itEnd ); - for ( ; !ValueInternalMap::equals( it, itEnd ); ValueInternalMap::increment(it) ) - members.push_back( std::string( ValueInternalMap::key( it ) ) ); -#endif - return members; -} -// -//# ifdef JSON_USE_CPPTL -//EnumMemberNames -//Value::enumMemberNames() const -//{ -// if ( type_ == objectValue ) -// { -// return CppTL::Enum::any( CppTL::Enum::transform( -// CppTL::Enum::keys( *(value_.map_), CppTL::Type() ), -// MemberNamesTransform() ) ); -// } -// return EnumMemberNames(); -//} -// -// -//EnumValues -//Value::enumValues() const -//{ -// if ( type_ == objectValue || type_ == arrayValue ) -// return CppTL::Enum::anyValues( *(value_.map_), -// CppTL::Type() ); -// return EnumValues(); -//} -// -//# endif - - -bool -Value::isNull() const -{ - return type_ == nullValue; -} - - -bool -Value::isBool() const -{ - return type_ == booleanValue; -} - - -bool -Value::isInt() const -{ - return type_ == intValue; -} - - -bool -Value::isUInt() const -{ - return type_ == uintValue; -} - - -bool -Value::isIntegral() const -{ - return type_ == intValue - || type_ == uintValue - || type_ == booleanValue; -} - - -bool -Value::isDouble() const -{ - return type_ == realValue; -} - - -bool -Value::isNumeric() const -{ - return isIntegral() || isDouble(); -} - - -bool -Value::isString() const -{ - return type_ == stringValue; -} - - -bool -Value::isArray() const -{ - return type_ == nullValue || type_ == arrayValue; -} - - -bool -Value::isObject() const -{ - return type_ == nullValue || type_ == objectValue; -} - - -void -Value::setComment( const char *comment, - CommentPlacement placement ) -{ - if ( !comments_ ) - comments_ = new CommentInfo[numberOfCommentPlacement]; - comments_[placement].setComment( comment ); -} - - -void -Value::setComment( const std::string &comment, - CommentPlacement placement ) -{ - setComment( comment.c_str(), placement ); -} - - -bool -Value::hasComment( CommentPlacement placement ) const -{ - return comments_ != 0 && comments_[placement].comment_ != 0; -} - -std::string -Value::getComment( CommentPlacement placement ) const -{ - if ( hasComment(placement) ) - return comments_[placement].comment_; - return ""; -} - - -std::string -Value::toStyledString() const -{ - StyledWriter writer; - return writer.write( *this ); -} - - -Value::const_iterator -Value::begin() const -{ - switch ( type_ ) - { -#ifdef JSON_VALUE_USE_INTERNAL_MAP - case arrayValue: - if ( value_.array_ ) - { - ValueInternalArray::IteratorState it; - value_.array_->makeBeginIterator( it ); - return const_iterator( it ); - } - break; - case objectValue: - if ( value_.map_ ) - { - ValueInternalMap::IteratorState it; - value_.map_->makeBeginIterator( it ); - return const_iterator( it ); - } - break; -#else - case arrayValue: - case objectValue: - if ( value_.map_ ) - return const_iterator( value_.map_->begin() ); - break; -#endif - default: - break; - } - return const_iterator(); -} - -Value::const_iterator -Value::end() const -{ - switch ( type_ ) - { -#ifdef JSON_VALUE_USE_INTERNAL_MAP - case arrayValue: - if ( value_.array_ ) - { - ValueInternalArray::IteratorState it; - value_.array_->makeEndIterator( it ); - return const_iterator( it ); - } - break; - case objectValue: - if ( value_.map_ ) - { - ValueInternalMap::IteratorState it; - value_.map_->makeEndIterator( it ); - return const_iterator( it ); - } - break; -#else - case arrayValue: - case objectValue: - if ( value_.map_ ) - return const_iterator( value_.map_->end() ); - break; -#endif - default: - break; - } - return const_iterator(); -} - - -Value::iterator -Value::begin() -{ - switch ( type_ ) - { -#ifdef JSON_VALUE_USE_INTERNAL_MAP - case arrayValue: - if ( value_.array_ ) - { - ValueInternalArray::IteratorState it; - value_.array_->makeBeginIterator( it ); - return iterator( it ); - } - break; - case objectValue: - if ( value_.map_ ) - { - ValueInternalMap::IteratorState it; - value_.map_->makeBeginIterator( it ); - return iterator( it ); - } - break; -#else - case arrayValue: - case objectValue: - if ( value_.map_ ) - return iterator( value_.map_->begin() ); - break; -#endif - default: - break; - } - return iterator(); -} - -Value::iterator -Value::end() -{ - switch ( type_ ) - { -#ifdef JSON_VALUE_USE_INTERNAL_MAP - case arrayValue: - if ( value_.array_ ) - { - ValueInternalArray::IteratorState it; - value_.array_->makeEndIterator( it ); - return iterator( it ); - } - break; - case objectValue: - if ( value_.map_ ) - { - ValueInternalMap::IteratorState it; - value_.map_->makeEndIterator( it ); - return iterator( it ); - } - break; -#else - case arrayValue: - case objectValue: - if ( value_.map_ ) - return iterator( value_.map_->end() ); - break; -#endif - default: - break; - } - return iterator(); -} - - -// class PathArgument -// ////////////////////////////////////////////////////////////////// - -PathArgument::PathArgument() - : kind_( kindNone ) -{ -} - - -PathArgument::PathArgument( ArrayIndex index ) - : index_( index ) - , kind_( kindIndex ) -{ -} - - -PathArgument::PathArgument( const char *key ) - : key_( key ) - , kind_( kindKey ) -{ -} - - -PathArgument::PathArgument( const std::string &key ) - : key_( key.c_str() ) - , kind_( kindKey ) -{ -} - -// class Path -// ////////////////////////////////////////////////////////////////// - -Path::Path( const std::string &path, - const PathArgument &a1, - const PathArgument &a2, - const PathArgument &a3, - const PathArgument &a4, - const PathArgument &a5 ) -{ - InArgs in; - in.push_back( &a1 ); - in.push_back( &a2 ); - in.push_back( &a3 ); - in.push_back( &a4 ); - in.push_back( &a5 ); - makePath( path, in ); -} - - -void -Path::makePath( const std::string &path, - const InArgs &in ) -{ - const char *current = path.c_str(); - const char *end = current + path.length(); - InArgs::const_iterator itInArg = in.begin(); - while ( current != end ) - { - if ( *current == '[' ) - { - ++current; - if ( *current == '%' ) - addPathInArg( path, in, itInArg, PathArgument::kindIndex ); - else - { - ArrayIndex index = 0; - for ( ; current != end && *current >= '0' && *current <= '9'; ++current ) - index = index * 10 + ArrayIndex(*current - '0'); - args_.push_back( index ); - } - if ( current == end || *current++ != ']' ) - invalidPath( path, int(current - path.c_str()) ); - } - else if ( *current == '%' ) - { - addPathInArg( path, in, itInArg, PathArgument::kindKey ); - ++current; - } - else if ( *current == '.' ) - { - ++current; - } - else - { - const char *beginName = current; - while ( current != end && !strchr( "[.", *current ) ) - ++current; - args_.push_back( std::string( beginName, current ) ); - } - } -} - - -void -Path::addPathInArg( const std::string &path, - const InArgs &in, - InArgs::const_iterator &itInArg, - PathArgument::Kind kind ) -{ - if ( itInArg == in.end() ) - { - // Error: missing argument %d - } - else if ( (*itInArg)->kind_ != kind ) - { - // Error: bad argument type - } - else - { - args_.push_back( **itInArg ); - } -} - - -void -Path::invalidPath( const std::string &path, - int location ) -{ - // Error: invalid path. -} - - -const Value & -Path::resolve( const Value &root ) const -{ - const Value *node = &root; - for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it ) - { - const PathArgument &arg = *it; - if ( arg.kind_ == PathArgument::kindIndex ) - { - if ( !node->isArray() || node->isValidIndex( arg.index_ ) ) - { - // Error: unable to resolve path (array value expected at position... - } - node = &((*node)[arg.index_]); - } - else if ( arg.kind_ == PathArgument::kindKey ) - { - if ( !node->isObject() ) - { - // Error: unable to resolve path (object value expected at position...) - } - node = &((*node)[arg.key_]); - if ( node == &Value::null ) - { - // Error: unable to resolve path (object has no member named '' at position...) - } - } - } - return *node; -} - - -Value -Path::resolve( const Value &root, - const Value &defaultValue ) const -{ - const Value *node = &root; - for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it ) - { - const PathArgument &arg = *it; - if ( arg.kind_ == PathArgument::kindIndex ) - { - if ( !node->isArray() || node->isValidIndex( arg.index_ ) ) - return defaultValue; - node = &((*node)[arg.index_]); - } - else if ( arg.kind_ == PathArgument::kindKey ) - { - if ( !node->isObject() ) - return defaultValue; - node = &((*node)[arg.key_]); - if ( node == &Value::null ) - return defaultValue; - } - } - return *node; -} - - -Value & -Path::make( Value &root ) const -{ - Value *node = &root; - for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it ) - { - const PathArgument &arg = *it; - if ( arg.kind_ == PathArgument::kindIndex ) - { - if ( !node->isArray() ) - { - // Error: node is not an array at position ... - } - node = &((*node)[arg.index_]); - } - else if ( arg.kind_ == PathArgument::kindKey ) - { - if ( !node->isObject() ) - { - // Error: node is not an object at position... - } - node = &((*node)[arg.key_]); - } - } - return *node; -} - - -} // namespace Json - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: src/lib_json/json_value.cpp -// ////////////////////////////////////////////////////////////////////// - - - - - - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: src/lib_json/json_writer.cpp -// ////////////////////////////////////////////////////////////////////// - -// Copyright 2007-2010 Baptiste Lepilleur -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#if !defined(JSON_IS_AMALGAMATION) -# include -# include "json_tool.h" -#endif // if !defined(JSON_IS_AMALGAMATION) -#include -#include -#include -#include -#include -#include -#include - -#if _MSC_VER >= 1400 // VC++ 8.0 -#pragma warning( disable : 4996 ) // disable warning about strdup being deprecated. -#endif - -namespace Json { - -static bool containsControlCharacter( const char* str ) -{ - while ( *str ) - { - if ( isControlCharacter( *(str++) ) ) - return true; - } - return false; -} - - -std::string valueToString( LargestInt value ) -{ - UIntToStringBuffer buffer; - char *current = buffer + sizeof(buffer); - bool isNegative = value < 0; - if ( isNegative ) - value = -value; - uintToString( LargestUInt(value), current ); - if ( isNegative ) - *--current = '-'; - assert( current >= buffer ); - return current; -} - - -std::string valueToString( LargestUInt value ) -{ - UIntToStringBuffer buffer; - char *current = buffer + sizeof(buffer); - uintToString( value, current ); - assert( current >= buffer ); - return current; -} - -#if defined(JSON_HAS_INT64) - -std::string valueToString( Int value ) -{ - return valueToString( LargestInt(value) ); -} - - -std::string valueToString( UInt value ) -{ - return valueToString( LargestUInt(value) ); -} - -#endif // # if defined(JSON_HAS_INT64) - - -std::string valueToString( double value ) -{ - char buffer[32]; -#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) // Use secure version with visual studio 2005 to avoid warning. - sprintf_s(buffer, sizeof(buffer), "%#.16g", value); -#else - sprintf(buffer, "%#.16g", value); -#endif - char* ch = buffer + strlen(buffer) - 1; - if (*ch != '0') return buffer; // nothing to truncate, so save time - while(ch > buffer && *ch == '0'){ - --ch; - } - char* last_nonzero = ch; - while(ch >= buffer){ - switch(*ch){ - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - --ch; - continue; - case '.': - // Truncate zeroes to save bytes in output, but keep one. - *(last_nonzero+2) = '\0'; - return buffer; - default: - return buffer; - } - } - return buffer; -} - - -std::string valueToString( bool value ) -{ - return value ? "true" : "false"; -} - -std::string valueToQuotedString( const char *value ) -{ - // Not sure how to handle unicode... - if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL && !containsControlCharacter( value )) - return std::string("\"") + value + "\""; - // We have to walk value and escape any special characters. - // Appending to std::string is not efficient, but this should be rare. - // (Note: forward slashes are *not* rare, but I am not escaping them.) - std::string::size_type maxsize = strlen(value)*2 + 3; // allescaped+quotes+NULL - std::string result; - result.reserve(maxsize); // to avoid lots of mallocs - result += "\""; - for (const char* c=value; *c != 0; ++c) - { - switch(*c) - { - case '\"': - result += "\\\""; - break; - case '\\': - result += "\\\\"; - break; - case '\b': - result += "\\b"; - break; - case '\f': - result += "\\f"; - break; - case '\n': - result += "\\n"; - break; - case '\r': - result += "\\r"; - break; - case '\t': - result += "\\t"; - break; - //case '/': - // Even though \/ is considered a legal escape in JSON, a bare - // slash is also legal, so I see no reason to escape it. - // (I hope I am not misunderstanding something. - // blep notes: actually escaping \/ may be useful in javascript to avoid (*c); - result += oss.str(); - } - else - { - result += *c; - } - break; - } - } - result += "\""; - return result; -} - -// Class Writer -// ////////////////////////////////////////////////////////////////// -Writer::~Writer() -{ -} - - -// Class FastWriter -// ////////////////////////////////////////////////////////////////// - -FastWriter::FastWriter() - : yamlCompatiblityEnabled_( false ) -{ -} - - -void -FastWriter::enableYAMLCompatibility() -{ - yamlCompatiblityEnabled_ = true; -} - - -std::string -FastWriter::write( const Value &root ) -{ - document_ = ""; - writeValue( root ); - document_ += "\n"; - return document_; -} - - -void -FastWriter::writeValue( const Value &value ) -{ - switch ( value.type() ) - { - case nullValue: - document_ += "null"; - break; - case intValue: - document_ += valueToString( value.asLargestInt() ); - break; - case uintValue: - document_ += valueToString( value.asLargestUInt() ); - break; - case realValue: - document_ += valueToString( value.asDouble() ); - break; - case stringValue: - document_ += valueToQuotedString( value.asCString() ); - break; - case booleanValue: - document_ += valueToString( value.asBool() ); - break; - case arrayValue: - { - document_ += "["; - int size = value.size(); - for ( int index =0; index < size; ++index ) - { - if ( index > 0 ) - document_ += ","; - writeValue( value[index] ); - } - document_ += "]"; - } - break; - case objectValue: - { - Value::Members members( value.getMemberNames() ); - document_ += "{"; - for ( Value::Members::iterator it = members.begin(); - it != members.end(); - ++it ) - { - const std::string &name = *it; - if ( it != members.begin() ) - document_ += ","; - document_ += valueToQuotedString( name.c_str() ); - document_ += yamlCompatiblityEnabled_ ? ": " - : ":"; - writeValue( value[name] ); - } - document_ += "}"; - } - break; - } -} - - -// Class StyledWriter -// ////////////////////////////////////////////////////////////////// - -StyledWriter::StyledWriter() - : rightMargin_( 74 ) - , indentSize_( 3 ) -{ -} - - -std::string -StyledWriter::write( const Value &root ) -{ - document_ = ""; - addChildValues_ = false; - indentString_ = ""; - writeCommentBeforeValue( root ); - writeValue( root ); - writeCommentAfterValueOnSameLine( root ); - document_ += "\n"; - return document_; -} - - -void -StyledWriter::writeValue( const Value &value ) -{ - switch ( value.type() ) - { - case nullValue: - pushValue( "null" ); - break; - case intValue: - pushValue( valueToString( value.asLargestInt() ) ); - break; - case uintValue: - pushValue( valueToString( value.asLargestUInt() ) ); - break; - case realValue: - pushValue( valueToString( value.asDouble() ) ); - break; - case stringValue: - pushValue( valueToQuotedString( value.asCString() ) ); - break; - case booleanValue: - pushValue( valueToString( value.asBool() ) ); - break; - case arrayValue: - writeArrayValue( value); - break; - case objectValue: - { - Value::Members members( value.getMemberNames() ); - if ( members.empty() ) - pushValue( "{}" ); - else - { - writeWithIndent( "{" ); - indent(); - Value::Members::iterator it = members.begin(); - for (;;) - { - const std::string &name = *it; - const Value &childValue = value[name]; - writeCommentBeforeValue( childValue ); - writeWithIndent( valueToQuotedString( name.c_str() ) ); - document_ += " : "; - writeValue( childValue ); - if ( ++it == members.end() ) - { - writeCommentAfterValueOnSameLine( childValue ); - break; - } - document_ += ","; - writeCommentAfterValueOnSameLine( childValue ); - } - unindent(); - writeWithIndent( "}" ); - } - } - break; - } -} - - -void -StyledWriter::writeArrayValue( const Value &value ) -{ - unsigned size = value.size(); - if ( size == 0 ) - pushValue( "[]" ); - else - { - bool isArrayMultiLine = isMultineArray( value ); - if ( isArrayMultiLine ) - { - writeWithIndent( "[" ); - indent(); - bool hasChildValue = !childValues_.empty(); - unsigned index =0; - for (;;) - { - const Value &childValue = value[index]; - writeCommentBeforeValue( childValue ); - if ( hasChildValue ) - writeWithIndent( childValues_[index] ); - else - { - writeIndent(); - writeValue( childValue ); - } - if ( ++index == size ) - { - writeCommentAfterValueOnSameLine( childValue ); - break; - } - document_ += ","; - writeCommentAfterValueOnSameLine( childValue ); - } - unindent(); - writeWithIndent( "]" ); - } - else // output on a single line - { - assert( childValues_.size() == size ); - document_ += "[ "; - for ( unsigned index =0; index < size; ++index ) - { - if ( index > 0 ) - document_ += ", "; - document_ += childValues_[index]; - } - document_ += " ]"; - } - } -} - - -bool -StyledWriter::isMultineArray( const Value &value ) -{ - int size = value.size(); - bool isMultiLine = size*3 >= rightMargin_ ; - childValues_.clear(); - for ( int index =0; index < size && !isMultiLine; ++index ) - { - const Value &childValue = value[index]; - isMultiLine = isMultiLine || - ( (childValue.isArray() || childValue.isObject()) && - childValue.size() > 0 ); - } - if ( !isMultiLine ) // check if line length > max line length - { - childValues_.reserve( size ); - addChildValues_ = true; - int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]' - for ( int index =0; index < size && !isMultiLine; ++index ) - { - writeValue( value[index] ); - lineLength += int( childValues_[index].length() ); - isMultiLine = isMultiLine && hasCommentForValue( value[index] ); - } - addChildValues_ = false; - isMultiLine = isMultiLine || lineLength >= rightMargin_; - } - return isMultiLine; -} - - -void -StyledWriter::pushValue( const std::string &value ) -{ - if ( addChildValues_ ) - childValues_.push_back( value ); - else - document_ += value; -} - - -void -StyledWriter::writeIndent() -{ - if ( !document_.empty() ) - { - char last = document_[document_.length()-1]; - if ( last == ' ' ) // already indented - return; - if ( last != '\n' ) // Comments may add new-line - document_ += '\n'; - } - document_ += indentString_; -} - - -void -StyledWriter::writeWithIndent( const std::string &value ) -{ - writeIndent(); - document_ += value; -} - - -void -StyledWriter::indent() -{ - indentString_ += std::string( indentSize_, ' ' ); -} - - -void -StyledWriter::unindent() -{ - assert( int(indentString_.size()) >= indentSize_ ); - indentString_.resize( indentString_.size() - indentSize_ ); -} - - -void -StyledWriter::writeCommentBeforeValue( const Value &root ) -{ - if ( !root.hasComment( commentBefore ) ) - return; - document_ += normalizeEOL( root.getComment( commentBefore ) ); - document_ += "\n"; -} - - -void -StyledWriter::writeCommentAfterValueOnSameLine( const Value &root ) -{ - if ( root.hasComment( commentAfterOnSameLine ) ) - document_ += " " + normalizeEOL( root.getComment( commentAfterOnSameLine ) ); - - if ( root.hasComment( commentAfter ) ) - { - document_ += "\n"; - document_ += normalizeEOL( root.getComment( commentAfter ) ); - document_ += "\n"; - } -} - - -bool -StyledWriter::hasCommentForValue( const Value &value ) -{ - return value.hasComment( commentBefore ) - || value.hasComment( commentAfterOnSameLine ) - || value.hasComment( commentAfter ); -} - - -std::string -StyledWriter::normalizeEOL( const std::string &text ) -{ - std::string normalized; - normalized.reserve( text.length() ); - const char *begin = text.c_str(); - const char *end = begin + text.length(); - const char *current = begin; - while ( current != end ) - { - char c = *current++; - if ( c == '\r' ) // mac or dos EOL - { - if ( *current == '\n' ) // convert dos EOL - ++current; - normalized += '\n'; - } - else // handle unix EOL & other char - normalized += c; - } - return normalized; -} - - -// Class StyledStreamWriter -// ////////////////////////////////////////////////////////////////// - -StyledStreamWriter::StyledStreamWriter( std::string indentation ) - : document_(NULL) - , rightMargin_( 74 ) - , indentation_( indentation ) -{ -} - - -void -StyledStreamWriter::write( std::ostream &out, const Value &root ) -{ - document_ = &out; - addChildValues_ = false; - indentString_ = ""; - writeCommentBeforeValue( root ); - writeValue( root ); - writeCommentAfterValueOnSameLine( root ); - *document_ << "\n"; - document_ = NULL; // Forget the stream, for safety. -} - - -void -StyledStreamWriter::writeValue( const Value &value ) -{ - switch ( value.type() ) - { - case nullValue: - pushValue( "null" ); - break; - case intValue: - pushValue( valueToString( value.asLargestInt() ) ); - break; - case uintValue: - pushValue( valueToString( value.asLargestUInt() ) ); - break; - case realValue: - pushValue( valueToString( value.asDouble() ) ); - break; - case stringValue: - pushValue( valueToQuotedString( value.asCString() ) ); - break; - case booleanValue: - pushValue( valueToString( value.asBool() ) ); - break; - case arrayValue: - writeArrayValue( value); - break; - case objectValue: - { - Value::Members members( value.getMemberNames() ); - if ( members.empty() ) - pushValue( "{}" ); - else - { - writeWithIndent( "{" ); - indent(); - Value::Members::iterator it = members.begin(); - for (;;) - { - const std::string &name = *it; - const Value &childValue = value[name]; - writeCommentBeforeValue( childValue ); - writeWithIndent( valueToQuotedString( name.c_str() ) ); - *document_ << " : "; - writeValue( childValue ); - if ( ++it == members.end() ) - { - writeCommentAfterValueOnSameLine( childValue ); - break; - } - *document_ << ","; - writeCommentAfterValueOnSameLine( childValue ); - } - unindent(); - writeWithIndent( "}" ); - } - } - break; - } -} - - -void -StyledStreamWriter::writeArrayValue( const Value &value ) -{ - unsigned size = value.size(); - if ( size == 0 ) - pushValue( "[]" ); - else - { - bool isArrayMultiLine = isMultineArray( value ); - if ( isArrayMultiLine ) - { - writeWithIndent( "[" ); - indent(); - bool hasChildValue = !childValues_.empty(); - unsigned index =0; - for (;;) - { - const Value &childValue = value[index]; - writeCommentBeforeValue( childValue ); - if ( hasChildValue ) - writeWithIndent( childValues_[index] ); - else - { - writeIndent(); - writeValue( childValue ); - } - if ( ++index == size ) - { - writeCommentAfterValueOnSameLine( childValue ); - break; - } - *document_ << ","; - writeCommentAfterValueOnSameLine( childValue ); - } - unindent(); - writeWithIndent( "]" ); - } - else // output on a single line - { - assert( childValues_.size() == size ); - *document_ << "[ "; - for ( unsigned index =0; index < size; ++index ) - { - if ( index > 0 ) - *document_ << ", "; - *document_ << childValues_[index]; - } - *document_ << " ]"; - } - } -} - - -bool -StyledStreamWriter::isMultineArray( const Value &value ) -{ - int size = value.size(); - bool isMultiLine = size*3 >= rightMargin_ ; - childValues_.clear(); - for ( int index =0; index < size && !isMultiLine; ++index ) - { - const Value &childValue = value[index]; - isMultiLine = isMultiLine || - ( (childValue.isArray() || childValue.isObject()) && - childValue.size() > 0 ); - } - if ( !isMultiLine ) // check if line length > max line length - { - childValues_.reserve( size ); - addChildValues_ = true; - int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]' - for ( int index =0; index < size && !isMultiLine; ++index ) - { - writeValue( value[index] ); - lineLength += int( childValues_[index].length() ); - isMultiLine = isMultiLine && hasCommentForValue( value[index] ); - } - addChildValues_ = false; - isMultiLine = isMultiLine || lineLength >= rightMargin_; - } - return isMultiLine; -} - - -void -StyledStreamWriter::pushValue( const std::string &value ) -{ - if ( addChildValues_ ) - childValues_.push_back( value ); - else - *document_ << value; -} - - -void -StyledStreamWriter::writeIndent() -{ - /* - Some comments in this method would have been nice. ;-) - - if ( !document_.empty() ) - { - char last = document_[document_.length()-1]; - if ( last == ' ' ) // already indented - return; - if ( last != '\n' ) // Comments may add new-line - *document_ << '\n'; - } - */ - *document_ << '\n' << indentString_; -} - - -void -StyledStreamWriter::writeWithIndent( const std::string &value ) -{ - writeIndent(); - *document_ << value; -} - - -void -StyledStreamWriter::indent() -{ - indentString_ += indentation_; -} - - -void -StyledStreamWriter::unindent() -{ - assert( indentString_.size() >= indentation_.size() ); - indentString_.resize( indentString_.size() - indentation_.size() ); -} - - -void -StyledStreamWriter::writeCommentBeforeValue( const Value &root ) -{ - if ( !root.hasComment( commentBefore ) ) - return; - *document_ << normalizeEOL( root.getComment( commentBefore ) ); - *document_ << "\n"; -} - - -void -StyledStreamWriter::writeCommentAfterValueOnSameLine( const Value &root ) -{ - if ( root.hasComment( commentAfterOnSameLine ) ) - *document_ << " " + normalizeEOL( root.getComment( commentAfterOnSameLine ) ); - - if ( root.hasComment( commentAfter ) ) - { - *document_ << "\n"; - *document_ << normalizeEOL( root.getComment( commentAfter ) ); - *document_ << "\n"; - } -} - - -bool -StyledStreamWriter::hasCommentForValue( const Value &value ) -{ - return value.hasComment( commentBefore ) - || value.hasComment( commentAfterOnSameLine ) - || value.hasComment( commentAfter ); -} - - -std::string -StyledStreamWriter::normalizeEOL( const std::string &text ) -{ - std::string normalized; - normalized.reserve( text.length() ); - const char *begin = text.c_str(); - const char *end = begin + text.length(); - const char *current = begin; - while ( current != end ) - { - char c = *current++; - if ( c == '\r' ) // mac or dos EOL - { - if ( *current == '\n' ) // convert dos EOL - ++current; - normalized += '\n'; - } - else // handle unix EOL & other char - normalized += c; - } - return normalized; -} - - -std::ostream& operator<<( std::ostream &sout, const Value &root ) -{ - Json::StyledStreamWriter writer; - writer.write(sout, root); - return sout; -} - - -} // namespace Json - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: src/lib_json/json_writer.cpp -// ////////////////////////////////////////////////////////////////////// From f00e30e77e9ce478f11dd9924c446b71cc62cc1e Mon Sep 17 00:00:00 2001 From: Jonathan Fine Date: Mon, 27 Aug 2018 19:43:36 -0400 Subject: [PATCH 46/68] Initial MMTF support Signed-off-by: Jonathan Fine --- avogadro/core/molecule.cpp | 2 +- avogadro/core/molecule.h | 2 +- avogadro/io/CMakeLists.txt | 7 ++ avogadro/io/fileformatmanager.cpp | 2 + avogadro/io/mmtfformat.cpp | 202 ++++++++++++++++++++++++++++++ avogadro/io/mmtfformat.h | 68 ++++++++++ cmake/FindMMTF.cmake | 15 +++ tests/io/CMakeLists.txt | 1 + tests/io/mmtftest.cpp | 138 ++++++++++++++++++++ 9 files changed, 435 insertions(+), 2 deletions(-) create mode 100644 avogadro/io/mmtfformat.cpp create mode 100644 avogadro/io/mmtfformat.h create mode 100644 cmake/FindMMTF.cmake create mode 100644 tests/io/mmtftest.cpp diff --git a/avogadro/core/molecule.cpp b/avogadro/core/molecule.cpp index 1a87b19aa5..25858cc7be 100644 --- a/avogadro/core/molecule.cpp +++ b/avogadro/core/molecule.cpp @@ -823,7 +823,7 @@ void Molecule::addResidue(Residue& residue) m_residues.push_back(residue); } -Residue Molecule::residue(int index) +Residue& Molecule::residue(int index) { return m_residues[index]; } diff --git a/avogadro/core/molecule.h b/avogadro/core/molecule.h index 5a00722f89..fbd28ccb02 100644 --- a/avogadro/core/molecule.h +++ b/avogadro/core/molecule.h @@ -550,7 +550,7 @@ class AVOGADROCORE_EXPORT Molecule Residue& addResidue(std::string& name, Index& number, char& id); void addResidue(Residue& residue); - Residue residue(int index); + Residue& residue(int index); protected: mutable Graph m_graph; // A transformation of the molecule to a graph. diff --git a/avogadro/io/CMakeLists.txt b/avogadro/io/CMakeLists.txt index b683c5d439..bed99b83be 100644 --- a/avogadro/io/CMakeLists.txt +++ b/avogadro/io/CMakeLists.txt @@ -1,4 +1,5 @@ find_package(Eigen3 REQUIRED) +find_package(MMTF REQUIRED) if(USE_HDF5) find_package(HDF5 REQUIRED COMPONENTS C) @@ -14,6 +15,7 @@ endif() # Add as "system headers" to avoid warnings generated by them with # compilers that support that notion. include_directories(SYSTEM "${EIGEN3_INCLUDE_DIR}" + "${MMTF_INCLUDE_DIRS}" "${AvogadroLibs_SOURCE_DIR}/thirdparty/pugixml" "${AvogadroLibs_SOURCE_DIR}/thirdparty/struct" "${AvogadroLibs_SOURCE_DIR}/thirdparty") @@ -36,6 +38,7 @@ set(HEADERS xyzformat.h trrformat.h lammpsformat.h + mmtfformat.h ) set(SOURCES @@ -51,6 +54,7 @@ set(SOURCES xyzformat.cpp trrformat.cpp lammpsformat.cpp + mmtfformat.cpp ) if(USE_HDF5) @@ -66,3 +70,6 @@ target_link_libraries(AvogadroIO if(USE_HDF5) target_link_libraries(AvogadroIO LINK_PRIVATE ${HDF5_LIBRARIES}) endif() +if(WIN32) + target_link_libraries(AvogadroIO LINK_PRIVATE ws2_32) +endif() diff --git a/avogadro/io/fileformatmanager.cpp b/avogadro/io/fileformatmanager.cpp index a13cb66492..af5c300f59 100644 --- a/avogadro/io/fileformatmanager.cpp +++ b/avogadro/io/fileformatmanager.cpp @@ -24,6 +24,7 @@ #include "gromacsformat.h" #include "lammpsformat.h" #include "mdlformat.h" +#include "mmtfformat.h" #include "pdbformat.h" #include "trrformat.h" #include "vaspformat.h" @@ -300,6 +301,7 @@ FileFormatManager::FileFormatManager() addFormat(new DcdFormat); addFormat(new LammpsTrajectoryFormat); addFormat(new LammpsDataFormat); + addFormat(new MMTFFormat); } FileFormatManager::~FileFormatManager() diff --git a/avogadro/io/mmtfformat.cpp b/avogadro/io/mmtfformat.cpp new file mode 100644 index 0000000000..c2f51e2e9f --- /dev/null +++ b/avogadro/io/mmtfformat.cpp @@ -0,0 +1,202 @@ +/****************************************************************************** + + This source file is part of the Avogadro project. + + Copyright 2012 Kitware, Inc. + + This source code is released under the New BSD License, (the "License"). + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +******************************************************************************/ + +#include "mmtfformat.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +namespace Avogadro { +namespace Io { + +using std::string; +using std::vector; + +using Core::Array; +using Core::Atom; +using Core::BasisSet; +using Core::Bond; +using Core::CrystalTools; +using Core::Cube; +using Core::Elements; +using Core::GaussianSet; +using Core::lexicalCast; +using Core::Molecule; +using Core::Residue; +using Core::split; +using Core::Variant; + +MMTFFormat::MMTFFormat() = default; + +MMTFFormat::~MMTFFormat() = default; + +bool MMTFFormat::read(std::istream& file, Molecule& molecule) +{ + mmtf::StructureData structure; + mmtf::decodeFromStream(structure, file); + + // This controls which model we load, currently just the first? + size_t modelIndex = 0; + size_t atomSkip = 0; + + size_t chainIndex = 0; + size_t groupIndex = 0; + size_t atomIndex = 0; + + molecule.setData("name", structure.title); + + if (structure.unitCell.size() == 6) { + Real a = static_cast(structure.unitCell[0]); + Real b = static_cast(structure.unitCell[1]); + Real c = static_cast(structure.unitCell[2]); + Real alpha = static_cast(structure.unitCell[3]) * DEG_TO_RAD; + Real beta = static_cast(structure.unitCell[4]) * DEG_TO_RAD; + Real gamma = static_cast(structure.unitCell[5]) * DEG_TO_RAD; + + Core::UnitCell* unitCellObject = + new Core::UnitCell(a, b, c, alpha, beta, gamma); + molecule.setUnitCell(unitCellObject); + } + + Index modelChainCount = + static_cast(structure.chainsPerModel[modelIndex]); + + for (Index j = 0; j < modelChainCount; j++) { + + Index chainGroupCount = + static_cast(structure.groupsPerChain[chainIndex]); + + bool ok; + std::string chainid_string = structure.chainIdList[chainIndex]; + char chainid = lexicalCast(chainid_string.substr(0, 1), ok); + + // A group is like a residue or other molecule in a PDB file. + for (size_t k = 0; k < chainGroupCount; k++) { + + Index groupType = static_cast(structure.groupTypeList[groupIndex]); + + const auto& group = structure.groupList[groupType]; + + Index groupId = static_cast(structure.groupIdList[groupIndex]); + auto resname = group.groupName; + + auto& residue = molecule.addResidue(resname, groupId, chainid); + + // Save the offset before we go changing it + Index atomOffset = atomIndex - atomSkip; + Index groupSize = group.atomNameList.size(); + + for (Index l = 0; l < groupSize; l++) { + + auto atom = molecule.addAtom( + Elements::atomicNumberFromSymbol(group.elementList[l])); + // Not supported by Avogadro? + // const auto& altLocList = structure.altLocList; + + atom.setFormalCharge(group.formalChargeList[l]); + atom.setPosition3d( + Vector3(static_cast(structure.xCoordList[atomIndex]), + static_cast(structure.yCoordList[atomIndex]), + static_cast(structure.zCoordList[atomIndex]))); + + // Stores if the compounds is a heteroatom + // mmtf::is_hetatm(group.chemCompType.c_str()); + std::string atomName = group.atomNameList[l]; + residue.addResidueAtom(atomName, atom); + atomIndex++; + } + + // Intra-resiude bonds + for (size_t l = 0; l < group.bondOrderList.size(); l++) { + + auto atom1 = static_cast(group.bondAtomList[l * 2]); + auto atom2 = static_cast(group.bondAtomList[l * 2 + 1]); + + char bo = static_cast(group.bondOrderList[l]); + + molecule.addBond(atomOffset + atom1, atomOffset + atom2, bo); + } + + // This is the origianl PDB Chain name + // if (!structure_.chainNameList.empty()) { + // structure.chainNameList[chainIndex_]; + //} + + groupIndex++; + } + + chainIndex++; + } + + // Use this eventually for multi-model formats + modelIndex++; + + // These are for inter-residue bonds + for (size_t i = 0; i < structure.bondAtomList.size() / 2; i++) { + + auto atom1 = static_cast(structure.bondAtomList[i * 2]); + auto atom2 = static_cast(structure.bondAtomList[i * 2 + 1]); + + /* Code for multiple models + // We are below the atoms we care about + if (atom1 < atomSkip || atom2 < atomSkip) { + continue; + } + + // We are above the atoms we care about + if (atom1 > atomIndex || atom2 > atomIndex) { + continue; + } */ + + size_t atom_idx1 = atom1 - atomSkip; // atomSkip = 0 for us (1 model) + size_t atom_idx2 = atom2 - atomSkip; + molecule.addBond(atom_idx1, atom_idx2, 1); // Always a single bond + } + + return true; +} + +bool MMTFFormat::write(std::ostream& out, const Core::Molecule& molecule) +{ + return false; +} + +vector MMTFFormat::fileExtensions() const +{ + vector ext; + ext.push_back("mmtf"); + return ext; +} + +vector MMTFFormat::mimeTypes() const +{ + vector mime; + mime.push_back("chemical/x-mmtf"); + return mime; +} + +} // namespace Io +} // namespace Avogadro diff --git a/avogadro/io/mmtfformat.h b/avogadro/io/mmtfformat.h new file mode 100644 index 0000000000..e7f31957b1 --- /dev/null +++ b/avogadro/io/mmtfformat.h @@ -0,0 +1,68 @@ +/****************************************************************************** + + This source file is part of the Avogadro project. + + Copyright 2012 Kitware, Inc. + + This source code is released under the New BSD License, (the "License"). + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +******************************************************************************/ + +#ifndef AVOGADRO_IO_MMTFFORMAT_H +#define AVOGADRO_IO_MMTFFORMAT_H + +#include "fileformat.h" + +namespace Avogadro { +namespace Core { +class GaussianSet; +} +namespace Io { + +/** + * @class MMTFFormat mmtf.h + * @brief Implementation of the MMTF format. + */ + +class AVOGADROIO_EXPORT MMTFFormat : public FileFormat +{ +public: + MMTFFormat(); + ~MMTFFormat() override; + + Operations supportedOperations() const override + { + return Read | File | Stream | String; + } + + FileFormat* newInstance() const override { return new MMTFFormat; } + std::string identifier() const override { return "Avogadro: MMTF"; } + std::string name() const override { return "MacroMolecular Transmission Format"; } + std::string description() const override + { + return "MMTF is a format used to express MacroMolecular data in a compressed " + "binary format."; + } + + std::string specificationUrl() const override + { + return "http://mmtf.rcsb.org/"; + } + + std::vector fileExtensions() const override; + std::vector mimeTypes() const override; + + bool read(std::istream& in, Core::Molecule& molecule) override; + bool write(std::ostream& out, const Core::Molecule& molecule) override; +}; + +} // end Io namespace +} // end Avogadro namespace + +#endif // AVOGADRO_IO_MMTFFORMAT_H diff --git a/cmake/FindMMTF.cmake b/cmake/FindMMTF.cmake new file mode 100644 index 0000000000..71030e6793 --- /dev/null +++ b/cmake/FindMMTF.cmake @@ -0,0 +1,15 @@ +# Find the MMTF library +# +# Defines: +# +# MMTF_FOUND - system has MMTF +# MMTF_INCLUDE_DIRS - the MMTF include directories +# +find_path(MMTF_INCLUDE_DIR mmtf.hpp) + +set(MMTF_INCLUDE_DIRS "${MMTF_INCLUDE_DIR}") + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(MMTF DEFAULT_MSG MMTF_INCLUDE_DIR) + +mark_as_advanced(MMTF_INCLUDE_DIR) diff --git a/tests/io/CMakeLists.txt b/tests/io/CMakeLists.txt index 1f7394df84..2ca57cbecf 100644 --- a/tests/io/CMakeLists.txt +++ b/tests/io/CMakeLists.txt @@ -7,6 +7,7 @@ set(tests Mdl Vasp Xyz + MMTF ) if(USE_HDF5) diff --git a/tests/io/mmtftest.cpp b/tests/io/mmtftest.cpp new file mode 100644 index 0000000000..384e87355e --- /dev/null +++ b/tests/io/mmtftest.cpp @@ -0,0 +1,138 @@ +/****************************************************************************** + + This source file is part of the Avogadro project. + + Copyright 2012 Kitware, Inc. + + This source code is released under the New BSD License, (the "License"). + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +******************************************************************************/ + +#include "iotests.h" + +#include + +#include +#include +#include +#include +#include + +#include + +using Avogadro::DEG_TO_RAD; +using Avogadro::MatrixX; +using Avogadro::Real; +using Avogadro::Vector3; +using Avogadro::Core::Atom; +using Avogadro::Core::Bond; +using Avogadro::Core::Molecule; +using Avogadro::Core::Residue; +using Avogadro::Core::Variant; +using Avogadro::Io::MMTFFormat; + +TEST(MMTFTest, readFile) +{ + MMTFFormat mmtf; + Molecule molecule; + mmtf.readFile(std::string(AVOGADRO_DATA) + "/data/4HHB.mmtf", molecule); + + EXPECT_EQ(molecule.data("name").type(), Variant::String); + EXPECT_EQ(molecule.data("name").toString(), + "THE CRYSTAL STRUCTURE OF HUMAN DEOXYHAEMOGLOBIN AT 1.74 ANGSTROMS " + "RESOLUTION"); +} + +TEST(MMTFTEST, unitCell) +{ + MMTFFormat mmtf; + Molecule molecule; + mmtf.readFile(std::string(AVOGADRO_DATA) + "/data/4HHB.mmtf", molecule); + + auto cell = molecule.unitCell(); + + EXPECT_NEAR(cell->a(), 63.150, 1e-3); + EXPECT_NEAR(cell->b(), 83.590, 1e-3); + EXPECT_NEAR(cell->c(), 53.800, 1e-3); + EXPECT_NEAR(cell->alpha(), 90.00 * DEG_TO_RAD, 1e-3); + EXPECT_NEAR(cell->beta(), 99.34 * DEG_TO_RAD, 1e-3); + EXPECT_NEAR(cell->gamma(), 90.00 * DEG_TO_RAD, 1e-3); +} + +TEST(MMTFTest, atoms) +{ + MMTFFormat mmtf; + Molecule molecule; + mmtf.readFile(std::string(AVOGADRO_DATA) + "/data/4HHB.mmtf", molecule); + + EXPECT_EQ(molecule.atomCount(), static_cast(4779)); + Atom atom = molecule.atom(0); + EXPECT_EQ(atom.atomicNumber(), static_cast(7)); + EXPECT_NEAR(atom.position3d().x(), 6.204, 1e-3); + EXPECT_NEAR(atom.position3d().y(), 16.869, 1e-3); + EXPECT_NEAR(atom.position3d().z(), 4.854, 1e-3); + + // Random alpha carbon + atom = molecule.atom(296); + EXPECT_EQ(atom.atomicNumber(), static_cast(6)); + EXPECT_NEAR(atom.position3d().x(), 10.167, 1e-3); + EXPECT_NEAR(atom.position3d().y(), -7.889, 1e-3); + EXPECT_NEAR(atom.position3d().z(), -16.138, 1e-3); + + // Final water + atom = molecule.atom(4778); + EXPECT_EQ(atom.atomicNumber(), static_cast(8)); + EXPECT_NEAR(atom.position3d().x(), -1.263, 1e-3); + EXPECT_NEAR(atom.position3d().y(), -2.837, 1e-3); + EXPECT_NEAR(atom.position3d().z(), -21.251, 1e-3); +} + +TEST(MMTFTest, bonds) +{ + MMTFFormat mmtf; + Molecule molecule; + mmtf.readFile(std::string(AVOGADRO_DATA) + "/data/4HHB.mmtf", molecule); + + EXPECT_EQ(molecule.bondCount(), static_cast(4700)); + + // First nitrogen to alpha carbon + Bond bond = molecule.bond(0); + EXPECT_EQ(bond.atom1().index(), static_cast(0)); + EXPECT_EQ(bond.atom2().index(), static_cast(1)); + EXPECT_EQ(bond.order(), static_cast(1)); + + bond = molecule.bond(6); + EXPECT_EQ(bond.atom1().index(), static_cast(7)); + EXPECT_EQ(bond.atom2().index(), static_cast(8)); + EXPECT_EQ(bond.order(), static_cast(1)); +} + +TEST(MMTFTest, residues) +{ + MMTFFormat mmtf; + Molecule molecule; + mmtf.readFile(std::string(AVOGADRO_DATA) + "/data/4HHB.mmtf", molecule); + + Residue& res = molecule.residue(0); + EXPECT_EQ(res.residueId(), static_cast(1)); + EXPECT_EQ(res.residueName(), "VAL"); + EXPECT_EQ(res.residueAtoms().size(), static_cast(7)); + + // The last Heme + Residue& res2 = molecule.residue(579); + EXPECT_EQ(res2.residueId(), static_cast(148)); + EXPECT_EQ(res2.residueName(), "HEM"); + EXPECT_EQ(res2.residueAtoms().size(), static_cast(43)); + + // The first water + Residue& res3 = molecule.residue(580); + EXPECT_EQ(res3.residueId(), static_cast(143)); + EXPECT_EQ(res3.residueName(), "HOH"); + EXPECT_EQ(res3.residueAtoms().size(), static_cast(1)); +} From 44a6da9426000167db599975bde4023f0ed9404c Mon Sep 17 00:00:00 2001 From: Jonathan Fine Date: Mon, 27 Aug 2018 20:04:42 -0400 Subject: [PATCH 47/68] Format fix Signed-off-by: Jonathan Fine --- avogadro/io/mmtfformat.h | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/avogadro/io/mmtfformat.h b/avogadro/io/mmtfformat.h index e7f31957b1..06ee89e3bc 100644 --- a/avogadro/io/mmtfformat.h +++ b/avogadro/io/mmtfformat.h @@ -43,11 +43,14 @@ class AVOGADROIO_EXPORT MMTFFormat : public FileFormat FileFormat* newInstance() const override { return new MMTFFormat; } std::string identifier() const override { return "Avogadro: MMTF"; } - std::string name() const override { return "MacroMolecular Transmission Format"; } + std::string name() const override + { + return "MacroMolecular Transmission Format"; + } std::string description() const override { - return "MMTF is a format used to express MacroMolecular data in a compressed " - "binary format."; + return "MMTF is a format used to express MacroMolecular data in a " + "compressed binary format."; } std::string specificationUrl() const override @@ -62,7 +65,7 @@ class AVOGADROIO_EXPORT MMTFFormat : public FileFormat bool write(std::ostream& out, const Core::Molecule& molecule) override; }; -} // end Io namespace -} // end Avogadro namespace +} // namespace Io +} // namespace Avogadro #endif // AVOGADRO_IO_MMTFFORMAT_H From 972af9746a4a8201f249c131144a3dbbe41de2cd Mon Sep 17 00:00:00 2001 From: "Marcus D. Hanwell" Date: Tue, 28 Aug 2018 13:56:16 -0400 Subject: [PATCH 48/68] Add API to specify options for file formats Keeping it fairly free form, where a string can be supplied with options for any file format. Most formats will ignore the string, while some will process certain options. Signed-off-by: Marcus D. Hanwell --- avogadro/io/fileformat.h | 13 +++++++++++++ avogadro/io/fileformatmanager.cpp | 16 ++++++++++++---- avogadro/io/fileformatmanager.h | 24 ++++++++++++++++-------- 3 files changed, 41 insertions(+), 12 deletions(-) diff --git a/avogadro/io/fileformat.h b/avogadro/io/fileformat.h index 98d799b170..d8a19d36af 100644 --- a/avogadro/io/fileformat.h +++ b/avogadro/io/fileformat.h @@ -178,6 +178,18 @@ class AVOGADROIO_EXPORT FileFormat */ std::string fileName() const { return m_fileName; } + /** + * @brief Set options for the file reader. + * @param options The options, each reader chooses how to use/interpret them. + */ + void setOptions(const std::string& options) { m_options = options; } + + /** + * @brief Get the file format options, can be used to change file IO. + * @return The options set for the reader (defaults to empty). + */ + std::string options() const { return m_options; } + /** * Clear the format and reset all state. */ @@ -236,6 +248,7 @@ class AVOGADROIO_EXPORT FileFormat private: std::string m_error; std::string m_fileName; + std::string m_options; // Streams for reading/writing data, especially streaming data in/out. Operation m_mode; diff --git a/avogadro/io/fileformatmanager.cpp b/avogadro/io/fileformatmanager.cpp index a13cb66492..9d2091bf2e 100644 --- a/avogadro/io/fileformatmanager.cpp +++ b/avogadro/io/fileformatmanager.cpp @@ -45,7 +45,8 @@ FileFormatManager& FileFormatManager::instance() bool FileFormatManager::readFile(Core::Molecule& molecule, const std::string& fileName, - const std::string& fileExtension) const + const std::string& fileExtension, + const std::string& options) const { FileFormat* format(nullptr); if (fileExtension.empty()) { @@ -62,12 +63,14 @@ bool FileFormatManager::readFile(Core::Molecule& molecule, return false; unique_ptr formatInstance(format->newInstance()); + formatInstance->setOptions(options); return formatInstance->readFile(fileName, molecule); } bool FileFormatManager::writeFile(const Core::Molecule& molecule, const std::string& fileName, - const std::string& fileExtension) const + const std::string& fileExtension, + const std::string& options) const { FileFormat* format(nullptr); if (fileExtension.empty()) { @@ -84,12 +87,14 @@ bool FileFormatManager::writeFile(const Core::Molecule& molecule, return false; unique_ptr formatInstance(format->newInstance()); + formatInstance->setOptions(options); return formatInstance->writeFile(fileName, molecule); } bool FileFormatManager::readString(Core::Molecule& molecule, const std::string& string, - const std::string& fileExtension) const + const std::string& fileExtension, + const std::string& options) const { FileFormat* format(filteredFormatFromFormatMap( fileExtension, FileFormat::Read | FileFormat::String, m_fileExtensions)); @@ -97,12 +102,14 @@ bool FileFormatManager::readString(Core::Molecule& molecule, return false; unique_ptr formatInstance(format->newInstance()); + formatInstance->setOptions(options); return formatInstance->readString(string, molecule); } bool FileFormatManager::writeString(const Core::Molecule& molecule, std::string& string, - const std::string& fileExtension) const + const std::string& fileExtension, + const std::string& options) const { FileFormat* format(filteredFormatFromFormatMap( fileExtension, FileFormat::Write | FileFormat::String, m_fileExtensions)); @@ -110,6 +117,7 @@ bool FileFormatManager::writeString(const Core::Molecule& molecule, return false; unique_ptr formatInstance(format->newInstance()); + formatInstance->setOptions(options); return formatInstance->writeString(string, molecule); } diff --git a/avogadro/io/fileformatmanager.h b/avogadro/io/fileformatmanager.h index a2c0bd8db9..6acd3807c2 100644 --- a/avogadro/io/fileformatmanager.h +++ b/avogadro/io/fileformatmanager.h @@ -58,35 +58,43 @@ class AVOGADROIO_EXPORT FileFormatManager /** * Load @p molecule with the @p fileName contents supplied, inferring the - * @p fileExtension if it is empty. + * @p fileExtension if it is empty. The @p options can be used to modify + * the behavior of the file format. * @return True on success, false on failure. */ bool readFile(Core::Molecule& molecule, const std::string& fileName, - const std::string& fileExtension = std::string()) const; + const std::string& fileExtension = std::string(), + const std::string& options = std::string()) const; /** * Write @p molecule to the @p fileName supplied, inferring the - * @p fileExtension if it is empty. + * @p fileExtension if it is empty. The @p options can be used to modify + * the behavior of the file format. * @return True on success, false on failure. */ bool writeFile(const Core::Molecule& molecule, const std::string& fileName, - const std::string& fileExtension = std::string()) const; + const std::string& fileExtension = std::string(), + const std::string& options = std::string()) const; /** * Load @p molecule with the contents of @p string, using the supplied - * @p fileExtension to determine the format. + * @p fileExtension to determine the format. The @p options can be used to + * modify the behavior of the file format. * @return True on success, false on failure. */ bool readString(Core::Molecule& molecule, const std::string& string, - const std::string& fileExtension) const; + const std::string& fileExtension, + const std::string& options = std::string()) const; /** * Write @p molecule to the @p string, using the supplied @p fileExtension - * to determine the format. + * to determine the format. The @p options can be used to modify the behavior + * of the file format. * @return True on success, false on failure. */ bool writeString(const Core::Molecule& molecule, std::string& string, - const std::string& fileExtension) const; + const std::string& fileExtension, + const std::string& options = std::string()) const; /** * @brief Register a new file format with the format manager. From f9c6ac93e9879f8f9152c83cb8eb702af919f523 Mon Sep 17 00:00:00 2001 From: "Marcus D. Hanwell" Date: Tue, 28 Aug 2018 13:57:24 -0400 Subject: [PATCH 49/68] Add an example option to CJSON to drop properties This defaults to true, but if set to false the properties will not be written. Signed-off-by: Marcus D. Hanwell --- avogadro/io/cjsonformat.cpp | 16 ++++++++++++---- tests/io/fileformatmanagertest.cpp | 22 ++++++++++++++++++++++ 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/avogadro/io/cjsonformat.cpp b/avogadro/io/cjsonformat.cpp index a12bdd157f..bfebbc05bf 100644 --- a/avogadro/io/cjsonformat.cpp +++ b/avogadro/io/cjsonformat.cpp @@ -363,14 +363,22 @@ bool CjsonFormat::read(std::istream& file, Molecule& molecule) bool CjsonFormat::write(std::ostream& file, const Molecule& molecule) { + json opts; + if (!options().empty()) + opts = json::parse(options()); + else + opts = json::object(); + json root; root["chemical json"] = 0; - if (molecule.data("name").type() == Variant::String) - root["name"] = molecule.data("name").toString().c_str(); - if (molecule.data("inchi").type() == Variant::String) - root["inchi"] = molecule.data("inchi").toString().c_str(); + if (opts.value("properties", true)) { + if (molecule.data("name").type() == Variant::String) + root["name"] = molecule.data("name").toString().c_str(); + if (molecule.data("inchi").type() == Variant::String) + root["inchi"] = molecule.data("inchi").toString().c_str(); + } if (molecule.unitCell()) { json unitCell; diff --git a/tests/io/fileformatmanagertest.cpp b/tests/io/fileformatmanagertest.cpp index d7c8bb2ee4..c8f29ba052 100644 --- a/tests/io/fileformatmanagertest.cpp +++ b/tests/io/fileformatmanagertest.cpp @@ -139,6 +139,28 @@ TEST(FileFormatManagerTest, writeStringCjson) EXPECT_EQ(cmlMol.data("inchi").toString(), "1/C2H6/c1-2/h1-2H3"); } +TEST(FileFormatManagerTest, writeStringCjsonOptions) +{ + Molecule molecule; + std::string options = "{ \"properties\": false }"; + FileFormatManager::instance().readFile(molecule, std::string(AVOGADRO_DATA) + + "/data/ethane.cjson"); + std::string cjson; + FileFormatManager::instance().writeString(molecule, cjson, "cjson", options); + + std::cout << cjson << std::endl; + + // See if they still have data in them now they have gone back and forth... + Molecule cjsonMol; + FileFormatManager::instance().readString(cjsonMol, cjson, "cjson"); + + // If the option was respected these should now be empty. + EXPECT_EQ(cjsonMol.data("name").type(), Variant::Null); + EXPECT_EQ(cjsonMol.data("name").toString(), ""); + EXPECT_EQ(cjsonMol.data("inchi").type(), Variant::Null); + EXPECT_EQ(cjsonMol.data("inchi").toString(), ""); +} + class Format : public FileFormat { private: From 5feb5633d2ed346a2cf195aab74dfc6f8320a50d Mon Sep 17 00:00:00 2001 From: "Marcus D. Hanwell" Date: Tue, 28 Aug 2018 14:39:09 -0400 Subject: [PATCH 50/68] Disable exceptions when parsing the options string Signed-off-by: Marcus D. Hanwell --- avogadro/io/cjsonformat.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/avogadro/io/cjsonformat.cpp b/avogadro/io/cjsonformat.cpp index bfebbc05bf..8642e64dab 100644 --- a/avogadro/io/cjsonformat.cpp +++ b/avogadro/io/cjsonformat.cpp @@ -365,7 +365,7 @@ bool CjsonFormat::write(std::ostream& file, const Molecule& molecule) { json opts; if (!options().empty()) - opts = json::parse(options()); + opts = json::parse(options(), nullptr, false); else opts = json::object(); From 479286f9366758980b188eb87060eab9a965eb40 Mon Sep 17 00:00:00 2001 From: Patrick Avery Date: Wed, 29 Aug 2018 09:17:26 -0400 Subject: [PATCH 51/68] Make mmtf optional for minimal core Signed-off-by: Patrick Avery --- CMakeLists.txt | 1 + avogadro/io/CMakeLists.txt | 15 +++++++++++---- avogadro/io/fileformatmanager.cpp | 7 ++++++- tests/io/CMakeLists.txt | 5 ++++- 4 files changed, 22 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 52226cdee0..f51f735fb9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,6 +49,7 @@ option(USE_VTK "Enable libraries that use VTK" OFF) option(USE_LIBARCHIVE "Enable optional Libarchive features" ON) option(USE_LIBMSYM "Enable optional features using libmsym" ON) option(USE_SPGLIB "Enable optional features using spglib" ON) +option(USE_MMTF "Enable optional features using mmtf" ON) option(USE_PROTOCALL "Enable libraries that use ProtoCall" OFF) option(USE_MOLEQUEUE "Enable the MoleQueue dependent functionality" ON) option(USE_PYTHON "Use Python to wrap some of our API" OFF) diff --git a/avogadro/io/CMakeLists.txt b/avogadro/io/CMakeLists.txt index bed99b83be..dec9b7b90e 100644 --- a/avogadro/io/CMakeLists.txt +++ b/avogadro/io/CMakeLists.txt @@ -1,5 +1,10 @@ find_package(Eigen3 REQUIRED) -find_package(MMTF REQUIRED) + +if(USE_MMTF) + find_package(MMTF REQUIRED) + include_directories(SYSTEM "${MMTF_INCLUDE_DIRS}") + add_definitions(-DAVO_USE_MMTF) +endif() if(USE_HDF5) find_package(HDF5 REQUIRED COMPONENTS C) @@ -15,7 +20,6 @@ endif() # Add as "system headers" to avoid warnings generated by them with # compilers that support that notion. include_directories(SYSTEM "${EIGEN3_INCLUDE_DIR}" - "${MMTF_INCLUDE_DIRS}" "${AvogadroLibs_SOURCE_DIR}/thirdparty/pugixml" "${AvogadroLibs_SOURCE_DIR}/thirdparty/struct" "${AvogadroLibs_SOURCE_DIR}/thirdparty") @@ -38,7 +42,6 @@ set(HEADERS xyzformat.h trrformat.h lammpsformat.h - mmtfformat.h ) set(SOURCES @@ -54,7 +57,6 @@ set(SOURCES xyzformat.cpp trrformat.cpp lammpsformat.cpp - mmtfformat.cpp ) if(USE_HDF5) @@ -62,6 +64,11 @@ if(USE_HDF5) list(APPEND SOURCES hdf5dataformat.cpp) endif() +if(USE_MMTF) + list(APPEND HEADERS mmtfformat.h) + list(APPEND SOURCES mmtfformat.cpp) +endif() + avogadro_add_library(AvogadroIO ${HEADERS} ${SOURCES}) target_link_libraries(AvogadroIO diff --git a/avogadro/io/fileformatmanager.cpp b/avogadro/io/fileformatmanager.cpp index af5c300f59..556c252894 100644 --- a/avogadro/io/fileformatmanager.cpp +++ b/avogadro/io/fileformatmanager.cpp @@ -24,12 +24,15 @@ #include "gromacsformat.h" #include "lammpsformat.h" #include "mdlformat.h" -#include "mmtfformat.h" #include "pdbformat.h" #include "trrformat.h" #include "vaspformat.h" #include "xyzformat.h" +#ifdef AVO_USE_MMTF +#include "mmtfformat.h" +#endif + #include #include @@ -301,7 +304,9 @@ FileFormatManager::FileFormatManager() addFormat(new DcdFormat); addFormat(new LammpsTrajectoryFormat); addFormat(new LammpsDataFormat); +#ifdef AVO_USE_MMTF addFormat(new MMTFFormat); +#endif } FileFormatManager::~FileFormatManager() diff --git a/tests/io/CMakeLists.txt b/tests/io/CMakeLists.txt index 2ca57cbecf..d2648df280 100644 --- a/tests/io/CMakeLists.txt +++ b/tests/io/CMakeLists.txt @@ -7,13 +7,16 @@ set(tests Mdl Vasp Xyz - MMTF ) if(USE_HDF5) list(APPEND tests Hdf5) endif() +if(USE_MMTF) + list(APPEND tests MMTF) +endif() + include_directories("${CMAKE_CURRENT_BINARY_DIR}" "${AvogadroLibs_BINARY_DIR}/avogadro/io") From a40dbadfbde94e8fd580b2bd91dd9eff5bdd32bc Mon Sep 17 00:00:00 2001 From: Patrick Avery Date: Wed, 29 Aug 2018 11:12:12 -0400 Subject: [PATCH 52/68] Io: Add an option to not perceive bonds in xyz Signed-off-by: Patrick Avery --- avogadro/io/xyzformat.cpp | 13 ++++++++++++- tests/io/xyztest.cpp | 25 +++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/avogadro/io/xyzformat.cpp b/avogadro/io/xyzformat.cpp index fae3fee8d4..610242a12f 100644 --- a/avogadro/io/xyzformat.cpp +++ b/avogadro/io/xyzformat.cpp @@ -21,12 +21,16 @@ #include #include +#include + #include #include #include #include #include +using json = nlohmann::json; + using std::string; using std::endl; using std::getline; @@ -58,6 +62,12 @@ XyzFormat::~XyzFormat() bool XyzFormat::read(std::istream& inStream, Core::Molecule& mol) { + json opts; + if (!options().empty()) + opts = json::parse(options(), nullptr, false); + else + opts = json::object(); + size_t numAtoms = 0; if (!(inStream >> numAtoms)) { appendError("Error parsing number of atoms."); @@ -141,7 +151,8 @@ bool XyzFormat::read(std::istream& inStream, Core::Molecule& mol) } // This format has no connectivity information, so perceive basics at least. - mol.perceiveBondsSimple(); + if (opts.value("perceiveBonds", true)) + mol.perceiveBondsSimple(); return true; } diff --git a/tests/io/xyztest.cpp b/tests/io/xyztest.cpp index 7aa805c7ee..457b885ecb 100644 --- a/tests/io/xyztest.cpp +++ b/tests/io/xyztest.cpp @@ -58,6 +58,31 @@ TEST(XyzTest, readAtomicSymbols) EXPECT_EQ(molecule.atom(4).position3d().z(), -0.36300); } +// Turn off the option to perceive bonds +TEST(XyzTest, readAtomicSymbolsNoBonds) +{ + XyzFormat xyz; + xyz.setOptions("{ \"perceiveBonds\": false }"); + Molecule molecule; + EXPECT_TRUE(xyz.readFile(AVOGADRO_DATA "/data/methane.xyz", molecule)); + ASSERT_EQ(xyz.error(), std::string()); + + EXPECT_EQ(molecule.atomCount(), 5); + + // We turned off bond perception, so there should be zero bonds + EXPECT_EQ(molecule.bondCount(), 0); + + EXPECT_EQ(molecule.atom(0).atomicNumber(), 6); + EXPECT_EQ(molecule.atom(1).atomicNumber(), 1); + EXPECT_EQ(molecule.atom(2).atomicNumber(), 1); + EXPECT_EQ(molecule.atom(3).atomicNumber(), 1); + EXPECT_EQ(molecule.atom(4).atomicNumber(), 1); + + EXPECT_EQ(molecule.atom(4).position3d().x(), -0.51336); + EXPECT_EQ(molecule.atom(4).position3d().y(), 0.88916); + EXPECT_EQ(molecule.atom(4).position3d().z(), -0.36300); +} + // methane-num.xyz uses atomic numbers to identify atoms TEST(XyzTest, readAtomicNumbers) { From fb4e50b9b0d8878922245272f8af096704c77356 Mon Sep 17 00:00:00 2001 From: Patrick Avery Date: Wed, 29 Aug 2018 13:53:53 -0400 Subject: [PATCH 53/68] Io: Add options arguments to python bindings Signed-off-by: Patrick Avery --- python/io.cpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/python/io.cpp b/python/io.cpp index ccee218681..ca2696edd8 100644 --- a/python/io.cpp +++ b/python/io.cpp @@ -26,27 +26,31 @@ class ffm ffm() : m_ffm(FileFormatManager::instance()) {} bool readFile(Core::Molecule& molecule, const std::string& fileName, - const std::string& fileExtension = std::string()) const + const std::string& fileExtension = std::string(), + const std::string& options = std::string()) const { - return m_ffm.readFile(molecule, fileName, fileExtension); + return m_ffm.readFile(molecule, fileName, fileExtension, options); } bool writeFile(const Core::Molecule& molecule, const std::string& fileName, - const std::string& fileExtension = std::string()) const + const std::string& fileExtension = std::string(), + const std::string& options = std::string()) const { - return m_ffm.writeFile(molecule, fileName, fileExtension); + return m_ffm.writeFile(molecule, fileName, fileExtension, options); } bool readString(Core::Molecule& molecule, const std::string& string, - const std::string& fileExtension) const + const std::string& fileExtension, + const std::string& options = std::string()) const { - return m_ffm.readString(molecule, string, fileExtension); + return m_ffm.readString(molecule, string, fileExtension, options); } - std::string writeString(const Molecule& mol, const std::string& ext) + std::string writeString(const Molecule& mol, const std::string& ext, + const std::string& options = std::string()) { std::string fileStr; - bool ok = m_ffm.writeString(mol, fileStr, ext); + bool ok = m_ffm.writeString(mol, fileStr, ext, options); if (!ok) fileStr = "Error: " + FileFormatManager::instance().error(); return fileStr; From d01e1d1cfdc2650e84c8468e8a8b2d538154c83f Mon Sep 17 00:00:00 2001 From: Patrick Avery Date: Wed, 29 Aug 2018 14:49:44 -0400 Subject: [PATCH 54/68] Pybind11 io: add default arguments for python Signed-off-by: Patrick Avery --- python/io.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/python/io.cpp b/python/io.cpp index ca2696edd8..2cdc07df18 100644 --- a/python/io.cpp +++ b/python/io.cpp @@ -59,7 +59,7 @@ class ffm private: FileFormatManager& m_ffm; }; -} +} // namespace void exportIo(py::module& m) { @@ -76,11 +76,18 @@ void exportIo(py::module& m) py::class_(m, "FileFormatManager") .def(py::init<>()) .def("readFile", &ffm::readFile, - "Read in a molecule from the supplied file path") + "Read in a molecule from the supplied file path", py::arg("molecule"), + py::arg("fileName"), py::arg("fileExtension") = std::string(), + py::arg("options") = std::string()) .def("writeFile", &ffm::writeFile, - "Write the molecule to the supplied file path") + "Write the molecule to the supplied file path", py::arg("molecule"), + py::arg("fileName"), py::arg("fileExtension") = std::string(), + py::arg("options") = std::string()) .def("readString", &ffm::readString, - "Read in a molecule from the supplied string") + "Read in a molecule from the supplied string", py::arg("molecule"), + py::arg("string"), py::arg("fileExtension"), + py::arg("options") = std::string()) .def("writeString", &ffm::writeString, - "Write a molecule to the supplied string"); + "Write a molecule to the supplied string", py::arg("mol"), + py::arg("ext"), py::arg("options") = std::string()); } From f7c73a755de8cf63830dd630538c11048d8fb6c3 Mon Sep 17 00:00:00 2001 From: Adarsh Balasubramanian Date: Thu, 6 Sep 2018 12:44:27 -0400 Subject: [PATCH 55/68] Copy of backgroundfileformat in qtgui Signed-off-by: Adarsh Balasubramanian --- avogadro/qtgui/CMakeLists.txt | 2 + avogadro/qtgui/backgroundfileformat.cpp | 86 ++++++++++++++++++ avogadro/qtgui/backgroundfileformat.h | 112 ++++++++++++++++++++++++ 3 files changed, 200 insertions(+) create mode 100644 avogadro/qtgui/backgroundfileformat.cpp create mode 100644 avogadro/qtgui/backgroundfileformat.h diff --git a/avogadro/qtgui/CMakeLists.txt b/avogadro/qtgui/CMakeLists.txt index 2c7f87a683..7e0e2a823d 100644 --- a/avogadro/qtgui/CMakeLists.txt +++ b/avogadro/qtgui/CMakeLists.txt @@ -32,6 +32,7 @@ configure_file("${CMAKE_CURRENT_BINARY_DIR}/avogadropython.h.in" "${CMAKE_CURRENT_BINARY_DIR}/avogadropython.h") set(HEADERS + backgroundfileformat.h containerwidget.h customelementdialog.h elementtranslator.h @@ -60,6 +61,7 @@ set(HEADERS ) set(SOURCES + backgroundfileformat.cpp containerwidget.cpp customelementdialog.cpp elementdetail_p.cpp diff --git a/avogadro/qtgui/backgroundfileformat.cpp b/avogadro/qtgui/backgroundfileformat.cpp new file mode 100644 index 0000000000..d6c6a91c54 --- /dev/null +++ b/avogadro/qtgui/backgroundfileformat.cpp @@ -0,0 +1,86 @@ +/****************************************************************************** + + This source file is part of the Avogadro project. + + Copyright 2013 Kitware, Inc. + + This source code is released under the New BSD License, (the "License"). + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +******************************************************************************/ + +#include "backgroundfileformat.h" + +#include + +namespace Avogadro { + +namespace QtGui { + +BackgroundFileFormat::BackgroundFileFormat(Io::FileFormat* format, + QObject* aparent) + : QObject(aparent), m_format(format), m_molecule(nullptr), m_success(false) +{} + +BackgroundFileFormat::~BackgroundFileFormat() +{ + delete m_format; +} + +void BackgroundFileFormat::read() +{ + m_success = false; + m_error.clear(); + + if (!m_molecule) + m_error = tr("No molecule set in BackgroundFileFormat!"); + + if (!m_format) + m_error = tr("No Io::FileFormat set in BackgroundFileFormat!"); + + if (m_fileName.isEmpty()) + m_error = tr("No file name set in BackgroundFileFormat!"); + + if (m_error.isEmpty()) { + m_success = + m_format->readFile(m_fileName.toLocal8Bit().data(), *m_molecule); + + if (!m_success) + m_error = QString::fromStdString(m_format->error()); + } + + emit finished(); +} + +void BackgroundFileFormat::write() +{ + m_success = false; + m_error.clear(); + + if (!m_molecule) + m_error = tr("No molecule set in BackgroundFileFormat!"); + + if (!m_format) + m_error = tr("No Io::FileFormat set in BackgroundFileFormat!"); + + if (m_fileName.isEmpty()) + m_error = tr("No file name set in BackgroundFileFormat!"); + + if (m_error.isEmpty()) { + m_success = + m_format->writeFile(m_fileName.toLocal8Bit().data(), *m_molecule); + + if (!m_success) + m_error = QString::fromStdString(m_format->error()); + } + + emit finished(); +} + +} // namespace QtGui +} // namespace Avogadro diff --git a/avogadro/qtgui/backgroundfileformat.h b/avogadro/qtgui/backgroundfileformat.h new file mode 100644 index 0000000000..58b0405e4f --- /dev/null +++ b/avogadro/qtgui/backgroundfileformat.h @@ -0,0 +1,112 @@ +/****************************************************************************** + + This source file is part of the Avogadro project. + + Copyright 2013 Kitware, Inc. + + This source code is released under the New BSD License, (the "License"). + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +******************************************************************************/ + +#ifndef AVOGADRO_QTGUI_BACKGROUNDFILEFORMAT_H +#define AVOGADRO_QTGUI_BACKGROUNDFILEFORMAT_H + +#include "avogadroqtguiexport.h" + +#include +#include + +namespace Avogadro { + +namespace Core { +class Molecule; +} + +namespace Io { +class FileFormat; +} + +namespace QtGui { + +/** + * @brief The BackgroundFileFormat class provides a thin QObject wrapper around + * an instance of Io::FileFormat. + */ +class AVOGADROQTGUI_EXPORT BackgroundFileFormat : public QObject +{ + Q_OBJECT +public: + /** + * This class takes ownership of @a format and will delete it when destructed. + */ + explicit BackgroundFileFormat(Io::FileFormat* format, QObject* aparent = 0); + ~BackgroundFileFormat(); + + /** + * The molecule instance to read/write. + * @{ + */ + void setMolecule(Core::Molecule* mol) { m_molecule = mol; } + Core::Molecule* molecule() const { return m_molecule; } + /**@}*/ + + /** + * The name of the file to read/write. + * @{ + */ + void setFileName(const QString& filename) { m_fileName = filename; } + QString fileName() const { return m_fileName; } + /**@}*/ + + /** + * The Io::FileFormat to use. + */ + Io::FileFormat* fileFormat() const { return m_format; } + + /** + * @return True if the operation was successful. + */ + bool success() const { return m_success; } + + /** + * @return An error string, set if success() is false. + */ + QString error() const { return m_error; } + +signals: + + /** + * Emitted when a call to read or write is called. + */ + void finished(); + +public slots: + + /** + * Use the fileFormat() to read fileName() into molecule(). + */ + void read(); + + /** + * Use the fileFormat() to write fileName() from molecule(). + */ + void write(); + +private: + Io::FileFormat* m_format; + Core::Molecule* m_molecule; + QString m_fileName; + QString m_error; + bool m_success; +}; + +} // namespace QtGui +} // namespace Avogadro + +#endif // AVOGADRO_BACKGROUNDFILEFORMAT_H From 06892768cc9024d05908f0f4efebc8abb48b7985 Mon Sep 17 00:00:00 2001 From: Adarsh Balasubramanian Date: Fri, 7 Sep 2018 12:50:32 -0400 Subject: [PATCH 56/68] Storing atomic numbers alongside the atom names in resdata Signed-off-by: Adarsh Balasubramanian --- avogadro/core/residue.cpp | 32 +- avogadro/core/residue.h | 6 +- avogadro/core/residuedata.h | 1022 ++++++++++++++++++++++------------- scripts/getresdata.py | 18 +- 4 files changed, 669 insertions(+), 409 deletions(-) diff --git a/avogadro/core/residue.cpp b/avogadro/core/residue.cpp index 4be2dbad59..b5788c5afa 100644 --- a/avogadro/core/residue.cpp +++ b/avogadro/core/residue.cpp @@ -23,25 +23,19 @@ namespace Core { Residue::Residue() {} -Residue::Residue(std::string& name) - : m_residueName(name) -{} +Residue::Residue(std::string& name) : m_residueName(name) {} Residue::Residue(std::string& name, Index& number) - : m_residueName(name) - , m_residueId(number) + : m_residueName(name), m_residueId(number) {} Residue::Residue(std::string& name, Index& number, char& id) - : m_residueName(name) - , m_residueId(number) - , m_chainId(id) + : m_residueName(name), m_residueId(number), m_chainId(id) {} Residue::Residue(const Residue& other) - : m_residueName(other.m_residueName) - , m_residueId(other.m_residueId) - , m_atomNameMap(other.m_atomNameMap) + : m_residueName(other.m_residueName), m_residueId(other.m_residueId), + m_atomNameMap(other.m_atomNameMap) {} Residue& Residue::operator=(Residue other) @@ -93,5 +87,17 @@ void Residue::resolveResidueBonds(Molecule& mol) } } -} // end Core namespace -} // end Avogadro namespace +int Residue::getAtomicNumber(std::string name) +{ + std::map resAtoms; + if (residueDict.find(m_residueName) != residueDict.end()) { + resAtoms = residueDict[m_residueName].residueAtoms(); + if (resAtoms.find(name) != resAtoms.end()) + return resAtoms[name]; + } + + return 0; +} + +} // namespace Core +} // namespace Avogadro diff --git a/avogadro/core/residue.h b/avogadro/core/residue.h index f38ba1a460..2f9f9264d1 100644 --- a/avogadro/core/residue.h +++ b/avogadro/core/residue.h @@ -77,6 +77,8 @@ class AVOGADROCORE_EXPORT Residue */ void resolveResidueBonds(Molecule& mol); + int getAtomicNumber(std::string name); + protected: std::string m_residueName; Index m_residueId; @@ -84,7 +86,7 @@ class AVOGADROCORE_EXPORT Residue AtomNameMap m_atomNameMap; }; -} // end Core namespace -} // end Avogadro namespace +} // namespace Core +} // namespace Avogadro #endif // AVOGADRO_CORE_RESIDUE_H diff --git a/avogadro/core/residuedata.h b/avogadro/core/residuedata.h index c67ba5d557..4434166805 100644 --- a/avogadro/core/residuedata.h +++ b/avogadro/core/residuedata.h @@ -12,13 +12,14 @@ class ResidueData { private: std::string m_residueName; - std::vector m_residueAtomNames; + std::vector> m_residueAtomNames; std::vector> m_residueSingleBonds; std::vector> m_residueDoubleBonds; public: ResidueData() {} - ResidueData(std::string name, std::vector atomNames, + ResidueData(std::string name, + std::vector> atomNames, std::vector> singleBonds, std::vector> doubleBonds) { @@ -43,6 +44,8 @@ class ResidueData return *this; } + std::map residueAtoms() { return m_residueAtomNames; } + std::vector> residueSingleBonds() { return m_residueSingleBonds; @@ -56,8 +59,19 @@ class ResidueData ResidueData ALAData("ALA", // Atoms - { "N", "CA", "C", "O", "CB", "OXT", "H", "H2", "HA", "HB1", - "HB2", "HB3", "HXT" }, + { { "N", 7 }, + { "CA", 6 }, + { "C", 6 }, + { "O", 8 }, + { "CB", 6 }, + { "OXT", 8 }, + { "H", 1 }, + { "H2", 1 }, + { "HA", 1 }, + { "HB1", 1 }, + { "HB2", 1 }, + { "HB3", 1 }, + { "HB3", 1 } }, // Single Bonds { { "N", "CA" }, { "N", "H" }, @@ -74,8 +88,20 @@ ResidueData ALAData("ALA", { { "C", "O" } }); ResidueData CYSData("CYS", // Atoms - { "N", "CA", "C", "O", "CB", "SG", "OXT", "H", "H2", "HA", - "HB2", "HB3", "HG", "HXT" }, + { { "N", 7 }, + { "CA", 6 }, + { "C", 6 }, + { "O", 8 }, + { "CB", 6 }, + { "SG", 16 }, + { "OXT", 8 }, + { "H", 1 }, + { "H2", 1 }, + { "HA", 1 }, + { "HB2", 1 }, + { "HB3", 1 }, + { "HG", 1 }, + { "HG", 1 } }, // Single Bonds { { "N", "CA" }, { "N", "H" }, @@ -93,8 +119,22 @@ ResidueData CYSData("CYS", { { "C", "O" } }); ResidueData ASPData("ASP", // Atoms - { "N", "CA", "C", "O", "CB", "CG", "OD1", "OD2", "OXT", "H", - "H2", "HA", "HB2", "HB3", "HD2", "HXT" }, + { { "N", 7 }, + { "CA", 6 }, + { "C", 6 }, + { "O", 8 }, + { "CB", 6 }, + { "CG", 6 }, + { "OD1", 8 }, + { "OD2", 8 }, + { "OXT", 8 }, + { "H", 1 }, + { "H2", 1 }, + { "HA", 1 }, + { "HB2", 1 }, + { "HB3", 1 }, + { "HD2", 1 }, + { "HD2", 1 } }, // Single Bonds { { "N", "CA" }, { "N", "H" }, @@ -113,9 +153,25 @@ ResidueData ASPData("ASP", { { "C", "O" }, { "CG", "OD1" } }); ResidueData GLUData("GLU", // Atoms - { "N", "CA", "C", "O", "CB", "CG", "CD", "OE1", "OE2", - "OXT", "H", "H2", "HA", "HB2", "HB3", "HG2", "HG3", "HE2", - "HXT" }, + { { "N", 7 }, + { "CA", 6 }, + { "C", 6 }, + { "O", 8 }, + { "CB", 6 }, + { "CG", 6 }, + { "CD", 6 }, + { "OE1", 8 }, + { "OE2", 8 }, + { "OXT", 8 }, + { "H", 1 }, + { "H2", 1 }, + { "HA", 1 }, + { "HB2", 1 }, + { "HB3", 1 }, + { "HG2", 1 }, + { "HG3", 1 }, + { "HE2", 1 }, + { "HE2", 1 } }, // Single Bonds { { "N", "CA" }, { "N", "H" }, @@ -138,9 +194,11 @@ ResidueData GLUData("GLU", ResidueData PHEData( "PHE", // Atoms - { "N", "CA", "C", "O", "CB", "CG", "CD1", "CD2", - "CE1", "CE2", "CZ", "OXT", "H", "H2", "HA", "HB2", - "HB3", "HD1", "HD2", "HE1", "HE2", "HZ", "HXT" }, + { { "N", 7 }, { "CA", 6 }, { "C", 6 }, { "O", 8 }, { "CB", 6 }, + { "CG", 6 }, { "CD1", 6 }, { "CD2", 6 }, { "CE1", 6 }, { "CE2", 6 }, + { "CZ", 6 }, { "OXT", 8 }, { "H", 1 }, { "H2", 1 }, { "HA", 1 }, + { "HB2", 1 }, { "HB3", 1 }, { "HD1", 1 }, { "HD2", 1 }, { "HE1", 1 }, + { "HE2", 1 }, { "HZ", 1 }, { "HZ", 1 } }, // Single Bonds { { "N", "CA" }, { "N", "H" }, @@ -165,8 +223,16 @@ ResidueData PHEData( { { "C", "O" }, { "CG", "CD1" }, { "CD2", "CE2" }, { "CE1", "CZ" } }); ResidueData GLYData("GLY", // Atoms - { "N", "CA", "C", "O", "OXT", "H", "H2", "HA2", "HA3", - "HXT" }, + { { "N", 7 }, + { "CA", 6 }, + { "C", 6 }, + { "O", 8 }, + { "OXT", 8 }, + { "H", 1 }, + { "H2", 1 }, + { "HA2", 1 }, + { "HA3", 1 }, + { "HA3", 1 } }, // Single Bonds { { "N", "CA" }, { "N", "H" }, @@ -180,9 +246,12 @@ ResidueData GLYData("GLY", { { "C", "O" } }); ResidueData HISData("HIS", // Atoms - { "N", "CA", "C", "O", "CB", "CG", "ND1", - "CD2", "CE1", "NE2", "OXT", "H", "H2", "HA", - "HB2", "HB3", "HD1", "HD2", "HE1", "HE2", "HXT" }, + { { "N", 7 }, { "CA", 6 }, { "C", 6 }, { "O", 8 }, + { "CB", 6 }, { "CG", 6 }, { "ND1", 7 }, { "CD2", 6 }, + { "CE1", 6 }, { "NE2", 7 }, { "OXT", 8 }, { "H", 1 }, + { "H2", 1 }, { "HA", 1 }, { "HB2", 1 }, { "HB3", 1 }, + { "HD1", 1 }, { "HD2", 1 }, { "HE1", 1 }, { "HE2", 1 }, + { "HE2", 1 } }, // Single Bonds { { "N", "CA" }, { "N", "H" }, @@ -207,9 +276,11 @@ ResidueData HISData("HIS", ResidueData ILEData( "ILE", // Atoms - { "N", "CA", "C", "O", "CB", "CG1", "CG2", "CD1", - "OXT", "H", "H2", "HA", "HB", "HG12", "HG13", "HG21", - "HG22", "HG23", "HD11", "HD12", "HD13", "HXT" }, + { { "N", 7 }, { "CA", 6 }, { "C", 6 }, { "O", 8 }, { "CB", 6 }, + { "CG1", 6 }, { "CG2", 6 }, { "CD1", 6 }, { "OXT", 8 }, { "H", 1 }, + { "H2", 1 }, { "HA", 1 }, { "HB", 1 }, { "HG12", 1 }, { "HG13", 1 }, + { "HG21", 1 }, { "HG22", 1 }, { "HG23", 1 }, { "HD11", 1 }, { "HD12", 1 }, + { "HD13", 1 }, { "HD13", 1 } }, // Single Bonds { { "N", "CA" }, { "N", "H" }, { "N", "H2" }, { "CA", "C" }, { "CA", "CB" }, { "CA", "HA" }, { "C", "OXT" }, { "CB", "CG1" }, @@ -221,9 +292,11 @@ ResidueData ILEData( ResidueData LYSData( "LYS", // Atoms - { "N", "CA", "C", "O", "CB", "CG", "CD", "CE", "NZ", - "OXT", "H", "H2", "HA", "HB2", "HB3", "HG2", "HG3", "HD2", - "HD3", "HE2", "HE3", "HZ1", "HZ2", "HZ3", "HXT" }, + { { "N", 7 }, { "CA", 6 }, { "C", 6 }, { "O", 8 }, { "CB", 6 }, + { "CG", 6 }, { "CD", 6 }, { "CE", 6 }, { "NZ", 7 }, { "OXT", 8 }, + { "H", 1 }, { "H2", 1 }, { "HA", 1 }, { "HB2", 1 }, { "HB3", 1 }, + { "HG2", 1 }, { "HG3", 1 }, { "HD2", 1 }, { "HD3", 1 }, { "HE2", 1 }, + { "HE3", 1 }, { "HZ1", 1 }, { "HZ2", 1 }, { "HZ3", 1 }, { "HZ3", 1 } }, // Single Bonds { { "N", "CA" }, { "N", "H" }, { "N", "H2" }, { "CA", "C" }, { "CA", "CB" }, { "CA", "HA" }, { "C", "OXT" }, { "CB", "CG" }, @@ -236,9 +309,11 @@ ResidueData LYSData( ResidueData LEUData( "LEU", // Atoms - { "N", "CA", "C", "O", "CB", "CG", "CD1", "CD2", - "OXT", "H", "H2", "HA", "HB2", "HB3", "HG", "HD11", - "HD12", "HD13", "HD21", "HD22", "HD23", "HXT" }, + { { "N", 7 }, { "CA", 6 }, { "C", 6 }, { "O", 8 }, { "CB", 6 }, + { "CG", 6 }, { "CD1", 6 }, { "CD2", 6 }, { "OXT", 8 }, { "H", 1 }, + { "H2", 1 }, { "HA", 1 }, { "HB2", 1 }, { "HB3", 1 }, { "HG", 1 }, + { "HD11", 1 }, { "HD12", 1 }, { "HD13", 1 }, { "HD21", 1 }, { "HD22", 1 }, + { "HD23", 1 }, { "HD23", 1 } }, // Single Bonds { { "N", "CA" }, { "N", "H" }, { "N", "H2" }, { "CA", "C" }, { "CA", "CB" }, { "CA", "HA" }, { "C", "OXT" }, { "CB", "CG" }, @@ -249,9 +324,11 @@ ResidueData LEUData( { { "C", "O" } }); ResidueData METData("MET", // Atoms - { "N", "CA", "C", "O", "CB", "CG", "SD", - "CE", "OXT", "H", "H2", "HA", "HB2", "HB3", - "HG2", "HG3", "HE1", "HE2", "HE3", "HXT" }, + { { "N", 7 }, { "CA", 6 }, { "C", 6 }, { "O", 8 }, + { "CB", 6 }, { "CG", 6 }, { "SD", 16 }, { "CE", 6 }, + { "OXT", 8 }, { "H", 1 }, { "H2", 1 }, { "HA", 1 }, + { "HB2", 1 }, { "HB3", 1 }, { "HG2", 1 }, { "HG3", 1 }, + { "HE1", 1 }, { "HE2", 1 }, { "HE3", 1 }, { "HE3", 1 } }, // Single Bonds { { "N", "CA" }, { "N", "H" }, @@ -275,8 +352,23 @@ ResidueData METData("MET", { { "C", "O" } }); ResidueData ASNData("ASN", // Atoms - { "N", "CA", "C", "O", "CB", "CG", "OD1", "ND2", "OXT", "H", - "H2", "HA", "HB2", "HB3", "HD21", "HD22", "HXT" }, + { { "N", 7 }, + { "CA", 6 }, + { "C", 6 }, + { "O", 8 }, + { "CB", 6 }, + { "CG", 6 }, + { "OD1", 8 }, + { "ND2", 7 }, + { "OXT", 8 }, + { "H", 1 }, + { "H2", 1 }, + { "HA", 1 }, + { "HB2", 1 }, + { "HB3", 1 }, + { "HD21", 1 }, + { "HD22", 1 }, + { "HD22", 1 } }, // Single Bonds { { "N", "CA" }, { "N", "H" }, @@ -296,8 +388,23 @@ ResidueData ASNData("ASN", { { "C", "O" }, { "CG", "OD1" } }); ResidueData PROData("PRO", // Atoms - { "N", "CA", "C", "O", "CB", "CG", "CD", "OXT", "H", "HA", - "HB2", "HB3", "HG2", "HG3", "HD2", "HD3", "HXT" }, + { { "N", 7 }, + { "CA", 6 }, + { "C", 6 }, + { "O", 8 }, + { "CB", 6 }, + { "CG", 6 }, + { "CD", 6 }, + { "OXT", 8 }, + { "H", 1 }, + { "HA", 1 }, + { "HB2", 1 }, + { "HB3", 1 }, + { "HG2", 1 }, + { "HG3", 1 }, + { "HD2", 1 }, + { "HD3", 1 }, + { "HD3", 1 } }, // Single Bonds { { "N", "CA" }, { "N", "CD" }, @@ -317,37 +424,42 @@ ResidueData PROData("PRO", { "OXT", "HXT" } }, // Double Bonds { { "C", "O" } }); -ResidueData GLNData("GLN", - // Atoms - { "N", "CA", "C", "O", "CB", "CG", "CD", - "OE1", "NE2", "OXT", "H", "H2", "HA", "HB2", - "HB3", "HG2", "HG3", "HE21", "HE22", "HXT" }, - // Single Bonds - { { "N", "CA" }, - { "N", "H" }, - { "N", "H2" }, - { "CA", "C" }, - { "CA", "CB" }, - { "CA", "HA" }, - { "C", "OXT" }, - { "CB", "CG" }, - { "CB", "HB2" }, - { "CB", "HB3" }, - { "CG", "CD" }, - { "CG", "HG2" }, - { "CG", "HG3" }, - { "CD", "NE2" }, - { "NE2", "HE21" }, - { "NE2", "HE22" }, - { "OXT", "HXT" } }, - // Double Bonds - { { "C", "O" }, { "CD", "OE1" } }); +ResidueData GLNData( + "GLN", + // Atoms + { { "N", 7 }, { "CA", 6 }, { "C", 6 }, { "O", 8 }, { "CB", 6 }, + { "CG", 6 }, { "CD", 6 }, { "OE1", 8 }, { "NE2", 7 }, { "OXT", 8 }, + { "H", 1 }, { "H2", 1 }, { "HA", 1 }, { "HB2", 1 }, { "HB3", 1 }, + { "HG2", 1 }, { "HG3", 1 }, { "HE21", 1 }, { "HE22", 1 }, { "HE22", 1 } }, + // Single Bonds + { { "N", "CA" }, + { "N", "H" }, + { "N", "H2" }, + { "CA", "C" }, + { "CA", "CB" }, + { "CA", "HA" }, + { "C", "OXT" }, + { "CB", "CG" }, + { "CB", "HB2" }, + { "CB", "HB3" }, + { "CG", "CD" }, + { "CG", "HG2" }, + { "CG", "HG3" }, + { "CD", "NE2" }, + { "NE2", "HE21" }, + { "NE2", "HE22" }, + { "OXT", "HXT" } }, + // Double Bonds + { { "C", "O" }, { "CD", "OE1" } }); ResidueData ARGData( "ARG", // Atoms - { "N", "CA", "C", "O", "CB", "CG", "CD", "NE", "CZ", - "NH1", "NH2", "OXT", "H", "H2", "HA", "HB2", "HB3", "HG2", - "HG3", "HD2", "HD3", "HE", "HH11", "HH12", "HH21", "HH22", "HXT" }, + { { "N", 7 }, { "CA", 6 }, { "C", 6 }, { "O", 8 }, { "CB", 6 }, + { "CG", 6 }, { "CD", 6 }, { "NE", 7 }, { "CZ", 6 }, { "NH1", 7 }, + { "NH2", 7 }, { "OXT", 8 }, { "H", 1 }, { "H2", 1 }, { "HA", 1 }, + { "HB2", 1 }, { "HB3", 1 }, { "HG2", 1 }, { "HG3", 1 }, { "HD2", 1 }, + { "HD3", 1 }, { "HE", 1 }, { "HH11", 1 }, { "HH12", 1 }, { "HH21", 1 }, + { "HH22", 1 }, { "HH22", 1 } }, // Single Bonds { { "N", "CA" }, { "N", "H" }, { "N", "H2" }, { "CA", "C" }, { "CA", "CB" }, { "CA", "HA" }, { "C", "OXT" }, { "CB", "CG" }, @@ -359,8 +471,20 @@ ResidueData ARGData( { { "C", "O" }, { "CZ", "NH2" } }); ResidueData SERData("SER", // Atoms - { "N", "CA", "C", "O", "CB", "OG", "OXT", "H", "H2", "HA", - "HB2", "HB3", "HG", "HXT" }, + { { "N", 7 }, + { "CA", 6 }, + { "C", 6 }, + { "O", 8 }, + { "CB", 6 }, + { "OG", 8 }, + { "OXT", 8 }, + { "H", 1 }, + { "H2", 1 }, + { "HA", 1 }, + { "HB2", 1 }, + { "HB3", 1 }, + { "HG", 1 }, + { "HG", 1 } }, // Single Bonds { { "N", "CA" }, { "N", "H" }, @@ -378,8 +502,23 @@ ResidueData SERData("SER", { { "C", "O" } }); ResidueData THRData("THR", // Atoms - { "N", "CA", "C", "O", "CB", "OG1", "CG2", "OXT", "H", "H2", - "HA", "HB", "HG1", "HG21", "HG22", "HG23", "HXT" }, + { { "N", 7 }, + { "CA", 6 }, + { "C", 6 }, + { "O", 8 }, + { "CB", 6 }, + { "OG1", 8 }, + { "CG2", 6 }, + { "OXT", 8 }, + { "H", 1 }, + { "H2", 1 }, + { "HA", 1 }, + { "HB", 1 }, + { "HG1", 1 }, + { "HG21", 1 }, + { "HG22", 1 }, + { "HG23", 1 }, + { "HG23", 1 } }, // Single Bonds { { "N", "CA" }, { "N", "H" }, @@ -400,9 +539,25 @@ ResidueData THRData("THR", { { "C", "O" } }); ResidueData VALData("VAL", // Atoms - { "N", "CA", "C", "O", "CB", "CG1", "CG2", "OXT", "H", "H2", - "HA", "HB", "HG11", "HG12", "HG13", "HG21", "HG22", - "HG23", "HXT" }, + { { "N", 7 }, + { "CA", 6 }, + { "C", 6 }, + { "O", 8 }, + { "CB", 6 }, + { "CG1", 6 }, + { "CG2", 6 }, + { "OXT", 8 }, + { "H", 1 }, + { "H2", 1 }, + { "HA", 1 }, + { "HB", 1 }, + { "HG11", 1 }, + { "HG12", 1 }, + { "HG13", 1 }, + { "HG21", 1 }, + { "HG22", 1 }, + { "HG23", 1 }, + { "HG23", 1 } }, // Single Bonds { { "N", "CA" }, { "N", "H" }, @@ -426,9 +581,12 @@ ResidueData VALData("VAL", ResidueData TRPData( "TRP", // Atoms - { "N", "CA", "C", "O", "CB", "CG", "CD1", "CD2", "NE1", - "CE2", "CE3", "CZ2", "CZ3", "CH2", "OXT", "H", "H2", "HA", - "HB2", "HB3", "HD1", "HE1", "HE3", "HZ2", "HZ3", "HH2", "HXT" }, + { { "N", 7 }, { "CA", 6 }, { "C", 6 }, { "O", 8 }, { "CB", 6 }, + { "CG", 6 }, { "CD1", 6 }, { "CD2", 6 }, { "NE1", 7 }, { "CE2", 6 }, + { "CE3", 6 }, { "CZ2", 6 }, { "CZ3", 6 }, { "CH2", 6 }, { "OXT", 8 }, + { "H", 1 }, { "H2", 1 }, { "HA", 1 }, { "HB2", 1 }, { "HB3", 1 }, + { "HD1", 1 }, { "HE1", 1 }, { "HE3", 1 }, { "HZ2", 1 }, { "HZ3", 1 }, + { "HH2", 1 }, { "HH2", 1 } }, // Single Bonds { { "N", "CA" }, { "N", "H" }, { "N", "H2" }, { "CA", "C" }, { "CA", "CB" }, { "CA", "HA" }, { "C", "OXT" }, { "CB", "CG" }, @@ -445,9 +603,11 @@ ResidueData TRPData( ResidueData TYRData( "TYR", // Atoms - { "N", "CA", "C", "O", "CB", "CG", "CD1", "CD2", - "CE1", "CE2", "CZ", "OH", "OXT", "H", "H2", "HA", - "HB2", "HB3", "HD1", "HD2", "HE1", "HE2", "HH", "HXT" }, + { { "N", 7 }, { "CA", 6 }, { "C", 6 }, { "O", 8 }, { "CB", 6 }, + { "CG", 6 }, { "CD1", 6 }, { "CD2", 6 }, { "CE1", 6 }, { "CE2", 6 }, + { "CZ", 6 }, { "OH", 8 }, { "OXT", 8 }, { "H", 1 }, { "H2", 1 }, + { "HA", 1 }, { "HB2", 1 }, { "HB3", 1 }, { "HD1", 1 }, { "HD2", 1 }, + { "HE1", 1 }, { "HE2", 1 }, { "HH", 1 }, { "HH", 1 } }, // Single Bonds { { "N", "CA" }, { "N", "H" }, { "N", "H2" }, { "CA", "C" }, { "CA", "CB" }, { "CA", "HA" }, { "C", "OXT" }, { "CB", "CG" }, @@ -459,10 +619,14 @@ ResidueData TYRData( ResidueData DAData( "DA", // Atoms - { "OP3", "P", "OP1", "OP2", "O5'", "C5'", "C4'", "O4'", "C3'", - "O3'", "C2'", "C1'", "N9", "C8", "N7", "C5", "C6", "N6", - "N1", "C2", "N3", "C4", "HOP3", "HOP2", "H5'", "H5''", "H4'", - "H3'", "HO3'", "H2'", "H2''", "H1'", "H8", "H61", "H62", "H2" }, + { { "OP3", 8 }, { "P", 15 }, { "OP1", 8 }, { "OP2", 8 }, { "O5'", 8 }, + { "C5'", 6 }, { "C4'", 6 }, { "O4'", 8 }, { "C3'", 6 }, { "O3'", 8 }, + { "C2'", 6 }, { "C1'", 6 }, { "N9", 7 }, { "C8", 6 }, { "N7", 7 }, + { "C5", 6 }, { "C6", 6 }, { "N6", 7 }, { "N1", 7 }, { "C2", 6 }, + { "N3", 7 }, { "C4", 6 }, { "HOP3", 1 }, { "HOP2", 1 }, { "H5'", 1 }, + { "H5''", 1 }, { "H4'", 1 }, { "H3'", 1 }, { "HO3'", 1 }, { "H2'", 1 }, + { "H2''", 1 }, { "H1'", 1 }, { "H8", 1 }, { "H61", 1 }, { "H62", 1 }, + { "H62", 1 } }, // Single Bonds { { "OP3", "P" }, { "OP3", "HOP3" }, { "P", "OP2" }, { "P", "O5'" }, { "OP2", "HOP2" }, { "O5'", "C5'" }, { "C5'", "C4'" }, { "C5'", "H5'" }, @@ -482,10 +646,13 @@ ResidueData DAData( ResidueData DCData( "DC", // Atoms - { "OP3", "P", "OP1", "OP2", "O5'", "C5'", "C4'", "O4'", "C3'", - "O3'", "C2'", "C1'", "N1", "C2", "O2", "N3", "C4", "N4", - "C5", "C6", "HOP3", "HOP2", "H5'", "H5''", "H4'", "H3'", "HO3'", - "H2'", "H2''", "H1'", "H41", "H42", "H5", "H6" }, + { { "OP3", 8 }, { "P", 15 }, { "OP1", 8 }, { "OP2", 8 }, { "O5'", 8 }, + { "C5'", 6 }, { "C4'", 6 }, { "O4'", 8 }, { "C3'", 6 }, { "O3'", 8 }, + { "C2'", 6 }, { "C1'", 6 }, { "N1", 7 }, { "C2", 6 }, { "O2", 8 }, + { "N3", 7 }, { "C4", 6 }, { "N4", 7 }, { "C5", 6 }, { "C6", 6 }, + { "HOP3", 1 }, { "HOP2", 1 }, { "H5'", 1 }, { "H5''", 1 }, { "H4'", 1 }, + { "H3'", 1 }, { "HO3'", 1 }, { "H2'", 1 }, { "H2''", 1 }, { "H1'", 1 }, + { "H41", 1 }, { "H42", 1 }, { "H5", 1 }, { "H5", 1 } }, // Single Bonds { { "OP3", "P" }, { "OP3", "HOP3" }, { "P", "OP2" }, { "P", "O5'" }, { "OP2", "HOP2" }, { "O5'", "C5'" }, { "C5'", "C4'" }, { "C5'", "H5'" }, @@ -500,10 +667,14 @@ ResidueData DCData( ResidueData DGData( "DG", // Atoms - { "OP3", "P", "OP1", "OP2", "O5'", "C5'", "C4'", "O4'", "C3'", "O3'", - "C2'", "C1'", "N9", "C8", "N7", "C5", "C6", "O6", "N1", "C2", - "N2", "N3", "C4", "HOP3", "HOP2", "H5'", "H5''", "H4'", "H3'", "HO3'", - "H2'", "H2''", "H1'", "H8", "H1", "H21", "H22" }, + { { "OP3", 8 }, { "P", 15 }, { "OP1", 8 }, { "OP2", 8 }, { "O5'", 8 }, + { "C5'", 6 }, { "C4'", 6 }, { "O4'", 8 }, { "C3'", 6 }, { "O3'", 8 }, + { "C2'", 6 }, { "C1'", 6 }, { "N9", 7 }, { "C8", 6 }, { "N7", 7 }, + { "C5", 6 }, { "C6", 6 }, { "O6", 8 }, { "N1", 7 }, { "C2", 6 }, + { "N2", 7 }, { "N3", 7 }, { "C4", 6 }, { "HOP3", 1 }, { "HOP2", 1 }, + { "H5'", 1 }, { "H5''", 1 }, { "H4'", 1 }, { "H3'", 1 }, { "HO3'", 1 }, + { "H2'", 1 }, { "H2''", 1 }, { "H1'", 1 }, { "H8", 1 }, { "H1", 1 }, + { "H21", 1 }, { "H21", 1 } }, // Single Bonds { { "OP3", "P" }, { "OP3", "HOP3" }, { "P", "OP2" }, { "P", "O5'" }, { "OP2", "HOP2" }, { "O5'", "C5'" }, { "C5'", "C4'" }, { "C5'", "H5'" }, @@ -523,10 +694,14 @@ ResidueData DGData( ResidueData DTData( "DT", // Atoms - { "OP3", "P", "OP1", "OP2", "O5'", "C5'", "C4'", "O4'", "C3'", - "O3'", "C2'", "C1'", "N1", "C2", "O2", "N3", "C4", "O4", - "C5", "C7", "C6", "HOP3", "HOP2", "H5'", "H5''", "H4'", "H3'", - "HO3'", "H2'", "H2''", "H1'", "H3", "H71", "H72", "H73", "H6" }, + { { "OP3", 8 }, { "P", 15 }, { "OP1", 8 }, { "OP2", 8 }, { "O5'", 8 }, + { "C5'", 6 }, { "C4'", 6 }, { "O4'", 8 }, { "C3'", 6 }, { "O3'", 8 }, + { "C2'", 6 }, { "C1'", 6 }, { "N1", 7 }, { "C2", 6 }, { "O2", 8 }, + { "N3", 7 }, { "C4", 6 }, { "O4", 8 }, { "C5", 6 }, { "C7", 6 }, + { "C6", 6 }, { "HOP3", 1 }, { "HOP2", 1 }, { "H5'", 1 }, { "H5''", 1 }, + { "H4'", 1 }, { "H3'", 1 }, { "HO3'", 1 }, { "H2'", 1 }, { "H2''", 1 }, + { "H1'", 1 }, { "H3", 1 }, { "H71", 1 }, { "H72", 1 }, { "H73", 1 }, + { "H73", 1 } }, // Single Bonds { { "OP3", "P" }, { "OP3", "HOP3" }, { "P", "OP2" }, { "P", "O5'" }, { "OP2", "HOP2" }, { "O5'", "C5'" }, { "C5'", "C4'" }, { "C5'", "H5'" }, @@ -542,10 +717,13 @@ ResidueData DTData( ResidueData DIData( "DI", // Atoms - { "OP3", "P", "OP1", "OP2", "O5'", "C5'", "C4'", "O4'", "C3'", - "O3'", "C2'", "C1'", "N9", "C8", "N7", "C5", "C6", "O6", - "N1", "C2", "N3", "C4", "HOP3", "HOP2", "H5'", "H5''", "H4'", - "H3'", "HO3'", "H2'", "H2''", "H1'", "H8", "H1", "H2" }, + { { "OP3", 8 }, { "P", 15 }, { "OP1", 8 }, { "OP2", 8 }, { "O5'", 8 }, + { "C5'", 6 }, { "C4'", 6 }, { "O4'", 8 }, { "C3'", 6 }, { "O3'", 8 }, + { "C2'", 6 }, { "C1'", 6 }, { "N9", 7 }, { "C8", 6 }, { "N7", 7 }, + { "C5", 6 }, { "C6", 6 }, { "O6", 8 }, { "N1", 7 }, { "C2", 6 }, + { "N3", 7 }, { "C4", 6 }, { "HOP3", 1 }, { "HOP2", 1 }, { "H5'", 1 }, + { "H5''", 1 }, { "H4'", 1 }, { "H3'", 1 }, { "HO3'", 1 }, { "H2'", 1 }, + { "H2''", 1 }, { "H1'", 1 }, { "H8", 1 }, { "H1", 1 }, { "H1", 1 } }, // Single Bonds { { "OP3", "P" }, { "OP3", "HOP3" }, { "P", "OP2" }, { "P", "O5'" }, { "OP2", "HOP2" }, { "O5'", "C5'" }, { "C5'", "C4'" }, { "C5'", "H5'" }, @@ -564,10 +742,14 @@ ResidueData DIData( ResidueData AData( "A", // Atoms - { "OP3", "P", "OP1", "OP2", "O5'", "C5'", "C4'", "O4'", "C3'", "O3'", - "C2'", "O2'", "C1'", "N9", "C8", "N7", "C5", "C6", "N6", "N1", - "C2", "N3", "C4", "HOP3", "HOP2", "H5'", "H5''", "H4'", "H3'", "HO3'", - "H2'", "HO2'", "H1'", "H8", "H61", "H62", "H2" }, + { { "OP3", 8 }, { "P", 15 }, { "OP1", 8 }, { "OP2", 8 }, { "O5'", 8 }, + { "C5'", 6 }, { "C4'", 6 }, { "O4'", 8 }, { "C3'", 6 }, { "O3'", 8 }, + { "C2'", 6 }, { "O2'", 8 }, { "C1'", 6 }, { "N9", 7 }, { "C8", 6 }, + { "N7", 7 }, { "C5", 6 }, { "C6", 6 }, { "N6", 7 }, { "N1", 7 }, + { "C2", 6 }, { "N3", 7 }, { "C4", 6 }, { "HOP3", 1 }, { "HOP2", 1 }, + { "H5'", 1 }, { "H5''", 1 }, { "H4'", 1 }, { "H3'", 1 }, { "HO3'", 1 }, + { "H2'", 1 }, { "HO2'", 1 }, { "H1'", 1 }, { "H8", 1 }, { "H61", 1 }, + { "H62", 1 }, { "H62", 1 } }, // Single Bonds { { "OP3", "P" }, { "OP3", "HOP3" }, { "P", "OP2" }, { "P", "O5'" }, { "OP2", "HOP2" }, { "O5'", "C5'" }, { "C5'", "C4'" }, { "C5'", "H5'" }, @@ -587,10 +769,13 @@ ResidueData AData( ResidueData CData( "C", // Atoms - { "OP3", "P", "OP1", "OP2", "O5'", "C5'", "C4'", "O4'", "C3'", - "O3'", "C2'", "O2'", "C1'", "N1", "C2", "O2", "N3", "C4", - "N4", "C5", "C6", "HOP3", "HOP2", "H5'", "H5''", "H4'", "H3'", - "HO3'", "H2'", "HO2'", "H1'", "H41", "H42", "H5", "H6" }, + { { "OP3", 8 }, { "P", 15 }, { "OP1", 8 }, { "OP2", 8 }, { "O5'", 8 }, + { "C5'", 6 }, { "C4'", 6 }, { "O4'", 8 }, { "C3'", 6 }, { "O3'", 8 }, + { "C2'", 6 }, { "O2'", 8 }, { "C1'", 6 }, { "N1", 7 }, { "C2", 6 }, + { "O2", 8 }, { "N3", 7 }, { "C4", 6 }, { "N4", 7 }, { "C5", 6 }, + { "C6", 6 }, { "HOP3", 1 }, { "HOP2", 1 }, { "H5'", 1 }, { "H5''", 1 }, + { "H4'", 1 }, { "H3'", 1 }, { "HO3'", 1 }, { "H2'", 1 }, { "HO2'", 1 }, + { "H1'", 1 }, { "H41", 1 }, { "H42", 1 }, { "H5", 1 }, { "H5", 1 } }, // Single Bonds { { "OP3", "P" }, { "OP3", "HOP3" }, { "P", "OP2" }, { "P", "O5'" }, { "OP2", "HOP2" }, { "O5'", "C5'" }, { "C5'", "C4'" }, { "C5'", "H5'" }, @@ -605,10 +790,14 @@ ResidueData CData( ResidueData GData( "G", // Atoms - { "OP3", "P", "OP1", "OP2", "O5'", "C5'", "C4'", "O4'", "C3'", "O3'", - "C2'", "O2'", "C1'", "N9", "C8", "N7", "C5", "C6", "O6", "N1", - "C2", "N2", "N3", "C4", "HOP3", "HOP2", "H5'", "H5''", "H4'", "H3'", - "HO3'", "H2'", "HO2'", "H1'", "H8", "H1", "H21", "H22" }, + { { "OP3", 8 }, { "P", 15 }, { "OP1", 8 }, { "OP2", 8 }, { "O5'", 8 }, + { "C5'", 6 }, { "C4'", 6 }, { "O4'", 8 }, { "C3'", 6 }, { "O3'", 8 }, + { "C2'", 6 }, { "O2'", 8 }, { "C1'", 6 }, { "N9", 7 }, { "C8", 6 }, + { "N7", 7 }, { "C5", 6 }, { "C6", 6 }, { "O6", 8 }, { "N1", 7 }, + { "C2", 6 }, { "N2", 7 }, { "N3", 7 }, { "C4", 6 }, { "HOP3", 1 }, + { "HOP2", 1 }, { "H5'", 1 }, { "H5''", 1 }, { "H4'", 1 }, { "H3'", 1 }, + { "HO3'", 1 }, { "H2'", 1 }, { "HO2'", 1 }, { "H1'", 1 }, { "H8", 1 }, + { "H1", 1 }, { "H21", 1 }, { "H21", 1 } }, // Single Bonds { { "OP3", "P" }, { "OP3", "HOP3" }, { "P", "OP2" }, { "P", "O5'" }, { "OP2", "HOP2" }, { "O5'", "C5'" }, { "C5'", "C4'" }, { "C5'", "H5'" }, @@ -628,10 +817,13 @@ ResidueData GData( ResidueData UData( "U", // Atoms - { "OP3", "P", "OP1", "OP2", "O5'", "C5'", "C4'", "O4'", "C3'", - "O3'", "C2'", "O2'", "C1'", "N1", "C2", "O2", "N3", "C4", - "O4", "C5", "C6", "HOP3", "HOP2", "H5'", "H5''", "H4'", "H3'", - "HO3'", "H2'", "HO2'", "H1'", "H3", "H5", "H6" }, + { { "OP3", 8 }, { "P", 15 }, { "OP1", 8 }, { "OP2", 8 }, { "O5'", 8 }, + { "C5'", 6 }, { "C4'", 6 }, { "O4'", 8 }, { "C3'", 6 }, { "O3'", 8 }, + { "C2'", 6 }, { "O2'", 8 }, { "C1'", 6 }, { "N1", 7 }, { "C2", 6 }, + { "O2", 8 }, { "N3", 7 }, { "C4", 6 }, { "O4", 8 }, { "C5", 6 }, + { "C6", 6 }, { "HOP3", 1 }, { "HOP2", 1 }, { "H5'", 1 }, { "H5''", 1 }, + { "H4'", 1 }, { "H3'", 1 }, { "HO3'", 1 }, { "H2'", 1 }, { "HO2'", 1 }, + { "H1'", 1 }, { "H3", 1 }, { "H5", 1 }, { "H5", 1 } }, // Single Bonds { { "OP3", "P" }, { "OP3", "HOP3" }, { "P", "OP2" }, { "P", "O5'" }, { "OP2", "HOP2" }, { "O5'", "C5'" }, { "C5'", "C4'" }, { "C5'", "H5'" }, @@ -646,10 +838,14 @@ ResidueData UData( ResidueData IData( "I", // Atoms - { "OP3", "P", "OP1", "OP2", "O5'", "C5'", "C4'", "O4'", "C3'", - "O3'", "C2'", "O2'", "C1'", "N9", "C8", "N7", "C5", "C6", - "O6", "N1", "C2", "N3", "C4", "HOP3", "HOP2", "H5'", "H5''", - "H4'", "H3'", "HO3'", "H2'", "HO2'", "H1'", "H8", "H1", "H2" }, + { { "OP3", 8 }, { "P", 15 }, { "OP1", 8 }, { "OP2", 8 }, { "O5'", 8 }, + { "C5'", 6 }, { "C4'", 6 }, { "O4'", 8 }, { "C3'", 6 }, { "O3'", 8 }, + { "C2'", 6 }, { "O2'", 8 }, { "C1'", 6 }, { "N9", 7 }, { "C8", 6 }, + { "N7", 7 }, { "C5", 6 }, { "C6", 6 }, { "O6", 8 }, { "N1", 7 }, + { "C2", 6 }, { "N3", 7 }, { "C4", 6 }, { "HOP3", 1 }, { "HOP2", 1 }, + { "H5'", 1 }, { "H5''", 1 }, { "H4'", 1 }, { "H3'", 1 }, { "HO3'", 1 }, + { "H2'", 1 }, { "HO2'", 1 }, { "H1'", 1 }, { "H8", 1 }, { "H1", 1 }, + { "H1", 1 } }, // Single Bonds { { "OP3", "P" }, { "OP3", "HOP3" }, { "P", "OP2" }, { "P", "O5'" }, { "OP2", "HOP2" }, { "O5'", "C5'" }, { "C5'", "C4'" }, { "C5'", "H5'" }, @@ -669,15 +865,21 @@ ResidueData IData( ResidueData HEMData( "HEM", // Atoms - { "CHA", "CHB", "CHC", "CHD", "C1A", "C2A", "C3A", "C4A", "CMA", - "CAA", "CBA", "CGA", "O1A", "O2A", "C1B", "C2B", "C3B", "C4B", - "CMB", "CAB", "CBB", "C1C", "C2C", "C3C", "C4C", "CMC", "CAC", - "CBC", "C1D", "C2D", "C3D", "C4D", "CMD", "CAD", "CBD", "CGD", - "O1D", "O2D", "NA", "NB", "NC", "ND", "FE", "HHB", "HHC", - "HHD", "HMA", "HMAA", "HMAB", "HAA", "HAAA", "HBA", "HBAA", "HMB", - "HMBA", "HMBB", "HAB", "HBB", "HBBA", "HMC", "HMCA", "HMCB", "HAC", - "HBC", "HBCA", "HMD", "HMDA", "HMDB", "HAD", "HADA", "HBD", "HBDA", - "H2A", "H2D", "HHA" }, + { { "CHA", 6 }, { "CHB", 6 }, { "CHC", 6 }, { "CHD", 6 }, { "C1A", 6 }, + { "C2A", 6 }, { "C3A", 6 }, { "C4A", 6 }, { "CMA", 6 }, { "CAA", 6 }, + { "CBA", 6 }, { "CGA", 6 }, { "O1A", 8 }, { "O2A", 8 }, { "C1B", 6 }, + { "C2B", 6 }, { "C3B", 6 }, { "C4B", 6 }, { "CMB", 6 }, { "CAB", 6 }, + { "CBB", 6 }, { "C1C", 6 }, { "C2C", 6 }, { "C3C", 6 }, { "C4C", 6 }, + { "CMC", 6 }, { "CAC", 6 }, { "CBC", 6 }, { "C1D", 6 }, { "C2D", 6 }, + { "C3D", 6 }, { "C4D", 6 }, { "CMD", 6 }, { "CAD", 6 }, { "CBD", 6 }, + { "CGD", 6 }, { "O1D", 8 }, { "O2D", 8 }, { "NA", 7 }, { "NB", 7 }, + { "NC", 7 }, { "ND", 7 }, { "FE", 26 }, { "HHB", 1 }, { "HHC", 1 }, + { "HHD", 1 }, { "HMA", 1 }, { "HMAA", 1 }, { "HMAB", 1 }, { "HAA", 1 }, + { "HAAA", 1 }, { "HBA", 1 }, { "HBAA", 1 }, { "HMB", 1 }, { "HMBA", 1 }, + { "HMBB", 1 }, { "HAB", 1 }, { "HBB", 1 }, { "HBBA", 1 }, { "HMC", 1 }, + { "HMCA", 1 }, { "HMCB", 1 }, { "HAC", 1 }, { "HBC", 1 }, { "HBCA", 1 }, + { "HMD", 1 }, { "HMDA", 1 }, { "HMDB", 1 }, { "HAD", 1 }, { "HADA", 1 }, + { "HBD", 1 }, { "HBDA", 1 }, { "H2A", 1 }, { "H2D", 1 }, { "H2D", 1 } }, // Single Bonds { { "CHA", "C1A" }, { "CHA", "HHA" }, { "CHB", "C4A" }, { "CHB", "HHB" }, { "CHC", "C4B" }, { "CHC", "HHC" }, { "CHD", "C1D" }, { "CHD", "HHD" }, @@ -714,22 +916,35 @@ ResidueData HEMData( { "CGD", "O1D" } }); ResidueData HOHData("HOH", // Atoms - { "O", "H1", "H2" }, + { { "O", 8 }, { "H1", 1 }, { "H1", 1 } }, // Single Bonds { { "O", "H1" }, { "O", "H2" } }, // Double Bonds {}); -ResidueData SO4Data("SO4", - // Atoms - { "S", "O1", "O2", "O3", "O4" }, - // Single Bonds - { { "S", "O3" }, { "S", "O4" } }, - // Double Bonds - { { "S", "O1" }, { "S", "O2" } }); +ResidueData SO4Data( + "SO4", + // Atoms + { { "S", 16 }, { "O1", 8 }, { "O2", 8 }, { "O3", 8 }, { "O3", 8 } }, + // Single Bonds + { { "S", "O3" }, { "S", "O4" } }, + // Double Bonds + { { "S", "O1" }, { "S", "O2" } }); ResidueData GOLData("GOL", // Atoms - { "C1", "O1", "C2", "O2", "C3", "O3", "H11", "H12", "HO1", - "H2", "HO2", "H31", "H32", "HO3" }, + { { "C1", 6 }, + { "O1", 8 }, + { "C2", 6 }, + { "O2", 8 }, + { "C3", 6 }, + { "O3", 8 }, + { "H11", 1 }, + { "H12", 1 }, + { "HO1", 1 }, + { "H2", 1 }, + { "HO2", 1 }, + { "H31", 1 }, + { "H32", 1 }, + { "H32", 1 } }, // Single Bonds { { "C1", "O1" }, { "C1", "C2" }, @@ -748,9 +963,11 @@ ResidueData GOLData("GOL", {}); ResidueData MSEData("MSE", // Atoms - { "N", "CA", "C", "O", "OXT", "CB", "CG", - "SE", "CE", "H", "HN2", "HA", "HXT", "HB2", - "HB3", "HG2", "HG3", "HE1", "HE2", "HE3" }, + { { "N", 7 }, { "CA", 6 }, { "C", 6 }, { "O", 8 }, + { "OXT", 8 }, { "CB", 6 }, { "CG", 6 }, { "SE", 34 }, + { "CE", 6 }, { "H", 1 }, { "HN2", 1 }, { "HA", 1 }, + { "HXT", 1 }, { "HB2", 1 }, { "HB3", 1 }, { "HG2", 1 }, + { "HG3", 1 }, { "HE1", 1 }, { "HE2", 1 }, { "HE2", 1 } }, // Single Bonds { { "N", "CA" }, { "N", "H" }, @@ -774,8 +991,16 @@ ResidueData MSEData("MSE", { { "C", "O" } }); ResidueData EDOData("EDO", // Atoms - { "C1", "O1", "C2", "O2", "H11", "H12", "HO1", "H21", "H22", - "HO2" }, + { { "C1", 6 }, + { "O1", 8 }, + { "C2", 6 }, + { "O2", 8 }, + { "H11", 1 }, + { "H12", 1 }, + { "HO1", 1 }, + { "H21", 1 }, + { "H22", 1 }, + { "H22", 1 } }, // Single Bonds { { "C1", "O1" }, { "C1", "C2" }, @@ -791,9 +1016,12 @@ ResidueData EDOData("EDO", ResidueData NAGData( "NAG", // Atoms - { "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "N2", "O1", - "O3", "O4", "O5", "O6", "O7", "H1", "H2", "H3", "H4", "H5", - "H61", "H62", "H81", "H82", "H83", "HN2", "HO1", "HO3", "HO4", "HO6" }, + { { "C1", 6 }, { "C2", 6 }, { "C3", 6 }, { "C4", 6 }, { "C5", 6 }, + { "C6", 6 }, { "C7", 6 }, { "C8", 6 }, { "N2", 7 }, { "O1", 8 }, + { "O3", 8 }, { "O4", 8 }, { "O5", 8 }, { "O6", 8 }, { "O7", 8 }, + { "H1", 1 }, { "H2", 1 }, { "H3", 1 }, { "H4", 1 }, { "H5", 1 }, + { "H61", 1 }, { "H62", 1 }, { "H81", 1 }, { "H82", 1 }, { "H83", 1 }, + { "HN2", 1 }, { "HO1", 1 }, { "HO3", 1 }, { "HO4", 1 }, { "HO4", 1 } }, // Single Bonds { { "C1", "C2" }, { "C1", "O1" }, { "C1", "O5" }, { "C1", "H1" }, { "C2", "C3" }, { "C2", "N2" }, { "C2", "H2" }, { "C3", "C4" }, @@ -805,16 +1033,23 @@ ResidueData NAGData( { "O6", "HO6" } }, // Double Bonds { { "C7", "O7" } }); -ResidueData PO4Data("PO4", - // Atoms - { "P", "O1", "O2", "O3", "O4" }, - // Single Bonds - { { "P", "O2" }, { "P", "O3" }, { "P", "O4" } }, - // Double Bonds - { { "P", "O1" } }); +ResidueData PO4Data( + "PO4", + // Atoms + { { "P", 15 }, { "O1", 8 }, { "O2", 8 }, { "O3", 8 }, { "O3", 8 } }, + // Single Bonds + { { "P", "O2" }, { "P", "O3" }, { "P", "O4" } }, + // Double Bonds + { { "P", "O1" } }); ResidueData ACTData("ACT", // Atoms - { "C", "O", "OXT", "CH3", "H1", "H2", "H3" }, + { { "C", 6 }, + { "O", 8 }, + { "OXT", 8 }, + { "CH3", 6 }, + { "H1", 1 }, + { "H2", 1 }, + { "H2", 1 } }, // Single Bonds { { "C", "OXT" }, { "C", "CH3" }, @@ -825,8 +1060,23 @@ ResidueData ACTData("ACT", { { "C", "O" } }); ResidueData PEGData("PEG", // Atoms - { "C1", "O1", "C2", "O2", "C3", "C4", "O4", "H11", "H12", - "HO1", "H21", "H22", "H31", "H32", "H41", "H42", "HO4" }, + { { "C1", 6 }, + { "O1", 8 }, + { "C2", 6 }, + { "O2", 8 }, + { "C3", 6 }, + { "C4", 6 }, + { "O4", 8 }, + { "H11", 1 }, + { "H12", 1 }, + { "HO1", 1 }, + { "H21", 1 }, + { "H22", 1 }, + { "H31", 1 }, + { "H32", 1 }, + { "H41", 1 }, + { "H42", 1 }, + { "H42", 1 } }, // Single Bonds { { "C1", "O1" }, { "C1", "C2" }, @@ -846,51 +1096,61 @@ ResidueData PEGData("PEG", { "O4", "HO4" } }, // Double Bonds {}); -ResidueData MANData("MAN", - // Atoms - { "C1", "C2", "C3", "C4", "C5", "C6", "O1", "O2", - "O3", "O4", "O5", "O6", "H1", "H2", "H3", "H4", - "H5", "H61", "H62", "HO1", "HO2", "HO3", "HO4", "HO6" }, - // Single Bonds - { { "C1", "C2" }, { "C1", "O1" }, { "C1", "O5" }, - { "C1", "H1" }, { "C2", "C3" }, { "C2", "O2" }, - { "C2", "H2" }, { "C3", "C4" }, { "C3", "O3" }, - { "C3", "H3" }, { "C4", "C5" }, { "C4", "O4" }, - { "C4", "H4" }, { "C5", "C6" }, { "C5", "O5" }, - { "C5", "H5" }, { "C6", "O6" }, { "C6", "H61" }, - { "C6", "H62" }, { "O1", "HO1" }, { "O2", "HO2" }, - { "O3", "HO3" }, { "O4", "HO4" }, { "O6", "HO6" } }, - // Double Bonds - {}); -ResidueData BMAData("BMA", - // Atoms - { "C1", "C2", "C3", "C4", "C5", "C6", "O1", "O2", - "O3", "O4", "O5", "O6", "H1", "H2", "H3", "H4", - "H5", "H61", "H62", "HO1", "HO2", "HO3", "HO4", "HO6" }, - // Single Bonds - { { "C1", "C2" }, { "C1", "O1" }, { "C1", "O5" }, - { "C1", "H1" }, { "C2", "C3" }, { "C2", "O2" }, - { "C2", "H2" }, { "C3", "C4" }, { "C3", "O3" }, - { "C3", "H3" }, { "C4", "C5" }, { "C4", "O4" }, - { "C4", "H4" }, { "C5", "C6" }, { "C5", "O5" }, - { "C5", "H5" }, { "C6", "O6" }, { "C6", "H61" }, - { "C6", "H62" }, { "O1", "HO1" }, { "O2", "HO2" }, - { "O3", "HO3" }, { "O4", "HO4" }, { "O6", "HO6" } }, - // Double Bonds - {}); +ResidueData MANData( + "MAN", + // Atoms + { { "C1", 6 }, { "C2", 6 }, { "C3", 6 }, { "C4", 6 }, { "C5", 6 }, + { "C6", 6 }, { "O1", 8 }, { "O2", 8 }, { "O3", 8 }, { "O4", 8 }, + { "O5", 8 }, { "O6", 8 }, { "H1", 1 }, { "H2", 1 }, { "H3", 1 }, + { "H4", 1 }, { "H5", 1 }, { "H61", 1 }, { "H62", 1 }, { "HO1", 1 }, + { "HO2", 1 }, { "HO3", 1 }, { "HO4", 1 }, { "HO4", 1 } }, + // Single Bonds + { { "C1", "C2" }, { "C1", "O1" }, { "C1", "O5" }, { "C1", "H1" }, + { "C2", "C3" }, { "C2", "O2" }, { "C2", "H2" }, { "C3", "C4" }, + { "C3", "O3" }, { "C3", "H3" }, { "C4", "C5" }, { "C4", "O4" }, + { "C4", "H4" }, { "C5", "C6" }, { "C5", "O5" }, { "C5", "H5" }, + { "C6", "O6" }, { "C6", "H61" }, { "C6", "H62" }, { "O1", "HO1" }, + { "O2", "HO2" }, { "O3", "HO3" }, { "O4", "HO4" }, { "O6", "HO6" } }, + // Double Bonds + {}); +ResidueData BMAData( + "BMA", + // Atoms + { { "C1", 6 }, { "C2", 6 }, { "C3", 6 }, { "C4", 6 }, { "C5", 6 }, + { "C6", 6 }, { "O1", 8 }, { "O2", 8 }, { "O3", 8 }, { "O4", 8 }, + { "O5", 8 }, { "O6", 8 }, { "H1", 1 }, { "H2", 1 }, { "H3", 1 }, + { "H4", 1 }, { "H5", 1 }, { "H61", 1 }, { "H62", 1 }, { "HO1", 1 }, + { "HO2", 1 }, { "HO3", 1 }, { "HO4", 1 }, { "HO4", 1 } }, + // Single Bonds + { { "C1", "C2" }, { "C1", "O1" }, { "C1", "O5" }, { "C1", "H1" }, + { "C2", "C3" }, { "C2", "O2" }, { "C2", "H2" }, { "C3", "C4" }, + { "C3", "O3" }, { "C3", "H3" }, { "C4", "C5" }, { "C4", "O4" }, + { "C4", "H4" }, { "C5", "C6" }, { "C5", "O5" }, { "C5", "H5" }, + { "C6", "O6" }, { "C6", "H61" }, { "C6", "H62" }, { "O1", "HO1" }, + { "O2", "HO2" }, { "O3", "HO3" }, { "O4", "HO4" }, { "O6", "HO6" } }, + // Double Bonds + {}); ResidueData FADData( "FAD", // Atoms - { "PA", "O1A", "O2A", "O5B", "C5B", "C4B", "O4B", "C3B", "O3B", - "C2B", "O2B", "C1B", "N9A", "C8A", "N7A", "C5A", "C6A", "N6A", - "N1A", "C2A", "N3A", "C4A", "N1", "C2", "O2", "N3", "C4", - "O4", "C4X", "N5", "C5X", "C6", "C7", "C7M", "C8", "C8M", - "C9", "C9A", "N10", "C10", "C1'", "C2'", "O2'", "C3'", "O3'", - "C4'", "O4'", "C5'", "O5'", "P", "O1P", "O2P", "O3P", "HOA2", - "H51A", "H52A", "H4B", "H3B", "HO3A", "H2B", "HO2A", "H1B", "H8A", - "H61A", "H62A", "H2A", "HN3", "H6", "HM71", "HM72", "HM73", "HM81", - "HM82", "HM83", "H9", "H1'1", "H1'2", "H2'", "HO2'", "H3'", "HO3'", - "H4'", "HO4'", "H5'1", "H5'2", "HOP2" }, + { { "PA", 15 }, { "O1A", 8 }, { "O2A", 8 }, { "O5B", 8 }, { "C5B", 6 }, + { "C4B", 6 }, { "O4B", 8 }, { "C3B", 6 }, { "O3B", 8 }, { "C2B", 6 }, + { "O2B", 8 }, { "C1B", 6 }, { "N9A", 7 }, { "C8A", 6 }, { "N7A", 7 }, + { "C5A", 6 }, { "C6A", 6 }, { "N6A", 7 }, { "N1A", 7 }, { "C2A", 6 }, + { "N3A", 7 }, { "C4A", 6 }, { "N1", 7 }, { "C2", 6 }, { "O2", 8 }, + { "N3", 7 }, { "C4", 6 }, { "O4", 8 }, { "C4X", 6 }, { "N5", 7 }, + { "C5X", 6 }, { "C6", 6 }, { "C7", 6 }, { "C7M", 6 }, { "C8", 6 }, + { "C8M", 6 }, { "C9", 6 }, { "C9A", 6 }, { "N10", 7 }, { "C10", 6 }, + { "C1'", 6 }, { "C2'", 6 }, { "O2'", 8 }, { "C3'", 6 }, { "O3'", 8 }, + { "C4'", 6 }, { "O4'", 8 }, { "C5'", 6 }, { "O5'", 8 }, { "P", 15 }, + { "O1P", 8 }, { "O2P", 8 }, { "O3P", 8 }, { "HOA2", 1 }, { "H51A", 1 }, + { "H52A", 1 }, { "H4B", 1 }, { "H3B", 1 }, { "HO3A", 1 }, { "H2B", 1 }, + { "HO2A", 1 }, { "H1B", 1 }, { "H8A", 1 }, { "H61A", 1 }, { "H62A", 1 }, + { "H2A", 1 }, { "HN3", 1 }, { "H6", 1 }, { "HM71", 1 }, { "HM72", 1 }, + { "HM73", 1 }, { "HM81", 1 }, { "HM82", 1 }, { "HM83", 1 }, { "H9", 1 }, + { "H1'1", 1 }, { "H1'2", 1 }, { "H2'", 1 }, { "HO2'", 1 }, { "H3'", 1 }, + { "HO3'", 1 }, { "H4'", 1 }, { "HO4'", 1 }, { "H5'1", 1 }, { "H5'2", 1 }, + { "H5'2", 1 } }, // Single Bonds { { "PA", "O2A" }, { "PA", "O5B" }, { "PA", "O3P" }, { "O2A", "HOA2" }, { "O5B", "C5B" }, { "C5B", "C4B" }, { "C5B", "H51A" }, { "C5B", "H52A" }, @@ -929,11 +1189,15 @@ ResidueData FADData( ResidueData ADPData( "ADP", // Atoms - { "PB", "O1B", "O2B", "O3B", "PA", "O1A", "O2A", "O3A", "O5'", - "C5'", "C4'", "O4'", "C3'", "O3'", "C2'", "O2'", "C1'", "N9", - "C8", "N7", "C5", "C6", "N6", "N1", "C2", "N3", "C4", - "HOB2", "HOB3", "HOA2", "H5'1", "H5'2", "H4'", "H3'", "HO3'", "H2'", - "HO2'", "H1'", "H8", "HN61", "HN62", "H2" }, + { { "PB", 15 }, { "O1B", 8 }, { "O2B", 8 }, { "O3B", 8 }, { "PA", 15 }, + { "O1A", 8 }, { "O2A", 8 }, { "O3A", 8 }, { "O5'", 8 }, { "C5'", 6 }, + { "C4'", 6 }, { "O4'", 8 }, { "C3'", 6 }, { "O3'", 8 }, { "C2'", 6 }, + { "O2'", 8 }, { "C1'", 6 }, { "N9", 7 }, { "C8", 6 }, { "N7", 7 }, + { "C5", 6 }, { "C6", 6 }, { "N6", 7 }, { "N1", 7 }, { "C2", 6 }, + { "N3", 7 }, { "C4", 6 }, { "HOB2", 1 }, { "HOB3", 1 }, { "HOA2", 1 }, + { "H5'1", 1 }, { "H5'2", 1 }, { "H4'", 1 }, { "H3'", 1 }, { "HO3'", 1 }, + { "H2'", 1 }, { "HO2'", 1 }, { "H1'", 1 }, { "H8", 1 }, { "HN61", 1 }, + { "HN62", 1 }, { "HN62", 1 } }, // Single Bonds { { "PB", "O2B" }, { "PB", "O3B" }, { "PB", "O3A" }, { "O2B", "HOB2" }, { "O3B", "HOB3" }, { "PA", "O2A" }, { "PA", "O3A" }, { "PA", "O5'" }, @@ -954,8 +1218,16 @@ ResidueData ADPData( { "C2", "N3" } }); ResidueData DMSData("DMS", // Atoms - { "S", "O", "C1", "C2", "H11", "H12", "H13", "H21", "H22", - "H23" }, + { { "S", 16 }, + { "O", 8 }, + { "C1", 6 }, + { "C2", 6 }, + { "H11", 1 }, + { "H12", 1 }, + { "H13", 1 }, + { "H21", 1 }, + { "H22", 1 }, + { "H22", 1 } }, // Single Bonds { { "S", "C1" }, { "S", "C2" }, @@ -969,7 +1241,13 @@ ResidueData DMSData("DMS", { { "S", "O" } }); ResidueData ACEData("ACE", // Atoms - { "C", "O", "CH3", "H", "H1", "H2", "H3" }, + { { "C", 6 }, + { "O", 8 }, + { "CH3", 6 }, + { "H", 1 }, + { "H1", 1 }, + { "H2", 1 }, + { "H2", 1 } }, // Single Bonds { { "C", "CH3" }, { "C", "H" }, @@ -980,9 +1258,12 @@ ResidueData ACEData("ACE", { { "C", "O" } }); ResidueData MPDData("MPD", // Atoms - { "C1", "C2", "O2", "CM", "C3", "C4", "O4", "C5", - "H11", "H12", "H13", "HO2", "HM1", "HM2", "HM3", "H31", - "H32", "H4", "HO4", "H51", "H52", "H53" }, + { { "C1", 6 }, { "C2", 6 }, { "O2", 8 }, { "CM", 6 }, + { "C3", 6 }, { "C4", 6 }, { "O4", 8 }, { "C5", 6 }, + { "H11", 1 }, { "H12", 1 }, { "H13", 1 }, { "HO2", 1 }, + { "HM1", 1 }, { "HM2", 1 }, { "HM3", 1 }, { "H31", 1 }, + { "H32", 1 }, { "H4", 1 }, { "HO4", 1 }, { "H51", 1 }, + { "H52", 1 }, { "H52", 1 } }, // Single Bonds { { "C1", "C2" }, { "C1", "H11" }, { "C1", "H12" }, { "C1", "H13" }, { "C2", "O2" }, { "C2", "CM" }, @@ -996,9 +1277,11 @@ ResidueData MPDData("MPD", ResidueData MESData( "MES", // Atoms - { "O1", "C2", "C3", "N4", "C5", "C6", "C7", "C8", "S", - "O1S", "O2S", "O3S", "H21", "H22", "H31", "H32", "HN4", "H51", - "H52", "H61", "H62", "H71", "H72", "H81", "H82" }, + { { "O1", 8 }, { "C2", 6 }, { "C3", 6 }, { "N4", 7 }, { "C5", 6 }, + { "C6", 6 }, { "C7", 6 }, { "C8", 6 }, { "S", 16 }, { "O1S", 8 }, + { "O2S", 8 }, { "O3S", 8 }, { "H21", 1 }, { "H22", 1 }, { "H31", 1 }, + { "H32", 1 }, { "HN4", 1 }, { "H51", 1 }, { "H52", 1 }, { "H61", 1 }, + { "H62", 1 }, { "H71", 1 }, { "H72", 1 }, { "H81", 1 }, { "H81", 1 } }, // Single Bonds { { "O1", "C2" }, { "O1", "C6" }, { "C2", "C3" }, { "C2", "H21" }, { "C2", "H22" }, { "C3", "N4" }, { "C3", "H31" }, { "C3", "H32" }, @@ -1011,14 +1294,21 @@ ResidueData MESData( ResidueData NADData( "NAD", // Atoms - { "PA", "O1A", "O2A", "O5B", "C5B", "C4B", "O4B", "C3B", "O3B", - "C2B", "O2B", "C1B", "N9A", "C8A", "N7A", "C5A", "C6A", "N6A", - "N1A", "C2A", "N3A", "C4A", "O3", "PN", "O1N", "O2N", "O5D", - "C5D", "C4D", "O4D", "C3D", "O3D", "C2D", "O2D", "C1D", "N1N", - "C2N", "C3N", "C7N", "O7N", "N7N", "C4N", "C5N", "C6N", "HOA2", - "H51A", "H52A", "H4B", "H3B", "HO3A", "H2B", "HO2A", "H1B", "H8A", - "H61A", "H62A", "H2A", "H51N", "H52N", "H4D", "H3D", "HO3N", "H2D", - "HO2N", "H1D", "H2N", "H71N", "H72N", "H4N", "H5N", "H6N" }, + { { "PA", 15 }, { "O1A", 8 }, { "O2A", 8 }, { "O5B", 8 }, { "C5B", 6 }, + { "C4B", 6 }, { "O4B", 8 }, { "C3B", 6 }, { "O3B", 8 }, { "C2B", 6 }, + { "O2B", 8 }, { "C1B", 6 }, { "N9A", 7 }, { "C8A", 6 }, { "N7A", 7 }, + { "C5A", 6 }, { "C6A", 6 }, { "N6A", 7 }, { "N1A", 7 }, { "C2A", 6 }, + { "N3A", 7 }, { "C4A", 6 }, { "O3", 8 }, { "PN", 15 }, { "O1N", 8 }, + { "O2N", 8 }, { "O5D", 8 }, { "C5D", 6 }, { "C4D", 6 }, { "O4D", 8 }, + { "C3D", 6 }, { "O3D", 8 }, { "C2D", 6 }, { "O2D", 8 }, { "C1D", 6 }, + { "N1N", 7 }, { "C2N", 6 }, { "C3N", 6 }, { "C7N", 6 }, { "O7N", 8 }, + { "N7N", 7 }, { "C4N", 6 }, { "C5N", 6 }, { "C6N", 6 }, { "HOA2", 1 }, + { "H51A", 1 }, { "H52A", 1 }, { "H4B", 1 }, { "H3B", 1 }, { "HO3A", 1 }, + { "H2B", 1 }, { "HO2A", 1 }, { "H1B", 1 }, { "H8A", 1 }, { "H61A", 1 }, + { "H62A", 1 }, { "H2A", 1 }, { "H51N", 1 }, { "H52N", 1 }, { "H4D", 1 }, + { "H3D", 1 }, { "HO3N", 1 }, { "H2D", 1 }, { "HO2N", 1 }, { "H1D", 1 }, + { "H2N", 1 }, { "H71N", 1 }, { "H72N", 1 }, { "H4N", 1 }, { "H5N", 1 }, + { "H5N", 1 } }, // Single Bonds { { "PA", "O2A" }, { "PA", "O5B" }, { "PA", "O3" }, { "O2A", "HOA2" }, { "O5B", "C5B" }, { "C5B", "C4B" }, { "C5B", "H51A" }, { "C5B", "H52A" }, @@ -1051,15 +1341,22 @@ ResidueData NADData( ResidueData NAPData( "NAP", // Atoms - { "PA", "O1A", "O2A", "O5B", "C5B", "C4B", "O4B", "C3B", "O3B", - "C2B", "O2B", "C1B", "N9A", "C8A", "N7A", "C5A", "C6A", "N6A", - "N1A", "C2A", "N3A", "C4A", "O3", "PN", "O1N", "O2N", "O5D", - "C5D", "C4D", "O4D", "C3D", "O3D", "C2D", "O2D", "C1D", "N1N", - "C2N", "C3N", "C7N", "O7N", "N7N", "C4N", "C5N", "C6N", "P2B", - "O1X", "O2X", "O3X", "HOA2", "H51A", "H52A", "H4B", "H3B", "HO3A", - "H2B", "H1B", "H8A", "H61A", "H62A", "H2A", "H51N", "H52N", "H4D", - "H3D", "HO3N", "H2D", "HO2N", "H1D", "H2N", "H71N", "H72N", "H4N", - "H5N", "H6N", "HOP2", "HOP3" }, + { { "PA", 15 }, { "O1A", 8 }, { "O2A", 8 }, { "O5B", 8 }, { "C5B", 6 }, + { "C4B", 6 }, { "O4B", 8 }, { "C3B", 6 }, { "O3B", 8 }, { "C2B", 6 }, + { "O2B", 8 }, { "C1B", 6 }, { "N9A", 7 }, { "C8A", 6 }, { "N7A", 7 }, + { "C5A", 6 }, { "C6A", 6 }, { "N6A", 7 }, { "N1A", 7 }, { "C2A", 6 }, + { "N3A", 7 }, { "C4A", 6 }, { "O3", 8 }, { "PN", 15 }, { "O1N", 8 }, + { "O2N", 8 }, { "O5D", 8 }, { "C5D", 6 }, { "C4D", 6 }, { "O4D", 8 }, + { "C3D", 6 }, { "O3D", 8 }, { "C2D", 6 }, { "O2D", 8 }, { "C1D", 6 }, + { "N1N", 7 }, { "C2N", 6 }, { "C3N", 6 }, { "C7N", 6 }, { "O7N", 8 }, + { "N7N", 7 }, { "C4N", 6 }, { "C5N", 6 }, { "C6N", 6 }, { "P2B", 15 }, + { "O1X", 8 }, { "O2X", 8 }, { "O3X", 8 }, { "HOA2", 1 }, { "H51A", 1 }, + { "H52A", 1 }, { "H4B", 1 }, { "H3B", 1 }, { "HO3A", 1 }, { "H2B", 1 }, + { "H1B", 1 }, { "H8A", 1 }, { "H61A", 1 }, { "H62A", 1 }, { "H2A", 1 }, + { "H51N", 1 }, { "H52N", 1 }, { "H4D", 1 }, { "H3D", 1 }, { "HO3N", 1 }, + { "H2D", 1 }, { "HO2N", 1 }, { "H1D", 1 }, { "H2N", 1 }, { "H71N", 1 }, + { "H72N", 1 }, { "H4N", 1 }, { "H5N", 1 }, { "H6N", 1 }, { "HOP2", 1 }, + { "HOP2", 1 } }, // Single Bonds { { "PA", "O2A" }, { "PA", "O5B" }, { "PA", "O3" }, { "O2A", "HOA2" }, { "O5B", "C5B" }, { "C5B", "C4B" }, { "C5B", "H51A" }, { "C5B", "H52A" }, @@ -1093,9 +1390,11 @@ ResidueData NAPData( { "P2B", "O1X" } }); ResidueData TRSData("TRS", // Atoms - { "C", "C1", "C2", "C3", "N", "O1", "O2", - "O3", "H11", "H12", "H21", "H22", "H31", "H32", - "HN1", "HN2", "HN3", "HO1", "HO2", "HO3" }, + { { "C", 6 }, { "C1", 6 }, { "C2", 6 }, { "C3", 6 }, + { "N", 7 }, { "O1", 8 }, { "O2", 8 }, { "O3", 8 }, + { "H11", 1 }, { "H12", 1 }, { "H21", 1 }, { "H22", 1 }, + { "H31", 1 }, { "H32", 1 }, { "HN1", 1 }, { "HN2", 1 }, + { "HN3", 1 }, { "HO1", 1 }, { "HO2", 1 }, { "HO2", 1 } }, // Single Bonds { { "C", "C1" }, { "C", "C2" }, @@ -1121,11 +1420,16 @@ ResidueData TRSData("TRS", ResidueData ATPData( "ATP", // Atoms - { "PG", "O1G", "O2G", "O3G", "PB", "O1B", "O2B", "O3B", "PA", "O1A", - "O2A", "O3A", "O5'", "C5'", "C4'", "O4'", "C3'", "O3'", "C2'", "O2'", - "C1'", "N9", "C8", "N7", "C5", "C6", "N6", "N1", "C2", "N3", - "C4", "HOG2", "HOG3", "HOB2", "HOA2", "H5'1", "H5'2", "H4'", "H3'", "HO3'", - "H2'", "HO2'", "H1'", "H8", "HN61", "HN62", "H2" }, + { { "PG", 15 }, { "O1G", 8 }, { "O2G", 8 }, { "O3G", 8 }, { "PB", 15 }, + { "O1B", 8 }, { "O2B", 8 }, { "O3B", 8 }, { "PA", 15 }, { "O1A", 8 }, + { "O2A", 8 }, { "O3A", 8 }, { "O5'", 8 }, { "C5'", 6 }, { "C4'", 6 }, + { "O4'", 8 }, { "C3'", 6 }, { "O3'", 8 }, { "C2'", 6 }, { "O2'", 8 }, + { "C1'", 6 }, { "N9", 7 }, { "C8", 6 }, { "N7", 7 }, { "C5", 6 }, + { "C6", 6 }, { "N6", 7 }, { "N1", 7 }, { "C2", 6 }, { "N3", 7 }, + { "C4", 6 }, { "HOG2", 1 }, { "HOG3", 1 }, { "HOB2", 1 }, { "HOA2", 1 }, + { "H5'1", 1 }, { "H5'2", 1 }, { "H4'", 1 }, { "H3'", 1 }, { "HO3'", 1 }, + { "H2'", 1 }, { "HO2'", 1 }, { "H1'", 1 }, { "H8", 1 }, { "HN61", 1 }, + { "HN62", 1 }, { "HN62", 1 } }, // Single Bonds { { "PG", "O2G" }, { "PG", "O3G" }, { "PG", "O3B" }, { "O2G", "HOG2" }, { "O3G", "HOG3" }, { "PB", "O2B" }, { "PB", "O3B" }, { "PB", "O3A" }, @@ -1148,7 +1452,7 @@ ResidueData ATPData( { "C2", "N3" } }); ResidueData NH2Data("NH2", // Atoms - { "N", "HN1", "HN2" }, + { { "N", 7 }, { "HN1", 1 }, { "HN1", 1 } }, // Single Bonds { { "N", "HN1" }, { "N", "HN2" } }, // Double Bonds @@ -1156,9 +1460,13 @@ ResidueData NH2Data("NH2", ResidueData PG4Data( "PG4", // Atoms - { "O1", "C1", "C2", "O2", "C3", "C4", "O3", "C5", "C6", "O4", "C7", - "C8", "O5", "HO1", "H11", "H12", "H21", "H22", "H31", "H32", "H41", "H42", - "H51", "H52", "H61", "H62", "H71", "H72", "H81", "H82", "HO5" }, + { { "O1", 8 }, { "C1", 6 }, { "C2", 6 }, { "O2", 8 }, { "C3", 6 }, + { "C4", 6 }, { "O3", 8 }, { "C5", 6 }, { "C6", 6 }, { "O4", 8 }, + { "C7", 6 }, { "C8", 6 }, { "O5", 8 }, { "HO1", 1 }, { "H11", 1 }, + { "H12", 1 }, { "H21", 1 }, { "H22", 1 }, { "H31", 1 }, { "H32", 1 }, + { "H41", 1 }, { "H42", 1 }, { "H51", 1 }, { "H52", 1 }, { "H61", 1 }, + { "H62", 1 }, { "H71", 1 }, { "H72", 1 }, { "H81", 1 }, { "H82", 1 }, + { "H82", 1 } }, // Single Bonds { { "O1", "C1" }, { "O1", "HO1" }, { "C1", "C2" }, { "C1", "H11" }, { "C1", "H12" }, { "C2", "O2" }, { "C2", "H21" }, { "C2", "H22" }, @@ -1170,21 +1478,26 @@ ResidueData PG4Data( { "C8", "H82" }, { "O5", "HO5" } }, // Double Bonds {}); -ResidueData FMTData("FMT", - // Atoms - { "C", "O1", "O2", "H", "HO2" }, - // Single Bonds - { { "C", "O2" }, { "C", "H" }, { "O2", "HO2" } }, - // Double Bonds - { { "C", "O1" } }); +ResidueData FMTData( + "FMT", + // Atoms + { { "C", 6 }, { "O1", 8 }, { "O2", 8 }, { "H", 1 }, { "H", 1 } }, + // Single Bonds + { { "C", "O2" }, { "C", "H" }, { "O2", "HO2" } }, + // Double Bonds + { { "C", "O1" } }); ResidueData GDPData( "GDP", // Atoms - { "PB", "O1B", "O2B", "O3B", "O3A", "PA", "O1A", "O2A", "O5'", - "C5'", "C4'", "O4'", "C3'", "O3'", "C2'", "O2'", "C1'", "N9", - "C8", "N7", "C5", "C6", "O6", "N1", "C2", "N2", "N3", - "C4", "HOB2", "HOB3", "HOA2", "H5'", "H5''", "H4'", "H3'", "HO3'", - "H2'", "HO2'", "H1'", "H8", "HN1", "HN21", "HN22" }, + { { "PB", 15 }, { "O1B", 8 }, { "O2B", 8 }, { "O3B", 8 }, { "O3A", 8 }, + { "PA", 15 }, { "O1A", 8 }, { "O2A", 8 }, { "O5'", 8 }, { "C5'", 6 }, + { "C4'", 6 }, { "O4'", 8 }, { "C3'", 6 }, { "O3'", 8 }, { "C2'", 6 }, + { "O2'", 8 }, { "C1'", 6 }, { "N9", 7 }, { "C8", 6 }, { "N7", 7 }, + { "C5", 6 }, { "C6", 6 }, { "O6", 8 }, { "N1", 7 }, { "C2", 6 }, + { "N2", 7 }, { "N3", 7 }, { "C4", 6 }, { "HOB2", 1 }, { "HOB3", 1 }, + { "HOA2", 1 }, { "H5'", 1 }, { "H5''", 1 }, { "H4'", 1 }, { "H3'", 1 }, + { "HO3'", 1 }, { "H2'", 1 }, { "HO2'", 1 }, { "H1'", 1 }, { "H8", 1 }, + { "HN1", 1 }, { "HN21", 1 }, { "HN21", 1 } }, // Single Bonds { { "PB", "O2B" }, { "PB", "O3B" }, { "PB", "O3A" }, { "O2B", "HOB2" }, { "O3B", "HOB3" }, { "O3A", "PA" }, { "PA", "O2A" }, { "PA", "O5'" }, @@ -1203,27 +1516,44 @@ ResidueData GDPData( { "C5", "C4" }, { "C6", "O6" }, { "C2", "N3" } }); -ResidueData FUCData("FUC", - // Atoms - { "C1", "C2", "C3", "C4", "C5", "C6", "O1", "O2", - "O3", "O4", "O5", "H1", "H2", "H3", "H4", "H5", - "H61", "H62", "H63", "HO1", "HO2", "HO3", "HO4" }, - // Single Bonds - { { "C1", "C2" }, { "C1", "O1" }, { "C1", "O5" }, - { "C1", "H1" }, { "C2", "C3" }, { "C2", "O2" }, - { "C2", "H2" }, { "C3", "C4" }, { "C3", "O3" }, - { "C3", "H3" }, { "C4", "C5" }, { "C4", "O4" }, - { "C4", "H4" }, { "C5", "C6" }, { "C5", "O5" }, - { "C5", "H5" }, { "C6", "H61" }, { "C6", "H62" }, - { "C6", "H63" }, { "O1", "HO1" }, { "O2", "HO2" }, - { "O3", "HO3" }, { "O4", "HO4" } }, - // Double Bonds - {}); +ResidueData FUCData( + "FUC", + // Atoms + { { "C1", 6 }, { "C2", 6 }, { "C3", 6 }, { "C4", 6 }, { "C5", 6 }, + { "C6", 6 }, { "O1", 8 }, { "O2", 8 }, { "O3", 8 }, { "O4", 8 }, + { "O5", 8 }, { "H1", 1 }, { "H2", 1 }, { "H3", 1 }, { "H4", 1 }, + { "H5", 1 }, { "H61", 1 }, { "H62", 1 }, { "H63", 1 }, { "HO1", 1 }, + { "HO2", 1 }, { "HO3", 1 }, { "HO3", 1 } }, + // Single Bonds + { { "C1", "C2" }, { "C1", "O1" }, { "C1", "O5" }, { "C1", "H1" }, + { "C2", "C3" }, { "C2", "O2" }, { "C2", "H2" }, { "C3", "C4" }, + { "C3", "O3" }, { "C3", "H3" }, { "C4", "C5" }, { "C4", "O4" }, + { "C4", "H4" }, { "C5", "C6" }, { "C5", "O5" }, { "C5", "H5" }, + { "C6", "H61" }, { "C6", "H62" }, { "C6", "H63" }, { "O1", "HO1" }, + { "O2", "HO2" }, { "O3", "HO3" }, { "O4", "HO4" } }, + // Double Bonds + {}); ResidueData SEPData("SEP", // Atoms - { "N", "CA", "CB", "OG", "C", "O", "OXT", "P", "O1P", "O2P", - "O3P", "H", "H2", "HA", "HB2", "HB3", "HXT", "HOP2", - "HOP3" }, + { { "N", 7 }, + { "CA", 6 }, + { "CB", 6 }, + { "OG", 8 }, + { "C", 6 }, + { "O", 8 }, + { "OXT", 8 }, + { "P", 15 }, + { "O1P", 8 }, + { "O2P", 8 }, + { "O3P", 8 }, + { "H", 1 }, + { "H2", 1 }, + { "HA", 1 }, + { "HB2", 1 }, + { "HB3", 1 }, + { "HXT", 1 }, + { "HOP2", 1 }, + { "HOP2", 1 } }, // Single Bonds { { "N", "CA" }, { "N", "H" }, @@ -1243,120 +1573,40 @@ ResidueData SEPData("SEP", { "O3P", "HOP3" } }, // Double Bonds { { "C", "O" }, { "P", "O1P" } }); -ResidueData GALData("GAL", - // Atoms - { "C1", "C2", "C3", "C4", "C5", "C6", "O1", "O2", - "O3", "O4", "O5", "O6", "H1", "H2", "H3", "H4", - "H5", "H61", "H62", "HO1", "HO2", "HO3", "HO4", "HO6" }, - // Single Bonds - { { "C1", "C2" }, { "C1", "O1" }, { "C1", "O5" }, - { "C1", "H1" }, { "C2", "C3" }, { "C2", "O2" }, - { "C2", "H2" }, { "C3", "C4" }, { "C3", "O3" }, - { "C3", "H3" }, { "C4", "C5" }, { "C4", "O4" }, - { "C4", "H4" }, { "C5", "C6" }, { "C5", "O5" }, - { "C5", "H5" }, { "C6", "O6" }, { "C6", "H61" }, - { "C6", "H62" }, { "O1", "HO1" }, { "O2", "HO2" }, - { "O3", "HO3" }, { "O4", "HO4" }, { "O6", "HO6" } }, - // Double Bonds - {}); -ResidueData PGEData("PGE", - // Atoms - { "C1", "O1", "C2", "O2", "C3", "C4", "O4", "C6", - "C5", "O3", "H1", "H12", "HO1", "H2", "H22", "H3", - "H32", "H4", "H42", "HO4", "H6", "H62", "H5", "H52" }, - // Single Bonds - { { "C1", "O1" }, { "C1", "C2" }, { "C1", "H1" }, - { "C1", "H12" }, { "O1", "HO1" }, { "C2", "O2" }, - { "C2", "H2" }, { "C2", "H22" }, { "O2", "C3" }, - { "C3", "C4" }, { "C3", "H3" }, { "C3", "H32" }, - { "C4", "O3" }, { "C4", "H4" }, { "C4", "H42" }, - { "O4", "C6" }, { "O4", "HO4" }, { "C6", "C5" }, - { "C6", "H6" }, { "C6", "H62" }, { "C5", "O3" }, - { "C5", "H5" }, { "C5", "H52" } }, - // Double Bonds - {}); - -ResidueData ASHData("ASH", - // Atoms - { "CA", "N", "CB", "C", "O", "CG", "OD2", "OD1" }, - // Single Bonds - { { "CA", "N" }, - { "CA", "CB" }, - { "CA", "C" }, - { "CB", "CG" }, - { "CG", "OD2" }, - { "N", "H" }, - { "N", "HN" }, - { "OD2", "HD2" } }, - // Double Bonds - { { "C", "O" }, { "CG", "OD1" } }); - -ResidueData CYXData("CYX", - // Atoms - { "CA", "N", "CB", "C", "O", "SG" }, - // Single Bonds - { { "CA", "N" }, - { "CA", "CB" }, - { "CA", "C" }, - { "CB", "SG" }, - { "N", "H" } }, - // Double Bonds - { { "C", "O" } }); - -ResidueData HIPData("HIP", - // Atoms - { "CA", "N", "CB", "C", "O", "CG", "ND1", "CD2", "NE2", - "CE1" }, - // Single Bonds - { { "CA", "N" }, - { "CA", "CB" }, - { "CA", "C" }, - { "CB", "CG" }, - { "CG", "ND1" }, - { "CD2", "NE2" }, - { "NE2", "CE1" }, - { "CE1", "ND1" }, - { "N", "H" }, - { "ND1", "HD1" }, - { "NE2", "HE2" } }, - // Double Bonds - { { "C", "O" }, { "CG", "CD2" } }); - -ResidueData HIDData("HID", - // Atoms - { "CA", "N", "CB", "C", "O", "CG", "ND1", "CD2", "NE2", - "CE1" }, - // Single Bonds - { { "CA", "N" }, - { "CA", "CB" }, - { "CA", "C" }, - { "CB", "CG" }, - { "CG", "ND1" }, - { "CD2", "NE2" }, - { "CE1", "ND1" }, - { "N", "H" }, - { "ND1", "HD1" } }, - // Double Bonds - { { "C", "O" }, { "CG", "CD2" }, { "NE2", "CE1" } }); - -ResidueData HIEData("HIE", - // Atoms - { "CA", "N", "CB", "C", "O", "CG", "ND1", "CD2", "NE2", - "CE1" }, - // Single Bonds - { { "CA", "N" }, - { "CA", "CB" }, - { "CA", "C" }, - { "CB", "CG" }, - { "CG", "ND1" }, - { "CD2", "NE2" }, - { "NE2", "CE1" }, - { "CE1", "ND1" }, - { "N", "H" }, - { "NE2", "HE2" } }, - // Double Bonds - { { "C", "O" }, { "CG", "CD2" } }); - +ResidueData PGEData( + "PGE", + // Atoms + { { "C1", 6 }, { "O1", 8 }, { "C2", 6 }, { "O2", 8 }, { "C3", 6 }, + { "C4", 6 }, { "O4", 8 }, { "C6", 6 }, { "C5", 6 }, { "O3", 8 }, + { "H1", 1 }, { "H12", 1 }, { "HO1", 1 }, { "H2", 1 }, { "H22", 1 }, + { "H3", 1 }, { "H32", 1 }, { "H4", 1 }, { "H42", 1 }, { "HO4", 1 }, + { "H6", 1 }, { "H62", 1 }, { "H5", 1 }, { "H5", 1 } }, + // Single Bonds + { { "C1", "O1" }, { "C1", "C2" }, { "C1", "H1" }, { "C1", "H12" }, + { "O1", "HO1" }, { "C2", "O2" }, { "C2", "H2" }, { "C2", "H22" }, + { "O2", "C3" }, { "C3", "C4" }, { "C3", "H3" }, { "C3", "H32" }, + { "C4", "O3" }, { "C4", "H4" }, { "C4", "H42" }, { "O4", "C6" }, + { "O4", "HO4" }, { "C6", "C5" }, { "C6", "H6" }, { "C6", "H62" }, + { "C5", "O3" }, { "C5", "H5" }, { "C5", "H52" } }, + // Double Bonds + {}); +ResidueData GALData( + "GAL", + // Atoms + { { "C1", 6 }, { "C2", 6 }, { "C3", 6 }, { "C4", 6 }, { "C5", 6 }, + { "C6", 6 }, { "O1", 8 }, { "O2", 8 }, { "O3", 8 }, { "O4", 8 }, + { "O5", 8 }, { "O6", 8 }, { "H1", 1 }, { "H2", 1 }, { "H3", 1 }, + { "H4", 1 }, { "H5", 1 }, { "H61", 1 }, { "H62", 1 }, { "HO1", 1 }, + { "HO2", 1 }, { "HO3", 1 }, { "HO4", 1 }, { "HO4", 1 } }, + // Single Bonds + { { "C1", "C2" }, { "C1", "O1" }, { "C1", "O5" }, { "C1", "H1" }, + { "C2", "C3" }, { "C2", "O2" }, { "C2", "H2" }, { "C3", "C4" }, + { "C3", "O3" }, { "C3", "H3" }, { "C4", "C5" }, { "C4", "O4" }, + { "C4", "H4" }, { "C5", "C6" }, { "C5", "O5" }, { "C5", "H5" }, + { "C6", "O6" }, { "C6", "H61" }, { "C6", "H62" }, { "O1", "HO1" }, + { "O2", "HO2" }, { "O3", "HO3" }, { "O4", "HO4" }, { "O6", "HO6" } }, + // Double Bonds + {}); std::map residueDict = { { "ALA", ALAData }, { "CYS", CYSData }, { "ASP", ASPData }, { "GLU", GLUData }, { "PHE", PHEData }, { "GLY", GLYData }, @@ -1377,11 +1627,9 @@ std::map residueDict = { { "NAD", NADData }, { "NAP", NAPData }, { "TRS", TRSData }, { "ATP", ATPData }, { "NH2", NH2Data }, { "PG4", PG4Data }, { "FMT", FMTData }, { "GDP", GDPData }, { "FUC", FUCData }, - { "SEP", SEPData }, { "GAL", GALData }, { "PGE", PGEData }, - { "ASH", ASHData }, { "CYX", CYXData }, { "HIP", HIPData }, - { "HID", HIDData }, { "HIE", HIEData }, -}; + { "SEP", SEPData }, { "PGE", PGEData }, { "GAL", GALData }, +}; } // namespace Core } // namespace Avogadro diff --git a/scripts/getresdata.py b/scripts/getresdata.py index 89bdb97c35..53951dd132 100644 --- a/scripts/getresdata.py +++ b/scripts/getresdata.py @@ -73,13 +73,13 @@ class ResidueData { private: std::string m_residueName; - std::vector m_residueAtomNames; + std::vector> m_residueAtomNames; std::vector> m_residueSingleBonds; std::vector> m_residueDoubleBonds; public: ResidueData() {} - ResidueData(std::string name, std::vector atomNames, + ResidueData(std::string name, std::vector> atomNames, std::vector> singleBonds, std::vector> doubleBonds) { @@ -104,6 +104,10 @@ class ResidueData return *this; } + std::map residueAtoms() { + return m_residueAtomNames; + } + std::vector> residueSingleBonds() { return m_residueSingleBonds; @@ -142,7 +146,7 @@ class ResidueData atom = mol_pdb.atoms[i].OBAtom res = atom.GetResidue() # build up a map between atom index and atom ID - atom_map[idx] = res.GetAtomID(atom).strip().rstrip() + atom_map[idx] = res.GetAtomID(atom).strip().rstrip(), atom.GetAtomicNum() # go through bonds single_bonds = [] @@ -151,17 +155,17 @@ class ResidueData begin = bond.GetBeginAtomIdx() end = bond.GetEndAtomIdx() if bond.GetBO() == 2: - double_bonds.append((atom_map[begin], atom_map[end])) + double_bonds.append((atom_map[begin][0], atom_map[end][0])) elif bond.GetBO() == 1: - single_bonds.append((atom_map[begin], atom_map[end])) + single_bonds.append((atom_map[begin][0], atom_map[end][0])) # print out the residue data print('ResidueData %sData("%s",' % (ligand, ligand)) print('// Atoms') print('{') for atom in atom_map.values()[:-1]: - print('"%s", ' % (atom), end='') - print('"%s"' % atom_map.values()[-1]) + print('{ "%s", %d },' % (atom[0], atom[1]), end='') + print('{"%s", %d }' % (atom[0], atom[1])) print('},') print('// Single Bonds') From 0fb5d7bcd04efd66b4c06b3100c681b5d8c32de7 Mon Sep 17 00:00:00 2001 From: Adarsh Balasubramanian Date: Fri, 7 Sep 2018 12:58:50 -0400 Subject: [PATCH 57/68] Adding relevant changes in resdata generator script Signed-off-by: Adarsh Balasubramanian --- avogadro/core/residuedata.h | 5 ++--- scripts/getresdata.py | 5 +++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/avogadro/core/residuedata.h b/avogadro/core/residuedata.h index 4434166805..bcc02024a7 100644 --- a/avogadro/core/residuedata.h +++ b/avogadro/core/residuedata.h @@ -12,14 +12,13 @@ class ResidueData { private: std::string m_residueName; - std::vector> m_residueAtomNames; + std::map m_residueAtomNames; std::vector> m_residueSingleBonds; std::vector> m_residueDoubleBonds; public: ResidueData() {} - ResidueData(std::string name, - std::vector> atomNames, + ResidueData(std::string name, std::map atomNames, std::vector> singleBonds, std::vector> doubleBonds) { diff --git a/scripts/getresdata.py b/scripts/getresdata.py index 53951dd132..48d46f6e96 100644 --- a/scripts/getresdata.py +++ b/scripts/getresdata.py @@ -73,13 +73,14 @@ class ResidueData { private: std::string m_residueName; - std::vector> m_residueAtomNames; + std::map m_residueAtomNames; std::vector> m_residueSingleBonds; std::vector> m_residueDoubleBonds; public: ResidueData() {} - ResidueData(std::string name, std::vector> atomNames, + ResidueData(std::string name, + std::map atomNames, std::vector> singleBonds, std::vector> doubleBonds) { From 2c40604c9f73640105b7184f0b29847289f76380 Mon Sep 17 00:00:00 2001 From: Patrick Avery Date: Thu, 30 Aug 2018 08:14:43 -0400 Subject: [PATCH 58/68] OBFileFormat: Allow processing of extra args Signed-off-by: Patrick Avery --- avogadro/qtplugins/openbabel/CMakeLists.txt | 2 + avogadro/qtplugins/openbabel/obfileformat.cpp | 37 ++++++++++++++++++- 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/avogadro/qtplugins/openbabel/CMakeLists.txt b/avogadro/qtplugins/openbabel/CMakeLists.txt index bb222f36cb..c4aec23969 100644 --- a/avogadro/qtplugins/openbabel/CMakeLists.txt +++ b/avogadro/qtplugins/openbabel/CMakeLists.txt @@ -1,3 +1,5 @@ +include_directories("${AvogadroLibs_SOURCE_DIR}/thirdparty") + set(openbabel_srcs obfileformat.cpp obforcefielddialog.cpp diff --git a/avogadro/qtplugins/openbabel/obfileformat.cpp b/avogadro/qtplugins/openbabel/obfileformat.cpp index 7655fddec0..7a169aee1a 100644 --- a/avogadro/qtplugins/openbabel/obfileformat.cpp +++ b/avogadro/qtplugins/openbabel/obfileformat.cpp @@ -20,10 +20,14 @@ #include +#include + #include #include #include +using json = nlohmann::json; + namespace Avogadro { namespace QtPlugins { @@ -90,6 +94,12 @@ OBFileFormat::~OBFileFormat() bool OBFileFormat::read(std::istream& in, Core::Molecule& molecule) { + json opts; + if (!options().empty()) + opts = json::parse(options(), nullptr, false); + else + opts = json::object(); + // Allow blocking until the read is completed. OBProcess proc; ProcessListener listener; @@ -112,6 +122,15 @@ bool OBFileFormat::read(std::istream& in, Core::Molecule& molecule) if (formats2D.contains(QString::fromStdString(m_fileExtensions.front()))) options << "--gen3d"; + // Check if we have extra arguments for open babel + json extraArgs = opts.value("arguments", json::object()); + if (extraArgs.is_array()) { + for (const auto& arg : extraArgs) { + if (arg.is_string()) + options << arg.get().c_str(); + } + } + if (!m_fileOnly) { // Determine length of data in.seekg(0, std::ios_base::end); @@ -175,6 +194,22 @@ bool OBFileFormat::read(std::istream& in, Core::Molecule& molecule) bool OBFileFormat::write(std::ostream& out, const Core::Molecule& molecule) { + json opts; + if (!options().empty()) + opts = json::parse(options(), nullptr, false); + else + opts = json::object(); + + // Check if we have extra arguments for open babel + QStringList options; + json extraArgs = opts.value("arguments", json::object()); + if (extraArgs.is_array()) { + for (const auto& arg : extraArgs) { + if (arg.is_string()) + options << arg.get().c_str(); + } + } + // Generate CML to give to OpenBabel std::string cml; Io::CmlFormat cmlWriter; @@ -197,7 +232,7 @@ bool OBFileFormat::write(std::ostream& out, const Core::Molecule& molecule) return false; } proc.convert(QByteArray(cml.c_str()), "cml", - QString::fromStdString(m_fileExtensions.front())); + QString::fromStdString(m_fileExtensions.front()), options); QByteArray output; if (!listener.waitForOutput(output)) { From cf56ba3da021662592bc6f0010320358a82a9ea1 Mon Sep 17 00:00:00 2001 From: Geoff Hutchison Date: Thu, 13 Sep 2018 11:42:52 -0400 Subject: [PATCH 59/68] Clean up the element colors to be more consistent with Jmol Roughly match Avo1 colors (from Open Babel) as well Signed-off-by: Geoff Hutchison --- avogadro/core/elementdata.h | 69 +++++++++++++++++++++++++------------ 1 file changed, 47 insertions(+), 22 deletions(-) diff --git a/avogadro/core/elementdata.h b/avogadro/core/elementdata.h index 7414959e21..a671e376e1 100644 --- a/avogadro/core/elementdata.h +++ b/avogadro/core/elementdata.h @@ -151,28 +151,53 @@ double element_covalent[] = { }; unsigned char element_color[][3] = { - { 17, 127, 178 }, { 255, 255, 255 }, { 216, 255, 255 }, { 204, 127, 255 }, - { 193, 255, 0 }, { 255, 181, 181 }, { 127, 127, 127 }, { 12, 12, 255 }, - { 255, 12, 12 }, { 178, 255, 255 }, { 178, 226, 244 }, { 170, 91, 242 }, - { 137, 255, 0 }, { 191, 165, 165 }, { 127, 153, 153 }, { 255, 127, 0 }, - { 255, 255, 48 }, { 30, 239, 30 }, { 127, 209, 226 }, { 142, 63, 211 }, - { 61, 255, 0 }, { 229, 229, 229 }, { 191, 193, 198 }, { 165, 165, 170 }, - { 137, 153, 198 }, { 155, 122, 198 }, { 127, 122, 198 }, { 112, 122, 198 }, - { 91, 122, 193 }, { 255, 122, 96 }, { 124, 127, 175 }, { 193, 142, 142 }, - { 102, 142, 142 }, { 188, 127, 226 }, { 255, 160, 0 }, { 165, 40, 40 }, - { 91, 183, 209 }, { 112, 45, 175 }, { 0, 255, 0 }, { 147, 255, 255 }, - { 147, 224, 224 }, { 114, 193, 201 }, { 84, 181, 181 }, { 58, 158, 158 }, - { 35, 142, 142 }, { 10, 124, 140 }, { 0, 104, 132 }, { 224, 224, 255 }, - { 255, 216, 142 }, { 165, 117, 114 }, { 102, 127, 127 }, { 158, 99, 181 }, - { 211, 122, 0 }, { 147, 0, 147 }, { 66, 158, 175 }, { 86, 22, 142 }, - { 0, 201, 0 }, { 112, 211, 255 }, { 255, 255, 198 }, { 216, 255, 198 }, - { 198, 255, 198 }, { 163, 255, 198 }, { 142, 255, 198 }, { 96, 255, 198 }, - { 68, 255, 198 }, { 48, 255, 198 }, { 30, 255, 198 }, { 0, 255, 155 }, - { 0, 229, 117 }, { 0, 211, 81 }, { 0, 191, 56 }, { 0, 170, 35 }, - { 76, 193, 255 }, { 76, 165, 255 }, { 33, 147, 214 }, { 38, 124, 170 }, - { 38, 102, 150 }, { 22, 84, 135 }, { 244, 237, 209 }, { 204, 209, 30 }, - { 181, 181, 193 }, { 165, 84, 76 }, { 86, 89, 96 }, { 158, 79, 181 }, - { 170, 91, 0 }, { 117, 79, 68 }, { 66, 130, 150 }, { 66, 0, 102 }, + // See, for example http://jmol.sourceforge.net/jscolors/index.en.html + // Changes - H is not completely white to add contrast on light backgrounds + // - F is bluer to add contrast with Cl (e.g. CFC compounds) + // # Du # H # He + { 17, 127, 178 }, { 240, 240, 240 }, { 217, 255, 255 }, { 204, 128, 255 }, + // # Be, B, C, N + { 194, 255, 0 }, { 255, 181, 181 }, { 144, 144, 144 }, { 48, 80, 255 }, + // # O, F, Ne, Na + { 255, 13, 13 }, { 178, 255, 255 }, { 178, 227, 245 }, { 171, 91, 242 }, + // # Mg + { 138, 255, 0 }, { 191, 166, 166 }, { 240, 200, 160 }, { 255, 128, 0 }, + // # S + { 255, 255, 48 }, { 31, 240, 31 }, { 128, 209, 227 }, { 143, 64, 212 }, + // # Ca + { 61, 255, 0 }, { 230, 230, 230 }, { 191, 194, 199 }, { 166, 166, 171 }, + // # Cr + { 138, 153, 199 }, { 156, 122, 199 }, { 224, 102, 51 }, { 240, 144, 160 }, + // # Ni + { 80, 208, 80 }, { 200, 128, 51 }, { 125, 128, 176 }, { 194, 143, 143 }, + // # Ge + { 102, 143, 143 }, { 189, 128, 227 }, { 255, 161, 0 }, { 166, 41, 41 }, + // # Kr + { 92, 184, 209 }, { 112, 46, 176 }, { 0, 255, 0 }, { 148, 255, 255 }, + // # Zr + { 148, 224, 224 }, { 115, 194, 201 }, { 84, 181, 181 }, { 59, 158, 158 }, + // # Ru + { 36, 143, 143 }, { 10, 125, 140 }, { 0, 105, 133 }, { 192, 192, 192 }, + // # Cd + { 255, 217, 143 }, { 166, 117, 115 }, { 102, 128, 128 }, { 158, 99, 181 }, + // # Te + { 211, 122, 0 }, { 148, 0, 148 }, { 66, 158, 176 }, { 87, 23, 143 }, + // # Ba + { 0, 201, 0 }, { 112, 212, 255 }, { 255, 255, 199 }, { 217, 255, 199 }, + // # Nd + { 199, 255, 199 }, { 163, 255, 199 }, { 143, 255, 199 }, { 97, 255, 199 }, + // # Gd + { 69, 255, 199 }, { 48, 255, 199 }, { 31, 255, 199 }, { 0, 255, 156 }, + // # Er + { 0, 230, 117 }, { 0, 212, 82 }, { 0, 191, 56 }, { 0, 171, 36 }, + // # Hf + { 77, 194, 255 }, { 77, 166, 255 }, { 33, 148, 214 }, { 38, 102, 150 }, + // # Os + { 38, 102, 150 }, { 23, 84, 135 }, { 208, 208, 224 }, { 255, 209, 35 }, + // # Hg + { 184, 194, 208 }, { 166, 84, 77 }, { 87, 89, 97 }, { 158, 79, 181 }, + // # Po + { 171, 92, 0 }, { 117, 79, 69 }, { 66, 130, 150 }, { 66, 0, 102 }, { 0, 124, 0 }, { 112, 170, 249 }, { 0, 186, 255 }, { 0, 160, 255 }, { 0, 142, 255 }, { 0, 127, 255 }, { 0, 107, 255 }, { 84, 91, 242 }, { 119, 91, 226 }, { 137, 79, 226 }, { 160, 53, 211 }, { 178, 30, 211 }, From d2bbbd10a64903c95082f7f1742252d7f631bb89 Mon Sep 17 00:00:00 2001 From: Geoff Hutchison Date: Thu, 13 Sep 2018 14:41:32 -0400 Subject: [PATCH 60/68] Tweak carbon for darker color from Avo1 Signed-off-by: Geoff Hutchison --- avogadro/core/elementdata.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/avogadro/core/elementdata.h b/avogadro/core/elementdata.h index a671e376e1..a4b2f30a35 100644 --- a/avogadro/core/elementdata.h +++ b/avogadro/core/elementdata.h @@ -153,11 +153,12 @@ double element_covalent[] = { unsigned char element_color[][3] = { // See, for example http://jmol.sourceforge.net/jscolors/index.en.html // Changes - H is not completely white to add contrast on light backgrounds + // - C is slightly darker (i.e. 50% gray - consistent with Avo1) // - F is bluer to add contrast with Cl (e.g. CFC compounds) // # Du # H # He { 17, 127, 178 }, { 240, 240, 240 }, { 217, 255, 255 }, { 204, 128, 255 }, // # Be, B, C, N - { 194, 255, 0 }, { 255, 181, 181 }, { 144, 144, 144 }, { 48, 80, 255 }, + { 194, 255, 0 }, { 255, 181, 181 }, { 127, 127, 127 }, { 48, 80, 255 }, // # O, F, Ne, Na { 255, 13, 13 }, { 178, 255, 255 }, { 178, 227, 245 }, { 171, 91, 242 }, // # Mg From 668a302593ee587832d75fc922ef4b6377dc0e0f Mon Sep 17 00:00:00 2001 From: Geoff Hutchison Date: Thu, 13 Sep 2018 14:41:46 -0400 Subject: [PATCH 61/68] Modify test for new color set Signed-off-by: Geoff Hutchison --- tests/core/elementtest.cpp | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/tests/core/elementtest.cpp b/tests/core/elementtest.cpp index c31e9a91db..f0eb76114a 100644 --- a/tests/core/elementtest.cpp +++ b/tests/core/elementtest.cpp @@ -66,15 +66,29 @@ TEST(ElementTest, radiusCovalent) TEST(ElementTest, colors) { - EXPECT_EQ(Elements::color(1)[0], 255); - EXPECT_EQ(Elements::color(1)[1], 255); - EXPECT_EQ(Elements::color(1)[2], 255); + // hydrogen + EXPECT_EQ(Elements::color(1)[0], 240); + EXPECT_EQ(Elements::color(1)[1], 240); + EXPECT_EQ(Elements::color(1)[2], 240); + + // boron EXPECT_EQ(Elements::color(5)[0], 255); EXPECT_EQ(Elements::color(5)[1], 181); EXPECT_EQ(Elements::color(5)[2], 181); + + // carbon EXPECT_EQ(Elements::color(6)[0], 127); EXPECT_EQ(Elements::color(6)[1], 127); EXPECT_EQ(Elements::color(6)[2], 127); + + EXPECT_EQ(Elements::color(7)[0], 48); + EXPECT_EQ(Elements::color(7)[1], 80); + EXPECT_EQ(Elements::color(7)[2], 255); + + // Oxygen + EXPECT_EQ(Elements::color(8)[0], 255); + EXPECT_EQ(Elements::color(8)[1], 13); + EXPECT_EQ(Elements::color(8)[2], 13); } TEST(ElementTest, dummyElement) From 63d1bfaf0db88df63877715a6c586e0b0966b7ca Mon Sep 17 00:00:00 2001 From: Geoff Hutchison Date: Fri, 14 Sep 2018 17:32:18 -0400 Subject: [PATCH 62/68] Roundtrip unit cell vectors in CJSON Signed-off-by: Geoff Hutchison --- avogadro/io/cjsonformat.cpp | 64 ++++++++++++++++++++++--------------- 1 file changed, 39 insertions(+), 25 deletions(-) diff --git a/avogadro/io/cjsonformat.cpp b/avogadro/io/cjsonformat.cpp index 884e26c991..bc0d4ef770 100644 --- a/avogadro/io/cjsonformat.cpp +++ b/avogadro/io/cjsonformat.cpp @@ -192,20 +192,33 @@ bool CjsonFormat::read(std::istream& file, Molecule& molecule) json unitCell = jsonRoot["unit cell"]; if (!unitCell.is_object()) unitCell = jsonRoot["unitCell"]; - if (unitCell.is_object() && unitCell["a"].is_number() && - unitCell["b"].is_number() && unitCell["c"].is_number() && - unitCell["alpha"].is_number() && unitCell["beta"].is_number() && - unitCell["gamma"].is_number()) { - Real a = static_cast(unitCell["a"]); - Real b = static_cast(unitCell["b"]); - Real c = static_cast(unitCell["c"]); - Real alpha = static_cast(unitCell["alpha"]) * DEG_TO_RAD; - Real beta = static_cast(unitCell["beta"]) * DEG_TO_RAD; - Real gamma = static_cast(unitCell["gamma"]) * DEG_TO_RAD; - Core::UnitCell* unitCellObject = - new Core::UnitCell(a, b, c, alpha, beta, gamma); - molecule.setUnitCell(unitCellObject); + + if (unitCell.is_object()) { + Core::UnitCell* unitCellObject = nullptr; + + // read in cell vectors in preference to a, b, c parameters + json cellVectors = unitCell["cellVectors"]; + if (cellVectors.is_array() && cellVectors.size() == 9 && + isNumericArray(cellVectors)) { + Vector3 aVector(cellVectors[0], cellVectors[1], cellVectors[2]); + Vector3 bVector(cellVectors[3], cellVectors[4], cellVectors[5]); + Vector3 cVector(cellVectors[6], cellVectors[7], cellVectors[8]); + unitCellObject = new Core::UnitCell(aVector, bVector, cVector); + } else if (unitCell["a"].is_number() && unitCell["b"].is_number() && + unitCell["c"].is_number() && unitCell["alpha"].is_number() && + unitCell["beta"].is_number() && unitCell["gamma"].is_number()) { + Real a = static_cast(unitCell["a"]); + Real b = static_cast(unitCell["b"]); + Real c = static_cast(unitCell["c"]); + Real alpha = static_cast(unitCell["alpha"]) * DEG_TO_RAD; + Real beta = static_cast(unitCell["beta"]) * DEG_TO_RAD; + Real gamma = static_cast(unitCell["gamma"]) * DEG_TO_RAD; + unitCellObject = new Core::UnitCell(a, b, c, alpha, beta, gamma); + } + if (unitCellObject != nullptr) + molecule.setUnitCell(unitCellObject); } + json fractional = atoms["coords"]["3d fractional"]; if (!fractional.is_array()) fractional = atoms["coords"]["3dFractional"]; @@ -379,13 +392,12 @@ bool CjsonFormat::write(std::ostream& file, const Molecule& molecule) unitCell["alpha"] = molecule.unitCell()->alpha() * RAD_TO_DEG; unitCell["beta"] = molecule.unitCell()->beta() * RAD_TO_DEG; unitCell["gamma"] = molecule.unitCell()->gamma() * RAD_TO_DEG; - root["unit cell"] = unitCell; json vectors; vectors.push_back(molecule.unitCell()->aVector().x()); vectors.push_back(molecule.unitCell()->aVector().y()); vectors.push_back(molecule.unitCell()->aVector().z()); - + vectors.push_back(molecule.unitCell()->bVector().x()); vectors.push_back(molecule.unitCell()->bVector().y()); vectors.push_back(molecule.unitCell()->bVector().z()); @@ -393,7 +405,9 @@ bool CjsonFormat::write(std::ostream& file, const Molecule& molecule) vectors.push_back(molecule.unitCell()->cVector().x()); vectors.push_back(molecule.unitCell()->cVector().y()); vectors.push_back(molecule.unitCell()->cVector().z()); - root["cell vectors"] = vectors; + unitCell["cellVectors"] = vectors; + + root["unit cell"] = unitCell; } // Create a basis set/MO matrix we can round trip. @@ -522,13 +536,13 @@ bool CjsonFormat::write(std::ostream& file, const Molecule& molecule) // everything gets real-space Cartesians json coords3d; for (vector::const_iterator - it = molecule.atomPositions3d().begin(), - itEnd = molecule.atomPositions3d().end(); - it != itEnd; ++it) { - coords3d.push_back(it->x()); - coords3d.push_back(it->y()); - coords3d.push_back(it->z()); - } + it = molecule.atomPositions3d().begin(), + itEnd = molecule.atomPositions3d().end(); + it != itEnd; ++it) { + coords3d.push_back(it->x()); + coords3d.push_back(it->y()); + coords3d.push_back(it->z()); + } root["atoms"]["coords"]["3d"] = coords3d; // if the unit cell exists, also write fractional coords @@ -625,5 +639,5 @@ vector CjsonFormat::mimeTypes() const return mime; } -} // end Io namespace -} // end Avogadro namespace +} // namespace Io +} // namespace Avogadro From 926abed4cc612580780d889c1a8a42e6fe88167e Mon Sep 17 00:00:00 2001 From: Geoff Hutchison Date: Sat, 15 Sep 2018 17:28:46 -0400 Subject: [PATCH 63/68] Add a default Mac build to the Travis script. Signed-off-by: Geoff Hutchison --- .travis.yml | 9 +++++++++ scripts/travis/build.sh | 4 +++- scripts/travis/install.sh | 2 +- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index f8edb4e1a0..cb7d274781 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,12 +7,16 @@ language: cpp sudo: true matrix: + allow_failures: + - os: osx + include: - language: python sudo: false python: 2.7 env: TASKS="clang-format" + os: linux dist: trusty addons: apt: @@ -23,6 +27,7 @@ matrix: - clang-format-6.0 - compiler: gcc + os: linux addons: apt: sources: ubuntu-toolchain-r-test @@ -32,6 +37,7 @@ matrix: - MATRIX_EVAL="CC=gcc-4.9 && CXX=g++-4.9" - compiler: gcc + os: linux addons: apt: sources: ubuntu-toolchain-r-test @@ -41,8 +47,11 @@ matrix: - MATRIX_EVAL="CC=gcc-6 && CXX=g++-6" - compiler: clang + os: linux env: TASKS="ctest clang-3.9" + - os: osx + install: - . ./scripts/travis/install.sh diff --git a/scripts/travis/build.sh b/scripts/travis/build.sh index ff99725075..524aef77b9 100755 --- a/scripts/travis/build.sh +++ b/scripts/travis/build.sh @@ -31,5 +31,7 @@ else .. make -j2 cd avogadrolibs - xvfb-run ctest --output-on-failure + if [[ $TRAVIS_OS_NAME == "linux" ]]; then + xvfb-run ctest --output-on-failure + fi fi diff --git a/scripts/travis/install.sh b/scripts/travis/install.sh index b67b9f7de8..25fca570b5 100755 --- a/scripts/travis/install.sh +++ b/scripts/travis/install.sh @@ -1,6 +1,6 @@ #!/bin/bash -if [[ $TASKS != "clang-format" ]]; then +if [[ $TASKS != "clang-format" && $TRAVIS_OS_NAME == "linux" ]]; then eval "${MATRIX_EVAL}" sudo add-apt-repository ppa:beineri/opt-qt542-trusty -y sudo apt-get update -qq From c739d6bacde11e003ada3f7f9d78e99de94b8365 Mon Sep 17 00:00:00 2001 From: Geoff Hutchison Date: Sat, 15 Sep 2018 17:44:05 -0400 Subject: [PATCH 64/68] Install some packages with brew and run cmake differently on osx Signed-off-by: Geoff Hutchison --- scripts/travis/build.sh | 15 +++++++++++++-- scripts/travis/install.sh | 2 ++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/scripts/travis/build.sh b/scripts/travis/build.sh index 524aef77b9..66f8b9926b 100755 --- a/scripts/travis/build.sh +++ b/scripts/travis/build.sh @@ -18,7 +18,8 @@ else mkdir build cd build - ${CMAKE_EXE} -DCMAKE_BUILD_TYPE=Debug \ + if [[ $TRAVIS_OS_NAME == "linux" ]]; then + ${CMAKE_EXE} -DCMAKE_BUILD_TYPE=RelWithDebInfo \ -DENABLE_TESTING=ON \ -DUSE_SYSTEM_EIGEN=ON \ -DUSE_SYSTEM_GLEW=ON \ @@ -29,7 +30,17 @@ else -DUSE_SYSTEM_PCRE=OFF \ -DUSE_SYSTEM_ZLIB=ON \ .. - make -j2 + else + # osx + cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo \ + -DENABLE_TESTING=ON \ + -DUSE_SYSTEM_EIGEN=ON \ + -DUSE_SYSTEM_GLEW=ON \ + -DUSE_SYSTEM_LIBXML2=ON \ + -DUSE_SYSTEM_ZLIB=ON \ + .. + fi + make -j$(nproc) cd avogadrolibs if [[ $TRAVIS_OS_NAME == "linux" ]]; then xvfb-run ctest --output-on-failure diff --git a/scripts/travis/install.sh b/scripts/travis/install.sh index 25fca570b5..f8f574b693 100755 --- a/scripts/travis/install.sh +++ b/scripts/travis/install.sh @@ -17,4 +17,6 @@ if [[ $TASKS != "clang-format" && $TRAVIS_OS_NAME == "linux" ]]; then tar -xzf ${CMAKE_NAME}.tar.gz export CMAKE_EXE=${PWD}/${CMAKE_NAME}/bin/cmake cd avogadrolibs +elif [[ $TASKS != "clang-format" && $TRAVIS_OS_NAME == "osx" ]]; then + brew install qt eigen glew fi From f5931040ea8cc193a4eecdd668b65fa6aa65eddd Mon Sep 17 00:00:00 2001 From: Geoff Hutchison Date: Sat, 15 Sep 2018 18:05:05 -0400 Subject: [PATCH 65/68] Make sure to use clang/clang++ and correct Qt5 path. Signed-off-by: Geoff Hutchison --- .travis.yml | 1 + scripts/travis/build.sh | 1 + 2 files changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index cb7d274781..533811ffc4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -51,6 +51,7 @@ matrix: env: TASKS="ctest clang-3.9" - os: osx + env: MATRIX_EVAL="CC=clang && CXX=clang++" install: - . ./scripts/travis/install.sh diff --git a/scripts/travis/build.sh b/scripts/travis/build.sh index 66f8b9926b..b0f2c5539c 100755 --- a/scripts/travis/build.sh +++ b/scripts/travis/build.sh @@ -32,6 +32,7 @@ else .. else # osx + export CMAKE_PREFIX_PATH=/usr/local/Cellar/qt/5.11.1/lib/cmake cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo \ -DENABLE_TESTING=ON \ -DUSE_SYSTEM_EIGEN=ON \ From 450c3166afb9308abd88d1977b0da2afc3ae86fa Mon Sep 17 00:00:00 2001 From: Geoff Hutchison Date: Sat, 15 Sep 2018 18:27:10 -0400 Subject: [PATCH 66/68] Another try with clang/clang++ and brew open-babel Signed-off-by: Geoff Hutchison --- .travis.yml | 1 - scripts/travis/build.sh | 3 +++ scripts/travis/install.sh | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 533811ffc4..cb7d274781 100644 --- a/.travis.yml +++ b/.travis.yml @@ -51,7 +51,6 @@ matrix: env: TASKS="ctest clang-3.9" - os: osx - env: MATRIX_EVAL="CC=clang && CXX=clang++" install: - . ./scripts/travis/install.sh diff --git a/scripts/travis/build.sh b/scripts/travis/build.sh index b0f2c5539c..36a8af4181 100755 --- a/scripts/travis/build.sh +++ b/scripts/travis/build.sh @@ -32,12 +32,15 @@ else .. else # osx + export CC=clang + export CXX=clang++ export CMAKE_PREFIX_PATH=/usr/local/Cellar/qt/5.11.1/lib/cmake cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo \ -DENABLE_TESTING=ON \ -DUSE_SYSTEM_EIGEN=ON \ -DUSE_SYSTEM_GLEW=ON \ -DUSE_SYSTEM_LIBXML2=ON \ + -DUSE_SYSTEM_OPENBABEL=ON \ -DUSE_SYSTEM_ZLIB=ON \ .. fi diff --git a/scripts/travis/install.sh b/scripts/travis/install.sh index f8f574b693..4ef63b25c2 100755 --- a/scripts/travis/install.sh +++ b/scripts/travis/install.sh @@ -18,5 +18,5 @@ if [[ $TASKS != "clang-format" && $TRAVIS_OS_NAME == "linux" ]]; then export CMAKE_EXE=${PWD}/${CMAKE_NAME}/bin/cmake cd avogadrolibs elif [[ $TASKS != "clang-format" && $TRAVIS_OS_NAME == "osx" ]]; then - brew install qt eigen glew + brew install qt eigen glew open-babel fi From 59fde9ff448e90129be6f90d303c3361fa2eace6 Mon Sep 17 00:00:00 2001 From: Geoff Hutchison Date: Tue, 18 Sep 2018 11:32:08 -0400 Subject: [PATCH 67/68] Add a TASK marker as suggested by Marcus. Signed-off-by: Geoff Hutchison --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index cb7d274781..62ceda9654 100644 --- a/.travis.yml +++ b/.travis.yml @@ -51,6 +51,7 @@ matrix: env: TASKS="ctest clang-3.9" - os: osx + env: TASKS="Mac clang" install: - . ./scripts/travis/install.sh From 6eeae1b85179cf6fb2a36acfb9f51043e0329e96 Mon Sep 17 00:00:00 2001 From: Patrick Avery Date: Sun, 23 Sep 2018 11:12:58 -0400 Subject: [PATCH 68/68] AppVeyor: Use ninja for the build Ninja seems to be much faster for the build than the previous build system, partially because it uses all of the cores on AppVeyor. Ninja is installed with chocolatey, and the Visual Studio 2017 environment variables are set with the `vcvarsall.bat` script. Verbosity detail was also turned off. This may have caused a significant speed increase as well. Signed-off-by: Patrick Avery --- appveyor.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 244d7a37e3..0fdee6f67a 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -8,7 +8,7 @@ init: environment: PATH: '%PATH%;%QTDIR%\bin' matrix: - - CMAKE_GENERATOR: '"Visual Studio 15 2017 Win64"' + - CMAKE_GENERATOR: '"Ninja"' QTDIR: C:\Qt\5.6\msvc2015_64 platform: x64 build_script: @@ -29,6 +29,10 @@ build_script: cd openchemistry-build + choco install ninja + + call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" amd64 + cmake -G %CMAKE_GENERATOR% ../openchemistry - cmake --build . --target avogadrolibs --config Release -- /verbosity:detailed + cmake --build . --target avogadrolibs --config Release