/*
 * $Id: vector.c,v 1.16 2004/10/14 17:35:15 stiv Exp $
 * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
 *
 * 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. The Blender
 * Foundation also sells licenses for use in proprietary software under
 * the Blender License.  See http://www.blender.org/BL/ for information
 * about this.
 *
 * 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 Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
 * All rights reserved.
 *
 * 
 * Contributor(s): Willian P. Germano & Joseph Gilbert
 *
 * ***** END GPL/BL DUAL LICENSE BLOCK *****
 */

#include "vector.h"

//doc strings
char Vector_Zero_doc[] = "() - set all values in the vector to 0";
char Vector_Normalize_doc[] = "() - normalize the vector";
char Vector_Negate_doc[] = "() - changes vector to it's additive inverse";
char Vector_Resize2D_doc[] = "() - resize a vector to [x,y]";
char Vector_Resize3D_doc[] = "() - resize a vector to [x,y,z]";
char Vector_Resize4D_doc[] = "() - resize a vector to [x,y,z,w]";

//method table
struct PyMethodDef Vector_methods[] = {
	{"zero", ( PyCFunction ) Vector_Zero, METH_NOARGS,
	 Vector_Zero_doc},
	{"normalize", ( PyCFunction ) Vector_Normalize, METH_NOARGS,
	 Vector_Normalize_doc},
	{"negate", ( PyCFunction ) Vector_Negate, METH_NOARGS,
	 Vector_Negate_doc},
	{"resize2D", ( PyCFunction ) Vector_Resize2D, METH_NOARGS,
	 Vector_Resize2D_doc},
	{"resize3D", ( PyCFunction ) Vector_Resize3D, METH_NOARGS,
	 Vector_Resize2D_doc},
	{"resize4D", ( PyCFunction ) Vector_Resize4D, METH_NOARGS,
	 Vector_Resize2D_doc},
	{NULL, NULL, 0, NULL}
};

/*****************************/
//    Vector Python Object   
/*****************************/

//object methods
PyObject *Vector_Zero( VectorObject * self )
{
	int x;
	for( x = 0; x < self->size; x++ ) {
		self->vec[x] = 0.0f;
	}

	return EXPP_incr_ret( Py_None );
}

PyObject *Vector_Normalize( VectorObject * self )
{
	float norm;
	int x;

	norm = 0.0f;
	for( x = 0; x < self->size; x++ ) {
		norm += self->vec[x] * self->vec[x];
	}
	norm = ( float ) sqrt( norm );
	for( x = 0; x < self->size; x++ ) {
		self->vec[x] /= norm;
	}

	return EXPP_incr_ret( Py_None );
}

PyObject *Vector_Negate( VectorObject * self )
{
	int x;
	for( x = 0; x < self->size; x++ ) {
		self->vec[x] = -( self->vec[x] );
	}

	return EXPP_incr_ret( Py_None );
}

PyObject *Vector_Resize2D( VectorObject * self )
{
	float x, y;

	if( self->size == 4 || self->size == 3 ) {
		x = self->vec[0];
		y = self->vec[1];
		PyMem_Free( self->vec );
		self->vec = PyMem_Malloc( 2 * sizeof( float ) );
		self->vec[0] = x;
		self->vec[1] = y;
		self->size = 2;
	}

	return EXPP_incr_ret( Py_None );
}

PyObject *Vector_Resize3D( VectorObject * self )
{
	float x, y, z;

	if( self->size == 2 ) {
		x = self->vec[0];
		y = self->vec[1];
		PyMem_Free( self->vec );
		self->vec = PyMem_Malloc( 3 * sizeof( float ) );
		self->vec[0] = x;
		self->vec[1] = y;
		self->vec[2] = 0.0f;
		self->size = 3;
	} else if( self->size == 4 ) {
		x = self->vec[0];
		y = self->vec[1];
		z = self->vec[2];
		PyMem_Free( self->vec );
		self->vec = PyMem_Malloc( 3 * sizeof( float ) );
		self->vec[0] = x;
		self->vec[1] = y;
		self->vec[2] = z;
		self->size = 3;
	}

	return EXPP_incr_ret( Py_None );
}

