/*
Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Matthew P. Hodges
This file is part of XMakemol.
XMakemol is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
XMakemol is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with XMakemol; see the file COPYING. If not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#define __DRAW_C__
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <Xm/Xm.h>
#include "bonds.h"
#include "defs.h"
#include "draw.h"
#include "globals.h"
#include "vectors.h"
#include "view.h"
static double atom_scale = 0.5;
static double bond_scale = 0.5;
static double hbond_scale = 0.5;
static double smallest_cov_rad;
void
draw_atom(int si)
{
void convert_to_canvas_coords(double *, double *, Boolean);
double get_atom_radius(int);
Boolean mouse_motion_p (void);
Boolean outline_mode_p (void);
double radius;
double atom_coord[3], canvas_coord[2];
radius = get_atom_radius(si);
gcv.foreground=atoms[si].pixel;
gcv.line_width=0;
gcv.line_style=LineSolid;
XChangeGC(display,gc,GCForeground|GCLineWidth|GCLineStyle,&gcv);
/* get the canvas coords of the atom */
atom_coord[0] = atoms[si].x;
atom_coord[1] = atoms[si].y;
atom_coord[2] = atoms[si].z;
convert_to_canvas_coords(atom_coord, canvas_coord, 0);
if((! mouse_motion_p ()) || (! outline_mode_p ())){
XFillArc
(display,
canvas_pm,
gc,
(int) (canvas_coord[0] - radius),
(int) (canvas_coord[1] - radius),
(int) (2.0 * radius),
(int) (2.0 * radius),
0,
360*64);
if(atoms[si].sel == 1)
{
}
}
if (atoms[si].sel == 1)
{
gcv.foreground = sel_color.pixel;
}
else
{
gcv.foreground = BlackPixelOfScreen (screen_ptr);
}
XChangeGC (display, gc, GCForeground, &gcv);
XDrawArc
(display,
canvas_pm,
gc,
(int) (canvas_coord[0] - radius),
(int) (canvas_coord[1] - radius),
(int) (2.0 * radius),
(int) (2.0 * radius),
0,
360*64);
/* Distinguish atoms not selected for rotation/translation */
if(atoms[si].edit == 0)
{
XDrawLine(display,
canvas_pm,
gc,
(int) (canvas_coord[0]),
(int) (canvas_coord[1] - (radius / 2)),
(int) (canvas_coord[0]),
(int) (canvas_coord[1] + (radius / 2)));
XDrawLine(display,
canvas_pm,
gc,
(int) (canvas_coord[0] - (radius / 2)),
(int) (canvas_coord[1]),
(int) (canvas_coord[0] + (radius / 2)),
(int) (canvas_coord[1]));
}
}
void
draw_bond(int si, int sj)
{
double get_atom_radius(int);
void update_canvas_bond_points(int, int, Boolean, double);
XPoint bond_points[5];
update_canvas_bond_points(si, sj, 0, 0.0);
gcv.line_width=0;
gcv.foreground=atoms[si].pixel;
gcv.line_style=LineSolid;
XChangeGC(display,gc,GCLineWidth|GCForeground|GCLineStyle,&gcv);
/* Draw polygon 0-1-4-5 */
bond_points[0].x = canvas_bond_points[0].x;
bond_points[0].y = canvas_bond_points[0].y;
bond_points[1].x = canvas_bond_points[1].x;
bond_points[1].y = canvas_bond_points[1].y;
bond_points[2].x = canvas_bond_points[4].x;
bond_points[2].y = canvas_bond_points[4].y;
bond_points[3].x = canvas_bond_points[5].x;
bond_points[3].y = canvas_bond_points[5].y;
XFillPolygon(display,
canvas_pm,
gc,
bond_points,
4,
Complex,CoordModeOrigin);
gcv.foreground=BlackPixelOfScreen(screen_ptr);
XChangeGC(display,gc,GCForeground,&gcv);
gcv.foreground=atoms[sj].pixel;
XChangeGC(display,gc,GCForeground,&gcv);
/* Draw polygon 2-1-4-3 */
bond_points[0].x = canvas_bond_points[2].x;
bond_points[0].y = canvas_bond_points[2].y;
bond_points[1].x = canvas_bond_points[1].x;
bond_points[1].y = canvas_bond_points[1].y;
bond_points[2].x = canvas_bond_points[4].x;
bond_points[2].y = canvas_bond_points[4].y;
bond_points[3].x = canvas_bond_points[3].x;
bond_points[3].y = canvas_bond_points[3].y;
XFillPolygon(display,
canvas_pm,
gc,
bond_points,
4,
Complex,
CoordModeOrigin);
gcv.foreground=BlackPixelOfScreen(screen_ptr);
XChangeGC(display,gc,GCForeground,&gcv);
/* Draw the lines 0-2-3-5-0 */
bond_points[0].x = canvas_bond_points[0].x;
bond_points[0].y = canvas_bond_points[0].y;
bond_points[1].x = canvas_bond_points[2].x;
bond_points[1].y = canvas_bond_points[2].y;
bond_points[2].x = canvas_bond_points[3].x;
bond_points[2].y = canvas_bond_points[3].y;
bond_points[3].x = canvas_bond_points[5].x;
bond_points[3].y = canvas_bond_points[5].y;
bond_points[4].x = canvas_bond_points[0].x;
bond_points[4].y = canvas_bond_points[0].y;
XDrawLines(display,
canvas_pm,
gc,
bond_points,
5,
CoordModeOrigin);
/* Draw the line 1-4 */
bond_points[0].x = canvas_bond_points[1].x;
bond_points[0].y = canvas_bond_points[1].y;
bond_points[1].x = canvas_bond_points[4].x;
bond_points[1].y = canvas_bond_points[4].y;
XDrawLines(display,
canvas_pm,
gc,
bond_points,
2,
CoordModeOrigin);
}
static int no_dashes = 5;
int get_no_dashes(void)
{
return(no_dashes);
}
void
draw_hbond(int si, int sj)
{
double get_h_bond_width(int, int);
int get_no_dashes(void);
void update_canvas_hbond_points(int, int, Boolean);
int xm_nint(double);
int offset, no_slots, ihbond_length, dash_length;
char dash_list[2]; /* So range is 0-255 */
double x, y, hbond_length;
update_canvas_hbond_points(si, sj, 0);
/* Get the H-bond length (on the canvas) */
x = canvas_hbond_points[0].x - canvas_hbond_points[1].x;
y = canvas_hbond_points[0].y - canvas_hbond_points[1].y;
hbond_length = sqrt ((x * x) + (y * y));
/* Integer value of hbond_length */
ihbond_length = xm_nint(hbond_length);
/* for no_dashes dashes, there are ((2 * no_dashes) - 1) slots:
\ /
||| ||| ||| ||| |||
A ||| ||| ||| ||| ||| B
||| ||| ||| ||| |||
/ \
*/
no_slots = (2 * get_no_dashes()) - 1;
dash_length = xm_nint(hbond_length/no_slots);
offset = (2 * dash_length) -
((ihbond_length - (no_slots * dash_length)) / 2);
if(dash_length == 0)
{
/* Must be non-zero */
return;
}
else if(dash_length > 255)
{
/* stored in type char */
return;
}
dash_list[0] = dash_length;
dash_list[1] = dash_list[0];
/* Set the dashes */
XSetDashes(display,
gc,
offset,
dash_list,
2);
/* Change the GC */
gcv.line_width = (int) get_h_bond_width(si, sj);
gcv.foreground=BlackPixelOfScreen(screen_ptr);
gcv.line_style=LineOnOffDash;
XChangeGC(display,gc,GCForeground | GCLineWidth | GCLineStyle, &gcv);
/* Draw the lines 0-1 */
XDrawLine(display,
canvas_pm,
gc,
canvas_hbond_points[0].x,
canvas_hbond_points[0].y,
canvas_hbond_points[1].x,
canvas_hbond_points[1].y);
}
void
draw_atom_numbers_and_symbols(int si)
{
void convert_to_canvas_coords(double *, double *, Boolean);
int i;
char *labels = "ABCD", label_string[10], temp_string[10];
double atom_coord[3], label_coord[2];
atom_coord[0] = atoms[si].x;
atom_coord[1] = atoms[si].y;
atom_coord[2] = atoms[si].z;
convert_to_canvas_coords(atom_coord, label_coord, 0);
/* Add atom number if appropriate */
strcpy(label_string, ""); /* Initialize */
if(at_nos_flag == 1)
{
sprintf(label_string, "%d ", si + 1);
}
/* Add atom symbol if appropriate */
if(at_sym_flag == 1)
{
sprintf(temp_string, "%s ", atoms[si].label);
strcat(label_string, temp_string);
}
/* Add the measure label if appropriate */
for(i = 0; i < 4; i++)
{
if(si == selected[i])
{
sprintf(temp_string, "%c", labels[i]);
strcat(label_string, temp_string);
}
}
XDrawString(display,
canvas_pm,
gc,
(int) label_coord[0],
(int) label_coord[1],
label_string,
strlen(label_string));
}
void
draw_axes(void)
{
char axis_lab[2];
int x_pos,y_pos;
gcv.foreground=BlackPixelOfScreen(screen_ptr);
gcv.line_style=LineSolid;
gcv.line_width=0;
x_pos = (int)(canvas_width-50);
y_pos = 50;
XChangeGC(display,gc,GCForeground|GCLineStyle|GCLineWidth, &gcv);
XDrawLine(display,canvas_pm,gc,
x_pos,
y_pos,
(int)(x_pos+global_matrix[0][0]*30),
(int)(y_pos-global_matrix[0][1]*30));
strcpy(axis_lab,"X");
XDrawString(display,canvas_pm,gc,
(int)(x_pos+global_matrix[0][0]*40),
(int)(y_pos-global_matrix[0][1]*40),
axis_lab,
strlen(axis_lab));
XDrawLine(display,canvas_pm,gc,
x_pos,
y_pos,
(int)(x_pos+global_matrix[1][0]*30),
(int)(y_pos-global_matrix[1][1]*30));
strcpy(axis_lab,"Y");
XDrawString(display,canvas_pm,gc,
(int)(x_pos+global_matrix[1][0]*40),
(int)(y_pos-global_matrix[1][1]*40),
axis_lab,
strlen(axis_lab));
XDrawLine(display,canvas_pm,gc,
x_pos,
y_pos,
(int)(x_pos+global_matrix[2][0]*30),
(int)(y_pos-global_matrix[2][1]*30));
strcpy(axis_lab,"Z");
XDrawString(display,canvas_pm,gc,
(int)(x_pos+global_matrix[2][0]*40),
(int)(y_pos-global_matrix[2][1]*40),
axis_lab,
strlen(axis_lab));
}
void
draw_vector(int si, int j)
{
void update_canvas_vector_points (int, int);
update_canvas_vector_points (si, j);
gcv.line_width = 2;
gcv.line_style=LineSolid;
gcv.foreground=BlackPixelOfScreen(screen_ptr);
XChangeGC(display, gc, GCLineWidth | GCLineStyle | GCForeground, &gcv);
switch (arrow_type)
{
case ARROW_OPEN:
XDrawLine(display,
canvas_pm,
gc,
canvas_vector_points[0].x,
canvas_vector_points[0].y,
canvas_vector_points[1].x,
canvas_vector_points[1].y);
XDrawLine(display,
canvas_pm,
gc,
canvas_vector_points[1].x,
canvas_vector_points[1].y,
canvas_vector_points[3].x,
canvas_vector_points[3].y);
XDrawLine(display,
canvas_pm,
gc,
canvas_vector_points[1].x,
canvas_vector_points[1].y,
canvas_vector_points[4].x,
canvas_vector_points[4].y);
break;
case ARROW_CLOSED:
XDrawLine(display,
canvas_pm,
gc,
canvas_vector_points[0].x,
canvas_vector_points[0].y,
canvas_vector_points[2].x,
canvas_vector_points[2].y);
XDrawLine(display,
canvas_pm,
gc,
canvas_vector_points[1].x,
canvas_vector_points[1].y,
canvas_vector_points[3].x,
canvas_vector_points[3].y);
XDrawLine(display,
canvas_pm,
gc,
canvas_vector_points[3].x,
canvas_vector_points[3].y,
canvas_vector_points[4].x,
canvas_vector_points[4].y);
XDrawLine(display,
canvas_pm,
gc,
canvas_vector_points[4].x,
canvas_vector_points[4].y,
canvas_vector_points[1].x,
canvas_vector_points[1].y);
break;
case ARROW_FILLED:
XDrawLine(display,
canvas_pm,
gc,
canvas_vector_points[0].x,
canvas_vector_points[0].y,
canvas_vector_points[2].x,
canvas_vector_points[2].y);
{
XPoint xpoints[3];
xpoints[0].x = canvas_vector_points[1].x;
xpoints[0].y = canvas_vector_points[1].y;
xpoints[1].x = canvas_vector_points[3].x;
xpoints[1].y = canvas_vector_points[3].y;
xpoints[2].x = canvas_vector_points[4].x;
xpoints[2].y = canvas_vector_points[4].y;
XFillPolygon (display,
canvas_pm,
gc,
xpoints,
3,
Complex,
CoordModeOrigin);
}
break;
}
}
void
draw_region(void)
{
XPoint region_get_start(void);
XPoint region_get_end(void);
int x1, y1, x2, y2, temp, width, height;
XPoint start, end;
start = region_get_start();
end = region_get_end();
x1 = start.x;
y1 = start.y;
x2 = end.x;
y2 = end.y;
if(x1 > x2)
{
temp = x1;
x1 = x2;
x2 = temp;
}
if(y1 > y2)
{
temp = y1;
y1 = y2;
y2 = temp;
}
width = x2 - x1;
height = y2 - y1;
gcv.line_width = 2;
XChangeGC(display,
gc,
GCLineWidth,
&gcv);
XDrawRectangle(display,
XtWindow(canvas),
gc,
x1, y1,
width, height);
}
double
get_atom_radius(int i)
{
double get_atom_scale(void);
double get_canvas_scale(void);
double get_depth_scale(double);
double radius;
radius =
get_atom_scale() * /* which is interactively scalable */
get_canvas_scale() * /* scale factor due to size of canvas */
get_depth_scale(atoms[i].z); /* scale factor due to depth of atom */
/* Scale by covalent of van der Waals radius, depending on whether
the atom is bonded to anything else */
if ((bond_adjacency_list[i] == NULL) && (never_use_vdw == 0))
{
radius *= atoms[i].vdw_rad;
}
else
{
radius *= atoms[i].cov_rad;
}
return (radius);
}
/*
What a bond looks like:
\ /
5--------------------4--------------------3
| | |
A l m n B
| | |
0--------------------1--------------------2
/ \
A and B are the atom centres. The bond length is the distance
between A and B. The bond is separated at the midpoint (vertical
line above). This is defined as follows. If the radii of a and b are
r_a and r_b respectively, the point m is at a + r_a/(r_a + r_b) * r
- this is the proportion of the bond that "belongs" to atom a.
Likewise, the proportion of the bond that "belongs" to atom b is
given by r_b/(r_a + r_b).
a = 0 -> A
b = 0 -> b
r = b - a
p = z x r (bond perpendicular, parallel 23 and 05)
l = a + radius(a) * r
m = a + r_a/(r_a + r_b) * r
n = b - radius(b) * r
*/
/* Note that for PostScript output, the Y axis is in the opposite
direction, so that y must be replaced with (canvas_width - y). This
is covered using the Boolean variable ps_corr */
void
update_canvas_bond_points(int si, int sj, Boolean ps_corr, double offset)
{
void convert_to_canvas_coords(double *, double *, Boolean);
double get_atom_scale(void);
double get_bond_width(void);
double mod_of_vec(double *);
void normalize_vec(double *);
int i;
double mod_r, a_prop, sb_wid, local_at_scale, half_bond_width;
double a[3], b[3], r[3], p[3], l[3], m[3], n[3];
a[0] = atoms[si].x;
a[1] = atoms[si].y;
a[2] = atoms[si].z;
b[0] = atoms[sj].x;
b[1] = atoms[sj].y;
b[2] = atoms[sj].z;
for(i = 0; i < 3; i++)
{
r[i] = b[i] - a[i];
}
/* We need to keep the modulus of r for later */
mod_r = mod_of_vec(r);
normalize_vec(r);
/* This satisfies the condition that p is perpendicular to both
the vector r and the z direction */
p[0] = -1.0 * r[1];
p[1] = 1.0 * r[0];
p[2] = 0.0;
normalize_vec(p);
/* Calculate intermediate quantities */
a_prop = atoms[si].cov_rad/(atoms[si].cov_rad + atoms[sj].cov_rad);
/* Fudge: switching off atoms is equivalent to having atoms of zero
radius */
if(atom_flag == 0)
{
local_at_scale = 0.0;
}
else
{
local_at_scale = get_atom_scale(); /* The "canonical" value */
}
for(i=0; i < 3; i++)
{
if (local_at_scale != 0)
{
l[i] = a[i] +
(atoms[si].cov_rad * local_at_scale + offset) * r[i];
}
else
{
l[i] = a[i] + (offset * r[i]);
}
m[i] = a[i] + a_prop * (mod_r - offset) * r[i];
n[i] = b[i] - (atoms[sj].cov_rad * local_at_scale * r[i]);
}
/* Calculate bond coordinates (cartesian) */
/* The maximum bond width is the covalent radius of the smallest atom */
sb_wid = get_bond_width ();
for(i = 0; i < 3; i++)
{
if ((i == 0) || (i == 1))
{
half_bond_width = ((sb_wid - (2.0 * offset)) * p[i] / 2.0);
}
else
{
half_bond_width = (sb_wid * p[i] / 2.0);
}
cartesian_bond_points[0][i] = l[i] - half_bond_width;
cartesian_bond_points[1][i] = m[i] - half_bond_width;
cartesian_bond_points[2][i] = n[i] - half_bond_width;
cartesian_bond_points[3][i] = n[i] + half_bond_width;
cartesian_bond_points[4][i] = m[i] + half_bond_width;
cartesian_bond_points[5][i] = l[i] + half_bond_width;
}
/* Loop over the bond coordinates and get canvas coordinates */
for(i = 0; i < 6; i++)
{
double xy_temp[2];
convert_to_canvas_coords(cartesian_bond_points[i], xy_temp, ps_corr);
canvas_bond_points[i].x = xy_temp[0];
canvas_bond_points[i].y = xy_temp[1];
}
}
void
update_canvas_hbond_points(int si, int sj, Boolean ps_corr)
{
double get_atom_scale(void);
void convert_to_canvas_coords(double *, double *, Boolean);
double mod_of_vec(double *);
void normalize_vec(double *);
int i;
double mod_r, local_at_scale;
double a[3], b[3], r[3];
a[0] = atoms[si].x;
a[1] = atoms[si].y;
a[2] = atoms[si].z;
b[0] = atoms[sj].x;
b[1] = atoms[sj].y;
b[2] = atoms[sj].z;
for(i = 0; i < 3; i++)
{
r[i] = b[i] - a[i];
}
/* We need to keep the modulus of r for later */
mod_r = mod_of_vec(r);
normalize_vec(r);
/* Fudge: switching off atoms is equivalent to having atoms of zero
radius */
if(atom_flag == 0)
{
local_at_scale = 0.0;
}
else
{
local_at_scale = get_atom_scale(); /* The "global" value */
}
for(i=0; i < 3; i++)
{
double radius[2];
/* If bonded use covalent radius, otherwise van der Waals */
if ((bond_adjacency_list[si] == NULL) && (never_use_vdw == 0))
{
radius[0] = atoms[si].vdw_rad;
}
else
{
radius[0] = atoms[si].cov_rad;
}
if ((bond_adjacency_list[sj] == NULL) && (never_use_vdw == 0))
{
radius[1] = atoms[sj].vdw_rad;
}
else
{
radius[1] = atoms[sj].cov_rad;
}
cartesian_hbond_points[0][i] =
a[i] + (radius[0] * local_at_scale * r[i]);
cartesian_hbond_points[1][i] =
b[i] - (radius[1] * local_at_scale * r[i]);
}
/* Loop over the bond coordinates and get canvas coordinates */
for(i = 0; i < 2; i++)
{
double xy_temp[2];
convert_to_canvas_coords(cartesian_hbond_points[i], xy_temp, ps_corr);
canvas_hbond_points[i].x = xy_temp[0];
canvas_hbond_points[i].y = xy_temp[1];
}
}
double
get_h_bond_width(int si, int sj)
{
double get_atom_radius(int);
double get_canvas_scale(void);
double get_depth_scale(double);
double get_hbond_scale(void);
int hi; /* hydrogen index */
double h_bond_width;
/* Determine which atom is hydrogen */
if(atoms[si].is_hydrogen == 1)
{
hi = si;
}
else
{
hi = sj;
}
/* This is set to the radius of a hydrogen atom. This is dependent
on the depth - cf get_atom_radius (we don't want this to be
dependent on atom_scale */
h_bond_width = atoms[hi].cov_rad *
get_canvas_scale() *
get_depth_scale(atoms[hi].z);
/* Scale according the adjustable H-bond factor (0->1) */
h_bond_width *= get_hbond_scale();
return(h_bond_width);
}
double
get_atom_scale(void)
{
return(atom_scale);
}
void
set_atom_scale(double new_scale)
{
atom_scale = new_scale;
}
double
get_hbond_scale(void)
{
return(hbond_scale);
}
void
set_hbond_scale(double new_scale)
{
hbond_scale = new_scale;
}
double
get_bond_scale(void)
{
return(bond_scale);
}
void
set_bond_scale(double new_scale)
{
bond_scale = new_scale;
}
double
get_bond_width (void)
{
return (bond_scale * smallest_cov_rad);
}
void
set_smallest_cov_rad(double new)
{
smallest_cov_rad = new;
}
double
get_smallest_cov_rad(void)
{
return(smallest_cov_rad);
}
syntax highlighted by Code2HTML, v. 0.9.1