Files
rdkit/Code/MinimalLib/common_defs.h
Greg Landrum 45681a1c04 Switch from using RapidJSON to Boost::JSON for MolInterchange (#8859)
* First pass at port

Mostly auto-converted using claude sonnet 4

Things are a bit slower in this initial port. Here's some timing data for molecules from SMILES (no coords) and from SDF (with coords)

# MASTER
## smiles
read: 50000 mols.
 9.260000s wall, 8.650000s user + 0.600000s system = 9.250000s CPU (99.9%)
serialize
 3.060000s wall, 2.400000s user + 0.660000s system = 3.060000s CPU (100.0%)
deserialize
 1.350000s wall, 1.250000s user + 0.090000s system = 1.340000s CPU (99.3%)

## SDF
read: 50000 mols.
 9.340000s wall, 8.930000s user + 0.400000s system = 9.330000s CPU (99.9%)
serialize
 6.630000s wall, 5.960000s user + 0.680000s system = 6.640000s CPU (100.2%)
deserialize
 1.450000s wall, 1.450000s user + 0.000000s system = 1.450000s CPU (100.0%)

# Boost::JSON
## smiles
read: 50000 mols.
 9.250000s wall, 8.830000s user + 0.420000s system = 9.250000s CPU (100.0%)
serialize
 4.770000s wall, 4.410000s user + 0.350000s system = 4.760000s CPU (99.8%)
deserialize
 2.320000s wall, 2.100000s user + 0.230000s system = 2.330000s CPU (100.4%)

## SDF
read: 50000 mols.
 9.500000s wall, 9.100000s user + 0.400000s system = 9.500000s CPU (100.0%)
serialize
 8.760000s wall, 8.330000s user + 0.420000s system = 8.750000s CPU (99.9%)
deserialize
 2.540000s wall, 2.330000s user + 0.210000s system = 2.540000s CPU (100.0%)

* some json parser optimization

* around the edges

* optimizations for the writer

* hopefully get things compiling

* convert the MinimalLib stuff to use boost::json

Again, a lot of the lifting here was done using Claude Sonnet 4 in VS Code Copilot

* fix Windows DLL build

* response to review

Co-authored-by: Paolo Tosco <paolo.tosco.mail@gmail.com>

* better not to blindly accept suggestions

* fix the problems in MinimalLib

---------

Co-authored-by: Paolo Tosco <paolo.tosco.mail@gmail.com>
Co-authored-by: = <=>
2025-11-11 11:54:44 +01:00

214 lines
7.5 KiB
C++

//
// Copyright (C) 2024 Novartis and other RDKit contributors
//
// @@ All Rights Reserved @@
// This file is part of the RDKit.
// The contents are covered by the terms of the BSD license
// which is included in the file license.txt, found at the root
// of the RDKit source tree.
//
#include <GraphMol/MolDraw2D/MolDraw2D.h>
#include <GraphMol/MolDraw2D/MolDraw2DHelpers.h>
#include <GraphMol/MolDraw2D/MolDraw2DUtils.h>
#include <GraphMol/Chirality.h>
#include <boost/json.hpp>
#include <string>
#include <vector>
namespace bj = boost::json;
namespace RDKit {
namespace MinimalLib {
struct DrawingDetails {
int width = -1;
int height = -1;
int offsetx = 0;
int offsety = 0;
int panelWidth = -1;
int panelHeight = -1;
bool noFreetype = false;
bool kekulize = true;
bool addChiralHs = true;
bool wedgeBonds = true;
bool forceCoords = false;
bool wavyBonds = false;
bool useMolBlockWedging = false;
bool returnDrawCoords = false;
std::string legend;
std::vector<int> atomIds;
std::vector<int> bondIds;
};
struct MolDrawingDetails : public DrawingDetails {
std::map<int, DrawColour> atomMap;
std::map<int, DrawColour> bondMap;
std::map<int, std::vector<DrawColour>> atomMultiMap;
std::map<int, std::vector<DrawColour>> bondMultiMap;
std::map<int, double> radiiMap;
std::map<int, int> lineWidthMultiplierMap;
};
struct RxnDrawingDetails : public DrawingDetails {
bool highlightByReactant = false;
std::vector<DrawColour> highlightColorsReactants;
};
extern std::string process_mol_details(const std::string &details,
MolDrawingDetails &molDrawingDetails);
[[deprecated(
"please use the overload taking MolDrawingDetails& as parameter")]] extern std::
string
process_mol_details(const std::string &details, int &width, int &height,
int &offsetx, int &offsety, std::string &legend,
std::vector<int> &atomIds, std::vector<int> &bondIds,
std::map<int, DrawColour> &atomMap,
std::map<int, DrawColour> &bondMap,
std::map<int, double> &radiiMap, bool &kekulize,
bool &addChiralHs, bool &wedgeBonds, bool &forceCoords,
bool &wavyBonds);
extern std::string process_rxn_details(const std::string &details,
RxnDrawingDetails &rxnDrawingDetails);
[[deprecated(
"please use the overload taking RxnDrawingDetails& as parameter")]] extern std::
string
process_rxn_details(const std::string &details, int &width, int &height,
int &offsetx, int &offsety, std::string &legend,
std::vector<int> &atomIds, std::vector<int> &bondIds,
bool &kekulize, bool &highlightByReactant,
std::vector<DrawColour> &highlightColorsReactants);
class DrawerFromDetails {
public:
virtual ~DrawerFromDetails() {}
std::string draw_mol(const ROMol &mol) {
MolDrawingDetails molDrawingDetails;
molDrawingDetails.width = d_width;
molDrawingDetails.height = d_height;
if (!d_details.empty()) {
auto problems = process_mol_details(d_details, molDrawingDetails);
if (!problems.empty()) {
return problems;
}
}
initDrawer(molDrawingDetails);
const ROMol *molPtr = &mol;
std::unique_ptr<RWMol> drawnMol;
bool haveMultiMap = (!molDrawingDetails.atomMultiMap.empty() ||
!molDrawingDetails.bondMultiMap.empty());
if (molDrawingDetails.useMolBlockWedging || haveMultiMap) {
drawnMol.reset(new RWMol(mol));
molPtr = static_cast<ROMol *>(drawnMol.get());
if (molDrawingDetails.useMolBlockWedging) {
Chirality::reapplyMolBlockWedging(*drawnMol);
drawer().drawOptions().useMolBlockWedging = false;
}
}
drawer().setOffset(molDrawingDetails.offsetx, molDrawingDetails.offsety);
if (!haveMultiMap) {
MolDraw2DUtils::prepareAndDrawMolecule(
drawer(), *molPtr, molDrawingDetails.legend,
&molDrawingDetails.atomIds, &molDrawingDetails.bondIds,
molDrawingDetails.atomMap.empty() ? nullptr
: &molDrawingDetails.atomMap,
molDrawingDetails.bondMap.empty() ? nullptr
: &molDrawingDetails.bondMap,
molDrawingDetails.radiiMap.empty() ? nullptr
: &molDrawingDetails.radiiMap,
-1, molDrawingDetails.kekulize, molDrawingDetails.addChiralHs,
molDrawingDetails.wedgeBonds, molDrawingDetails.forceCoords,
molDrawingDetails.wavyBonds);
} else {
MolDraw2DUtils::prepareMolForDrawing(
*drawnMol, molDrawingDetails.kekulize, molDrawingDetails.addChiralHs,
molDrawingDetails.wedgeBonds, molDrawingDetails.forceCoords,
molDrawingDetails.wavyBonds);
drawer().drawMoleculeWithHighlights(
*drawnMol, molDrawingDetails.legend, molDrawingDetails.atomMultiMap,
molDrawingDetails.bondMultiMap, molDrawingDetails.radiiMap,
molDrawingDetails.lineWidthMultiplierMap);
}
if (molDrawingDetails.returnDrawCoords) {
d_drawCoords.reset(new std::vector<RDGeom::Point2D>());
d_drawCoords->reserve(molPtr->getNumAtoms());
for (size_t i = 0; i < molPtr->getNumAtoms(); ++i) {
d_drawCoords->push_back(drawer().getDrawCoords(i));
}
}
return finalizeDrawing();
}
std::string draw_rxn(const ChemicalReaction &rxn) {
RxnDrawingDetails rxnDrawingDetails;
rxnDrawingDetails.width = d_width;
rxnDrawingDetails.height = d_height;
if (!d_details.empty()) {
auto problems = process_rxn_details(d_details, rxnDrawingDetails);
if (!problems.empty()) {
return problems;
}
}
initDrawer(rxnDrawingDetails);
if (!rxnDrawingDetails.kekulize) {
drawer().drawOptions().prepareMolsBeforeDrawing = false;
}
drawer().drawReaction(
rxn, rxnDrawingDetails.highlightByReactant,
!rxnDrawingDetails.highlightByReactant ||
rxnDrawingDetails.highlightColorsReactants.empty()
? nullptr
: &rxnDrawingDetails.highlightColorsReactants);
return finalizeDrawing();
}
protected:
void init(int w = -1, int h = -1,
const std::string &details = std::string()) {
d_width = w;
d_height = h;
d_details = details;
}
void updateDrawerParamsFromJSON() {
if (!d_details.empty()) {
MolDraw2DUtils::updateDrawerParamsFromJSON(drawer(), d_details);
}
}
std::string createDrawingResult(const std::string &res) {
if (!d_drawCoords) {
return res;
}
bj::object doc;
bj::array bjDrawCoords;
for (const auto &drawXY : *d_drawCoords) {
bj::array bjXY;
bjXY.push_back(drawXY.x);
bjXY.push_back(drawXY.y);
bjDrawCoords.push_back(std::move(bjXY));
}
doc["drawCoords"] = bjDrawCoords;
const auto drawingResultKey = getDrawingResultKey();
if (drawingResultKey) {
doc[drawingResultKey] = res;
}
return bj::serialize(doc);
}
private:
virtual MolDraw2D &drawer() const = 0;
virtual void initDrawer(const DrawingDetails &drawingDetails) = 0;
virtual std::string finalizeDrawing() = 0;
virtual const char *getDrawingResultKey() { return nullptr; };
int d_width;
int d_height;
std::string d_details;
std::unique_ptr<std::vector<RDGeom::Point2D>> d_drawCoords;
};
enum class MDLVersion {
AUTO,
V2000,
V3000
};
} // namespace MinimalLib
} // namespace RDKit