PyObject *Vector_Resize4D( VectorObject * self )
{
	float x, y, z;

	if( self->size == 2 ) {
		x = self->vec[0];
		y = self->vec[1];
		PyMem_Free( self->vec );
		self->vec = PyMem_Malloc( 4 * sizeof( float ) );
		self->vec[0] = x;
		self->vec[1] = y;
		self->vec[2] = 0.0f;
		self->vec[3] = 1.0f;
		self->size = 4;
	} else if( self->size == 3 ) {
		x = self->vec[0];
		y = self->vec[1];
		z = self->vec[2];
		PyMem_Free( self->vec );
		self->vec = PyMem_Malloc( 4 * sizeof( float ) );
		self->vec[0] = x;
		self->vec[1] = y;
		self->vec[2] = z;
		self->vec[3] = 1.0f;
		self->size = 4;
	}

	return EXPP_incr_ret( Py_None );
}

static void Vector_dealloc( VectorObject * self )
{
	/* if we own this memory we must delete it */
	if( self->delete_pymem )
		PyMem_Free( self->vec );

	PyObject_DEL( self );
}

static PyObject *Vector_getattr( VectorObject * self, char *name )
{
	if( self->size == 4 && ELEM4( name[0], 'x', 'y', 'z', 'w' )
	    && name[1] == 0 ) {
		if( ( name[0] ) == ( 'w' ) ) {
			return PyFloat_FromDouble( self->vec[3] );
		} else {
			return PyFloat_FromDouble( self->vec[name[0] - 'x'] );
		}
	} else if( self->size == 3 && ELEM3( name[0], 'x', 'y', 'z' )
		   && name[1] == 0 )
		return PyFloat_FromDouble( self->vec[name[0] - 'x'] );
	else if( self->size == 2 && ELEM( name[0], 'x', 'y' ) && name[1] == 0 )
		return PyFloat_FromDouble( self->vec[name[0] - 'x'] );

	if( ( strcmp( name, "length" ) == 0 ) ) {
		if( self->size == 4 ) {
			return PyFloat_FromDouble( sqrt
						   ( self->vec[0] *
						     self->vec[0] +
						     self->vec[1] *
						     self->vec[1] +
						     self->vec[2] *
						     self->vec[2] +
						     self->vec[3] *
						     self->vec[3] ) );
		} else if( self->size == 3 ) {
			return PyFloat_FromDouble( sqrt
						   ( self->vec[0] *
						     self->vec[0] +
						     self->vec[1] *
						     self->vec[1] +
						     self->vec[2] *
						     self->vec[2] ) );
		} else if( self->size == 2 ) {
			return PyFloat_FromDouble( sqrt
						   ( self->vec[0] *
						     self->vec[0] +
						     self->vec[1] *
						     self->vec[1] ) );
		} else
			return EXPP_ReturnPyObjError( PyExc_AttributeError,
						      "can only return the length of a 2D ,3D or 4D vector\n" );
	}

	return Py_FindMethod( Vector_methods, ( PyObject * ) self, name );
}

static int Vector_setattr( VectorObject * self, char *name, PyObject * v )
{
	float val;
	int valTemp;

	if( !PyFloat_Check( v ) ) {
		if( !PyInt_Check( v ) ) {
			return EXPP_ReturnIntError( PyExc_TypeError,
						    "int or float expected\n" );
		} else {
			if( !PyArg_Parse( v, "i", &valTemp ) )
				return EXPP_ReturnIntError( PyExc_TypeError,
							    "unable to parse int argument\n" );
			val = ( float ) valTemp;
		}
	} else {
		if( !PyArg_Parse( v, "f", &val ) )
			return EXPP_ReturnIntError( PyExc_TypeError,
						    "unable to parse float argument\n" );
	}
	if( self->size == 4 && ELEM4( name[0], 'x', 'y', 'z', 'w' )
	    && name[1] == 0 ) {
		if( ( name[0] ) == ( 'w' ) ) {
			self->vec[3] = val;
		} else {
			self->vec[name[0] - 'x'] = val;
		}
	} else if( self->size == 3 && ELEM3( name[0], 'x', 'y', 'z' )
		   && name[1] == 0 )
		self->vec[name[0] - 'x'] = val;
	else if( self->size == 2 && ELEM( name[0], 'x', 'y' ) && name[1] == 0 )
		self->vec[name[0] - 'x'] = val;
	else
		return -1;

	return 0;
}

