// // 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; { std::string smiles = "C"; ROMol *m = SmilesToMol(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("CH") != std::string::npos); delete m; } { std::string smiles = "O"; ROMol *m = SmilesToMol(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("OH") == std::string::npos); delete m; } { std::string smiles = "[C]"; ROMol *m = SmilesToMol(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); delete m; } { std::string smiles = "C.CC.[Cl-]"; ROMol *m = SmilesToMol(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("CH") != std::string::npos); TEST_ASSERT(txt.find("Cl") != std::string::npos); delete m; } { // empty molecule auto *m = new ROMol(); TEST_ASSERT(m); RDDepict::compute2DCoords(*m); MolDraw2DSVG drawer(300, 300); drawer.drawMolecule(*m); drawer.finishDrawing(); std::string txt = drawer.getDrawingText(); TEST_ASSERT(txt.find("") == std::string::npos); delete m; } std::cerr << " Done" << std::endl; } void testGithub774() { std::cout << " ----------------- Test Github774" << std::endl; { std::string smiles = "Cc1c(C(=O)NCC[NH3+])[n+](=O)c2cc(CC[C@](F)(Cl)Br)ccc2n1[O-]"; std::string nameBase = "test774_1"; RWMol *m = SmilesToMol(smiles); TEST_ASSERT(m); RDDepict::compute2DCoords(*m); WedgeMolBonds(*m, &(m->getConformer())); MolOps::Kekulize(*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(); Point2D ocoords(1.0, 2.0); Point2D dcoords = drawer.getAtomCoords(std::make_pair(ocoords.x, ocoords.y)); Point2D acoords = drawer.getDrawCoords(dcoords); TEST_ASSERT(feq(acoords.x, 1.0)); TEST_ASSERT(feq(acoords.y, 2.0)); } // m->setProp("_Name","mol"); // std::cerr<getConformer())); MolOps::Kekulize(*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(); } // m->setProp("_Name","mol"); // std::cerr<getConformer())); MolDraw2DSVG drawer(300, 300); drawer.drawMolecule(*m, "mol legend"); drawer.finishDrawing(); std::string txt = drawer.getDrawingText(); std::ofstream outs("test9_1.svg"); outs << txt; // 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(); 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("<1") == std::string::npos); TEST_ASSERT(text.find(">1") == 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; { std::string smiles = "CCC[Se]"; // made up RWMol *m1 = SmilesToMol(smiles); TEST_ASSERT(m1); MolDraw2DUtils::prepareMolForDrawing(*m1); { MolDraw2DSVG drawer(500, 200, 250, 200); drawer.drawMolecule(*m1, "m1"); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); TEST_ASSERT(text.find("Se") != std::string::npos); } { 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_1.svg"); outs << text; outs.flush(); TEST_ASSERT(text.find("Se") == std::string::npos); TEST_ASSERT(text.find("customlabel") != std::string::npos); } delete m1; } std::cerr << " Done" << std::endl; } void testGithub565() { std::cout << " ----------------- Testing github 565: support a fixed bond " "length in the MolDraw2D code" << std::endl; { std::string smiles = "CCCCC"; RWMol *m1 = SmilesToMol(smiles); TEST_ASSERT(m1); MolDraw2DUtils::prepareMolForDrawing(*m1); Point2D minV, maxV; const Conformer &cnf = m1->getConformer(); minV.x = maxV.x = cnf.getAtomPos(0).x; minV.y = maxV.y = cnf.getAtomPos(0).y; for (unsigned int i = 1; i < m1->getNumAtoms(); i++) { minV.x = std::min(minV.x, cnf.getAtomPos(i).x); minV.y = std::min(minV.y, cnf.getAtomPos(i).y); maxV.x = std::max(maxV.x, cnf.getAtomPos(i).x); maxV.y = std::max(maxV.y, cnf.getAtomPos(i).y); } { unsigned int dpa = 100; unsigned int w = dpa * (maxV.x - minV.x); unsigned int h = dpa * (maxV.y - minV.y); MolDraw2DSVG drawer(w, h); drawer.setScale(w, h, minV, maxV); drawer.drawMolecule(*m1, "m1"); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); std::ofstream outs("test565_1.svg"); outs << text; outs.flush(); } { unsigned int dpa = 50; unsigned int w = dpa * (maxV.x - minV.x); unsigned int h = dpa * (maxV.y - minV.y); MolDraw2DSVG drawer(w, h); drawer.setScale(w, h, minV, maxV); drawer.drawMolecule(*m1, "m1"); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); std::ofstream outs("test565_2.svg"); outs << text; outs.flush(); } delete m1; } 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:4px;") == 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:4px;") != 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=\"54.") != 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("atom-smiles=\"[NH]\" drawing-x=\"54.") != std::string::npos); TEST_ASSERT(text.find("atom-smiles=\"[NH]\" drawing-x=\"254.") != std::string::npos); for (auto ptr : ms) { delete ptr; } } } std::cerr << " Done" << std::endl; } void test17MaxFontSize() { std::cout << " ----------------- Test 16 - 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 = "test16_"; 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(); TEST_ASSERT(text.find("font-size:40px") != std::string::npos); } { std::ofstream outs((nameBase + "2.svg").c_str()); MolDraw2DSVG drawer(300, 300); drawer.drawOptions().maxFontSize = -1; drawer.drawMolecule(*m); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); outs << text; outs.flush(); TEST_ASSERT(text.find("font-size:47px") != std::string::npos); } { std::ofstream outs((nameBase + "3.svg").c_str()); MolDraw2DSVG drawer(300, 300); drawer.drawOptions().maxFontSize = 20; drawer.drawMolecule(*m); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); outs << text; outs.flush(); TEST_ASSERT(text.find("font-size:20px") != std::string::npos); } } std::cerr << " Done" << std::endl; } void test18FixedScales() { std::cout << " ----------------- Testing use of fixed scales for drawing." << std::endl; std::string nameBase = "test18_"; { std::string smi = "Clc1ccccc1"; std::unique_ptr m(SmilesToMol(smi)); TEST_ASSERT(m); { MolDraw2DSVG drawer(300, 300); drawer.drawMolecule(*m); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); std::ofstream outs((nameBase + "1.svg").c_str()); outs << text; outs.flush(); TEST_ASSERT(text.find("font-size:28px") != std::string::npos); } { MolDraw2DSVG drawer(300, 300); // fix scale so bond is 5% if window width. drawer.drawOptions().fixedScale = 0.05; drawer.drawMolecule(*m); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); std::ofstream outs((nameBase + "2.svg").c_str()); outs << text; outs.flush(); TEST_ASSERT(text.find("font-size:7px") != std::string::npos); } } { std::string smi = "C[C@@H](N[C@@H]1CC[C@@H](C(=O)N2CCC(C(=O)N3CCCC3)" "(c3ccccc3)CC2)C(C)(C)C1)c1ccc(Cl)cc1"; std::unique_ptr m(SmilesToMol(smi)); TEST_ASSERT(m); { MolDraw2DSVG drawer(300, 300); drawer.drawMolecule(*m); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); std::ofstream outs((nameBase + "3.svg").c_str()); outs << text; outs.flush(); TEST_ASSERT(text.find("font-size:8px") != std::string::npos); } { // fix bond length to 10 pixels. MolDraw2DSVG drawer(300, 300); drawer.drawOptions().fixedBondLength = 10; drawer.drawMolecule(*m); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); std::ofstream outs((nameBase + "4.svg").c_str()); outs << text; outs.flush(); TEST_ASSERT(text.find("font-size:5px") != std::string::npos); } { // this one should be the same size as the first, as it won't scale // up if the picture won't fit. MolDraw2DSVG drawer(300, 300); drawer.drawOptions().fixedBondLength = 30; drawer.drawMolecule(*m); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); std::ofstream outs((nameBase + "5.svg").c_str()); outs << text; outs.flush(); TEST_ASSERT(text.find("font-size:8px") != std::string::npos); } } std::cerr << " Done" << std::endl; } void test19RotateDrawing() { std::cout << " ----------------- Testing rotation of 2D drawing." << std::endl; std::string nameBase = "test19_"; { std::string smi = "Clc1ccccc1"; std::unique_ptr m(SmilesToMol(smi)); TEST_ASSERT(m); { MolDraw2DSVG drawer(300, 300); drawer.drawMolecule(*m); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); std::ofstream outs((nameBase + "1.svg").c_str()); outs << text; outs.flush(); TEST_ASSERT(text.find("text-anchor=\"start\" x='256.907' y='154.276'") != std::string::npos); } { MolDraw2DSVG drawer(300, 300); drawer.drawOptions().rotate = 90.0; drawer.drawMolecule(*m); drawer.finishDrawing(); std::string text = drawer.getDrawingText(); std::ofstream outs((nameBase + "2.svg").c_str()); outs << text; outs.flush(); TEST_ASSERT(text.find("text-anchor=\"start\" x='136.604' y='276.316'") != std::string::npos); } } std::cerr << " Done" << std::endl; } void testGithub2063() { std::cout << " ----------------- Testing Github2063: Drawing racemic bond " "stereo as crossed bonds should be the default" << std::endl; { std::string molb = R"molb(squiggle bond Mrv1810 09301816112D 4 3 0 0 0 0 999 V2000 0.5804 -0.3125 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 1.2948 0.1000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -0.1341 0.1000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 2.0093 -0.3125 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 1 2 2 0 0 0 0 1 3 1 0 0 0 0 2 4 1 4 0 0 0 M END)molb"; std::unique_ptr 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:5px") != std::string::npos); // this is the 2nd ellipse in the file (line 34) TEST_ASSERT(text.find("11") != std::string::npos); } { 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(); TEST_ASSERT(text.find("x='278.629' y='221.042' style='font-size:27px;" "font-style:normal;font-weight:normal;" "fill-opacity:1;stroke:none;font-family:sans-serif;" "fill:#000000") != std::string::npos); } { 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(); TEST_ASSERT(text.find("x='209.32' y='180.482' style='font-size:15px;" "font-style:normal;font-weight:normal;" "fill-opacity:1;stroke:none;" "font-family:sans-serif;fill:#000000'" " >foolish annotation") != std::string::npos); } 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(); testGithub565(); test14BWPalette(); test15ContinuousHighlightingWithGrid(); test17MaxFontSize(); testGithub1829(); test18FixedScales(); test19RotateDrawing(); #endif test16MoleculeMetadata(); testGithub2063(); testGithub2151(); testGithub2762(); testGithub2931(); test20Annotate(); }