/*
Copyright (C) 2003 by Sean David Fleming
sean@ivec.org
This program 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
of the License, or (at your option) any later version.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
The GNU GPL can also be found at http://www.gnu.org
*/
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef __WIN32
#include <sys/times.h>
#endif
#include "gdis.h"
#include "coords.h"
#include "edit.h"
#include "matrix.h"
#include "opengl.h"
#include "render.h"
#include "select.h"
#include "shortcuts.h"
#include "interface.h"
#include "zone.h"
#define DEBUG 0
extern struct sysenv_pak sysenv;
extern struct elem_pak elements[];
gint current_colour[3];
/*********************/
/* copy an atom core */
/*********************/
/* return the number of items copied (ie 0-2) */
#define DEBUG_COPY_CORE 0
struct core_pak *copy_core(struct core_pak *core, struct model_pak *src,
struct model_pak *dest)
{
gint items=0;
gdouble vec[3];
struct core_pak *copyc;
struct shel_pak *copys;
/* checks */
g_assert(core != NULL);
g_assert(src != NULL);
g_assert(dest != NULL);
/* duplicate data structure */
copyc = dup_core(core);
items++;
/* setup status */
copyc->status = copyc->status & (~SELECT & ~SELECT);
copyc->orig = copyc->primary = TRUE;
copyc->primary_core = NULL;
VEC3SET(copyc->offset, 0.0, 0.0, 0.0);
/* coords, account for transformation matrices */
ARR3SET(vec, core->rx);
vecmat(dest->ilatmat, vec);
ARR3ADD(vec, dest->centroid);
ARR3SET(copyc->x, vec);
dest->cores = g_slist_prepend(dest->cores, copyc);
/* attached shell? */
if (copyc->shell)
{
copys = copyc->shell;
items++;
/* main info */
copys->status = copys->status & (~SELECT);
copys->primary=copys->orig=TRUE;
copys->primary_shell = NULL;
VEC3SET(copys->offset, 0.0, 0.0, 0.0);
/* coords, account for transformation matrices */
ARR3SET(vec, copys->rx);
vecmat(dest->ilatmat, vec);
ARR3ADD(vec, dest->centroid);
ARR3SET(copys->x, vec);
dest->shels = g_slist_prepend(dest->shels, copys);
}
return(copyc);
}
/********************/
/* duplicate a core */
/********************/
struct core_pak *dup_core(struct core_pak *orig)
{
struct core_pak *core;
/* checks */
g_assert(orig != NULL);
core = g_malloc(sizeof(struct core_pak));
memcpy(core, orig, sizeof(struct core_pak));
/* clear pointers */
core->bonds = NULL;
core->shell = NULL;
core->mol = NULL;
core->primary_core = NULL;
/* duplicate strings */
core->atom_label = g_strdup(orig->atom_label);
core->atom_type = g_strdup(orig->atom_type);
core->res_name = g_strdup(orig->res_name);
core->flags = g_strdup(orig->flags);
core->vibx_list = NULL;
core->viby_list = NULL;
core->vibz_list = NULL;
/* duplicate the shell */
if (orig->shell)
{
core->shell = dup_shel(orig->shell);
(core->shell)->core = core;
}
return(core);
}
/*********************/
/* shell duplication */
/*********************/
struct shel_pak *dup_shel(struct shel_pak *orig)
{
struct shel_pak *shel;
/* checks */
g_assert(orig != NULL);
shel = g_malloc(sizeof(struct shel_pak));
memcpy(shel, orig, sizeof(struct shel_pak));
/* clear pointers */
shel->core = NULL;
shel->primary_shell = NULL;
VEC3SET(shel->pic, 0, 0, 0);
/* duplicate strings */
shel->flags = g_strdup(orig->flags);
return(shel);
}
/****************************/
/* base atom initialization */
/****************************/
void core_init(gchar *elem, struct core_pak *core, struct model_pak *model)
{
gint code;
struct elem_pak elem_data;
/* attempt to match atom type with database */
if (model->protein)
code = pdb_elem_type(elem);
else
code = elem_test(elem);
/* general initialization */
core->atom_code = code;
core->atom_type = NULL;
core->atom_label = NULL;
core->res_name = g_strdup("");
core->res_no = 1;
core->chain = NULL;
core->atom_order = 0;
/* element related initialization */
get_elem_data(code, &elem_data, model);
core->bond_cutoff = elem_data.cova;
ARR3SET(core->colour, elem_data.colour);
core->colour[3] = 1.0;
}
/***************************/
/* atom creation primitive */
/***************************/
gpointer core_new(gchar *elem, gchar *label, struct model_pak *model)
{
struct core_pak *core;
g_assert(elem != NULL);
g_assert(model != NULL);
core = g_malloc(sizeof(struct core_pak));
/* element related initialization */
core_init(elem, core, model);
/* general initialization */
if (label)
core->atom_label = g_strdup(label);
else
core->atom_label = g_strdup(elem);
VEC4SET(core->x, 0.0, 0.0, 0.0, 1.0);
VEC4SET(core->rx, 0.0, 0.0, 0.0, 1.0);
VEC3SET(core->v, 0.0, 0.0, 0.0);
VEC3SET(core->offset, 0.0, 0.0, 0.0);
core->status = NORMAL;
core->primary = TRUE;
core->orig = TRUE;
core->ghost = FALSE;
core->breathe = FALSE;
core->growth = FALSE;
core->translate = FALSE;
core->render_mode = BALL_STICK;
core->render_wire = FALSE;
core->region = REGION1A;
core->radius = 0.0;
core->has_sof = FALSE;
core->sof = 1.0;
core->charge = 0.0;
core->lookup_charge = TRUE;
core->flags = NULL;
core->bonds = NULL;
core->mol = NULL;
core->shell = NULL;
core->primary_core = NULL;
core->vibx_list = NULL;
core->viby_list = NULL;
core->vibz_list = NULL;
/* NEW: hydrogen bond capabilities */
if (g_strrstr(elem, "H") != NULL)
core->hydrogen_bond = TRUE;
else
core->hydrogen_bond = FALSE;
return(core);
}
/*******************************/
/* unified atom initialization */
/*******************************/
/* deprec */
#define DEBUG_NEW_CORE 0
struct core_pak *new_core(gchar *elem, struct model_pak *model)
{
struct core_pak *core;
core = core_new(elem, NULL, model);
return(core);
}
/****************************/
/* shell creation primitive */
/****************************/
gpointer shell_new(gchar *elem, gchar *label, struct model_pak *model)
{
gint code;
struct elem_pak elem_data;
struct shel_pak *shell;
g_assert(elem != NULL);
g_assert(model != NULL);
shell = g_malloc(sizeof(struct shel_pak));
/* attempt to match atom type with database */
code = elem_test(elem);
if (!code)
printf("Warning: element [%s] not found.\n", elem);
/* init modifiable element data */
get_elem_data(code, &elem_data, model);
ARR3SET(shell->colour, elem_data.colour);
shell->atom_code = code;
if (label)
shell->shell_label = g_strdup(label);
else
shell->shell_label = g_strdup(elem);
VEC4SET(shell->x, 0.0, 0.0, 0.0, 1.0);
VEC4SET(shell->rx, 0.0, 0.0, 0.0, 1.0);
VEC3SET(shell->v, 0.0, 0.0, 0.0);
VEC3SET(shell->offset, 0.0, 0.0, 0.0);
shell->status = NORMAL;
shell->primary = TRUE;
shell->orig = TRUE;
shell->breathe = FALSE;
shell->translate = FALSE;
shell->region = REGION1A;
shell->core = NULL;
shell->primary_shell = NULL;
shell->radius = 0.0;
shell->charge = 0.0;
shell->has_sof = FALSE;
shell->sof = 1.0;
shell->lookup_charge = TRUE;
shell->flags = NULL;
return(shell);
}
/**********************************/
/* replacement shell init routine */
/**********************************/
/* deprec */
struct shel_pak *new_shell(gchar *elem, struct model_pak *model)
{
struct shel_pak *shell;
shell = shell_new(elem, NULL, model);
return(shell);
}
/***************************************/
/* fully duplicate a model's core list */
/***************************************/
GSList *dup_core_list(GSList *orig)
{
GSList *copy, *list;
struct core_pak *core;
copy = NULL;
for (list=orig ; list ; list=g_slist_next(list))
{
core = dup_core(list->data);
copy = g_slist_prepend(copy, core);
}
copy = g_slist_reverse(copy);
return(copy);
}
/****************************************/
/* fully duplicate a model's shell list */
/****************************************/
GSList *dup_shell_list(GSList *orig)
{
GSList *copy, *list;
struct shel_pak *shell;
copy = NULL;
for (list=orig ; list ; list=g_slist_next(list))
{
shell = dup_shel(list->data);
copy = g_slist_prepend(copy, shell);
}
copy = g_slist_reverse(copy);
return(copy);
}
/**************************/
/* remove duplicate cores */
/**************************/
/* NB: assumes zone_init() has been done */
#define DEBUG_REMOVE_DUPLICATES 0
#define DEBUG_REMOVE_DUPLICATES_MORE 0
void delete_duplicate_cores(struct model_pak *model)
{
gdouble vec[3];
GSList *list1, *list2;
gpointer zone;
struct core_pak *core1, *core2;
struct shel_pak *s1, *s2;
/* checks */
g_assert(model != NULL);
g_assert(model->zone_array != NULL);
#if DEBUG_REMOVE_DUPLICATES
printf("Initial cores: %d\n", g_slist_length(model->cores));
printf("Initial shels: %d\n", g_slist_length(model->shels));
#endif
/* enumerate all cores */
for (list1=model->cores ; list1 ; list1=g_slist_next(list1))
{
core1 = list1->data;
if (core1->status & DELETED)
continue;
/* enumerate cores in current locality */
zone = zone_get(core1->x, model->zone_array);
#if DEBUG_REMOVE_DUPLICATES_MORE
printf(" + %s [%p] : [%p] :", core1->atom_label, core1, zone);
P3VEC(" ", core1->x);
#endif
/* should use zone_area_cores() as a very small coord difference */
/* can result in cores being put in different (neighbouring) zones */
/*
for (list2=zone_cores(zone) ; list2 ; list2=g_slist_next(list2))
*/
for (list2=zone_area_cores(1, zone, model->zone_array) ; list2 ; list2=g_slist_next(list2))
{
core2 = list2->data;
if (core2->status & DELETED)
continue;
/* avoid double counting */
if (core1 >= core2)
continue;
if (core1->atom_code != core2->atom_code)
continue;
#if DEBUG_REMOVE_DUPLICATES_MORE
printf(" - %s :", core2->atom_label);
P3VEC(" ", core2->x);
#endif
/* compute and test the minimum separation */
ARR3SET(vec, core1->x);
ARR3SUB(vec, core2->x);
fractional_minsq(vec, model->periodic);
if (VEC3MAGSQ(vec) < FRACTION_TOLERANCE)
{
/* delete core2, unless primary AND core1 is non primary */
if (core2->primary && !core1->primary)
{
core1->status |= DELETED;
/* FIXME - this may be a problem since we start the core2 loop */
/* requiring that core1 be undeleted */
#if DEBUG_REMOVE_DUPLICATES_MORE
printf(" * rm 1\n");
#endif
}
else
{
core2->status |= DELETED;
#if DEBUG_REMOVE_DUPLICATES_MORE
printf(" * rm 2\n");
#endif
}
}
}
}
/* commit before searching for duplicate shells, as a commit */
/* will delete some attached shells */
delete_commit(model);
for (list1=model->shels ; list1 ; list1=g_slist_next(list1))
{
s1 = list1->data;
if (s1->status & DELETED)
continue;
/* NEW - enumerate shells in the current locality */
zone = zone_get(s1->x, model->zone_array);
for (list2=zone_shells(zone) ; list2 ; list2=g_slist_next(list2))
{
s2 = list2->data;
if (s2->status & DELETED)
continue;
if (s1 == s2)
continue;
ARR3SET(vec, s1->x);
ARR3SUB(vec, s2->x);
/* adjust for periodicity */
fractional_minsq(vec, model->periodic);
if (VEC3MAGSQ(vec) < FRACTION_TOLERANCE)
{
/* delete shell2, unless primary AND shell1 is non primary */
if (s2->primary && !s1->primary)
s1->status |= DELETED;
else
s2->status |= DELETED;
}
}
}
delete_commit(model);
#if DEBUG_REMOVE_DUPLICATES
printf("Final cores: %d\n", g_slist_length(model->cores));
printf("Final shels: %d\n", g_slist_length(model->shels));
#endif
}
/********************************************************/
/* set vector to minimum fractional magnitute (squared) */
/********************************************************/
#define DEBUG_FRAC_MINSQ 0
void fractional_minsq(gdouble *x, gint dim)
{
gint i, j;
gdouble whole;
g_assert(dim < 4);
#if DEBUG_FRAC_MINSQ
P3VEC("b4: ", x);
#endif
for (i=0 ; i<dim ; i++)
{
/* clamp value -1 < x < 1 */
x[i] = modf(x[i], &whole);
/* clamp to range (-0.5, 0.5) */
j = (gint) (-2.0 * x[i]);
x[i] += (gdouble) j;
}
#if DEBUG_FRAC_MINSQ
P3VEC("af: ", x);
#endif
}
/*************************************/
/* clamp coords to fractional limits */
/*************************************/
#define DEBUG_CLAMP 0
void fractional_clamp(gdouble *vec, gint *mov, gint dim)
{
gint i;
gdouble ip;
#if DEBUG_CLAMP
P3VEC("inp: ", vec);
#endif
/* NB: init ALL 3 coords as isolated molecules call this */
/* routine & it is expected that mov to be set to 0,0,0 */
mov[0] = mov[1] = mov[2] = 0;
/*
for (i=0 ; i<dim ; i++)
*/
for (i=dim ; i-- ; )
{
mov[i] = -vec[i];
if (vec[i] < 0.0)
{
/* increment the move for -ve's with exception -1.0, -2.0, -3.0,... */
if (modf(vec[i], &ip) != 0.0)
mov[i]++;
}
else
mov[i] = -vec[i];
vec[i] += (gdouble) mov[i];
}
#if DEBUG_CLAMP
P3VEC("out: ", vec);
#endif
}
/********************************************/
/* confine a list of atoms to the unit cell */
/********************************************/
#define DEBUG_PBC_ATOMS 0
void coords_confine_cores(GSList *cores, struct model_pak *model)
{
gint xlat[3];
gdouble mov[3];
GSList *list;
struct core_pak *core;
struct shel_pak *shell;
g_assert(model != NULL);
if (!model->periodic)
return;
/* translate cores to within the cell */
for (list=cores ; list ; list=g_slist_next(list))
{
core = list->data;
fractional_clamp(core->x, xlat, model->periodic);
/* move shell */
if (core->shell)
{
shell = core->shell;
ARR3SET(mov, xlat);
ARR3ADD(shell->x, mov);
}
}
}
/**********************************************/
/* confine a molecule's centroid to unit cell */
/**********************************************/
void coords_confine_centroid(struct mol_pak *mol, struct model_pak *model)
{
gint xlat[3];
gdouble mov[3];
GSList *list;
struct core_pak *core;
/* calc moves required to bring centroid within pbc */
fractional_clamp(mol->centroid, xlat, model->periodic);
ARR3SET(mov, xlat);
/* apply to all atoms/shells in this molecule */
for (list=mol->cores ; list ; list=g_slist_next(list))
{
core = list->data;
ARR3ADD(core->x, mov);
if (core->shell)
{
ARR3ADD((core->shell)->x, mov);
}
}
}
/*******************************************/
/* draw a box - contents are the selection */
/*******************************************/
void update_box(gint x, gint y, struct model_pak *data, gint call_type)
{
switch (call_type)
{
case START:
/* don't clean the selection (allows multiple box selections) */
/* setup the box selection object */
data->box_on = TRUE;
data->select_box[0] = x;
data->select_box[1] = y;
case UPDATE:
data->select_box[2] = x;
data->select_box[3] = y;
break;
}
}
/**********************************************************/
/* check if a given label matches with element/atom label */
/**********************************************************/
#define DEBUG_SHELL_MATCH 0
gint shel_match(const gchar *label, struct shel_pak *shell)
{
gint code;
#if DEBUG_SHELL_MATCH
printf("[%s] : [%s]\n", label, shell->shell_label);
#endif
code = elem_symbol_test(label);
/* if input label doesnt match the element symbol length - it means the */
/* user has put in something like H1 - compare this with the atom label */
if (code)
{
if (g_ascii_strcasecmp(label, elements[shell->atom_code].symbol) != 0)
{
if (g_ascii_strcasecmp(shell->shell_label, label) == 0)
return(1);
}
else
return(1);
}
else
return(1);
#if DEBUG_SHELL_MATCH
printf("rejected.\n");
#endif
return(0);
}
/**********************************************************/
/* check if a given label matches with element/atom label */
/**********************************************************/
#define DEBUG_ATOM_MATCH 0
gint core_match(const gchar *label, struct core_pak *core)
{
gint code;
#if DEBUG_ATOM_MATCH
printf("[%s] : [%s]\n", label, core->atom_label);
#endif
code = elem_symbol_test(label);
/* if input label doesnt match the element symbol length - it means the */
/* user has put in something like H1 - compare this with the atom label */
if (code)
{
if (g_ascii_strcasecmp(label, elements[core->atom_code].symbol) != 0)
{
if (g_ascii_strcasecmp(core->atom_label, label) == 0)
return(1);
}
else
return(1);
}
else
return(1);
#if DEBUG_ATOM_MATCH
printf("rejected.\n");
#endif
return(0);
}
syntax highlighted by Code2HTML, v. 0.9.1