/* Vectors Sequence methods */
static int Vector_len( VectorObject * self )
{
	return self->size;
}

static PyObject *Vector_item( VectorObject * self, int i )
{
	if( i < 0 || i >= self->size )
		return EXPP_ReturnPyObjError( PyExc_IndexError,
					      "array index out of range\n" );

	return Py_BuildValue( "f", self->vec[i] );

}

static PyObject *Vector_slice( VectorObject * self, int begin, int end )
{
	PyObject *list;
	int count;

	if( begin < 0 )
		begin = 0;
	if( end > self->size )
		end = self->size;
	if( begin > end )
		begin = end;

	list = PyList_New( end - begin );

	for( count = begin; count < end; count++ ) {
		PyList_SetItem( list, count - begin,
				PyFloat_FromDouble( self->vec[count] ) );
	}

	return list;
}

static int Vector_ass_item( VectorObject * self, int i, PyObject * ob )
{
	if( i < 0 || i >= self->size )
		return EXPP_ReturnIntError( PyExc_IndexError,
					    "array assignment index out of range\n" );
	if( !PyInt_Check( ob ) && !PyFloat_Check( ob ) )
		return EXPP_ReturnIntError( PyExc_IndexError,
					    "vector member must be a number\n" );

	self->vec[i] = ( float ) PyFloat_AsDouble( ob );

	return 0;
}

static int Vector_ass_slice( VectorObject * self, int begin, int end,
			     PyObject * seq )
{
	int count, z;

	if( begin < 0 )
		begin = 0;
	if( end > self->size )
		end = self->size;
	if( begin > end )
		begin = end;

	if( !PySequence_Check( seq ) )
		return EXPP_ReturnIntError( PyExc_TypeError,
					    "illegal argument type for built-in operation\n" );
	if( PySequence_Length( seq ) != ( end - begin ) )
		return EXPP_ReturnIntError( PyExc_TypeError,
					    "size mismatch in slice assignment\n" );

	z = 0;
	for( count = begin; count < end; count++ ) {
		PyObject *ob = PySequence_GetItem( seq, z );
		z++;
		if( !PyInt_Check( ob ) && !PyFloat_Check( ob ) )
			return EXPP_ReturnIntError( PyExc_IndexError,
						    "list member must be a number\n" );

		if( !PyArg_Parse( ob, "f", &self->vec[count] ) ) {
			Py_DECREF( ob );
			return -1;
		}
	}

	return 0;
}

static PyObject *Vector_repr( VectorObject * self )
{
	int i, maxindex = self->size - 1;
	char ftoa[24];
	PyObject *str1, *str2;

	str1 = PyString_FromString( "[" );

	for( i = 0; i < maxindex; i++ ) {
		sprintf( ftoa, "%.4f, ", self->vec[i] );
		str2 = PyString_FromString( ftoa );
		if( !str1 || !str2 )
			goto error;
		PyString_ConcatAndDel( &str1, str2 );
	}

	sprintf( ftoa, "%.4f]", self->vec[maxindex] );
	str2 = PyString_FromString( ftoa );
	if( !str1 || !str2 )
		goto error;
	PyString_ConcatAndDel( &str1, str2 );

	if( str1 )
		return str1;

      error:
	Py_XDECREF( str1 );
	Py_XDECREF( str2 );
	return EXPP_ReturnPyObjError( PyExc_MemoryError,
				      "couldn't create PyString!\n" );
}


