RDKit: DrawingToCairo.h Source File

| RDKit Open-source cheminformatics and machine learning.

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

DrawingToCairo.h
Go to the documentation of this file.
1 // $Id$
2 //
3 // Copyright (C) 2012 Greg Landrum
4 //
5 // @@ All Rights Reserved @@
6 // This file is part of the RDKit.
7 // The contents are covered by the terms of the BSD license
8 // which is included in the file license.txt, found at the root
9 // of the RDKit source tree.
10 //
11
12 /*
13 To use include this in your CPPFLAGS:
14 $(shell pkg-config --cflags cairo)
15 and this in your LDFLAGS:
16 $(shell pkg-config --libs cairo)
17 */
18
19 #ifndef _RD_DRAWING_TO_CAIRO_H_
20 #define _RD_DRAWING_TO_CAIRO_H_
21
22 #include <GraphMol/MolDrawing/MolDrawing.h>
23 #include <cairo.h>
24
25 namespace RDKit {
26 namespace Drawing {
27 namespace {
28 void setColorCairo(int atNum, cairo_t *cr) {
29 PRECONDITION(cr, "no context");
30 switch (atNum) {
31 case 7:
32 cairo_set_source_rgb(cr, 0.0, 0.0, 1.0);
33 break;
34 case 8:
35 cairo_set_source_rgb(cr, 1.0, 0.0, 0.0);
36 break;
37 case 9:
38 cairo_set_source_rgb(cr, 0.2, 0.8, 0.8);
39 break;
40 case 15:
41 cairo_set_source_rgb(cr, 1.0, 0.5, 0.0);
42 break;
43 case 16:
44 cairo_set_source_rgb(cr, 0.8, 0.8, 0.0);
45 break;
46 case 17:
47 cairo_set_source_rgb(cr, 0.0, 0.8, 0.0);
48 break;
49 case 35:
50 cairo_set_source_rgb(cr, 0.5, 0.3, 0.1);
51 break;
52 case 0:
53 cairo_set_source_rgb(cr, 0.5, 0.5, 0.5);
54 break;
55 default:
56 cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
57 }
58 }
59 void drawLineCairo(std::vector<int>::const_iterator &pos, cairo_t *cr) {
60 PRECONDITION(cr, "no context");
61 int width = *pos++;
62 cairo_set_line_width(cr, width * 10);
63 int dashed = *pos++;
64 double dashes[2];
65 switch (dashed) {
66 case 0:
67 cairo_set_dash(cr, 0, 0, 0);
68 break;
69 case 2:
70 dashes[0] = 5.0;
71 dashes[1] = 20.0;
72 cairo_set_dash(cr, dashes, sizeof(dashes) / sizeof(dashes[0]), 0);
73 break;
74 default:
75 dashes[0] = 20.0;
76 dashes[1] = 20.0;
77 cairo_set_dash(cr, dashes, sizeof(dashes) / sizeof(dashes[0]), 0);
78 }
79 int an1 = *pos++;
80 int an2 = *pos++;
81 int xp1 = *pos++;
82 int yp1 = *pos++;
83 int xp2 = *pos++;
84 int yp2 = *pos++;
85 if (an1 == an2) {
86 setColorCairo(an1, cr);
87 cairo_move_to(cr, xp1, yp1);
88 cairo_line_to(cr, xp2, yp2);
89 cairo_stroke(cr);
90 } else {
91 int mx = xp1 + (xp2 - xp1) / 2;
92 int my = yp1 + (yp2 - yp1) / 2;
93
94 setColorCairo(an1, cr);
95 cairo_move_to(cr, xp1, yp1);
96 cairo_line_to(cr, mx, my);
97 cairo_stroke(cr);
98 setColorCairo(an2, cr);
99 cairo_move_to(cr, mx, my);
100 cairo_line_to(cr, xp2, yp2);
101 cairo_stroke(cr);
102 }
103 }
104 void drawAtomCairo(std::vector<int>::const_iterator &pos, cairo_t *cr) {
105 PRECONDITION(cr, "no context");
106 int fontSz = 50;
107 int atNum = *pos++;
108 double xp = static_cast<double>(*pos++);
109 double yp = static_cast<double>(*pos++);
110 int slen = *pos++;
111 std::string label = "";
112 for (unsigned int i = 0; i < slen; ++i) {
113 label += (char)*pos++;
114 }
115 RDKit::Drawing::OrientType orient =
116 static_cast<RDKit::Drawing::OrientType>(*pos++);
117 if (label.length()) {
118 cairo_text_extents_t extents;
119 cairo_text_extents(cr, label.c_str(), &extents);
120 double twidth = extents.width, theight = extents.height;
121
122 switch (orient) {
123 case RDKit::Drawing::W:
124 xp -= twidth;
125 yp += theight / 2;
126 break;
127 case RDKit::Drawing::E:
128 yp += theight / 2;
129 break;
130 case RDKit::Drawing::S:
131 xp -= twidth / 2;
132 yp += theight;
133 break;
134 case RDKit::Drawing::N:
135 xp -= twidth / 2;
136 yp -= theight / 2;
137 break;
138 default:
139 xp -= twidth / 2;
140 yp += theight / 2;
141 }
142 cairo_set_source_rgb(cr, 1.0, 1., 1.);
143 cairo_rectangle(cr, xp - 10, yp - theight - 10, twidth + 20, theight + 20);
144 cairo_fill(cr);
145
146 cairo_move_to(cr, xp, yp);
147 setColorCairo(atNum, cr);
148 cairo_show_text(cr, label.c_str());
149 cairo_stroke(cr);
150 }
151 }
152 } // end of anonymous namespace
153
154 void DrawingToCairo(const std::vector<int> &drawing, cairo_t *cr, int width,
155 int height, int fontSize = 12,
156 int maxDotsPerAngstrom = 60) {
157 PRECONDITION(cr, "no context");
158 PRECONDITION(width > 0 && height > 0, "bad dimensions");
159
160 cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
161 cairo_rectangle(cr, 0, 0, width, height);
162 cairo_fill(cr);
163
164 cairo_select_font_face(cr, "sans", CAIRO_FONT_SLANT_NORMAL,
165 CAIRO_FONT_WEIGHT_NORMAL);
166
167 std::vector<int>::const_iterator pos = drawing.begin();
168 int resolution = 0;
169 if (*pos != Drawing::RESOLUTION) {
170 std::cerr << "no RESOLUTION token found" << std::endl;
171 return;
172 }
173 resolution = *(pos + 1);
174 PRECONDITION(resolution > 0, "bad resolution");
175 pos += 2;
176 if (*pos != Drawing::BOUNDS) {
177 std::cerr << "no bounds token found" << std::endl;
178 return;
179 }
180 pos += 3;
181 int dwidth, dheight;
182 dwidth = *pos++;
183 dheight = *pos++;
184 PRECONDITION(dwidth > 0 && dheight > 0, "bad dimensions");
185
186 // size of the image in angstroms:
187 double xSize, ySize;
188 xSize = static_cast<double>(dwidth) / resolution;
189 ySize = static_cast<double>(dheight) / resolution;
190 double scale = 1.0;
191
192 if (dwidth > width || dheight > height) {
193 if (static_cast<double>(dwidth) / width >
194 static_cast<double>(dheight) / height) {
195 scale = static_cast<double>(width) / dwidth;
196 } else {
197 scale = static_cast<double>(height) / dheight;
198 }
199 } else {
200 if (width / xSize > height / ySize) {
201 if (width / xSize > maxDotsPerAngstrom) {
202 scale = maxDotsPerAngstrom * xSize / width;
203 }
204 } else {
205 if (height / ySize > maxDotsPerAngstrom) {
206 scale = maxDotsPerAngstrom * ySize / height;
207 }
208 }
209 }
210
211 scale *= 0.80;
212 cairo_translate(cr, .5 * (width - dwidth * scale),
213 .5 * (height - dheight * scale));
214 cairo_scale(cr, scale, scale);
215
216 // scaling factors here are empirically determined
217 double dFontSize = 1.5 * maxDotsPerAngstrom * fontSize / 14;
218 cairo_set_font_size(cr, dFontSize);
219
220 while (pos != drawing.end()) {
221 int token = *pos++;
222 switch (token) {
223 case Drawing::LINE:
224 drawLineCairo(pos, cr);
225 break;
226 case Drawing::ATOM:
227 drawAtomCairo(pos, cr);
228 break;
229 default:
230 std::cerr << "unrecognized token: " << token << std::endl;
231 }
232 }
233 }
234 } // end of namespace Drawing
235 } // end of namespace RDKit
236 #endif
RDKit::Drawing::N
Definition: MolDrawing.h:41
RDKit::Drawing::S
Definition: MolDrawing.h:41
MolDrawing.h
RDKit::Drawing::RESOLUTION
Definition: MolDrawing.h:40
RDKit::Drawing::DrawingToCairo
void DrawingToCairo(const std::vector< int > &drawing, cairo_t *cr, int width, int height, int fontSize=12, int maxDotsPerAngstrom=60)
Definition: DrawingToCairo.h:154
RDKit::Drawing::LINE
Definition: MolDrawing.h:40
RDKit::Drawing::BOUNDS
Definition: MolDrawing.h:40
RDKit::Drawing::E
Definition: MolDrawing.h:41
RDKit
Includes a bunch of functionality for handling Atom and Bond queries.
Definition: Atom.h:28
RDKit::Drawing::ATOM
Definition: MolDrawing.h:40
RDKit::Drawing::OrientType
OrientType
Definition: MolDrawing.h:41
RDKit::Drawing::W
Definition: MolDrawing.h:41
PRECONDITION
#define PRECONDITION(expr, mess)
Definition: Invariant.h:103