RDKit
Open-source cheminformatics and machine learning.
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 
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,
60  cairo_t *cr){
61  PRECONDITION(cr,"no context");
62  int width=*pos++;
63  cairo_set_line_width(cr,width*10);
64  int dashed=*pos++;
65  double dashes[2];
66  switch(dashed){
67  case 0:
68  cairo_set_dash(cr,0,0,0);
69  break;
70  case 2:
71  dashes[0]=5.0;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;dashes[1]=20.0;
76  cairo_set_dash(cr,dashes,sizeof(dashes)/sizeof(dashes[0]),0);
77  }
78  int an1=*pos++;
79  int an2=*pos++;
80  int xp1 = *pos++;
81  int yp1 = *pos++;
82  int xp2 = *pos++;
83  int yp2 = *pos++;
84  if(an1==an2){
85  setColorCairo(an1,cr);
86  cairo_move_to(cr,xp1,yp1);
87  cairo_line_to(cr,xp2,yp2);
88  cairo_stroke(cr);
89  } else {
90  int mx = xp1+(xp2-xp1)/2;
91  int my = yp1+(yp2-yp1)/2;
92 
93  setColorCairo(an1,cr);
94  cairo_move_to(cr,xp1,yp1);
95  cairo_line_to(cr,mx,my);
96  cairo_stroke(cr);
97  setColorCairo(an2,cr);
98  cairo_move_to(cr,mx,my);
99  cairo_line_to(cr,xp2,yp2);
100  cairo_stroke(cr);
101  }
102  }
103  void drawAtomCairo(std::vector<int>::const_iterator &pos,
104  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=static_cast<RDKit::Drawing::OrientType>(*pos++);
116  if(label.length()){
117  cairo_text_extents_t extents;
118  cairo_text_extents(cr,label.c_str(),&extents);
119  double twidth=extents.width,theight=extents.height;
120 
121  switch(orient){
122  case RDKit::Drawing::W:
123  xp -= twidth;
124  yp += theight/2;
125  break;
126  case RDKit::Drawing::E:
127  yp += theight/2;
128  break;
129  case RDKit::Drawing::S:
130  xp -= twidth/2;
131  yp += theight;
132  break;
133  case RDKit::Drawing::N:
134  xp -= twidth/2;
135  yp -= theight/2;
136  break;
137  default:
138  xp -= twidth/2;
139  yp += theight/2;
140  }
141  cairo_set_source_rgb (cr, 1.0, 1., 1.);
142  cairo_rectangle(cr,
143  xp-10,yp-theight-10,
144  twidth+20,theight+20);
145  cairo_fill(cr);
146 
147 
148  cairo_move_to(cr,xp,yp);
149  setColorCairo(atNum,cr);
150  cairo_show_text(cr,label.c_str());
151  cairo_stroke(cr);
152  }
153  }
154  } // end of anonymous namespace
155 
156 
157  void DrawingToCairo(const std::vector<int> &drawing,cairo_t *cr,
158  int width,int height,
159  int fontSize=12,int maxDotsPerAngstrom=60){
160  PRECONDITION(cr,"no context");
161  PRECONDITION(width>0 && height>0,"bad dimensions");
162 
163  cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
164  cairo_rectangle(cr,0,0,width,height);
165  cairo_fill(cr);
166 
167  cairo_select_font_face (cr, "sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
168 
169  std::vector<int>::const_iterator pos=drawing.begin();
170  int resolution=0;
171  if(*pos!=Drawing::RESOLUTION){
172  std::cerr<<"no RESOLUTION token found"<<std::endl;
173  return;
174  }
175  resolution=*(pos+1);
176  PRECONDITION(resolution>0,"bad resolution");
177  pos+=2;
178  if(*pos!=Drawing::BOUNDS){
179  std::cerr<<"no bounds token found"<<std::endl;
180  return;
181  }
182  pos+=3;
183  int dwidth,dheight;
184  dwidth = *pos++;
185  dheight = *pos++;
186  PRECONDITION(dwidth>0 && dheight>0,"bad dimensions");
187 
188  // size of the image in angstroms:
189  double xSize,ySize;
190  xSize=static_cast<double>(dwidth)/resolution;
191  ySize=static_cast<double>(dheight)/resolution;
192  double scale=1.0;
193 
194  if(dwidth>width || dheight>height){
195  if(static_cast<double>(dwidth)/width > static_cast<double>(dheight)/height){
196  scale = static_cast<double>(width)/dwidth;
197  } else {
198  scale = static_cast<double>(height)/dheight;
199  }
200  } else {
201  if(width/xSize > height/ySize){
202  if( width/xSize > maxDotsPerAngstrom ){
203  scale = maxDotsPerAngstrom*xSize/width;
204  }
205  } else {
206  if( height/ySize > maxDotsPerAngstrom ){
207  scale = maxDotsPerAngstrom*ySize/height;
208  }
209  }
210  }
211 
212  scale*=0.80;
213  cairo_translate(cr,
214  .5*(width-dwidth*scale),
215  .5*(height-dheight*scale));
216  cairo_scale(cr,scale,scale);
217 
218  // scaling factors here are empirically determined
219  double dFontSize=1.5*maxDotsPerAngstrom*fontSize/14;
220  cairo_set_font_size (cr, dFontSize);
221 
222  while(pos!=drawing.end()){
223  int token=*pos++;
224  switch(token){
225  case Drawing::LINE:
226  drawLineCairo(pos,cr);
227  break;
228  case Drawing::ATOM:
229  drawAtomCairo(pos,cr);
230  break;
231  default:
232  std::cerr<<"unrecognized token: "<<token<<std::endl;
233  }
234  }
235  }
236  } // end of namespace Drawing
237 } // end of namespace RDKit
238 #endif
void DrawingToCairo(const std::vector< int > &drawing, cairo_t *cr, int width, int height, int fontSize=12, int maxDotsPerAngstrom=60)
Includes a bunch of functionality for handling Atom and Bond queries.
Definition: Atom.h:28
#define PRECONDITION(expr, mess)
Definition: Invariant.h:119