PyObject *Vector_add( PyObject * v1, PyObject * v2 )
{
	float *vec;
	int x;
	PyObject *retval;

	if( ( !VectorObject_Check( v1 ) ) || ( !VectorObject_Check( v2 ) ) )
		return EXPP_ReturnPyObjError( PyExc_TypeError,
					      "unsupported type for this operation\n" );
	if( ( ( VectorObject * ) v1 )->flag != 0
	    || ( ( VectorObject * ) v2 )->flag != 0 )
		return EXPP_ReturnPyObjError( PyExc_TypeError,
					      "cannot add a scalar to a vector\n" );
	if( ( ( VectorObject * ) v1 )->size !=
	    ( ( VectorObject * ) v2 )->size )
		return EXPP_ReturnPyObjError( PyExc_AttributeError,
					      "vectors must have the same dimensions for this operation\n" );

	vec = PyMem_Malloc( ( ( ( VectorObject * ) v1 )->size ) *
			    sizeof( float ) );

	for( x = 0; x < ( ( VectorObject * ) v1 )->size; x++ ) {
		vec[x] = ( ( VectorObject * ) v1 )->vec[x] +
			( ( VectorObject * ) v2 )->vec[x];
	}

	retval = ( PyObject * ) newVectorObject( vec,
						 ( ( ( VectorObject * ) v1 )->
						   size ) );
	PyMem_Free( vec );
	return retval;
}

PyObject *Vector_sub( PyObject * v1, PyObject * v2 )
{
	float *vec;
	int x;
	PyObject *retval;

	if( ( !VectorObject_Check( v1 ) ) || ( !VectorObject_Check( v2 ) ) )
		return EXPP_ReturnPyObjError( PyExc_TypeError,
					      "unsupported type for this operation\n" );
	if( ( ( VectorObject * ) v1 )->flag != 0
	    || ( ( VectorObject * ) v2 )->flag != 0 )
		return EXPP_ReturnPyObjError( PyExc_TypeError,
					      "cannot subtract a scalar from a vector\n" );
	if( ( ( VectorObject * ) v1 )->size !=
	    ( ( VectorObject * ) v2 )->size )
		return EXPP_ReturnPyObjError( PyExc_AttributeError,
					      "vectors must have the same dimensions for this operation\n" );

	vec = PyMem_Malloc( ( ( ( VectorObject * ) v1 )->size ) *
			    sizeof( float ) );

	for( x = 0; x < ( ( VectorObject * ) v1 )->size; x++ ) {
		vec[x] = ( ( VectorObject * ) v1 )->vec[x] -
			( ( VectorObject * ) v2 )->vec[x];
	}

	retval = ( PyObject * ) newVectorObject( vec,
						 ( ( ( VectorObject * ) v1 )->
						   size ) );
	PyMem_Free( vec );
	return retval;
}

PyObject *Vector_mul( PyObject * v1, PyObject * v2 )
{
	float *vec;
	int x;
	PyObject *retval;

	if( ( !VectorObject_Check( v1 ) ) || ( !VectorObject_Check( v2 ) ) )
		return EXPP_ReturnPyObjError( PyExc_TypeError,
					      "unsupported type for this operation\n" );
	if( ( ( VectorObject * ) v1 )->flag == 0
	    && ( ( VectorObject * ) v2 )->flag == 0 )
		return EXPP_ReturnPyObjError( PyExc_ArithmeticError,
					      "please use the dot product or the cross product to multiply vectors\n" );
	if( ( ( VectorObject * ) v1 )->size !=
	    ( ( VectorObject * ) v2 )->size )
		return EXPP_ReturnPyObjError( PyExc_AttributeError,
					      "vector dimension error during Vector_mul\n" );

	vec = PyMem_Malloc( ( ( ( VectorObject * ) v1 )->size ) *
			    sizeof( float ) );

	for( x = 0; x < ( ( VectorObject * ) v1 )->size; x++ ) {
		vec[x] = ( ( VectorObject * ) v1 )->vec[x] *
			( ( VectorObject * ) v2 )->vec[x];
	}

	retval =  ( PyObject * ) newVectorObject( vec,
						  ( ( ( VectorObject * ) v1 )->
						    size ) );
	PyMem_Free( vec );
	return retval;
}

