/* changing it so it rotates around the three principal axises - Adam Hogan */ void molecule_rotate_quaternion(molecule_t *molecule, double alpha, double beta, double gamma, int reverse_flag) { atom_t *atom_ptr; double com[3]; int i, ii, n; double *new_coord_array; /* count the number of atoms in a molecule, and allocate new coords array */ for(atom_ptr = molecule->atoms, n = 0; atom_ptr; atom_ptr = atom_ptr->next) ++n; new_coord_array = calloc(n*3, sizeof(double)); memnullcheck(new_coord_array,n*3*sizeof(double),__LINE__-1, __FILE__); /* save the com coordinate */ com[0] = molecule->com[0]; com[1] = molecule->com[1]; com[2] = molecule->com[2]; /* translate the molecule to the origin */ for(atom_ptr = molecule->atoms; atom_ptr; atom_ptr = atom_ptr->next) { atom_ptr->pos[0] -= com[0]; atom_ptr->pos[1] -= com[1]; atom_ptr->pos[2] -= com[2]; } /* construct the rotation quaternions */ struct quaternion first, second, third, total, total_conjugate, position, answer; //total = quaternion with no rotation quaternion_construct_xyzw(&total,0.,0.,0.,1.); //first = rotation around z axis quaternion_construct_axis_angle_degree(&first,0.,0.,1.,alpha); //second = rotation around y axis quaternion_construct_axis_angle_degree(&second,0.,1.,0.,beta); //third = rotation around z axis quaternion_construct_axis_angle_degree(&third,1.,0.,0.,gamma); //combine all rotations into total quaternion_multiplication(&first,&total,&total); quaternion_multiplication(&second,&total,&total); quaternion_multiplication(&third,&total,&total); //if we are undoing a rotation we need to conjugate total if (reverse_flag) quaternion_conjugate(&total,&total); quaternion_conjugate(&total,&total_conjugate); for(atom_ptr = molecule->atoms, i = 0; atom_ptr; atom_ptr = atom_ptr->next, i++) { ii = i*3; //position = position vector quaternion_construct_xyzw(&position,atom_ptr->pos[0],atom_ptr->pos[1],atom_ptr->pos[2],0.); //answer = total*(position*total_conjugate) quaternion_multiplication(&position,&total_conjugate,&answer); quaternion_multiplication(&total,&answer,&answer); //set the new coords new_coord_array[ii+0] = answer.x; new_coord_array[ii+1] = answer.y; new_coord_array[ii+2] = answer.z; } /* set the new coordinates and then translate back from the origin */ for(atom_ptr = molecule->atoms, i = 0; atom_ptr; atom_ptr = atom_ptr->next, i++) { ii = i*3; atom_ptr->pos[0] = new_coord_array[ii+0]; atom_ptr->pos[1] = new_coord_array[ii+1]; atom_ptr->pos[2] = new_coord_array[ii+2]; atom_ptr->pos[0] += com[0]; atom_ptr->pos[1] += com[1]; atom_ptr->pos[2] += com[2]; } /* free our temporary array */ free(new_coord_array); }
/* now with quaternions AH */ void rotate(system_t *system, molecule_t *molecule, pbc_t *pbc, double scale) { atom_t *atom_ptr; double u1, u2, u3; double com[3]; int i, ii, n; double *new_coord_array; struct quaternion position_vector, rnd_rotation, rnd_rotation_conjugate, answer; // create a random rotation // http://planning.cs.uiuc.edu/node198.html u1 = get_rand(system); u2 = get_rand(system); u3 = get_rand(system); // simple linear interpolation for adjusting the scale quaternion_construct_xyzw(&rnd_rotation, scale*sqrt(1-u1)*sin(2*M_PI*u2), scale*sqrt(1-u1)*cos(2*M_PI*u2), scale*sqrt(u1)*sin(2*M_PI*u3), 1-scale+scale*sqrt(u1)*cos(2*M_PI*u3)); /* make a random quaternion */ quaternion_normalize(&rnd_rotation); quaternion_conjugate(&rnd_rotation, &rnd_rotation_conjugate); /* needed to transform coordinates */ /* count the number of atoms in a molecule, and allocate new coords array */ for (atom_ptr = molecule->atoms, n = 0; atom_ptr; atom_ptr = atom_ptr->next) ++n; new_coord_array = calloc(n * 3, sizeof(double)); memnullcheck(new_coord_array, n * 3 * sizeof(double), __LINE__ - 1, __FILE__); /* save the com coordinate */ com[0] = molecule->com[0]; com[1] = molecule->com[1]; com[2] = molecule->com[2]; /* translate the molecule to the origin */ for (atom_ptr = molecule->atoms; atom_ptr; atom_ptr = atom_ptr->next) { atom_ptr->pos[0] -= com[0]; atom_ptr->pos[1] -= com[1]; atom_ptr->pos[2] -= com[2]; } /* quaternion multiply */ for (atom_ptr = molecule->atoms, i = 0; atom_ptr; atom_ptr = atom_ptr->next, i++) { ii = i * 3; //position_vector = position quaternion_construct_xyzw(&position_vector, atom_ptr->pos[0], atom_ptr->pos[1], atom_ptr->pos[2], 0.); //answer = rnd_rotation*(position*rnd_rotation_conjugate) quaternion_multiplication(&position_vector, &rnd_rotation_conjugate, &answer); quaternion_multiplication(&rnd_rotation, &answer, &answer); //set the new coords new_coord_array[ii + 0] = answer.x; new_coord_array[ii + 1] = answer.y; new_coord_array[ii + 2] = answer.z; } /* set the new coordinates and then translate back from the origin */ for (atom_ptr = molecule->atoms, i = 0; atom_ptr; atom_ptr = atom_ptr->next, i++) { ii = i * 3; atom_ptr->pos[0] = new_coord_array[ii + 0]; atom_ptr->pos[1] = new_coord_array[ii + 1]; atom_ptr->pos[2] = new_coord_array[ii + 2]; atom_ptr->pos[0] += com[0]; atom_ptr->pos[1] += com[1]; atom_ptr->pos[2] += com[2]; } /* free our temporary array */ free(new_coord_array); }