mirror of
https://github.com/rdkit/rdkit.git
synced 2026-06-07 22:44:25 +08:00
237 lines
6.2 KiB
C++
237 lines
6.2 KiB
C++
// $Id$
|
|
//
|
|
// Copyright (C) 2012 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.
|
|
//
|
|
|
|
/*
|
|
To use include this in your CPPFLAGS:
|
|
$(shell pkg-config --cflags cairo)
|
|
and this in your LDFLAGS:
|
|
$(shell pkg-config --libs cairo)
|
|
*/
|
|
|
|
#ifndef _RD_DRAWING_TO_CAIRO_H_
|
|
#define _RD_DRAWING_TO_CAIRO_H_
|
|
|
|
#include <GraphMol/MolDrawing/MolDrawing.h>
|
|
#include <cairo.h>
|
|
|
|
namespace RDKit {
|
|
namespace Drawing {
|
|
namespace {
|
|
void setColorCairo(int atNum, cairo_t *cr) {
|
|
PRECONDITION(cr, "no context");
|
|
switch (atNum) {
|
|
case 7:
|
|
cairo_set_source_rgb(cr, 0.0, 0.0, 1.0);
|
|
break;
|
|
case 8:
|
|
cairo_set_source_rgb(cr, 1.0, 0.0, 0.0);
|
|
break;
|
|
case 9:
|
|
cairo_set_source_rgb(cr, 0.2, 0.8, 0.8);
|
|
break;
|
|
case 15:
|
|
cairo_set_source_rgb(cr, 1.0, 0.5, 0.0);
|
|
break;
|
|
case 16:
|
|
cairo_set_source_rgb(cr, 0.8, 0.8, 0.0);
|
|
break;
|
|
case 17:
|
|
cairo_set_source_rgb(cr, 0.0, 0.8, 0.0);
|
|
break;
|
|
case 35:
|
|
cairo_set_source_rgb(cr, 0.5, 0.3, 0.1);
|
|
break;
|
|
case 0:
|
|
cairo_set_source_rgb(cr, 0.5, 0.5, 0.5);
|
|
break;
|
|
default:
|
|
cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
|
|
}
|
|
}
|
|
void drawLineCairo(std::vector<int>::const_iterator &pos, cairo_t *cr) {
|
|
PRECONDITION(cr, "no context");
|
|
int width = *pos++;
|
|
cairo_set_line_width(cr, width * 10);
|
|
int dashed = *pos++;
|
|
double dashes[2];
|
|
switch (dashed) {
|
|
case 0:
|
|
cairo_set_dash(cr, 0, 0, 0);
|
|
break;
|
|
case 2:
|
|
dashes[0] = 5.0;
|
|
dashes[1] = 20.0;
|
|
cairo_set_dash(cr, dashes, sizeof(dashes) / sizeof(dashes[0]), 0);
|
|
break;
|
|
default:
|
|
dashes[0] = 20.0;
|
|
dashes[1] = 20.0;
|
|
cairo_set_dash(cr, dashes, sizeof(dashes) / sizeof(dashes[0]), 0);
|
|
}
|
|
int an1 = *pos++;
|
|
int an2 = *pos++;
|
|
int xp1 = *pos++;
|
|
int yp1 = *pos++;
|
|
int xp2 = *pos++;
|
|
int yp2 = *pos++;
|
|
if (an1 == an2) {
|
|
setColorCairo(an1, cr);
|
|
cairo_move_to(cr, xp1, yp1);
|
|
cairo_line_to(cr, xp2, yp2);
|
|
cairo_stroke(cr);
|
|
} else {
|
|
int mx = xp1 + (xp2 - xp1) / 2;
|
|
int my = yp1 + (yp2 - yp1) / 2;
|
|
|
|
setColorCairo(an1, cr);
|
|
cairo_move_to(cr, xp1, yp1);
|
|
cairo_line_to(cr, mx, my);
|
|
cairo_stroke(cr);
|
|
setColorCairo(an2, cr);
|
|
cairo_move_to(cr, mx, my);
|
|
cairo_line_to(cr, xp2, yp2);
|
|
cairo_stroke(cr);
|
|
}
|
|
}
|
|
void drawAtomCairo(std::vector<int>::const_iterator &pos, cairo_t *cr) {
|
|
PRECONDITION(cr, "no context");
|
|
int fontSz = 50;
|
|
int atNum = *pos++;
|
|
double xp = static_cast<double>(*pos++);
|
|
double yp = static_cast<double>(*pos++);
|
|
int slen = *pos++;
|
|
std::string label = "";
|
|
for (unsigned int i = 0; i < slen; ++i) {
|
|
label += (char)*pos++;
|
|
}
|
|
RDKit::Drawing::OrientType orient =
|
|
static_cast<RDKit::Drawing::OrientType>(*pos++);
|
|
if (label.length()) {
|
|
cairo_text_extents_t extents;
|
|
cairo_text_extents(cr, label.c_str(), &extents);
|
|
double twidth = extents.width, theight = extents.height;
|
|
|
|
switch (orient) {
|
|
case RDKit::Drawing::W:
|
|
xp -= twidth;
|
|
yp += theight / 2;
|
|
break;
|
|
case RDKit::Drawing::E:
|
|
yp += theight / 2;
|
|
break;
|
|
case RDKit::Drawing::S:
|
|
xp -= twidth / 2;
|
|
yp += theight;
|
|
break;
|
|
case RDKit::Drawing::N:
|
|
xp -= twidth / 2;
|
|
yp -= theight / 2;
|
|
break;
|
|
default:
|
|
xp -= twidth / 2;
|
|
yp += theight / 2;
|
|
}
|
|
cairo_set_source_rgb(cr, 1.0, 1., 1.);
|
|
cairo_rectangle(cr, xp - 10, yp - theight - 10, twidth + 20, theight + 20);
|
|
cairo_fill(cr);
|
|
|
|
cairo_move_to(cr, xp, yp);
|
|
setColorCairo(atNum, cr);
|
|
cairo_show_text(cr, label.c_str());
|
|
cairo_stroke(cr);
|
|
}
|
|
}
|
|
} // end of anonymous namespace
|
|
|
|
void DrawingToCairo(const std::vector<int> &drawing, cairo_t *cr, int width,
|
|
int height, int fontSize = 12,
|
|
int maxDotsPerAngstrom = 60) {
|
|
PRECONDITION(cr, "no context");
|
|
PRECONDITION(width > 0 && height > 0, "bad dimensions");
|
|
|
|
cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
|
|
cairo_rectangle(cr, 0, 0, width, height);
|
|
cairo_fill(cr);
|
|
|
|
cairo_select_font_face(cr, "sans", CAIRO_FONT_SLANT_NORMAL,
|
|
CAIRO_FONT_WEIGHT_NORMAL);
|
|
|
|
std::vector<int>::const_iterator pos = drawing.begin();
|
|
int resolution = 0;
|
|
if (*pos != Drawing::RESOLUTION) {
|
|
std::cerr << "no RESOLUTION token found" << std::endl;
|
|
return;
|
|
}
|
|
resolution = *(pos + 1);
|
|
PRECONDITION(resolution > 0, "bad resolution");
|
|
pos += 2;
|
|
if (*pos != Drawing::BOUNDS) {
|
|
std::cerr << "no bounds token found" << std::endl;
|
|
return;
|
|
}
|
|
pos += 3;
|
|
int dwidth, dheight;
|
|
dwidth = *pos++;
|
|
dheight = *pos++;
|
|
PRECONDITION(dwidth > 0 && dheight > 0, "bad dimensions");
|
|
|
|
// size of the image in angstroms:
|
|
double xSize, ySize;
|
|
xSize = static_cast<double>(dwidth) / resolution;
|
|
ySize = static_cast<double>(dheight) / resolution;
|
|
double scale = 1.0;
|
|
|
|
if (dwidth > width || dheight > height) {
|
|
if (static_cast<double>(dwidth) / width >
|
|
static_cast<double>(dheight) / height) {
|
|
scale = static_cast<double>(width) / dwidth;
|
|
} else {
|
|
scale = static_cast<double>(height) / dheight;
|
|
}
|
|
} else {
|
|
if (width / xSize > height / ySize) {
|
|
if (width / xSize > maxDotsPerAngstrom) {
|
|
scale = maxDotsPerAngstrom * xSize / width;
|
|
}
|
|
} else {
|
|
if (height / ySize > maxDotsPerAngstrom) {
|
|
scale = maxDotsPerAngstrom * ySize / height;
|
|
}
|
|
}
|
|
}
|
|
|
|
scale *= 0.80;
|
|
cairo_translate(cr, .5 * (width - dwidth * scale),
|
|
.5 * (height - dheight * scale));
|
|
cairo_scale(cr, scale, scale);
|
|
|
|
// scaling factors here are empirically determined
|
|
double dFontSize = 1.5 * maxDotsPerAngstrom * fontSize / 14;
|
|
cairo_set_font_size(cr, dFontSize);
|
|
|
|
while (pos != drawing.end()) {
|
|
int token = *pos++;
|
|
switch (token) {
|
|
case Drawing::LINE:
|
|
drawLineCairo(pos, cr);
|
|
break;
|
|
case Drawing::ATOM:
|
|
drawAtomCairo(pos, cr);
|
|
break;
|
|
default:
|
|
std::cerr << "unrecognized token: " << token << std::endl;
|
|
}
|
|
}
|
|
}
|
|
} // end of namespace Drawing
|
|
} // end of namespace RDKit
|
|
#endif
|