PyObject *Vector_div( PyObject * v1, PyObject * v2 )
{
	float *vec;
	int x;
	PyObject *retval;

	if( ( !VectorObject_Check( v1 ) ) || ( !VectorObject_Check( v2 ) ) )
		return EXPP_ReturnPyObjError( PyExc_TypeError,
					      "unsupported type for this operation\n" );
	if( ( ( VectorObject * ) v1 )->flag == 0
	    && ( ( VectorObject * ) v2 )->flag == 0 )
		return EXPP_ReturnPyObjError( PyExc_ArithmeticError,
					      "cannot divide two vectors\n" );
	if( ( ( VectorObject * ) v1 )->flag != 0
	    && ( ( VectorObject * ) v2 )->flag == 0 )
		return EXPP_ReturnPyObjError( PyExc_TypeError,
					      "cannot divide a scalar by a vector\n" );
	if( ( ( VectorObject * ) v1 )->size !=
	    ( ( VectorObject * ) v2 )->size )
		return EXPP_ReturnPyObjError( PyExc_AttributeError,
					      "vector dimension error during Vector_mul\n" );

	vec = PyMem_Malloc( ( ( ( VectorObject * ) v1 )->size ) *
			    sizeof( float ) );

	for( x = 0; x < ( ( VectorObject * ) v1 )->size; x++ ) {
		vec[x] = ( ( VectorObject * ) v1 )->vec[x] /
			( ( VectorObject * ) v2 )->vec[x];
	}

	retval =  ( PyObject * ) newVectorObject( vec,
						  ( ( ( VectorObject * ) v1 )->
						    size ) );
	PyMem_Free( vec );
	return retval;
}

//coercion of unknown types to type VectorObject for numeric protocols
int Vector_coerce( PyObject ** v1, PyObject ** v2 )
{
	long *tempI;
	double *tempF;
	float *vec;
	int x;

	if( VectorObject_Check( *v1 ) ) {
		if( VectorObject_Check( *v2 ) ) {	//two vectors
			Py_INCREF( *v1 );  /* fixme:  wahy are we bumping the ref count? */
			Py_INCREF( *v2 );
			return 0;
		} else {
			if( Matrix_CheckPyObject( *v2 ) ) {
				printf( "vector/matrix numeric protocols unsupported...\n" );
				Py_INCREF( *v1 );
				return 0;	//operation will type check
			} else if( PyNumber_Check( *v2 ) ) {
				if( PyInt_Check( *v2 ) ) {	//cast scalar to vector
					tempI = PyMem_Malloc( 1 *
							      sizeof( long ) );
					*tempI = PyInt_AsLong( *v2 );
					vec = PyMem_Malloc( ( ( ( VectorObject
								  * ) *
								v1 )->size ) *
							    sizeof( float ) );
					for( x = 0;
					     x <  ( ( ( VectorObject * ) * v1 )->size );
					     x++ ) {
						vec[x] = ( float ) *tempI;
					}
					PyMem_Free( tempI );
					*v2 = newVectorObject( vec,
							       ( ( ( VectorObject * ) * v1 )->size ) );
					( ( VectorObject * ) * v2 )->flag = 1;	//int coercion
					Py_INCREF( *v1 );
					return 0;
				} else if( PyFloat_Check( *v2 ) ) {	//cast scalar to vector
					tempF = PyMem_Malloc( 1 *
							      sizeof
							      ( double ) );
					*tempF = PyFloat_AsDouble( *v2 );
					vec = PyMem_Malloc( ( ( ( VectorObject
								  * ) *
								v1 )->size ) *
							    sizeof( float ) );
					for( x = 0;
					     x <
					     ( ( ( VectorObject * ) *
						 v1 )->size ); x++ ) {
						vec[x] = ( float ) *tempF;
					}
					PyMem_Free( tempF );
					*v2 = newVectorObject( vec,
							       ( ( ( VectorObject * ) * v1 )->size ) );
					( ( VectorObject * ) * v2 )->flag = 2;	//float coercion
					Py_INCREF( *v1 );
					return 0;
				}
			}
			//unknown type or numeric cast failure
			printf( "attempting vector operation with unsupported type...\n" );
			Py_INCREF( *v1 );
			return 0;	//operation will type check
		}
	} else {
		printf( "numeric protocol failure...\n" );
		return -1;	//this should not occur - fail
	}
	return -1;
}


static PySequenceMethods Vector_SeqMethods = {
	( inquiry ) Vector_len,	/* sq_length */
	( binaryfunc ) 0,	/* sq_concat */
	( intargfunc ) 0,	/* sq_repeat */
	( intargfunc ) Vector_item,	/* sq_item */
	( intintargfunc ) Vector_slice,	/* sq_slice */
	( intobjargproc ) Vector_ass_item,	/* sq_ass_item */
	( intintobjargproc ) Vector_ass_slice,	/* sq_ass_slice */
};

