/* Copyright (C) 2000, 2001 Damir Zucic */

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

				project_planes.c

Purpose:
	For each macromolecular complex,  project plane to  the screen.
	The plane is represented  by a circle in space,  which projects
	into  an ellipse.  The plane  is projected always,  even if not
	visible.  This function prepares only parameters which are kept
	in  PlaneS structure,  associated with  a given  macromolecular
	complex.  Other parameters will be prepared in a function which
	draws plane to the screen.

Input:
	(1) Pointer to MolComplexS structure, with macromol. complexes.
	(2) Number of macromolecular complexes.
	(3) Pointer to ConfigS structure, with configuration data.
	    
Output:
	(1) Parameters which define plane projection to the screen will
	    be calculated for each macromolecular complex containing at
	    least one atom. 

Return value:
	No return value.

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

#include <stdio.h>

#include <limits.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"

/*======project planes:=======================================================*/

void ProjectPlanes_ (MolComplexS *mol_complexSP, int mol_complexesN,
		     ConfigS *configSP)
{
double			nominator_x, nominator_y, user_atomic_position;
int			center_screen_x[2], center_screen_y;
int			mol_complexI;
MolComplexS		*curr_mol_complexSP;
PlaneS			*curr_planeSP;
int			imagesN, imageI;
double			denominator, reciprocal_denominator;
double			normal_x, normal_y, normal_z;
double			rationalized_x, rationalized_y;
double			scalar_product, abs_value_squared, abs_value;
double			cos_theta, cos_phi, angle;
double			value1, value2;

/* The number of images (1 for mono, 2 for stereo): */
if (configSP->stereoF == 1) imagesN = 2;
else imagesN = 1;

/* Prepare the factors which are used to */
/* reduce the number of multiplications: */
nominator_x = configSP->user_screen_atomic_distance *
	      configSP->atomic_to_screen_scale_x;
nominator_y = configSP->user_screen_atomic_distance *
	      configSP->atomic_to_screen_scale_y;

/* Prepare the user position in atomic coordinates: */
user_atomic_position = configSP->user_atomic_position;

/* Position of the window free area center (stereo data): */
center_screen_x[0] = configSP->center_screen_x[0];
center_screen_x[1] = configSP->center_screen_x[1];
center_screen_y = configSP->center_screen_y;

/* Project plane for each macromolecular complex: */
for (mol_complexI = 0; mol_complexI < mol_complexesN; mol_complexI++)
	{
	/* Pointer to the current macromolecular complex: */
	curr_mol_complexSP = mol_complexSP + mol_complexI;

	/* If this complex contains no atoms, ignore it: */
	if (curr_mol_complexSP->atomsN == 0) continue;

	/* Projection is not necessary if the position is unchanged: */
	if (curr_mol_complexSP->position_changedF == 0) continue;

	/* Pointer to the current plane: */
	curr_planeSP = &curr_mol_complexSP->planeS;

	/* Stereo data should be prepared: */
	for (imageI = 0; imageI < imagesN; imageI++)
		{
		/*------prepare auxilliary parameters:-----------------------*/

		denominator = curr_planeSP->center_z[imageI] -
			      user_atomic_position;
		if (denominator == 0.0) reciprocal_denominator = 0.0;
		else reciprocal_denominator = 1.0 / denominator;
		normal_x = curr_planeSP->normal_x[imageI];
		normal_y = curr_planeSP->normal_y;
		normal_z = curr_planeSP->normal_z[imageI];

		/*------project plane center to the screen:------------------*/

		/* Prepare rationalized coordinates: */
		rationalized_x = curr_planeSP->center_x[imageI] *
				 nominator_x * reciprocal_denominator;
		rationalized_y = curr_planeSP->center_y *
				 nominator_y * reciprocal_denominator;

		/* Keep them in a reasonable range: */
		if      (rationalized_x > (double) INT_MAX / 4)
			 rationalized_x = (double) INT_MAX / 4;
		else if (rationalized_x < (double) INT_MIN / 4)
			 rationalized_x = (double) INT_MIN / 4;
		if      (rationalized_y > (double) INT_MAX / 4)
			 rationalized_y = (double) INT_MAX / 4;
		else if (rationalized_y < (double) INT_MIN / 4)
			 rationalized_y = (double) INT_MIN / 4;

		/* Prepare screen coordinates of the plane center: */
		curr_planeSP->center_screen_x[imageI] =
				(int) rationalized_x + center_screen_x[imageI];
		curr_planeSP->center_screen_y =
				(int) rationalized_y + center_screen_y;

		/*------angle between normal vector and z axis:--------------*/

		scalar_product = normal_z;
		abs_value_squared = normal_x * normal_x +
				    normal_y * normal_y +
				    normal_z * normal_z;
		abs_value = sqrt (abs_value_squared);
		if (abs_value == 0.0)
			{
			cos_theta = 0.0;
			curr_planeSP->normal_theta[imageI] = 1.5707963;
			}
		else
			{
			cos_theta = scalar_product / abs_value;
			if (cos_theta <= -1.0) angle = 3.1415927;
			else if (cos_theta >= 1.0) angle = 0.0;
			else angle = acos (cos_theta);
			curr_planeSP->normal_theta[imageI] = angle;
			}

		/*------visible side index (0 = top, 1 = bottom):------------*/

		if (cos_theta <= 0.0) curr_planeSP->visible_sideI[imageI] = 0;
		else curr_planeSP->visible_sideI[imageI] = 1;

		/*------angle between x and project. of n. v. to xy plane:---*/

		/* Prepare and check the cosine of normal_phi: */
		abs_value = sqrt (normal_x * normal_x + normal_y * normal_y);
		cos_phi = normal_x / abs_value;
		if (cos_phi >  1.0) cos_phi =  1.0;
		if (cos_phi < -1.0) cos_phi = -1.0;

		/* The special case (undefined phi): */
		if ((normal_x == 0.0) && (normal_y == 0.0))
			{
			curr_planeSP->normal_phi[imageI] = 0.0;
			}

		/* If y component of the normal vector is positive: */
		else if (normal_y >= 0.0)
			{
			if (cos_phi <= -1.0) angle = 3.1415927;
			else if (cos_phi >= 1.0) angle = 0.0;
			else angle = acos (cos_phi);
			curr_planeSP->normal_phi[imageI] = angle;
			}

		/* If y component of the normal vector is negative: */
		else
			{
			if (cos_phi <= -1.0) angle = 3.1415927;
			else if (cos_phi >= 1.0) angle = 0.0;
			else angle = acos (cos_phi);
			curr_planeSP->normal_phi[imageI] = 6.2831853 - angle;
			}

		/*------large half axis of the ellipse in screen units:------*/

		value1 = curr_planeSP->circle_radius *
			 nominator_x *
			 reciprocal_denominator;
		value2 = curr_planeSP->circle_radius *
			 nominator_y *
			 reciprocal_denominator;
		if (value1 > value2) curr_planeSP->screen_a = value1;
		else curr_planeSP->screen_a = value2;

		/*------small half axis of the ellipse (stereo data):--------*/

		curr_planeSP->screen_b[imageI] = curr_planeSP->screen_a *
						 fabs (cos_theta);

		/* The minimal value should be one: */
		if (curr_planeSP->screen_b[imageI] < 1.0)
			curr_planeSP->screen_b[imageI] = 1.0;
		}
	}
}

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


