agg/examples/mol_view.cpp

1077 lines
25 KiB
C++

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include "agg_rendering_buffer.h"
#include "agg_rasterizer_scanline_aa.h"
#include "agg_scanline_p.h"
#include "agg_renderer_scanline.h"
#include "agg_conv_transform.h"
#include "agg_conv_stroke.h"
#include "agg_bspline.h"
#include "agg_ellipse.h"
#include "agg_gsv_text.h"
#include "ctrl/agg_slider_ctrl.h"
#include "ctrl/agg_scale_ctrl.h"
#include "platform/agg_platform_support.h"
#define AGG_BGR24
//#define AGG_RGB24
//#define AGG_BGRA32
//#define AGG_RGBA32
//#define AGG_ARGB32
//#define AGG_ABGR32
//#define AGG_BGR96
//#define AGG_BGRA128
//#define AGG_RGB565
//#define AGG_RGB555
#include "pixel_formats.h"
enum flip_y_e { flip_y = true };
enum default_num_points_e { default_num_points = 20000 };
enum start_size_e
{
start_width = 400,
start_height = 400
};
enum atom_color_e
{
atom_color_general = 0,
atom_color_N = 1,
atom_color_O = 2,
atom_color_S = 3,
atom_color_P = 4,
atom_color_halogen = 5,
end_of_atom_colors
};
struct atom_type
{
double x;
double y;
char label[4];
int charge;
unsigned color_idx;
};
struct bond_type
{
unsigned idx1;
unsigned idx2;
double x1;
double y1;
double x2;
double y2;
unsigned order;
int stereo;
int topology;
};
class molecule
{
public:
~molecule();
molecule();
bool read(FILE* fd);
unsigned num_atoms() const { return m_num_atoms; }
unsigned num_bonds() const { return m_num_bonds; }
const atom_type& atom(unsigned idx) const { return m_atoms[idx]; }
const bond_type& bond(unsigned idx) const { return m_bonds[idx]; }
double average_bond_len() const { return m_avr_len; }
const char* name() const { return m_name; }
static int get_int(const char* buf, int pos, int len);
static double get_dbl(const char* buf, int pos, int len);
static char* get_str(char* dst, const char* buf, int pos, int len);
private:
atom_type* m_atoms;
unsigned m_num_atoms;
bond_type* m_bonds;
unsigned m_num_bonds;
char m_name[128];
double m_avr_len;
};
molecule::~molecule()
{
delete [] m_bonds;
delete [] m_atoms;
}
molecule::molecule() :
m_atoms(0),
m_num_atoms(0),
m_bonds(0),
m_num_bonds(0),
m_avr_len(0)
{
m_name[0] = 0;
}
int molecule::get_int(const char* buf, int pos, int len)
{
char tmp[32];
return atoi(get_str(tmp, buf, pos, len));
}
double molecule::get_dbl(const char* buf, int pos, int len)
{
char tmp[32];
return atof(get_str(tmp, buf, pos, len));
}
char* molecule::get_str(char* dst, const char* buf, int pos, int len)
{
--pos;
int buf_len = strlen(buf);
buf += pos;
while(pos + len < buf_len && isspace(*buf))
{
++buf;
--len;
}
if(len >= 0)
{
if(len > 0) memcpy(dst, buf, len);
dst[len] = 0;
}
char* ts = dst;
while(*ts && !isspace(*ts)) ts++;
*ts = 0;
return dst;
}
unsigned trim_cr_lf(char* buf)
{
unsigned len = strlen(buf);
// Trim "\n\r" at the beginning
unsigned pos = 0;
while(len && (buf[0] == '\n' || buf[0] == '\r'))
{
--len;
++pos;
}
// Note that strcpy has undefined behavior if the strings overlap
if(pos) memmove(buf, buf + pos, len);
// Trim "\n\r" at the end
while(len && (buf[len-1] == '\n' || buf[len-1] == '\r')) --len;
buf[len] = 0;
return len;
}
/*
MFCD00191150
Mt7.00 09020210442D
23 23 0 0 1 0 0 0 0 0999 V2000
-2.6793 -0.2552 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
. . .
1 2 1 0 0 0 0
. . .
M END
> <MDLNUMBER>
MFCD00191150
$$$$
*/
bool molecule::read(FILE* fd)
{
char buf[512];
unsigned len;
if(!fgets(buf, 510, fd)) return false;
len = trim_cr_lf(buf);
if(len > 127) len = 127;
if(len) memcpy(m_name, buf, len);
m_name[len] = 0;
if(!fgets(buf, 510, fd)) return false;
if(!fgets(buf, 510, fd)) return false;
if(!fgets(buf, 510, fd)) return false;
trim_cr_lf(buf);
m_num_atoms = get_int(buf, 1, 3);
m_num_bonds = get_int(buf, 4, 3);
if(m_num_atoms == 0 || m_num_bonds == 0) return false;
m_atoms = new atom_type[m_num_atoms];
m_bonds = new bond_type[m_num_bonds];
memset(m_atoms, 0, sizeof(atom_type) * m_num_atoms);
memset(m_bonds, 0, sizeof(bond_type) * m_num_bonds);
unsigned i;
for(i = 0; i < m_num_atoms; i++)
{
if(!fgets(buf, 510, fd)) return false;
trim_cr_lf(buf);
/*
-2.6793 -0.2552 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
*/
m_atoms[i].x = get_dbl(buf, 1, 10);
m_atoms[i].y = get_dbl(buf, 11, 10);
get_str(m_atoms[i].label, buf, 32, 3);
m_atoms[i].charge = get_int(buf, 39, 1);
if(m_atoms[i].charge) m_atoms[i].charge = 4 - m_atoms[i].charge;
if(strcmp(m_atoms[i].label, "N") == 0) m_atoms[i].color_idx = atom_color_N;
if(strcmp(m_atoms[i].label, "O") == 0) m_atoms[i].color_idx = atom_color_O;
if(strcmp(m_atoms[i].label, "S") == 0) m_atoms[i].color_idx = atom_color_S;
if(strcmp(m_atoms[i].label, "P") == 0) m_atoms[i].color_idx = atom_color_P;
if(strcmp(m_atoms[i].label, "F") == 0 ||
strcmp(m_atoms[i].label, "Cl") == 0 ||
strcmp(m_atoms[i].label, "Br") == 0 ||
strcmp(m_atoms[i].label, "I") == 0) m_atoms[i].color_idx = atom_color_halogen;
}
m_avr_len = 0.0;
for(i = 0; i < m_num_bonds; i++)
{
if(!fgets(buf, 510, fd)) return false;
trim_cr_lf(buf);
/*
1 2 1 0 0 0 0
*/
m_bonds[i].idx1 = get_int(buf, 1, 3) - 1;
m_bonds[i].idx2 = get_int(buf, 4, 3) - 1;
if(m_bonds[i].idx1 >= m_num_atoms || m_bonds[i].idx2 >= m_num_atoms) return false;
m_bonds[i].x1 = m_atoms[m_bonds[i].idx1].x;
m_bonds[i].y1 = m_atoms[m_bonds[i].idx1].y;
m_bonds[i].x2 = m_atoms[m_bonds[i].idx2].x;
m_bonds[i].y2 = m_atoms[m_bonds[i].idx2].y;
m_bonds[i].order = get_int(buf, 7, 3);
m_bonds[i].stereo = get_int(buf, 10, 3);
m_bonds[i].topology = get_int(buf, 13, 3);
m_avr_len += sqrt((m_bonds[i].x1 - m_bonds[i].x2) * (m_bonds[i].x1 - m_bonds[i].x2) +
(m_bonds[i].y1 - m_bonds[i].y2) * (m_bonds[i].y1 - m_bonds[i].y2));
}
m_avr_len /= double(m_num_bonds);
while(fgets(buf, 510, fd))
{
trim_cr_lf(buf);
if(buf[0] == '$') return true;
}
return false;
}
namespace agg
{
class line
{
public:
line() :
m_x1(0.0), m_y1(0.0), m_x2(1.0), m_y2(0.0), m_thickness(0.1)
{
}
line(double x1, double y1, double x2, double y2, double thickness) :
m_x1(x1), m_y1(y1), m_x2(x2), m_y2(y2), m_thickness(thickness)
{
}
void init(double x1, double y1, double x2, double y2)
{
m_x1 = x1;
m_y1 = y1;
m_x2 = x2;
m_y2 = y2;
}
void thickness(double th)
{
m_thickness = th;
}
void rewind(unsigned start);
unsigned vertex(double* x, double* y);
private:
double m_x1;
double m_y1;
double m_x2;
double m_y2;
double m_dx;
double m_dy;
double m_thickness;
unsigned m_vertex;
};
inline void line::rewind(unsigned)
{
calc_orthogonal(m_thickness*0.5, m_x1, m_y1, m_x2, m_y2, &m_dx, &m_dy);
m_vertex = 0;
}
inline unsigned line::vertex(double* x, double* y)
{
switch(m_vertex)
{
case 0:
*x = m_x1 - m_dx;
*y = m_y1 - m_dy;
m_vertex++;
return path_cmd_move_to;
case 1:
*x = m_x2 - m_dx;
*y = m_y2 - m_dy;
m_vertex++;
return path_cmd_line_to;
case 2:
*x = m_x2 + m_dx;
*y = m_y2 + m_dy;
m_vertex++;
return path_cmd_line_to;
case 3:
*x = m_x1 + m_dx;
*y = m_y1 + m_dy;
m_vertex++;
return path_cmd_line_to;
}
return path_cmd_stop;
}
class solid_wedge
{
public:
solid_wedge() :
m_x1(0.0), m_y1(0.0), m_x2(1.0), m_y2(0.0), m_thickness(0.1)
{
}
solid_wedge(double x1, double y1, double x2, double y2, double thickness) :
m_x1(x1), m_y1(y1), m_x2(x2), m_y2(y2), m_thickness(thickness)
{
}
void init(double x1, double y1, double x2, double y2)
{
m_x1 = x1;
m_y1 = y1;
m_x2 = x2;
m_y2 = y2;
}
void thickness(double th)
{
m_thickness = th;
}
void rewind(unsigned start);
unsigned vertex(double* x, double* y);
private:
double m_x1;
double m_y1;
double m_x2;
double m_y2;
double m_dx;
double m_dy;
double m_thickness;
unsigned m_vertex;
};
inline void solid_wedge::rewind(unsigned)
{
calc_orthogonal(m_thickness*2.0, m_x1, m_y1, m_x2, m_y2, &m_dx, &m_dy);
m_vertex = 0;
}
inline unsigned solid_wedge::vertex(double* x, double* y)
{
switch(m_vertex)
{
case 0:
*x = m_x1;
*y = m_y1;
m_vertex++;
return path_cmd_move_to;
case 1:
*x = m_x2 - m_dx;
*y = m_y2 - m_dy;
m_vertex++;
return path_cmd_line_to;
case 2:
*x = m_x2 + m_dx;
*y = m_y2 + m_dy;
m_vertex++;
return path_cmd_line_to;
}
return path_cmd_stop;
}
class dashed_wedge
{
public:
dashed_wedge() :
m_x1(0.0), m_y1(0.0), m_x2(1.0), m_y2(0.0),
m_thickness(0.1),
m_num_dashes(8)
{
}
dashed_wedge(double x1, double y1, double x2, double y2,
double thickness, unsigned num_dashes=8) :
m_x1(x2), m_y1(y2), m_x2(x1), m_y2(y1),
m_thickness(thickness),
m_num_dashes(num_dashes)
{
}
void init(double x1, double y1, double x2, double y2)
{
m_x1 = x2;
m_y1 = y2;
m_x2 = x1;
m_y2 = y1;
}
void num_dashes(unsigned nd)
{
m_num_dashes = nd;
}
void thickness(double th)
{
m_thickness = th;
}
void rewind(unsigned start);
unsigned vertex(double* x, double* y);
private:
double m_x1;
double m_y1;
double m_x2;
double m_y2;
double m_xt2;
double m_yt2;
double m_xt3;
double m_yt3;
double m_xd[4];
double m_yd[4];
double m_thickness;
unsigned m_num_dashes;
unsigned m_vertex;
};
void dashed_wedge::rewind(unsigned)
{
double dx;
double dy;
calc_orthogonal(m_thickness*2.0, m_x1, m_y1, m_x2, m_y2, &dx, &dy);
m_xt2 = m_x2 - dx;
m_yt2 = m_y2 - dy;
m_xt3 = m_x2 + dx;
m_yt3 = m_y2 + dy;
m_vertex = 0;
}
unsigned dashed_wedge::vertex(double* x, double* y)
{
if(m_vertex < m_num_dashes * 4)
{
if((m_vertex % 4) == 0)
{
double k1 = double(m_vertex / 4) / double(m_num_dashes);
double k2 = k1 + 0.4 / double(m_num_dashes);
m_xd[0] = m_x1 + (m_xt2 - m_x1) * k1;
m_yd[0] = m_y1 + (m_yt2 - m_y1) * k1;
m_xd[1] = m_x1 + (m_xt2 - m_x1) * k2;
m_yd[1] = m_y1 + (m_yt2 - m_y1) * k2;
m_xd[2] = m_x1 + (m_xt3 - m_x1) * k2;
m_yd[2] = m_y1 + (m_yt3 - m_y1) * k2;
m_xd[3] = m_x1 + (m_xt3 - m_x1) * k1;
m_yd[3] = m_y1 + (m_yt3 - m_y1) * k1;
*x = m_xd[0];
*y = m_yd[0];
m_vertex++;
return path_cmd_move_to;
}
else
{
*x = m_xd[m_vertex % 4];
*y = m_yd[m_vertex % 4];
m_vertex++;
return path_cmd_line_to;
}
}
return path_cmd_stop;
}
}
class bond_vertex_generator
{
enum bond_style_e
{
bond_single,
bond_wedged_solid,
bond_wedged_dashed,
bond_double,
bond_double_left,
bond_double_right,
bond_triple
};
public:
bond_vertex_generator(const bond_type& bond, double thickness) :
m_bond(bond),
m_thickness(thickness),
m_style(bond_single)
{
if(bond.order == 1)
{
if(bond.stereo == 1) m_style = bond_wedged_solid;
if(bond.stereo == 6) m_style = bond_wedged_dashed;
}
if(bond.order == 2)
{
m_style = bond_double;
if(bond.topology == 1) m_style = bond_double_left;
if(bond.topology == 2) m_style = bond_double_right;
}
if(bond.order == 3) m_style = bond_triple;
m_line1.thickness(thickness);
m_line2.thickness(thickness);
m_line3.thickness(thickness);
m_solid_wedge.thickness(thickness);
m_dashed_wedge.thickness(thickness);
}
void rewind(unsigned)
{
double dx, dy, dx1, dy1, dx2, dy2;
switch(m_style)
{
case bond_wedged_solid:
m_solid_wedge.init(m_bond.x1, m_bond.y1, m_bond.x2, m_bond.y2);
m_solid_wedge.rewind(0);
break;
case bond_wedged_dashed:
m_dashed_wedge.init(m_bond.x1, m_bond.y1, m_bond.x2, m_bond.y2);
m_dashed_wedge.rewind(0);
break;
case bond_double:
case bond_double_left:
case bond_double_right:
agg::calc_orthogonal(m_thickness,
m_bond.x1, m_bond.y1,
m_bond.x2, m_bond.y2,
&dx, &dy);
dx1 = dy1 = 0;
// To Do: ring perception and the proper drawing
// of the double bonds in the aromatic rings.
//if(m_style == bond_double)
{
dx1 = dx2 = dx;
dy1 = dy2 = dy;
}
/*
else if(m_style == bond_double_left)
{
dx2 = dx * 2.0;
dy2 = dy * 2.0;
}
else
{
dx2 = -dx * 2.0;
dy2 = -dy * 2.0;
}
*/
m_line1.init(m_bond.x1 - dx1,
m_bond.y1 - dy1,
m_bond.x2 - dx1,
m_bond.y2 - dy1);
m_line1.rewind(0);
m_line2.init(m_bond.x1 + dx2,
m_bond.y1 + dy2,
m_bond.x2 + dx2,
m_bond.y2 + dy2);
m_line2.rewind(0);
m_status = 0;
break;
case bond_triple:
// To Do: triple bonds drawing.
default:
m_line1.init(m_bond.x1, m_bond.y1, m_bond.x2, m_bond.y2);
m_line1.rewind(0);
break;
}
}
unsigned vertex(double* x, double* y)
{
unsigned flag = agg::path_cmd_stop;
switch(m_style)
{
case bond_wedged_solid:
return m_solid_wedge.vertex(x, y);
case bond_wedged_dashed:
return m_dashed_wedge.vertex(x, y);
case bond_double_left:
case bond_double_right:
case bond_double:
if(m_status == 0)
{
flag = m_line1.vertex(x, y);
if(flag == agg::path_cmd_stop)
{
m_status = 1;
}
}
if(m_status == 1)
{
flag = m_line2.vertex(x, y);
}
return flag;
case bond_triple:
case bond_single:
break;
}
return m_line1.vertex(x, y);
}
private:
bond_vertex_generator(const bond_vertex_generator&);
const bond_vertex_generator& operator = (const bond_vertex_generator&);
const bond_type& m_bond;
double m_thickness;
bond_style_e m_style;
agg::line m_line1;
agg::line m_line2;
agg::line m_line3;
agg::solid_wedge m_solid_wedge;
agg::dashed_wedge m_dashed_wedge;
unsigned m_status;
};
class the_application : public agg::platform_support
{
molecule* m_molecules;
unsigned m_num_molecules;
unsigned m_cur_molecule;
agg::slider_ctrl<color_type> m_thickness;
agg::slider_ctrl<color_type> m_text_size;
double m_pdx;
double m_pdy;
double m_center_x;
double m_center_y;
double m_scale;
double m_prev_scale;
double m_angle;
double m_prev_angle;
bool m_mouse_move;
agg::srgba8 m_atom_colors[end_of_atom_colors];
public:
virtual ~the_application()
{
delete [] m_molecules;
}
the_application(agg::pix_format_e format, bool flip_y, const char* fname) :
agg::platform_support(format, flip_y),
m_molecules(new molecule [100]),
m_num_molecules(0),
m_cur_molecule(0),
m_thickness(5, 5, start_width-5, 12),
m_text_size(5, 20, start_width-5, 27),
m_pdx(0.0),
m_pdy(0.0),
m_center_x(start_width / 2),
m_center_y(start_height / 2),
m_scale(1.0),
m_prev_scale(1.0),
m_angle(0.0),
m_prev_angle(0.0),
m_mouse_move(false)
{
m_thickness.label("Thickness=%3.2f");
m_text_size.label("Label Size=%3.2f");
add_ctrl(m_thickness);
add_ctrl(m_text_size);
FILE* fd = fopen(full_file_name(fname), "r");
if(fd)
{
unsigned i;
for(i = 0; i < 100; i++)
{
if(!m_molecules[m_num_molecules].read(fd)) break;
m_num_molecules++;
}
fclose(fd);
}
else
{
char buf[256];
sprintf(buf, "File not found: '%s'. Copy from ../art/%s\n",
fname, fname);
message(buf);
}
memset(m_atom_colors, 0, sizeof(agg::srgba8) * end_of_atom_colors);
m_atom_colors[atom_color_general] = agg::srgba8(0,0,0);
m_atom_colors[atom_color_N] = agg::srgba8(0,0,120);
m_atom_colors[atom_color_O] = agg::srgba8(200,0,0);
m_atom_colors[atom_color_S] = agg::srgba8(120,120,0);
m_atom_colors[atom_color_P] = agg::srgba8(80,50,0);
m_atom_colors[atom_color_halogen] = agg::srgba8(0,200,0);
}
virtual void on_init()
{
}
virtual void on_draw()
{
double width = initial_width();
double height = initial_height();
agg::rasterizer_scanline_aa<> ras;
agg::scanline_p8 sl;
typedef agg::renderer_base<pixfmt> renderer_base;
typedef agg::renderer_scanline_aa_solid<renderer_base> renderer_solid;
pixfmt pixf(rbuf_window());
renderer_base rb(pixf);
renderer_solid rs(rb);
ras.clip_box(0, 0, rb.width(), rb.height());
rb.clear(agg::rgba(1,1,1));
const molecule& mol = m_molecules[m_cur_molecule];
unsigned i;
double min_x = 1e100;
double max_x = -1e100;
double min_y = 1e100;
double max_y = -1e100;
for(i = 0; i < mol.num_atoms(); i++)
{
if(mol.atom(i).x < min_x) min_x = mol.atom(i).x;
if(mol.atom(i).y < min_y) min_y = mol.atom(i).y;
if(mol.atom(i).x > max_x) max_x = mol.atom(i).x;
if(mol.atom(i).y > max_y) max_y = mol.atom(i).y;
}
agg::trans_affine mtx;
mtx *= agg::trans_affine_translation(-(max_x + min_x) * 0.5, -(max_y + min_y) * 0.5);
double scale = width / (max_x - min_x);
double t = height / (max_y - min_y);
if(scale > t) scale = t;
double text_size = mol.average_bond_len() * m_text_size.value() / 4.0;
double thickness = mol.average_bond_len() /
sqrt(m_scale < 0.0001 ? 0.0001 : m_scale) /
8.0;
mtx *= agg::trans_affine_scaling(scale*0.80, scale*0.80);
mtx *= agg::trans_affine_rotation(m_angle);
mtx *= agg::trans_affine_scaling(m_scale, m_scale);
mtx *= agg::trans_affine_translation(m_center_x, m_center_y);
mtx *= trans_affine_resizing();
rs.color(agg::rgba(0,0,0));
for(i = 0; i < mol.num_bonds(); i++)
{
bond_vertex_generator bond(mol.bond(i),
m_thickness.value() * thickness);
agg::conv_transform<bond_vertex_generator> tr(bond, mtx);
ras.add_path(tr);
agg::render_scanlines(ras, sl, rs);
}
agg::ellipse ell;
agg::conv_transform<agg::ellipse> tr(ell, mtx);
for(i = 0; i < mol.num_atoms(); i++)
{
if(strcmp(mol.atom(i).label, "C") != 0)
{
ell.init(mol.atom(i).x,
mol.atom(i).y,
text_size * 2.5,
text_size * 2.5,
20);
ras.add_path(tr);
rs.color(agg::rgba(1.0, 1.0, 1.0));
agg::render_scanlines(ras, sl, rs);
}
}
text_size *= 3.0;
agg::gsv_text label;
agg::conv_stroke<agg::gsv_text> ls(label);
agg::conv_transform<agg::conv_stroke<agg::gsv_text> > lo(ls, mtx);
ls.line_join(agg::round_join);
ls.line_cap(agg::round_cap);
ls.approximation_scale(mtx.scale());
for(i = 0; i < mol.num_atoms(); i++)
{
if(strcmp(mol.atom(i).label, "C") != 0)
{
ls.width(m_thickness.value() * thickness);
label.text(mol.atom(i).label);
label.start_point(mol.atom(i).x - text_size/2, mol.atom(i).y - text_size/2);
label.size(text_size);
ras.add_path(lo);
rs.color(m_atom_colors[mol.atom(i).color_idx]);
agg::render_scanlines(ras, sl, rs);
}
}
ls.approximation_scale(1.0);
agg::conv_transform<agg::conv_stroke<agg::gsv_text> > name(ls, trans_affine_resizing());
ls.width(1.5);
label.text(mol.name());
label.size(10.0);
label.start_point(10.0, start_height - 20.0);
ras.reset();
ras.add_path(name);
rs.color(agg::rgba(0,0,0));
agg::render_scanlines(ras, sl, rs);
agg::render_ctrl(ras, sl, rb, m_thickness);
agg::render_ctrl(ras, sl, rb, m_text_size);
}
virtual void on_idle()
{
m_angle += agg::deg2rad(0.1);
force_redraw();
}
virtual void on_mouse_button_down(int x, int y, unsigned flags)
{
m_mouse_move = true;
double x2 = x;
double y2 = y;
trans_affine_resizing().inverse_transform(&x2, &y2);
m_pdx = m_center_x - x2;
m_pdy = m_center_y - y2;
m_prev_scale = m_scale;
m_prev_angle = m_angle + agg::pi;
force_redraw();
}
virtual void on_mouse_button_up(int x, int y, unsigned flags)
{
m_mouse_move = false;
}
virtual void on_mouse_move(int x, int y, unsigned flags)
{
double x2 = x;
double y2 = y;
trans_affine_resizing().inverse_transform(&x2, &y2);
if(m_mouse_move && (flags & agg::mouse_left) != 0)
{
double dx = x2 - m_center_x;
double dy = y2 - m_center_y;
m_scale = m_prev_scale *
sqrt(dx * dx + dy * dy) /
sqrt(m_pdx * m_pdx + m_pdy * m_pdy);
m_angle = m_prev_angle + atan2(dy, dx) - atan2(m_pdy, m_pdx);
force_redraw();
}
if(m_mouse_move && (flags & agg::mouse_right) != 0)
{
m_center_x = x2 + m_pdx;
m_center_y = y2 + m_pdy;
force_redraw();
}
}
virtual void on_key(int, int, unsigned key, unsigned)
{
switch(key)
{
case agg::key_left:
case agg::key_up:
case agg::key_page_up:
if(m_cur_molecule) --m_cur_molecule;
force_redraw();
break;
case agg::key_right:
case agg::key_down:
case agg::key_page_down:
if(m_cur_molecule < m_num_molecules - 1) ++m_cur_molecule;
force_redraw();
break;
case ' ':
wait_mode(!wait_mode());
break;
}
}
};
int agg_main(int argc, char* argv[])
{
const char* fname = "1.sdf";
if(argc > 1)
{
fname = argv[1];
}
the_application app(pix_format, flip_y, fname);
app.caption("AGG - A Simple SDF Molecular Viewer");
if(app.init(start_width, start_height, agg::window_resize))
{
return app.run();
}
return 1;
}