static PyNumberMethods Vector_NumMethods = {
	( binaryfunc ) Vector_add,	/* __add__ */
	( binaryfunc ) Vector_sub,	/* __sub__ */
	( binaryfunc ) Vector_mul,	/* __mul__ */
	( binaryfunc ) Vector_div,	/* __div__ */
	( binaryfunc ) 0,	/* __mod__ */
	( binaryfunc ) 0,	/* __divmod__ */
	( ternaryfunc ) 0,	/* __pow__ */
	( unaryfunc ) 0,	/* __neg__ */
	( unaryfunc ) 0,	/* __pos__ */
	( unaryfunc ) 0,	/* __abs__ */
	( inquiry ) 0,		/* __nonzero__ */
	( unaryfunc ) 0,	/* __invert__ */
	( binaryfunc ) 0,	/* __lshift__ */
	( binaryfunc ) 0,	/* __rshift__ */
	( binaryfunc ) 0,	/* __and__ */
	( binaryfunc ) 0,	/* __xor__ */
	( binaryfunc ) 0,	/* __or__ */
	( coercion ) Vector_coerce,	/* __coerce__ */
	( unaryfunc ) 0,	/* __int__ */
	( unaryfunc ) 0,	/* __long__ */
	( unaryfunc ) 0,	/* __float__ */
	( unaryfunc ) 0,	/* __oct__ */
	( unaryfunc ) 0,	/* __hex__ */

};

PyTypeObject vector_Type = {
	PyObject_HEAD_INIT( NULL ) 0,	/*ob_size */
	"vector",		/*tp_name */
	sizeof( VectorObject ),	/*tp_basicsize */
	0,			/*tp_itemsize */
	( destructor ) Vector_dealloc,	/*tp_dealloc */
	( printfunc ) 0,	/*tp_print */
	( getattrfunc ) Vector_getattr,	/*tp_getattr */
	( setattrfunc ) Vector_setattr,	/*tp_setattr */
	0,			/*tp_compare */
	( reprfunc ) Vector_repr,	/*tp_repr */
	&Vector_NumMethods,	/*tp_as_number */
	&Vector_SeqMethods,	/*tp_as_sequence */
};


/* 
 * create a Vector Object( vec, size )
 *
 *  Note: Vector now  uses copy semantics like STL containers.
 *   Memory for vec member is allocated on python stack.  
 *   We own this memory and will free it later. 
 *  
 * size arg is number of floats to alloc.
 *
 * if vec arg is NULL
 *   fill our vec with zeros
 *   initialize 4d vectors to zero in homogenous coords.
 * else
 *   vec param is copied into our local memory and always freed.
 */

PyObject *newVectorObject( float *vec, int size )
{
	VectorObject *self;
	int x;

	vector_Type.ob_type = &PyType_Type;

	self = PyObject_NEW( VectorObject, &vector_Type );

	self->vec = PyMem_Malloc( size * sizeof( float ) );
	self->delete_pymem = 1;	/* must free this alloc later */

	if( !vec ) {
		for( x = 0; x < size; x++ ) {
			self->vec[x] = 0.0f;
		}
		if( size == 4 )  /* do the homogenous thing */
			self->vec[3] = 1.0f;
	} else {
		for( x = 0; x < size; x++ ){
			self->vec[x] = vec[x];
		}
	}

	self->size = size;
	self->flag = 0;

	return ( PyObject * ) self;
}


/*
  create a Vector that is a proxy for blender data.
  we do not own this data, we NEVER free it.
  Note: users must deal with bad pointer issue
*/

PyObject *newVectorProxy( float *vec, int size)
{
	VectorObject *proxy;
	int x;

	proxy = PyObject_NEW( VectorObject, &vector_Type );

	proxy->delete_pymem = 0;	/* must NOT free this alloc later */

	if( !vec || size < 1 ) {
		return EXPP_ReturnPyObjError( PyExc_AttributeError,
				       "cannot creat zero length vector proxy" );
	}
		
	proxy->vec = vec;
	proxy->size = size;
	proxy->flag = 0;

	return ( PyObject * ) proxy;
}
	
