// // Copyright (C) 2015-2017 Greg Landrum // // @@ 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace RDKit; void test1() { std::cout << " ----------------- Test 1" << std::endl; { std::string smiles = "CO[C@@H](O)C1=C(O[C@H](F)Cl)C(C#N)=C1ONNC[NH3+]"; ROMol *m = SmilesToMol(smiles); TEST_ASSERT(m); RDDepict::compute2DCoords(*m); WedgeMolBonds(*m, &(m->getConformer())); std::ofstream outs("test1_1.svg"); MolDraw2DSVG drawer(300, 300, outs); drawer.drawMolecule(*m); drawer.finishDrawing(); outs.flush(); delete m; } { // make sure this works with the stringstream too: std::string smiles = "CO[C@@H](O)C1=C(O[C@H](F)Cl)C=C1ONNC[NH3+]"; ROMol *m = SmilesToMol(smiles); TEST_ASSERT(m); RDDepict::compute2DCoords(*m); WedgeMolBonds(*m, &(m->getConformer())); MolDraw2DSVG drawer(300, 300); drawer.drawMolecule(*m); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); TEST_ASSERT(text.find("") != std::string::npos); delete m; } { std::string smiles = "Cc1c(C(=O)NCCO)[n+](=O)c2ccccc2n1[O-]"; ROMol *m = SmilesToMol(smiles); TEST_ASSERT(m); RDDepict::compute2DCoords(*m); WedgeMolBonds(*m, &(m->getConformer())); std::ofstream outs("test1_2.svg"); MolDraw2DSVG drawer(300, 300, outs); drawer.drawMolecule(*m); drawer.finishDrawing(); outs.flush(); delete m; } { std::string smiles = "Cc1c(C(=O)NCCO)[n+](=O)c2ccccc2n1[O-]"; ROMol *m = SmilesToMol(smiles); TEST_ASSERT(m); RDDepict::compute2DCoords(*m); WedgeMolBonds(*m, &(m->getConformer())); std::ofstream outs("test1_3.svg"); MolDraw2DSVG drawer(300, 300, outs); std::vector highlights; highlights.push_back(0); highlights.push_back(4); highlights.push_back(5); drawer.drawMolecule(*m, &highlights); drawer.finishDrawing(); outs.flush(); delete m; } { std::string smiles = "CO[C@@H](O)C1=C(O[C@H](F)Cl)C(C#N)=C1ONNC[NH3+]"; ROMol *m = SmilesToMol(smiles); TEST_ASSERT(m); RDDepict::compute2DCoords(*m); WedgeMolBonds(*m, &(m->getConformer())); std::ofstream outs("test1_4.svg"); MolDraw2DSVG drawer(300, 300, outs); drawer.drawOptions().additionalAtomLabelPadding = 0.25; drawer.drawMolecule(*m); drawer.finishDrawing(); outs.flush(); delete m; } { // in this one, all three double bonds in the phenyl ring need to be inside // the aromatic ring. There was a time when one of them strayed into the // aliphatic ring. std::string smiles = "CN1CC[C@]23c4c5ccc(O)c4O[C@H]2[C@@H](O)C=C[C@H]3[C@H]1C5"; ROMol *m = SmilesToMol(smiles); TEST_ASSERT(m); RDDepict::compute2DCoords(*m); WedgeMolBonds(*m, &(m->getConformer())); std::ofstream outs("test1_5.svg"); MolDraw2DSVG drawer(300, 300, outs); drawer.drawMolecule(*m); drawer.finishDrawing(); outs.flush(); delete m; } { // Here, the H should be between the two bonds off the N, not // on top of the vertical one. std::string smiles = "C[NH+](C)CCC"; std::string nameBase = "test1_6"; ROMol *m = SmilesToMol(smiles); TEST_ASSERT(m); RDDepict::compute2DCoords(*m); WedgeMolBonds(*m, &(m->getConformer())); MolDraw2DSVG drawer(300, 300); drawer.drawMolecule(*m); drawer.finishDrawing(); std::string txt = drawer.getDrawingText(); std::ofstream outs("test1_6.svg"); outs << txt; delete m; } std::cout << " Done" << std::endl; } #ifdef RDK_BUILD_CAIRO_SUPPORT #include #include "MolDraw2DCairo.h" void test2() { std::cout << " ----------------- Test 2" << std::endl; { std::string smiles = "CO[C@@H](O)C1=C(O[C@H](F)Cl)C(C#N)=C1ONNC[NH3+]"; ROMol *m = SmilesToMol(smiles); TEST_ASSERT(m); RDDepict::compute2DCoords(*m); WedgeMolBonds(*m, &(m->getConformer())); MolDraw2DCairo drawer(300, 300); drawer.drawMolecule(*m); drawer.finishDrawing(); drawer.writeDrawingText("test2_1.png"); delete m; } { std::string smiles = "Cc1c(C(=O)NCCO)[n+](=O)c2ccccc2n1[O-]"; ROMol *m = SmilesToMol(smiles); TEST_ASSERT(m); RDDepict::compute2DCoords(*m); WedgeMolBonds(*m, &(m->getConformer())); MolDraw2DCairo drawer(300, 300); drawer.drawMolecule(*m); drawer.finishDrawing(); std::string drawing = drawer.getDrawingText(); TEST_ASSERT(drawing.size() > 0); std::ofstream ofs("test2_2.png"); ofs.write(drawing.c_str(), drawing.size()); delete m; } { // ensure we still work with a client-provided drawing context std::string smiles = "Cc1c(C(=O)NCCO)[n+](=O)c2ccccc2n1[O-]"; ROMol *m = SmilesToMol(smiles); TEST_ASSERT(m); RDDepict::compute2DCoords(*m); WedgeMolBonds(*m, &(m->getConformer())); cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 300, 300); cairo_t *cr = cairo_create(surface); MolDraw2DCairo drawer(300, 300, cr); std::vector highlights; highlights.push_back(0); highlights.push_back(4); highlights.push_back(5); drawer.drawMolecule(*m, &highlights); drawer.finishDrawing(); cairo_destroy(cr); cairo_surface_write_to_png(surface, "test2_3.png"); cairo_surface_destroy(surface); delete m; } std::cout << " Done" << std::endl; } #else // RDK_BUILD_CAIRO_SUPPORT void test2() {} #endif void test3() { std::cout << " ----------------- Test 3" << std::endl; { std::string smiles = "C1CC1CC1ON1"; std::string nameBase = "test3_1"; ROMol *m = SmilesToMol(smiles); TEST_ASSERT(m); RDDepict::compute2DCoords(*m); WedgeMolBonds(*m, &(m->getConformer())); static const int ha[] = {0, 3, 4, 5}; std::vector highlight_atoms(ha, ha + sizeof(ha) / sizeof(int)); std::map atomLabels; atomLabels[2] = "C1"; atomLabels[1] = "a34"; atomLabels[0] = "[CH2;X2:4]"; atomLabels[6] = "[NH2+:7]"; #ifdef RDK_BUILD_CAIRO_SUPPORT { MolDraw2DCairo drawer(300, 300); drawer.drawOptions().atomLabels = atomLabels; drawer.drawMolecule(*m, &highlight_atoms); drawer.finishDrawing(); drawer.writeDrawingText(nameBase + ".png"); } #endif { std::ofstream outs((nameBase + ".svg").c_str()); MolDraw2DSVG drawer(300, 300, outs); drawer.drawOptions().atomLabels = atomLabels; drawer.drawMolecule(*m, &highlight_atoms); drawer.finishDrawing(); outs.flush(); } delete m; } { std::string smiles = "C1CC1CC1ON1"; std::string nameBase = "test3_2"; ROMol *m = SmilesToMol(smiles); TEST_ASSERT(m); RDDepict::compute2DCoords(*m); WedgeMolBonds(*m, &(m->getConformer())); static const int ha[] = {0, 3, 4, 5}; std::vector highlight_atoms(ha, ha + sizeof(ha) / sizeof(int)); #ifdef RDK_BUILD_CAIRO_SUPPORT { MolDraw2DCairo drawer(300, 300); drawer.drawOptions().circleAtoms = false; drawer.drawMolecule(*m, &highlight_atoms); drawer.finishDrawing(); drawer.writeDrawingText(nameBase + ".png"); } #endif { std::ofstream outs((nameBase + ".svg").c_str()); MolDraw2DSVG drawer(300, 300, outs); drawer.drawOptions().circleAtoms = false; drawer.drawMolecule(*m, &highlight_atoms); drawer.finishDrawing(); outs.flush(); } delete m; } { std::string smiles = "Cc1c(C(=O)NCCO)[n+](=O)c2ccccc2n1[O-]"; std::string nameBase = "test3_3"; ROMol *m = SmilesToMol(smiles); TEST_ASSERT(m); RDDepict::compute2DCoords(*m); WedgeMolBonds(*m, &(m->getConformer())); static const int ha[] = {11, 12, 13, 14, 15, 16}; std::vector highlight_atoms(ha, ha + sizeof(ha) / sizeof(int)); std::map highlight_colors; highlight_colors[12] = DrawColour(0, 0, 1); highlight_colors[13] = DrawColour(0, 1, 0); #ifdef RDK_BUILD_CAIRO_SUPPORT { MolDraw2DCairo drawer(300, 300); drawer.drawOptions().circleAtoms = true; drawer.drawMolecule(*m, &highlight_atoms, &highlight_colors); drawer.finishDrawing(); drawer.writeDrawingText(nameBase + ".png"); } #endif { std::ofstream outs((nameBase + ".svg").c_str()); MolDraw2DSVG drawer(300, 300, outs); drawer.drawOptions().circleAtoms = true; drawer.drawMolecule(*m, &highlight_atoms, &highlight_colors); drawer.finishDrawing(); outs.flush(); } delete m; } { std::string smiles = "Cc1c(C(=O)NCCO)[n+](=O)c2ccccc2n1[O-]"; std::string nameBase = "test3_4"; ROMol *m = SmilesToMol(smiles); TEST_ASSERT(m); RDDepict::compute2DCoords(*m); WedgeMolBonds(*m, &(m->getConformer())); static const int ha[] = {11, 12, 13, 14, 15, 16, 3}; std::vector highlight_atoms(ha, ha + sizeof(ha) / sizeof(int)); std::map highlight_colors; highlight_colors[12] = DrawColour(.5, .5, 1); highlight_colors[13] = DrawColour(.5, 1, .5); MolDrawOptions options; options.circleAtoms = true; options.highlightColour = DrawColour(1, .5, .5); options.continuousHighlight = true; #ifdef RDK_BUILD_CAIRO_SUPPORT { MolDraw2DCairo drawer(300, 300); drawer.drawOptions() = options; drawer.drawMolecule(*m, &highlight_atoms, &highlight_colors); drawer.finishDrawing(); drawer.writeDrawingText(nameBase + ".png"); } #endif { std::ofstream outs((nameBase + ".svg").c_str()); MolDraw2DSVG drawer(300, 300, outs); drawer.drawOptions() = options; drawer.drawMolecule(*m, &highlight_atoms, &highlight_colors); drawer.finishDrawing(); outs.flush(); } delete m; } { std::string smiles = "CCOC(=O)Nc1ccc(SCC2COC(Cn3ccnc3)(c3ccc(Cl)cc3Cl)O2)cc1"; std::string nameBase = "test3_5"; ROMol *m = SmilesToMol(smiles); TEST_ASSERT(m); RDDepict::compute2DCoords(*m); WedgeMolBonds(*m, &(m->getConformer())); static const int ha[] = {17, 18, 19, 20, 21, 6, 7, 8, 9, 31, 32}; std::vector highlight_atoms(ha, ha + sizeof(ha) / sizeof(int)); std::map highlight_colors; MolDrawOptions options; options.circleAtoms = true; options.highlightColour = DrawColour(1, .5, .5); options.continuousHighlight = true; #ifdef RDK_BUILD_CAIRO_SUPPORT { MolDraw2DCairo drawer(200, 200); drawer.drawOptions() = options; drawer.drawMolecule(*m, &highlight_atoms, &highlight_colors); drawer.finishDrawing(); drawer.writeDrawingText(nameBase + ".png"); } #endif { std::ofstream outs((nameBase + ".svg").c_str()); MolDraw2DSVG drawer(200, 200, outs); drawer.drawOptions() = options; drawer.drawMolecule(*m, &highlight_atoms, &highlight_colors); drawer.finishDrawing(); outs.flush(); } delete m; } { std::string smiles = "CCOC(=O)Nc1ccc(SCC2COC(Cn3ccnc3)(c3ccc(Cl)cc3Cl)O2)cc1"; std::string nameBase = "test3_6"; ROMol *m = SmilesToMol(smiles); TEST_ASSERT(m); RDDepict::compute2DCoords(*m); WedgeMolBonds(*m, &(m->getConformer())); MolDrawOptions options; static const int ha1[] = {17, 18, 19, 20, 21}; std::vector highlight_atoms1(ha1, ha1 + sizeof(ha1) / sizeof(int)); options.atomRegions.push_back(highlight_atoms1); static const int ha2[] = {6, 7, 8, 9, 31, 32}; std::vector highlight_atoms2(ha2, ha2 + sizeof(ha2) / sizeof(int)); options.atomRegions.push_back(highlight_atoms2); options.includeAtomTags = true; #ifdef RDK_BUILD_CAIRO_SUPPORT { MolDraw2DCairo drawer(300, 300); drawer.drawOptions() = options; drawer.drawMolecule(*m); drawer.finishDrawing(); drawer.writeDrawingText(nameBase + ".png"); } #endif { std::ofstream outs((nameBase + ".svg").c_str()); MolDraw2DSVG drawer(300, 300, outs); drawer.drawOptions() = options; drawer.drawMolecule(*m); drawer.finishDrawing(); outs.flush(); } delete m; } { std::string smiles = "CCOC(=O)Nc1ccc(SCC2COC(Cn3ccnc3)(c3ccc(Cl)cc3Cl)O2)cc1"; std::string nameBase = "test3_7"; ROMol *m = SmilesToMol(smiles); TEST_ASSERT(m); RDDepict::compute2DCoords(*m); WedgeMolBonds(*m, &(m->getConformer())); MolDrawOptions options; options.continuousHighlight = true; static const int ha[] = {17, 20, 25}; std::vector highlight_atoms(ha, ha + sizeof(ha) / sizeof(int)); std::map highlight_radii; highlight_radii[17] = 0.5; highlight_radii[20] = 1.0; std::map highlight_colors; highlight_colors[17] = DrawColour(.5, .5, 1.); #ifdef RDK_BUILD_CAIRO_SUPPORT { MolDraw2DCairo drawer(300, 300); drawer.drawOptions() = options; drawer.drawMolecule(*m, &highlight_atoms, &highlight_colors, &highlight_radii); drawer.finishDrawing(); drawer.writeDrawingText(nameBase + ".png"); } #endif { std::ofstream outs((nameBase + ".svg").c_str()); MolDraw2DSVG drawer(300, 300, outs); drawer.drawOptions() = options; drawer.drawMolecule(*m, &highlight_atoms, &highlight_colors, &highlight_radii); drawer.finishDrawing(); outs.flush(); } delete m; } std::cout << " Done" << std::endl; } void test4() { std::cout << " ----------------- Test 4" << std::endl; { std::string fName = getenv("RDBASE"); fName += "/Code/GraphMol/MolDraw2D/test_dir"; fName += "/clash.mol"; ROMol *m = MolFileToMol(fName); std::string nameBase = "test4_1"; TEST_ASSERT(m); #ifdef RDK_BUILD_CAIRO_SUPPORT { MolDraw2DCairo drawer(300, 300); drawer.drawMolecule(*m); drawer.finishDrawing(); drawer.writeDrawingText(nameBase + ".png"); } #endif { std::ofstream outs((nameBase + ".svg").c_str()); MolDraw2DSVG drawer(300, 300, outs); drawer.drawMolecule(*m); drawer.finishDrawing(); outs.flush(); } delete m; } std::cout << " Done" << std::endl; } void test5() { std::cout << " ----------------- Test 5" << std::endl; { std::string smiles = "*c1cc(*)cc(*)c1"; std::string nameBase = "test5_1"; ROMol *m = SmilesToMol(smiles); TEST_ASSERT(m); RDDepict::compute2DCoords(*m); WedgeMolBonds(*m, &(m->getConformer())); MolDrawOptions options; options.dummiesAreAttachments = true; options.atomLabels[0] = "R1"; #ifdef RDK_BUILD_CAIRO_SUPPORT { MolDraw2DCairo drawer(300, 300); drawer.drawOptions() = options; drawer.drawMolecule(*m); drawer.finishDrawing(); drawer.writeDrawingText(nameBase + ".png"); } #endif { std::ofstream outs((nameBase + ".svg").c_str()); MolDraw2DSVG drawer(300, 300, outs); drawer.drawOptions() = options; drawer.drawMolecule(*m); drawer.finishDrawing(); outs.flush(); } delete m; } { std::string smiles = "*C"; std::string nameBase = "test5_2"; ROMol *m = SmilesToMol(smiles); TEST_ASSERT(m); RDDepict::compute2DCoords(*m, nullptr, true); WedgeMolBonds(*m, &(m->getConformer())); MolDrawOptions options; options.dummiesAreAttachments = true; #ifdef RDK_BUILD_CAIRO_SUPPORT { MolDraw2DCairo drawer(300, 300); drawer.drawOptions() = options; drawer.drawMolecule(*m); drawer.finishDrawing(); drawer.writeDrawingText(nameBase + ".png"); } #endif { std::ofstream outs((nameBase + ".svg").c_str()); MolDraw2DSVG drawer(300, 300, outs); drawer.drawOptions() = options; drawer.drawMolecule(*m); drawer.finishDrawing(); outs.flush(); } delete m; } { std::string smiles = "CC(F)(Cl)Br"; std::string nameBase = "test5_3"; ROMol *m = SmilesToMol(smiles); TEST_ASSERT(m); m->getBondBetweenAtoms(1, 2)->setBondDir(Bond::UNKNOWN); RDDepict::compute2DCoords(*m, nullptr, true); WedgeMolBonds(*m, &(m->getConformer())); MolDrawOptions options; options.dummiesAreAttachments = true; #ifdef RDK_BUILD_CAIRO_SUPPORT { MolDraw2DCairo drawer(300, 300); drawer.drawOptions() = options; drawer.drawMolecule(*m); drawer.finishDrawing(); drawer.writeDrawingText(nameBase + ".png"); } #endif { std::ofstream outs((nameBase + ".svg").c_str()); MolDraw2DSVG drawer(300, 300, outs); drawer.drawOptions() = options; drawer.drawMolecule(*m); drawer.finishDrawing(); outs.flush(); } delete m; } std::cout << " Done" << std::endl; } #ifdef RDK_TEST_MULTITHREADED #include #include namespace { void runblock(const std::vector &mols, const std::vector &refData, unsigned int count, unsigned int idx) { for (unsigned int j = 0; j < 200; j++) { for (unsigned int i = 0; i < mols.size(); ++i) { if (i % count != idx) { continue; } ROMol *mol = mols[i]; MolDraw2DSVG drawer(300, 300); drawer.drawMolecule(*mol); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); TEST_ASSERT(text == refData[i]); } } } } // namespace void testMultiThreaded() { std::cout << " ----------------- Test multi-threaded drawing" << std::endl; std::string fName = getenv("RDBASE"); fName += "/Data/NCI/first_200.props.sdf"; RDKit::SDMolSupplier suppl(fName); std::cerr << "reading molecules" << std::endl; std::vector mols; while (!suppl.atEnd() && mols.size() < 100) { ROMol *mol = nullptr; try { mol = suppl.next(); } catch (...) { continue; } if (!mol) { continue; } mols.push_back(mol); } std::cerr << "generating reference drawings" << std::endl; std::vector refData(mols.size()); for (unsigned int i = 0; i < mols.size(); ++i) { MolDraw2DSVG drawer(300, 300); drawer.drawMolecule(*(mols[i])); drawer.finishDrawing(); refData[i] = drawer.getDrawingText(); TEST_ASSERT(refData[i].find("") != std::string::npos); } std::vector> tg; unsigned int count = 4; std::cerr << "processing" << std::endl; for (unsigned int i = 0; i < count; ++i) { std::cerr << " launch :" << i << std::endl; std::cerr.flush(); tg.emplace_back( std::async(std::launch::async, runblock, mols, refData, count, i)); } for (auto &fut : tg) { fut.get(); } for (auto &&mol : mols) { delete mol; } std::cerr << " Done" << std::endl; } #else void testMultiThreaded() {} #endif void test6() { std::cout << " ----------------- Test 6 (atom labels)" << std::endl; { std::string smiles = "CC[13CH2][CH2:7][CH-]C[15NH2+]C"; std::string nameBase = "test5_1"; ROMol *m = SmilesToMol(smiles); TEST_ASSERT(m); RDDepict::compute2DCoords(*m); WedgeMolBonds(*m, &(m->getConformer())); MolDraw2DSVG drawer(300, 300); drawer.drawMolecule(*m); drawer.finishDrawing(); std::string txt = drawer.getDrawingText(); std::ofstream outs("test6_1.svg"); outs << txt; // TEST_ASSERT(txt.find("getBondType() != Bond::AROMATIC); TEST_ASSERT(nm.getBondBetweenAtoms(0, 1)->getIsAromatic()); TEST_ASSERT(nm.getBondBetweenAtoms(6, 7)->getBondType() == Bond::SINGLE); TEST_ASSERT(nm.getBondBetweenAtoms(6, 7)->getBondDir() == Bond::BEGINWEDGE); // make sure we can do it again: MolDraw2DUtils::prepareMolForDrawing(nm); TEST_ASSERT(nm.getNumAtoms() == 9); TEST_ASSERT(nm.getNumConformers() == 1); TEST_ASSERT(nm.getBondBetweenAtoms(0, 1)->getBondType() != Bond::AROMATIC); TEST_ASSERT(nm.getBondBetweenAtoms(0, 1)->getIsAromatic()); } { RWMol nm(*m); TEST_ASSERT(nm.getNumAtoms() == 9) MolDraw2DUtils::prepareMolForDrawing(nm, false); TEST_ASSERT(nm.getNumAtoms() == 9); TEST_ASSERT(nm.getNumConformers() == 1); TEST_ASSERT(nm.getBondBetweenAtoms(0, 1)->getBondType() == Bond::AROMATIC); TEST_ASSERT(nm.getBondBetweenAtoms(0, 1)->getIsAromatic()); } { RWMol nm(*m); TEST_ASSERT(nm.getNumAtoms() == 9) MolDraw2DUtils::prepareMolForDrawing(nm, false, false); TEST_ASSERT(nm.getNumAtoms() == 9); TEST_ASSERT(nm.getNumConformers() == 1); TEST_ASSERT(nm.getBondBetweenAtoms(0, 1)->getBondType() == Bond::AROMATIC); TEST_ASSERT(nm.getBondBetweenAtoms(0, 1)->getIsAromatic()); } { RWMol nm(*m); TEST_ASSERT(nm.getNumAtoms() == 9) MolDraw2DUtils::prepareMolForDrawing(nm, false, true); TEST_ASSERT(nm.getNumAtoms() == 9); TEST_ASSERT(nm.getNumConformers() == 1); TEST_ASSERT(nm.getBondBetweenAtoms(0, 1)->getBondType() == Bond::AROMATIC); TEST_ASSERT(nm.getBondBetweenAtoms(0, 1)->getIsAromatic()); } { RWMol nm(*m); TEST_ASSERT(nm.getNumAtoms() == 9) MolDraw2DUtils::prepareMolForDrawing(nm, true, true, false); TEST_ASSERT(nm.getNumAtoms() == 9); TEST_ASSERT(nm.getNumConformers() == 1); TEST_ASSERT(nm.getBondBetweenAtoms(0, 1)->getBondType() != Bond::AROMATIC); TEST_ASSERT(nm.getBondBetweenAtoms(0, 1)->getIsAromatic()); TEST_ASSERT(nm.getBondBetweenAtoms(6, 7)->getBondType() == Bond::SINGLE); TEST_ASSERT(nm.getBondBetweenAtoms(6, 7)->getBondDir() == Bond::NONE); } { // by default we don't force conformer generation RWMol nm(*m); RDDepict::compute2DCoords(nm); nm.getConformer().set3D(true); // it's not really, we're cheating TEST_ASSERT(nm.getNumAtoms() == 9) MolDraw2DUtils::prepareMolForDrawing(nm); TEST_ASSERT(nm.getNumAtoms() == 9); TEST_ASSERT(nm.getNumConformers() == 1); // we have a conformer anyway TEST_ASSERT(nm.getConformer().is3D()); // but if we do force, it blows out that conformer: MolDraw2DUtils::prepareMolForDrawing(nm, true, true, true, true); TEST_ASSERT(!nm.getConformer().is3D()); } delete m; } { std::string smiles = "C1CC[C@H]2NCCCC2C1"; ROMol *m = SmilesToMol(smiles); TEST_ASSERT(m); { RWMol nm(*m); TEST_ASSERT(nm.getNumAtoms() == 10) MolDraw2DUtils::prepareMolForDrawing(nm); TEST_ASSERT(nm.getNumAtoms() == 11); TEST_ASSERT(nm.getNumConformers() == 1); TEST_ASSERT(!nm.getConformer().is3D()); TEST_ASSERT(nm.getBondBetweenAtoms(3, 10)->getBondType() == Bond::SINGLE); TEST_ASSERT(nm.getBondBetweenAtoms(3, 10)->getBondDir() == Bond::BEGINDASH); // make sure we can do it again: MolDraw2DUtils::prepareMolForDrawing(nm); TEST_ASSERT(nm.getNumAtoms() == 11); TEST_ASSERT(nm.getNumConformers() == 1); TEST_ASSERT(nm.getBondBetweenAtoms(3, 10)->getBondType() == Bond::SINGLE); TEST_ASSERT(nm.getBondBetweenAtoms(3, 10)->getBondDir() == Bond::BEGINDASH); } { RWMol nm(*m); TEST_ASSERT(nm.getNumAtoms() == 10) MolDraw2DUtils::prepareMolForDrawing(nm, false, false); TEST_ASSERT(nm.getNumAtoms() == 10); TEST_ASSERT(nm.getNumConformers() == 1); TEST_ASSERT(nm.getBondBetweenAtoms(3, 2)->getBondType() == Bond::SINGLE); TEST_ASSERT(nm.getBondBetweenAtoms(3, 2)->getBondDir() == Bond::BEGINWEDGE); } delete m; } std::cerr << " Done" << std::endl; } void testGithub781() { std::cout << " ----------------- Test Github #781: Rendering single-atom " "molecules" << std::endl; { auto m = "C"_smiles; TEST_ASSERT(m); RDDepict::compute2DCoords(*m); MolDraw2DSVG drawer(300, 300); drawer.drawMolecule(*m); drawer.finishDrawing(); std::string txt = drawer.getDrawingText(); TEST_ASSERT(txt.find("C") != std::string::npos); // the first radical marker TEST_ASSERT( txt.find( "getConformer())); std::ofstream outs("test910_1.svg"); MolDraw2DSVG drawer(600, 300, outs); drawer.drawMolecule(*m); drawer.finishDrawing(); outs.flush(); delete m; } { // now with Hs // this is a ChEMBL molecule std::string smiles = "CSCC[C@H](NC(=O)[C@@H](CCC(N)=O)NC(=O)[C@@H](N)Cc1c[nH]c2ccccc12)C(=" "O)" "NCC(=O)N[C@@H](Cc1c[nH]cn1)C(=O)N[C@@H](CO)C(=O)O"; RWMol *m = SmilesToMol(smiles); TEST_ASSERT(m); MolDraw2DUtils::prepareMolForDrawing(*m); std::ofstream outs("test910_2.svg"); MolDraw2DSVG drawer(600, 300, outs); drawer.drawMolecule(*m); drawer.finishDrawing(); outs.flush(); delete m; } std::cerr << " Done" << std::endl; } void testGithub932() { std::cout << " ----------------- Test Github #932: mistake in SVG for " "wedged bonds" << std::endl; { std::string smiles = "CC[C@](F)(Cl)Br"; RWMol *m = SmilesToMol(smiles); TEST_ASSERT(m); MolDraw2DUtils::prepareMolForDrawing(*m); MolDraw2DSVG drawer(200, 200); drawer.drawMolecule(*m); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); TEST_ASSERT(text.find("evenoddstroke") == std::string::npos); delete m; } std::cerr << " Done" << std::endl; } void testGithub953() { std::cout << " ----------------- Test Github #953: default color should " "not be cyan" << std::endl; { std::string smiles = "[Nb]"; RWMol *m = SmilesToMol(smiles); TEST_ASSERT(m); MolDraw2DUtils::prepareMolForDrawing(*m); MolDraw2DSVG drawer(200, 200); drawer.drawMolecule(*m); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); TEST_ASSERT(text.find("#00FFFF") == std::string::npos); delete m; } std::cerr << " Done" << std::endl; } void testGithub983() { std::cout << " ----------------- Test Github #983: wedged bonds between " "chiral centers drawn improperly" << std::endl; { // this has an ugly drawing (wedged bond between chiral centers) but we // force it to be drawn that way just to check. std::string mb = "\n\ Mrv1561 07241608122D\n\ \n\ 6 5 0 0 0 0 999 V2000\n\ 8.6830 -9.5982 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n\ 9.3975 -9.1857 0.0000 C 0 0 2 0 0 0 0 0 0 0 0 0\n\ 10.1120 -9.5982 0.0000 C 0 0 1 0 0 0 0 0 0 0 0 0\n\ 9.3975 -8.3607 0.0000 Cl 0 0 0 0 0 0 0 0 0 0 0 0\n\ 10.8264 -9.1857 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n\ 10.1120 -10.4232 0.0000 F 0 0 0 0 0 0 0 0 0 0 0 0\n\ 1 2 1 0 0 0 0\n\ 3 5 1 0 0 0 0\n\ 3 2 1 1 0 0 0\n\ 2 4 1 1 0 0 0\n\ 3 6 1 0 0 0 0\n\ M END"; RWMol *m = MolBlockToMol(mb, false, false); TEST_ASSERT(m); MolOps::sanitizeMol(*m); MolDraw2DUtils::prepareMolForDrawing(*m); MolDraw2DSVG drawer(200, 200); drawer.drawMolecule(*m); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); std::ofstream outs("test983_1.svg"); outs << text; outs.flush(); #ifdef RDK_BUILD_FREETYPE_SUPPORT TEST_ASSERT(text.find("2") != std::string::npos) { ++count; } #endif } #ifdef RDK_BUILD_FREETYPE_SUPPORT TEST_ASSERT(count == 8); #else // the first superscript 2 TEST_ASSERT(count == 1); #endif } { auto m = "C([3H])([3H])([3H])[3H]"_smiles; RDDepict::compute2DCoords(*m); std::string nameBase = "testNoTritium"; std::ofstream outs((nameBase + ".svg").c_str()); MolDraw2DSVG drawer(300, 300, outs); drawer.drawOptions().atomLabelDeuteriumTritium = false; drawer.drawMolecule(*m); drawer.finishDrawing(); outs.close(); std::ifstream ins((nameBase + ".svg").c_str()); bool ok = true; unsigned int count = 0; while (ok) { std::string line; std::getline(ins, line); ok = (ins.good() && !ins.eof()); if (!ok) { continue; } #ifdef RDK_BUILD_FREETYPE_SUPPORT // there are no characters to look for, but each atom should // be made of 2 glyphs, the superscript 3 and the H. if ((line.find("atom-") != std::string::npos)) { ++count; } #else if (line.find("3") != std::string::npos) { ++count; } #endif } #ifdef RDK_BUILD_FREETYPE_SUPPORT TEST_ASSERT(count == 8); #else TEST_ASSERT(count == 1); #endif } { auto m = "C([2H])([2H])([2H])[2H]"_smiles; RDDepict::compute2DCoords(*m); std::string nameBase = "testDeuterium"; std::ofstream outs((nameBase + ".svg").c_str()); MolDraw2DSVG drawer(300, 300, outs); drawer.drawOptions().atomLabelDeuteriumTritium = true; drawer.drawMolecule(*m); drawer.finishDrawing(); outs.close(); std::ifstream ins((nameBase + ".svg").c_str()); bool ok = true; unsigned int count = 0; while (ok) { std::string line; std::getline(ins, line); ok = (ins.good() && !ins.eof()); if (!ok) { continue; } #ifdef RDK_BUILD_FREETYPE_SUPPORT // there should be just 1 glyph per atom - a D if ((line.find("atom-") != std::string::npos)) { ++count; } #else if ((line.find("baseline-shift:super") == std::string::npos) && (line.find(">2<") == std::string::npos) && (line.find(">D<") != std::string::npos)) { ++count; } #endif } TEST_ASSERT(count == 4); } { auto m = "C([3H])([3H])([3H])[3H]"_smiles; RDDepict::compute2DCoords(*m); std::string nameBase = "testTritium"; std::ofstream outs((nameBase + ".svg").c_str()); MolDraw2DSVG drawer(300, 300, outs); drawer.drawOptions().atomLabelDeuteriumTritium = true; drawer.drawMolecule(*m); drawer.finishDrawing(); outs.close(); std::ifstream ins((nameBase + ".svg").c_str()); bool ok = true; unsigned int count = 0; while (ok) { std::string line; std::getline(ins, line); ok = (ins.good() && !ins.eof()); if (!ok) { continue; } #ifdef RDK_BUILD_FREETYPE_SUPPORT // there should be just 1 glyph per atom - a T if ((line.find("atom-") != std::string::npos)) { ++count; } #else if ((line.find("baseline-shift:super") == std::string::npos) && (line.find(">3<") == std::string::npos) && (line.find(">T<") != std::string::npos)) { ++count; } #endif } TEST_ASSERT(count == 4); } std::cerr << " Done" << std::endl; } void testCrossedBonds() { std::cerr << " ----------------- Test crossed bonds" << std::endl; { std::string smiles = "CC=CC"; RWMol *m = SmilesToMol(smiles); TEST_ASSERT(m); m->getBondWithIdx(1)->setBondDir(Bond::EITHERDOUBLE); MolDraw2DUtils::prepareMolForDrawing(*m); std::string nameBase = "crossed_bonds"; std::ofstream outs((nameBase + ".svg").c_str()); MolDraw2DSVG drawer(300, 300, outs); drawer.drawMolecule(*m); drawer.finishDrawing(); outs.close(); delete m; } std::cerr << " Done" << std::endl; } void test10DrawSecondMol() { std::cout << " ----------------- Testing drawing a second molecule" << std::endl; std::string mb1 = "\n\ Mrv1561 08301611102D\n\ \n\ 3 2 0 0 0 0 999 V2000\n\ -2.5670 1.3616 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n\ -1.8525 1.7741 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n\ -1.1380 1.3616 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n\ 1 2 1 0 0 0 0\n\ 2 3 1 0 0 0 0\n\ M END"; RWMol *m1 = MolBlockToMol(mb1); TEST_ASSERT(m1); MolOps::sanitizeMol(*m1); MolDraw2DUtils::prepareMolForDrawing(*m1); RDGeom::Point3D c1 = MolTransforms::computeCentroid(m1->getConformer()); for (unsigned int i = 0; i < m1->getNumAtoms(); ++i) { RDGeom::Point3D &p = m1->getConformer().getAtomPos(i); p -= c1; } std::string mb2 = "\n\ Mrv1561 08301611122D\n\ \n\ 3 2 0 0 0 0 999 V2000\n\ -1.9900 2.2136 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n\ -1.5775 1.4991 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n\ -1.9900 0.7846 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n\ 1 2 1 0 0 0 0\n\ 2 3 1 0 0 0 0\n\ M END"; RWMol *m2 = MolBlockToMol(mb2); TEST_ASSERT(m2); MolOps::sanitizeMol(*m2); MolDraw2DUtils::prepareMolForDrawing(*m2); RDGeom::Point3D c2 = MolTransforms::computeCentroid(m2->getConformer()); for (unsigned int i = 0; i < m2->getNumAtoms(); ++i) { RDGeom::Point3D &p = m2->getConformer().getAtomPos(i); p -= c2; } { MolDraw2DSVG drawer(200, 200); drawer.drawOptions().padding = 0.2; drawer.drawMolecule(*m1); drawer.drawMolecule(*m2); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); std::ofstream outs("test10_1.svg"); outs << text; outs.flush(); } { MolDraw2DSVG drawer(200, 200); drawer.drawOptions().padding = 0.2; drawer.drawMolecule(*m2); drawer.drawMolecule(*m1); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); std::ofstream outs("test10_2.svg"); outs << text; outs.flush(); } { MolDraw2DSVG drawer(400, 200, 200, 200); drawer.drawOptions().padding = 0.2; drawer.drawMolecule(*m1); drawer.setOffset(200, 0); drawer.drawMolecule(*m2); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); std::ofstream outs("test10_3.svg"); outs << text; outs.flush(); } { MolDraw2DSVG drawer(200, 400, 200, 200); drawer.drawOptions().padding = 0.2; drawer.drawMolecule(*m1); drawer.setOffset(0, 200); drawer.drawMolecule(*m2); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); std::ofstream outs("test10_4.svg"); outs << text; outs.flush(); } { MolDraw2DSVG drawer(200, 400, 200, 200); Point2D minv(1000, 1000); Point2D maxv(-1000, -1000); for (unsigned int i = 0; i < m1->getNumAtoms(); ++i) { const RDGeom::Point3D &pti = m1->getConformer().getAtomPos(i); minv.x = std::min(minv.x, pti.x); minv.y = std::min(minv.y, pti.y); maxv.x = std::max(maxv.x, pti.x); maxv.y = std::max(maxv.y, pti.y); } drawer.setScale(200, 200, minv, maxv); drawer.drawMolecule(*m1); drawer.setOffset(0, 200); drawer.drawMolecule(*m2); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); std::ofstream outs("test10_5.svg"); outs << text; outs.flush(); } { MolDraw2DSVG drawer(200, 400, 200, 200); Point2D minv(1000, 1000); Point2D maxv(-1000, -1000); for (unsigned int i = 0; i < m1->getNumAtoms(); ++i) { const RDGeom::Point3D &pti = m1->getConformer().getAtomPos(i); minv.x = std::min(minv.x, pti.x); minv.y = std::min(minv.y, pti.y); maxv.x = std::max(maxv.x, pti.x); maxv.y = std::max(maxv.y, pti.y); } drawer.drawOptions().padding = 0.2; drawer.setScale(200, 200, minv, maxv); drawer.drawMolecule(*m1); drawer.setOffset(0, 200); drawer.drawMolecule(*m2); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); std::ofstream outs("test10_6.svg"); outs << text; outs.flush(); } delete m1; delete m2; std::cerr << " Done" << std::endl; } void test11DrawMolGrid() { std::cout << " ----------------- Testing drawing a grid of molecules" << std::endl; std::string smiles = "COc1cccc(NC(=O)[C@H](Cl)Sc2nc(ns2)c3ccccc3Cl)c1"; // made up RWMol *m1 = SmilesToMol(smiles); TEST_ASSERT(m1); MolDraw2DUtils::prepareMolForDrawing(*m1); RDGeom::Point3D c1 = MolTransforms::computeCentroid(m1->getConformer()); for (unsigned int i = 0; i < m1->getNumAtoms(); ++i) { RDGeom::Point3D &p = m1->getConformer().getAtomPos(i); p -= c1; } smiles = "NC(=O)[C@H](Cl)Sc1ncns1"; // made up RWMol *m2 = SmilesToMol(smiles); TEST_ASSERT(m2); MolDraw2DUtils::prepareMolForDrawing(*m2); RDGeom::Point3D c2 = MolTransforms::computeCentroid(m2->getConformer()); for (unsigned int i = 0; i < m2->getNumAtoms(); ++i) { RDGeom::Point3D &p = m2->getConformer().getAtomPos(i); p -= c2; } smiles = "BrCNC(=O)[C@H](Cl)Sc1ncns1"; // made up RWMol *m3 = SmilesToMol(smiles); TEST_ASSERT(m3); MolDraw2DUtils::prepareMolForDrawing(*m3); RDGeom::Point3D c3 = MolTransforms::computeCentroid(m3->getConformer()); for (unsigned int i = 0; i < m3->getNumAtoms(); ++i) { RDGeom::Point3D &p = m3->getConformer().getAtomPos(i); p -= c3; } { MolDraw2DSVG drawer(500, 400, 250, 200); drawer.drawMolecule(*m1, "m1"); drawer.setOffset(250, 0); drawer.drawMolecule(*m2, "m2"); drawer.setOffset(0, 200); drawer.drawMolecule(*m3, "m3"); drawer.setOffset(250, 200); drawer.drawMolecule(*m1, "m4"); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); std::ofstream outs("test11_1.svg"); outs << text; outs.flush(); } { // drawing "out of order" MolDraw2DSVG drawer(500, 400, 250, 200); drawer.setOffset(250, 0); drawer.drawMolecule(*m1, "m1"); drawer.setOffset(0, 0); drawer.drawMolecule(*m2, "m2"); drawer.setOffset(0, 200); drawer.drawMolecule(*m1, "m3"); drawer.setOffset(250, 200); drawer.drawMolecule(*m2, "m4"); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); std::ofstream outs("test11_2.svg"); outs << text; outs.flush(); } delete m1; delete m2; delete m3; std::cerr << " Done" << std::endl; } void test12DrawMols() { std::cout << " ----------------- Testing drawMolecules" << std::endl; auto setup_mol = [](const std::string &smi, const std::string leg, std::vector &mols, std::vector &legends) { mols.push_back(SmilesToMol(smi)); TEST_ASSERT(mols.back()); legends.push_back(leg); }; std::vector mols; std::unique_ptr> legends( new std::vector()); // made up SMILES, each with sequence F, Cl, Br so we can see which // ones are drawn, which ones are missing. setup_mol("COc1cccc(NC(=O)[C@H](F)Sc2nc(ns2)c3ccccc3F)c1", "m1", mols, *legends); setup_mol("NC(=O)[C@H](F)Sc1ncns1", "m2", mols, *legends); setup_mol("COc1cccc(NC(=O)[C@H](Cl)Sc2nc(ns2)c3ccccc3F)c1", "m3", mols, *legends); setup_mol("NC(=O)[C@H](Cl)Sc1ncns1", "m4", mols, *legends); setup_mol("COc1cccc(NC(=O)[C@H](Br)Sc2nc(ns2)c3ccccc3F)c1", "m5", mols, *legends); setup_mol("NC(=O)[C@H](Br)Sc1ncns1", "m6", mols, *legends); { MolDraw2DSVG drawer(750, 400, 250, 200); drawer.drawMolecules(mols, legends.get()); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); std::ofstream outs("test12_1.svg"); outs << text; outs.flush(); } { // github #1325: multiple molecules in one pane MolDraw2DSVG drawer(300, 300, 300, 300); drawer.drawMolecules(mols); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); std::ofstream outs("test12_3.svg"); outs << text; outs.flush(); } { // github #1325: multiple molecules in one pane MolDraw2DSVG drawer(300, 300); drawer.drawMolecules(mols); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); std::ofstream outs("test12_4.svg"); outs << text; outs.flush(); } { delete mols[2]; delete mols[4]; mols[2] = nullptr; mols[4] = nullptr; MolDraw2DSVG drawer(750, 400, 250, 200); drawer.drawMolecules(mols); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); std::ofstream outs("test12_2.svg"); outs << text; outs.flush(); } for (auto m : mols) { delete m; } std::cerr << " Done" << std::endl; } void test13JSONConfig() { std::cerr << " ----------------- Test JSON Configuration" << std::endl; { auto m = "CCO"_smiles; TEST_ASSERT(m); MolDraw2DUtils::prepareMolForDrawing(*m); MolDraw2DSVG drawer(250, 200); const char *json = "{\"legendColour\":[1.0,0.5,1.0], \"rotate\": 90, " "\"bondLineWidth\": 5}"; MolDraw2DUtils::updateDrawerParamsFromJSON(drawer, json); drawer.drawMolecule(*m, "foo"); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); std::ofstream outs("test13_1.svg"); outs << text; outs.close(); #ifdef RDK_BUILD_FREETYPE_SUPPORT // we'll just have to assume that this pink is for the legend TEST_ASSERT(text.find("' fill='#FF7FFF") != std::string::npos); TEST_ASSERT(text.find("1"); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); std::ofstream outs("testGithub1090_1.svg"); outs << text; outs.flush(); TEST_ASSERT(text.find("C&1") == std::string::npos); TEST_ASSERT(text.find("<<") == std::string::npos); TEST_ASSERT(text.find(">>") == std::string::npos); TEST_ASSERT(text.find("d&l") == std::string::npos); } delete m1; std::cerr << " Done" << std::endl; } void testGithub1035() { std::cout << " ----------------- Testing github 1035: overflow bug in SVG " "color generation" << std::endl; std::string smiles = "CCOC"; // made up RWMol *m1 = SmilesToMol(smiles); TEST_ASSERT(m1); MolDraw2DUtils::prepareMolForDrawing(*m1); std::vector highlights; highlights.push_back(0); highlights.push_back(1); { MolDraw2DSVG drawer(250, 200); drawer.drawOptions().highlightColour = DrawColour(1.1, .5, .5); bool ok = false; try { drawer.drawMolecule(*m1, &highlights); } catch (const ValueErrorException &) { ok = true; } TEST_ASSERT(ok); } { MolDraw2DSVG drawer(250, 200); drawer.drawOptions().highlightColour = DrawColour(.1, -.5, .5); bool ok = false; try { drawer.drawMolecule(*m1, &highlights); } catch (const ValueErrorException &) { ok = true; } TEST_ASSERT(ok); } { MolDraw2DSVG drawer(250, 200); drawer.drawOptions().highlightColour = DrawColour(1., .5, 1.5); bool ok = false; try { drawer.drawMolecule(*m1, &highlights); } catch (const ValueErrorException &) { ok = true; } TEST_ASSERT(ok); } delete m1; std::cerr << " Done" << std::endl; } void testGithub1271() { std::cout << " ----------------- Testing github 1271: MolDraw2D not drawing " "anything for molecules aligned with the X or Y axes" << std::endl; { std::string mb = "ethane\n\ RDKit 2D\n\ \n\ 2 1 0 0 0 0 0 0 0 0999 V2000\n\ -0.7500 0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n\ 0.7500 -0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n\ 1 2 1 0\n\ M END"; RWMol *m = MolBlockToMol(mb); TEST_ASSERT(m); MolDraw2DUtils::prepareMolForDrawing(*m); MolDraw2DSVG drawer(200, 200); drawer.drawMolecule(*m); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); std::ofstream outs("test1271_1.svg"); outs << text; outs.flush(); TEST_ASSERT(text.find("d='M 0,200 0,200") == std::string::npos); delete m; } { std::string mb = "ethane\n\ RDKit 2D\n\ \n\ 2 1 0 0 0 0 0 0 0 0999 V2000\n\ -0.0000 0.5000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n\ 0.0000 -0.5000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n\ 1 2 1 0\n\ M END"; RWMol *m = MolBlockToMol(mb); TEST_ASSERT(m); MolDraw2DUtils::prepareMolForDrawing(*m); MolDraw2DSVG drawer(200, 200); drawer.drawMolecule(*m); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); std::ofstream outs("test1271_2.svg"); outs << text; outs.flush(); TEST_ASSERT(text.find("d='M 0,200 0,200") == std::string::npos); delete m; } { std::string mb = "water\n\ RDKit 2D\n\ \n\ 1 0 0 0 0 0 0 0 0 0999 V2000\n\ -0.0000 0.0000 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n\ M END"; RWMol *m = MolBlockToMol(mb); TEST_ASSERT(m); MolDraw2DUtils::prepareMolForDrawing(*m); MolDraw2DSVG drawer(200, 200); drawer.drawMolecule(*m); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); std::ofstream outs("test1271_3.svg"); outs << text; outs.flush(); TEST_ASSERT(text.find("d='M 0,200 0,200") == std::string::npos); delete m; } { std::string mb = "water\n\ RDKit 2D\n\ \n\ 1 0 0 0 0 0 0 0 0 0999 V2000\n\ -0.0000 0.5000 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n\ M END"; RWMol *m = MolBlockToMol(mb); TEST_ASSERT(m); MolDraw2DUtils::prepareMolForDrawing(*m); MolDraw2DSVG drawer(200, 200); drawer.drawMolecule(*m); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); std::ofstream outs("test1271_4.svg"); outs << text; outs.flush(); TEST_ASSERT(text.find("d='M 0,200 0,200") == std::string::npos); delete m; } { std::string smiles = "C=C(O)C(O)"; // made up RWMol *m1 = SmilesToMol(smiles); TEST_ASSERT(m1); MolDraw2DUtils::prepareMolForDrawing(*m1); smiles = "O"; RWMol *m2 = SmilesToMol(smiles); TEST_ASSERT(m2); MolDraw2DUtils::prepareMolForDrawing(*m2); MolDraw2DSVG drawer(500, 200, 250, 200); drawer.drawMolecule(*m1, "m1"); drawer.setOffset(250, 0); drawer.drawMolecule(*m2, "m2"); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); std::ofstream outs("test1271_5.svg"); outs << text; outs.flush(); delete m1; delete m2; } std::cerr << " Done" << std::endl; } void testGithub1322() { std::cout << " ----------------- Testing github 1322: add custom atom labels" << std::endl; { auto m1 = "CCC[Se]"_smiles; // made up TEST_ASSERT(m1); MolDraw2DUtils::prepareMolForDrawing(*m1); { MolDraw2DSVG drawer(500, 200, 250, 200); drawer.drawMolecule(*m1, "m1"); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); std::ofstream outs("test1322_1.svg"); outs << text; outs.flush(); #ifdef RDK_BUILD_FREETYPE_SUPPORT // there should be 2 paths of class atom-3, one for the S, // the other for the e. size_t start_pos = 0; int count = 0; while (true) { start_pos = text.find("atom-3", start_pos); if (start_pos == std::string::npos) { break; } ++count; ++start_pos; } TEST_ASSERT(count == 2); #else TEST_ASSERT(text.find(">S") != std::string::npos); TEST_ASSERT(text.find(">e") != std::string::npos); #endif } { m1->getAtomWithIdx(3)->setProp(common_properties::atomLabel, "customlabel"); MolDraw2DSVG drawer(500, 200, 250, 200); drawer.drawMolecule(*m1, "m1"); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); std::ofstream outs("test1322_2.svg"); outs << text; outs.flush(); #ifdef RDK_BUILD_FREETYPE_SUPPORT // there should be 11 paths of class atom-3, one for each letter // of customlabel size_t start_pos = 0; int count = 0; while (true) { start_pos = text.find("atom-3", start_pos); if (start_pos == std::string::npos) { break; } ++count; ++start_pos; } TEST_ASSERT(count == 11); #else TEST_ASSERT(text.find(">S") == std::string::npos); TEST_ASSERT(text.find(">s") != std::string::npos); TEST_ASSERT(text.find(">b") != std::string::npos); #endif } } std::cerr << " Done" << std::endl; } void test14BWPalette() { std::cout << " ----------------- Testing use of a black & white palette" << std::endl; { std::string smiles = "CNC(Cl)C(=O)O"; RWMol *m1 = SmilesToMol(smiles); TEST_ASSERT(m1); MolDraw2DUtils::prepareMolForDrawing(*m1); { // start with color MolDraw2DSVG drawer(200, 200); drawer.drawMolecule(*m1, "m1"); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); TEST_ASSERT(text.find("stroke:#00CC00") != std::string::npos); std::ofstream outs("test14_1.svg"); outs << text; outs.flush(); } { // now B&W MolDraw2DSVG drawer(200, 200); assignBWPalette(drawer.drawOptions().atomColourPalette); drawer.drawMolecule(*m1, "m1"); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); TEST_ASSERT(text.find("stroke:#00CC00") == std::string::npos); std::ofstream outs("test14_2.svg"); outs << text; outs.flush(); } delete m1; } std::cerr << " Done" << std::endl; } void test15ContinuousHighlightingWithGrid() { std::cerr << " ----------------- Testing use of continuous highlighting with " "drawMolecules" << std::endl; { std::string smiles = "COc1cccc(NC(=O)[C@H](Cl)Sc2nc(ns2)c3ccccc3Cl)c1"; // made up RWMol *m1 = SmilesToMol(smiles); TEST_ASSERT(m1); smiles = "NC(=O)[C@H](Cl)Sc1ncns1"; // made up RWMol *m2 = SmilesToMol(smiles); TEST_ASSERT(m2); std::vector mols; mols.push_back(m1); mols.push_back(m2); std::vector> atHighlights(2); atHighlights[0].push_back(0); atHighlights[0].push_back(1); atHighlights[0].push_back(2); atHighlights[0].push_back(6); atHighlights[1].push_back(0); atHighlights[1].push_back(1); atHighlights[1].push_back(2); atHighlights[1].push_back(6); { MolDraw2DSVG drawer(500, 200, 250, 200); drawer.drawOptions().continuousHighlight = false; drawer.drawMolecules(mols, nullptr, &atHighlights); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); std::ofstream outs("test15_1.svg"); outs << text; outs.flush(); TEST_ASSERT(text.find("stroke:#FF7F7F;stroke-width:4.0px;") == std::string::npos); } { MolDraw2DSVG drawer(500, 200, 250, 200); drawer.drawOptions().continuousHighlight = true; drawer.drawMolecules(mols, nullptr, &atHighlights); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); std::ofstream outs("test15_2.svg"); outs << text; outs.flush(); TEST_ASSERT(text.find("stroke:#FF7F7F;stroke-width:4.3px") != std::string::npos); } for (auto &&mol : mols) { delete mol; } } std::cerr << " Done" << std::endl; } void testGithub1829() { std::cerr << " ----------------- Testing github 1829: crash when " "drawMolecules() is called with an empty list" << std::endl; { std::vector mols; MolDraw2DSVG drawer(750, 400, 250, 200); // this should run quietly without complaining drawer.drawMolecules(mols); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); } std::cerr << " Done" << std::endl; } void test16MoleculeMetadata() { std::cout << " ----------------- Testing inclusion of molecule metadata" << std::endl; { std::string smiles = "CN[C@H](Cl)C(=O)O"; std::unique_ptr m1(SmilesToMol(smiles)); TEST_ASSERT(m1); MolDraw2DUtils::prepareMolForDrawing(*m1); { // one molecule MolDraw2DSVG drawer(200, 200); drawer.drawMolecule(*m1, "m1"); drawer.addMoleculeMetadata(*m1); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); std::ofstream outs("test16_1.svg"); outs << text; outs.flush(); TEST_ASSERT(text.find("idx=\"2\" atom-smiles=\"[NH]\" drawing-x=\"55.") != std::string::npos); TEST_ASSERT(text.find("idx=\"2\" begin-atom-idx=\"3\" end-atom-idx=\"2\" " "bond-smiles=\"-\"") != std::string::npos); } { // multiple molecules MolDraw2DSVG drawer(400, 400, 200, 200); auto *rom = rdcast(m1.get()); std::vector ms = {new ROMol(*rom), new ROMol(*rom), new ROMol(*rom), new ROMol(*rom)}; drawer.drawMolecules(ms); drawer.addMoleculeMetadata(ms); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); std::ofstream outs("test16_2.svg"); outs << text; outs.flush(); TEST_ASSERT(text.find("idx=\"2\" atom-smiles=\"[NH]\" drawing-x=\"55.") != std::string::npos); TEST_ASSERT( text.find("idx=\"2\" atom-smiles=\"[NH]\" drawing-x=\"255.") != std::string::npos); for (auto ptr : ms) { delete ptr; } } } std::cerr << " Done" << std::endl; } void test17MaxMinFontSize() { std::cout << " ----------------- Test 17 - Testing maximum font size" << std::endl; { std::string fName = getenv("RDBASE"); fName += "/Code/GraphMol/MolDraw2D/test_dir"; fName += "/clash.mol"; std::unique_ptr m(MolFileToMol(fName)); std::string nameBase = "test17_"; TEST_ASSERT(m); { std::ofstream outs((nameBase + "1.svg").c_str()); MolDraw2DSVG drawer(300, 300); drawer.drawMolecule(*m); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); outs << text; outs.flush(); #ifdef RDK_BUILD_FREETYPE_SUPPORT // where it starts drawing the N is a poor surrogate for checking // the font size, but all we have. TEST_ASSERT(text.find(" m1(MolBlockToMol(molb)); TEST_ASSERT(m1); MolDraw2DUtils::prepareMolForDrawing(*m1); MolDraw2DSVG drawer(200, 200); drawer.drawMolecule(*m1, "m1"); drawer.addMoleculeMetadata(*m1); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); std::ofstream outs("testGithub2063_1.svg"); outs << text; outs.flush(); TEST_ASSERT( text.find( " m1(MolBlockToMol(molb)); TEST_ASSERT(m1); MolDraw2DUtils::prepareMolForDrawing(*m1); MolDraw2DSVG drawer(200, 200); drawer.drawMolecule(*m1, "m1"); drawer.addMoleculeMetadata(*m1); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); std::ofstream outs("testGithub2063_2.svg"); outs << text; outs.flush(); TEST_ASSERT( text.find( " mols; mols.push_back(m1.get()); mols.push_back(m2.get()); MolDraw2DSVG drawer(500, 250, 250, 250); drawer.drawMolecules(mols); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); std::ofstream outs("testGithub2762.svg"); outs << text; outs.flush(); TEST_ASSERT(text.find("font-size:0px") == std::string::npos); TEST_ASSERT(text.find("'bond-0' d='M 0,200 L 0,200'") == std::string::npos); } std::cerr << " Done" << std::endl; } void testGithub2931() { std::cout << " ----------------- Testing testGithub2931: multi-coloured" " molecule highlights." << std::endl; auto get_all_hit_atoms = [](ROMol &mol, const std::string &smt) -> std::vector { std::vector hit_atoms; RWMol *query = SmartsToMol(smt); std::vector hits_vect; SubstructMatch(mol, *query, hits_vect); for (size_t i = 0; i < hits_vect.size(); ++i) { for (size_t j = 0; j < hits_vect[i].size(); ++j) { hit_atoms.emplace_back(hits_vect[i][j].second); } } delete query; return hit_atoms; }; auto get_all_hit_bonds = [](ROMol &mol, const std::vector &hit_atoms) -> std::vector { std::vector hit_bonds; for (int i : hit_atoms) { for (int j : hit_atoms) { if (i > j) { Bond *bnd = mol.getBondBetweenAtoms(i, j); if (bnd) { hit_bonds.emplace_back(bnd->getIdx()); } } } } return hit_bonds; }; auto update_colour_map = [](const std::vector &ats, DrawColour col, std::map> &ha_map) { for (auto h : ats) { auto ex = ha_map.find(h); if (ex == ha_map.end()) { std::vector cvec(1, col); ha_map.insert(make_pair(h, cvec)); } else { if (ex->second.end() == find(ex->second.begin(), ex->second.end(), col)) { ex->second.emplace_back(col); } } } }; { std::string smiles = "CO[C@@H](O)C1=C(O[C@H](F)Cl)C(C#N)=C1ONNC[NH3+]"; std::unique_ptr m(SmilesToMol(smiles)); RDDepict::compute2DCoords(*m); WedgeMolBonds(*m, &(m->getConformer())); std::vector smarts = {"CONN", "N#CC~CO", "C=CON", "CONNCN"}; std::vector colours = { DrawColour(1.0, 0.0, 0.0), DrawColour(0.0, 1.0, 0.0), DrawColour(0.0, 0.0, 1.0), DrawColour(1.0, 0.55, 0.0)}; std::map> ha_map; std::map> hb_map; for (size_t i = 0; i < smarts.size(); ++i) { std::vector hit_atoms = get_all_hit_atoms(*m, smarts[i]); std::vector hit_bonds = get_all_hit_bonds(*m, hit_atoms); update_colour_map(hit_atoms, colours[i], ha_map); update_colour_map(hit_bonds, colours[i], hb_map); } std::map h_rads; std::map h_lw_mult; { MolDraw2DSVG drawer(500, 500); drawer.drawOptions().fillHighlights = false; drawer.drawOptions().continuousHighlight = true; drawer.drawMoleculeWithHighlights(*m, "Test 1", ha_map, hb_map, h_rads, h_lw_mult); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); std::ofstream outs("testGithub2931_1.svg"); outs << text; outs.flush(); TEST_ASSERT(text.find("stroke:#FF8C00;stroke-width:5.6px") != std::string::npos); #ifdef RDK_BUILD_FREETYPE_SUPPORT TEST_ASSERT(text.find("b") != std::string::npos); #endif } { auto m = "CCCC"_smiles; TEST_ASSERT(m); MolDraw2DUtils::prepareMolForDrawing(*m); MolDraw2DSVG drawer(250, 200); drawer.drawMolecule(*m, "foo\nbar"); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); std::ofstream outs("testGithub3112_2.svg"); outs << text; outs.close(); #ifdef RDK_BUILD_FREETYPE_SUPPORT // this is the b on the 2nd line. TEST_ASSERT(text.find("b") != std::string::npos); #endif } { auto m = "CCCC"_smiles; TEST_ASSERT(m); MolDraw2DUtils::prepareMolForDrawing(*m); MolDraw2DSVG drawer(250, 200); drawer.drawMolecule( *m, "No one in their right mind would have a legend this long, surely."); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); std::ofstream outs("testGithub3112_3.svg"); outs << text; outs.close(); #ifdef RDK_BUILD_FREETYPE_SUPPORT // The first letter, N. TEST_ASSERT(text.find("N") != std::string::npos); #endif } { auto m = "CCCC"_smiles; TEST_ASSERT(m); MolDraw2DUtils::prepareMolForDrawing(*m); MolDraw2DSVG drawer(250, 200); drawer.drawMolecule( *m, "No one in their right mind would\nhave a legend this long, surely."); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); std::ofstream outs("testGithub3112_4.svg"); outs << text; outs.close(); #ifdef RDK_BUILD_FREETYPE_SUPPORT // The first letter, N TEST_ASSERT(text.find("N") != std::string::npos); #endif } std::cerr << " Done" << std::endl; } void test20Annotate() { std::cout << " ----------------- Testing annotation of 2D Drawing." << std::endl; // add serial numbers to the atoms in the molecule. // There's an option for this, but for debugging it's sometimes // useful to be able to put notes on just a few atoms. auto addAtomSerialNumbers = [](ROMol &mol) { for (auto atom : mol.atoms()) { atom->setProp(common_properties::atomNote, atom->getIdx()); } }; auto addBondSerialNumbers = [](ROMol &mol) { for (auto bond : mol.bonds()) { bond->setProp(common_properties::bondNote, bond->getIdx()); } }; { auto m1 = "S=C1N=C(NC(CC#N)(C)C=C=C)NC2=NNN=C21"_smiles; addAtomSerialNumbers(*m1); addBondSerialNumbers(*m1); #ifdef RDK_BUILD_CAIRO_SUPPORT { MolDraw2DCairo drawer(500, 500); drawer.drawMolecule(*m1); drawer.finishDrawing(); drawer.writeDrawingText("test20_1.png"); } #endif MolDraw2DSVG drawer(500, 500); drawer.drawMolecule(*m1); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); std::ofstream outs("test20_1.svg"); outs << text; outs.flush(); #ifdef RDK_BUILD_FREETYPE_SUPPORT // first note (atom 0) TEST_ASSERT(text.find("1") != std::string::npos); #endif } { auto m1 = "C[C@@H](F)/C=C/[C@H](O)C"_smiles; #ifdef RDK_BUILD_CAIRO_SUPPORT { MolDraw2DCairo drawer(300, 300); drawer.drawOptions().addStereoAnnotation = true; drawer.drawMolecule(*m1); drawer.finishDrawing(); drawer.writeDrawingText("test20_2.png"); } #endif MolDraw2DSVG drawer(500, 500); drawer.drawOptions().addStereoAnnotation = true; drawer.drawMolecule(*m1); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); std::ofstream outs("test20_2.svg"); outs << text; outs.flush(); #ifdef RDK_BUILD_FREETYPE_SUPPORT // last note TEST_ASSERT(text.find("E") != std::string::npos); #endif } { auto m1 = "S=C1N=C(NC(CC#N)(C)C=C=C)NC2=NNN=C21"_smiles; auto atom = m1->getAtomWithIdx(3); atom->setProp("atomNote", "foolish annotation"); auto bond = m1->getBondWithIdx(5); bond->setProp("bondNote", "way too long to be useful"); #ifdef RDK_BUILD_CAIRO_SUPPORT { MolDraw2DCairo drawer(300, 300); drawer.drawOptions().addStereoAnnotation = true; drawer.drawMolecule(*m1); drawer.finishDrawing(); drawer.writeDrawingText("test20_3.png"); } #endif MolDraw2DSVG drawer(500, 500); drawer.drawOptions().addStereoAnnotation = true; drawer.drawMolecule(*m1); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); std::ofstream outs("test20_3.svg"); outs << text; outs.flush(); #ifdef RDK_BUILD_FREETYPE_SUPPORT // first note TEST_ASSERT(text.find("f") != std::string::npos); #endif } { auto m1 = "S=C1N=C(NC(CC#N)(C)C=C=C)NC2=NNN=C21"_smiles; #ifdef RDK_BUILD_CAIRO_SUPPORT { MolDraw2DCairo drawer(200, 200); drawer.drawOptions().addAtomIndices = true; drawer.drawMolecule(*m1); drawer.finishDrawing(); drawer.writeDrawingText("test20_4.png"); } #endif MolDraw2DSVG drawer(200, 200); drawer.drawOptions().addAtomIndices = true; drawer.drawMolecule(*m1); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); std::ofstream outs("test20_4.svg"); outs << text; outs.flush(); #ifdef RDK_BUILD_FREETYPE_SUPPORT // first note (atom 0) TEST_ASSERT(text.find("1") != std::string::npos); #endif } std::cerr << " Done" << std::endl; } void test21FontFile() { #ifdef RDK_BUILD_FREETYPE_SUPPORT std::cout << " ----------------- Test 21 - different font" << std::endl; // You have to look at this one, there's no algorithmic check. { auto m = "CO[C@@H](O)C1=C(O[C@H](F)Cl)C(C#N)=C1ONNC[NH3+]"_smiles; TEST_ASSERT(m); RDDepict::compute2DCoords(*m); WedgeMolBonds(*m, &(m->getConformer())); std::ofstream outs("test21_1.svg"); MolDraw2DSVG drawer(500, 500, outs); std::string fName = getenv("RDBASE"); fName += "/Data/Fonts/Amadeus.ttf"; drawer.drawOptions().fontFile = fName; drawer.drawMolecule(*m); drawer.finishDrawing(); outs.flush(); } { auto m = "CO[C@@H](O)C1=C(O[C@H](F)Cl)C(C#N)=C1ONNC[NH3+]"_smiles; TEST_ASSERT(m); RDDepict::compute2DCoords(*m); WedgeMolBonds(*m, &(m->getConformer())); std::ofstream outs("test21_2.svg"); MolDraw2DSVG drawer(500, 500, outs); std::string fName = getenv("RDBASE"); fName += "/Data/Fonts/No_Such_Font_File.ttf"; drawer.drawOptions().fontFile = fName; drawer.drawMolecule(*m); drawer.finishDrawing(); outs.flush(); } std::cerr << "Done" << std::endl; #endif } void test22ExplicitMethyl() { std::cout << " ----------------- Test 22 - draw explicit methyls." << std::endl; auto m = "CCC(C#C)C=C"_smiles; TEST_ASSERT(m); RDDepict::compute2DCoords(*m); { MolDraw2DSVG drawer(300, 300); drawer.drawMolecule(*m); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); std::ofstream outs("test22_1.svg"); outs << text; outs.flush(); TEST_ASSERT(text.find("class='atom-") == std::string::npos); } { MolDraw2DSVG drawer(300, 300); drawer.drawOptions().explicitMethyl = true; drawer.drawMolecule(*m); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); std::ofstream outs("test22_2.svg"); outs << text; outs.flush(); TEST_ASSERT(text.find("class='atom-") != std::string::npos); } std::cerr << "Done" << std::endl; } void testGithub3305() { std::cout << " ----------------- Test Github 3305 - change and scale line widths." << std::endl; auto m = "CCC(C#C)C=C"_smiles; TEST_ASSERT(m); RDDepict::compute2DCoords(*m); std::string nameBase = "testGithub3305_"; { MolDraw2DSVG drawer(300, 300); drawer.drawMolecule(*m); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); std::ofstream outs(nameBase + "1.svg"); outs << text; outs.flush(); TEST_ASSERT(text.find("stroke-width:2.0px") != std::string::npos); } { MolDraw2DSVG drawer(600, 600); drawer.drawOptions().bondLineWidth = 2; drawer.drawMolecule(*m); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); std::ofstream outs(nameBase + "2.svg"); outs << text; outs.flush(); TEST_ASSERT(text.find("stroke-width:2.0px") != std::string::npos); } { MolDraw2DSVG drawer(600, 600); drawer.drawOptions().bondLineWidth = 2; drawer.drawOptions().scaleBondWidth = true; drawer.drawMolecule(*m); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); std::ofstream outs(nameBase + "3.svg"); outs << text; outs.flush(); TEST_ASSERT(text.find("stroke-width:4.2px") != std::string::npos); } #ifdef RDK_BUILD_CAIRO_SUPPORT { MolDraw2DCairo drawer(300, 300); drawer.drawMolecule(*m); drawer.finishDrawing(); drawer.writeDrawingText(nameBase + "1.png"); } { MolDraw2DCairo drawer(600, 600); drawer.drawOptions().bondLineWidth = 2; drawer.drawMolecule(*m); drawer.finishDrawing(); drawer.writeDrawingText(nameBase + "2.png"); } { MolDraw2DCairo drawer(600, 600); drawer.drawOptions().bondLineWidth = 2; drawer.drawOptions().scaleBondWidth = true; drawer.drawMolecule(*m); drawer.finishDrawing(); drawer.writeDrawingText(nameBase + "3.png"); } #endif { auto m = "CCOC(=O)Nc1ccc(SCC2COC(Cn3ccnc3)(c3ccc(Cl)cc3Cl)O2)cc1"_smiles; TEST_ASSERT(m); RDDepict::compute2DCoords(*m); WedgeMolBonds(*m, &(m->getConformer())); static const int ha[] = {17, 18, 19, 20, 21, 6, 7, 8, 9, 31, 32}; std::vector highlight_atoms(ha, ha + sizeof(ha) / sizeof(int)); std::map highlight_colors; MolDrawOptions options; options.circleAtoms = true; options.highlightColour = DrawColour(1, .5, .5); options.continuousHighlight = true; #ifdef RDK_BUILD_CAIRO_SUPPORT { MolDraw2DCairo drawer(200, 200); options.scaleHighlightBondWidth = true; drawer.drawOptions() = options; drawer.drawMolecule(*m, &highlight_atoms, &highlight_colors); drawer.finishDrawing(); drawer.writeDrawingText(nameBase + "4.png"); } #endif { MolDraw2DSVG drawer(200, 200); options.scaleHighlightBondWidth = true; drawer.drawOptions() = options; drawer.drawMolecule(*m, &highlight_atoms, &highlight_colors); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); std::ofstream outs(nameBase + "4.svg"); outs << text; outs.flush(); TEST_ASSERT(text.find("stroke:#FF7F7F;stroke-width:2.7") != std::string::npos); TEST_ASSERT(text.find("stroke:#FF7F7F;stroke-width:16.0px") == std::string::npos); } #ifdef RDK_BUILD_CAIRO_SUPPORT { MolDraw2DCairo drawer(200, 200); options.scaleHighlightBondWidth = false; drawer.drawOptions() = options; drawer.drawMolecule(*m, &highlight_atoms, &highlight_colors); drawer.finishDrawing(); drawer.writeDrawingText(nameBase + "5.png"); } #endif { // This picture has very wide bond highlights as a test - it // looks pretty unsavoury. I mention it so that when you flick // through the test images you don't panic and start searching // for the bug. Been there, done that! MolDraw2DSVG drawer(200, 200); options.scaleHighlightBondWidth = false; drawer.drawOptions() = options; drawer.drawMolecule(*m, &highlight_atoms, &highlight_colors); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); std::ofstream outs((nameBase + "5.svg").c_str()); outs << text; outs.flush(); TEST_ASSERT(text.find("stroke:#FF7F7F;stroke-width:2.7") == std::string::npos); TEST_ASSERT(text.find("stroke:#FF7F7F;stroke-width:16.0px") != std::string::npos); } options.continuousHighlight = false; #ifdef RDK_BUILD_CAIRO_SUPPORT { MolDraw2DCairo drawer(200, 200); options.scaleHighlightBondWidth = true; drawer.drawOptions() = options; drawer.drawMolecule(*m, &highlight_atoms, &highlight_colors); drawer.finishDrawing(); drawer.writeDrawingText(nameBase + "6.png"); } #endif { MolDraw2DSVG drawer(200, 200); options.scaleHighlightBondWidth = true; drawer.drawOptions() = options; drawer.drawMolecule(*m, &highlight_atoms, &highlight_colors); drawer.finishDrawing(); std::ofstream outs((nameBase + "6.svg").c_str()); std::string text = drawer.getDrawingText(); outs << text; outs.flush(); TEST_ASSERT(text.find("stroke:#FF7F7F;stroke-width:0.7") != std::string::npos); TEST_ASSERT(text.find("stroke:#FF7F7F;stroke-width:4.0px") == std::string::npos); } #ifdef RDK_BUILD_CAIRO_SUPPORT { MolDraw2DCairo drawer(200, 200); options.scaleHighlightBondWidth = false; drawer.drawOptions() = options; drawer.drawMolecule(*m, &highlight_atoms, &highlight_colors); drawer.finishDrawing(); drawer.writeDrawingText(nameBase + "7.png"); } #endif { MolDraw2DSVG drawer(200, 200); options.scaleHighlightBondWidth = false; drawer.drawOptions() = options; drawer.drawMolecule(*m, &highlight_atoms, &highlight_colors); drawer.finishDrawing(); std::ofstream outs((nameBase + "7.svg").c_str()); std::string text = drawer.getDrawingText(); outs << text; outs.flush(); TEST_ASSERT(text.find("stroke:#FF7F7F;stroke-width:0.7") == std::string::npos); TEST_ASSERT(text.find("stroke:#FF7F7F;stroke-width:4.0px") != std::string::npos); } } std::cerr << "Done" << std::endl; } void testGithub3391() { std::cout << " ----------------- Test Github 3391 - maxFontSize interacting badly" " with DrawMolecules." << std::endl; auto m = "C"_smiles; auto m2 = "CCOC(=O)Nc1ccc(SCC2COC(Cn3ccnc3)(c3ccc(Cl)cc3Cl)O2)cc1"_smiles; auto m3 = "CCl"_smiles; { MolDraw2DSVG drawer(400, 200, 200, 200); drawer.drawOptions().maxFontSize = 14; std::vector mols; mols.push_back(m.get()); mols.push_back(m.get()); drawer.drawMolecules(mols); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); std::ofstream outs("testGithub3391_1.svg"); outs << text; outs.flush(); } { MolDraw2DSVG drawer(400, 200, 200, 200); drawer.drawOptions().maxFontSize = 14; std::vector mols; mols.push_back(m.get()); mols.push_back(m2.get()); drawer.drawMolecules(mols); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); std::ofstream outs("testGithub3391_2.svg"); outs << text; outs.flush(); } { MolDraw2DSVG drawer(400, 200, 200, 200); drawer.drawOptions().maxFontSize = 14; std::vector mols; mols.push_back(m2.get()); mols.push_back(m.get()); drawer.drawMolecules(mols); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); std::ofstream outs("testGithub3391_3.svg"); outs << text; outs.flush(); } { MolDraw2DSVG drawer(600, 200, 200, 200); drawer.drawOptions().maxFontSize = 14; drawer.drawOptions().minFontSize = 8; std::vector mols; auto m1 = "CO"_smiles; auto m2 = "CCCCCCCCCCO"_smiles; auto m3 = "CCCCCCCCCCCCCCCCCCCCCCO"_smiles; mols.push_back(m3.get()); mols.push_back(m2.get()); mols.push_back(m1.get()); drawer.drawMolecules(mols); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); std::ofstream outs("testGithub3391_4.svg"); outs << text; outs.flush(); } std::cerr << "Done" << std::endl; } int main() { #ifdef RDK_BUILD_COORDGEN_SUPPORT RDDepict::preferCoordGen = false; #endif RDLog::InitLogs(); #if 1 test1(); test2(); test4(); test5(); test6(); test7(); test8PrepareMolForDrawing(); testMultiThreaded(); testGithub781(); test3(); testGithub774(); test9MolLegends(); testGithub852(); testGithub860(); testGithub910(); testGithub932(); testGithub953(); testGithub983(); testDeuteriumTritium(); testCrossedBonds(); test10DrawSecondMol(); test11DrawMolGrid(); test12DrawMols(); test13JSONConfig(); testGithub1090(); testGithub1035(); testGithub1271(); testGithub1322(); test14BWPalette(); test15ContinuousHighlightingWithGrid(); test17MaxMinFontSize(); testGithub1829(); test18FixedScales(); test19RotateDrawing(); test16MoleculeMetadata(); testGithub2063(); testGithub2151(); testGithub2762(); testGithub2931(); test20Annotate(); test21FontFile(); test22ExplicitMethyl(); testGithub3112(); testGithub3305(); testGithub3391(); #endif }