from ctypes import c_char_p, c_bool, c_int, c_double,\
c_char, c_void_p, sizeof, \
Array, create_string_buffer, cast, Structure, \
string_at
import numpy
import six
from numpy import ctypeslib as numpc
# Collection of supporting functions for wrapper functions
__author__ = 'AndrewAnnex'
errorformat = """
================================================================================
Toolkit version: {tkvsn}
{short} --
{explain}
{long}
{traceback}
================================================================================\
"""
[docs]class SpiceyError(Exception):
"""
SpiceyError wraps CSPICE errors.
:type value: str
"""
def __init__(self, value):
self.value = value
def __str__(self):
return self.value
[docs]def toDoubleVector(x):
return DoubleArray.from_param(param=x)
[docs]def toDoubleMatrix(x):
return DoubleMatrix.from_param(param=x)
[docs]def toIntVector(x):
return IntArray.from_param(param=x)
[docs]def toBoolVector(x):
return BoolArray.from_param(param=x)
[docs]def toPythonString(inString):
if six.PY2:
if isinstance(inString, c_char_p):
return toPythonString(inString.value)
return string_at(inString)
elif six.PY3:
if isinstance(inString, c_char_p):
return toPythonString(inString.value)
return bytes.decode(string_at(inString))
[docs]def listtocharvector(x):
assert (isinstance(x, list))
return (c_char_p * len(x))(*[stringToCharP(y) for y in x])
[docs]def charvector(ndim=1, lenvals=10):
return ((c_char * lenvals) * ndim)()
[docs]def listtodoublematrix(data, x=3, y=3):
matrix = ((c_double * x) * y)()
for i, row in enumerate(data):
matrix[i] = tuple(row)
return matrix
[docs]def emptyCharArray(xLen=None, yLen=None):
if not yLen:
yLen = 1
if not xLen:
xLen = 1
if isinstance(xLen, c_int):
xLen = xLen.value
if isinstance(yLen, c_int):
yLen = yLen.value
return ((c_char * xLen) * yLen)()
[docs]def emptyDoubleMatrix(x=3, y=3):
return ((c_double * x) * y)()
[docs]def emptyDoubleVector(n):
if isinstance(n, c_int):
n = n.value
assert(isinstance(n, int))
return (c_double * n)()
[docs]def emptyIntVector(n):
if isinstance(n, c_int):
n = n.value
assert (isinstance(n, int))
return (c_int * n)()
[docs]def vectorToList(x):
if isinstance(x[0], bool):
return numpy.fromiter(x, numpy.bool, count=len(x))
elif isinstance(x[0], int):
return numpy.fromiter(x, numpy.int_, count=len(x))
elif isinstance(x[0], float):
return numpy.fromiter(x, numpy.float64, count=len(x))
elif isinstance(x[0].value, bytes):
return [toPythonString(y) for y in x]
[docs]def matrixToList(x):
return numpc.as_array(x)
[docs]def stringToCharP(inobject, inlen=None):
"""
:param inobject: input string, int for getting null string of length of int
:param inlen: optional parameter, length of a given string can be specified
:return:
"""
if inlen and isinstance(inobject, str):
return create_string_buffer(inobject.encode(encoding='UTF-8'), inlen)
if isinstance(inobject, bytes):
return inobject
if isinstance(inobject, c_int):
return stringToCharP(" " * inobject.value)
if isinstance(inobject, int):
return stringToCharP(" " * inobject)
return c_char_p(inobject.encode(encoding='UTF-8'))
[docs]def listToCharArray(inList, xLen=None, yLen=None):
assert (isinstance(inList, list))
if not yLen:
yLen = len(inList)
if not xLen:
xLen = max(len(s) for s in inList) + 1
if isinstance(xLen, c_int):
xLen = xLen.value
if isinstance(yLen, c_int):
yLen = yLen.value
return ((c_char * xLen) * yLen)(*[stringToCharP(l, inlen=xLen) for l in inList])
[docs]def listToCharArrayPtr(inList, xLen=None, yLen=None):
assert (isinstance(inList, list))
if not yLen:
yLen = len(inList)
if not xLen:
xLen = max(len(s) for s in inList) + 1
if isinstance(xLen, c_int):
xLen = xLen.value
if isinstance(yLen, c_int):
yLen = yLen.value
return cast(((c_char * xLen) * yLen)(*[stringToCharP(l, inlen=xLen) for l in inList]), c_char_p)
[docs]class DoubleArrayType:
# Class type that will handle all double vectors,
# inspiration from python cookbook 3rd edition
[docs] def from_param(self, param):
typename = type(param).__name__
if hasattr(self, 'from_' + typename):
return getattr(self, 'from_' + typename)(param)
elif isinstance(param, Array):
return param
else:
raise TypeError("Can't convert %s" % typename)
# Cast from lists/tuples
[docs] def from_list(self, param):
val = ((c_double) * len(param))(*param)
return val
# Cast from Tuple
[docs] def from_tuple(self, param):
val = ((c_double) * len(param))(*param)
return val
# Cast from a numpy array,
[docs] def from_ndarray(self, param):
# return param.data_as(POINTER(c_double))
# the above older method does not work with
# functions which take vectors of known size
return numpy.ctypeslib.as_ctypes(param)
# Cast from array.array objects
[docs] def from_array(self, param):
if param.typecode != 'd':
raise TypeError('must be an array of doubles')
return self.from_list(param)
[docs]class DoubleMatrixType:
# Class type that will handle all double matricies,
# inspiration from python cookbook 3rd edition
[docs] def from_param(self, param):
typename = type(param).__name__
if hasattr(self, 'from_' + typename):
return getattr(self, 'from_' + typename)(param)
elif isinstance(param, Array):
return param
else:
raise TypeError("Can't convert %s" % typename)
# Cast from lists/tuples
[docs] def from_list(self, param):
val = ((c_double * len(param[0])) * len(param))(*[DoubleArray.from_param(x) for x in param])
return val
# Cast from Tuple
[docs] def from_tuple(self, param):
val = ((c_double * len(param[0])) * len(param))(*[DoubleArray.from_param(x) for x in param])
return val
# Cast from a numpy array
[docs] def from_ndarray(self, param):
# return param.data_as(POINTER(c_double))
return numpy.ctypeslib.as_ctypes(param)
# Cast from a numpy matrix
[docs] def from_matrix(self, param):
# return param.data_as(POINTER(c_double))
return numpy.ctypeslib.as_ctypes(param)
[docs]class IntArrayType:
# Class type that will handle all int vectors,
# inspiration from python cookbook 3rd edition
[docs] def from_param(self, param):
typename = type(param).__name__
if hasattr(self, 'from_' + typename):
return getattr(self, 'from_' + typename)(param)
elif isinstance(param, Array):
return param
else:
raise TypeError("Can't convert %s" % typename)
# Cast from lists/tuples
[docs] def from_list(self, param):
val = ((c_int) * len(param))(*param)
return val
# Cast from Tuple
[docs] def from_tuple(self, param):
val = ((c_int) * len(param))(*param)
return val
# Cast from a numpy array
[docs] def from_ndarray(self, param):
# return param.data_as(POINTER(c_int))
# not sure if long is same as int, it should be..
# return numpy.ctypeslib.as_ctypes(param)
return self.from_param(param.tolist())
# Cast from array.array objects
[docs] def from_array(self, param):
if param.typecode != 'i':
raise TypeError('must be an array of ints')
return self.from_list(param)
[docs]class BoolArrayType:
# Class type that will handle all int vectors,
# inspiration from python cookbook 3rd edition
[docs] def from_param(self, param):
typename = type(param).__name__
if hasattr(self, 'from_' + typename):
return getattr(self, 'from_' + typename)(param)
elif isinstance(param, Array):
return param
else:
raise TypeError("Can't convert %s" % typename)
# Cast from lists/tuples
[docs] def from_list(self, param):
val = ((c_bool) * len(param))(*param)
return val
# Cast from Tuple
[docs] def from_tuple(self, param):
val = ((c_bool) * len(param))(*param)
return val
# Cast from a numpy array
[docs] def from_ndarray(self, param):
# return param.data_as(POINTER(c_int))
# not sure if long is same as int, it should be..
# return numpy.ctypeslib.as_ctypes(param)
return self.from_param(param.tolist())
DoubleArray = DoubleArrayType()
IntArray = IntArrayType()
BoolArray = BoolArrayType()
DoubleMatrix = DoubleMatrixType()
[docs]class Plane(Structure):
_fields_ = [
('_normal', c_double * 3),
('_constant', c_double)
]
@property
def normal(self):
return vectorToList(self._normal)
@property
def constant(self):
return self._constant
def __str__(self):
return '<SpicePlane: normal=%s; constant=%s>' % (', '.join([str(x) for x in self._normal]), self._constant)
[docs]class Ellipse(Structure):
_fields_ = [
('_center', c_double * 3),
('_semi_major', c_double * 3),
('_semi_minor', c_double * 3)
]
@property
def center(self):
return vectorToList(self._center)
@property
def semi_major(self):
return vectorToList(self._semi_major)
@property
def semi_minor(self):
return vectorToList(self._semi_minor)
def __str__(self):
return '<SpiceEllipse: center = %s, semi_major = %s, semi_minor = %s>' % \
(self.center, self.semi_major, self.semi_minor)
[docs]class DataType(object):
SPICE_CHR = 0
SPICE_DP = 1
SPICE_INT = 2
SPICE_TIME = 3
SPICE_BOOL = 4
CHR = 0
DP = 1
INT = 2
TIME = 3
BOOL = 4
def __init__(self):
pass
[docs]class SpiceEKDataType(c_int):
_fields_ = [
('SPICE_CHR', c_int(0)),
('SPICE_DP', c_int(1)),
('SPICE_INT', c_int(2)),
('SPICE_TIME', c_int(3)),
('SPICE_BOOL', c_int(4)),
]
[docs]class SpiceEKExprClass(c_int):
_fields_ = [
('SPICE_EK_EXP_COL', c_int(0)),
('SPICE_EK_EXP_FUNC', c_int(1)),
('SPICE_EK_EXP_EXPR', c_int(2))
]
[docs]class SpiceEKAttDsc(Structure):
_fields_ = [
('_cclass', c_int),
('_dtype', SpiceEKDataType),
('_strlen', c_int),
('_size', c_int),
('_indexd', c_bool),
('_nullok', c_bool)
]
@property
def cclass(self):
return self._cclass
@property
def dtype(self):
return self._dtype.value
@property
def strlen(self):
return self._strlen
@property
def size(self):
return self._size
@property
def indexd(self):
return self._indexd
@property
def nullok(self):
return self._nullok
def __str__(self):
return '<SpiceEKAttDsc cclass = %s, dtype = %s, strlen = %s, size = %s, indexd = %s, nullok = %s >' % \
(self.cclass, self.dtype, self.strlen, self.size, self.indexd, self.nullok)
[docs]class SpiceEKSegSum(Structure):
_fields_ = [
('_tabnam', c_char * 65),
('_nrows', c_int),
('_ncols', c_int),
('_cnames', (c_char * 100) * 33),
('_cdescrs', SpiceEKAttDsc * 100)
]
@property
def tabnam(self):
return toPythonString(self._tabnam)
@property
def nrows(self):
return self._nrows
@property
def ncols(self):
return self._ncols
@property
def cnames(self):
return vectorToList(self._cnames)[0:self.ncols]
@property
def cdescrs(self):
return self._cdescrs[0:self.ncols]
def __str__(self):
return '<SpiceEKSegSum tabnam = %s, nrows = %s, ncols = %s, cnames = %s, cdescrs = %s >' % (self.tabnam, self.nrows, self.ncols, self.cnames, self.cdescrs)
# SpiceCell implementation below is inpart from github.com/DaRasch/spiceminer/
# and modified as needed for this author, maybe we should work together?
### helper classes/functions ###
BITSIZE = {'char': sizeof(c_char), 'int': sizeof(c_int), 'double': sizeof(c_double)}
def _char_getter(data_p, index, length):
return toPythonString((c_char * length).from_address(data_p + index * length * BITSIZE['char']))
def _double_getter(data_p, index, length):
return c_double.from_address(data_p + index * BITSIZE['double']).value
def _int_getter(data_p, index, length):
return c_int.from_address(data_p + index * BITSIZE['int']).value
[docs]def SPICEDOUBLE_CELL(size):
return SpiceCell.double(size)
[docs]def SPICEINT_CELL(size):
return SpiceCell.integer(size)
[docs]def SPICECHAR_CELL(size, length):
return SpiceCell.character(size, length)
[docs]class SpiceCell(Structure):
#Most written by DaRasch
DATATYPES_ENUM = {'char': 0, 'double': 1, 'int': 2, 'time': 3, 'bool': 4}
DATATYPES_GET = [_char_getter, _double_getter] + [_int_getter] * 3
baseSize = 6
minCharLen = 6
CTRLBLOCK = 6
_fields_ = [
('dtype', c_int),
('length', c_int),
('size', c_int),
('card', c_int),
('isSet', c_int),
('adjust', c_int),
('init', c_int),
('base', c_void_p),
('data', c_void_p)
]
def __init__(self, dtype=None, length=None, size=None, card=None, isSet=None, base=None, data=None):
super(SpiceCell, self).__init__()
self.dtype = dtype
self.length = length
self.size = size
self.card = card
self.isSet = isSet
self.adjust = 0 # Always False, because not implemented
self.init = 0 # Always False, because this is the constructor
self.base = base # void pointer
self.data = data
def __str__(self):
return '<SpiceCell dtype = %s, length = %s, size = %s, card = %s,' \
' isSet = %s, adjust = %s, init = %s, base = %s, data = %s>' % \
(self.dtype, self.length, self.size, self.card, self.isSet,
self.adjust, self.init, self.base, self.data)
[docs] def is_int(self):
return self.dtype == 2
[docs] def is_double(self):
return self.dtype == 1
[docs] def is_char(self):
return self.dtype == 0
[docs] def is_time(self):
return self.dtype == 3
[docs] def is_bool(self):
return self.dtype == 4
[docs] def is_set(self):
return self.isSet == 1
@classmethod
[docs] def character(cls, size, length):
base = (c_char * ((cls.CTRLBLOCK + size) * length))()
data = (c_char * (size * length)).from_buffer(
base, cls.CTRLBLOCK * BITSIZE['char'] * length)
instance = cls(cls.DATATYPES_ENUM['char'], length, size, 0, 1,
cast(base, c_void_p),
cast(data, c_void_p))
return instance
@classmethod
[docs] def integer(cls, size):
base = (c_int * (cls.CTRLBLOCK + size))()
data = (c_int * size).from_buffer(
base, cls.CTRLBLOCK * BITSIZE['int'])
instance = cls(cls.DATATYPES_ENUM['int'], 0, size, 0, 1,
cast(base, c_void_p),
cast(data, c_void_p))
return instance
@classmethod
[docs] def double(cls, size):
base = (c_double * (cls.CTRLBLOCK + size))()
data = (c_double * size).from_buffer(
base, cls.CTRLBLOCK * BITSIZE['double'])
instance = cls(cls.DATATYPES_ENUM['double'], 0, size, 0, 1,
cast(base, c_void_p),
cast(data, c_void_p))
return instance
def __len__(self):
return self.card
def __iter__(self):
getter = SpiceCell.DATATYPES_GET[self.dtype]
length, card, data = self.length, self.card, self.data
for i in range(card):
yield (getter(data, i, length))
def __contains__(self, key):
return key in self.__iter__()
def __getitem__(self, key):
getter = SpiceCell.DATATYPES_GET[self.dtype]
if isinstance(key, slice):
#TODO Typechecking
if self.card == 0:
return []
else:
start, stop, step = key.indices(self.card)
return [getter(self.data, i, self.length) for i in range(start, stop, step)]
elif key in range(-self.card, self.card):
index = key if key >= 0 else self.card - abs(key)
return getter(self.data, index, self.length)
elif not isinstance(key, int):
raise TypeError('SpiceCell indices must be integers, not {}'.format(type(key)))
else:
raise IndexError('SpiceCell index out of range')
[docs] def reset(self):
self.card = 0
self.init = 0