/* Copyright (C) 2001 Damir Zucic */

/*=============================================================================

				rotate_range.c

Purpose:
	Rotate the specified range of atoms. The rotation is done about the
	specified axis.  The axis is specified by one point and by one unit
	vector.

Input:
	(1) Pointer to  AtomS structure,  pointing to  the first element of
	    the atomic array.
	(2) Index of the first atom in the range.
	(3) Index of the last atom in the range.
	(4) Pointer to VectorS structure, which defines the point in space.
	(5) Pointer to VectorS structure, which defines the unit vector.
	(6) The rotation angle.

Output:
	(1) The specified range of atoms translated.
	(2) Return value.

Return value:
	No return value.

========includes:============================================================*/

#include <stdio.h>

#include <math.h>

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xos.h>
#include <X11/Xatom.h>

#include "defines.h"
#include "typedefs.h"

/*======function prototypes:=================================================*/

int		ParallelPart_ (VectorS *, VectorS *, VectorS *);
double		AbsoluteValue_ (VectorS *);
void		VectorProduct_ (VectorS *, VectorS *, VectorS *);
double		ScalarProduct_ (VectorS *, VectorS *);

/*======rotate the range of atoms:===========================================*/

void RotateRange_ (AtomS *atomSP, size_t atom_startI, size_t atom_endI,
		   VectorS *origin_vectorSP, VectorS *axis_vectorSP,
		   double angle)
{
double		cos_angle, sin_angle;
size_t		atomI;
AtomS		*curr_atomSP;
VectorS		radius_vectorS;
VectorS		parallel_vectorS;
VectorS		perpendicular_vectorS;
double		perpendicular_part;
double		abs_value;
double		reciprocal_abs_value;
VectorS		unit_vector1S, unit_vector2S;
double          p1_new, p2_new;

/* Prepare the cosine and sine of the angle: */
cos_angle = cos (angle);
sin_angle = sin (angle);

/* Scan the range of atoms: */
for (atomI = atom_startI; atomI <= atom_endI; atomI++)
	{
	/* Pointer to the current atom: */
	curr_atomSP = atomSP + atomI;

	/* Prepare the radius vector of the given atom: */
	radius_vectorS.x = curr_atomSP->raw_atomS.x[0] - origin_vectorSP->x;
	radius_vectorS.y = curr_atomSP->raw_atomS.y    - origin_vectorSP->y;
	radius_vectorS.z = curr_atomSP->raw_atomS.z[0] - origin_vectorSP->z;

	/* Find the part of  the radius vector */
	/* which is parallel to the rot. axis. */
	ParallelPart_ (&parallel_vectorS, axis_vectorSP, &radius_vectorS);

	/* Find the part of the radius vector which */
	/* is perpendicular  to the  rotation axis: */
	perpendicular_vectorS.x = radius_vectorS.x - parallel_vectorS.x;
	perpendicular_vectorS.y = radius_vectorS.y - parallel_vectorS.y;
	perpendicular_vectorS.z = radius_vectorS.z - parallel_vectorS.z;

	/* Prepare and check the absolute value of the perpendicular part: */
	perpendicular_part = AbsoluteValue_ (&perpendicular_vectorS);
	if (perpendicular_part <= 0.0) continue;

	/* Prepare the first unit vector, required for rotation: */
	reciprocal_abs_value = 1.0 / perpendicular_part;
	unit_vector1S.x = reciprocal_abs_value * perpendicular_vectorS.x;
	unit_vector1S.y = reciprocal_abs_value * perpendicular_vectorS.y;
	unit_vector1S.z = reciprocal_abs_value * perpendicular_vectorS.z;

	/* Prepare and check the second unit vector: */
	VectorProduct_ (&unit_vector2S, axis_vectorSP, &unit_vector1S);
	abs_value = AbsoluteValue_ (&unit_vector2S);
	if (abs_value <= 0.0) continue;
	reciprocal_abs_value = 1.0 / abs_value;
	unit_vector2S.x = unit_vector2S.x * reciprocal_abs_value;
	unit_vector2S.y = unit_vector2S.y * reciprocal_abs_value;
	unit_vector2S.z = unit_vector2S.z * reciprocal_abs_value;

	/* Rotate the perpendicular vector: */
	p1_new = perpendicular_part * cos_angle;
	p2_new = perpendicular_part * sin_angle;
	perpendicular_vectorS.x = p1_new * unit_vector1S.x +
				  p2_new * unit_vector2S.x;
	perpendicular_vectorS.y = p1_new * unit_vector1S.y +
				  p2_new * unit_vector2S.y;
	perpendicular_vectorS.z = p1_new * unit_vector1S.z +
				  p2_new * unit_vector2S.z;

	/* Update the radius vector: */
	radius_vectorS.x = parallel_vectorS.x + perpendicular_vectorS.x;
	radius_vectorS.y = parallel_vectorS.y + perpendicular_vectorS.y;
	radius_vectorS.z = parallel_vectorS.z + perpendicular_vectorS.z;

	/* Update the atomic coordinates: */
	curr_atomSP->raw_atomS.x[0] = radius_vectorS.x + origin_vectorSP->x;
	curr_atomSP->raw_atomS.y    = radius_vectorS.y + origin_vectorSP->y;
	curr_atomSP->raw_atomS.z[0] = radius_vectorS.z + origin_vectorSP->z;
	}
}

/*===========================================================================*/


