APPENDIX
1
A shadow class in Python is really a Python class. It calls various C++ functions generated by SWIG, which in turn call the original C++ functions. A template class such as mac::vector3D<T> needs to be slightly modified before using SWIG. This appendix shows some examples on how to modify the original C++ code and to instruct SWIG by writing the interface file.
As described above, the first step is to copy the source code in C++ to another place, and make necessary changes. It is still hard to write the C++ code directly compatible with SWIG. These changes include the following.
Nested class definition must be removed or commented out before using SWIG, since it is not supported.
The order of overloaded functions and operators may be sorted such that the one will appear in Python is the first one. The later ones will be ignored. If they are not sorted, explicit instruction is needed in the interface file in order to ignore some overloaded functions and operators. If overloaded functions and operators are desired in Python, some of them must be renamed in the interface file. See below for more.
Unbounded non-member functions should be removed. If they are really needed, they should reside in a separate function module. I have not found a way to merge functions with classes in one module.
Additional member functions specific to Python shadow class may be included, such as __str__, __repr__, etc.
It may be desirable to merge the .c++ file into the header file, but if the .c++ file is too long, it can be included at the end of the header file by using #include, and still kept as a separate file. Other unnecessary bits can be removed in order to make the SWIG interface file and output log cleaner.
The following listing is the modified vector3D.h.
#ifndef CPL_MAC_VECTOR3D_H
#define CPL_MAC_VECTOR3D_H
#include <iostream.h>
#include
<strstream.h>
#include
<fstream.h>
#include
<algo.h>
#include
<complex.h>
#include
<float.h>
#include
"utility.h"
#include
"matrix3D.h"
namespace
mac
{
template
<class T>
class
vector3D
{
friend ostream
&operator<<(ostream& out, const vector3D<T>& v)
{out << v.getX() << "," << v.getY() <<
"," << v.getZ();
return out;}
public:
vector3D(const T
u = 0, const T v = 0, const T w = 0)
: x(u), y(v), z(w) {}
vector3D(const
vector3D<T>& v) : x(v.x), y(v.y), z(v.z) {}
~vector3D() {}
// Conversion
// operator vector3() const
{return vector3(x, y, z);}
// operator
vector3D<double>() const {return vector3D<double>(x, y, z);}
// operator
vector3D<int> () const
// {return
vector3D<int>(int(x), int(y), int(z));}
vector3D<int> nearest() const
{return vector3D<int>(mac::nearest(x),
mac::nearest(y),
mac::nearest(z));}
// Output
// void write(ofstream* f)
const {if (f) *f << *this << endl;}
// void write(const char* =
message::typeGeneral) const;
#ifdef
SWIG
%extend
{char *__str__()
{ostrstream line;
line << "<" << self->getX() << "
"
<< self->getY() << " "
<<
self->getZ() << ">" << ends;
return line.str();}}
#endif
// Element access
inline T operator()(const int i) const
{switch (i) {case 1: return x; case 2: return y; case 3: return z;
default: assert (0);}
return x;} // This will never happen.
inline T&
operator()(const int i) // 1-offset, i = 1 - 3
{switch (i) {case 1: return x; case 2: return y; case 3: return z;
default: assert (0);}
return x;}
// This will never happen.
inline T operator[](const int i) const {return
(*this)(i + 1);}
// 0-offset, i = 0 - 2
inline T&
operator[](const int i) {return
(*this)(i + 1);}
T getX() const
{return x;}
T getY() const {return y;}
T getZ() const
{return z;}
// Assignment
const
vector3D<T> &operator=(const vector3D<T>& v)
{if (&v != this) {x = v.x; y = v.y; z = v.z;} return *this;}
// Addition/subtraction
vector3D<T> operator+=(const vector3D<T>& v)
{x += v.x; y += v.y; z += v.z; return *this;}
vector3D<T> operator-=(const vector3D<T>& v)
{x -= v.x; y -= v.y; z -= v.z; return *this;}
vector3D<T> operator+(const vector3D<T>& v) const
{vector3D<T> u = *this; return u += v;}
vector3D<T> operator-(const vector3D<T>& v) const
{vector3D<T> u = *this; return u -= v;}
vector3D<T> operator+() const {return *this;}
vector3D<T> operator-() const {return vector3D<T>(0, 0, 0) -
*this;}
// Pre-multiplication
vector3D<T> operator*=(const mac::matrix3D<T>& m)
{vector3D<T> v = *this;
x = m(1, 1) * v.x + m(1, 2) * v.y + m(1, 3) * v.z;
y = m(2, 1) * v.x + m(2, 2) * v.y + m(2, 3) * v.z;
z = m(3, 1)
* v.x + m(3, 2) * v.y + m(3, 3) * v.z;
return *this;}
vector3D<T> operator/=(const mac::matrix3D<T>& m)
{mac::matrix3D<T> n = m; n.inverse(); return *this *= n;}
vector3D<T> operator*(const mac::matrix3D<T>& m) const
// Caution: This operator means matrix3D<T> * vector3D<T>,
returns a
//
vector3D<T>.
{vector3D<T> v = *this; return v *= m;}
// Scaling
vector3D<T> operator*=(const T a)
// isotropic scaling
{x *= a; y *= a; z *= a; return *this;}
vector3D<T> operator/=(const T a)
// isotropic scaling
{x /= a; y /= a; z /= a; return *this;}
vector3D<T> operator*=(const vector3D<T>& v)
{x *= v.x; y *= v.y; z *= v.z; return *this;} // anisotropic scaling
vector3D<T> operator/=(const vector3D<T>& v)
{assert (v.x && v.y && v.z);
x /= v.x; y /= v.y; z /= v.z;
return *this;}
// anisotropic scaling
vector3D<T> operator*(const T a)
const // isotropic scaling
{vector3D<T> v = *this; return v *= a;}
vector3D<T> operator/(const T a)
const // isotropic scaling
{vector3D<T> v = *this; return v /= a;}
vector3D<T> operator/(const vector3D<T>& v) const // anisotropic scaling
{vector3D<T> u = *this; return u /= v;}
// Cross (vector) multiplication
static
vector3D<T> cross(const vector3D<T>& u, const
vector3D<T>& v)
{return vector3D<T>(u.y * v.z - u.z * v.y,
u.z * v.x - u.x * v.z,
u.x * v.y - u.y * v.x);}
vector3D<T> cross(const vector3D<T> &v) const {return
cross(*this, v);}
vector3D<T> operator->*(const vector3D<T> &v) const
{return cross(v);}
// Dot (scalar) multiplication
static T
dot(const vector3D<T> &u, const vector3D<T> &v)
{return u.x * v.x + u.y * v.y + u.z * v.z;}
T dot(const
vector3D<T> &v) const {return dot(*this, v);}
T
operator*(const vector3D<T> &v) const {return dot(v);}
// Length
static double
vabs(const T x, const T y, const T z)
{return sqrt(double(x * x + y * y + z * z));}
static double
vabs(const vector3D<T> &v) {return vabs(v.x, v.y, v.z);}
double vabs()
const {return vabs(*this);}
static T
vnorm(const T x, const T y, const T z)
{return vnorm(vector3D<T>(x, y, z));}
static T
vnorm(const vector3D<T> &v)
{return v.x * v.x + v.y * v.y + v.z * v.z;}
T vnorm() const
{return vnorm(*this);}
static bool
shorterThan(const vector3D<T>& u, const vector3D<T>& v)
{const T un = u.vnorm();
const T vn = v.vnorm();
if (un == vn) return u <
v;
else
return un < vn;}
bool
shorterThan(const vector3D<T> &v) const
{return shorterThan(*this, v);}
// class shorter
// {
// public:
// bool
operator()(const vector3D<T>& u, const vector3D<T>& v)
const
//
{return shorterThan(u, v);}
// };
// Comparison
bool operator!()
const {return *this == vector3D<T>(0, 0, 0);}
bool
operator==(const vector3D<T> &v) const
{return x == v.getX() && y == v.getY() && z ==
v.getZ();}
bool
operator!=(const vector3D<T> &v) const
{return x != v.getX() || y != v.getY() || z != v.getZ();}
bool
operator&=(const vector3D<T> &v) const // approximately equal
{return vnorm(*this - v) < 10 * FLT_EPSILON;}
bool
operator> (const vector3D<T> &v) const
{return !(*this < v) && !(*this == v);}
bool
operator< (const vector3D<T> &v) const
{return lessThan(*this, v);}
bool
operator>=(const vector3D<T> &v) const
{return *this > v || *this == v;}
bool
operator<=(const vector3D<T> &v) const
{return *this < v || *this == v;}
static bool
lessThan(const vector3D<T>& u, const vector3D<T>& v)
{if (u.x == v.x)
if (u.y == v.y) return u.z < v.z;
else
return u.y < v.y;
else
return u.x < v.x;}
// class less
// {
// public:
//
bool operator()(const vector3D<T>& u, const
vector3D<T>& v) const
//
{return lessThan(u, v);}
// };
// Projection
double
projectionOn(const vector3D<T>& v) const
{assert (!!v); return dot(v) / v.vabs();}
// Projection of *this on v.
complex<double> projectionOn(const vector3D<T>& u, const
vector3D<T>& v)
const {return complex<double>(projectionOn(u), projectionOn(v));}
// Projection of *this on u and v.
vector3D<double> projectionOn(const vector3D<T>& u,
const vector3D<T>& v,
const vector3D<T>& w) const
{return vector3D<double>(projectionOn(u),
projectionOn(v),
projectionOn(w));}
// Projection of *this on u, v, and w.
double
projectionOf(const vector3D<T>& v) const
{assert (!!*this); return dot(v) / vabs();}
// Projection of v on *this.
static double
projection(const vector3D<T>& u, const vector3D<T>& v)
{assert (!!v); return u * v / v.vabs();} // Projection of u on v.
static T
projectionSq(const vector3D<T>& u, const vector3D<T>& v)
{assert (!!v);
const T d = u * v;
const T p = d * d / v.vnorm();
return d >= 0 ? p : -p;}
// The squared projection of u on v. Do not use with T being any
// integer type.
// Orientation
vector3D<double> vcos() const
{assert (!!*this); const double r = vabs();
return r ? vector3D<double>(x, y, z) / r :
vector3D<double>(0, 0, 0);}
//return r ? *this / r : vector3D<double>(0, 0, 0);}
vector3D<double> vsin() const
{const vector3D<double> a = orientationAngle();
return vector3D<double>(sin(a.getX()),
sin(a.getY()),
sin(a.getZ()));}
vector3D<double> vtan() const
{const vector3D<double> a = orientationAngle();
return vector3D<double>(tan(a.getX()),
tan(a.getY()),
tan(a.getZ()));}
vector3D<double> orientationAngle() const
{const vector3D<double> c = vcos();
return vector3D<double>(acos(c.getX()),
acos(c.getY()),
acos(c.getZ()));}
complex<double>
polarAngle() const
// Polar angles psi and phi define an orientation. In a orthogonal
// coordinate system, rotating Y-axis around Z-axis by psi according
// to the left-hand rule, followed by a rotation of the new Y-axis
// around the old Y-axis by phi according to the right-hand rule, the
// resulting Y-axis is the orientation defined by polar angles psi
// and phi (Z. Ren, Thesis, Academia Sinica, Beijing, China, 1990).
{const
vector3D<double> c = vcos();
const double psi = acos(c.getY());
// 0 <= psi <= pi, therefore sin(psi) >= 0.
double phi; // 0 <= phi <= pi, so the return phi is (-pi, pi].
const double sinPsi = sin(psi);
if (!sinPsi) phi = 0;
else {const double cosPhi = c.getX() / sinPsi;
if
(cosPhi >= 1) phi = 0;
else if (cosPhi <= -1) phi = M_PI;
else
phi = acos(cosPhi);}
return c.getZ() > 0 ? complex<double>(psi, -phi) :
complex<double>(psi,
phi);}
vector3D<double> polarAngle(const double kappa) const
{const complex<double> polar = polarAngle();
return vector3D<double>(real(polar), imag(polar), kappa);}
bool
operator||(const vector3D<T> &v) const
{return this->vcos() == v.vcos() && !!v;}
bool
parallel(const vector3D<T> &v) const {return *this || v;}
bool
antiparallel(const vector3D<T> &v) const {return *this || -v;}
bool
perpendicular(const vector3D<T> &v) const {return !(*this * v);}
// Distance
static double
distance(const vector3D<T> &u, const vector3D<T> &v)
{return vabs(u.x - v.x, u.y - v.y, u.z - v.z);}
double
distance(const vector3D<T> &v) const {return distance(*this, v);}
double
operator|(const vector3D<T> &v) const {return distance(v);}
// Angle
static double
cosAngle(const vector3D<T> &u, const vector3D<T> &v)
{return (u * v) / (vabs(u) * vabs(v));}
double
cosAngle(const vector3D<T> &v) const {return cosAngle(*this, v);}
static double
sinAngle(const vector3D<T> &u, const vector3D<T> &v)
{return vabs(u ->* v) / (vabs(u) * vabs(v));}
double sinAngle(const
vector3D<T> &v) const {return sinAngle(*this, v);}
static double
tanAngle(const vector3D<T> &u, const vector3D<T> &v)
{return vabs(u ->* v) / (u * v);}
double
tanAngle(const vector3D<T> &v) const {return tanAngle(*this, v);}
static double
angle(const vector3D<T> &u, const vector3D<T> &v)
// in radian
{return atan2(sinAngle(u, v), cosAngle(u, v));}
double
angle(const vector3D<T> &v) const {return angle(*this, v);}
double
operator^(const vector3D<T> &v) const {return angle(v);}
// Area
static double
triangleVertices(const vector3D<T> &u,
const vector3D<T> &v,
const vector3D<T> &w)
// u, v, w are vertices
{return vabs((v - u) ->* (w - u)) / 2;}
double
triangleVertices(const vector3D<T> &u, const vector3D<T>
&v) const
{return triangleVertices(*this, u, v);}
static double
triangleEdges(const vector3D<T> &u,
const
vector3D<T> &v)
// u and v are two edges
{return triangleVertices(vector3D<T>(0, 0, 0), u, v);}
double
triangleEdges(const vector3D<T> &v) const
{return triangleEdges(*this, v);}
// Volume
static T
scalarTripleProduct(const vector3D<T> &u,
const vector3D<T> &v,
const vector3D<T> &w)
{return u * (v ->* w);}
T
scalarTripleProduct(const vector3D<T> &u, const vector3D<T>
&v) const
{return scalarTripleProduct(*this, u, v);}
static T
parallelepipedVolume(const vector3D<T> &u,
const vector3D<T> &v,
const vector3D<T> &w)
{const T stp = scalarTripleProduct(u, v, w);
return stp < 0 ? -stp : stp;}
T
parallelepipedVolume(const vector3D<T> &u, const vector3D<T>
&v) const
{return parallelepipedVolume(*this, u, v);}
// Location
bool inside(const vector3D<T> &u,
const vector3D<T> &v) const
// Return whether *this is inside the parallelepiped whose two body
// diagonal vertices are u and v, respectively.
{return min(u.x, v.x) <= x && x <= max(u.x, v.x)
&&
min(u.y, v.y) <= y
&& y <= max(u.y, v.y) &&
min(u.z, v.z) <= z && z <= max(u.z, v.z);}
bool
outside(const vector3D<T> &u, const vector3D<T> &v) const
{return !inside(u, v);}
private:
T x, y, z;
};
}
// namespace mac
/*
template
<class T>
mac::vector3D<double>
sin(const mac::vector3D<T>& v) {return v.vsin();}
template
<class T>
mac::vector3D<double>
cos(const mac::vector3D<T>& v) {return v.vcos();}
template
<class T>
mac::vector3D<double>
tan(const mac::vector3D<T>& v) {return v.vtan();}
template
<class T>
double abs(const
mac::vector3D<T>& v) {return v.vabs();}
template
<class T>
double abs(const T& x, const T&
y, const T& z)
{return mac::vector3D<T>(x,
y, z).vabs();}
template
<class T>
double norm(const mac::vector3D<T>&
v) {return v.vnorm();}
template
<class T>
double norm(const T& x, const T& y,
const T& z)
{return mac::vector3D<T>(x,
y, z).vnorm();}
template
<class T>
double vabs(const mac::vector3D<T>&
v) {return v.vabs();}
template
<class T>
T vnorm(const
mac::vector3D<T>& v) {return v.vnorm();}
template
<class T>
double vabs(const T& x, const T& y,
const T& z)
{return mac::vector3D<T>(x,
y, z).vabs();}
template
<class T>
T vnorm(const
T& x, const T& y, const T& z)
{return mac::vector3D<T>(x,
y, z).vnorm();}
template
<class T>
T dot_prod(const
mac::vector3D<T>& v1,
const mac::vector3D<T>& v2) {return v1 * v2;}
template
<class T>
mac::vector3D<T>
operator*(const T& x,
const mac::vector3D<T>& v) {return v * x;}
template
<class T>
mac::vector3D<T>
operator/(const T& x, const mac::vector3D<T>& v)
{return mac::vector3D<T>(x,
x, x) / v;}
template
<class T>
mac::vector3D<T>
operator*(const mac::matrix3D<T>& m,
const mac::vector3D<T>& v)
{return v * m;} //
pre-multiplication
*/
#endif
Listing A1.1.0.0.1 The modified vector3D.h ready for wrapping by SWIG.
Several shadow classes can be included in a module. Listing A1.1.0.0.2 shows matrix3D.h. This header file includes the .c++ file at the end.
#ifndef
CPL_MAC_MATRIX3D_H
#define
CPL_MAC_MATRIX3D_H
#include
<iostream.h>
#include
<strstream.h>
#include
<assert.h>
//#include
"matrix.h"
namespace
mac
{
template
<class T> class vector3D;
template
<class T>