Index: /GTP/trunk/Lib/Vis/Preprocessing/scripts/Preprocessor.vcproj
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/scripts/Preprocessor.vcproj	(revision 1020)
+++ /GTP/trunk/Lib/Vis/Preprocessing/scripts/Preprocessor.vcproj	(revision 1097)
@@ -502,4 +502,263 @@
 				RelativePath="..\src\X3dParserXerces.h">
 			</File>
+			<Filter
+				Name="mixkit"
+				Filter="">
+				<File
+					RelativePath="..\src\mixkit\getopt.c">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\getopt.h">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\getopt1.c">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\mixio.h">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\mixmops.cxx">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\mixmops.h">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\mixmsg.cxx">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\mixmsg.h">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\mixvops.h">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxArcball.cxx">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxArcball.h">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxAsp.cxx">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxAsp.h">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxBlock.h">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxBlock2.h">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxBlock3.h">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxBlockModel.cxx">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxBlockModel.h">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxCamera.cxx">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxCamera.h">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxCmdParser.cxx">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxCmdParser.h">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxDynBlock.h">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxEdgeFilter.cxx">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxEdgeFilter.h">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxGeom3D.cxx">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxGeom3D.h">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxGeoPrims.h">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxGL.h">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxGLDebug.cxx">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxGLPane.cxx">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxGLPane.h">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxGLUtils.cxx">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxGLUtils.h">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxHeap.cxx">
+					<FileConfiguration
+						Name="Debug|Win32">
+						<Tool
+							Name="VCCLCompilerTool"
+							ObjectFile="$(IntDir)/$(InputName)1.obj"/>
+					</FileConfiguration>
+					<FileConfiguration
+						Name="Release|Win32">
+						<Tool
+							Name="VCCLCompilerTool"
+							ObjectFile="$(IntDir)/$(InputName)1.obj"/>
+					</FileConfiguration>
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxHeap.h">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxLineModel.cxx">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxManipulator.h">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxMat2.cxx">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxMat2.h">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxMat3-jacobi.cxx">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxMat3.cxx">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxMat3.h">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxMat4-jacobi.cxx">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxMat4.cxx">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxMat4.h">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxMath.h">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxMatrix.cxx">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxMatrix.h">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxPropSlim.cxx">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxPropSlim.h">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxQMetric.cxx">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxQMetric.h">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxQMetric2.cxx">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxQMetric2.h">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxQMetric3.cxx">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxQMetric3.h">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxQSlim.cxx">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxQSlim.h">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxQVis3.cxx">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxRaster-tiff.cxx">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxRaster.cxx">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxRaster.h">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxSMF.cxx">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxSMF.h">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxStack.h">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxStdModel.cxx">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxStdModel.h">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxStdPane.cxx">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxStdPane.h">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxStdRender.cxx">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxStdSlim.cxx">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxStdSlim.h">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxTimer.cxx">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxTimer.h">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxTriProject.cxx">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxVec2.h">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxVec3.h">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxVec4.h">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\MxVector.h">
+				</File>
+				<File
+					RelativePath="..\src\mixkit\stdmix.h">
+				</File>
+			</Filter>
 		</Filter>
 		<Filter
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxGLDebug.cxx
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxGLDebug.cxx	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxGLDebug.cxx	(revision 1097)
@@ -0,0 +1,50 @@
+/************************************************************************
+
+  MxGLDebug
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxGLDebug.cxx,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "stdmix.h"
+#include "MxGL.h"
+
+void mxgl_report_stack_depth()
+{
+    GLint depth;
+
+    glGetIntegerv(GL_PROJECTION_STACK_DEPTH, &depth);
+    cerr << "   Projection stack depth = " << depth;
+    glGetIntegerv(GL_MAX_PROJECTION_STACK_DEPTH, &depth);
+    cerr << " (" << depth << " max)" << endl;
+
+    glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &depth);
+    cerr << "   ModelView stack depth = " << depth;
+    glGetIntegerv(GL_MAX_MODELVIEW_STACK_DEPTH, &depth);
+    cerr << " (" << depth << " max)" << endl;
+
+    glGetIntegerv(GL_TEXTURE_STACK_DEPTH, &depth);
+    cerr << "   Texture stack depth = " << depth;
+    glGetIntegerv(GL_MAX_TEXTURE_STACK_DEPTH, &depth);
+    cerr << " (" << depth << " max)" << endl;
+}
+
+
+void mxgl_check_errors(const char *msg)
+{
+    bool stack_error = false;
+
+    for(GLenum err=glGetError(); err!=GL_NO_ERROR; err=glGetError())
+    {
+	cerr << "GL ERROR ";
+	if( msg ) cerr << msg;
+	cerr << ": " << (const char *)gluErrorString(err) << endl;
+
+	if( err==GL_STACK_OVERFLOW || err==GL_STACK_UNDERFLOW )
+	    stack_error = true;
+    }
+
+    if( stack_error )  mxgl_report_stack_depth();
+}
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxGeoPrims.h
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxGeoPrims.h	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxGeoPrims.h	(revision 1097)
@@ -0,0 +1,262 @@
+#ifndef MXGEOPRIMS_INCLUDED // -*- C++ -*-
+#define MXGEOPRIMS_INCLUDED
+#if !defined(__GNUC__)
+#  pragma once
+#endif
+
+/************************************************************************
+
+  MxGeoPrims
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxGeoPrims.h,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "MxMath.h"
+
+//
+// Standard names for ID types
+//
+typedef unsigned int MxVertexID;
+typedef unsigned int MxFaceID;
+
+//
+// Convenient nicknames
+//
+#define VID MxVertexID
+#define FID MxFaceID
+
+#if !defined(MX_COLOR_RGBA) && !defined(MX_COLOR_ABGR)
+#  define MX_COLOR_RGBA
+#endif
+
+class MxColor : public MxEQ
+{
+private:
+    inline unsigned char _ftop(float x)
+	{ return (unsigned char)((x>1.0f?1.0f:x)*255.0f); }
+    inline float _ptof(unsigned char c) const { return ((float)c) / 255.0f; }
+
+public:
+    union {
+#if defined(MX_COLOR_RGBA)
+	struct { unsigned char r, g, b, a; } chan;
+#elif defined(MX_COLOR_ABGR)
+	struct { unsigned char a, b, g, r; } chan;
+#else
+#  error "Packed color format illegal or left unspecified"
+#endif
+	unsigned int word;
+    } as;
+
+    MxColor() { }
+    MxColor(float r, float g, float b) { as.chan.a=0; set(r, g, b); }
+
+    void set(float r, float g, float b)
+	{ as.chan.r=_ftop(r);  as.chan.g=_ftop(g);  as.chan.b=_ftop(b); }
+    void set(const float *c)
+	{ as.chan.r=_ftop(c[0]);as.chan.g=_ftop(c[1]);as.chan.b=_ftop(c[2]); }
+    void set(const double *c)
+	{ as.chan.r=_ftop(c[0]);as.chan.g=_ftop(c[1]);as.chan.b=_ftop(c[2]); }
+
+    float R() const { return _ptof(as.chan.r); }
+    float G() const { return _ptof(as.chan.g); }
+    float B() const { return _ptof(as.chan.b); }
+};
+
+class MxTexCoord : public MxEQ
+{
+public:
+    float u[2];
+
+    MxTexCoord() { }
+    MxTexCoord(float s, float t) { u[0]=s; u[1]=t; }
+    MxTexCoord(const MxTexCoord& t) { *this = t; }
+
+    float& operator[](int i)       { return u[i]; }
+    float  operator[](int i) const { return u[i]; }
+    operator const float*() const { return u; }
+    operator       float*()       { return u; }
+
+    MxTexCoord& operator=(const MxTexCoord& t)
+	{ u[0]=t[0];  u[1]=t[1]; return *this; }
+};
+
+
+class MxVertex : public MxEQ
+{
+public:
+    union {
+	float pos[3];
+	struct { MxVertexID parent, next, prev; } proxy;
+    } as;
+
+    MxVertex() { }
+    MxVertex(float x, float y, float z) {as.pos[0]=x;as.pos[1]=y;as.pos[2]=z;}
+    MxVertex(const MxVertex& v) { *this = v; }
+    
+    MxVertex& operator=(const MxVertex& v)
+	{ as.pos[0]=v.as.pos[0]; as.pos[1]=v.as.pos[1];
+	  as.pos[2]=v.as.pos[2]; return *this; }
+    operator const float*() const { return as.pos; }
+    operator float*() { return as.pos; }
+
+    float& operator()(int i)       { return as.pos[i]; }
+    float  operator()(int i) const { return as.pos[i]; }
+    //
+    // The [] operator is preferred over ()
+    //
+    float& operator[](int i)       { return as.pos[i]; }
+    float  operator[](int i) const { return as.pos[i]; }
+};
+
+class MxNormal : public MxEQ
+{
+private:
+    inline short _ftos(float x)
+	{ return (short)rint((x>1.0f?1.0f:x)*(float)SHRT_MAX); }
+    inline short _dtos(double x)
+	{ return (short)rint((x>1.0?1.0:x)*(double)SHRT_MAX); }
+
+    inline float _stof(short s) const { return (float)s/(float)SHRT_MAX; }
+    inline double _stod(short s) const { return (double)s/(double)SHRT_MAX; }
+
+    short dir[3];
+
+public:
+    MxNormal() { }
+    MxNormal(float x, float y, float z) { set(x,y,z); }
+    MxNormal(const float *v) { set(v); }
+    MxNormal(const double *v) { set(v); }
+
+    inline void set(double x, double y, double z)
+	{ dir[0]=_dtos(x);  dir[1]=_dtos(y);  dir[2]=_dtos(z); }
+    inline void set(const float *v)
+	{ dir[0]=_ftos(v[0]);  dir[1]=_ftos(v[1]);  dir[2]=_ftos(v[2]); }
+    inline void set(const double *v)
+	{ dir[0]=_dtos(v[0]);  dir[1]=_dtos(v[1]);  dir[2]=_dtos(v[2]); }
+
+    float operator[](uint i) const { AssertBound(i<3); return _stof(dir[i]); }
+    short raw(uint i) const { return dir[i]; }
+};
+    
+class MxEdge : public MxEQ
+{
+public:
+    MxVertexID v1, v2;
+
+    MxEdge() { v1=v2=MXID_NIL; }
+    MxEdge(MxVertexID a, MxVertexID b) { v1=a; v2=b; }
+    MxEdge(const MxEdge& e) { v1=e.v1;  v2=e.v2; }
+
+    MxVertexID opposite_vertex(MxVertexID v)
+	{
+	    if( v==v1 ) return v2;
+	    else { SanityCheck(v==v2); return v1; }
+	}
+};
+
+class MxFace : public MxEQ
+{
+public:
+    MxVertexID v[3];
+
+    MxFace() { }
+    MxFace(MxVertexID v0, MxVertexID v1, MxVertexID v2)
+	{ v[0]=v0;  v[1]=v1;  v[2]=v2; }
+    MxFace(const MxFace& f) { v[0]=f.v[0]; v[1]=f.v[1]; v[2]=f.v[2]; }
+
+    MxVertexID& operator()(int i)       { return v[i]; }
+    MxVertexID  operator()(int i) const { return v[i]; }
+    //
+    // The [] operator is now preferred over the () operator.
+    //
+    MxVertexID& operator[](int i)       { return v[i]; }
+    MxVertexID  operator[](int i) const { return v[i]; }
+
+    int remap_vertex(MxVertexID from, MxVertexID to)
+	{
+	    int nmapped = 0;
+	    for(int i=0; i<3; i++)
+		if( v[i]==from )
+		{
+		    v[i]=to;
+		    nmapped++;
+		}
+	    return nmapped;
+	}
+
+    uint find_vertex(MxVertexID i)
+	{
+	    if( v[0]==i ) return 0;
+	    else if( v[1]==i ) return 1;
+	    else { SanityCheck(v[2]==i); return 2; }
+	}
+
+    MxVertexID opposite_vertex(MxVertexID v0, MxVertexID v1)
+	{
+	    if( v[0]!=v0 && v[0]!=v1 ) return v[0];
+	    else if( v[1]!=v0 && v[1]!=v1 ) return v[1];
+	    else { SanityCheck( v[2]!=v0 && v[2]!=v1 ); return v[2]; }
+	}
+
+    bool is_inorder(MxVertexID v0, MxVertexID v1)
+	{
+	    if( v[0]==v0 ) return v[1]==v1;
+	    else if( v[1]==v0 ) return v[2]==v1;
+	    else { SanityCheck(v[2]==v0); return v[0]==v1; }
+	}
+};
+
+
+inline ostream& operator<<(ostream& out, const MxVertex& v)
+{
+    return out << "v " << v(0) << " " << v(1) << " " << v(2);
+}
+
+inline ostream& operator<<(ostream& out, const MxFace& f)
+{
+    return out << "f " << f(0)+1 << " " <<  f(1)+1 << " " <<  f(2)+1;
+}
+
+inline ostream& operator<<(ostream& out, const MxColor& c)
+{
+    return out << "c " << c.R() << " " << c.G() << " " << c.B();
+}
+
+inline ostream& operator<<(ostream& out, const MxNormal& n)
+{
+    return out << "n " << n[0] << " " << n[1] << " " << n[2];
+}
+
+inline ostream& operator<<(ostream& out, const MxTexCoord& t)
+{
+    return out << "r " << t[0] << " " << t[1];
+}
+
+#ifdef MXGL_INCLUDED
+inline void glC(const MxColor& c)
+{
+    glColor3ub(c.as.chan.r, c.as.chan.g, c.as.chan.b);
+}
+inline void glT(const MxTexCoord& t) { glTexCoord2fv(t); }
+inline void glV(const MxVertex& v) { glVertex3fv(v); }
+inline void glN(const MxNormal& n) { 
+    //
+    // !!WARNING!! glNormal3sv doesn't work for some reason, and neither
+    // glNormal3s.  Oddly, glNormal3i correctly.  Is this some sort of GL bug
+    // or am I doing something wrong??
+    //
+    glNormal3i(n.raw(0), n.raw(1), n.raw(2));
+}
+
+inline void glC(const MxColor *c)    { glC(*c); }
+inline void glT(const MxTexCoord *t) { glT(*t); }
+inline void glV(const MxVertex *v)   { glV(*v); }
+inline void glN(const MxNormal *n)   { glN(*n); }
+#endif
+
+// MXGEOPRIMS_INCLUDED
+#endif
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxQMetric3.h
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxQMetric3.h	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxQMetric3.h	(revision 1097)
@@ -0,0 +1,128 @@
+#ifndef MXQMETRIC3_INCLUDED // -*- C++ -*-
+#define MXQMETRIC3_INCLUDED
+#if !defined(__GNUC__)
+#  pragma once
+#endif
+
+/************************************************************************
+
+  3D Quadric Error Metric
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxQMetric3.h,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "MxMath.h"
+#include "MxMat3.h"
+#include "MxMat4.h"
+
+class MxQuadric3
+{
+private:
+    double a2, ab, ac, ad;
+    double     b2, bc, bd;
+    double         c2, cd;
+    double             d2;
+
+    double r;
+
+    void init(double a, double b, double c, double d, double area);
+    void init(const Mat4& Q, double area);
+
+public:
+    MxQuadric3() { clear(); }
+    MxQuadric3(double a, double b, double c, double d, double area=1.0)
+	{ init(a, b, c, d, area); }
+    MxQuadric3(const float *n, double d, double area=1.0)
+	{ init(n[X], n[Y], n[Z], d, area); }
+    MxQuadric3(const double *n, double d, double area=1.0)
+	{ init(n[X], n[Y], n[Z], d, area); }
+    MxQuadric3(const MxQuadric3& Q) { *this = Q; }
+
+    Mat3 tensor() const;
+    Vec3 vector() const { return Vec3(ad, bd, cd); }
+    double offset() const { return d2; }
+    double area() const { return r; }
+    Mat4 homogeneous() const;
+
+    void set_coefficients(const double *);
+    void set_area(double a) { r=a; }
+
+    void clear(double val=0.0) { a2=ab=ac=ad=b2=bc=bd=c2=cd=d2=r=val; }
+    MxQuadric3& operator=(const MxQuadric3& Q);
+    MxQuadric3& operator+=(const MxQuadric3& Q);
+    MxQuadric3& operator-=(const MxQuadric3& Q);
+    MxQuadric3& operator*=(double s);
+    MxQuadric3& transform(const Mat4& P);
+
+    double evaluate(double x, double y, double z) const;
+    double evaluate(const double *v) const {return evaluate(v[X], v[Y], v[Z]);}
+    double evaluate(const float *v) const  {return evaluate(v[X], v[Y], v[Z]);}
+
+    double operator()(double x, double y, double z) const
+	{ return evaluate(x, y, z); }
+    double operator()(const double *v) const {return evaluate(v[X],v[Y],v[Z]);}
+    double operator()(const float *v) const  {return evaluate(v[X],v[Y],v[Z]);}
+
+    bool optimize(Vec3& v) const;
+    bool optimize(float *x, float *y, float *z) const;
+
+    bool optimize(Vec3& v, const Vec3& v1, const Vec3& v2) const;
+    bool optimize(Vec3& v,const Vec3& v1,const Vec3& v2,const Vec3& v3) const;
+
+
+    ostream& write(ostream& out)
+	{
+	    return out << a2 << " " << ab << " " << ac << " " << ad << " "
+		       << b2 << " " << bc << " " << bd << " " << c2 << " "
+		       << cd << " " << d2 << " " << r;
+	}
+
+    ostream& write_full(ostream& out)
+	{
+	    return out << a2 << " " << ab << " " << ac << " " << ad << " "
+		       << ab << " " << b2 << " " << bc << " " << bd << " "
+		       << ac << " " << bc << " " << c2 << " " << cd << " "
+		       << ad << " " << bd << " " << cd << " " << d2;
+	}
+
+
+    istream& read(istream& in)
+	{
+	    return in >> a2 >> ab >> ac >> ad >> b2
+		      >> bc >> bd >> c2 >> cd >> d2 >> r;
+	}
+    
+
+    istream& read_full(istream& in)
+	{
+	    return in >> a2 >> ab >> ac >> ad
+		      >> ab >> b2 >> bc >> bd
+		      >> ac >> bc >> c2 >> cd
+		      >> ad >> bd >> cd >> d2;
+	}
+
+};
+
+
+inline ostream& operator<<(ostream& out, MxQuadric3& Q) {return Q.write(out);}
+inline istream& operator>>(istream& in, MxQuadric3& Q) { return Q.read(in); }
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// Quadric visualization routines
+//
+
+#define MX_RED_ELLIPSOIDS 0x1
+#define MX_GREEN_ELLIPSOIDS 0x2
+#define MX_CHARCOAL_ELLIPSOIDS 0x3
+
+extern void mx_quadric_shading(int c=MX_GREEN_ELLIPSOIDS, bool twosided=true);
+extern void mx_draw_quadric(const MxQuadric3& Q, double r, const float*v=NULL);
+extern void mx_draw_osculant(float k1, float k2, float extent=1.0);
+
+// MXQMETRIC3_INCLUDED
+#endif
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxCamera.h
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxCamera.h	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxCamera.h	(revision 1097)
@@ -0,0 +1,37 @@
+#ifndef MXCAMERA_INCLUDED // -*- C++ -*-
+#define MXCAMERA_INCLUDED
+#if !defined(__GNUC__)
+#  pragma once
+#endif
+
+/************************************************************************
+
+  MxCamera
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxCamera.h,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "MxGL.h"
+#include "MxGeom3D.h"
+
+class MxCamera
+{
+public:
+
+    double fovy, aspect;
+    double znear, zfar;
+    Vec3 from, at, up;
+
+    void look_at(const MxBounds&, double ratio=1.333333);
+
+    void apply();
+    void apply(GLenum mode);
+};
+
+
+
+// MXCAMERA_INCLUDED
+#endif
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxStdSlim.cxx
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxStdSlim.cxx	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxStdSlim.cxx	(revision 1097)
@@ -0,0 +1,36 @@
+/************************************************************************
+
+  Surface simplification using quadric error metrics
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxStdSlim.cxx,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "stdmix.h"
+#include "MxStdSlim.h"
+
+MxStdSlim::MxStdSlim(MxStdModel *m0)
+    : heap(64)
+{
+    m = m0;
+
+    // Externally visible variables
+    placement_policy = MX_PLACE_OPTIMAL;
+    weighting_policy = MX_WEIGHT_AREA;
+    boundary_weight = 1000.0;
+    compactness_ratio = 0.0;
+    meshing_penalty = 1.0;
+    local_validity_threshold = 0.0;
+    vertex_degree_limit = 24;
+    will_join_only = false;
+
+    valid_faces = 0;
+    valid_verts = 0;
+    is_initialized = false;
+
+    uint i;
+    for(i=0; i<m->face_count(); i++) if(m->face_is_valid(i))  valid_faces++;
+    for(i=0; i<m->vert_count(); i++) if(m->vertex_is_valid(i))  valid_verts++;
+}
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxManipulator.h
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxManipulator.h	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxManipulator.h	(revision 1097)
@@ -0,0 +1,42 @@
+#ifndef MXMANIPULATOR_INCLUDED // -*- C++ -*-
+#define MXMANIPULATOR_INCLUDED
+#if !defined(__GNUC__)
+#  pragma once
+#endif
+
+/************************************************************************
+
+  MxManipulator
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxManipulator.h,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "MxGeom3D.h"
+
+class MxManipulator
+{
+public:
+
+    virtual void init(const MxBounds&, float) { }
+
+    bool mouse(int kind, int which, int x, int y)
+	{
+	    if( kind&0xf == 1 ) return mouse_down(which, x, y);
+	    else if( kind&0xf == 2 ) return mouse_up(which, x, y);
+	    else return motion(x, y);
+	}
+    virtual bool mouse_down(int which, int x, int y, int kind=1) = 0;
+    virtual bool mouse_up(int which, int x, int y, int kind=2) = 0;
+    virtual bool motion(int x, int y) = 0;
+    virtual bool animate() { return false; }
+
+    virtual void apply() = 0;
+    virtual void unapply() = 0;
+    virtual void draw() { }
+};
+
+// MXMANIPULATOR_INCLUDED
+#endif
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxCmdParser.cxx
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxCmdParser.cxx	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxCmdParser.cxx	(revision 1097)
@@ -0,0 +1,131 @@
+/************************************************************************
+
+  MxCmdParser
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxCmdParser.cxx,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "stdmix.h"
+#include "mixio.h"
+#include "MxCmdParser.h"
+
+#include "MxDynBlock.h"
+#include <ctype.h>
+
+typedef MxDynBlock<char *> string_list;
+
+#define MXCMD_PHRASE_SEPARATOR ';'
+
+static
+char *trimleft(char *line)
+{
+    if( !line ) return NULL;
+    while(isspace(*line)) line++;
+    return line;
+}
+
+static
+char *shift_token(char *line)
+{
+    if( !line )  return NULL;
+
+    char *rest = NULL;
+
+    while( *line && !isspace(*line) )  line++;
+
+    if( *line )  rest = line+1;
+
+    *line = '\0';
+
+    return trimleft(rest);
+}
+
+static
+char *shift_phrase(char *line)
+{
+    if( !line )  return NULL;
+
+    char *rest = NULL;
+
+    while( *line && *line != MXCMD_PHRASE_SEPARATOR ) line++;
+
+    if( *line )  rest = line+1;
+
+    *line = '\0';
+
+    return trimleft(rest);
+}
+
+MxCmdParser::MxCmdParser()
+    : cmd(16)
+{
+    will_ignore_unknown = true;
+}
+
+void MxCmdParser::parse_line(char *line, void *closure)
+{
+    uint i,j;
+
+    line = trimleft(line);
+
+    if(!line[0] || line[0] == '#')  return; // Ignore comments and empty lines
+
+    // Extract operator
+    //
+    char *op = line;   line = shift_token(line);
+
+    // Extract phrases
+    //
+    string_list phrases;
+
+    while( line )
+    {
+        phrases.add(line);
+        line = shift_phrase(line);
+    }
+
+    cmd.phrases.reset();
+    cmd.op = op;
+
+    // Extract args in phrases
+    //
+    string_list args;
+
+    for(i=0; i<phrases.length(); i++)
+    {
+        char *phrase = phrases[i];
+        args.reset();
+
+        while( phrase )
+        {
+            char *arg = phrase;
+            phrase = shift_token(phrase);
+            if( *arg )  args.add(arg); // trailing space doesn't count
+        }
+
+	cmd.phrases.add();
+	cmd.phrases[i].reset();
+        if( args.length() )
+        {
+            for(j=0; j<args.length(); j++)
+                cmd.phrases[i].add(args[j]);
+        }
+    }
+
+    bool result = execute_command(cmd, closure);
+
+    if( !result && phrases.length()==1 )
+	result = store.execute_command(cmd.phrases[0].length(), cmd.op,
+				       (const char **)&cmd.phrases[0][0]);
+
+    if( !result && !will_ignore_unknown )
+	mxmsg_signal(MXMSG_WARN, "Unknown operator on input", line);
+}
+
+bool MxCmdParser::execute_command(const MxCmd& cmd, void *)
+{
+    return false;
+}
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxAsp.cxx
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxAsp.cxx	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxAsp.cxx	(revision 1097)
@@ -0,0 +1,314 @@
+/************************************************************************
+
+  MxAsp
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxAsp.cxx,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "stdmix.h"
+#include "MxAsp.h"
+
+
+#define MXASP_OWN_MEMORY 0x1
+
+void MxAspVar::own_memory(bool t)
+{
+    if( t ) flags |= MXASP_OWN_MEMORY;
+    else    flags &= ~MXASP_OWN_MEMORY;
+}
+
+bool MxAspVar::is_memory_owned()
+{
+    return flags & MXASP_OWN_MEMORY;
+}
+
+void MxAspVar::clear()
+{
+    type = MXASP_NULL;
+    size = 0;
+    flags = 0;
+    as.any = NULL;
+    name = NULL;
+}
+
+void MxAspVar::bind(const char *n, MxAspType t, void *v, uint len)
+{
+    unbind();
+
+    name = strdup(n);
+    type = t;
+    as.any = v;
+    size = len;
+}
+
+void MxAspVar::unbind()
+{
+    if( is_memory_owned() && as.any ) free(as.any);
+    if( name ) free(name);
+
+    clear();
+}
+
+#define asprint(V)\
+out<< *as##.##V##_var; \
+for(i=1; i<size; i++) out << " " << as##.##V##_var[i]
+
+ostream& MxAspVar::print(ostream& out) const
+{
+    uint i;
+
+    switch( type )
+    {
+    case MXASP_BOOL:    asprint(bool); break;
+    case MXASP_INT:     asprint(int); break;
+    case MXASP_UINT:    asprint(uint); break;
+    case MXASP_FLOAT:   asprint(float); break;
+    case MXASP_DOUBLE:  asprint(double); break;
+    case MXASP_PROC:    out << "#<proc " << name << ">"; break;
+
+    default: out << "#<avar '" << name << "' of unknown type>"; break;
+    }
+
+    return out;
+}
+#undef asprint
+
+#define defset(V, T) \
+bool MxAspVar::set_##V(V val, uint i) \
+{\
+     if( type==T && i<size ) { as##.##V##_var[i]=val; return true; } \
+     else  return false; \
+}
+
+defset(bool,   MXASP_BOOL)
+defset(int,    MXASP_INT)
+defset(uint,   MXASP_UINT)
+defset(float,  MXASP_FLOAT)
+defset(double, MXASP_DOUBLE)
+
+#undef defset
+
+#define defget(V, T) \
+V *MxAspVar::get_##V(V *out, uint i) \
+{\
+     if( type==T && i<size ) { *out = as##.##V##_var[i]; return out; } \
+     else  return NULL; \
+} 
+
+defget(bool,   MXASP_BOOL)
+defget(int,    MXASP_INT)
+defget(uint,   MXASP_UINT)
+defget(float,  MXASP_FLOAT)
+defget(double, MXASP_DOUBLE)
+
+#undef defget
+
+
+bool MxAspVar::read_from(const char *str, uint i)
+{
+    if( i>=size )  return false;
+
+    switch( type )
+    {
+    case MXASP_BOOL:   as.bool_var[i] = atoi(str)&1; break;
+    case MXASP_INT:    as.int_var[i] = atoi(str); break;
+    case MXASP_UINT:   as.uint_var[i] = atoi(str); break;
+    case MXASP_FLOAT:  as.float_var[i] = atof(str); break;
+    case MXASP_DOUBLE: as.double_var[i] = atof(str); break;
+
+    default:  return false;
+    }
+
+    return true;
+}
+
+bool MxAspVar::apply(int argc, const char **argv, MxAspStore *store)
+{
+    if( type==MXASP_PROC && argc>=as.proc_var->args_expected )
+    {
+	if( as.proc_var->args_expected==0 )
+	{
+	    apply(NULL, store);
+	}
+	else
+	{
+	    void *value = mxasp_alloc_value(as.proc_var->arg_type,
+					    as.proc_var->args_expected);
+
+	    MxAspVar arg("{frame}", as.proc_var->arg_type,
+			 value, as.proc_var->args_expected);
+
+	    arg.own_memory(true);
+	    for(uint i=0; i<argc; i++) arg.read_from(argv[i], i);
+
+	    apply(&arg, store);
+	}
+
+	return true;
+    }
+
+    return false;
+}
+
+
+bool MxAspVar::apply(MxAspVar *arg, MxAspStore *store)
+{
+    if( type==MXASP_PROC )
+    {
+	(*as.proc_var->proc)(arg, store);
+	return true;
+    }
+
+    return false;
+}
+
+
+
+
+MxAspStore::MxAspStore()
+    : vars(8)
+{
+}
+
+
+MxAspVar *MxAspStore::lookup(const char *name) const
+{
+    for(uint i=0; i<vars.length(); i++)
+	if( streq(vars[i].nameof(), name) )
+	    //
+	    // NOTE: You might think it odd that we need the cast here.
+	    //       However, some compilers (i.e., SGI's) seem to need
+	    //       this to avoid getting confused.  Presumably because
+	    //       there is both a const and non-const access method.
+	    return (MxAspVar *)&vars[i];
+
+    return NULL;
+}
+
+MxAspVar *MxAspStore::defvar(const char *name, MxAspType t, void *v, uint len)
+{
+    uint i = vars.add();
+
+    vars[i].bind(name, t, v, len);
+    return (MxAspVar *)&vars[i];
+}
+
+MxAspVar *MxAspStore::defun(const char *name, MxAspProc proc,
+			    MxAspType type, uint expects)
+{
+    MxAspProcDefn *defn = (MxAspProcDefn *)calloc(1, sizeof(MxAspProcDefn));
+    defn->proc = proc;
+    defn->arg_type = type;
+    defn->args_expected = expects;
+
+    return defvar(name, MXASP_PROC, defn, 1);
+}
+
+bool MxAspStore::execute_command(int argc, const char *cmd, const char **argv)
+{
+    const char *varname  = argc?argv[0]:(const char*)NULL;
+    MxAspVar *avar = varname?lookup(varname):(MxAspVar*)NULL;
+
+    if( streq(cmd, "set") )
+    {
+	if( avar )
+	{
+	    for(uint i=1; i<argc; i++)
+		avar->read_from(argv[i], i-1);
+	}
+	else
+	    mxmsg_signal(MXMSG_WARN,
+			 "Tried to SET undefined Asp variable", varname);
+    }
+    else if( streq(cmd, "print") )
+    {
+	if( avar )
+	{
+	    cout << "  : " << varname << " = ";
+	    avar->print(cout) << endl;
+	}
+	else
+	    mxmsg_signal(MXMSG_WARN,
+			 "Tried to PRINT undefined Asp variable", varname);
+    }
+    else if( streq(cmd, "defvar") )
+    {
+	if( avar )
+	    mxmsg_signal(MXMSG_WARN, "Can't redefine Asp variable", varname);
+	else
+	{
+	    MxAspType type = mxasp_type_from_name(argv[1]);
+	    uint size = (argc>2)?atoi(argv[2]):1;
+	    void *value = mxasp_alloc_value(type, size);
+
+	    avar = defvar(varname, type, value, size);
+	    avar->own_memory(true);
+	}
+    }
+    else if( (avar=lookup(cmd)) )
+    {
+	avar->apply(argc, argv, this);
+    }
+    else
+	return false;
+
+    return true;
+}
+
+void MxAspStore::write(ostream& out)
+{
+    out << "# ASP automatic state dump" << endl;
+    for(uint i=0; i<vars.length(); i++)
+	out << "set " << vars[i] << endl;
+}
+
+
+
+
+static
+char *typenames[] =
+{
+    "null",
+    "bool",
+    "int",
+    "uint",
+    "float",
+    "double",
+    "proc",
+    NULL
+};
+
+static
+uint typesizes[] = 
+{
+    0,
+    sizeof(bool),
+    sizeof(int),
+    sizeof(uint),
+    sizeof(float),
+    sizeof(double),
+    sizeof(MxAspProcDefn)
+};
+
+
+MxAspType mxasp_type_from_name(const char *name)
+{
+    for(uint i=1; i<MXASP_USER_TYPE; i++)
+	if( streq(name, typenames[i]) )
+	    return (MxAspType)i;
+
+    return MXASP_NULL;
+}
+
+void *mxasp_alloc_value(MxAspType t, uint size)
+{
+    if( t>MXASP_NULL && t<MXASP_USER_TYPE )
+    {
+	return (void *)calloc(size, typesizes[t]);
+    }
+    else
+	return NULL;
+}
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxStdPane.h
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxStdPane.h	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxStdPane.h	(revision 1097)
@@ -0,0 +1,93 @@
+#ifndef MXSTDPANE_INCLUDED // -*- C++ -*-
+#define MXSTDPANE_INCLUDED
+#if !defined(__GNUC__)
+#  pragma once
+#endif
+
+/************************************************************************
+
+  MxStdPane
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxStdPane.h,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "MxGLPane.h"
+#include "MxStdModel.h"
+#include "MxGeom3D.h"
+#include "MxArcball.h"
+#include "MxCamera.h"
+#include "MxAsp.h"
+
+class MxStdPane : public MxGLPane
+{
+private:
+    GLdouble __proj_save[16];
+    int selection_state;
+
+protected:
+    MxStdModel *m;
+    MxArcball manip;
+    MxBounds bounds;
+    MxCamera camera;
+    float light_position[4];
+
+    MxDynBlock<char> typein;
+
+    uint pick_something(int x, int y, double window, int mode);
+
+public:
+    bool will_draw_surface;
+    bool will_draw_mesh;
+    bool will_draw_points;
+    bool will_draw_texture;
+    bool will_illustrate;
+    bool will_light_scene;
+    bool ntsc_output;
+
+    MxStdPane(MxStdModel *M)
+	: typein(64)
+	{
+	    m = M;
+	    will_draw_surface = true;
+	    will_draw_mesh = false;
+	    will_draw_points = false;
+	    will_draw_texture = (m->texcoord_binding() != MX_UNBOUND);
+	    will_illustrate = true;
+	    will_light_scene = true;
+	    ntsc_output = false;
+	    selection_state = 0;
+
+	    for(MxVertexID v=0; v<m->vert_count(); v++)
+		bounds.add_point(m->vertex(v));
+	    bounds.complete();
+
+	    float aspect = 640.0f / 480.0f;  // guess at aspect ratio
+	    camera.look_at(bounds, aspect);
+	    manip.init(bounds, aspect);
+	}
+
+
+    void write_pane_config(ostream&);
+    void bind_asp_vars(MxAspStore *);
+
+    uint pick_face(int x, int y);
+    uint pick_vertex(int x, int y);
+    void move_light(float dx, float dy, float dz);
+
+    void gl_init();
+    void button(int kind, int which, int x, int y);
+    void key(char);
+    void redraw();
+    void begin_redraw();
+    void end_redraw();
+    void illustrate();
+    void size(int width, int height);
+
+    void quit();
+};
+
+// MXSTDPANE_INCLUDED
+#endif
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxSMF.cxx
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxSMF.cxx	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxSMF.cxx	(revision 1097)
@@ -0,0 +1,412 @@
+/************************************************************************
+
+  MxSMF
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxSMF.cxx,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "stdmix.h"
+#include "mixio.h"
+#include "MxSMF.h"
+#include "MxVector.h"
+
+#define SMF_MAXLINE 65536
+
+
+MxSMFReader::cmd_entry MxSMFReader::read_cmds[] = {
+    { "v", &MxSMFReader::vertex },
+    { "t", &MxSMFReader::face },
+    { "f", &MxSMFReader::face },
+
+    // Properties and binding -- this is the new way to handle things
+    { "bind", &MxSMFReader::prop_bind },
+    { "n", &MxSMFReader::prop_normal },
+    { "c", &MxSMFReader::prop_color },
+    { "r", &MxSMFReader::prop_texcoord },
+
+    { "begin", &MxSMFReader::begin },
+    { "end", &MxSMFReader::end },
+
+    { "trans", &MxSMFReader::trans },
+    { "rot", &MxSMFReader::rot },
+    { "scale", &MxSMFReader::scale },
+
+    { "tex", &MxSMFReader::read_texture },
+    { "t_trans", &MxSMFReader::t_trans },
+    { "t_scale", &MxSMFReader::t_scale },
+
+    { NULL, NULL }
+};
+
+
+MxSMFReader::MxSMFReader()
+    : vx_stack(Mat4::I, 2), tx_stack(Mat4::I, 2),
+      vcorrect_stack(0, 2), vfirst_stack(1, 2)
+{
+    next_vertex=1;
+    next_face=1;
+    quad_count=0;
+    poly_count=0;
+    line_buffer = new char[SMF_MAXLINE];
+    unparsed_hook = NULL;
+
+    define_avars();
+}
+
+MxSMFReader::~MxSMFReader()
+{
+    delete[] line_buffer;
+}
+
+void MxSMFReader::v_xform(Vec3& v)
+{
+    Vec4 v2 = vx_stack.top() * Vec4(v,1);
+
+    v[X] = v2[X]/v2[W];
+    v[Y] = v2[Y]/v2[W];
+    v[Z] = v2[Z]/v2[W];
+}
+
+void MxSMFReader::t_xform(Vec2& v)
+{
+    Vec4 v2 = tx_stack.top() * Vec4(v[X],v[Y],0,1);
+
+    v[X] = v2[X]/v2[W];
+    v[Y] = v2[Y]/v2[W];
+}
+
+unsigned int MxSMFReader::vid_xform(int id)
+{
+    if( id < 0 )
+	id += next_vertex;
+    else
+	id += vcorrect_stack.top() + (vfirst_stack.top() - 1);
+
+    return id;
+}
+
+////////////////////////////////////////////////////////////////////////
+
+void MxSMFReader::define_avars()
+{
+    asp_store()->defvar("vertex_correction", MXASP_INT, &vcorrect_stack.top());
+}
+
+void MxSMFReader::update_avars()
+{
+    MxAspVar *avar;
+
+    avar = asp_store()->lookup("vertex_correction");
+    if( avar )
+	avar->bind("vertex_correction", MXASP_INT, &vcorrect_stack.top());
+}
+
+void MxSMFReader::begin(int, char *[], MxStdModel&)
+{
+    vx_stack.push();
+    tx_stack.push();
+    vfirst_stack.push(next_vertex);
+    vcorrect_stack.push();
+    update_avars();
+}
+
+void MxSMFReader::end(int, char *[], MxStdModel&)
+{
+    vx_stack.pop();
+    tx_stack.pop();
+    vfirst_stack.pop();
+    vcorrect_stack.pop();
+    update_avars();
+}
+
+void MxSMFReader::trans(int, char *argv[], MxStdModel&)
+{
+    Mat4 M = Mat4::trans(atof(argv[0]), atof(argv[1]), atof(argv[2]));
+    vx_stack.top() = vx_stack.top() * M;
+}
+
+void MxSMFReader::rot(int, char *argv[], MxStdModel&)
+{
+    Mat4 M;
+    switch( argv[0][0] )
+    {
+    case 'x':
+	M = Mat4::xrot(atof(argv[1]) * M_PI/180.0);
+	break;
+    case 'y':
+	M = Mat4::yrot(atof(argv[1]) * M_PI/180.0);
+	break;
+    case 'z':
+	M = Mat4::zrot(atof(argv[1]) * M_PI/180.0);
+	break;
+    default:
+	mxmsg_signal(MXMSG_WARN, "Malformed SMF rotation command.");
+	break;
+    }
+
+    vx_stack.top() = vx_stack.top() * M;
+}
+
+void MxSMFReader::scale(int, char *argv[], MxStdModel&)
+{
+    Mat4 M = Mat4::scale(atof(argv[0]), atof(argv[1]), atof(argv[2]));
+    vx_stack.top() = vx_stack.top() * M;
+}
+
+void MxSMFReader::t_trans(int, char *argv[], MxStdModel&)
+{
+    Mat4 M = Mat4::trans(atof(argv[0]), atof(argv[1]), 0.0);
+    tx_stack.top() = tx_stack.top() * M;
+}
+
+void MxSMFReader::t_scale(int, char *argv[], MxStdModel&)
+{
+    Mat4 M = Mat4::scale(atof(argv[0]), atof(argv[1]), 1.0);
+    tx_stack.top() = tx_stack.top() * M;
+}
+
+void MxSMFReader::vertex(int, char *argv[], MxStdModel& m)
+{
+    Vec3 v(atof(argv[0]), atof(argv[1]), atof(argv[2]));
+
+    v_xform(v);
+    next_vertex++;
+
+    m.add_vertex((float)v[X], (float)v[Y], (float)v[Z]);
+}
+
+void MxSMFReader::prop_bind(int argc, char *argv[], MxStdModel& m)
+{
+    if( argc < 2 )  return;	// Not enough arguments
+
+    switch( argv[0][0] )
+    {
+    case 'n': m.normal_binding(m.parse_binding(argv[1])); break;
+    case 'c': m.color_binding(m.parse_binding(argv[1])); break;
+    case 'r': m.texcoord_binding(m.parse_binding(argv[1])); break;
+    }
+}
+
+void MxSMFReader::prop_normal(int /*argc*/, char *argv[], MxStdModel& m)
+{
+    Vec3 n(atof(argv[0]), atof(argv[1]), atof(argv[2]));
+    //v_xform(n);  //!!BUG: Need to transform normals appropriately
+    unitize(n);
+    m.add_normal((float)n[X], (float)n[Y], (float)n[Z]);
+}
+
+void MxSMFReader::prop_color(int /*argc*/, char *argv[], MxStdModel& m)
+{
+    float r = (float)atof(argv[0]);
+    float g = (float)atof(argv[1]);
+    float b = (float)atof(argv[2]);
+    m.add_color(r, g, b);
+}
+
+void MxSMFReader::prop_texcoord(int /*argc*/, char *argv[], MxStdModel& m)
+{
+    Vec2 v(atof(argv[0]), atof(argv[1]));
+    t_xform(v);
+    m.add_texcoord((float)v[X], (float)v[Y]);
+}
+
+void MxSMFReader::read_texture(int /*argc*/, char *argv[], MxStdModel& m)
+{
+    ifstream in(argv[0]);
+    MxRaster *tex = pnm_read(in);
+    tex->vflip();
+    m.add_texmap(tex, argv[0]);
+}
+
+void MxSMFReader::face(int argc, char *argv[], MxStdModel& m)
+{
+    if( argc == 3 )
+    {
+	unsigned int v0 = vid_xform(atoi(argv[0]));
+	unsigned int v1 = vid_xform(atoi(argv[1]));
+	unsigned int v2 = vid_xform(atoi(argv[2]));
+
+	next_face++;
+	m.add_face(v0 - 1, v1 - 1, v2 - 1);
+    }
+    else if( argc == 4 )
+    {
+	if( !quad_count )
+	    mxmsg_signalf(MXMSG_NOTE,
+	    "Input polygon #%d is a quadrilateral.  Splitting it.", next_face);
+
+	quad_count++;
+
+	unsigned int v[4];
+	v[0] = vid_xform(atoi(argv[0])) - 1;
+	v[1] = vid_xform(atoi(argv[1])) - 1;
+	v[2] = vid_xform(atoi(argv[2])) - 1;
+	v[3] = vid_xform(atoi(argv[3])) - 1;
+
+	float e[4][3];
+	mxv_unitize(mxv_sub(e[0], m.vertex(v[1]), m.vertex(v[0]), 3), 3);
+	mxv_unitize(mxv_sub(e[1], m.vertex(v[2]), m.vertex(v[1]), 3), 3);
+	mxv_unitize(mxv_sub(e[2], m.vertex(v[3]), m.vertex(v[2]), 3), 3);
+	mxv_unitize(mxv_sub(e[3], m.vertex(v[0]), m.vertex(v[3]), 3), 3);
+
+	float a_02 = (1-mxv_dot(e[0], e[3], 3)) + (1-mxv_dot(e[1], e[2], 3));
+	float a_13 = (1-mxv_dot(e[1], e[0], 3)) + (1-mxv_dot(e[3], e[2], 3));
+
+	if( a_02 <= a_13 )
+	{
+	    next_face++;  m.add_face(v[0], v[1], v[2]);
+	    next_face++;  m.add_face(v[0], v[2], v[3]);
+	}
+	else
+	{
+	    next_face++;  m.add_face(v[0], v[1], v[3]);
+	    next_face++;  m.add_face(v[1], v[2], v[3]);
+	}
+    }
+    else
+    {
+	mxmsg_signalf(MXMSG_WARN,
+		      "Input polygon #%d has more than 4 sides.  Ignoring it.",
+		      next_face);
+	
+	poly_count++;
+    }
+}
+
+////////////////////////////////////////////////////////////////////////
+
+bool MxSMFReader::execute_command(const MxCmd& cmd, void *closure)
+{
+    MxStdModel& m = *(MxStdModel *)closure;
+    int argc = cmd.phrases[0].length();
+    char **argv = (char **)&cmd.phrases[0][0];
+
+    cmd_entry *entry = &read_cmds[0];
+    bool handled = false;
+
+    while( entry->name && !handled )
+        if( streq(entry->name, cmd.op) )
+        {
+            (this->*(entry->cmd))(argc, argv, m);
+            handled = true;
+        }
+        else
+            entry++;
+
+    if( !handled )
+        if( !unparsed_hook || 
+            unparsed_hook && !(*unparsed_hook)(cmd.op, argc, argv, m) )
+        {
+            return false;
+        }
+
+    return true;
+}
+
+void MxSMFReader::parse_line(char *line, MxStdModel& m)
+{
+    MxCmdParser::parse_line(line, &m);
+}
+
+MxStdModel *MxSMFReader::read(istream& in, MxStdModel *m)
+{
+    if( !m )
+	m = new MxStdModel(8, 16);
+
+    begin(0, NULL, *m);
+    while( !in.eof() )
+    {
+	in >> ws;
+	if( in.peek() == '#' )
+	    in.ignore(SMF_MAXLINE, '\n');
+	else if( in.getline(line_buffer, SMF_MAXLINE, '\n').good() )
+	    parse_line(line_buffer, *m);
+    }
+    end(0, NULL, *m);
+
+    if( quad_count )
+	mxmsg_signalf(MXMSG_WARN,
+		      "Split %d input quadrilaterals.  "
+		      "Auto-splitting does not preserve properties!",
+		      quad_count);
+    if( poly_count )
+	mxmsg_signalf(MXMSG_WARN,
+		      "Ignored %d input polygons of more than 4 sides.",
+		      poly_count);
+
+
+    return m;
+}
+
+#ifndef MIX_ANSI_IOSTREAMS
+MxStdModel *MxSMFReader::read(int fd, MxStdModel *m)
+{
+    ifstream in(dup(fd));	// Duplicate handle will be closed on exit
+    return read(in, m);
+}
+#endif
+
+
+
+
+MxSMFWriter::MxSMFWriter()
+{
+    vertex_annotate = NULL;
+    face_annotate = NULL;
+}
+
+void MxSMFWriter::write(ostream& out, MxStdModel& m)
+{
+    unsigned int i;
+
+    out << "begin" << endl;
+
+    for(unsigned int v=0; v<m.vert_count(); v++)
+    {
+	// We must output all vertices since numbering is implicit
+	if( vertex_annotate )  (*vertex_annotate)(out, m, v);
+	out << m.vertex(v) << endl;
+    }
+
+    for(unsigned int f=0; f<m.face_count(); f++)
+	if( m.face_is_valid(f) )
+	{
+	    if( face_annotate ) (*face_annotate)(out, m, f);
+	    out << m.face(f) << endl;
+	}
+
+    if( m.normal_binding() != MX_UNBOUND )
+    {
+	out << "bind n " << m.binding_name(m.normal_binding()) << endl;
+	for(i=0; i<m.normal_count(); i++)
+	    out << m.normal(i) << endl;
+    }
+
+    if( m.color_binding() != MX_UNBOUND )
+    {
+	out << "bind c " << m.binding_name(m.color_binding()) << endl;
+	for(i=0; i<m.color_count(); i++)
+	    out << m.color(i) << endl;
+    }
+
+    if( m.texcoord_binding() != MX_UNBOUND )
+    {
+	out << "tex " << m.texmap_name() << endl;
+	out << "bind r " << m.binding_name(m.texcoord_binding()) << endl;
+	for(i=0; i<m.texcoord_count(); i++)
+	    out << m.texcoord(i) << endl;
+    }
+
+    out << "end" << endl;
+}
+
+#ifndef MIX_ANSI_IOSTREAMS
+void MxSMFWriter::write(int fd, MxStdModel& m)
+{
+    ofstream out(dup(fd));	// Duplicate handle will be closed on exit
+    write(out, m);
+}
+#endif
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/mixmops.cxx
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/mixmops.cxx	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/mixmops.cxx	(revision 1097)
@@ -0,0 +1,222 @@
+/************************************************************************
+
+  NxN Matrix class
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: mixmops.cxx,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "stdmix.h"
+#include "MxMatrix.h"
+
+// This section originally from Paul's matrix library.
+
+#define SWAP(a, b, t)   {t = a; a = b; b = t;}
+#define A(i,j) mxm_ref(_a, i, j, N)
+#define B(i,j) mxm_ref(_b, i, j, N)
+
+// Solve nxn system Ax=b.
+// Leaves solution x in b, and destroys original A and b vectors.
+// Return value is determinant of A.
+// If system is singular, returns 0 and leaves trash in b
+//
+// Uses Gaussian elimination with partial pivoting.
+//
+static
+double internal_solve(double *_a, double *b, const int N)
+{
+    int i, j, k;
+    double max, t, det, sum, pivot;
+
+    /*---------- forward elimination ----------*/
+
+    det = 1.0;
+    for (i=0; i<N; i++) {		/* eliminate in column i */
+	max = -1.0;
+	for (k=i; k<N; k++)		/* find pivot for column i */
+	    if (fabs(A(k, i)) > max) {
+		max = fabs(A(k, i));
+		j = k;
+	    }
+	if (max<=0.) return 0.0;	/* if no nonzero pivot, PUNT */
+	if (j!=i) {			/* swap rows i and j */
+	    for (k=i; k<N; k++)
+		SWAP(A(i, k), A(j, k), t);
+	    det = -det;
+	    SWAP(b[i], b[j], t);	/* swap elements of column vector */
+	}
+	pivot = A(i, i);
+	det *= pivot;
+	for (k=i+1; k<N; k++)		/* only do elems to right of pivot */
+	    A(i, k) /= pivot;
+
+	/* we know that A(i, i) will be set to 1, so don't bother to do it */
+	b[i] /= pivot;
+	for (j=i+1; j<N; j++) {		/* eliminate in rows below i */
+	    t = A(j, i);		/* we're gonna zero this guy */
+	    for (k=i+1; k<N; k++)	/* subtract scaled row i from row j */
+		A(j, k) -= A(i, k)*t;	/* (ignore k<=i, we know they're 0) */
+	    b[j] -= b[i]*t;
+	}
+    }
+
+    /*---------- back substitution ----------*/
+
+    for (i=N-1; i>=0; i--) {		/* solve for x[i] (put it in b[i]) */
+	sum = b[i];
+	for (k=i+1; k<N; k++)		/* really A(i, k)*x[k] */
+	    sum -= A(i, k)*b[k];
+	b[i] = sum;
+    }
+
+    return det;
+}
+
+// Returns determinant of a, and b=a inverse.
+// If matrix is singular, returns 0 and leaves trash in b.
+//
+// Uses Gaussian elimination with partial pivoting.
+//
+static
+double internal_invert(double *_a, double *_b, const int N)
+{
+    uint i, j, k;
+    double max, t, det, pivot;
+
+    /*---------- forward elimination ----------*/
+
+    for (i=0; i<N; i++)                 /* put identity matrix in B */
+        for (j=0; j<N; j++)
+            B(i, j) = (double)(i==j);
+
+    det = 1.0;
+    for (i=0; i<N; i++) {               /* eliminate in column i, below diag */
+        max = -1.;
+        for (k=i; k<N; k++)             /* find pivot for column i */
+            if (fabs(A(k, i)) > max) {
+                max = fabs(A(k, i));
+                j = k;
+            }
+        if (max<=0.) return 0.;         /* if no nonzero pivot, PUNT */
+        if (j!=i) {                     /* swap rows i and j */
+            for (k=i; k<N; k++)
+                SWAP(A(i, k), A(j, k), t);
+            for (k=0; k<N; k++)
+                SWAP(B(i, k), B(j, k), t);
+            det = -det;
+        }
+        pivot = A(i, i);
+        det *= pivot;
+        for (k=i+1; k<N; k++)           /* only do elems to right of pivot */
+            A(i, k) /= pivot;
+        for (k=0; k<N; k++)
+            B(i, k) /= pivot;
+        /* we know that A(i, i) will be set to 1, so don't bother to do it */
+
+        for (j=i+1; j<N; j++) {         /* eliminate in rows below i */
+            t = A(j, i);                /* we're gonna zero this guy */
+            for (k=i+1; k<N; k++)       /* subtract scaled row i from row j */
+                A(j, k) -= A(i, k)*t;   /* (ignore k<=i, we know they're 0) */
+            for (k=0; k<N; k++)
+                B(j, k) -= B(i, k)*t;
+        }
+    }
+
+    /*---------- backward elimination ----------*/
+
+    for (i=N-1; i>0; i--) {             /* eliminate in column i, above diag */
+        for (j=0; j<i; j++) {           /* eliminate in rows above i */
+            t = A(j, i);                /* we're gonna zero this guy */
+            for (k=0; k<N; k++)         /* subtract scaled row i from row j */
+                B(j, k) -= B(i, k)*t;
+        }
+    }
+
+    return det;
+}
+
+#undef A
+#undef B
+#undef SWAP
+
+float mxm_invert(float *r, const float *a, const int N)
+{
+    mxm_local_block(a2, double, N);
+    mxm_local_block(r2, double, N);
+
+    uint i;
+    for(i=0; i<N*N; i++) a2[i] = a[i];
+    float det = internal_invert(a2, r2, N);
+    for(i=0; i<N*N; i++) r[i] = r2[i];
+
+    mxm_free_local(a2);
+    mxm_free_local(r2);
+    return det;
+}
+
+double mxm_invert(double *r, const double *a, const int N)
+{
+    mxm_local_block(a2, double, N);
+    mxm_set(a2, a, N);
+    double det = internal_invert(a2, r, N);
+    mxm_free_local(a2);
+    return det;
+}
+
+double mxm_solve(double *x, const double *A, const double *b, const int N)
+{
+    mxm_local_block(a2, double, N);
+    mxm_set(a2, A, N);
+    mxv_set(x, b, N);
+    double det = internal_solve(a2, x, N);
+    mxm_free_local(a2);
+    return det;
+}
+
+// Originally based on public domain code by <Ajay_Shah@rand.org>
+// which can be found at http://lib.stat.cmu.edu/general/ajay
+//
+// The factorization is valid as long as the returned nullity == 0
+// U contains the upper triangular factor itself.
+//
+int mxm_cholesky(double *U, const double *A, const int N)
+{
+    double sum;
+
+    int nullity = 0;
+    mxm_set(U, 0.0, N);
+
+    for(int i=0; i<N; i++)
+    {
+	/* First compute U[i][i] */
+	sum = mxm_ref(A, i, i, N);
+
+	for(int j=0; j<=(i-1); j++)
+	    sum -= mxm_ref(U, j, i, N) * mxm_ref(U, j, i, N);
+
+	if( sum > 0 )
+	{
+	    mxm_ref(U, i, i, N) = sqrt(sum);
+
+	    /* Now find elements U[i][k], k > i. */
+	    for(int k=(i+1); k<N; k++)
+	    {
+		sum = mxm_ref(A, i, k, N);
+
+		for(int j=0; j<=(i-1); j++)
+		    sum -= mxm_ref(U, j, i, N)*mxm_ref(U, j, k, N);
+		
+		mxm_ref(U, i, k, N) = sum / mxm_ref(U, i, i, N);
+	    }
+	}
+	else
+	{
+	    for(int k=i; k<N; k++) mxm_ref(U, i, k, N) = 0.0;
+	    nullity++;
+	}
+    }
+
+    return nullity;
+}
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxLineModel.h
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxLineModel.h	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxLineModel.h	(revision 1097)
@@ -0,0 +1,96 @@
+#ifndef MXLINEMODEL_INCLUDED // -*- C++ -*-
+#define MXLINEMODEL_INCLUDED
+#if !defined(__GNUC__)
+#  pragma once
+#endif
+
+/************************************************************************
+
+  MxLineModel
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxLineModel.h,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "MxDynBlock.h"
+#include "MxGeoPrims.h"
+
+typedef MxFaceID MxSegmentID;
+
+class MxVertex2D : public MxEQ
+{
+public:
+    float pos[2];
+
+    MxVertex2D() { }
+    MxVertex2D(float x, float y) { pos[0]=x; pos[1]=y; }
+    MxVertex2D(const MxVertex2D& v) { *this = v; }
+
+    MxVertex2D& operator=(const MxVertex2D& v)
+	{ pos[0]=v.pos[0]; pos[1]=v.pos[1]; return *this; }
+
+    operator const float*() const { return pos; }
+    operator       float*()       { return pos; }
+#ifdef __GNUC__
+    float& operator[](int i)       { return pos[i]; }
+    float  operator[](int i) const { return pos[i]; }
+#endif
+};
+
+class MxSegment2D : public MxEQ
+{
+public:
+    MxVertexID v[2];
+
+    MxSegment2D() { }
+    MxSegment2D(MxVertexID v0, MxVertexID v1) { v[0]=v0; v[1]=v1; }
+    MxSegment2D(const MxSegment2D& s) { *this = s; }
+
+    MxSegment2D& operator=(const MxSegment2D& s)
+	{ v[0]=s.v[0]; v[1]=s.v[1]; return *this; }
+
+    MxVertexID& operator[](int i)       { return v[i]; }
+    MxVertexID  operator[](int i) const { return v[i]; }
+};
+
+inline ostream& operator<<(ostream& out, const MxVertex2D& v)
+{
+    return out << "v " << v[0] << " " << v[1];
+}
+
+inline ostream& operator<<(ostream& out, const MxSegment2D& s)
+{
+    return out << "l " << s[0]+1 << " " << s[1]+1;
+}
+
+
+class MxLineModel
+{
+private:
+    MxDynBlock<MxVertex2D> vertices;
+    MxDynBlock<MxSegment2D> segments;
+
+
+public:
+    MxLineModel(uint nvert, uint nseg) : vertices(nvert), segments(nseg)
+	{ }
+
+    uint vert_count() const { return vertices.length(); }
+    uint segment_count() const { return segments.length(); }
+
+    MxVertex2D&       vertex(uint i)       { return vertices(i); }
+    const MxVertex2D& vertex(uint i) const { return vertices(i); }
+    MxSegment2D&       segment(uint i)       { return segments(i); }
+    const MxSegment2D& segment(uint i) const { return segments(i); }
+
+    MxVertexID add_vertex(float, float);
+    MxFaceID add_segment(MxVertexID, MxVertexID);
+};
+
+
+
+
+// MXLINEMODEL_INCLUDED
+#endif
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/getopt1.c
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/getopt1.c	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/getopt1.c	(revision 1097)
@@ -0,0 +1,189 @@
+/* getopt_long and getopt_long_only entry points for GNU getopt.
+   Copyright (C) 1987,88,89,90,91,92,93,94,96,97 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "getopt.h"
+
+#if !defined (__STDC__) || !__STDC__
+/* This is a separate conditional since some stdc systems
+   reject `defined (const)'.  */
+#ifndef const
+#define const
+#endif
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+   actually compiling the library itself.  This code is part of the GNU C
+   Library, but also included in many other GNU distributions.  Compiling
+   and linking in this code is a waste when using the GNU C library
+   (especially if it is a shared library).  Rather than having every GNU
+   program understand `configure --with-gnu-libc' and omit the object files,
+   it is simpler to just do this in the source for each such file.  */
+
+#define GETOPT_INTERFACE_VERSION 2
+#if !defined (_LIBC) && defined (__GLIBC__) && __GLIBC__ >= 2
+#include <gnu-versions.h>
+#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
+#define ELIDE_CODE
+#endif
+#endif
+
+#ifndef ELIDE_CODE
+
+
+/* This needs to come after some library #include
+   to get __GNU_LIBRARY__ defined.  */
+#ifdef __GNU_LIBRARY__
+#include <stdlib.h>
+#endif
+
+#ifndef	NULL
+#define NULL 0
+#endif
+
+int
+getopt_long (argc, argv, options, long_options, opt_index)
+     int argc;
+     char *const *argv;
+     const char *options;
+     const struct option *long_options;
+     int *opt_index;
+{
+  return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
+}
+
+/* Like getopt_long, but '-' as well as '--' can indicate a long option.
+   If an option that starts with '-' (not '--') doesn't match a long option,
+   but does match a short option, it is parsed as a short option
+   instead.  */
+
+int
+getopt_long_only (argc, argv, options, long_options, opt_index)
+     int argc;
+     char *const *argv;
+     const char *options;
+     const struct option *long_options;
+     int *opt_index;
+{
+  return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
+}
+
+
+#endif	/* Not ELIDE_CODE.  */
+
+
+#ifdef TEST
+
+#include <stdio.h>
+
+int
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  int c;
+  int digit_optind = 0;
+
+  while (1)
+    {
+      int this_option_optind = optind ? optind : 1;
+      int option_index = 0;
+      static struct option long_options[] =
+      {
+	{"add", 1, 0, 0},
+	{"append", 0, 0, 0},
+	{"delete", 1, 0, 0},
+	{"verbose", 0, 0, 0},
+	{"create", 0, 0, 0},
+	{"file", 1, 0, 0},
+	{0, 0, 0, 0}
+      };
+
+      c = getopt_long (argc, argv, "abc:d:0123456789",
+		       long_options, &option_index);
+      if (c == -1)
+	break;
+
+      switch (c)
+	{
+	case 0:
+	  printf ("option %s", long_options[option_index].name);
+	  if (optarg)
+	    printf (" with arg %s", optarg);
+	  printf ("\n");
+	  break;
+
+	case '0':
+	case '1':
+	case '2':
+	case '3':
+	case '4':
+	case '5':
+	case '6':
+	case '7':
+	case '8':
+	case '9':
+	  if (digit_optind != 0 && digit_optind != this_option_optind)
+	    printf ("digits occur in two different argv-elements.\n");
+	  digit_optind = this_option_optind;
+	  printf ("option %c\n", c);
+	  break;
+
+	case 'a':
+	  printf ("option a\n");
+	  break;
+
+	case 'b':
+	  printf ("option b\n");
+	  break;
+
+	case 'c':
+	  printf ("option c with value `%s'\n", optarg);
+	  break;
+
+	case 'd':
+	  printf ("option d with value `%s'\n", optarg);
+	  break;
+
+	case '?':
+	  break;
+
+	default:
+	  printf ("?? getopt returned character code 0%o ??\n", c);
+	}
+    }
+
+  if (optind < argc)
+    {
+      printf ("non-option ARGV-elements: ");
+      while (optind < argc)
+	printf ("%s ", argv[optind++]);
+      printf ("\n");
+    }
+
+  exit (0);
+}
+
+#endif /* TEST */
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxRaster.cxx
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxRaster.cxx	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxRaster.cxx	(revision 1097)
@@ -0,0 +1,183 @@
+/************************************************************************
+
+  MxRaster
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxRaster.cxx,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "stdmix.h"
+#include "MxRaster.h"
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// Raster manipulation
+//
+
+// !!BUG: This could probably be made significantly faster.
+//
+void MxRaster::reverse(uint start, uint end)
+{
+    if(end >= length()) end = length() - channels();
+
+    uint i=start;
+    uint j=end;
+    unsigned char t;
+    
+    while(i<j)
+    {
+	for(uint k=0; k<channels(); k++)
+	{
+	    t=(*this)[i+k];
+	    (*this)[i+k] = (*this)[j+k];
+	    (*this)[j+k] = t;
+	}
+	i += channels();
+	j -= channels();
+    }
+}
+
+void MxRaster::hflip()
+{
+     uint i = 0;
+     uint j = channels()*(width()-1);
+
+     while( i<length() )
+     {
+	 reverse(i, i+j);
+	 i += j + channels();
+     }
+}
+
+void MxRaster::vflip()
+{
+    reverse();
+    hflip();
+}
+
+////////////////////////////////////////////////////////////////////////
+//
+// PNM output
+//
+ostream& pnm_write_header(ostream& out, const MxRaster& r, bool is_raw)
+{
+    return out << "P" << (is_raw?r.channels()*2:r.channels())
+	       << " " << r.width() << " " << r.height() << " 255" << endl;
+}
+
+ostream& pnm_write_data(ostream& out, const MxRaster& r, bool is_raw)
+{
+    if( is_raw )
+	out.write((const char *)(const unsigned char *)r, r.length());
+    else
+    {
+	for(uint i=0; i<r.length(); i++)
+	{
+	    out << (uint)(r[i]);
+	    if( i%6 ) out << " ";
+	    else      out << endl;
+	}
+    }
+
+    return out;
+}
+
+////////////////////////////////////////////////////////////////////////
+//
+// PNM input
+//
+static
+istream& pnm_skip(istream& in)
+{
+    for(;;)
+    {
+	in >> ws;
+	if( in.peek() == '#' )
+	    in.ignore(65535, '\n');
+	else
+	    return in;
+    }
+}
+
+static
+void pnm_read_ascii(istream& in, MxRaster& img)
+{
+    unsigned char *current = img;
+    uint val;
+
+    for(uint j=0; j<img.height(); j++) for(uint i=0; i<img.width(); i++)
+        for(uint k=0; k<img.channels(); k++)
+        {
+            pnm_skip(in) >> val;
+            *current++ = (unsigned char)val;
+        }
+}
+
+static
+void pnm_read_ascii(istream& in, MxRaster& img, float scale)
+{
+    unsigned char *current = img;
+    float val;
+
+    for(uint j=0; j<img.height(); j++) for(uint i=0; i<img.width(); i++)
+        for(uint k=0; k<img.channels(); k++)
+        {
+            pnm_skip(in) >> val;
+            *current++ = (unsigned char)(val*scale);
+        }
+}
+
+static
+void pnm_read_raw(istream& in, MxRaster& img)
+{
+    char c;  in.get(c);  // extract 1 whitespace character
+
+    //
+    // Is this guaranteed to read all the requested bytes?
+    //
+    in.read((char *)(unsigned char *)img, img.length());
+}
+
+MxRaster *pnm_read(istream& in)
+{
+    unsigned char P, N;
+
+    in >> P >> N;
+
+    if( P!='P' )  return NULL;
+
+    uint width, height, maxval;
+    pnm_skip(in) >> width;
+    pnm_skip(in) >> height;
+    pnm_skip(in) >> maxval;
+
+    bool is_raw = false;
+    uint channels = N - '0';
+    if( channels > 3 )
+    {
+	channels /= 2;
+	is_raw = true;
+    }
+
+    if( channels > 3 )  return NULL;
+
+    MxRaster *img = new MxRaster(width, height, channels);
+
+    if( is_raw )
+    {
+	if( maxval>255 )  return NULL;
+	if( maxval < 255 )
+	    mxmsg_signal(MXMSG_WARN, "Ignoring scaled raw PNM data.");
+
+	pnm_read_raw(in, *img);
+    }
+    else if( maxval==255 )
+	pnm_read_ascii(in, *img);
+    else
+	pnm_read_ascii(in, *img, 255.0f/(float)maxval);
+
+    return img;
+}
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxBlock2.h
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxBlock2.h	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxBlock2.h	(revision 1097)
@@ -0,0 +1,59 @@
+#ifndef MXBLOCK2_INCLUDED // -*- C++ -*-
+#define MXBLOCK2_INCLUDED
+#if !defined(__GNUC__)
+#  pragma once
+#endif
+
+/************************************************************************
+
+  MxBlock2 provides typed access to 2D data blocks.
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxBlock2.h,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "MxBlock.h"
+
+template<class T>
+class MxBlock2 : public MxBlock<T>
+{
+private:
+    uint W, H;
+
+protected:
+    MxBlock2() { }
+    void init_block(uint w, uint h)
+	{ W=w;  H=h;  MxBlock<T>::init_block(w*h); }
+    void resize_block(uint w, uint h)
+	{ W=w;  H=h;  MxBlock<T>::resize_block(w*h); }
+
+    T&       raw(uint i, uint j)       { return MxBlock<T>::raw(j*W+i); }
+    const T& raw(uint i, uint j) const { return MxBlock<T>::raw(j*W+i); }
+
+#define __MXCK(i,j) AssertBound(i<W); AssertBound(j<H)
+
+public:
+    // Exported constructors/destructors
+    // 
+    MxBlock2(uint w, uint h) { init_block(w,h); }
+
+    // Accessors
+    //
+    T&       ref(uint i, uint j)              { __MXCK(i,j); return raw(i,j); }
+    const T& ref(uint i, uint j) const        { __MXCK(i,j); return raw(i,j); }
+    T&       operator()(uint i, uint j)       { return ref(i,j); }
+    const T& operator()(uint i, uint j) const { return ref(i,j); }
+
+    uint width() const { return W; }
+    uint height() const { return H; }
+
+    void resize(uint w, uint h) { resize_block(w,h); }
+
+#undef __MXCK
+};
+
+
+// MXBLOCK2_INCLUDED
+#endif
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/mixcfg.h.in
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/mixcfg.h.in	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/mixcfg.h.in	(revision 1097)
@@ -0,0 +1,69 @@
+/* This -*- C -*- file is meant to be processed by the configure script */
+
+/* Some systems (eg. Debian GNU/Linux) put <forms.h> in <X11/forms.h>. */
+#undef MIX_USE_X11_FORMS
+
+/* Define this if your compiler doesn't support the new C++ 'bool' type */
+#undef MIX_NEED_BOOL
+
+/* Define if your system supports fabsf() */
+#undef MIX_HAVE_FABSF
+
+/* Define if your system supports rint() */
+#undef MIX_HAVE_RINT
+
+/* Define if your system supports getrusage() */
+#undef MIX_HAVE_GETRUSAGE
+
+/* Define if your system does not support getrusage() but supports times() */
+#undef MIX_HAVE_TIMES
+
+/* Define if your system supports random() as opposed to just rand() */
+#undef MIX_HAVE_RANDOM
+
+/* Define if your system uses/needs <unistd.h> */
+#undef HAVE_UNISTD_H
+
+/* Stuff determining the presence of support for alloca() */
+#undef HAVE_ALLOCA_H
+#undef HAVE_ALLOCA
+
+/* Define if ANSI Standard C++ Library iostreams are available and */
+/* you want to use them. */
+#undef MIX_ANSI_IOSTREAMS
+
+/* 
+   Global safety policy for MixKit software.
+
+   Safety levels:
+
+       -2 Reckless
+       -1 Optimized
+        0 Normal
+        1 Cautious
+        2 Paranoid
+
+*/
+#ifndef SAFETY
+#define SAFETY 0
+#endif
+
+/* Define if Sam Leffler's libtiff is available */
+#undef MIX_HAVE_LIBTIFF
+
+/* Define if libpng is available */
+#undef MIX_HAVE_LIBPNG
+
+/* ***** OpenGL configuration section ***** */
+
+/* Define to the name of OpenGL implementation (e.g., "OpenGL" or "Mesa") */
+#undef MIX_HAVE_OPENGL
+
+/* Define if glPolygonOffsetEXT is available */
+#undef MIX_HAVE_POLYOFFSET_EXT
+
+/* Define if glPolygonOffset is available */
+#undef MIX_HAVE_POLYOFFSET
+
+/* Define if glDrawArraysEXT is available */
+#undef MIX_HAVE_VERTARRAYS
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxGeom3D.h
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxGeom3D.h	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxGeom3D.h	(revision 1097)
@@ -0,0 +1,54 @@
+#ifndef MXGEOM3D_INCLUDED // -*- C++ -*-
+#define MXGEOM3D_INCLUDED
+#if !defined(__GNUC__)
+#  pragma once
+#endif
+
+/************************************************************************
+
+  Handy 3D geometrical primitives
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxGeom3D.h,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "MxVec3.h"
+#include "MxVec4.h"
+
+extern double triangle_area(const Vec3&, const Vec3&, const Vec3&);
+extern Vec3 triangle_raw_normal(const Vec3&, const Vec3&, const Vec3&);
+extern Vec3 triangle_normal(const Vec3&, const Vec3&, const Vec3&);
+extern Vec4 triangle_plane(const Vec3&, const Vec3&, const Vec3&);
+extern Vec4 triangle_raw_plane(const Vec3&, const Vec3&, const Vec3&);
+extern double triangle_compactness(const Vec3&, const Vec3&, const Vec3&);
+
+extern double triangle_project_point(const Vec3& v0, const Vec3& v1,
+				     const Vec3& v2, const Vec3& v,
+				     Vec3 *bary=NULL);
+
+extern void mx3d_box_corners(const Vec3& min, const Vec3& max, Vec3 *v);
+
+class MxBounds
+{
+public:
+
+    Vec3 min, max;
+    Vec3 center;
+    double radius;
+    unsigned int points;
+
+    void reset();
+    void add_point(const double *v, bool will_update=true);
+    void add_point(const float *v, bool will_update=true);
+    void complete();
+    void merge(const MxBounds&);
+
+    MxBounds() { reset(); }
+};
+
+
+
+// MXGEOM3D_INCLUDED
+#endif
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxStdSlim.h
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxStdSlim.h	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxStdSlim.h	(revision 1097)
@@ -0,0 +1,68 @@
+#ifndef MXSTDSLIM_INCLUDED // -*- C++ -*-
+#define MXSTDSLIM_INCLUDED
+#if !defined(__GNUC__)
+#  pragma once
+#endif
+
+/************************************************************************
+
+  Core simplification interface.  The MxStdSlim class defines the
+  interface which all simplification classes conform to.
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxStdSlim.h,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "MxStdModel.h"
+#include "MxHeap.h"
+
+#define MX_PLACE_ENDPOINTS 0
+#define MX_PLACE_ENDORMID  1
+#define MX_PLACE_LINE      2
+#define MX_PLACE_OPTIMAL   3
+
+#define MX_WEIGHT_UNIFORM       0
+#define MX_WEIGHT_AREA          1
+#define MX_WEIGHT_ANGLE         2
+#define MX_WEIGHT_AVERAGE       3
+#define MX_WEIGHT_AREA_AVG      4
+#define MX_WEIGHT_RAWNORMALS    5
+#define MX_WEIGHT_EDGE_ONLY		6
+
+class MxStdSlim
+{
+protected:
+    MxStdModel *m;
+    MxHeap heap;
+
+public:
+    unsigned int valid_verts;
+    unsigned int valid_faces;
+    bool is_initialized;
+
+    int placement_policy;
+    int weighting_policy;
+    bool will_join_only;
+
+    double boundary_weight;
+    double compactness_ratio;
+    double meshing_penalty;
+    double local_validity_threshold;
+    uint vertex_degree_limit;
+
+public:
+    MxStdSlim(MxStdModel *m0);
+
+  
+    virtual void initialize() = 0;
+    virtual bool decimate(uint) = 0;
+
+    MxStdModel& model() { return *m; }
+	MxHeap& GetHeap() { return heap; }
+
+};
+
+// MXSTDSLIM_INCLUDED
+#endif
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxQVis3.cxx
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxQVis3.cxx	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxQVis3.cxx	(revision 1097)
@@ -0,0 +1,160 @@
+/************************************************************************
+
+  Visualization of 3D quadric error metric
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxQVis3.cxx,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "stdmix.h"
+#include "MxGL.h"
+#include "MxQMetric3.h"
+#include "MxMatrix.h"
+
+class _QContext
+{
+public:
+
+    GLUquadricObj *quadric;
+
+    _QContext()
+	{
+	    quadric = gluNewQuadric();
+	    if( !quadric )
+		fatal_error("Unable to allocate GL quadric context.");
+
+	    gluQuadricNormals(quadric, (GLenum)GLU_SMOOTH);
+	    gluQuadricDrawStyle(quadric, (GLenum)GLU_FILL);
+	    gluQuadricOrientation(quadric, (GLenum)GLU_OUTSIDE);
+	}
+};
+
+
+//
+// NOTE:  This relies on C++ static constructors being called during
+//        initialization.  This may not work if the program is linked
+//        with a C compiler.
+//
+static _QContext context;
+
+static
+GLfloat colors[][4] = {
+    { 0.4f, 0.1f, 0.1f, 1.0f },
+    { 0.1f, 0.4f, 0.1f, 1.0f },
+    { 0.02f, 0.02f, 0.02f, 1.0f },
+};
+
+void mx_quadric_shading(int color, bool twosided)
+{
+    if( color < 1 ) color = 1;
+    if( color > 3 ) color = 3;
+
+    glEnable(GL_LIGHTING);
+    glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, twosided);
+
+    GLfloat mat_ambient[]  = { 0.1f, 0.1f, 0.1f, 1.0f };
+    glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mat_ambient);
+    glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 10.0f);
+    glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, colors[color-1]);
+    glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, colors[color-1]);
+}
+
+//
+// !!BUG: This procedure will not work if Q.offset()==0.
+//
+void mx_draw_quadric(const MxQuadric3& quadric, double radius, const float *v)
+{
+    Mat4 Q, Qh = quadric.homogeneous();
+
+    glMatrixMode(GL_MODELVIEW);
+    if( mxm_cholesky(Q, Qh, 4) == 0 )
+    {
+        glPushMatrix();
+
+        Mat4 N;
+        Q.invert(N);
+
+        glMultMatrix(N);
+        gluSphere(context.quadric, radius, 10, 10);
+        glPopMatrix();
+    }
+    else if( v )
+    {
+        glPushAttrib(GL_LIGHTING_BIT);
+	mx_quadric_shading(MX_RED_ELLIPSOIDS);
+
+        glPushMatrix();
+        glTranslated(v[X], v[Y], v[Z]);
+        gluSphere(context.quadric, 0.0025, 3, 3);
+        glPopMatrix();
+
+        glPopAttrib();
+    }
+}
+
+static
+void q_vertex(float k1, float k2, float x, float y)
+{
+    float g = sqrt(1 + k1*k1*x*x + k2*k2*y*y);
+    glNormal3f(-1/g, k1*x/g, k2*y/g);
+    glVertex3f(0.5*(k1*x*x + k2*y*y), x, y);
+}
+
+void mx_draw_osculant(float k1, float k2, float extent)
+{
+    int i,j;
+    int ring_count = 8;
+    int N = 12;
+
+    float dR = extent/ring_count; 
+    float R = dR;
+    float dT = 2*M_PI/N;
+    float theta;
+
+    glOffsetForMesh();
+    mx_quadric_shading(MX_GREEN_ELLIPSOIDS);
+
+    // Emit the central ring
+    glBegin(GL_TRIANGLE_FAN);
+      q_vertex(k1, k2, 0, 0);
+      for(j=0, theta=0; j<N; j++, theta+=dT)
+	  q_vertex(k1, k2, R*cos(theta), R*sin(theta));
+      q_vertex(k1, k2, R, 0);
+    glEnd();
+
+    for(i=1; i<ring_count; i++)
+    {
+	R += dR;
+	glBegin(GL_QUAD_STRIP);
+	for(j=0, theta=0; j<N; j++, theta+=dT)
+	{
+	    q_vertex(k1, k2, R*cos(theta), R*sin(theta));
+	    q_vertex(k1, k2, (R-dR)*cos(theta), (R-dR)*sin(theta));
+	}
+	q_vertex(k1, k2, R, 0);
+	q_vertex(k1, k2, R-dR, 0);
+	glEnd();
+    }
+
+    mx_quadric_shading(MX_CHARCOAL_ELLIPSOIDS);
+
+    glBegin(GL_LINE_STRIP);
+    for(i=0, R=0; i<=ring_count; i++, R+=dR)
+	q_vertex(k1, k2, R, 0);
+    glEnd();
+    glBegin(GL_LINE_STRIP);
+    for(i=0, R=0; i<=ring_count; i++, R+=dR)
+	q_vertex(k1, k2, -R, 0);
+    glEnd();
+    mx_quadric_shading(MX_RED_ELLIPSOIDS);
+    glBegin(GL_LINE_STRIP);
+    for(i=0, R=0; i<=ring_count; i++, R+=dR)
+	q_vertex(k1, k2, 0, R);
+    glEnd();
+    glBegin(GL_LINE_STRIP);
+    for(i=0, R=0; i<=ring_count; i++, R+=dR)
+	q_vertex(k1, k2, 0, -R);
+    glEnd();
+}
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxTimer.h
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxTimer.h	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxTimer.h	(revision 1097)
@@ -0,0 +1,22 @@
+#ifndef MXTIMER_INCLUDED // -*- C++ -*-
+#define MXTIMER_INCLUDED
+#if !defined(__GNUC__)
+#  pragma once
+#endif
+
+/************************************************************************
+
+  MxTimer
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxTimer.h,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#define MXTIME(t, cmd) { t=mx_get_time(); cmd; t=mx_get_time() - t; }
+
+extern double mx_get_time();
+
+// MXTIMER_INCLUDED
+#endif
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxGLPane.cxx
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxGLPane.cxx	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxGLPane.cxx	(revision 1097)
@@ -0,0 +1,729 @@
+/************************************************************************
+
+  MxGLPane
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxGLPane.cxx,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "stdmix.h"
+#include "mixio.h"
+#include "MxMath.h"
+#include "MxGLPane.h"
+
+uint mxgl_default_pane_width = 800;
+uint mxgl_default_pane_height = 600;
+
+#ifdef WIN32
+
+MxGLApp *MxGLApp::application = NULL;
+bool (*MxGLApp::init_hook)(MxGLApp *) = NULL;
+
+void MxGLApp::bind_pane(MxGLPane *pane, char *name)
+{
+    m_pMainWnd = pane;
+    pane->create(name);
+    m_pMainWnd->ShowWindow(m_nCmdShow);
+    m_pMainWnd->UpdateWindow();
+}
+
+const char *MxGLApp::query_filename(const char *prompt, const char *cwd,
+				    const char *filter, const char *default_name)
+{
+    static CString filename;
+    char *ext = strchr(filter, '.');
+    if( !ext ) ext = ""; else ext++;
+
+    CString converted_cwd(cwd);
+    for(int i=0; i<converted_cwd.GetLength(); i++)
+	if( converted_cwd[i] == '/' )  converted_cwd.SetAt(i, '\\');
+
+    CFileDialog dlg(true, ext, NULL,
+	OFN_HIDEREADONLY,
+	"||");
+    dlg.m_ofn.lpstrInitialDir = converted_cwd;
+
+    if( dlg.DoModal() == IDOK )
+    {
+	filename = dlg.GetPathName();
+	return filename;
+    }
+    else
+	return NULL;
+}
+
+#include "MxDynBlock.h"
+
+BOOL MxGLApp::InitInstance()
+{
+    bool result;
+
+    // Split command line into argc/argv 
+    MxDynBlock<char *> args(10);
+    char *cmdline = strdup(m_lpCmdLine);  // Don't modify original
+    const char *ws=" \t";
+    char *token = strtok(cmdline, ws);
+    while( token )
+    {
+	args.add(token);
+	token = strtok(NULL, ws);
+    }
+
+    argc = args.length() + 1;
+    argv = new char*[argc];
+    argv[0] = strdup(m_pszAppName);
+    for(int i=1; i<argc; i++) { argv[i]=args[i-1]; }
+
+    if( MxGLApp::init_hook )
+	result = (init_hook)(this);
+    else
+	result = application->init_application();
+
+    return (BOOL)result;    
+}
+
+
+BEGIN_MESSAGE_MAP(MxGLPane, CFrameWnd)
+    ON_WM_PAINT()
+    ON_WM_ERASEBKGND()
+    ON_WM_CREATE()
+    ON_WM_SIZE()
+    ON_WM_DESTROY()
+    ON_WM_LBUTTONDOWN()
+    ON_WM_LBUTTONUP()
+    ON_WM_RBUTTONDOWN()
+    ON_WM_RBUTTONUP()
+    ON_WM_MBUTTONDOWN()
+    ON_WM_MBUTTONUP()
+    ON_WM_MOUSEMOVE()
+    ON_WM_CHAR()
+    ON_WM_TIMER()
+END_MESSAGE_MAP()
+
+MxGLPane::MxGLPane()
+{
+    gl_context = NULL;
+    pixel_format = 0;
+    active_dc = NULL;
+
+    background_color[0] = 0.3f;
+    background_color[1] = 0.3f;
+    background_color[2] = 1.0f;
+}
+
+void MxGLPane::create(char *name)
+{
+    Create(NULL, name);
+}
+
+bool MxGLPane::create_glcontext(HDC hDC)
+{
+    gl_context = wglCreateContext(hDC);
+    if( !gl_context )
+	return false;
+
+    if( !wglMakeCurrent(hDC, gl_context) )
+	return false;
+
+    return true;
+}
+
+bool MxGLPane::set_pixel_format(HDC hDC)
+{
+    PIXELFORMATDESCRIPTOR pixelDesc;
+
+    //
+    // These are the important fields of the PFD
+    //
+    pixelDesc.nSize = sizeof(PIXELFORMATDESCRIPTOR);
+    pixelDesc.nVersion = 1;
+
+    pixelDesc.dwFlags =
+	PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL |
+	PFD_DOUBLEBUFFER | PFD_STEREO_DONTCARE;  
+    pixelDesc.iPixelType = PFD_TYPE_RGBA;
+    pixelDesc.cColorBits = 24;
+    pixelDesc.iLayerType = PFD_MAIN_PLANE;
+
+
+    //
+    // According to the docs, these can be/are ignored.
+    //
+    pixelDesc.cRedBits = 8;
+    pixelDesc.cRedShift = 16;
+    pixelDesc.cGreenBits = 8;
+    pixelDesc.cGreenShift = 8;
+    pixelDesc.cBlueBits = 8;
+    pixelDesc.cBlueShift = 0;
+    pixelDesc.cAlphaBits = 0;
+    pixelDesc.cAlphaShift = 0;
+    pixelDesc.cAccumBits = 0;	
+    pixelDesc.cAccumRedBits = 0;
+    pixelDesc.cAccumGreenBits = 0;
+    pixelDesc.cAccumBlueBits = 0;
+    pixelDesc.cAccumAlphaBits = 0;
+    pixelDesc.cDepthBits = 32;
+    pixelDesc.cStencilBits = 0;
+    pixelDesc.cAuxBuffers = 0;
+    pixelDesc.bReserved = 0;
+    pixelDesc.dwLayerMask = 0;
+    pixelDesc.dwVisibleMask = 0;
+    pixelDesc.dwDamageMask = 0;
+
+    pixel_format = ChoosePixelFormat(hDC, &pixelDesc);
+    if( !pixel_format )
+    {
+	// Try and guess a decent default pixel format
+	pixel_format = 1;
+	if( !DescribePixelFormat(hDC, pixel_format,
+				 sizeof(PIXELFORMATDESCRIPTOR), &pixelDesc) )
+	    return false;
+   }
+
+    if( !SetPixelFormat(hDC, pixel_format, &pixelDesc) )
+	return false;
+
+    return true;
+}
+
+BOOL MxGLPane::PreCreateWindow(CREATESTRUCT& cs)
+{
+    // Need to set special style requirements for OpenGL windows
+    cs.style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
+    return CFrameWnd::PreCreateWindow(cs);
+}
+
+int MxGLPane::OnCreate(LPCREATESTRUCT cs)
+{
+    if( CFrameWnd::OnCreate(cs) == -1 )
+	return -1;
+
+    HWND wnd = GetSafeHwnd();
+    HDC dc = ::GetDC(wnd);
+
+    if( !set_pixel_format(dc) )
+	MessageBox("Failed to set up proper pixel format.");
+    if( !create_glcontext(dc) )
+	MessageBox("Failed to create GL context.");
+
+    gl_init();
+
+    return 0;
+}
+
+void MxGLPane::OnDestroy()
+{
+    if( wglGetCurrentContext() )
+	wglMakeCurrent(NULL, NULL);
+
+    if( gl_context )
+    {
+	wglDeleteContext(gl_context);
+	gl_context = NULL;
+    }
+
+    CFrameWnd::OnDestroy();
+}
+
+void MxGLPane::OnSize(UINT /*type*/, int cx, int cy)
+{
+    size(cx, cy);
+}
+
+BOOL MxGLPane::OnEraseBkgnd(CDC *)
+{
+    return FALSE;   // Don't want background to be erased thank you
+}
+
+void MxGLPane::do_redraw(CDC& dc)
+{
+    make_current(dc.GetSafeHdc());
+    active_dc = &dc;
+    begin_redraw();
+    redraw();
+    end_redraw();
+    finish(dc.GetSafeHdc());
+    dc.SetBkMode(TRANSPARENT); // Draw over the scene image 
+    illustrate();
+    active_dc = NULL;
+}
+
+void MxGLPane::OnPaint()
+{
+    CPaintDC dc(this);
+    do_redraw(dc);
+}
+
+void MxGLPane::get_canvas_geometry(int *x, int *y, int *w, int *h)
+{
+    CRect rect;    
+
+    GetClientRect(rect);
+    if( x )  *x = rect.TopLeft().x;
+    if( y )  *y = rect.TopLeft().y;
+    if( w )  *w = rect.Width();
+    if( h )  *h = rect.Height();
+}
+
+void MxGLPane::draw_string(int x, int y, const char *str)
+{
+    if( active_dc )
+    {
+	active_dc->SetTextColor(fRGB(0.9f, 0.9f, 0.2f));
+	active_dc->TextOut(x, y, str, strlen(str));
+    }
+}
+
+void MxGLPane::require_redraw()
+{
+    CDC *dc = GetDC();
+    if( !dc ) return;  // Failed to get valid DC!
+
+    do_redraw(*dc);
+    ReleaseDC(dc);
+    
+    // Alternative implementation: just SendMessage(WM_PAINT)
+    // However, this doesn't quite turn out the way I'd like.
+    // For instance, the text drawn in illustrate() by QVis
+    // is not (always?) visible.
+}
+
+void MxGLPane::post_redraw()
+{
+    InvalidateRect(NULL, FALSE);
+}
+
+void MxGLPane::handle_mouse(int kind, UINT flags, CPoint point)
+{
+    int which = 0;
+
+    if( flags&MK_MBUTTON || (flags&MK_LBUTTON && flags&MK_RBUTTON) )
+	which = 2;
+    else if( flags&MK_LBUTTON )
+	which = 1;
+    else if( flags&MK_RBUTTON )
+	which = 3;
+
+    if( flags&MK_SHIFT )  kind |= MX_SHIFTKEY;
+    if( flags&MK_CONTROL) kind |= MX_CTRLKEY;
+    // Assume that the ALT modifier key is used by the system.
+
+    if( kind==MX_BUTTONDOWN )
+	SetCapture();
+    else if( kind==MX_BUTTONUP )
+	ReleaseCapture();
+    
+    button(kind, which, point.x, point.y);
+}
+
+void MxGLPane::OnLButtonDown(UINT flags, CPoint point)
+    { handle_mouse(MX_BUTTONDOWN, flags, point); }
+void MxGLPane::OnLButtonUp(UINT flags, CPoint point)
+    { handle_mouse(MX_BUTTONUP, flags, point); }
+void MxGLPane::OnRButtonDown(UINT flags, CPoint point)
+    { handle_mouse(MX_BUTTONDOWN, flags, point); }
+void MxGLPane::OnRButtonUp(UINT flags, CPoint point)
+    { handle_mouse(MX_BUTTONUP, flags, point); }
+void MxGLPane::OnMButtonDown(UINT flags, CPoint point)
+    { handle_mouse(MX_BUTTONDOWN, flags, point); }
+void MxGLPane::OnMButtonUp(UINT flags, CPoint point)
+    { handle_mouse(MX_BUTTONUP, flags, point); }
+void MxGLPane::OnMouseMove(UINT flags, CPoint point)
+    { handle_mouse(MX_POINTERMOTION, flags, point); }
+
+void MxGLPane::OnChar(UINT ch, UINT repcount, UINT flags)
+    { key(ch); }
+
+void MxGLPane::OnTimer(UINT timer_id)
+{
+    timer(timer_id);
+}
+
+unsigned int MxGLPane::add_timer(unsigned int id, unsigned int millisecs)
+{
+    return SetTimer(id, millisecs, NULL);
+}
+
+bool MxGLPane::remove_timer(unsigned int id)
+{
+    return KillTimer(id)>0;
+}
+
+#else
+
+static int GLXF_CFG_DOUBLEBUFFER[] =
+{
+    GLX_DOUBLEBUFFER,
+    GLX_RGBA,
+    GLX_RED_SIZE, 1,
+    GLX_GREEN_SIZE, 1,
+    GLX_BLUE_SIZE, 1,
+    GLX_DEPTH_SIZE, 1,
+    None
+};
+
+MxGLApp *MxGLApp::application = NULL;
+bool (*MxGLApp::init_hook)(MxGLApp *) = NULL;
+
+void MxGLApp::bind_pane(MxGLPane *pane, char *name)
+{
+    pane->create(name);
+    pane->make_current();
+}
+
+const char *MxGLApp::query_filename(const char *prompt,
+				    const char *cwd,
+				    const char *filter,
+				    const char *default_name)
+{
+    return fl_show_fselector(prompt, cwd, filter, default_name);
+}
+
+main(int argc, char **argv)
+{
+    if( !MxGLApp::application )
+	fatal_error("Fatal Error: No application instance defined.");
+
+    // I've disabled XForms command line parsing.  It was interfering
+    // with my own command line parsing, for some reason that I'm not
+    // entirely sure of.  It was screwing up the '-r' flag, when in fact,
+    // that isn't even one of the XForms command line arguments.  Go figure.
+    //
+    int fl_argc = 1;
+    char *fl_argv[2];  fl_argv[0]=argv[0];  fl_argv[1]=NULL;
+    fl_initialize(&fl_argc, fl_argv, "MxGLApp", 0, 0);
+    //fl_initialize(&argc, argv, "QVis", 0, 0);
+    fl_set_glcanvas_defaults(GLXF_CFG_DOUBLEBUFFER);
+
+    bool result;
+
+    MxGLApp::application->argc = argc;
+    MxGLApp::application->argv = argv;
+
+    if( MxGLApp::init_hook )
+	result = (*MxGLApp::init_hook)(MxGLApp::application);
+    else
+	result = MxGLApp::application->init_application();
+
+    if( !result )
+	fatal_error("Error during initialization ... Quitting.");
+
+    while( true )
+#if FL_INCLUDE_VERSION > 81
+	fl_check_forms();
+#else
+	fl_do_forms();
+#endif
+}
+
+
+MxGLPane::MxGLPane()
+{
+    gc = NULL;
+
+    background_color[0] = 0.3f;
+    background_color[1] = 0.3f;
+    background_color[2] = 1.0f;
+}
+
+MxGLPane::~MxGLPane()
+{
+    if( gc )
+	XFreeGC(fl_display, gc);
+}
+
+void MxGLPane::create(char *name, int *x, int *y, int *w, int *h)
+{
+    int W = mxgl_default_pane_width;
+    int H = mxgl_default_pane_height;
+
+    glpane = fl_bgn_form(FL_NO_BOX, W + 20, H + 20);
+    fl_add_box(FL_UP_BOX, 0, 0, W + 20, H + 20, "");
+    canvas = fl_add_glcanvas(FL_NORMAL_CANVAS, 10, 10, W, H, "");
+    fl_end_form();
+
+    //
+    // Pass back the canvas geometry we've set up
+    if( x ) *x = 10;   if( y ) *y = 10;
+    if( w ) *w = W;  if( h ) *h = H;
+
+    fl_add_canvas_handler(canvas, Expose, cb_expose, NULL);
+    fl_add_canvas_handler(canvas, MapNotify, cb_mapnotify, NULL);
+    fl_add_canvas_handler(canvas, ButtonPress, cb_button, NULL);
+    fl_add_canvas_handler(canvas, ButtonRelease, cb_button, NULL);
+    fl_add_canvas_handler(canvas, MotionNotify, cb_button, NULL);
+    fl_add_canvas_handler(canvas, KeyPress, cb_key, NULL);
+    fl_add_canvas_handler(canvas, ConfigureNotify, cb_configure, NULL);
+
+    glpane_for_form(glpane, this);
+    fl_set_form_position(glpane, 0, 0);
+    fl_show_form(glpane, FL_PLACE_CENTER|FL_FREE_SIZE, FL_FULLBORDER, name);
+}
+
+void MxGLPane::get_canvas_geometry(int *x, int *y, int *w, int *h)
+{
+    int junk;
+    fl_get_object_geometry(canvas, x?x:&junk, y?y:&junk, w?w:&junk, h?h:&junk);
+}
+
+void MxGLPane::glpane_for_form(FL_FORM *form, MxGLPane *pane)
+{
+    form->u_vdata = pane;
+}
+
+MxGLPane *MxGLPane::glpane_for_form(FL_FORM *form)
+{
+    return (MxGLPane *)form->u_vdata;
+}
+
+MxGLPane *MxGLPane::glpane_for_object(FL_OBJECT *obj)
+{
+    return glpane_for_form(obj->form);
+}
+
+static
+inline XColor *fRGB(XColor& c, float r, float g, float b)
+{
+    c.red   = (unsigned short)(r * 65535);
+    c.green = (unsigned short)(g * 65535);
+    c.blue  = (unsigned short)(b * 65535);
+    c.flags = DoRed|DoGreen|DoBlue;
+    return &c;
+}
+
+int MxGLPane::cb_mapnotify(FL_OBJECT *canvas, Window win, int, int,
+			   XEvent *, void *)
+{
+    MxGLPane *pane = glpane_for_object(canvas);
+
+
+    XWindowAttributes attribs;
+    XGetWindowAttributes(fl_display, win, &attribs);
+
+    XGCValues gcv;
+    gcv.font = XLoadFont(fl_display, "8x13");
+
+    XColor fg;
+    XAllocColor(fl_display, attribs.colormap, fRGB(fg, 0.9, 0.9, 0.2));
+    gcv.foreground = fg.pixel;
+
+
+    pane->gc = XCreateGC(fl_display, win, GCFont|GCForeground, &gcv);
+
+    pane->make_current();
+    pane->gl_init();
+    return 0;
+}
+
+int MxGLPane::cb_configure(FL_OBJECT *canvas, Window,
+			   int width , int height,
+			   XEvent *, void *)
+{
+    MxGLPane *pane = glpane_for_object(canvas);
+    pane->make_current();
+    pane->size(width, height);
+    return 0;
+}
+			   
+
+int MxGLPane::cb_expose(FL_OBJECT *canvas, Window,
+			int width, int height,
+			XEvent *, void *)
+{
+    MxGLPane *pane = glpane_for_object(canvas);
+
+    if( canvas->visible )
+    {
+	glViewport(0, 0, width, height);
+	pane->post_redraw();
+    }
+
+    return 0;
+}
+
+int MxGLPane::cb_button(FL_OBJECT *canvas, Window, int, int,
+			XEvent *event, void *)
+{
+    MxGLPane *pane = glpane_for_object(canvas);
+
+    int kind;
+    if( event->type == ButtonPress )
+	kind = MX_BUTTONDOWN;
+    else if( event->type == ButtonRelease )
+	kind = MX_BUTTONUP;
+    else
+	kind = MX_POINTERMOTION;
+    
+    if( event->xbutton.state & ShiftMask )  kind |= MX_SHIFTKEY;
+    if( event->xbutton.state & ControlMask )  kind |= MX_CTRLKEY;
+
+    pane->button(kind, event->xbutton.button,
+		 event->xbutton.x, event->xbutton.y);
+
+    return 0;
+}
+
+
+int MxGLPane::cb_key(FL_OBJECT *canvas, Window, int, int,
+		     XEvent *event, void *)
+{
+    MxGLPane *pane = glpane_for_object(canvas);
+
+    char c;
+    XLookupString(&event->xkey, &c, 1, NULL, NULL);
+    pane->key(c);
+
+    return 0;
+}
+
+void MxGLPane::post_redraw()
+{
+    make_current();
+
+    begin_redraw();
+    redraw();
+    end_redraw();
+
+    finish();
+
+    illustrate();
+
+    XFlush(fl_display);		// Cuts down a lot on flicker (not completely)
+    //XSync(fl_display, False); // No flicker, but a good bit slower
+}
+
+void MxGLPane::require_redraw()
+{
+    // Under X, we always do the redraw right away anyway
+    post_redraw();
+}
+
+#endif
+
+MxRaster *MxGLPane::grab_snapshot()
+{
+    // ??BUG: Is this necessary?  The problem is that make_current() does
+    //        not currently have a common cross-platform interface.
+    //make_current();
+
+    int x, y, w ,h; glGetViewport(&x, &y, &w, &h);
+
+    MxRaster *img = new MxRaster(w-x, h-y, 3);
+    glReadBuffer(GL_FRONT);
+    glReadPixels(x, y, w, h, GL_RGB, GL_UNSIGNED_BYTE, (unsigned char*)(*img));
+    img->vflip();
+
+    return img;
+}
+
+void MxGLPane::snapshot_ppm(const char *name)
+{
+    MxRaster *img = grab_snapshot();
+
+    const char *filename = 
+	MxGLApp::application->query_filename("Save PPM Snapshot", ".",
+					     "*.ppm", name?name:"snap.ppm");
+
+    if( filename )
+    {
+        ofstream out(filename);
+        pnm_write(out, *img);
+        out.close();
+    }
+
+    delete img;
+}
+
+void MxGLPane::snapshot_tiff(const char *name)
+{
+    MxRaster *img = grab_snapshot();
+
+    const char *filename = 
+	MxGLApp::application->query_filename("Save TIFF Snapshot", ".",
+					     "*.tif", name?name:"snap.tif");
+
+    if( filename )
+	if( !tiff_write(filename, *img) )
+	    mxmsg_signal(MXMSG_WARN,
+			 "Failed to write TIFF file.\n"
+			 "TIFF may not be supported.");
+
+    delete img;
+}
+
+////////////////////////////////////////////////////////////////////////
+//
+// Default handlers.  Note that these are platform independent.
+//
+
+void MxGLPane::gl_init()
+{
+    glEnable(GL_DEPTH_TEST);
+    glEnable(GL_LIGHTING);
+    glEnable(GL_NORMALIZE);
+    glShadeModel(GL_SMOOTH);
+
+
+    glMatrixMode(GL_PROJECTION);
+    // load anything?
+    glMatrixMode(GL_MODELVIEW);
+
+
+    GLfloat mat_ambient[] = { 0.1f, 0.1f, 0.1f, 1.0f };
+    GLfloat mat_diffuse[] = { 0.5f, 0.5f, 0.5f, 1.0f };
+    GLfloat mat_specular[] = { 0.1f, 0.1f, 0.1f, 1.0f };
+    glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mat_ambient);
+    glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_diffuse);
+    glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular);
+    glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, 40);
+
+    GLfloat light_pos[] = {0.0f, 0.0f, 1.0f, 0.0f};
+    glLightfv(GL_LIGHT0, GL_POSITION, light_pos);
+    glEnable(GL_LIGHT0);
+
+    glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
+    glEnable(GL_COLOR_MATERIAL);
+    glColor3f(0.5f, 0.5f, 0.5f);
+    glClearColor(background_color[0], background_color[1],
+		 background_color[2], 0.0f);
+}
+
+void MxGLPane::begin_redraw()
+{
+    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+    glColor3f(0.5f, 0.5f, 0.5f); // Enforce the default surface color
+}
+
+void MxGLPane::redraw()
+{
+
+}
+
+void MxGLPane::end_redraw()
+{
+
+}
+
+void MxGLPane::illustrate()
+{
+
+}
+
+void MxGLPane::key(char)
+{
+
+}
+
+void MxGLPane::button(int, int ,int, int)
+{
+
+}
+
+void MxGLPane::size(int width, int height)
+{
+    glViewport(0, 0, width, height);
+}
+
+void MxGLPane::timer(unsigned int) { }
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/Makefile
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/Makefile	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/Makefile	(revision 1097)
@@ -0,0 +1,47 @@
+#
+# Makefile for building the MixKit library
+# $Id: Makefile,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+#
+
+include ../mix-config
+
+CORE_SRCS = mixmsg.cxx MxTimer.cxx MxCmdParser.cxx MxAsp.cxx
+
+MATH_SRCS = MxMat2.cxx MxMat3.cxx MxMat4.cxx \
+            MxMat3-jacobi.cxx MxMat4-jacobi.cxx \
+	    MxGeom3D.cxx MxTriProject.cxx mixmops.cxx
+
+MODEL_SRCS = MxBlockModel.cxx MxStdModel.cxx MxSMF.cxx MxQMetric3.cxx \
+             MxQSlim.cxx MxStdSlim.cxx MxQMetric.cxx MxPropSlim.cxx \
+             MxEdgeFilter.cxx MxQMetric2.cxx MxLineModel.cxx
+
+DATA_SRCS = MxHeap.cxx MxRaster.cxx MxRaster-tiff.cxx
+
+# These modules require OpenGL or Mesa
+GL_SRCS = MxArcball.cxx MxCamera.cxx MxQVis3.cxx \
+          MxStdRender.cxx MxGLDebug.cxx MxGLUtils.cxx
+
+# These modules require XForms under X11 or MFC under Win32
+GUI_SRCS = MxGLPane.cxx MxStdPane.cxx 
+
+SRCS = $(CORE_SRCS) $(MATH_SRCS) $(MODEL_SRCS) $(DATA_SRCS) \
+       $(GL_SRCS) $(GUI_SRCS)
+
+OBJS = $(SRCS:.cxx=.o)
+
+########################################################################
+
+libmix.a: $(OBJS)
+	$(AR) cru libmix.a $(OBJS)
+	$(RANLIB) libmix.a
+
+clean:
+	-$(CLEAN)
+	-/bin/rm -f libmix.a
+	-cat /dev/null > Makefile.dep
+
+depend:
+	makedepend -f Makefile.dep -- $(ALL_CXXFLAGS) -- $(SRCS)
+
+-include Makefile.dep
+#sinclude Makefile.dep     # Alternative syntax for some makes
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxAsp.h
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxAsp.h	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxAsp.h	(revision 1097)
@@ -0,0 +1,132 @@
+#ifndef MXASP_INCLUDED // -*- C++ -*-
+#define MXASP_INCLUDED
+#if !defined(__GNUC__)
+#  pragma once
+#endif
+
+/************************************************************************
+
+  MxAsp
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxAsp.h,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "MxDynBlock.h"
+
+enum MxAspType
+{
+    MXASP_NULL=0,
+    MXASP_BOOL=1,
+    MXASP_INT=2,
+    MXASP_UINT=3,
+    MXASP_FLOAT=4,
+    MXASP_DOUBLE=5,
+    MXASP_PROC=6,
+    MXASP_USER_TYPE=7
+};
+
+class MxAspVar;
+class MxAspStore;
+
+typedef void (*MxAspProc)(MxAspVar *, MxAspStore *);
+
+struct MxAspProcDefn
+{
+    MxAspProc proc;
+    MxAspType arg_type;
+    uint args_expected;
+};
+
+
+class MxAspVar : public MxEQ
+{
+private:
+    MxAspType type;
+    union {
+	void    *any;
+	bool    *bool_var;
+	int     *int_var;
+	uint    *uint_var;
+	float   *float_var;
+	double  *double_var;
+	MxAspProcDefn *proc_var;
+    } as;
+
+    uint size;
+    uint flags;
+
+    char *name;
+
+protected:
+    void clear();
+
+public:
+    MxAspVar() { clear(); }
+    MxAspVar(const char *n,MxAspType t,void *v,uint len=1)
+	{ clear(); bind(n,t,v,len); }
+    ~MxAspVar() { unbind(); }
+
+    void bind(const char *, MxAspType, void *, uint len=1);
+    void unbind();
+
+    const char *nameof() const { return name; }
+    uint length() const { return size; }
+    MxAspType get_type() const { return type; }
+    ostream& print(ostream&) const;
+
+    void own_memory(bool);
+    bool is_memory_owned();
+
+#define mxasp_defset(V)  bool set_##V(V, uint i=0)
+    mxasp_defset(bool);
+    mxasp_defset(int);
+    mxasp_defset(uint);
+    mxasp_defset(float);
+    mxasp_defset(double);
+#undef mxasp_defset
+
+#define mxasp_defget(V)  V *get_##V(V *, uint i=0)
+    mxasp_defget(bool);
+    mxasp_defget(int);
+    mxasp_defget(uint);
+    mxasp_defget(float);
+    mxasp_defget(double);
+#undef mxasp_defget
+
+    bool read_from(const char *, uint i=0);
+    bool apply(int argc, const char **argv, MxAspStore *store);
+    bool apply(MxAspVar *arg, MxAspStore *store);
+};
+
+
+class MxAspStore
+{
+private:
+    MxDynBlock<MxAspVar> vars;
+
+public:
+    MxAspStore();
+
+    MxAspVar *lookup(const char *name) const;
+    MxAspVar *defvar(const char *name, MxAspType, void *, uint len=1);
+    MxAspVar *defun(const char *name, MxAspProc proc,
+		    MxAspType type=MXASP_NULL, uint expects=0);
+
+    bool execute_command(int argc, const char *cmd, const char **argv);
+
+    void write(ostream&);
+};
+
+inline ostream& operator<<(ostream& out, const MxAspVar& v)
+{ return out<<v.nameof()<<" ",v.print(out); }
+
+extern MxAspType mxasp_type_from_name(const char *);
+extern void *mxasp_alloc_value(MxAspType, uint size=1);
+extern void mxasp_apply(MxAspVar *proc, MxAspVar *arg, MxAspStore *store);
+extern void mxasp_apply(MxAspProc proc, MxAspVar *arg, MxAspStore *store);
+
+// MXASP_INCLUDED
+#endif
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxSMF.h
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxSMF.h	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxSMF.h	(revision 1097)
@@ -0,0 +1,106 @@
+#ifndef MXSMF_INCLUDED // -*- C++ -*-
+#define MXSMF_INCLUDED
+#if !defined(__GNUC__)
+#  pragma once
+#endif
+
+/************************************************************************
+
+  MxSMF
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxSMF.h,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+
+// Interim reader based on SMF 1.0
+// This reader is designed to create MxStdModel models
+
+#include "MxCmdParser.h"
+#include "MxStack.h"
+#include "MxStdModel.h"
+#include "MxMat4.h"
+
+class MxSMFReader : private MxCmdParser
+{
+public:
+    typedef void (MxSMFReader::*read_cmd)(int argc,
+					  char *argv[],
+					  MxStdModel& m);
+    struct cmd_entry { char *name; read_cmd cmd; };
+
+private:
+    MxStack<unsigned int> vfirst_stack;
+    MxStack<int> vcorrect_stack;
+    MxStack<Mat4> vx_stack;
+    MxStack<Mat4> tx_stack;
+    unsigned int next_vertex;
+    unsigned int next_face;
+
+    unsigned int quad_count;	// # of quadrilaterals in input
+    unsigned int poly_count;	// # of 5+ sided polygons in input
+
+    char *line_buffer;
+
+    static cmd_entry read_cmds[];
+
+private:
+    bool execute_command(const MxCmd&, void *closure);
+    void define_avars();
+    void update_avars();
+
+protected:
+    void v_xform(Vec3& v);
+    void t_xform(Vec2& v);
+    unsigned int vid_xform(int id);
+
+    void vertex(int argc, char *argv[], MxStdModel&);
+    void face(int argc, char *argv[], MxStdModel&);
+
+    void prop_bind(int argc, char *argv[], MxStdModel&);
+    void prop_normal(int argc, char *argv[], MxStdModel&);
+    void prop_color(int argc, char *argv[], MxStdModel&);
+    void prop_texcoord(int argc, char *argv[], MxStdModel&);
+    void read_texture(int argc, char *argv[], MxStdModel&);
+
+    void begin(int argc, char *argv[], MxStdModel&);
+    void end(int argc, char *argv[], MxStdModel&);
+    void trans(int argc, char *argv[], MxStdModel&);
+    void rot(int argc, char *argv[], MxStdModel&);
+    void scale(int argc, char *argv[], MxStdModel&);
+    void t_trans(int argc, char *argv[], MxStdModel&);
+    void t_scale(int argc, char *argv[], MxStdModel&);
+
+public:
+    MxSMFReader();
+    ~MxSMFReader();
+
+    bool (*unparsed_hook)(char *cmd, int argc, char *argv[], MxStdModel& m);
+
+    MxAspStore *asp_store() { return this->MxCmdParser::asp_store(); }
+
+    MxStdModel *read(istream& in, MxStdModel *model=NULL);
+#ifndef MIX_ANSI_IOSTREAMS
+    MxStdModel *read(int fd, MxStdModel *model=NULL);
+#endif
+    void parse_line(char *, MxStdModel&);
+};
+
+class MxSMFWriter
+{
+public:
+    MxSMFWriter();
+
+    void (*vertex_annotate)(ostream&, const MxStdModel&, MxVertexID);
+    void (*face_annotate)(ostream&, const MxStdModel&, MxVertexID);
+
+    void write(ostream& out, MxStdModel& m);
+#ifndef MIX_ANSI_IOSTREAMS
+    void write(int fd, MxStdModel& m);
+#endif
+};
+
+// MXSMF_INCLUDED
+#endif
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/mixmops.h
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/mixmops.h	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/mixmops.h	(revision 1097)
@@ -0,0 +1,153 @@
+#ifndef MIXMOPS_INCLUDED // -*- C++ -*-
+#define MIXMOPS_INCLUDED //
+#endif                   // WARNING:  Multiple inclusions allowed
+
+/************************************************************************
+
+  Low-level matrix math operations.
+
+  This header file is intended for internal library use only.  You should
+  understand what's going on in here before trying to use it yourself.
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: mixmops.h,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#ifdef MX_DEFAULT_DIM
+#  define __DIM const int N=MX_DEFAULT_DIM
+#else
+#  define __DIM const int N
+#endif
+
+#ifndef __T
+#  define __T double
+#endif
+
+#define forall(i, N) for(unsigned int i=0; i<N*N; i++)
+
+
+#define def3(name, op) inline __T *name(__T *r, const __T *a, const __T *b, __DIM) { forall(i,N) op; return r; }
+
+#define def2(name, op) inline __T *name(__T *r, const __T *a, __DIM) { forall(i,N) op; return r; }
+
+#define def1(name, op) inline __T *name(__T *r, __DIM) { forall(i,N) op; return r; }
+
+#define def2s(name, op) inline __T *name(__T *r, const __T *a, __T d, __DIM) { forall(i,N) op; return r; }
+
+#define def1s(name, op) inline __T *name(__T *r, __T d, __DIM) { forall(i,N) op; return r; }
+
+def3(mxm_add, r[i] = a[i] + b[i])
+def3(mxm_sub, r[i] = a[i] - b[i])
+
+def2(mxm_addinto, r[i] += a[i])
+def2(mxm_subfrom, r[i] -= a[i])
+
+def2(mxm_set, r[i] = a[i])
+def1(mxm_neg, r[i] = -r[i])
+def2(mxm_neg, r[i] = -a[i])
+
+def1s(mxm_set, r[i]=d)
+def1s(mxm_scale, r[i] *= d)
+def1s(mxm_invscale, r[i] /= d)
+def2s(mxm_scale, r[i] = a[i]*d)
+def2s(mxm_invscale, r[i] = a[i]/d)
+
+inline __T &mxm_ref(__T *A, uint i, uint j, __DIM) { return A[i*N + j]; }
+inline __T mxm_ref(const __T *A, uint i, uint j, __DIM) { return A[i*N + j]; }
+inline __T *mxm_row(__T *A, uint i, __DIM) { return A + i*N; }
+inline const __T *mxm_row(const __T *A, uint i, __DIM) { return A + i*N; }
+
+
+inline __T *mxm_identity(__T *A, __DIM)
+{
+    mxm_set(A, 0.0, N);
+    for(uint i=0; i<N; i++) mxm_ref(A, i, i, N) = 1.0;
+    return A;
+}
+
+inline __T *mxm_xform(__T *r, const __T *A, const __T *x, __DIM)
+{
+    const __T *a = A;
+    for(uint i=0; i<N; i++)
+    {
+	r[i] = 0.0;
+	for(uint j=0; j<N; j++)
+	    r[i] += (*a++) * x[j];
+    }
+    return r;
+}
+
+////////////////////////////////////////////////////////////////////////
+// The following couple of procedures are fairly straightforward but
+// rather inefficient. mxm_ref() provides an easy way to access the
+// (i,j) element of the matrix, but it's inefficient for looping over
+// all the elements.
+//
+inline __T *mxm_outerprod(__T *A, const __T *u, const __T *v, __DIM)
+{
+    for(uint i=0; i<N; i++) for(uint j=0; j<N; j++)
+	mxm_ref(A, i, j, N) = u[i] * v[j];
+    return A;
+}
+
+inline __T *mxm_mul(__T *r, const __T *a, const __T *b, __DIM)
+{
+    mxm_set(r, 0.0, N);
+
+    for(uint i=0; i<N; i++) for(uint j=0; j<N; j++)
+    {
+	for(uint k=0; k<N; k++)
+	    mxm_ref(r, i, j, N) += mxm_ref(a, i, k, N) * mxm_ref(b, k, j, N);
+    }
+
+    return r;
+}
+
+//
+// Only actually implemented for double (and maybe float).
+//
+extern __T mxm_invert(__T *r, const __T *a, __DIM);
+extern __T mxm_solve(__T *x, const __T *A, const __T *b, __DIM);
+extern int mxm_cholesky(__T *c, const __T *a, __DIM);
+
+inline ostream& mxm_write(ostream& out, const __T *a, __DIM)
+{
+    for(uint i=0; i<N; i++)
+    {
+	for(uint j=0; j<N; j++)
+	    out << mxm_ref(a, i, j, N) << " ";
+	out << endl;
+    }
+
+    return out;
+}
+inline ostream& mxm_write(const __T *a, __DIM) {return mxm_write(cout, a, N);}
+
+#ifndef mxm_local_block
+#ifdef __GNUC__
+#  define mxm_local_block(a,T,N)  T a[N*N]
+#  define mxm_free_local(a)
+#else
+#  ifdef HAVE_ALLOCA
+#    include <alloca.h>
+#    define mxm_local_block(a,T,N)  T *a = (T *)alloca(sizeof(T)*(N)*(N))
+#    define mxm_free_local(a)
+#  else
+#    define mxm_local_block(a,T,N)  T *a = new T[(N)*(N)]
+#    define mxm_free_local(a)       delete[] a
+#  endif
+#endif
+#endif
+
+#undef __T
+#undef __DIM
+#undef forall
+#undef def3
+#undef def2
+#undef def1
+#undef def2s
+#undef def1s
+
+// MIXMOPS_INCLUDED
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxMath.h
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxMath.h	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxMath.h	(revision 1097)
@@ -0,0 +1,67 @@
+#ifndef MXMATH_INCLUDED // -*- C++ -*-
+#define MXMATH_INCLUDED
+#if !defined(__GNUC__)
+#  pragma once
+#endif
+
+/************************************************************************
+
+  Standard math include file for the MixKit library.
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxMath.h,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include <math.h>
+
+// NOTE: The use of mx_real is deprecated, and the typedef will
+//       be going away in the near future.
+//
+#ifdef MIX_REAL_FLOAT
+typedef float mx_real;
+#else
+#define MIX_REAL_DOUBLE
+typedef double mx_real;
+#endif
+
+// Some systems use HUGE_VAL instead of HUGE
+#if !defined(HUGE) && defined(HUGE_VAL)
+#define HUGE HUGE_VAL
+#endif
+
+// Handle platforms, such as Win32, which don't define M_PI in <math.h>
+#ifndef M_PI
+#define M_PI 3.141592653589793238462643383279502884197169399375105820974944592308
+#endif
+
+#ifndef FEQ_EPS
+#define FEQ_EPS 1e-6
+#define FEQ_EPS2 1e-12
+#endif
+inline bool FEQ(double a,double b,double eps=FEQ_EPS) { return fabs(a-b)<eps; }
+inline bool FEQ2(double a,double b,double eps=FEQ_EPS2) {return fabs(a-b)<eps;}
+#ifdef MIX_HAVE_FABSF
+inline bool FEQ(float a,float b,float eps=FEQ_EPS) { return fabsf(a-b)<eps; }
+inline bool FEQ2(float a,float b,float eps=FEQ_EPS2) { return fabsf(a-b)<eps; }
+#endif
+
+#if defined(WIN32) || !defined(MIX_HAVE_RINT)
+inline double rint(double x) { return floor(x + 0.5); }
+#endif
+
+#ifdef MIX_HAVE_RANDOM
+inline double random1() { return (double)random() / (double)LONG_MAX; }
+inline char   random_byte() { return (char)(random() & 0xff); }
+#else
+inline double random1() { return (double)rand() / (double)RAND_MAX; }
+inline char   random_byte() { return (char)(rand() & 0xff); }
+#endif
+
+#ifndef MIX_NO_AXIS_NAMES
+enum Axis {X=0, Y=1, Z=2, W=3};
+#endif
+
+// MXMATH_INCLUDED
+#endif
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxVec2.h
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxVec2.h	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxVec2.h	(revision 1097)
@@ -0,0 +1,230 @@
+#ifndef MXVEC2_INCLUDED // -*- C++ -*-
+#define MXVEC2_INCLUDED
+#if !defined(__GNUC__)
+#  pragma once
+#endif
+
+/************************************************************************
+
+  2D Vector class
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxVec2.h,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "MxMath.h"
+
+#ifdef MIX_USE_TVEC
+#include "MxVector.h"
+
+template<class T>
+class MxTVec2 : public MxVBlock<T, 2>
+{
+public:
+    MxTVec2() { }
+    MxTVec2(T x, T y) { (*this)[0]=x; (*this)[1]=y; }
+    MxTVec2(const MxVBlock<T, 2>& v) : MxVBlock<T, 2>(v) { }
+    MxTVec2(const float *v) {(*this)[0]=v[0];(*this)[1]=v[1];}
+    MxTVec2(const double *v) {(*this)[0]=v[0];(*this)[1]=v[1];}
+};
+
+typedef MxTVec2<double> Vec2;
+
+
+#else
+
+class Vec2 {
+private:
+    double elt[2];
+
+protected:
+    inline void copy(const Vec2& v);
+
+public:
+    //
+    // Standard constructors
+    //
+    Vec2(double x=0, double y=0) { elt[0]=x; elt[1]=y; }
+    Vec2(const Vec2& v) { copy(v); }
+    Vec2(const float *v) { elt[0]=v[0]; elt[1]=v[1]; }
+    Vec2(const double *v) { elt[0]=v[0]; elt[1]=v[1]; }
+
+    //
+    // Access methods
+    //
+    double& operator()(uint i)       { AssertBound(i<2); return elt[i]; }
+    double  operator()(uint i) const { AssertBound(i<2); return elt[i]; }
+#ifdef __GNUC__
+    double& operator[](uint i)       { return elt[i]; }
+    double  operator[](uint i) const { return elt[i]; }
+#endif
+
+    operator double*() { return elt; }
+    operator const double*() const { return elt; }
+
+    //
+    // Comparison operators
+    //
+    inline bool operator==(const Vec2& v) const;
+    inline bool operator!=(const Vec2& v) const;
+
+    //
+    // Assignment and in-place arithmetic methods
+    //
+    inline void set(double x, double y) { elt[0]=x; elt[1]=y; }
+    inline Vec2& operator=(const Vec2& v);
+    inline Vec2& operator+=(const Vec2& v);
+    inline Vec2& operator-=(const Vec2& v);
+    inline Vec2& operator*=(double s);
+    inline Vec2& operator/=(double s);
+
+    //
+    // Binary arithmetic methods
+    //
+    inline Vec2 operator+(const Vec2& v) const;
+    inline Vec2 operator-(const Vec2& v) const;
+    inline Vec2 operator-() const;
+
+    inline Vec2 operator*(double s) const;
+    inline Vec2 operator/(double s) const;
+    inline double operator*(const Vec2& v) const;
+};
+
+
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// Method definitions
+//
+
+inline void Vec2::copy(const Vec2& v)
+{
+    elt[0]=v.elt[0]; elt[1]=v.elt[1];
+}
+
+inline bool Vec2::operator==(const Vec2& v) const
+{
+    double dx=elt[X]-v[X],  dy=elt[Y]-v[Y];
+    return (dx*dx + dy*dy) < FEQ_EPS2;
+}
+
+inline bool Vec2::operator!=(const Vec2& v) const
+{
+    double dx=elt[X]-v[X],  dy=elt[Y]-v[Y];
+    return (dx*dx + dy*dy) > FEQ_EPS2;
+}
+
+inline Vec2& Vec2::operator=(const Vec2& v)
+{
+    copy(v);
+    return *this;
+}
+
+inline Vec2& Vec2::operator+=(const Vec2& v)
+{
+    elt[0] += v[0];   elt[1] += v[1];
+    return *this;
+}
+
+inline Vec2& Vec2::operator-=(const Vec2& v)
+{
+    elt[0] -= v[0];   elt[1] -= v[1];
+    return *this;
+}
+
+inline Vec2& Vec2::operator*=(double s)
+{
+    elt[0] *= s;   elt[1] *= s;
+    return *this;
+}
+
+inline Vec2& Vec2::operator/=(double s)
+{
+    elt[0] /= s;   elt[1] /= s;
+    return *this;
+}
+
+inline Vec2 Vec2::operator+(const Vec2& v) const
+{
+    return Vec2(elt[0]+v[0], elt[1]+v[1]);
+}
+
+inline Vec2 Vec2::operator-(const Vec2& v) const
+{
+    return Vec2(elt[0]-v[0], elt[1]-v[1]);
+}
+
+inline Vec2 Vec2::operator-() const
+{
+    return Vec2(-elt[0], -elt[1]);
+}
+
+inline Vec2 Vec2::operator*(double s) const
+{
+    return Vec2(elt[0]*s, elt[1]*s);
+}
+
+inline Vec2 Vec2::operator/(double s) const
+{
+    return Vec2(elt[0]/s, elt[1]/s);
+}
+
+inline double Vec2::operator*(const Vec2& v) const
+{
+    return elt[0]*v[0] + elt[1]*v[1];
+}
+
+#endif
+
+// Make scalar multiplication commutative
+inline Vec2 operator*(double s, const Vec2& v) { return v*s; }
+
+
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// Primitive function definitions
+//
+
+inline double norm(const Vec2& v) { return sqrt(v[0]*v[0] + v[1]*v[1]); }
+inline double norm2(const Vec2& v) { return v[0]*v[0] + v[1]*v[1]; }
+
+inline double unitize(Vec2& v)
+{
+    double l=norm2(v);
+    if( l!=1.0 && l!=0.0 )
+    {
+	l = sqrt(l);
+	v /= l;
+    }
+    return l;
+}
+
+
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// Misc. function definitions
+//
+
+inline ostream& operator<<(ostream& out, const Vec2& v)
+{
+    return out << v[0] << " " << v[1];
+}
+
+inline istream& operator>>(istream& in, Vec2& v)
+{
+    return in >> v[0] >> v[1];
+}
+
+#ifdef MXGL_INCLUDED
+inline void glV(const Vec2& v) { glVertex2d(v[X], v[Y]); }
+#endif
+
+// MXVEC2_INCLUDED
+#endif
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxQSlim.cxx
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxQSlim.cxx	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxQSlim.cxx	(revision 1097)
@@ -0,0 +1,770 @@
+/************************************************************************
+
+  Surface simplification using quadric error metrics
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxQSlim.cxx,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "stdmix.h"
+#include "MxQSlim.h"
+#include "MxGeom3D.h"
+#include "MxVector.h"
+
+typedef MxQuadric3 Quadric;
+
+MxQSlim::MxQSlim(MxStdModel& _m)
+    : MxStdSlim(&_m),
+      quadrics(_m.vert_count())
+{
+    // Externally visible variables
+    object_transform = NULL;
+}
+
+void MxQSlim::initialize()
+{
+    collect_quadrics();
+    if( boundary_weight > 0.0 )
+	constrain_boundaries();
+    if( object_transform )
+	transform_quadrics(*object_transform);
+
+    is_initialized = true;
+}
+
+void MxQSlim::collect_quadrics()
+{
+    uint j;
+
+    for(j=0; j<quadrics.length(); j++)
+	quadrics(j).clear();
+
+    for(MxFaceID i=0; i<m->face_count(); i++)
+    {
+	MxFace& f = m->face(i);
+
+	Vec3 v1(m->vertex(f(0)));
+	Vec3 v2(m->vertex(f(1)));
+	Vec3 v3(m->vertex(f(2)));
+
+	Vec4 p = (weighting_policy==MX_WEIGHT_RAWNORMALS) ?
+		    triangle_raw_plane(v1, v2, v3):
+		    triangle_plane(v1, v2, v3);
+	Quadric Q(p[X], p[Y], p[Z], p[W], m->compute_face_area(i));
+
+	switch( weighting_policy )
+	{
+	case MX_WEIGHT_ANGLE:
+	    for(j=0; j<3; j++)
+	    {
+		Quadric Q_j = Q;
+		Q_j *= m->compute_corner_angle(i, j);
+		quadrics(f[j]) += Q_j;
+	    }
+	    break;
+	case MX_WEIGHT_AREA:
+	case MX_WEIGHT_AREA_AVG:
+	    Q *= Q.area();
+	    // no break: fallthrough
+	default:
+	    quadrics(f[0]) += Q;
+	    quadrics(f[1]) += Q;
+	    quadrics(f[2]) += Q;
+	    break;
+	}
+    }
+}
+
+void MxQSlim::transform_quadrics(const Mat4& P)
+{
+    for(uint j=0; j<quadrics.length(); j++)
+	quadrics(j).transform(P);
+}
+
+void MxQSlim::discontinuity_constraint(MxVertexID i, MxVertexID j,
+				       const MxFaceList& faces)
+{
+    for(uint f=0; f<faces.length(); f++)
+    {
+	Vec3 org(m->vertex(i)), dest(m->vertex(j));
+	Vec3 e = dest - org;
+
+	Vec3 n;
+	m->compute_face_normal(faces[f], n);
+
+	Vec3 n2 = e ^ n;
+	unitize(n2);
+
+	MxQuadric3 Q(n2, -(n2*org));
+	Q *= boundary_weight;
+
+	if( weighting_policy == MX_WEIGHT_AREA ||
+	    weighting_policy == MX_WEIGHT_AREA_AVG )
+	{
+	    Q.set_area(norm2(e));
+	    Q *= Q.area();
+	}
+
+	quadrics(i) += Q;
+	quadrics(j) += Q;
+    }
+}
+
+void MxQSlim::constrain_boundaries()
+{
+    MxVertexList star;
+    MxFaceList faces;
+
+    for(MxVertexID i=0; i<m->vert_count(); i++)
+    {
+	star.reset();
+	m->collect_vertex_star(i, star);
+
+	for(uint j=0; j<star.length(); j++)
+	    if( i < star(j) )
+	    {
+		faces.reset();
+		m->collect_edge_neighbors(i, star(j), faces);
+		if( faces.length() == 1 )
+		    discontinuity_constraint(i, star(j), faces);
+	    }
+    }
+}
+
+
+
+
+
+MxEdgeQSlim::MxEdgeQSlim(MxStdModel& _m)
+  : MxQSlim(_m),
+    edge_links(_m.vert_count())
+{
+    contraction_callback = NULL;
+}
+
+MxEdgeQSlim::~MxEdgeQSlim()
+{
+    // Delete everything remaining in the heap
+    for(uint i=0; i<heap.size(); i++)
+	delete ((MxQSlimEdge *)heap.item(i));
+}
+
+///////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT NOTE:  These check_xxx functions assume that the local
+//                  neighborhoods have been marked so that each face
+//                  is marked with the number of involved vertices it has.
+//
+
+double MxEdgeQSlim::check_local_compactness(uint v1, uint/*v2*/,
+					    const float *vnew)
+{
+    const MxFaceList& N1 = m->neighbors(v1);
+    double c_min = 1.0;
+
+    for(uint i=0; i<N1.length(); i++)
+	if( m->face_mark(N1[i]) == 1 )
+	{
+	    const MxFace& f = m->face(N1[i]);
+	    Vec3 f_after[3];
+	    for(uint j=0; j<3; j++)
+		f_after[j] = (f[j]==v1)?Vec3(vnew):Vec3(m->vertex(f[j]));
+
+	    double c=triangle_compactness(f_after[0], f_after[1], f_after[2]);
+
+	    if( c < c_min ) c_min = c;
+	}
+
+    return c_min;
+}
+
+double MxEdgeQSlim::check_local_inversion(uint v1,uint/*v2*/,const float *vnew)
+{
+    double Nmin = 1.0;
+    const MxFaceList& N1 = m->neighbors(v1);
+
+    for(uint i=0; i<N1.length(); i++)
+	if( m->face_mark(N1[i]) == 1 )
+	{
+	    const MxFace& f = m->face(N1[i]);
+	    Vec3 n_before;
+	    m->compute_face_normal(N1[i], n_before);
+
+	    Vec3 f_after[3];
+	    for(uint j=0; j<3; j++)
+		f_after[j] = (f[j]==v1)?Vec3(vnew):Vec3(m->vertex(f[j]));
+
+	    double delta = n_before *
+		triangle_normal(f_after[0], f_after[1], f_after[2]);
+
+	    if( delta < Nmin ) Nmin = delta;
+	}
+
+    return Nmin;
+}
+
+uint MxEdgeQSlim::check_local_validity(uint v1, uint /*v2*/, const float *vnew)
+
+{
+    const MxFaceList& N1 = m->neighbors(v1);
+    uint nfailed = 0;
+    uint i;
+
+    for(i=0; i<N1.length(); i++)
+	if( m->face_mark(N1[i]) == 1 )
+	{
+	    MxFace& f = m->face(N1[i]);
+	    uint k = f.find_vertex(v1);
+	    uint x = f[(k+1)%3];
+	    uint y = f[(k+2)%3];
+
+	    float d_yx[3], d_vx[3], d_vnew[3], f_n[3], n[3];
+	    mxv_sub(d_yx, m->vertex(y),  m->vertex(x), 3);   // d_yx = y-x
+	    mxv_sub(d_vx, m->vertex(v1), m->vertex(x), 3);   // d_vx = v-x
+	    mxv_sub(d_vnew, vnew, m->vertex(x), 3);          // d_vnew = vnew-x
+
+	    mxv_cross3(f_n, d_yx, d_vx);
+	    mxv_cross3(n, f_n, d_yx);     // n = ((y-x)^(v-x))^(y-x)
+	    mxv_unitize(n, 3);
+
+	    // assert( mxv_dot(d_vx, n, 3) > -FEQ_EPS );
+	    if(mxv_dot(d_vnew,n,3)<local_validity_threshold*mxv_dot(d_vx,n,3))
+		nfailed++;
+	}
+
+    return nfailed;
+}
+
+uint MxEdgeQSlim::check_local_degree(uint v1, uint v2, const float *)
+{
+    const MxFaceList& N1 = m->neighbors(v1);
+    const MxFaceList& N2 = m->neighbors(v2);
+    uint i;
+    uint degree = 0;
+
+    // Compute the degree of the vertex after contraction
+    //
+    for(i=0; i<N1.length(); i++)
+	if( m->face_mark(N1[i]) == 1 )
+	    degree++;
+
+    for(i=0; i<N2.length(); i++)
+	if( m->face_mark(N2[i]) == 1 )
+	    degree++;
+
+
+    if( degree > vertex_degree_limit )
+	return degree - vertex_degree_limit;
+    else
+	return 0;
+}
+
+void MxEdgeQSlim::apply_mesh_penalties(MxQSlimEdge *info)
+{
+    uint i;
+
+    const MxFaceList& N1 = m->neighbors(info->v1);
+    const MxFaceList& N2 = m->neighbors(info->v2);
+
+    // Set up the face marks as the check_xxx() functions expect.
+    //
+    for(i=0; i<N2.length(); i++) m->face_mark(N2[i], 0);
+    for(i=0; i<N1.length(); i++) m->face_mark(N1[i], 1);
+    for(i=0; i<N2.length(); i++) m->face_mark(N2[i], m->face_mark(N2[i])+1);
+
+    double base_error = info->heap_key();
+    double bias = 0.0;
+    
+    // Check for excess over degree bounds.
+    //
+    uint max_degree = MAX(N1.length(), N2.length());
+    if( max_degree > vertex_degree_limit )
+	bias += (max_degree-vertex_degree_limit) * meshing_penalty * 0.001;
+
+#if ALTERNATE_DEGREE_BIAS
+    // ??BUG:  This code was supposed to be a slight improvement over
+    //         the earlier version above.  But it performs worse.
+    //         Should check into why sometime.
+    //
+    uint degree_excess = check_local_degree(info->v1, info->v2, info->vnew);
+    if( degree_excess )
+ 	bias += degree_excess * meshing_penalty;
+#endif
+
+    // Local validity checks
+    //
+    uint nfailed = check_local_validity(info->v1, info->v2, info->vnew);
+    nfailed += check_local_validity(info->v2, info->v1, info->vnew);
+    if( nfailed )
+	bias += nfailed*meshing_penalty;
+
+    if( compactness_ratio > 0.0 )
+    {
+	double c1_min=check_local_compactness(info->v1, info->v2, info->vnew);
+	double c2_min=check_local_compactness(info->v2, info->v1, info->vnew);
+	double c_min = MIN(c1_min, c2_min);
+
+	// !!BUG: There's a small problem with this: it ignores the scale
+	//        of the errors when adding the bias.  For instance, enabling
+	//        this on the cow produces bad results.  I also tried
+	//        += (base_error + FEQ_EPS) * (2-c_min), but that works
+	//        poorly on the flat planar thing.  A better solution is
+	//        clearly needed.
+	//
+	//  NOTE: The prior heuristic was
+	//        if( ratio*cmin_before > cmin_after ) apply penalty;
+	//
+	if( c_min < compactness_ratio )
+	    bias += (1-c_min);
+    }
+
+#if USE_OLD_INVERSION_CHECK
+    double Nmin1 = check_local_inversion(info->v1, info->v2, info->vnew);
+    double Nmin2 = check_local_inversion(info->v2, info->v1, info->vnew);
+    if( MIN(Nmin1, Nmin2) < 0.0 )
+	bias += meshing_penalty;
+#endif
+
+    info->heap_key(base_error - bias);
+}
+
+void MxEdgeQSlim::compute_target_placement(MxQSlimEdge *info)
+{
+    MxVertexID i=info->v1, j=info->v2;
+
+    const Quadric &Qi=quadrics(i), &Qj=quadrics(j);
+
+    Quadric Q = Qi;  Q += Qj;
+    double e_min;
+
+    if( placement_policy==MX_PLACE_OPTIMAL &&
+	Q.optimize(&info->vnew[X], &info->vnew[Y], &info->vnew[Z]) )
+    {
+	e_min = Q(info->vnew);
+    }
+    else
+    {
+	Vec3 vi(m->vertex(i)), vj(m->vertex(j));	
+	Vec3 best;
+
+	if( placement_policy>=MX_PLACE_LINE && Q.optimize(best, vi, vj) )
+	    e_min = Q(best);
+	else
+	{
+	    double ei=Q(vi), ej=Q(vj);
+
+	    if( ei < ej ) { e_min = ei; best = vi; }
+	    else          { e_min = ej; best = vj; }
+
+	    if( placement_policy>=MX_PLACE_ENDORMID )
+	    {
+		Vec3 mid = (vi+vj)/2;
+		double e_mid = Q(mid);
+
+		if( e_mid < e_min ) { e_min = e_mid; best = mid; }
+	    }
+	}
+
+	info->vnew[X] = best[X];
+	info->vnew[Y] = best[Y];
+	info->vnew[Z] = best[Z];
+    }
+
+    if( weighting_policy == MX_WEIGHT_AREA_AVG )
+ 	e_min /= Q.area();
+
+
+    if ( weighting_policy == MX_WEIGHT_EDGE_ONLY )
+    {
+	Vec3 vi(m->vertex(i)), vj(m->vertex(j));
+	e_min = norm2(vi - vj);
+    }
+
+
+    info->heap_key(-e_min);
+}
+
+/*
+void MxEdgeQSlim::compute_target_placement(MxQSlimEdge *info)
+{
+    MxVertexID i=info->v1, j=info->v2;
+
+    const Quadric &Qi=quadrics(i), &Qj=quadrics(j);
+
+    Quadric Q = Qi;  Q += Qj;
+    double e_min;
+
+    if( placement_policy==MX_PLACE_OPTIMAL &&
+	Q.optimize(&info->vnew[X], &info->vnew[Y], &info->vnew[Z]) )
+    {
+	e_min = Q(info->vnew);
+    }
+    else
+    {
+	Vec3 vi(m->vertex(i)), vj(m->vertex(j));	
+	Vec3 best;
+
+	if( placement_policy>=MX_PLACE_LINE && Q.optimize(best, vi, vj) )
+	    e_min = Q(best);
+	else
+	{
+	    double ei=Q(vi), ej=Q(vj);
+
+	    if( ei < ej ) { e_min = ei; best = vi; }
+	    else          { e_min = ej; best = vj; }
+
+	    if( placement_policy>=MX_PLACE_ENDORMID )
+	    {
+		Vec3 mid = (vi+vj)/2;
+		double e_mid = Q(mid);
+
+		if( e_mid < e_min ) { e_min = e_mid; best = mid; }
+	    }
+	}
+
+	info->vnew[X] = best[X];
+	info->vnew[Y] = best[Y];
+	info->vnew[Z] = best[Z];
+    }
+
+    if( weighting_policy == MX_WEIGHT_AREA_AVG )
+ 	e_min /= Q.area();
+
+    info->heap_key(-e_min);
+}
+*/
+
+void MxEdgeQSlim::finalize_edge_update(MxQSlimEdge *info)
+{
+    if( meshing_penalty > 1.0 )
+	apply_mesh_penalties(info);
+
+    if( info->is_in_heap() )
+	heap.update(info);
+    else
+	heap.insert(info);
+}
+
+
+void MxEdgeQSlim::compute_edge_info(MxQSlimEdge *info)
+{
+    compute_target_placement(info);
+
+    finalize_edge_update(info);
+}
+
+void MxEdgeQSlim::create_edge(MxVertexID i, MxVertexID j)
+{
+    MxQSlimEdge *info = new MxQSlimEdge;
+
+    edge_links(i).add(info);
+    edge_links(j).add(info);
+
+    info->v1 = i;
+    info->v2 = j;
+
+    compute_edge_info(info);
+}
+
+void MxEdgeQSlim::collect_edges()
+{
+    MxVertexList star;
+
+    for(MxVertexID i=0; i<m->vert_count(); i++)
+    {
+	star.reset();
+	m->collect_vertex_star(i, star);
+
+	for(uint j=0; j<star.length(); j++)
+	    if( i < star(j) )  // Only add particular edge once
+		create_edge(i, star(j));
+    }
+}
+
+void MxEdgeQSlim::initialize()
+{
+    MxQSlim::initialize();
+    collect_edges();
+}
+
+void MxEdgeQSlim::initialize(const MxEdge *edges, uint count)
+{
+    MxQSlim::initialize();
+    for(uint i=0; i<count; i++)
+	create_edge(edges[i].v1, edges[i].v2);
+}
+
+void MxEdgeQSlim::update_pre_contract(const MxPairContraction& conx)
+{
+    MxVertexID v1=conx.v1, v2=conx.v2;
+    uint i, j;
+
+    star.reset();
+    //
+    // Before, I was gathering the vertex "star" using:
+    //      m->collect_vertex_star(v1, star);
+    // This doesn't work when we initially begin with a subset of
+    // the total edges.  Instead, we need to collect the "star"
+    // from the edge links maintained at v1.
+    //
+    for(i=0; i<edge_links(v1).length(); i++)
+	star.add(edge_links(v1)[i]->opposite_vertex(v1));
+
+    for(i=0; i<edge_links(v2).length(); i++)
+    {
+	MxQSlimEdge *e = edge_links(v2)(i);
+	MxVertexID u = (e->v1==v2)?e->v2:e->v1;
+	SanityCheck( e->v1==v2 || e->v2==v2 );
+	SanityCheck( u!=v2 );
+
+	if( u==v1 || star.find(u) )
+	{
+	    // This is a useless link --- kill it
+	    bool found = edge_links(u).find(e, &j);
+	    assert( found );
+	    edge_links(u).remove(j);
+	    heap.remove(e);
+	    if( u!=v1 ) delete e; // (v1,v2) will be deleted later
+	}
+	else
+	{
+	    // Relink this to v1
+	    e->v1 = v1;
+	    e->v2 = u;
+	    edge_links(v1).add(e);
+	}
+    }
+
+    edge_links(v2).reset();
+}
+
+void MxEdgeQSlim::update_post_contract(const MxPairContraction& conx)
+{
+}
+
+void MxEdgeQSlim::apply_contraction(const MxPairContraction& conx)
+{
+    //
+    // Pre-contraction update
+    valid_verts--;
+    valid_faces -= conx.dead_faces.length();
+    quadrics(conx.v1) += quadrics(conx.v2);
+
+    update_pre_contract(conx);
+
+    m->apply_contraction(conx);
+
+    update_post_contract(conx);
+
+    // Must update edge info here so that the meshing penalties
+    // will be computed with respect to the new mesh rather than the old
+    for(uint i=0; i<edge_links(conx.v1).length(); i++)
+	compute_edge_info(edge_links(conx.v1)[i]);
+}
+
+void MxEdgeQSlim::update_pre_expand(const MxPairContraction&)
+{
+}
+
+void MxEdgeQSlim::update_post_expand(const MxPairContraction& conx)
+{
+    MxVertexID v1=conx.v1, v2=conx.v2;
+    uint i;
+
+    star.reset(); star2.reset();
+    PRECAUTION(edge_links(conx.v2).reset());
+    m->collect_vertex_star(conx.v1, star);
+    m->collect_vertex_star(conx.v2, star2);
+
+    i = 0;
+    while( i<edge_links(v1).length() )
+    {
+	MxQSlimEdge *e = edge_links(v1)(i);
+	MxVertexID u = (e->v1==v1)?e->v2:e->v1;
+	SanityCheck( e->v1==v1 || e->v2==v1 );
+	SanityCheck( u!=v1 && u!=v2 );
+
+	bool v1_linked = star.find(u);
+	bool v2_linked = star2.find(u);
+
+	if( v1_linked )
+	{
+	    if( v2_linked )  create_edge(v2, u);
+	    i++;
+	}
+	else
+	{
+	    // !! BUG: I expected this to be true, but it's not.
+	    //         Need to find out why, and whether it's my
+	    //         expectation or the code that's wrong.
+	    // SanityCheck(v2_linked);
+	    e->v1 = v2;
+	    e->v2 = u;
+	    edge_links(v2).add(e);
+	    edge_links(v1).remove(i);
+	}
+
+	compute_edge_info(e);
+    }
+
+    if( star.find(v2) )
+	// ?? BUG: Is it legitimate for there not to be an edge here ??
+	create_edge(v1, v2);
+}
+
+
+void MxEdgeQSlim::apply_expansion(const MxPairContraction& conx)
+{
+    update_pre_expand(conx);
+
+    m->apply_expansion(conx);
+
+    //
+    // Post-expansion update
+    valid_verts++;
+    valid_faces += conx.dead_faces.length();
+    quadrics(conx.v1) -= quadrics(conx.v2);
+
+    update_post_expand(conx);
+}
+
+bool MxEdgeQSlim::decimate(uint target)
+{
+    MxPairContraction local_conx;
+
+    while( valid_faces > target )
+    {
+	MxQSlimEdge *info = (MxQSlimEdge *)heap.extract();
+	if( !info ) { return false; }
+
+	MxVertexID v1=info->v1, v2=info->v2;
+
+	if( m->vertex_is_valid(v1) && m->vertex_is_valid(v2) )
+	{
+	    MxPairContraction& conx = local_conx;
+
+	    m->compute_contraction(v1, v2, &conx, info->vnew);
+
+	    if( will_join_only && conx.dead_faces.length()>0 ) continue;
+
+	    if( contraction_callback )
+ 			(*contraction_callback)(conx, -info->heap_key());
+	    
+	    apply_contraction(conx);
+	}
+
+	delete info;
+    }
+
+    return true;
+}
+
+
+
+
+void MxFaceQSlim::compute_face_info(MxFaceID f)
+{
+    tri_info& info = f_info(f);
+    info.f = f;
+
+    MxVertexID i = m->face(f)(0);
+    MxVertexID j = m->face(f)(1);
+    MxVertexID k = m->face(f)(2);
+
+    const Quadric& Qi = quadrics(i);
+    const Quadric& Qj = quadrics(j);
+    const Quadric& Qk = quadrics(k);
+
+    Quadric Q = Qi;
+    Q += Qj;
+    Q += Qk;
+
+    if( placement_policy == MX_PLACE_OPTIMAL &&
+	Q.optimize(&info.vnew[X], &info.vnew[Y], &info.vnew[Z]) )
+    {
+      info.heap_key(-Q(info.vnew));
+    }
+    else
+    {
+      Vec3 v1(m->vertex(i)), v2(m->vertex(j)), v3(m->vertex(k));
+      double e1=Q(v1), e2=Q(v2), e3=Q(v3);
+
+      Vec3 best;
+      double e_min;
+
+      if( e1<=e2 && e1<=e3 ) { e_min=e1; best=v1; }
+      else if( e2<=e1 && e2<=e3 ) { e_min=e2; best=v2; }
+      else { e_min=e3; best=v3; }
+
+      info.vnew[X] = best[X];
+      info.vnew[Y] = best[Y];
+      info.vnew[Z] = best[Z];
+      info.heap_key(-e_min);
+    }
+
+    if( weighting_policy == MX_WEIGHT_AREA_AVG )
+	info.heap_key(info.heap_key() / Q.area());
+
+    if( info.is_in_heap() )
+	heap.update(&info);
+    else
+	heap.insert(&info);
+}
+
+
+MxFaceQSlim::MxFaceQSlim(MxStdModel& _m)
+  : MxQSlim(_m), f_info(_m.face_count())
+{
+}
+
+void MxFaceQSlim::initialize()
+{
+    MxQSlim::initialize();
+
+    for(MxFaceID f=0; f<m->face_count(); f++)
+      compute_face_info(f);
+}
+
+bool MxFaceQSlim::decimate(uint target)
+{
+    unsigned int i;
+
+    MxFaceList changed;
+
+    while( valid_faces > target )
+    {
+	tri_info *info = (tri_info *)heap.extract();
+	if( !info ) { return false; }
+
+	MxFaceID f = info->f;
+	MxVertexID v1 = m->face(f)(0),
+	  v2 = m->face(f)(1),
+	  v3 = m->face(f)(2);
+
+	if( m->face_is_valid(f) )
+	{
+	    //
+	    // Perform the actual contractions
+	    m->contract(v1, v2, v3, info->vnew, changed);
+
+	    quadrics(v1) += quadrics(v2);  	// update quadric of v1
+	    quadrics(v1) += quadrics(v3);
+
+	    //
+	    // Update valid counts
+	    valid_verts -= 2;
+	    for(i=0; i<changed.length(); i++)
+		if( !m->face_is_valid(changed(i)) ) valid_faces--;
+
+	    for(i=0; i<changed.length(); i++)
+		if( m->face_is_valid(changed(i)) )
+		    compute_face_info(changed(i));
+		else
+		    heap.remove(&f_info(changed(i)));
+	}
+    }
+
+    return true;
+}
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxTriProject.cxx
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxTriProject.cxx	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxTriProject.cxx	(revision 1097)
@@ -0,0 +1,166 @@
+/************************************************************************
+
+  Code for projecting points onto the nearest point of a triangle.
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxTriProject.cxx,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+/*
+ * The projection code in this file was originally due to Hugues Hoppe
+ * and was distributed under the following terms:
+ *
+ *      Copyright (c) 1992, 1993, 1994, Hugues Hoppe, University of Washington.
+ *      Copying, use, and development for non-commercial purposes permitted.
+ *                       All rights for commercial use reserved.
+ *
+ * Anoop Bhattacharjya <anoop@epal.smos.com> made some small changes.
+ *
+ * I made some small modifications, primarily to fix some C++ const-related
+ * issues.  I've also added my own interface to the code.  My intention is
+ * to rewrite it at some point, but at the moment, I have other things to do.
+ * 
+ *
+ *      - Michael Garland
+ *
+ */
+
+#include "stdmix.h"
+#include "MxGeom3D.h"
+
+#ifdef DOTP
+#undef DOTP
+#endif
+
+#define DOTP(a, b) (a[0] * b[0] + a[1] * b[1] + a[2] * b[2])
+
+static double Distance2(double x[3], double *y)
+{
+    double a, b, c;
+	
+    a = x[0] - y[0];  b = x[1] - y[1];  c = x[2] - y[2];
+    return (a * a + b * b + c * c);
+}
+
+static void interp(double *proj, const double *p1, const double *p2,
+		   const double *p3, const double *bary)
+{
+    proj[0] = p1[0] * bary[0] + p2[0] * bary[1] + p3[0] * bary[2];
+    proj[1] = p1[1] * bary[0] + p2[1] * bary[1] + p3[1] * bary[2];
+    proj[2] = p1[2] * bary[0] + p2[2] * bary[1] + p3[2] * bary[2];
+}
+
+static void Projecth(const double *v1, const double *v2, const double *v3,double *bary)
+{
+    int     i;
+    double   vvi[3],vppi[3];
+    double   d12sq, don12,d2, mind2, a;
+    double   proj[3];
+    double   pf[3][3];
+    double   ba[3];
+    double   cba[3];
+
+    mind2 = 1e30;
+    interp(proj,v1,v2,v3,bary);
+    pf[0][0] = v1[0]; pf[0][1] = v1[1]; pf[0][2] = v1[2];
+    pf[1][0] = v2[0]; pf[1][1] = v2[1]; pf[1][2] = v2[2];
+    pf[2][0] = v3[0]; pf[2][1] = v3[1]; pf[2][2] = v3[2];
+
+    ba[0] = bary[0]; ba[1] = bary[1]; ba[2] = bary[2];
+
+    for (i = 0; i < 3; i++){
+	if (ba[(i+2)%3] >= 0) continue;
+	/* project proj onto segment pf[(i+0)%3]--pf[(i+1)%3]  */
+         
+	vvi[0] = pf[(i+1) % 3][0] - pf[i][0];
+	vvi[1] = pf[(i+1) % 3][1] - pf[i][1];
+	vvi[2] = pf[(i+1) % 3][2] - pf[i][2];
+         
+	vppi[0] = proj[0] - pf[i][0];
+	vppi[1] = proj[1] - pf[i][1];
+	vppi[2] = proj[2] - pf[i][2];
+
+	d12sq = DOTP(vvi, vvi);
+	don12 = DOTP(vvi, vppi);
+
+	if (don12<=0) {
+	    d2 = Distance2(pf[i], proj);
+	    if (d2 >= mind2) continue;
+	    mind2=d2; cba[i]=1; cba[(i+1)%3]=0; cba[(i+2)%3]=0;
+	}
+	else {
+	    if (don12 >= d12sq) {
+		d2 = Distance2(pf[(i+1)%3], proj);
+		if (d2>=mind2) continue;
+		mind2=d2; cba[i]=0; cba[(i+1)%3]=1; cba[(i+2)%3]=0;
+	    }
+	    else {
+		a = don12/d12sq;
+		cba[i]=1-a; cba[(i+1)%3]=a; cba[(i+2)%3]=0;
+		break;
+	    }
+	}
+    }
+
+    bary[0] = cba[0]; bary[1] = cba[1]; bary[2] = cba[2];
+}
+
+static void ProjectPtri(const double *point,  const double *v1, 
+			const double *v2,  const double *v3, double *bary)
+{
+    int    i;
+    double  localv2[3], localv3[3], vpp1[3];
+    double  v22,v33,v23,v2pp1,v3pp1;
+    double  a1,a2,a3,denom;
+
+    for (i = 0; i < 3; i++){
+	localv2[i] = v2[i] - v1[i];
+	localv3[i] = v3[i] - v1[i];
+	vpp1[i] = point[i] - v1[i];
+    }
+	
+    v22   = DOTP(localv2, localv2);
+    v33   = DOTP(localv3, localv3);
+    v23   = DOTP(localv2, localv3);
+    v2pp1 = DOTP(localv2, vpp1);
+    v3pp1 = DOTP(localv3, vpp1);
+	
+    if (!v22) v22=1;        /* recover if v2==0 */
+    if (!v33) v33=1;        /* recover if v3==0 */
+
+    denom = ( v33 - v23 * v23 / v22);
+    if (!denom) {
+	a2 = a3 = 1.0/3.0;    /* recover if v23*v23==v22*v33 */
+    }
+    else {
+	a3=(v3pp1-v23/v22*v2pp1)/denom;
+	a2=(v2pp1-a3*v23)/v22;
+    }
+    a1 = 1 - a2 - a3;
+
+    bary[0] = a1; bary[1] = a2; bary[2] = a3;
+
+    if ((a1 < 0) || (a2 < 0) || (a3 < 0)){
+	Projecth(v1,v2,v3,bary);
+	return;
+    }
+}
+
+double triangle_project_point(const Vec3& v0, const Vec3& v1,
+			      const Vec3& v2, const Vec3& v, 
+			      Vec3 *bary)
+{
+    Vec3 __bary;
+
+    if( !bary ) bary = &__bary;
+
+    ProjectPtri(v, v0, v1, v2, *bary);
+
+    Vec3 p = (*bary)[X]*v0 + (*bary)[Y]*v1 + (*bary)[Z]*v2;
+
+    Vec3 diff = v - p;
+
+    return diff*diff;
+}
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxRaster-tiff.cxx
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxRaster-tiff.cxx	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxRaster-tiff.cxx	(revision 1097)
@@ -0,0 +1,139 @@
+/************************************************************************
+
+  TIFF support is optional.  Only PNM support is guaranteed to be
+  available.  Since it is optional, the TIFF code is contained here in a
+  separate source file.
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxRaster-tiff.cxx,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "stdmix.h"
+#include "MxRaster.h"
+
+
+#ifdef MIX_HAVE_LIBTIFF
+#include <tiffio.h>
+
+////////////////////////////////////////////////////////////////////////
+//
+// TIFF output
+//
+static
+bool __tiff_write(TIFF *tif, const MxRaster& img)
+{
+    TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, img.width());
+    TIFFSetField(tif, TIFFTAG_IMAGELENGTH, img.height());
+
+    TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
+    TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, img.channels());
+    TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8);
+    TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+    TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
+
+    // Turn on LZW compression.  Shhhhh!  Don't tell Unisys!
+    TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_LZW);
+    //
+    // Predictors:
+    //     1 (default) -- No predictor
+    //     2           -- Horizontal differencing
+    TIFFSetField(tif, TIFFTAG_PREDICTOR, 2);
+
+    uint32 scanline_size = img.channels() * img.width();
+    if( TIFFScanlineSize(tif) != scanline_size )
+    {
+	mxmsg_signal(MXMSG_WARN,
+		     "Mismatch with library's expected scanline size!",
+		     "tiff_write");
+	return false;
+    }
+
+    TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(tif, -1));
+
+    char *scanline_buf = new char[scanline_size];
+
+    const unsigned char *scanline = img;
+    for(uint32 y=0; y<img.height(); y++)
+    {
+	memcpy(scanline_buf, scanline, scanline_size);
+	// NOTE: TIFFWriteScanline modifies the buffer you pass it.
+	//       Thus, we need to copy stuff out of the raster first.
+	TIFFWriteScanline(tif, scanline_buf, y, 0);
+	scanline += scanline_size;
+    }
+    delete[] scanline_buf;
+
+    return true;
+}
+
+bool tiff_write(const char *filename, const MxRaster& img)
+{
+    TIFF *tif = TIFFOpen(filename, "w");
+    if( !tif ) return false;
+
+    bool result = __tiff_write(tif, img);
+
+    TIFFClose(tif);
+
+    return result;
+}
+
+////////////////////////////////////////////////////////////////////////
+//
+// TIFF input
+//
+static
+void unpack_tiff_raster(uint32 *raster, MxRaster *img, uint npixels)
+{
+    unsigned char *pix = img[0];
+    
+    for(uint i=0; i<npixels; i++)
+    {
+	*pix++ = TIFFGetR(raster[i]);
+	*pix++ = TIFFGetG(raster[i]);
+	*pix++ = TIFFGetB(raster[i]);
+    }
+}
+
+static
+MxRaster *__tiff_read(TIFF *tif)
+{
+    uint32 w, h;
+    TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w);
+    TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
+
+    uint npixels = w*h;
+
+    uint32 *raster = (uint32 *)_TIFFmalloc(npixels * sizeof(uint32));
+    if( !raster ) return NULL;
+
+    TIFFReadRGBAImage(tif, w, h, raster, true);
+
+    MxRaster *img = new MxRaster(w, h, 3);
+    unpack_tiff_raster(raster, img, npixels);
+
+    _TIFFfree(raster);
+
+    return img;
+}
+
+MxRaster *tiff_read(const char *filename)
+{
+    TIFF *tif = TIFFOpen(filename, "r");
+    if( !tif ) return NULL;
+
+    MxRaster *img = __tiff_read(tif);
+
+    TIFFClose(tif);
+
+    return img;
+}
+
+#else
+
+bool tiff_write(const char *, const MxRaster&) { return false; }
+MxRaster *tiff_read(const char *) { return NULL; }
+
+#endif
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxVec4.h
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxVec4.h	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxVec4.h	(revision 1097)
@@ -0,0 +1,279 @@
+#ifndef MXVEC4_INCLUDED // -*- C++ -*-
+#define MXVEC4_INCLUDED
+#if !defined(__GNUC__)
+#  pragma once
+#endif
+
+/************************************************************************
+
+  4D Vector class
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxVec4.h,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "MxMath.h"
+#include "MxVec3.h"
+
+#ifdef MIX_USE_TVEC
+#include "MxVector.h"
+
+template<class T>
+class MxTVec4 : public MxVBlock<T, 4>
+{
+public:
+    MxTVec4() { }
+    MxTVec4(T x, T y, T z, T w)
+	{ (*this)[0]=x; (*this)[1]=y; (*this)[2]=z; (*this)[3]=w; }
+    MxTVec4(const MxVBlock<T, 3>& v, T w)
+	{(*this)[0]=v[0];(*this)[1]=v[1];(*this)[2]=v[2];(*this)[3]=w;}
+    MxTVec4(const MxVBlock<T, 4>& v) : MxVBlock<T, 4>(v) { }
+    MxTVec4(const float *v)
+	{(*this)[0]=v[0];(*this)[1]=v[1];(*this)[2]=v[2];(*this)[3]=v[3];}
+    MxTVec4(const double *v)
+	{(*this)[0]=v[0];(*this)[1]=v[1];(*this)[2]=v[2];(*this)[3]=v[3];}
+};
+
+typedef MxTVec4<double> Vec4;
+
+#else
+
+class Vec4 {
+private:
+    double elt[4];
+
+protected:
+    inline void copy(const Vec4& v);
+
+public:
+    //
+    // Standard constructors
+    //
+    Vec4(double x=0, double y=0, double z=0, double w=0) {
+	elt[0]=x; elt[1]=y; elt[2]=z; elt[3]=w;
+    }
+    Vec4(const Vec3& v,double w) {elt[0]=v[0];elt[1]=v[1];elt[2]=v[2];elt[3]=w;}
+    Vec4(const Vec4& v) { copy(v); }
+    Vec4(const float *v) {elt[0]=v[0]; elt[1]=v[1]; elt[2]=v[2]; elt[3]=v[3]; }
+    Vec4(const double *v) {elt[0]=v[0]; elt[1]=v[1]; elt[2]=v[2]; elt[3]=v[3];}
+
+    //
+    // Access methods
+    //
+    double& operator()(uint i)       { AssertBound(i<4); return elt[i]; }
+    double  operator()(uint i) const { AssertBound(i<4); return elt[i]; }
+#ifdef __GNUC__
+    double& operator[](uint i)       { return elt[i]; }
+    double  operator[](uint i) const { return elt[i]; }
+#endif
+
+    operator double*() { return elt; }
+    operator const double*() const { return elt; }
+    // operator Vec3&() { return *((Vec3 *)this); }
+
+    //
+    // Comparison methods
+    //
+    inline bool operator==(const Vec4&) const;
+    inline bool operator!=(const Vec4&) const;
+
+    //
+    // Assignment and in-place arithmetic methods
+    //
+    inline void set(double x, double y, double z, double w){
+	elt[0]=x; elt[1]=y; elt[2]=z; elt[3]=w;
+    }
+    inline Vec4& operator=(const Vec4& v);
+    inline Vec4& operator+=(const Vec4& v);
+    inline Vec4& operator-=(const Vec4& v);
+    inline Vec4& operator*=(double s);
+    inline Vec4& operator/=(double s);
+
+    //
+    // Binary arithmetic methods
+    //
+    inline Vec4 operator+(const Vec4& v) const;
+    inline Vec4 operator-(const Vec4& v) const;
+    inline Vec4 operator-() const;
+
+    inline Vec4 operator*(double s) const;
+    inline Vec4 operator/(double s) const;
+    inline double operator*(const Vec4& v) const;
+};
+
+
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// Method definitions
+//
+
+inline void Vec4::copy(const Vec4& v)
+{
+    elt[0]=v.elt[0]; elt[1]=v.elt[1]; elt[2]=v.elt[2]; elt[3]=v.elt[3];
+}
+
+inline bool Vec4::operator==(const Vec4& v) const
+{
+    double dx=elt[X]-v[X],  dy=elt[Y]-v[Y],  dz=elt[Z]-v[Z],  dw=elt[W]-v[W];
+    return (dx*dx + dy*dy + dz*dz + dw*dw) < FEQ_EPS2;
+}
+
+inline bool Vec4::operator!=(const Vec4& v) const
+{
+    double dx=elt[X]-v[X],  dy=elt[Y]-v[Y],  dz=elt[Z]-v[Z],  dw=elt[W]-v[W];
+    return (dx*dx + dy*dy + dz*dz + dw*dw) > FEQ_EPS2;
+}
+
+inline Vec4& Vec4::operator=(const Vec4& v)
+{
+    copy(v);
+    return *this;
+}
+
+inline Vec4& Vec4::operator+=(const Vec4& v)
+{
+    elt[0] += v[0];   elt[1] += v[1];   elt[2] += v[2];   elt[3] += v[3];
+    return *this;
+}
+
+inline Vec4& Vec4::operator-=(const Vec4& v)
+{
+    elt[0] -= v[0];   elt[1] -= v[1];   elt[2] -= v[2];   elt[3] -= v[3];
+    return *this;
+}
+
+inline Vec4& Vec4::operator*=(double s)
+{
+    elt[0] *= s;   elt[1] *= s;   elt[2] *= s;  elt[3] *= s;
+    return *this;
+}
+
+inline Vec4& Vec4::operator/=(double s)
+{
+    elt[0] /= s;   elt[1] /= s;   elt[2] /= s;   elt[3] /= s;
+    return *this;
+}
+
+inline Vec4 Vec4::operator+(const Vec4& v) const
+{
+    return Vec4(elt[0]+v[0], elt[1]+v[1], elt[2]+v[2], elt[3]+v[3]);
+}
+
+inline Vec4 Vec4::operator-(const Vec4& v) const
+{
+    return Vec4(elt[0]-v[0], elt[1]-v[1], elt[2]-v[2], elt[3]-v[3]);
+}
+
+inline Vec4 Vec4::operator-() const
+{
+    return Vec4(-elt[0], -elt[1], -elt[2], -elt[3]);
+}
+
+inline Vec4 Vec4::operator*(double s) const
+{
+    return Vec4(elt[0]*s, elt[1]*s, elt[2]*s, elt[3]*s);
+}
+
+inline Vec4 Vec4::operator/(double s) const
+{
+    return Vec4(elt[0]/s, elt[1]/s, elt[2]/s, elt[3]/s);
+}
+
+inline double Vec4::operator*(const Vec4& v) const
+{
+    return elt[0]*v[0] + elt[1]*v[1] + elt[2]*v[2] + elt[3]*v[3];
+}
+
+#endif
+
+// Make scalar multiplication commutative
+inline Vec4 operator*(double s, const Vec4& v) { return v*s; }
+
+
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// Primitive function definitions
+//
+
+//
+// Code adapted from VecLib4d.c in Graphics Gems V
+inline Vec4 cross(const Vec4& a, const Vec4& b, const Vec4& c)
+{
+    Vec4 result;
+
+    double d1 = (b[Z] * c[W]) - (b[W] * c[Z]);
+    double d2 = (b[Y] * c[W]) - (b[W] * c[Y]);
+    double d3 = (b[Y] * c[Z]) - (b[Z] * c[Y]);
+    double d4 = (b[X] * c[W]) - (b[W] * c[X]);
+    double d5 = (b[X] * c[Z]) - (b[Z] * c[X]);
+    double d6 = (b[X] * c[Y]) - (b[Y] * c[X]);
+
+    result[X] = - a[Y] * d1 + a[Z] * d2 - a[W] * d3;
+    result[Y] =   a[X] * d1 - a[Z] * d4 + a[W] * d5;
+    result[Z] = - a[X] * d2 + a[Y] * d4 - a[W] * d6;
+    result[W] =   a[X] * d3 - a[Y] * d5 + a[Z] * d6;
+
+    return result;
+}
+
+inline double norm(const Vec4& v)
+{
+    return sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2] + v[3]*v[3]);
+}
+
+inline double norm2(const Vec4& v)
+{
+    return v[0]*v[0] + v[1]*v[1] + v[2]*v[2] + v[3]*v[3];
+}
+
+inline double unitize(Vec4& v)
+{
+    double l=norm2(v);
+    if( l!=1.0 && l!=0.0 )
+    {
+	l = sqrt(l);
+	v /= l;
+    }
+    return l;
+}
+
+inline Vec3 proj(const Vec4& v)
+{
+    Vec3 u(v[0], v[1], v[2]);
+    if( v[3]!=1.0 && v[3]!=0.0 )
+	u /= v[3];
+    return u;
+}
+
+
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// Misc. function definitions
+//
+
+inline ostream& operator<<(ostream& out, const Vec4& v)
+{
+    return
+	out << v[0] << " " << v[1] << " " << v[2] << " " << v[3];
+}
+
+inline istream& operator>>(istream& in, Vec4& v)
+{
+    return in >> v[0] >> v[1] >> v[2] >> v[3];
+}
+
+#ifdef MXGL_INCLUDED
+inline void glV(const Vec4& v) { glVertex4d(v[X], v[Y], v[Z], v[W]); }
+inline void glC(const Vec4& v) { glColor4d(v[X], v[Y], v[Z], v[W]); }
+#endif
+
+// MXVEC4_INCLUDED
+#endif
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxVector.h
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxVector.h	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxVector.h	(revision 1097)
@@ -0,0 +1,143 @@
+#ifndef MXVECTOR_INCLUDED // -*- C++ -*-
+#define MXVECTOR_INCLUDED
+#if !defined(__GNUC__)
+#  pragma once
+#endif
+
+/************************************************************************
+
+  Generic n-dimensional vector class
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxVector.h,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "MxMath.h"
+
+#ifdef __T
+#undef __T
+#endif
+
+#define __T float
+#include "mixvops.h"
+
+#define __T double
+#include "mixvops.h"
+
+////////////////////////////////////////////////////////////////////////
+//
+// MxVBlock -- fixed-size vector class template
+//
+// The idea here is that we want a small collection of vector classes,
+// {2,3,4}D say, and we want *zero* space overhead.  No length fields,
+// no vtables, just N numerical values.
+//
+template<class T, unsigned int N>
+class MxVBlock
+{
+private:
+    T elt[N];
+
+protected:
+    inline void copy(const MxVBlock<T,N>& v)
+	{ for(uint i=0; i<N; i++) elt[i]=v.elt[i]; }
+
+public:
+    MxVBlock() { }
+    MxVBlock(const MxVBlock<T,N>& v) { mxv_set(elt, v, N); }
+    MxVBlock(const T *v) { mxv_set(elt, v, N); }
+
+    inline unsigned int dim() const { return N; }
+
+    T& operator()(uint i)       { AssertBound(i<N); return elt[i]; }
+    T  operator()(uint i) const { AssertBound(i<N); return elt[i]; }
+
+    operator       T*()       { return elt; }
+    operator const T*() const { return elt; }
+
+
+    // In-place arithmetic methods
+    //
+    inline MxVBlock<T,N>& operator=(const MxVBlock<T,N>& v)
+	{ mxv_set(elt, v, N); return *this; }
+    inline MxVBlock<T,N>& operator+=(const MxVBlock<T,N>& v)
+	{ mxv_addinto(elt, v, N); return *this; }
+    inline MxVBlock<T,N>& operator-=(const MxVBlock<T,N>& v)
+	{ mxv_subfrom(elt, v, N); return *this; }
+    inline MxVBlock<T,N>& operator*=(T s) { mxv_scale(elt,s,N); return *this; }
+    inline MxVBlock<T,N>& operator/=(T s) {mxv_invscale(elt,s,N);return *this;}
+    inline MxVBlock<T,N>& negate() { mxv_neg(elt, N); return *this; }
+
+    // Binary arithmetic methods
+    // 
+    inline MxVBlock<T,N> operator+(const MxVBlock<T,N>& v) const
+	{ MxVBlock<T,N> r; mxv_add(r, elt, v, N); return r; }
+    inline MxVBlock<T,N> operator-(const MxVBlock<T,N>& v) const
+	{ MxVBlock<T,N> r; mxv_sub(r, elt, v, N); return r; }
+    inline MxVBlock<T,N> operator*(T s) const
+	{ MxVBlock<T,N> r; mxv_scale(r, elt, s, N); return r; }
+    inline MxVBlock<T,N> operator/(T s) const
+	{ MxVBlock<T,N> r; mxv_invscale(r, elt, s, N); return r; }
+    inline MxVBlock<T,N> operator-() const
+	{ MxVBlock<T,N> r; mxv_neg(r, elt, N); return r; }
+
+    inline T operator*(const MxVBlock<T,N>& v) const {return mxv_dot(elt,v,N);}
+
+    // Comparison operators
+    inline bool operator==(const MxVBlock<T,N>& v) const
+	{ return mxv_equal(elt, v, N); }
+    inline bool operator!=(const MxVBlock<T,N>& v) const
+	{ return !mxv_equal(elt, v, N); }
+};
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// MxVector -- arbitrarily sized vectors
+//
+// With MxVector vectors, we're willing to pay a little per-vector space
+// overhead to achieve greater flexibility without having to instantiate
+// a template class for every single dimension we care about.
+//
+
+#include "MxBlock.h"
+
+class MxVector : public MxBlock<double>
+{
+public:
+    MxVector(unsigned int n) : MxBlock<double>(n) {mxv_set(*this,0.0,dim());}
+    MxVector(const MxVector& v) : MxBlock<double>(v.length()) { copy(v); }
+
+    MxVector& operator=(const MxVector& v)  { copy(v); return *this; }
+    MxVector& operator=(double d) { mxv_set(*this, d, dim()); return *this; }
+
+    unsigned int dim() const { return length(); }
+
+    MxVector& operator+=(const MxVector& v)
+	{ mxv_addinto(*this, v, dim()); return *this; }
+    MxVector& operator-=(const MxVector& v)
+	{ mxv_subfrom(*this, v, dim()); return *this; }
+    MxVector& operator*=(double d)
+	{ mxv_scale(*this, d, dim()); return *this; }
+    MxVector& operator/=(double d)
+	{ mxv_invscale(*this, d, dim()); return *this; }
+
+    double operator*(const MxVector& v) const {return mxv_dot(*this,v,dim());}
+};
+
+
+// Convenient wrappers for mixvops functionality
+//
+inline double norm(const MxVector& v) { return mxv_norm(v, v.dim()); }
+inline double norm2(const MxVector& v) { return mxv_dot(v, v, v.dim()); }
+inline double unitize(MxVector& v) { return mxv_unitize(v, v.dim()); }
+
+inline ostream&
+operator<<(ostream& out,const MxVector& v) { return mxv_write(out,v,v.dim()); }
+inline istream&
+operator>>(istream& in, MxVector& v) { return mxv_read(in, v, v.dim()); }
+
+// MXVECTOR_INCLUDED
+#endif
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxCamera.cxx
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxCamera.cxx	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxCamera.cxx	(revision 1097)
@@ -0,0 +1,48 @@
+/************************************************************************
+
+  MxCamera
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxCamera.cxx,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "stdmix.h"
+#include "MxCamera.h"
+
+
+
+void MxCamera::look_at(const MxBounds& bounds, double ratio)
+{
+    double d = 3*bounds.radius / tan(60*M_PI/180.0);
+
+    at = bounds.center;
+    from = at;
+
+    from[Z] += d;
+
+    up[X] = 0; up[Y] = 1; up[Z] = 0;
+
+    fovy = 60.0;
+    aspect = ratio;
+
+    znear = d/20;
+    zfar = 10*d;
+}
+
+void MxCamera::apply()
+{
+    gluPerspective(fovy, aspect, znear, zfar);
+    gluLookAt(from[X], from[Y], from[Z],
+              at[X], at[Y], at[Z],
+              up[X], up[Y], up[Z]);
+}
+
+void MxCamera::apply(GLenum mode)
+{
+    GLint last_mode; glGetIntegerv(GL_MATRIX_MODE, &last_mode);
+      glMatrixMode(mode);
+      apply();
+    glMatrixMode((GLenum)last_mode);
+}
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxMat3.h
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxMat3.h	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxMat3.h	(revision 1097)
@@ -0,0 +1,165 @@
+#ifndef MXMAT3_INCLUDED // -*- C++ -*-
+#define MXMAT3_INCLUDED
+#if !defined(__GNUC__)
+#  pragma once
+#endif
+
+/************************************************************************
+
+  3x3 Matrix class
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxMat3.h,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "MxMath.h"
+#include "MxVec3.h"
+
+class Mat3
+{
+private:
+    Vec3 row[3];
+
+protected:
+
+    inline void copy(const Mat3& m);
+    inline Vec3 col(int i) const {return Vec3(row[0][i],row[1][i],row[2][i]);}
+
+public:
+    // Standard matrices
+    static Mat3 I;
+    static Mat3 zero;
+    static Mat3 unit;
+    static Mat3 diag(const Vec3& v);    // diagonal elements from v
+    static Mat3 extend(const Vec3& v);  // each row becomes v
+    static Mat3 outer_product(const Vec3& v); // outer product of v by v
+
+    // Standard constructors
+    Mat3() { copy(zero); }
+    Mat3(const Vec3& r0,const Vec3& r1,const Vec3& r2)
+    { row[0]=r0; row[1]=r1; row[2]=r2; }
+    Mat3(const Mat3& m) { copy(m); }
+
+    // Access methods
+    // M(i, j) == row i;col j
+    double& operator()(int i, int j)       { return row[i][j]; }
+    double  operator()(int i, int j) const { return row[i][j]; }
+    Vec3&       operator[](int i)       { return row[i]; }
+    const Vec3& operator[](int i) const { return row[i]; }
+
+    operator       double*()       { return row[0]; }
+    operator const double*() const { return row[0]; }
+
+    // Assignment methods
+    inline Mat3& operator=(const Mat3& m) { copy(m); return *this; }
+    inline Mat3& operator+=(const Mat3& m);
+    inline Mat3& operator-=(const Mat3& m);
+
+    inline Mat3& operator*=(double s);
+    inline Mat3& operator/=(double s);
+
+
+    // Arithmetic methods
+    inline Mat3 operator+(const Mat3& m) const;
+    inline Mat3 operator-(const Mat3& m) const;
+    inline Mat3 operator-() const;
+
+    inline Mat3 operator*(double s) const;
+    inline Mat3 operator/(double s) const;
+    Mat3 operator*(const Mat3& m) const;
+
+    inline Vec3 operator*(const Vec3& v) const; // [x y z]
+
+    // Matrix operations
+    double det();
+    double trace();
+    Mat3 transpose();
+    Mat3 adjoint();
+    double invert(Mat3&);
+};
+
+
+
+
+inline void Mat3::copy(const Mat3& m)
+{
+    row[0] = m.row[0]; row[1] = m.row[1]; row[2] = m.row[2];
+}
+
+inline Mat3& Mat3::operator+=(const Mat3& m)
+{
+    row[0] += m.row[0]; row[1] += m.row[1]; row[2] += m.row[2];
+    return *this;
+}
+
+inline Mat3& Mat3::operator-=(const Mat3& m)
+{
+    row[0] -= m.row[0]; row[1] -= m.row[1]; row[2] -= m.row[2];
+    return *this;
+}
+
+inline Mat3& Mat3::operator*=(double s)
+{
+    row[0] *= s; row[1] *= s; row[2] *= s;
+    return *this;
+}
+
+inline Mat3& Mat3::operator/=(double s)
+{
+    row[0] /= s; row[1] /= s; row[2] /= s;
+    return *this;
+}
+
+inline Mat3 Mat3::operator+(const Mat3& m) const
+{
+    return Mat3(row[0]+m.row[0],
+		row[1]+m.row[1],
+		row[2]+m.row[2]);
+}
+
+inline Mat3 Mat3::operator-(const Mat3& m) const
+{
+    return Mat3(row[0]-m.row[0],
+		row[1]-m.row[1],
+		row[2]-m.row[2]);
+}
+
+inline Mat3 Mat3::operator-() const
+{
+    return Mat3(-row[0], -row[1], -row[2]);
+}
+
+inline Mat3 Mat3::operator*(double s) const
+{
+    return Mat3(row[0]*s, row[1]*s, row[2]*s);
+}
+
+inline Mat3 Mat3::operator/(double s) const
+{
+    return Mat3(row[0]/s, row[1]/s, row[2]/s);
+}
+
+inline Vec3 Mat3::operator*(const Vec3& v) const
+{
+    return Vec3(row[0]*v, row[1]*v, row[2]*v);
+}
+
+inline ostream& operator<<(ostream& out, const Mat3& M)
+{
+    return out << M[0] << endl << M[1] << endl << M[2];
+}
+
+inline istream& operator>>(istream& in, Mat3& M)
+{
+    return in >> M[0] >> M[1] >> M[2];
+}
+
+extern bool jacobi(const Mat3& m, Vec3& vals, Vec3 vecs[3]);
+extern bool jacobi(const Mat3& m, double *vals, double *vecs);
+
+extern bool fast_jacobi(const Mat3& m, Vec3& vals, Vec3 vecs[3]);
+
+// MXMAT3_INCLUDED
+#endif
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxMatrix.h
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxMatrix.h	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxMatrix.h	(revision 1097)
@@ -0,0 +1,64 @@
+#ifndef MXMATRIX_INCLUDED // -*- C++ -*-
+#define MXMATRIX_INCLUDED
+#if !defined(__GNUC__)
+#  pragma once
+#endif
+
+/************************************************************************
+
+  Generic n-dimensional matrix class
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxMatrix.h,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "MxVector.h"
+
+#define __T float
+#include "mixmops.h"
+
+#define __T double
+#include "mixmops.h"
+
+////////////////////////////////////////////////////////////////////////
+//
+// Matrix class
+//
+
+#include "MxBlock2.h"
+
+class MxMatrix : public MxBlock2<double>
+{
+public:
+    MxMatrix(unsigned int n) : MxBlock2<double>(n,n) { *this = 0.0; }
+    MxMatrix(const MxMatrix& m) : MxBlock2<double>(m.dim(),m.dim()) {copy(m);}
+
+    MxMatrix& operator=(const MxMatrix& m) { copy(m); return *this; }
+    MxMatrix& operator=(double d) { mxm_set(*this, d, dim()); return *this; }
+
+    unsigned int dim() const { return width(); }
+
+    MxMatrix& operator+=(const MxMatrix& m)
+	{ mxm_addinto(*this, m, dim()); return *this; }
+    MxMatrix& operator-=(const MxMatrix& m)
+	{ mxm_subfrom(*this, m, dim()); return *this; }
+    MxMatrix& operator*=(double d) {mxm_scale(*this, d, dim()); return *this;}
+    MxMatrix& operator/=(double d) {mxm_invscale(*this,d,dim());return *this;}
+
+
+    MxVector operator*(const MxVector& v) const
+	{ MxVector r(dim()); mxm_xform(r, *this, v, dim()); return r; }
+
+    double invert(MxMatrix& inv) const {return mxm_invert(inv, *this, dim());}
+};
+
+
+inline ostream& operator<<(ostream& out, const MxMatrix& a)
+{
+    return mxm_write(out, a, a.dim());
+}
+
+// MXMATRIX_INCLUDED
+#endif
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxStdRender.cxx
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxStdRender.cxx	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxStdRender.cxx	(revision 1097)
@@ -0,0 +1,280 @@
+/************************************************************************
+
+  Since we don't want to have to rewrite rendering loops every time we
+  want to draw a model, this module provides centralized drawing code.
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxStdRender.cxx,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "stdmix.h"
+#include "MxGL.h"
+#include "MxStdModel.h"
+
+////////////////////////////////////////////////////////////////////////
+//
+// Globally visible variables.  These exist for quasi-easy
+// customization.  Eventually, we'll have a more flexible system.
+//
+
+float mx_mesh_color[3] = {0.05f, 0.05f, 0.05f};
+float mx_alt_mesh_color[3] = {0.8f, 0.1f, 0.1f};
+
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// Currently, we create custom routines for each possible combination
+// of normal and color bindings. This approach might eventually lead
+// to excessive code bloat.  Be careful!
+//
+// Note that the whole point of this is to avoid conditional branching
+// in the rendering loop.  Currently, we have 2: one for the loop
+// condition and one to test face validity.  This is minimal.
+//
+
+#define _0(x) 
+#define _V(x) glV(m.vertex(x))
+#define _N(x) glN(m.normal(x))
+#define _C(x) glC(m.color(x))
+
+#define _CV(x) _C(x),_V(x)
+#define _NV(x) _N(x),_V(x)
+#define _NC(x) _N(x),_C(x)
+#define _NCV(x) _N(x),_C(x),_V(x)
+
+
+#define defdraw(fn, per_face, per_vert) \
+static void fn(MxStdModel& m) \
+{ \
+    glBegin(GL_TRIANGLES); \
+    for(MxFaceID f=0; f<m.face_count(); f++) \
+    { \
+	if( !m.face_is_valid(f) ) continue; \
+	MxVertexID v1=m.face(f)(0), v2=m.face(f)(1), v3=m.face(f)(2); \
+	per_face(f); \
+	per_vert(v1); \
+	per_vert(v2); \
+	per_vert(v3); \
+    } \
+    glEnd(); \
+}
+
+defdraw(draw_c0n0, _0 , _V)
+defdraw(draw_c0n1, _N , _V)
+defdraw(draw_c0n2, _0 , _NV)
+
+defdraw(draw_c1n0, _C , _V)
+defdraw(draw_c1n1, _NC, _V)
+defdraw(draw_c1n2, _C , _NV)
+
+defdraw(draw_c2n0, _0 , _CV)
+defdraw(draw_c2n1, _N , _CV)
+defdraw(draw_c2n2, _0 , _NCV)
+
+
+static inline void emit_face(MxStdModel& m, MxFaceID f)
+{
+    if( m.normal_binding()==MX_PERFACE )  glN(m.normal(f));
+    if( m.color_binding()==MX_PERFACE ) glC(m.color(f));
+}
+
+static inline void emit_vertex(MxStdModel& m, MxVertexID v)
+{
+    if( m.normal_binding()==MX_PERVERTEX ) glN(m.normal(v));
+    if( m.color_binding()==MX_PERVERTEX ) glC(m.color(v));
+    if( m.texcoord_binding()==MX_PERVERTEX) glT(m.texcoord(v));
+    glV(m.vertex(v));
+}
+
+static
+void draw_fallback(MxStdModel& m)
+{
+    glBegin(GL_TRIANGLES);
+    for(MxFaceID f=0; f<m.face_count(); f++)
+    {
+	if( !m.face_is_valid(f) ) continue;
+	MxVertexID v1=m.face(f)(0), v2=m.face(f)(1), v3=m.face(f)(2);
+	emit_face(m,f);
+	emit_vertex(m,v1);
+	emit_vertex(m,v2);
+	emit_vertex(m,v3);
+    }
+    glEnd();
+}
+
+typedef void (*render_func)(MxStdModel&);
+
+#define TABLE_SIZE 12
+
+static render_func render_table[12] = {
+    draw_c0n0, draw_c0n1, draw_c0n2, NULL,
+
+    draw_c1n0, draw_c1n1, draw_c1n2, NULL,
+
+    draw_c2n0, draw_c2n1, draw_c2n2, NULL,
+};
+
+
+static
+void render_faces_for_selection(MxStdModel& m)
+{
+    for(MxFaceID f=0; f<m.face_count(); f++)
+    {
+	if( !m.face_is_valid(f) ) continue;
+	MxVertexID v1=m.face(f)(0), v2=m.face(f)(1), v3=m.face(f)(2);
+	glLoadName(f);
+	glBegin(GL_TRIANGLES);
+	emit_face(m, f); // emit normal in case backface culling is on
+	glV(m.vertex(v1));
+	glV(m.vertex(v2));
+	glV(m.vertex(v3));
+	glEnd();
+    }
+}
+
+static
+void render_points_for_selection(MxStdModel& m)
+{
+    for(MxVertexID v=0; v<m.vert_count(); v++)
+    {
+	if( !m.vertex_is_valid(v) )  continue;
+	glLoadName(v);
+	glBegin(GL_POINTS);
+	glV(m.vertex(v));
+	glEnd();
+    }
+}
+
+static inline int get_mode()
+{
+    int mode; glGetIntegerv(GL_RENDER_MODE, &mode); return mode;
+}
+
+void mx_render_model(MxStdModel& m)
+{
+
+    if( get_mode() == GL_SELECT ) { render_faces_for_selection(m);  return; }
+
+    uint index = (m.texcoord_binding() << 4) |
+	         (m.color_binding() << 2) | m.normal_binding();
+
+    if( index >= TABLE_SIZE )
+	draw_fallback(m);
+    else
+    {
+	render_func fn = render_table[index];
+	if( fn ) (*fn)(m);
+	else fatal_error("mx_render_model: Illegal model properties.");
+    }
+}
+
+static
+inline void emit_faces_only(MxStdModel& m)
+{
+    glBegin(GL_TRIANGLES);
+    for(MxFaceID f=0; f<m.face_count(); f++)
+    {
+	if( !m.face_is_valid(f) ) continue;
+	glV(m.corner(f, 0));
+	glV(m.corner(f, 1));
+	glV(m.corner(f, 2));
+    }
+    glEnd();
+}
+
+static
+inline void emit_points_only(MxStdModel& m)
+{
+    glBegin(GL_POINTS);
+    for(MxVertexID v=0; v<m.vert_count(); v++)
+    {
+	if( !m.vertex_is_valid(v) )  continue;
+	glV(m.vertex(v));
+    }
+    glEnd();
+}
+
+void mx_draw_mesh(MxStdModel& m, double *color)
+{
+    if( get_mode() == GL_SELECT ) return;
+
+
+    glPushAttrib(GL_ENABLE_BIT | GL_POLYGON_BIT);
+    glDisable(GL_LIGHTING);
+    glDisable(GL_TEXTURE_2D);
+    if( color ) glColor3dv(color); else glColor3fv(mx_mesh_color);
+
+    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+    emit_faces_only(m);
+
+    glPopAttrib();
+}
+
+void mx_draw_wireframe(MxStdModel& m, double *color)
+{
+    GLfloat bkg_color[4];
+    glGetFloatv(GL_COLOR_CLEAR_VALUE, bkg_color);
+
+    glPushAttrib(GL_ENABLE_BIT | GL_POLYGON_BIT);
+    glDisable(GL_LIGHTING);
+    glDisable(GL_TEXTURE_2D);
+
+    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+    glNoOffset();
+    if( color ) glColor3dv(color); else glColor3fv(mx_mesh_color);
+    emit_faces_only(m);
+
+    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+    glOffsetForMesh();
+    glC(bkg_color[0], bkg_color[1], bkg_color[2]);
+    emit_faces_only(m);
+
+    glPopAttrib();
+}
+
+void mx_draw_pointcloud(MxStdModel& m)
+{
+    if( get_mode() == GL_SELECT ) { render_points_for_selection(m);  return; }
+
+    glPushAttrib(GL_ENABLE_BIT | GL_POINT_BIT);
+    glDisable(GL_LIGHTING);
+    glDisable(GL_TEXTURE_2D);
+    glPointSize(2.0);
+
+    emit_points_only(m);
+
+    glPopAttrib();
+}
+
+void mx_draw_boundaries(MxStdModel& m)
+{
+    glPushAttrib(GL_LIGHTING_BIT);
+    glDisable(GL_LIGHTING);
+    glC(0.8, 0.8, 0.1);
+
+    glBegin(GL_LINES);
+
+    MxVertexList star;
+    MxFaceList faces;
+    for(MxVertexID i=0; i<m.vert_count(); i++)
+    {
+	star.reset();
+	m.collect_vertex_star(i, star);
+
+	for(uint j=0; j<star.length(); j++)
+	    if( i < star(j) )
+	    {
+		faces.reset();
+		m.collect_edge_neighbors(i, star(j), faces);
+		if( faces.length() == 1 )
+		{ glV(m.vertex(i)); glV(m.vertex(star(j))); }
+	    }
+    }
+
+    glEnd();
+
+    glPopAttrib();
+}
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxDynBlock.h
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxDynBlock.h	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxDynBlock.h	(revision 1097)
@@ -0,0 +1,76 @@
+#ifndef MXDYNBLOCK_INCLUDED // -*- C++ -*-
+#define MXDYNBLOCK_INCLUDED
+#if !defined(__GNUC__)
+#  pragma once
+#endif
+
+/************************************************************************
+
+  MxDynBlocks are blocks that automatically grow to fit the data added
+  to them.
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxDynBlock.h,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "MxBlock.h"
+
+template<class T>
+class MxDynBlock : public MxBlock<T>
+{
+private:
+    uint fill;
+
+public:
+    MxDynBlock() { init_block(8); fill=0; }
+    MxDynBlock(uint n) { init_block(n); fill=0; }
+
+    T&       operator()(uint i)       { AssertBound(i<fill); return ref(i); }
+    const T& operator()(uint i) const { AssertBound(i<fill); return ref(i); }
+
+    uint length() const { return fill; }
+    uint total_space() const { return MxBlock<T>::length(); }
+    T& last() { AssertBound(fill>0); return raw(fill-1); }
+    const T& last() const { AssertBound(fill>0); return raw(fill-1); }
+
+    uint add()
+	{
+	    if( length()==total_space() )  resize(total_space() * 2);
+	    return fill++;
+	}
+    uint add(const T& t)
+	{
+	    uint i=add();
+	    raw(i) = t;
+	    return i;
+	}
+
+    void reset() { fill = 0; }
+    T& drop() { return raw(--fill); }
+    void drop(uint d) { fill -= d; }
+    bool find(const T& t, uint *index=NULL)
+	{
+	    for(uint i=0; i<fill; i++)
+		if( raw(i) == t )
+		{
+		    if( index ) *index = i;
+		    return true;
+		}
+	    return false;
+	}
+    void remove(uint i)
+	{ AssertBound(i<fill); fill--; raw(i) = raw(fill); }
+    void remove_inorder(uint i)
+	{ memmove(&raw(i), &raw(i+1), (--fill - i)*sizeof(T)); }
+};
+
+template<class T, int T_SIZE>
+class MxSizedDynBlock : public MxDynBlock<T>
+{
+public:   MxSizedDynBlock(uint n=T_SIZE) : MxDynBlock<T>(n) { }
+};
+
+// MXDYNBLOCK_INCLUDED
+#endif
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxMat4-jacobi.cxx
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxMat4-jacobi.cxx	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxMat4-jacobi.cxx	(revision 1097)
@@ -0,0 +1,177 @@
+/************************************************************************
+
+  Jacobi iteration on 4x4 matrices.
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+
+  NOTE: This code was adapted from VTK source code (vtkMath.cxx) which
+        seems to have been adapted directly from Numerical Recipes in C.
+	See Hoppe's Recon software for an alternative adaptation of the
+	Numerical Recipes code.
+  
+  $Id: MxMat4-jacobi.cxx,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "stdmix.h"
+#include "MxMat4.h"
+
+#define ROT(a,i,j,k,l) g=a[i][j];h=a[k][l];a[i][j]=g-s*(h+g*tau);a[k][l]=h+s*(g-h*tau);
+
+#define MAX_ROTATIONS 60
+
+static
+bool internal_jacobi4(double a[4][4], double w[4], double v[4][4])
+{
+    int i, j, k, iq, ip;
+    double tresh, theta, tau, t, sm, s, h, g, c;
+    double b[4], z[4], tmp;
+
+    // initialize
+    for (ip=0; ip<4; ip++) 
+    {
+	for (iq=0; iq<4; iq++) v[ip][iq] = 0.0;
+	v[ip][ip] = 1.0;
+    }
+    for (ip=0; ip<4; ip++) 
+    {
+	b[ip] = w[ip] = a[ip][ip];
+	z[ip] = 0.0;
+    }
+
+    // begin rotation sequence
+    for (i=0; i<MAX_ROTATIONS; i++) 
+    {
+	sm = 0.0;
+	for (ip=0; ip<3; ip++) 
+	{
+	    for (iq=ip+1; iq<4; iq++) sm += fabs(a[ip][iq]);
+	}
+	if (sm == 0.0) break;
+
+	if (i < 4) tresh = 0.2*sm/(16);
+	else tresh = 0.0;
+
+	for (ip=0; ip<3; ip++) 
+	{
+	    for (iq=ip+1; iq<4; iq++) 
+	    {
+		g = 100.0*fabs(a[ip][iq]);
+		if (i > 4 && (fabs(w[ip])+g) == fabs(w[ip])
+		    && (fabs(w[iq])+g) == fabs(w[iq]))
+		{
+		    a[ip][iq] = 0.0;
+		}
+		else if (fabs(a[ip][iq]) > tresh) 
+		{
+		    h = w[iq] - w[ip];
+		    if ( (fabs(h)+g) == fabs(h)) t = (a[ip][iq]) / h;
+		    else 
+		    {
+			theta = 0.5*h / (a[ip][iq]);
+			t = 1.0 / (fabs(theta)+sqrt(1.0+theta*theta));
+			if (theta < 0.0) t = -t;
+		    }
+		    c = 1.0 / sqrt(1+t*t);
+		    s = t*c;
+		    tau = s/(1.0+c);
+		    h = t*a[ip][iq];
+		    z[ip] -= h;
+		    z[iq] += h;
+		    w[ip] -= h;
+		    w[iq] += h;
+		    a[ip][iq]=0.0;
+		    for (j=0;j<ip-1;j++) 
+		    {
+			ROT(a,j,ip,j,iq)
+			    }
+		    for (j=ip+1;j<iq-1;j++) 
+		    {
+			ROT(a,ip,j,j,iq)
+			    }
+		    for (j=iq+1; j<4; j++) 
+		    {
+			ROT(a,ip,j,iq,j)
+			    }
+		    for (j=0; j<4; j++) 
+		    {
+			ROT(v,j,ip,j,iq)
+			    }
+		}
+	    }
+	}
+
+	for (ip=0; ip<4; ip++) 
+	{
+	    b[ip] += z[ip];
+	    w[ip] = b[ip];
+	    z[ip] = 0.0;
+	}
+    }
+
+    if ( i >= MAX_ROTATIONS )
+    {
+	mxmsg_signal(MXMSG_WARN, "Error computing eigenvalues.", "jacobi");
+	return false;
+    }
+
+    // sort eigenfunctions
+    for (j=0; j<4; j++) 
+    {
+	k = j;
+	tmp = w[k];
+	for (i=j; i<4; i++)
+	{
+	    if (w[i] >= tmp) 
+	    {
+		k = i;
+		tmp = w[k];
+	    }
+	}
+	if (k != j) 
+	{
+	    w[k] = w[j];
+	    w[j] = tmp;
+	    for (i=0; i<4; i++) 
+	    {
+		tmp = v[i][j];
+		v[i][j] = v[i][k];
+		v[i][k] = tmp;
+	    }
+	}
+    }
+    // insure eigenvector consistency (i.e., Jacobi can compute vectors that
+    // are negative of one another (.707,.707,0) and (-.707,-.707,0). This can
+    // reek havoc in hyperstreamline/other stuff. We will select the most
+    // positive eigenvector.
+    int numPos;
+    for (j=0; j<4; j++)
+    {
+	for (numPos=0, i=0; i<4; i++) if ( v[i][j] >= 0.0 ) numPos++;
+	if ( numPos < 3 ) for(i=0; i<4; i++) v[i][j] *= -1.0;
+    }
+
+    return true;
+}
+
+
+#undef ROT
+#undef MAX_ROTATIONS
+
+bool jacobi(const Mat4& m, Vec4& eig_vals, Vec4 eig_vecs[4])
+{
+    double a[4][4], w[4], v[4][4];
+    int i,j;
+
+    for(i=0;i<4;i++) for(j=0;j<4;j++) a[i][j] = m(i,j);
+
+    bool result = internal_jacobi4(a, w, v);
+    if( result )
+    {
+	for(i=0;i<4;i++) eig_vals[i] = w[i];
+
+	for(i=0;i<4;i++) for(j=0;j<4;j++) eig_vecs[i][j] = v[j][i];
+    }
+
+    return result;
+}
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxStack.h
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxStack.h	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxStack.h	(revision 1097)
@@ -0,0 +1,48 @@
+#ifndef MXSTACK_INCLUDED // -*- C++ -*-
+#define MXSTACK_INCLUDED
+#if !defined(__GNUC__)
+#  pragma once
+#endif
+
+/************************************************************************
+
+  This provides a very simple typed-access stack class.  It's really
+  just a convenience wrapper for the underlying MxDynBlock class.
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxStack.h,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "MxDynBlock.h"
+
+template<class T>
+class MxStack : private MxDynBlock<T>
+{
+public:
+    MxStack(unsigned int n) : MxDynBlock<T>(n)
+	{ }
+    MxStack(const T& val, unsigned int n) : MxDynBlock<T>(n)
+	{ push(val); }
+
+    T&       top()       { return last(); }
+    const T& top() const { return last(); }
+
+    bool is_empty() { return length()==0; }
+
+    T& pop() { return drop(); }
+
+    void push(const T& val) { add(val); }
+    //
+    // NOTE: In this code, it is *crucial* that we do the add() and
+    //       assignment in separate steps.  The obvious alternative
+    //       is something like { add(top()); }.  But this is subtly
+    //       broken!  The top() will grab a pointer into the block,
+    //       but the add() may reallocate the block before doing the
+    //       assignment.  Thus, the pointer will become invalid.
+    void push() { add(); top() = raw(length()-2); }
+};
+
+// MXSTACK_INCLUDED
+#endif
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxStdPane.cxx
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxStdPane.cxx	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxStdPane.cxx	(revision 1097)
@@ -0,0 +1,321 @@
+/************************************************************************
+
+  MxStdPane
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxStdPane.cxx,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "stdmix.h"
+#include "MxStdPane.h"
+#include "MxGLUtils.h"
+
+#define MX_SELECT_NONE 0
+#define MX_SELECT_FACE 1
+#define MX_SELECT_VERT 2
+
+void MxStdPane::bind_asp_vars(MxAspStore *store)
+{
+    store->defvar("cam.fovy", MXASP_DOUBLE, &camera.fovy);
+    store->defvar("cam.aspect", MXASP_DOUBLE, &camera.aspect);
+    store->defvar("cam.znear", MXASP_DOUBLE, &camera.znear);
+    store->defvar("cam.zfar", MXASP_DOUBLE, &camera.zfar);
+    store->defvar("cam.from", MXASP_DOUBLE, (double*)camera.from, 3);
+    store->defvar("cam.at", MXASP_DOUBLE, (double *)camera.at, 3);
+    store->defvar("cam.up", MXASP_DOUBLE, (double *)camera.up, 3);
+
+    store->defvar("light.pos", MXASP_FLOAT, light_position, 3);
+
+    store->defvar("bounds.min", MXASP_DOUBLE, (double*)bounds.min, 3);
+    store->defvar("bounds.max", MXASP_DOUBLE, (double*)bounds.max, 3);
+    store->defvar("bounds.ctr", MXASP_DOUBLE, (double*)bounds.center, 3);
+    store->defvar("bounds.radius", MXASP_DOUBLE, &bounds.radius, 1);
+
+    store->defvar("manip.vnow", MXASP_DOUBLE, (double*)manip.vNow, 4);
+    store->defvar("manip.cam", MXASP_FLOAT, (double*)manip.cam, 3);
+
+    store->defvar("will_draw_surface", MXASP_BOOL, &will_draw_surface);
+    store->defvar("will_draw_mesh", MXASP_BOOL, &will_draw_mesh);
+    store->defvar("will_draw_points", MXASP_BOOL, &will_draw_points);
+    store->defvar("will_draw_texture", MXASP_BOOL, &will_draw_texture);
+    store->defvar("will_illustrate", MXASP_BOOL, &will_illustrate);
+    store->defvar("will_light_scene", MXASP_BOOL, &will_light_scene);
+    store->defvar("ntsc_output", MXASP_BOOL, &ntsc_output);
+
+    extern float mx_mesh_color[3];
+    store->defvar("mesh_color", MXASP_FLOAT, mx_mesh_color, 3);
+}
+
+void MxStdPane::write_pane_config(ostream& out)
+{
+    out << "set cam.fovy " << camera.fovy << endl;
+    out << "set cam.aspect " << camera.aspect << endl;
+    out << "set cam.znear " << camera.znear << endl;
+    out << "set cam.zfar " << camera.zfar << endl;
+
+    out << "set cam.from " << camera.from[X] << " "
+	<< camera.from[Y] << " " << camera.from[Z] << endl;
+    out << "set cam.at " << camera.at[X] << " "
+	<< camera.at[Y] << " " << camera.at[Z] << endl;
+    out << "set cam.up " << camera.up[X] << " "
+	<< camera.up[Y] << " " << camera.up[Z] << endl;
+
+    glGetLightfv(GL_LIGHT0, GL_POSITION, light_position);
+    out << "set light.pos" << light_position[X] << " "
+	<< light_position[Y] << " " << light_position[Z] << endl;
+
+    out << "set manip.vnow " << manip.vNow[X] << " " << manip.vNow[Y] << " "
+	<< manip.vNow[Z] << " " << manip.vNow[W] << endl;
+    out << "set manip.cam " << manip.cam[X] << " " << manip.cam[Y] << " "
+	<< manip.cam[Z] << endl;
+}
+
+void MxStdPane::gl_init()
+{
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();
+    // camera.apply();
+    glMatrixMode(GL_MODELVIEW);
+
+    MxGLPane::gl_init();
+
+    glGetLightfv(GL_LIGHT0, GL_POSITION, light_position);
+    CAREFUL(mxgl_check_errors("at end of MxStdPane::gl_init"));
+
+    mxgl_default_texinit(m->texmap(), will_draw_texture);
+}
+
+uint MxStdPane::pick_something(int x, int y, double window, int mode)
+{
+    selection_state = mode;
+
+    MxGLPicker pick(x, y, window);
+    begin_redraw();  redraw();  end_redraw();
+
+    selection_state = MX_SELECT_NONE;
+    return pick.complete();
+}
+
+uint MxStdPane::pick_face(int x, int y)
+{
+    return pick_something(x, y, 1.0, MX_SELECT_FACE);
+}
+
+uint MxStdPane::pick_vertex(int x, int y)
+{
+    return pick_something(x, y, 16.0, MX_SELECT_VERT);
+}
+
+void MxStdPane::move_light(float dx, float dy, float dz)
+{
+    light_position[0] += dx;
+    light_position[1] += dy;
+    light_position[2] += dz;
+    glLightfv(GL_LIGHT0, GL_POSITION, light_position);
+}
+
+void MxStdPane::size(int width, int height)
+{
+    MxGLPane::size(width, height);
+    
+    camera.look_at(bounds, (float)width / (float)height);
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();
+    //camera.apply();
+}
+
+void MxStdPane::button(int kind, int which, int x, int y)
+{
+    switch( kind&0xf )
+    {
+    case MX_BUTTONDOWN:
+        if( manip.mouse_down(which, x, y, kind) )
+            post_redraw();
+        break;
+
+    case MX_BUTTONUP:
+        if( manip.mouse_up(which, x, y, kind) )
+            post_redraw();
+        break;
+
+    case MX_POINTERMOTION:
+        if( manip.motion(x, y) )
+            post_redraw();
+        break;
+    }
+}
+
+void MxStdPane::key(char c)
+{
+    switch( c )
+    {
+    case 'm':
+        will_draw_mesh = !will_draw_mesh;
+        if( will_draw_mesh )
+            glOffsetForMesh();
+        else
+            glNoOffset();
+        break;
+
+    case 'L':
+	if( will_light_scene )
+	    glDisable(GL_LIGHTING);
+	else
+	    glEnable(GL_LIGHTING);
+	will_light_scene = !will_light_scene;
+	break;
+
+    case 'p': will_draw_points = !will_draw_points; break;
+
+    case 'x':  snapshot_ppm(); return;
+    case 'X':  snapshot_tiff(); return;
+	
+    case 's':
+        will_draw_surface = !will_draw_surface;
+        break;
+
+    case 't':
+        will_draw_texture = !will_draw_texture;
+	if( m->texmap() )
+	{
+	    if( will_draw_texture ) glEnable(GL_TEXTURE_2D);
+	    else glDisable(GL_TEXTURE_2D);
+	}
+        break;
+
+    case 'i':  will_illustrate = !will_illustrate; break;
+
+    case 'n':
+        if(m->normal_binding()==MX_PERFACE)  m->normal_binding(MX_PERVERTEX);
+        else  m->normal_binding(MX_PERFACE);
+        m->synthesize_normals();
+        break;
+
+    case 'V':
+	ntsc_output = !ntsc_output;
+	if( ntsc_output )
+	{
+	    glEnable(GL_LINE_SMOOTH);
+	    glLineWidth(1.5);
+	}
+	else
+	{
+	    glDisable(GL_LINE_SMOOTH);
+	    glLineWidth(1.0);
+	}
+	break;
+
+    case 'D': write_pane_config(cerr); return;
+
+    case 'q':
+	quit();
+	break;
+
+    case MXKEY_DEL: case MXKEY_BS: if(typein.length()) typein.drop(); break;
+    case '@':  typein.reset(); break;
+
+    default:
+	if( c>='0' && c<='9' )
+	    typein.add(c);
+	else
+	    return;
+
+	break;
+    }
+
+    post_redraw();
+}
+
+void MxStdPane::begin_redraw()
+{
+    MxGLPane::begin_redraw();
+
+    if( will_draw_mesh ) glOffsetForMesh(); else glNoOffset();
+    if( will_light_scene ) glEnable(GL_LIGHTING); else glDisable(GL_LIGHTING);
+
+    glMatrixMode(GL_PROJECTION);
+    // Conserve stack space by avoiding glPushMatrix
+    glGetDoublev(GL_PROJECTION_MATRIX, __proj_save);
+    camera.apply();
+
+    glMatrixMode(GL_MODELVIEW);
+    manip.apply();
+
+    // Use a pure white surface color when we're texturing
+    if( will_draw_texture )
+	glC(1.0, 1.0, 1.0);
+    else
+	// glC(0.5, 0.5, 0.5);
+	glC(0.569, 0.447, 0.315);
+
+    CAREFUL(mxgl_check_errors("at end of MxStdPane::begin_redraw"));
+}
+
+void MxStdPane::end_redraw()
+{
+    manip.unapply();
+    glMatrixMode(GL_PROJECTION);
+    glLoadMatrixd(__proj_save);	// Explicit save to save stack space
+    glMatrixMode(GL_MODELVIEW);
+    MxGLPane::end_redraw();
+    CAREFUL(mxgl_check_errors("at end of MxStdPane::end_redraw"));
+}
+
+void MxStdPane::redraw()
+{
+    if( !selection_state )
+    {
+	if( will_draw_surface )
+	{
+	    mx_render_model(*m);
+	    if( will_draw_mesh )
+		mx_draw_mesh(*m);
+	}
+	else if( will_draw_mesh )
+	    mx_draw_wireframe(*m);
+
+	if( will_draw_points )
+	    mx_draw_pointcloud(*m);
+    }
+    else if( selection_state == MX_SELECT_FACE )
+	mx_render_model(*m);
+    else if( selection_state == MX_SELECT_VERT )
+	mx_draw_pointcloud(*m);
+}
+
+void MxStdPane::illustrate()
+{
+    if( !will_illustrate )  return;
+
+    char buf[128];
+    int w, h;
+    get_canvas_geometry(NULL, NULL, &w, &h);
+
+    if( typein.length() )
+    {
+	buf[0] = '>';
+	buf[1] = ' ';
+	strncpy(buf+2, typein, typein.length());
+	buf[typein.length() + 2] = '\0';
+
+	draw_string(10, h-30, buf);
+    }
+}
+
+#ifdef WIN32
+
+void MxStdPane::quit()
+{
+    DestroyWindow();
+}
+
+#else
+
+void MxStdPane::quit()
+{
+    exit(0);
+}
+
+#endif
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxEdgeFilter.h
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxEdgeFilter.h	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxEdgeFilter.h	(revision 1097)
@@ -0,0 +1,57 @@
+#ifndef MXEDGEFILTER_INCLUDED // -*- C++ -*-
+#define MXEDGEFILTER_INCLUDED
+
+/************************************************************************
+
+  MxEdgeFilter
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxEdgeFilter.h,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "MxStdModel.h"
+#include "MxHeap.h"
+
+class MxRankedEdge : public MxEdge, public MxHeapable
+{
+public:
+    MxRankedEdge(MxVertexID v1, MxVertexID v2) : MxEdge(v1,v2) { }
+};
+
+class MxEdgeFilter
+{
+private:
+    MxHeap heap;
+    MxDynBlock<MxRankedEdge *> update_list;
+
+    bool filter1();
+
+protected:
+    MxStdModel *m;
+
+    MxRankedEdge *create_edge(MxVertexID, MxVertexID, bool will_rank=true);
+    void collect_edges();
+    void collect_star_for_update(MxVertexID);
+    void rank_and_update_edge(MxRankedEdge *);
+
+    MxVertexID split_edge(MxRankedEdge *);
+
+    virtual float compute_edge_rank(MxRankedEdge *);
+    virtual void filter_target_edge(MxRankedEdge *);
+
+public:
+    uint original_edge_count;
+    uint current_edge_count;
+
+public:
+    MxEdgeFilter(MxStdModel *m0);
+
+    void initialize();
+    bool filter(uint target);
+    bool filter_above_rank(float);
+};
+
+// MXEDGEFILTER_INCLUDED
+#endif
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxPropSlim.cxx
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxPropSlim.cxx	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxPropSlim.cxx	(revision 1097)
@@ -0,0 +1,548 @@
+/************************************************************************
+
+  MxPropSlim
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxPropSlim.cxx,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "stdmix.h"
+#include "MxPropSlim.h"
+#include "MxGeom3D.h"
+
+typedef MxQuadric Quadric;
+
+MxPropSlim::MxPropSlim(MxStdModel *m0)
+    : MxStdSlim(m0),
+      __quadrics(m0->vert_count()),
+      edge_links(m0->vert_count())
+{
+    consider_color();
+    consider_texture();
+    consider_normals();
+
+    D = compute_dimension(m);
+
+    will_decouple_quadrics = false;
+}
+
+void MxPropSlim::consider_color(bool will)
+{
+    use_color = will && (m->color_binding() == MX_PERVERTEX);
+    D = compute_dimension(m);
+}
+
+void MxPropSlim::consider_texture(bool will)
+{
+    use_texture = will && (m->texcoord_binding() == MX_PERVERTEX);
+    D = compute_dimension(m);
+}
+
+void MxPropSlim::consider_normals(bool will)
+{
+    use_normals = will && (m->normal_binding() == MX_PERVERTEX);
+    D = compute_dimension(m);
+}
+
+uint MxPropSlim::compute_dimension(MxStdModel *m)
+{
+    uint d = 3;
+
+    if( use_color )  d += 3;
+    if( use_texture )  d += 2;
+    if( use_normals )  d += 3;
+
+    return d;
+}
+
+void MxPropSlim::pack_to_vector(MxVertexID id, MxVector& v)
+{
+    SanityCheck( v.dim() == D );
+    SanityCheck( id < m->vert_count() );
+
+    v[0] = m->vertex(id)[0];
+    v[1] = m->vertex(id)[1];
+    v[2] = m->vertex(id)[2];
+
+    uint i = 3;
+    if( use_color )
+    {
+	v[i++] = m->color(id).R();
+	v[i++] = m->color(id).G();
+	v[i++] = m->color(id).B();
+    }
+    if( use_texture )
+    {
+	v[i++] = m->texcoord(id)[0];
+	v[i++] = m->texcoord(id)[1];
+    }
+    if( use_normals )
+    {
+	v[i++] = m->normal(id)[0];
+	v[i++] = m->normal(id)[1];
+	v[i++] = m->normal(id)[2];
+    }
+}
+
+void MxPropSlim::pack_prop_to_vector(MxVertexID id, MxVector& v, uint target)
+{
+    if( target == 0 )
+    {
+	v[0] = m->vertex(id)[0];
+	v[1] = m->vertex(id)[1];
+	v[2] = m->vertex(id)[2];
+	return;
+    }
+
+    uint i = 3;
+    target--;
+
+    if( use_color )
+    {
+	if( target == 0 )
+	{
+	    v[i]   = m->color(id).R();
+	    v[i+1] = m->color(id).G();
+	    v[i+2] = m->color(id).B();
+	    return;
+	}
+	i += 3;
+	target--;
+    }
+    if( use_texture )
+    {
+	if( target == 0 )
+	{
+	    v[i]   = m->texcoord(id)[0];
+	    v[i+1] = m->texcoord(id)[1];
+	    return;
+	}
+	i += 2;
+	target--;
+    }
+    if( use_normals )
+    {
+	if( target == 0 )
+	{
+	    v[i]   = m->normal(id)[0];
+	    v[i+1] = m->normal(id)[1];
+	    v[i+2] = m->normal(id)[2];
+	    return;
+	}
+    }
+}
+
+static inline void CLAMP(double& v, double lo, double hi)
+{
+    if( v<lo ) v = lo;
+    if( v>hi ) v = hi;
+}
+
+void MxPropSlim::unpack_from_vector(MxVertexID id, MxVector& v)
+{
+    SanityCheck( v.dim() == D );
+    SanityCheck( id < m->vert_count() );
+
+    m->vertex(id)[0] = v[0];
+    m->vertex(id)[1] = v[1];
+    m->vertex(id)[2] = v[2];
+
+    uint i = 3;
+    if( use_color )
+    {
+	CLAMP(v[i], 0, 1);
+	CLAMP(v[i+1], 0, 1);
+	CLAMP(v[i+2], 0, 1);
+	m->color(id).set(v[i], v[i+1], v[i+2]);
+	i += 3;
+    }
+    if( use_texture )
+    {
+	m->texcoord(id)[0] = v[i++];
+        m->texcoord(id)[1] = v[i++];
+    }
+    if( use_normals )
+    {
+	float n[3];  n[0]=v[i++];  n[1]=v[i++];  n[2]=v[i++];
+	mxv_unitize(n, 3);
+	m->normal(id).set(n[0], n[1], n[2]);
+    }
+}
+
+void MxPropSlim::unpack_prop_from_vector(MxVertexID id,MxVector& v,uint target)
+{
+    if( target == 0 )
+    {
+	m->vertex(id)[0] = v[0];
+	m->vertex(id)[1] = v[1];
+	m->vertex(id)[2] = v[2];
+	return;
+    }
+
+    uint i=3;
+    target--;
+
+    if( use_color )
+    {
+	if( target == 0 )
+	{
+	    m->color(id).set(v[i], v[i+1], v[i+2]);
+	    return;
+	}
+	i+=3;
+	target--;
+    }
+    if( use_texture )
+    {
+	if( target == 0 )
+	{
+	    m->texcoord(id)[0] = v[i];
+	    m->texcoord(id)[1] = v[i+1];
+	    return;
+	}
+	i += 2;
+	target--;
+    }
+    if( use_normals )
+    {
+	if( target == 0 )
+	{
+	    float n[3];  n[0]=v[i];  n[1]=v[i+1];  n[2]=v[i+2];
+	    mxv_unitize(n, 3);
+	    m->normal(id).set(n[0], n[1], n[2]);
+	    return;
+	}
+    }
+}
+
+
+uint MxPropSlim::prop_count()
+{
+    uint i = 1;
+
+    if( use_color ) i++;
+    if( use_texture) i++;
+    if( use_normals ) i++;
+
+    return i;
+}
+
+void MxPropSlim::compute_face_quadric(MxFaceID i, MxQuadric& Q)
+{
+    MxFace& f = m->face(i);
+
+    MxVector v1(dim());
+    MxVector v2(dim());
+    MxVector v3(dim());
+
+    if( will_decouple_quadrics )
+    {
+	Q.clear();
+
+	for(uint p=0; p<prop_count(); p++)
+	{
+	    v1=0.0;  v2=0.0;  v3=0.0;
+
+	    pack_prop_to_vector(f[0], v1, p);
+	    pack_prop_to_vector(f[1], v2, p);
+	    pack_prop_to_vector(f[2], v3, p);
+
+	    // !!BUG: Will count area multiple times (once per property)
+	    MxQuadric Q_p(v1, v2, v3, m->compute_face_area(i));
+
+	    // !!BUG: Need to only extract the relevant block of the matrix.
+	    //        Adding the whole thing gives us extraneous stuff.
+	    Q += Q_p;
+	}
+    }
+    else
+    {
+	pack_to_vector(f[0], v1);
+	pack_to_vector(f[1], v2);
+	pack_to_vector(f[2], v3);
+
+	Q = MxQuadric(v1, v2, v3, m->compute_face_area(i));
+    }
+}
+
+void MxPropSlim::collect_quadrics()
+{
+    for(uint j=0; j<quadric_count(); j++)
+	__quadrics[j] = new MxQuadric(dim());
+
+    for(MxFaceID i=0; i<m->face_count(); i++)
+    {
+	MxFace& f = m->face(i);
+
+	MxQuadric Q(dim());
+	compute_face_quadric(i, Q);
+
+// 	if( weight_by_area )
+// 	    Q *= Q.area();
+
+	quadric(f[0]) += Q;
+	quadric(f[1]) += Q;
+	quadric(f[2]) += Q;
+    }
+}
+
+void MxPropSlim::initialize()
+{
+    collect_quadrics();
+
+    if( boundary_weight > 0.0 )
+ 	constrain_boundaries();
+
+
+    collect_edges();
+
+    is_initialized = true;
+}
+
+void MxPropSlim::compute_target_placement(edge_info *info)
+{
+    MxVertexID i=info->v1, j=info->v2;
+
+    const MxQuadric &Qi=quadric(i), &Qj=quadric(j);
+    MxQuadric Q=Qi;  Q+=Qj;
+
+    double err;
+
+    if( Q.optimize(info->target) )
+    {
+	err = Q(info->target);
+    }
+    else
+    {
+	// Fall back only on endpoints
+
+	MxVector v_i(dim()), v_j(dim());
+
+	pack_to_vector(i, v_i);
+	pack_to_vector(j, v_j);
+
+	double e_i = Q(v_i);
+	double e_j = Q(v_j);
+
+	if( e_i<=e_j )
+	{
+	    info->target = v_i;
+	    err = e_i;
+	}
+	else
+	{
+	    info->target = v_j;
+	    err = e_j;
+	}
+    }
+
+//     if( weight_by_area )
+// 	err / Q.area();
+    info->heap_key(-err);
+}
+
+bool MxPropSlim::decimate(uint target)
+{
+    MxPairContraction conx;
+
+    while( valid_faces > target )
+    {
+	edge_info *info = (edge_info *)heap.extract();
+	if( !info )  return false;
+
+	MxVertexID v1=info->v1, v2=info->v2;
+
+	if( m->vertex_is_valid(v1) && m->vertex_is_valid(v2) )
+	{
+	    m->compute_contraction(v1, v2, &conx);
+
+	    conx.dv1[X] = info->target[X] - m->vertex(v1)[X];
+	    conx.dv1[Y] = info->target[Y] - m->vertex(v1)[Y];
+	    conx.dv1[Z] = info->target[Z] - m->vertex(v1)[Z];
+	    conx.dv2[X] = info->target[X] - m->vertex(v2)[X];
+	    conx.dv2[Y] = info->target[Y] - m->vertex(v2)[Y];
+	    conx.dv2[Z] = info->target[Z] - m->vertex(v2)[Z];
+
+	    apply_contraction(conx, info);
+	}
+
+	delete info;
+    }
+
+    return true;
+}
+
+
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// This is *very* close to the code in MxEdgeQSlim
+
+void MxPropSlim::create_edge(MxVertexID i, MxVertexID j)
+{
+    edge_info *info = new edge_info(dim());
+
+    edge_links(i).add(info);
+    edge_links(j).add(info);
+
+    info->v1 = i;
+    info->v2 = j;
+
+    compute_edge_info(info);
+}
+
+void MxPropSlim::discontinuity_constraint(MxVertexID i, MxVertexID j,
+					  const MxFaceList& faces)
+{
+    for(uint f=0; f<faces.length(); f++)
+    {
+	Vec3 org(m->vertex(i)), dest(m->vertex(j));
+	Vec3 e = dest - org;
+
+	Vec3 v1(m->vertex(m->face(faces(f))(0)));
+	Vec3 v2(m->vertex(m->face(faces(f))(1)));
+	Vec3 v3(m->vertex(m->face(faces(f))(2)));
+	Vec3 n = triangle_normal(v1,v2,v3);
+
+	Vec3 n2 = e ^ n;
+	unitize(n2);
+
+	MxQuadric3 Q3(n2, -(n2*org));
+	Q3 *= boundary_weight;
+
+	MxQuadric Q(Q3, dim());
+
+	quadric(i) += Q;
+	quadric(j) += Q;
+    }
+}
+
+void MxPropSlim::apply_contraction(const MxPairContraction& conx,
+				   edge_info *info)
+{
+    valid_verts--;
+    valid_faces -= conx.dead_faces.length();
+    quadric(conx.v1) += quadric(conx.v2);
+
+    update_pre_contract(conx);
+
+    m->apply_contraction(conx);
+
+    unpack_from_vector(conx.v1, info->target);
+
+    // Must update edge_info here so that the meshing penalties
+    // will be computed with respect to the new mesh rather than the old
+    for(uint i=0; i<edge_links(conx.v1).length(); i++)
+        compute_edge_info(edge_links(conx.v1)[i]);
+}
+
+
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// These were copied *unmodified* from MxEdgeQSlim
+// (with some unsupported features commented out).
+//
+
+void MxPropSlim::collect_edges()
+{
+    MxVertexList star;
+
+    for(MxVertexID i=0; i<m->vert_count(); i++)
+    {
+        star.reset();
+        m->collect_vertex_star(i, star);
+
+        for(uint j=0; j<star.length(); j++)
+            if( i < star(j) )  // Only add particular edge once
+                create_edge(i, star(j));
+    }
+}
+
+void MxPropSlim::constrain_boundaries()
+{
+    MxVertexList star;
+    MxFaceList faces;
+
+    for(MxVertexID i=0; i<m->vert_count(); i++)
+    {
+	star.reset();
+	m->collect_vertex_star(i, star);
+
+	for(uint j=0; j<star.length(); j++)
+	    if( i < star(j) )
+	    {
+		faces.reset();
+		m->collect_edge_neighbors(i, star(j), faces);
+		if( faces.length() == 1 )
+		    discontinuity_constraint(i, star(j), faces);
+	    }
+    }
+}
+
+void MxPropSlim::compute_edge_info(edge_info *info)
+{
+    compute_target_placement(info);
+
+//     if( will_normalize_error )
+//     {
+//         double e_max = Q_max(info->vnew);
+//         if( weight_by_area )
+//             e_max /= Q_max.area();
+
+//         info->heap_key(info->heap_key() / e_max);
+//     }
+
+    finalize_edge_update(info);
+}
+
+void MxPropSlim::finalize_edge_update(edge_info *info)
+{
+//     if( meshing_penalty > 1.0 )
+//         apply_mesh_penalties(info);
+
+    if( info->is_in_heap() )
+        heap.update(info);
+    else
+        heap.insert(info);
+}
+
+void MxPropSlim::update_pre_contract(const MxPairContraction& conx)
+{
+    MxVertexID v1=conx.v1, v2=conx.v2;
+    uint i, j;
+
+    star.reset();
+    m->collect_vertex_star(v1, star);
+
+    for(i=0; i<edge_links(v2).length(); i++)
+    {
+        edge_info *e = edge_links(v2)(i);
+        MxVertexID u = (e->v1==v2)?e->v2:e->v1;
+        SanityCheck( e->v1==v2 || e->v2==v2 );
+        SanityCheck( u!=v2 );
+
+        if( u==v1 || star.find(u) )
+        {
+            // This is a useless link --- kill it
+            bool found = edge_links(u).find(e, &j);
+            assert( found );
+            edge_links(u).remove(j);
+            heap.remove(e);
+            if( u!=v1 ) delete e; // (v1,v2) will be deleted later
+        }
+        else
+        {
+            // Relink this to v1
+            e->v1 = v1;
+            e->v2 = u;
+            edge_links(v1).add(e);
+        }
+    }
+
+    edge_links(v2).reset();
+}
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxLineModel.cxx
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxLineModel.cxx	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxLineModel.cxx	(revision 1097)
@@ -0,0 +1,25 @@
+/************************************************************************
+
+  MxLineModel
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxLineModel.cxx,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "stdmix.h"
+#include "MxLineModel.h"
+
+
+MxVertexID MxLineModel::add_vertex(float x, float y)
+{
+    MxVertexID id = vertices.add(MxVertex2D(x,y));
+    return id;
+}
+
+MxFaceID MxLineModel::add_segment(MxVertexID v1, MxVertexID v2)
+{
+    MxFaceID id = segments.add(MxSegment2D(v1, v2));
+    return id;
+}
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxQSlim.h
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxQSlim.h	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxQSlim.h	(revision 1097)
@@ -0,0 +1,121 @@
+#ifndef MXQSLIM_INCLUDED // -*- C++ -*-
+#define MXQSLIM_INCLUDED
+#if !defined(__GNUC__)
+#  pragma once
+#endif
+
+/************************************************************************
+
+  Surface simplification using quadric error metrics
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxQSlim.h,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "MxStdSlim.h"
+#include "MxQMetric3.h"
+
+class MxQSlim : public MxStdSlim
+{
+protected:
+    MxBlock<MxQuadric3> quadrics;
+
+    void discontinuity_constraint(MxVertexID, MxVertexID, const MxFaceList&);
+    void collect_quadrics();
+    void transform_quadrics(const Mat4&);
+    void constrain_boundaries();
+
+public:
+
+    Mat4 *object_transform;
+
+public:
+    MxQSlim(MxStdModel&);
+    virtual ~MxQSlim() { }
+
+    virtual void initialize();
+
+    const MxQuadric3& vertex_quadric(MxVertexID v) { return quadrics(v); }
+};
+
+class MxQSlimEdge : public MxEdge, public MxHeapable
+{
+public:
+    float vnew[3];
+};
+
+class MxEdgeQSlim : public MxQSlim
+{
+private:
+    typedef MxSizedDynBlock<MxQSlimEdge*, 6> edge_list;
+
+    MxBlock<edge_list> edge_links;
+
+    //
+    // Temporary variables used by methods
+    MxVertexList star, star2;
+    MxPairContraction conx_tmp;
+
+protected:
+    double check_local_compactness(uint v1, uint v2, const float *vnew);
+    double check_local_inversion(uint v1, uint v2, const float *vnew);
+    uint check_local_validity(uint v1, uint v2, const float *vnew);
+    uint check_local_degree(uint v1, uint v2, const float *vnew);
+    void apply_mesh_penalties(MxQSlimEdge *);
+    void create_edge(MxVertexID i, MxVertexID j);
+    void collect_edges();
+
+    void compute_target_placement(MxQSlimEdge *);
+    void finalize_edge_update(MxQSlimEdge *);
+
+    virtual void compute_edge_info(MxQSlimEdge *);
+    virtual void update_pre_contract(const MxPairContraction&);
+    virtual void update_post_contract(const MxPairContraction&);
+    virtual void update_pre_expand(const MxPairContraction&);
+    virtual void update_post_expand(const MxPairContraction&);
+
+public:
+    MxEdgeQSlim(MxStdModel&);
+    virtual ~MxEdgeQSlim();
+
+    void initialize();
+    void initialize(const MxEdge *edges, uint count);
+    bool decimate(uint target);
+
+    void apply_contraction(const MxPairContraction& conx);
+    void apply_expansion(const MxPairContraction& conx);
+
+    uint edge_count() const { return heap.size(); }
+    const MxQSlimEdge *edge(uint i) const {return (MxQSlimEdge *)heap.item(i);}
+
+public:
+    void (*contraction_callback)(const MxPairContraction&, float);
+};
+
+class MxFaceQSlim : public MxQSlim
+{
+private:
+    class tri_info : public MxHeapable
+    {
+    public:
+	MxFaceID f;
+	float vnew[3];
+    };
+
+    MxBlock<tri_info> f_info;
+
+protected:
+    void compute_face_info(MxFaceID);
+
+
+public:
+    MxFaceQSlim(MxStdModel&);
+
+    void initialize();
+    bool decimate(uint target);
+};
+
+// MXQSLIM_INCLUDED
+#endif
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxBlockModel.cxx
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxBlockModel.cxx	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxBlockModel.cxx	(revision 1097)
@@ -0,0 +1,263 @@
+/************************************************************************
+
+  MxBlockModel
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxBlockModel.cxx,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "stdmix.h"
+#include "MxBlockModel.h"
+#include "MxVector.h"
+
+////////////////////////////////////////////////////////////////////////
+//
+// Basic allocation routines
+//
+
+MxFaceID MxBlockModel::alloc_face(MxVertexID v1, MxVertexID v2, MxVertexID v3)
+{
+    return faces.add(MxFace(v1,v2,v3));
+}
+
+MxVertexID MxBlockModel::alloc_vertex(float x, float y, float z)
+{
+    return vertices.add(MxVertex(x,y,z));
+}
+
+MxVertexID MxBlockModel::add_vertex(float x, float y, float z)
+{
+    MxVertexID id = alloc_vertex(x,y,z);
+    init_vertex(id);
+    return id;
+}
+
+void MxBlockModel::remove_vertex(MxVertexID v)
+{
+    AssertBound( v < vertices.length() );
+
+    free_vertex(v);
+    vertices.remove(v);
+    if( normal_binding() == MX_PERVERTEX ) normals->remove(v);
+    if( color_binding() == MX_PERVERTEX ) colors->remove(v);
+    if( texcoord_binding() == MX_PERVERTEX ) tcoords->remove(v);
+}
+
+void MxBlockModel::remove_face(MxFaceID f)
+{
+    AssertBound( f < faces.length() );
+
+    free_face(f);
+    faces.remove(f);
+    if( normal_binding() == MX_PERFACE ) normals->remove(f);
+    if( color_binding() == MX_PERFACE ) colors->remove(f);
+    if( texcoord_binding() == MX_PERFACE ) tcoords->remove(f);
+}
+
+MxFaceID MxBlockModel::add_face(unsigned int v1,
+				unsigned int v2,
+				unsigned int v3,
+				bool will_link)
+{
+    MxFaceID id = alloc_face(v1, v2, v3);
+    if( will_link )  init_face(id);
+    return id;
+}
+
+unsigned int MxBlockModel::add_color(float r, float g, float b)
+{
+    assert( colors );
+    MxColor c(r, g, b);
+    return colors->add(c);
+}
+
+unsigned int MxBlockModel::add_normal(float x, float y, float z)
+{
+    MxNormal n(x, y, z);
+    return normals->add(n);
+}
+
+unsigned int MxBlockModel::add_texcoord(float s, float t)
+{
+    return tcoords->add(MxTexCoord(s,t));
+}
+
+uint MxBlockModel::add_texmap(MxRaster *t, const char *name)
+{
+    if( !t ) return MXID_NIL;
+    if( !name ) name = "tex";
+
+    if( tex ) delete tex;
+    if( tex_name ) delete tex_name;
+
+    tex_name = strdup(name);
+    tex = t;
+    return 0;
+}
+
+////////////////////////////////////////////////////////////////////////
+//
+// Property binding
+//
+
+static const char *bindings[] = {
+    "unbound",
+    "face",
+    "vertex",
+    NULL
+};
+
+static
+uint binding_size(MxBlockModel& m, unsigned char i)
+{
+    switch( i )
+    {
+    case MX_UNBOUND: return 0;
+    case MX_PERVERTEX: return MAX(1, m.vert_count());
+    case MX_PERFACE: return MAX(1, m.face_count());
+    default: return 0;
+    }
+}
+
+const char *MxBlockModel::binding_name(int b)
+{
+    if( b > MX_MAX_BINDING )
+	return NULL;
+    else
+	return bindings[b];
+}
+    
+int MxBlockModel::parse_binding(const char *name)
+{
+    for(int i=0; i<=MX_MAX_BINDING; i++)
+	if( streq(bindings[i], name) )  return i;
+
+    return MX_UNBOUND;
+}
+
+void MxBlockModel::color_binding(unsigned char b)
+{
+    int size = binding_size(*this, b);
+
+    if( b==MX_UNBOUND )
+    {
+	if( colors ) { delete colors; colors=NULL; }
+	binding_mask &= (~MX_COLOR_MASK);
+    }
+    else
+    {
+	if( colors )
+	    colors->reset();
+	else
+	    colors = new MxDynBlock<MxColor>(size);
+	binding_mask |= MX_COLOR_MASK;
+    }
+
+    cbinding=b;
+}
+
+void MxBlockModel::normal_binding(unsigned char b)
+{
+    int size = binding_size(*this, b);
+
+    if( b==MX_UNBOUND )
+    {
+	if( normals ) { delete normals; normals=NULL; }
+	binding_mask &= (~MX_NORMAL_MASK);
+    }
+    else
+    {
+	if( normals )
+	    normals->reset();
+	else
+	    normals = new MxDynBlock<MxNormal>(size);
+	binding_mask |= MX_NORMAL_MASK;
+    }
+
+    nbinding=b;
+}
+
+void MxBlockModel::texcoord_binding(unsigned char b)
+{
+    if( b!=MX_UNBOUND && b!=MX_PERVERTEX )
+	fatal_error("Illegal texture coordinate binding.");
+
+    int size = binding_size(*this, b);
+    if( tcoords )  tcoords->reset();
+    else tcoords = new MxDynBlock<MxTexCoord>(size);
+
+    tbinding = b;
+}
+
+////////////////////////////////////////////////////////////////////////
+//
+// Utility methods for computing characteristics of faces.
+//
+
+void MxBlockModel::compute_face_normal(MxFaceID f, float *n, bool will_unitize)
+{
+    float *v1 = vertex(face(f)[0]);
+    float *v2 = vertex(face(f)[1]);
+    float *v3 = vertex(face(f)[2]);
+
+    float a[3], b[3];
+
+    mxv_sub(a, v2, v1, 3);
+    mxv_sub(b, v3, v1, 3);
+    mxv_cross3(n, a, b);
+    if( will_unitize )
+	mxv_unitize(n, 3);
+}
+
+void MxBlockModel::compute_face_normal(MxFaceID f, double *n,bool will_unitize)
+{
+    float *v1 = vertex(face(f)[0]);
+    float *v2 = vertex(face(f)[1]);
+    float *v3 = vertex(face(f)[2]);
+
+    double a[3], b[3];
+    for(int i=0; i<3; i++) { a[i] = v2[i]-v1[i];  b[i] = v3[i]-v1[i]; }
+
+    mxv_cross3(n, a, b);
+    if( will_unitize )
+	mxv_unitize(n, 3);
+}
+
+double MxBlockModel::compute_face_area(MxFaceID f)
+{
+    double n[3];
+
+    compute_face_normal(f, n, false);
+    return 0.5 * mxv_norm(n, 3);
+}
+
+double MxBlockModel::compute_face_perimeter(MxFaceID fid, bool *flags)
+{
+    double perim = 0.0;
+    const MxFace& f = face(fid);
+
+    for(uint i=0; i<3; i++)
+    {
+	if( !flags || flags[i] )
+	{
+	    float *vi = vertex(f[i]),  *vj = vertex(f[(i+1)%3]), e[3];
+	    perim += mxv_norm(mxv_sub(e, vi, vj, 3), 3);
+	}
+    }
+
+    return perim;
+}
+
+double MxBlockModel::compute_corner_angle(MxFaceID f, uint i)
+{
+    uint i_prev = (i==0)?2:i-1;
+    uint i_next = (i==2)?0:i+1;
+
+    float e_prev[3], e_next[3];
+    mxv_unitize(mxv_sub(e_prev, corner(f, i_prev), corner(f, i), 3), 3);
+    mxv_unitize(mxv_sub(e_next, corner(f, i_next), corner(f, i), 3), 3);
+
+    return acos(mxv_dot(e_prev, e_next, 3));
+}
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxQMetric2.h
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxQMetric2.h	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxQMetric2.h	(revision 1097)
@@ -0,0 +1,69 @@
+#ifndef MXQMETRIC2_INCLUDED // -*- C++ -*-
+#define MXQMETRIC2_INCLUDED
+#if !defined(__GNUC__)
+#  pragma once
+#endif
+
+/************************************************************************
+
+  2D Quadric Error Metric
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+
+  $Id: MxQMetric2.h,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "MxMath.h"
+#include "MxMat2.h"
+#include "MxMat3.h"
+
+class MxQuadric2
+{
+private:
+    double a2, ab, ac;
+    double     b2, bc;
+    double         c2;
+
+    double r;
+
+    void init(double a, double b, double c, double len);
+
+public:
+    MxQuadric2() { clear(); }
+    MxQuadric2(double a, double b, double c, double len=1.0)
+	{ init(a, b, c, len); }
+    MxQuadric2(const float *n, double c, double len=1.0)
+	{ init(n[X], n[Y], c, len); }
+    MxQuadric2(const double *n, double c, double len=1.0)
+	{ init(n[X], n[Y], c, len); }
+    MxQuadric2(const MxQuadric2& Q) { *this = Q; }
+
+    Mat2 tensor() const;
+    Vec2 vector() const { return Vec2(ac, bc); }
+    double offset() const { return c2; }
+    double length() const { return r; }
+    Mat3 homogeneous() const;
+
+    void clear(double val=0.0) { a2=ab=ac=b2=bc=c2=r=val; }
+    MxQuadric2& operator=(const MxQuadric2& Q);
+    MxQuadric2& operator+=(const MxQuadric2& Q);
+    MxQuadric2& operator-=(const MxQuadric2& Q);
+    MxQuadric2& operator*=(double s);
+
+    double evaluate(double x, double y) const;
+    double evaluate(const double *v) const { return evaluate(v[X], v[Y]); }
+    double evaluate(const float *v) const { return evaluate(v[X], v[Y]); }
+
+    double operator()(double x, double y) const { return evaluate(x,y); }
+    double operator()(const double *v) const  { return evaluate(v[X], v[Y]); }
+    double operator()(const float *v) const  { return evaluate(v[X], v[Y]); }
+
+    bool optimize(Vec2& v) const;
+    bool optimize(float *x, float *y) const;
+
+    //    bool optimize(Vec2& v, const Vec2& v1, const Vec2& v2) const;
+};
+
+// MXQMETRIC2_INCLUDED
+#endif
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/getopt.c
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/getopt.c	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/getopt.c	(revision 1097)
@@ -0,0 +1,1055 @@
+/* Getopt for GNU.
+   NOTE: getopt is now part of the C library, so if you don't know what
+   "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
+   before changing it!
+
+   Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97
+   	Free Software Foundation, Inc.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+
+/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.
+   Ditto for AIX 3.2 and <stdlib.h>.  */
+#ifndef _NO_PROTO
+#define _NO_PROTO
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#if !defined (__STDC__) || !__STDC__
+/* This is a separate conditional since some stdc systems
+   reject `defined (const)'.  */
+#ifndef const
+#define const
+#endif
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+   actually compiling the library itself.  This code is part of the GNU C
+   Library, but also included in many other GNU distributions.  Compiling
+   and linking in this code is a waste when using the GNU C library
+   (especially if it is a shared library).  Rather than having every GNU
+   program understand `configure --with-gnu-libc' and omit the object files,
+   it is simpler to just do this in the source for each such file.  */
+
+#define GETOPT_INTERFACE_VERSION 2
+#if !defined (_LIBC) && defined (__GLIBC__) && __GLIBC__ >= 2
+#include <gnu-versions.h>
+#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
+#define ELIDE_CODE
+#endif
+#endif
+
+#ifndef ELIDE_CODE
+
+
+/* This needs to come after some library #include
+   to get __GNU_LIBRARY__ defined.  */
+#ifdef	__GNU_LIBRARY__
+/* Don't include stdlib.h for non-GNU C libraries because some of them
+   contain conflicting prototypes for getopt.  */
+#include <stdlib.h>
+#include <unistd.h>
+#endif	/* GNU C library.  */
+
+#ifdef VMS
+#include <unixlib.h>
+#if HAVE_STRING_H - 0
+#include <string.h>
+#endif
+#endif
+
+#if defined (WIN32) && !defined (__CYGWIN32__)
+/* It's not Unix, really.  See?  Capital letters.  */
+#include <windows.h>
+#define getpid() GetCurrentProcessId()
+#endif
+
+#ifndef _
+/* This is for other GNU distributions with internationalized messages.
+   When compiling libc, the _ macro is predefined.  */
+#ifdef HAVE_LIBINTL_H
+# include <libintl.h>
+# define _(msgid)	gettext (msgid)
+#else
+# define _(msgid)	(msgid)
+#endif
+#endif
+
+/* This version of `getopt' appears to the caller like standard Unix `getopt'
+   but it behaves differently for the user, since it allows the user
+   to intersperse the options with the other arguments.
+
+   As `getopt' works, it permutes the elements of ARGV so that,
+   when it is done, all the options precede everything else.  Thus
+   all application programs are extended to handle flexible argument order.
+
+   Setting the environment variable POSIXLY_CORRECT disables permutation.
+   Then the behavior is completely standard.
+
+   GNU application programs can use a third alternative mode in which
+   they can distinguish the relative order of options and other arguments.  */
+
+#include "getopt.h"
+
+/* For communication from `getopt' to the caller.
+   When `getopt' finds an option that takes an argument,
+   the argument value is returned here.
+   Also, when `ordering' is RETURN_IN_ORDER,
+   each non-option ARGV-element is returned here.  */
+
+char *optarg = NULL;
+
+/* Index in ARGV of the next element to be scanned.
+   This is used for communication to and from the caller
+   and for communication between successive calls to `getopt'.
+
+   On entry to `getopt', zero means this is the first call; initialize.
+
+   When `getopt' returns -1, this is the index of the first of the
+   non-option elements that the caller should itself scan.
+
+   Otherwise, `optind' communicates from one call to the next
+   how much of ARGV has been scanned so far.  */
+
+/* 1003.2 says this must be 1 before any call.  */
+int optind = 1;
+
+/* Formerly, initialization of getopt depended on optind==0, which
+   causes problems with re-calling getopt as programs generally don't
+   know that. */
+
+int __getopt_initialized = 0;
+
+/* The next char to be scanned in the option-element
+   in which the last option character we returned was found.
+   This allows us to pick up the scan where we left off.
+
+   If this is zero, or a null string, it means resume the scan
+   by advancing to the next ARGV-element.  */
+
+static char *nextchar;
+
+/* Callers store zero here to inhibit the error message
+   for unrecognized options.  */
+
+int opterr = 1;
+
+/* Set to an option character which was unrecognized.
+   This must be initialized on some systems to avoid linking in the
+   system's own getopt implementation.  */
+
+int optopt = '?';
+
+/* Describe how to deal with options that follow non-option ARGV-elements.
+
+   If the caller did not specify anything,
+   the default is REQUIRE_ORDER if the environment variable
+   POSIXLY_CORRECT is defined, PERMUTE otherwise.
+
+   REQUIRE_ORDER means don't recognize them as options;
+   stop option processing when the first non-option is seen.
+   This is what Unix does.
+   This mode of operation is selected by either setting the environment
+   variable POSIXLY_CORRECT, or using `+' as the first character
+   of the list of option characters.
+
+   PERMUTE is the default.  We permute the contents of ARGV as we scan,
+   so that eventually all the non-options are at the end.  This allows options
+   to be given in any order, even with programs that were not written to
+   expect this.
+
+   RETURN_IN_ORDER is an option available to programs that were written
+   to expect options and other ARGV-elements in any order and that care about
+   the ordering of the two.  We describe each non-option ARGV-element
+   as if it were the argument of an option with character code 1.
+   Using `-' as the first character of the list of option characters
+   selects this mode of operation.
+
+   The special argument `--' forces an end of option-scanning regardless
+   of the value of `ordering'.  In the case of RETURN_IN_ORDER, only
+   `--' can cause `getopt' to return -1 with `optind' != ARGC.  */
+
+static enum
+{
+  REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
+} ordering;
+
+/* Value of POSIXLY_CORRECT environment variable.  */
+static char *posixly_correct;
+
+
+#ifdef	__GNU_LIBRARY__
+/* We want to avoid inclusion of string.h with non-GNU libraries
+   because there are many ways it can cause trouble.
+   On some systems, it contains special magic macros that don't work
+   in GCC.  */
+#include <string.h>
+#define	my_index	strchr
+#else
+
+/* Avoid depending on library functions or files
+   whose names are inconsistent.  */
+
+char *getenv ();
+
+static char *
+my_index (str, chr)
+     const char *str;
+     int chr;
+{
+  while (*str)
+    {
+      if (*str == chr)
+	return (char *) str;
+      str++;
+    }
+  return 0;
+}
+
+/* If using GCC, we can safely declare strlen this way.
+   If not using GCC, it is ok not to declare it.  */
+#ifdef __GNUC__
+/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h.
+   That was relevant to code that was here before.  */
+#if !defined (__STDC__) || !__STDC__
+/* gcc with -traditional declares the built-in strlen to return int,
+   and has done so at least since version 2.4.5. -- rms.  */
+extern int strlen (const char *);
+#endif /* not __STDC__ */
+#endif /* __GNUC__ */
+
+#endif /* not __GNU_LIBRARY__ */
+
+
+/* Handle permutation of arguments.  */
+
+/* Describe the part of ARGV that contains non-options that have
+   been skipped.  `first_nonopt' is the index in ARGV of the first of them;
+   `last_nonopt' is the index after the last of them.  */
+
+static int first_nonopt;
+static int last_nonopt;
+
+#ifdef _LIBC
+/* Bash 2.0 gives us an environment variable containing flags
+   indicating ARGV elements that should not be considered arguments.  */
+
+/* Defined in getopt_init.c  */
+extern char *__getopt_nonoption_flags;
+
+static int nonoption_flags_max_len;
+static int nonoption_flags_len;
+
+static int original_argc;
+static char *const *original_argv;
+
+extern pid_t __libc_pid;
+
+/* Make sure the environment variable bash 2.0 puts in the environment
+   is valid for the getopt call we must make sure that the ARGV passed
+   to getopt is that one passed to the process.  */
+static void
+__attribute__ ((unused))
+store_args_and_env (int argc, char *const *argv)
+{
+  /* XXX This is no good solution.  We should rather copy the args so
+     that we can compare them later.  But we must not use malloc(3).  */
+  original_argc = argc;
+  original_argv = argv;
+}
+text_set_element (__libc_subinit, store_args_and_env);
+
+# define SWAP_FLAGS(ch1, ch2) \
+  if (nonoption_flags_len > 0)						      \
+    {									      \
+      char __tmp = __getopt_nonoption_flags[ch1];			      \
+      __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2];	      \
+      __getopt_nonoption_flags[ch2] = __tmp;				      \
+    }
+#else	/* !_LIBC */
+# define SWAP_FLAGS(ch1, ch2)
+#endif	/* _LIBC */
+
+/* Exchange two adjacent subsequences of ARGV.
+   One subsequence is elements [first_nonopt,last_nonopt)
+   which contains all the non-options that have been skipped so far.
+   The other is elements [last_nonopt,optind), which contains all
+   the options processed since those non-options were skipped.
+
+   `first_nonopt' and `last_nonopt' are relocated so that they describe
+   the new indices of the non-options in ARGV after they are moved.  */
+
+#if defined (__STDC__) && __STDC__
+static void exchange (char **);
+#endif
+
+static void
+exchange (argv)
+     char **argv;
+{
+  int bottom = first_nonopt;
+  int middle = last_nonopt;
+  int top = optind;
+  char *tem;
+
+  /* Exchange the shorter segment with the far end of the longer segment.
+     That puts the shorter segment into the right place.
+     It leaves the longer segment in the right place overall,
+     but it consists of two parts that need to be swapped next.  */
+
+#ifdef _LIBC
+  /* First make sure the handling of the `__getopt_nonoption_flags'
+     string can work normally.  Our top argument must be in the range
+     of the string.  */
+  if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len)
+    {
+      /* We must extend the array.  The user plays games with us and
+	 presents new arguments.  */
+      char *new_str = malloc (top + 1);
+      if (new_str == NULL)
+	nonoption_flags_len = nonoption_flags_max_len = 0;
+      else
+	{
+	  memcpy (new_str, __getopt_nonoption_flags, nonoption_flags_max_len);
+	  memset (&new_str[nonoption_flags_max_len], '\0',
+		  top + 1 - nonoption_flags_max_len);
+	  nonoption_flags_max_len = top + 1;
+	  __getopt_nonoption_flags = new_str;
+	}
+    }
+#endif
+
+  while (top > middle && middle > bottom)
+    {
+      if (top - middle > middle - bottom)
+	{
+	  /* Bottom segment is the short one.  */
+	  int len = middle - bottom;
+	  register int i;
+
+	  /* Swap it with the top part of the top segment.  */
+	  for (i = 0; i < len; i++)
+	    {
+	      tem = argv[bottom + i];
+	      argv[bottom + i] = argv[top - (middle - bottom) + i];
+	      argv[top - (middle - bottom) + i] = tem;
+	      SWAP_FLAGS (bottom + i, top - (middle - bottom) + i);
+	    }
+	  /* Exclude the moved bottom segment from further swapping.  */
+	  top -= len;
+	}
+      else
+	{
+	  /* Top segment is the short one.  */
+	  int len = top - middle;
+	  register int i;
+
+	  /* Swap it with the bottom part of the bottom segment.  */
+	  for (i = 0; i < len; i++)
+	    {
+	      tem = argv[bottom + i];
+	      argv[bottom + i] = argv[middle + i];
+	      argv[middle + i] = tem;
+	      SWAP_FLAGS (bottom + i, middle + i);
+	    }
+	  /* Exclude the moved top segment from further swapping.  */
+	  bottom += len;
+	}
+    }
+
+  /* Update records for the slots the non-options now occupy.  */
+
+  first_nonopt += (optind - last_nonopt);
+  last_nonopt = optind;
+}
+
+/* Initialize the internal data when the first call is made.  */
+
+#if defined (__STDC__) && __STDC__
+static const char *_getopt_initialize (int, char *const *, const char *);
+#endif
+static const char *
+_getopt_initialize (argc, argv, optstring)
+     int argc;
+     char *const *argv;
+     const char *optstring;
+{
+  /* Start processing options with ARGV-element 1 (since ARGV-element 0
+     is the program name); the sequence of previously skipped
+     non-option ARGV-elements is empty.  */
+
+  first_nonopt = last_nonopt = optind;
+
+  nextchar = NULL;
+
+  posixly_correct = getenv ("POSIXLY_CORRECT");
+
+  /* Determine how to handle the ordering of options and nonoptions.  */
+
+  if (optstring[0] == '-')
+    {
+      ordering = RETURN_IN_ORDER;
+      ++optstring;
+    }
+  else if (optstring[0] == '+')
+    {
+      ordering = REQUIRE_ORDER;
+      ++optstring;
+    }
+  else if (posixly_correct != NULL)
+    ordering = REQUIRE_ORDER;
+  else
+    ordering = PERMUTE;
+
+#ifdef _LIBC
+  if (posixly_correct == NULL
+      && argc == original_argc && argv == original_argv)
+    {
+      if (nonoption_flags_max_len == 0)
+	{
+	  if (__getopt_nonoption_flags == NULL
+	      || __getopt_nonoption_flags[0] == '\0')
+	    nonoption_flags_max_len = -1;
+	  else
+	    {
+	      const char *orig_str = __getopt_nonoption_flags;
+	      int len = nonoption_flags_max_len = strlen (orig_str);
+	      if (nonoption_flags_max_len < argc)
+		nonoption_flags_max_len = argc;
+	      __getopt_nonoption_flags =
+		(char *) malloc (nonoption_flags_max_len);
+	      if (__getopt_nonoption_flags == NULL)
+		nonoption_flags_max_len = -1;
+	      else
+		{
+		  memcpy (__getopt_nonoption_flags, orig_str, len);
+		  memset (&__getopt_nonoption_flags[len], '\0',
+			  nonoption_flags_max_len - len);
+		}
+	    }
+	}
+      nonoption_flags_len = nonoption_flags_max_len;
+    }
+  else
+    nonoption_flags_len = 0;
+#endif
+
+  return optstring;
+}
+
+
+/* Scan elements of ARGV (whose length is ARGC) for option characters
+   given in OPTSTRING.
+
+   If an element of ARGV starts with '-', and is not exactly "-" or "--",
+   then it is an option element.  The characters of this element
+   (aside from the initial '-') are option characters.  If `getopt'
+   is called repeatedly, it returns successively each of the option characters
+   from each of the option elements.
+
+   If `getopt' finds another option character, it returns that character,
+   updating `optind' and `nextchar' so that the next call to `getopt' can
+   resume the scan with the following option character or ARGV-element.
+
+   If there are no more option characters, `getopt' returns -1.
+   Then `optind' is the index in ARGV of the first ARGV-element
+   that is not an option.  (The ARGV-elements have been permuted
+   so that those that are not options now come last.)
+
+   OPTSTRING is a string containing the legitimate option characters.
+   If an option character is seen that is not listed in OPTSTRING,
+   return '?' after printing an error message.  If you set `opterr' to
+   zero, the error message is suppressed but we still return '?'.
+
+   If a char in OPTSTRING is followed by a colon, that means it wants an arg,
+   so the following text in the same ARGV-element, or the text of the following
+   ARGV-element, is returned in `optarg'.  Two colons mean an option that
+   wants an optional arg; if there is text in the current ARGV-element,
+   it is returned in `optarg', otherwise `optarg' is set to zero.
+
+   If OPTSTRING starts with `-' or `+', it requests different methods of
+   handling the non-option ARGV-elements.
+   See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
+
+   Long-named options begin with `--' instead of `-'.
+   Their names may be abbreviated as long as the abbreviation is unique
+   or is an exact match for some defined option.  If they have an
+   argument, it follows the option name in the same ARGV-element, separated
+   from the option name by a `=', or else the in next ARGV-element.
+   When `getopt' finds a long-named option, it returns 0 if that option's
+   `flag' field is nonzero, the value of the option's `val' field
+   if the `flag' field is zero.
+
+   The elements of ARGV aren't really const, because we permute them.
+   But we pretend they're const in the prototype to be compatible
+   with other systems.
+
+   LONGOPTS is a vector of `struct option' terminated by an
+   element containing a name which is zero.
+
+   LONGIND returns the index in LONGOPT of the long-named option found.
+   It is only valid when a long-named option has been found by the most
+   recent call.
+
+   If LONG_ONLY is nonzero, '-' as well as '--' can introduce
+   long-named options.  */
+
+int
+_getopt_internal (argc, argv, optstring, longopts, longind, long_only)
+     int argc;
+     char *const *argv;
+     const char *optstring;
+     const struct option *longopts;
+     int *longind;
+     int long_only;
+{
+  optarg = NULL;
+
+  if (optind == 0 || !__getopt_initialized)
+    {
+      if (optind == 0)
+	optind = 1;	/* Don't scan ARGV[0], the program name.  */
+      optstring = _getopt_initialize (argc, argv, optstring);
+      __getopt_initialized = 1;
+    }
+
+  /* Test whether ARGV[optind] points to a non-option argument.
+     Either it does not have option syntax, or there is an environment flag
+     from the shell indicating it is not an option.  The later information
+     is only used when the used in the GNU libc.  */
+#ifdef _LIBC
+#define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0'	      \
+		     || (optind < nonoption_flags_len			      \
+			 && __getopt_nonoption_flags[optind] == '1'))
+#else
+#define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0')
+#endif
+
+  if (nextchar == NULL || *nextchar == '\0')
+    {
+      /* Advance to the next ARGV-element.  */
+
+      /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been
+	 moved back by the user (who may also have changed the arguments).  */
+      if (last_nonopt > optind)
+	last_nonopt = optind;
+      if (first_nonopt > optind)
+	first_nonopt = optind;
+
+      if (ordering == PERMUTE)
+	{
+	  /* If we have just processed some options following some non-options,
+	     exchange them so that the options come first.  */
+
+	  if (first_nonopt != last_nonopt && last_nonopt != optind)
+	    exchange ((char **) argv);
+	  else if (last_nonopt != optind)
+	    first_nonopt = optind;
+
+	  /* Skip any additional non-options
+	     and extend the range of non-options previously skipped.  */
+
+	  while (optind < argc && NONOPTION_P)
+	    optind++;
+	  last_nonopt = optind;
+	}
+
+      /* The special ARGV-element `--' means premature end of options.
+	 Skip it like a null option,
+	 then exchange with previous non-options as if it were an option,
+	 then skip everything else like a non-option.  */
+
+      if (optind != argc && !strcmp (argv[optind], "--"))
+	{
+	  optind++;
+
+	  if (first_nonopt != last_nonopt && last_nonopt != optind)
+	    exchange ((char **) argv);
+	  else if (first_nonopt == last_nonopt)
+	    first_nonopt = optind;
+	  last_nonopt = argc;
+
+	  optind = argc;
+	}
+
+      /* If we have done all the ARGV-elements, stop the scan
+	 and back over any non-options that we skipped and permuted.  */
+
+      if (optind == argc)
+	{
+	  /* Set the next-arg-index to point at the non-options
+	     that we previously skipped, so the caller will digest them.  */
+	  if (first_nonopt != last_nonopt)
+	    optind = first_nonopt;
+	  return -1;
+	}
+
+      /* If we have come to a non-option and did not permute it,
+	 either stop the scan or describe it to the caller and pass it by.  */
+
+      if (NONOPTION_P)
+	{
+	  if (ordering == REQUIRE_ORDER)
+	    return -1;
+	  optarg = argv[optind++];
+	  return 1;
+	}
+
+      /* We have found another option-ARGV-element.
+	 Skip the initial punctuation.  */
+
+      nextchar = (argv[optind] + 1
+		  + (longopts != NULL && argv[optind][1] == '-'));
+    }
+
+  /* Decode the current option-ARGV-element.  */
+
+  /* Check whether the ARGV-element is a long option.
+
+     If long_only and the ARGV-element has the form "-f", where f is
+     a valid short option, don't consider it an abbreviated form of
+     a long option that starts with f.  Otherwise there would be no
+     way to give the -f short option.
+
+     On the other hand, if there's a long option "fubar" and
+     the ARGV-element is "-fu", do consider that an abbreviation of
+     the long option, just like "--fu", and not "-f" with arg "u".
+
+     This distinction seems to be the most useful approach.  */
+
+  if (longopts != NULL
+      && (argv[optind][1] == '-'
+	  || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1])))))
+    {
+      char *nameend;
+      const struct option *p;
+      const struct option *pfound = NULL;
+      int exact = 0;
+      int ambig = 0;
+      int indfound = -1;
+      int option_index;
+
+      for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
+	/* Do nothing.  */ ;
+
+      /* Test all long options for either exact match
+	 or abbreviated matches.  */
+      for (p = longopts, option_index = 0; p->name; p++, option_index++)
+	if (!strncmp (p->name, nextchar, nameend - nextchar))
+	  {
+	    if ((unsigned int) (nameend - nextchar)
+		== (unsigned int) strlen (p->name))
+	      {
+		/* Exact match found.  */
+		pfound = p;
+		indfound = option_index;
+		exact = 1;
+		break;
+	      }
+	    else if (pfound == NULL)
+	      {
+		/* First nonexact match found.  */
+		pfound = p;
+		indfound = option_index;
+	      }
+	    else
+	      /* Second or later nonexact match found.  */
+	      ambig = 1;
+	  }
+
+      if (ambig && !exact)
+	{
+	  if (opterr)
+	    fprintf (stderr, _("%s: option `%s' is ambiguous\n"),
+		     argv[0], argv[optind]);
+	  nextchar += strlen (nextchar);
+	  optind++;
+	  optopt = 0;
+	  return '?';
+	}
+
+      if (pfound != NULL)
+	{
+	  option_index = indfound;
+	  optind++;
+	  if (*nameend)
+	    {
+	      /* Don't test has_arg with >, because some C compilers don't
+		 allow it to be used on enums.  */
+	      if (pfound->has_arg)
+		optarg = nameend + 1;
+	      else
+		{
+		  if (opterr)
+		   if (argv[optind - 1][1] == '-')
+		    /* --option */
+		    fprintf (stderr,
+		     _("%s: option `--%s' doesn't allow an argument\n"),
+		     argv[0], pfound->name);
+		   else
+		    /* +option or -option */
+		    fprintf (stderr,
+		     _("%s: option `%c%s' doesn't allow an argument\n"),
+		     argv[0], argv[optind - 1][0], pfound->name);
+
+		  nextchar += strlen (nextchar);
+
+		  optopt = pfound->val;
+		  return '?';
+		}
+	    }
+	  else if (pfound->has_arg == 1)
+	    {
+	      if (optind < argc)
+		optarg = argv[optind++];
+	      else
+		{
+		  if (opterr)
+		    fprintf (stderr,
+			   _("%s: option `%s' requires an argument\n"),
+			   argv[0], argv[optind - 1]);
+		  nextchar += strlen (nextchar);
+		  optopt = pfound->val;
+		  return optstring[0] == ':' ? ':' : '?';
+		}
+	    }
+	  nextchar += strlen (nextchar);
+	  if (longind != NULL)
+	    *longind = option_index;
+	  if (pfound->flag)
+	    {
+	      *(pfound->flag) = pfound->val;
+	      return 0;
+	    }
+	  return pfound->val;
+	}
+
+      /* Can't find it as a long option.  If this is not getopt_long_only,
+	 or the option starts with '--' or is not a valid short
+	 option, then it's an error.
+	 Otherwise interpret it as a short option.  */
+      if (!long_only || argv[optind][1] == '-'
+	  || my_index (optstring, *nextchar) == NULL)
+	{
+	  if (opterr)
+	    {
+	      if (argv[optind][1] == '-')
+		/* --option */
+		fprintf (stderr, _("%s: unrecognized option `--%s'\n"),
+			 argv[0], nextchar);
+	      else
+		/* +option or -option */
+		fprintf (stderr, _("%s: unrecognized option `%c%s'\n"),
+			 argv[0], argv[optind][0], nextchar);
+	    }
+	  nextchar = (char *) "";
+	  optind++;
+	  optopt = 0;
+	  return '?';
+	}
+    }
+
+  /* Look at and handle the next short option-character.  */
+
+  {
+    char c = *nextchar++;
+    char *temp = my_index (optstring, c);
+
+    /* Increment `optind' when we start to process its last character.  */
+    if (*nextchar == '\0')
+      ++optind;
+
+    if (temp == NULL || c == ':')
+      {
+	if (opterr)
+	  {
+	    if (posixly_correct)
+	      /* 1003.2 specifies the format of this message.  */
+	      fprintf (stderr, _("%s: illegal option -- %c\n"),
+		       argv[0], c);
+	    else
+	      fprintf (stderr, _("%s: invalid option -- %c\n"),
+		       argv[0], c);
+	  }
+	optopt = c;
+	return '?';
+      }
+    /* Convenience. Treat POSIX -W foo same as long option --foo */
+    if (temp[0] == 'W' && temp[1] == ';')
+      {
+	char *nameend;
+	const struct option *p;
+	const struct option *pfound = NULL;
+	int exact = 0;
+	int ambig = 0;
+	int indfound = 0;
+	int option_index;
+
+	/* This is an option that requires an argument.  */
+	if (*nextchar != '\0')
+	  {
+	    optarg = nextchar;
+	    /* If we end this ARGV-element by taking the rest as an arg,
+	       we must advance to the next element now.  */
+	    optind++;
+	  }
+	else if (optind == argc)
+	  {
+	    if (opterr)
+	      {
+		/* 1003.2 specifies the format of this message.  */
+		fprintf (stderr, _("%s: option requires an argument -- %c\n"),
+			 argv[0], c);
+	      }
+	    optopt = c;
+	    if (optstring[0] == ':')
+	      c = ':';
+	    else
+	      c = '?';
+	    return c;
+	  }
+	else
+	  /* We already incremented `optind' once;
+	     increment it again when taking next ARGV-elt as argument.  */
+	  optarg = argv[optind++];
+
+	/* optarg is now the argument, see if it's in the
+	   table of longopts.  */
+
+	for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++)
+	  /* Do nothing.  */ ;
+
+	/* Test all long options for either exact match
+	   or abbreviated matches.  */
+	for (p = longopts, option_index = 0; p->name; p++, option_index++)
+	  if (!strncmp (p->name, nextchar, nameend - nextchar))
+	    {
+	      if ((unsigned int) (nameend - nextchar) == strlen (p->name))
+		{
+		  /* Exact match found.  */
+		  pfound = p;
+		  indfound = option_index;
+		  exact = 1;
+		  break;
+		}
+	      else if (pfound == NULL)
+		{
+		  /* First nonexact match found.  */
+		  pfound = p;
+		  indfound = option_index;
+		}
+	      else
+		/* Second or later nonexact match found.  */
+		ambig = 1;
+	    }
+	if (ambig && !exact)
+	  {
+	    if (opterr)
+	      fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"),
+		       argv[0], argv[optind]);
+	    nextchar += strlen (nextchar);
+	    optind++;
+	    return '?';
+	  }
+	if (pfound != NULL)
+	  {
+	    option_index = indfound;
+	    if (*nameend)
+	      {
+		/* Don't test has_arg with >, because some C compilers don't
+		   allow it to be used on enums.  */
+		if (pfound->has_arg)
+		  optarg = nameend + 1;
+		else
+		  {
+		    if (opterr)
+		      fprintf (stderr, _("\
+%s: option `-W %s' doesn't allow an argument\n"),
+			       argv[0], pfound->name);
+
+		    nextchar += strlen (nextchar);
+		    return '?';
+		  }
+	      }
+	    else if (pfound->has_arg == 1)
+	      {
+		if (optind < argc)
+		  optarg = argv[optind++];
+		else
+		  {
+		    if (opterr)
+		      fprintf (stderr,
+			       _("%s: option `%s' requires an argument\n"),
+			       argv[0], argv[optind - 1]);
+		    nextchar += strlen (nextchar);
+		    return optstring[0] == ':' ? ':' : '?';
+		  }
+	      }
+	    nextchar += strlen (nextchar);
+	    if (longind != NULL)
+	      *longind = option_index;
+	    if (pfound->flag)
+	      {
+		*(pfound->flag) = pfound->val;
+		return 0;
+	      }
+	    return pfound->val;
+	  }
+	  nextchar = NULL;
+	  return 'W';	/* Let the application handle it.   */
+      }
+    if (temp[1] == ':')
+      {
+	if (temp[2] == ':')
+	  {
+	    /* This is an option that accepts an argument optionally.  */
+	    if (*nextchar != '\0')
+	      {
+		optarg = nextchar;
+		optind++;
+	      }
+	    else
+	      optarg = NULL;
+	    nextchar = NULL;
+	  }
+	else
+	  {
+	    /* This is an option that requires an argument.  */
+	    if (*nextchar != '\0')
+	      {
+		optarg = nextchar;
+		/* If we end this ARGV-element by taking the rest as an arg,
+		   we must advance to the next element now.  */
+		optind++;
+	      }
+	    else if (optind == argc)
+	      {
+		if (opterr)
+		  {
+		    /* 1003.2 specifies the format of this message.  */
+		    fprintf (stderr,
+			   _("%s: option requires an argument -- %c\n"),
+			   argv[0], c);
+		  }
+		optopt = c;
+		if (optstring[0] == ':')
+		  c = ':';
+		else
+		  c = '?';
+	      }
+	    else
+	      /* We already incremented `optind' once;
+		 increment it again when taking next ARGV-elt as argument.  */
+	      optarg = argv[optind++];
+	    nextchar = NULL;
+	  }
+      }
+    return c;
+  }
+}
+
+int
+getopt (argc, argv, optstring)
+     int argc;
+     char *const *argv;
+     const char *optstring;
+{
+  return _getopt_internal (argc, argv, optstring,
+			   (const struct option *) 0,
+			   (int *) 0,
+			   0);
+}
+
+#endif	/* Not ELIDE_CODE.  */
+
+
+#ifdef TEST
+
+/* Compile with -DTEST to make an executable for use in testing
+   the above definition of `getopt'.  */
+
+int
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  int c;
+  int digit_optind = 0;
+
+  while (1)
+    {
+      int this_option_optind = optind ? optind : 1;
+
+      c = getopt (argc, argv, "abc:d:0123456789");
+      if (c == -1)
+	break;
+
+      switch (c)
+	{
+	case '0':
+	case '1':
+	case '2':
+	case '3':
+	case '4':
+	case '5':
+	case '6':
+	case '7':
+	case '8':
+	case '9':
+	  if (digit_optind != 0 && digit_optind != this_option_optind)
+	    printf ("digits occur in two different argv-elements.\n");
+	  digit_optind = this_option_optind;
+	  printf ("option %c\n", c);
+	  break;
+
+	case 'a':
+	  printf ("option a\n");
+	  break;
+
+	case 'b':
+	  printf ("option b\n");
+	  break;
+
+	case 'c':
+	  printf ("option c with value `%s'\n", optarg);
+	  break;
+
+	case '?':
+	  break;
+
+	default:
+	  printf ("?? getopt returned character code 0%o ??\n", c);
+	}
+    }
+
+  if (optind < argc)
+    {
+      printf ("non-option ARGV-elements: ");
+      while (optind < argc)
+	printf ("%s ", argv[optind++]);
+      printf ("\n");
+    }
+
+  exit (0);
+}
+
+#endif /* TEST */
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxHeap.cxx
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxHeap.cxx	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxHeap.cxx	(revision 1097)
@@ -0,0 +1,135 @@
+/************************************************************************
+
+  Heap data structure
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxHeap.cxx,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "stdmix.h"
+#include "MxHeap.h"
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// Internal functions for manipulating the heap
+
+inline void MxHeap::place(MxHeapable *x, unsigned int i)
+{
+    ref(i) = x;
+    x->set_heap_pos(i);
+}
+
+void MxHeap::swap(unsigned int i, unsigned int j)
+{
+    MxHeapable *tmp = ref(i);
+
+    place(ref(j), i);
+    place(tmp, j);
+}
+
+void MxHeap::upheap(unsigned int i)
+{
+    MxHeapable *moving = ref(i);
+    uint index = i;
+    uint p = parent(i);
+
+    while( index>0 && moving->heap_key() > ref(p)->heap_key() )
+    {
+	place(ref(p), index);
+	index = p;
+	p = parent(p);
+    }
+
+    if( index != i )
+	place(moving, index);
+}
+
+void MxHeap::downheap(unsigned int i)
+{
+    MxHeapable *moving = ref(i);
+    uint index = i;
+    uint l = left(i);
+    uint r = right(i);
+    uint largest;
+
+    while( l<length() )
+    {
+	if( r<length() && ref(l)->heap_key() < ref(r)->heap_key() )
+	    largest = r;
+	else 
+	    largest = l;
+
+	if( moving->heap_key() < ref(largest)->heap_key() )
+	{
+	    place(ref(largest), index);
+	    index = largest;
+	    l = left(index);
+	    r = right(index);
+	}
+	else
+	    break;
+    }
+
+    if( index != i )
+	place(moving, index);
+}
+
+////////////////////////////////////////////////////////////////////////
+//
+// Exported interface to the heap
+//
+
+void MxHeap::insert(MxHeapable *t, float v)
+{
+    t->heap_key(v);
+
+    unsigned int i = add(t);
+    t->set_heap_pos(i);
+
+    upheap(i);
+}
+
+void MxHeap::update(MxHeapable *t, float v)
+{
+    SanityCheck( t->is_in_heap() );
+    t->heap_key(v);
+
+    unsigned int i = t->get_heap_pos();
+
+    if( i>0 && v>ref(parent(i))->heap_key() )
+	upheap(i);
+    else
+	downheap(i);
+}
+
+MxHeapable *MxHeap::extract()
+{
+    if( length() < 1 ) return NULL;
+
+    swap(0, length()-1);
+    MxHeapable *dead=drop();
+
+    downheap(0);
+    dead->not_in_heap();
+    return dead;
+}
+
+MxHeapable *MxHeap::remove(MxHeapable *t)
+{
+    if( !t->is_in_heap() ) return NULL;
+
+    int i = t->get_heap_pos();
+    swap(i, length()-1);
+    drop();
+    t->not_in_heap();
+
+    if( ref(i)->heap_key() < t->heap_key() )
+	downheap(i);
+    else
+	upheap(i);
+
+    return t;
+}
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxGeom3D.cxx
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxGeom3D.cxx	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxGeom3D.cxx	(revision 1097)
@@ -0,0 +1,152 @@
+/************************************************************************
+
+  Handy 3D geometrical primitives
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxGeom3D.cxx,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "stdmix.h"
+#include "MxGeom3D.h"
+
+Vec3 triangle_raw_normal(const Vec3& v1, const Vec3& v2, const Vec3& v3)
+{
+    Vec3 a = v2 - v1;
+    Vec3 b = v3 - v1;
+    return a^b;
+}
+
+double triangle_area(const Vec3& v1, const Vec3& v2, const Vec3& v3)
+{
+    return 0.5 * norm(triangle_raw_normal(v1, v2, v3));
+}
+
+Vec3 triangle_normal(const Vec3& v1, const Vec3& v2, const Vec3& v3)
+{
+    Vec3 n = triangle_raw_normal(v1, v2, v3);
+    unitize(n);
+
+    return n;
+}
+
+Vec4 triangle_plane(const Vec3& v1, const Vec3& v2, const Vec3& v3)
+{
+    Vec3 n = triangle_normal(v1, v2, v3);
+
+    return Vec4(n, -(n*v1));
+}
+
+Vec4 triangle_raw_plane(const Vec3& v1, const Vec3& v2, const Vec3& v3)
+{
+    Vec3 n = triangle_raw_normal(v1, v2, v3);
+
+    return Vec4(n, -(n*v1));
+}
+
+const double FOUR_ROOT3 = 6.928203230275509;
+
+double triangle_compactness(const Vec3& v1, const Vec3& v2, const Vec3& v3)
+{
+    double L1 = norm2(v2 - v1);
+    double L2 = norm2(v3 - v2);
+    double L3 = norm2(v1 - v3);
+
+    return FOUR_ROOT3 * triangle_area(v1, v2, v3) / (L1+L2+L3);
+}
+
+void mx3d_box_corners(const Vec3& min, const Vec3& max, Vec3 *v)
+{
+    v[0] = min;
+    v[1] = Vec3(min[X], max[Y], min[Z]);
+    v[2] = Vec3(max[X], min[Y], min[Z]);
+    v[3] = Vec3(max[X], max[Y], min[Z]);
+    v[4] = Vec3(min[X], min[Y], max[Z]);
+    v[5] = Vec3(min[X], max[Y], max[Z]);
+    v[6] = Vec3(max[X], min[Y], max[Z]);
+    v[7] = max;
+}
+
+////////////////////////////////////////////////////////////////////////
+//
+// Basic bounding volumes.
+// This has been imported pretty much directly from GFX
+//
+
+void MxBounds::reset()
+{
+    min[X] = min[Y] = min[Z] = HUGE;
+    max[X] = max[Y] = max[Z] = -HUGE;
+
+    center[X] = center[Y] = center[Z] = 0.0;
+    radius = 0.0;
+
+    points = 0;
+}
+
+void MxBounds::add_point(const double *v, bool will_update)
+{
+    if( v[X] < min[X] ) min[X] = v[X];
+    if( v[Y] < min[Y] ) min[Y] = v[Y];
+    if( v[Z] < min[Z] ) min[Z] = v[Z];
+
+    if( v[X] > max[X] ) max[X] = v[X];
+    if( v[Y] > max[Y] ) max[Y] = v[Y];
+    if( v[Z] > max[Z] ) max[Z] = v[Z];
+
+
+    if( will_update )
+    {
+	center += Vec3(v);
+	points++;
+    }
+}
+
+void MxBounds::add_point(const float *v, bool will_update)
+{
+    if( v[X] < min[X] ) min[X] = v[X];
+    if( v[Y] < min[Y] ) min[Y] = v[Y];
+    if( v[Z] < min[Z] ) min[Z] = v[Z];
+
+    if( v[X] > max[X] ) max[X] = v[X];
+    if( v[Y] > max[Y] ) max[Y] = v[Y];
+    if( v[Z] > max[Z] ) max[Z] = v[Z];
+
+
+    if( will_update )
+    {
+	center += Vec3(v);
+	points++;
+    }
+}
+
+void MxBounds::complete()
+{
+    center /= (double)points;
+
+    Vec3 R1 = max-center;
+    Vec3 R2 = min-center;
+
+    radius = MAX(norm(R1), norm(R2));
+}
+
+void MxBounds::merge(const MxBounds& b)
+{
+    add_point(b.min, false);
+    add_point(b.max, false);
+    points += b.points;
+
+    Vec3 dC = b.center - center;
+    double dist = norm(dC);
+
+    if( dist + b.radius > radius )
+    {
+	// New sphere does not lie within old sphere
+	center += b.center;
+	center /= 2;
+
+	dist /= 2;
+	radius = MAX(dist+radius, dist+b.radius);
+    }
+}
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxTimer.cxx
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxTimer.cxx	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxTimer.cxx	(revision 1097)
@@ -0,0 +1,70 @@
+/************************************************************************
+
+  MxTimer
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxTimer.cxx,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "stdmix.h"
+#include "MxTimer.h"
+
+#if defined(WIN32)
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+// Only Windows NT supports getting proper time usage information.
+// In Windows 95, we have to settle for measuring real time.
+double mx_get_time()
+{
+    FILETIME start, end, kernel, user;
+
+    if( !GetThreadTimes(GetCurrentThread(), &start, &end, &kernel, &user) )
+    {
+	// We're running under Windows 95 instead of NT.
+	// Just get the current time and be done with it.
+	SYSTEMTIME now;
+	GetSystemTime(&now);
+	SystemTimeToFileTime(&now, &user);
+    }
+
+    // Convert into something we can do math on
+    LARGE_INTEGER i;
+    i.LowPart = user.dwLowDateTime;
+    i.HighPart = user.dwHighDateTime;
+
+    // Convert to seconds and return
+    return (double)(i.QuadPart) / 1e7;
+}
+
+#elif defined(MIX_HAVE_GETRUSAGE)
+#include <sys/time.h>
+#include <sys/resource.h>
+
+double mx_get_time()
+{
+    struct rusage t;
+
+    getrusage(RUSAGE_SELF, &t);
+
+    return (double)t.ru_utime.tv_sec + (double)t.ru_utime.tv_usec/1000000;
+}
+
+#elif defined(MIX_HAVE_TIMES)
+
+double mx_get_time()
+{
+    struct tms t;
+
+    times(&t);
+
+    return (double)(t.tms_utime) / (double)CLK_TCK;
+}
+
+#else
+
+#error "MxTimer: No supported timing mechanism available."
+
+#endif
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/getopt.h
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/getopt.h	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/getopt.h	(revision 1097)
@@ -0,0 +1,131 @@
+/* Declarations for getopt.
+   Copyright (C) 1989,90,91,92,93,94,96,97 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifndef _GETOPT_H
+#define _GETOPT_H 1
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+/* For communication from `getopt' to the caller.
+   When `getopt' finds an option that takes an argument,
+   the argument value is returned here.
+   Also, when `ordering' is RETURN_IN_ORDER,
+   each non-option ARGV-element is returned here.  */
+
+extern char *optarg;
+
+/* Index in ARGV of the next element to be scanned.
+   This is used for communication to and from the caller
+   and for communication between successive calls to `getopt'.
+
+   On entry to `getopt', zero means this is the first call; initialize.
+
+   When `getopt' returns -1, this is the index of the first of the
+   non-option elements that the caller should itself scan.
+
+   Otherwise, `optind' communicates from one call to the next
+   how much of ARGV has been scanned so far.  */
+
+extern int optind;
+
+/* Callers store zero here to inhibit the error message `getopt' prints
+   for unrecognized options.  */
+
+extern int opterr;
+
+/* Set to an option character which was unrecognized.  */
+
+extern int optopt;
+
+/* Describe the long-named options requested by the application.
+   The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
+   of `struct option' terminated by an element containing a name which is
+   zero.
+
+   The field `has_arg' is:
+   no_argument		(or 0) if the option does not take an argument,
+   required_argument	(or 1) if the option requires an argument,
+   optional_argument 	(or 2) if the option takes an optional argument.
+
+   If the field `flag' is not NULL, it points to a variable that is set
+   to the value given in the field `val' when the option is found, but
+   left unchanged if the option is not found.
+
+   To have a long-named option do something other than set an `int' to
+   a compiled-in constant, such as set a value from `optarg', set the
+   option's `flag' field to zero and its `val' field to a nonzero
+   value (the equivalent single-letter option character, if there is
+   one).  For long options that have a zero `flag' field, `getopt'
+   returns the contents of the `val' field.  */
+
+struct option
+{
+#if defined (__STDC__) && __STDC__
+  const char *name;
+#else
+  char *name;
+#endif
+  /* has_arg can't be an enum because some compilers complain about
+     type mismatches in all the code that assumes it is an int.  */
+  int has_arg;
+  int *flag;
+  int val;
+};
+
+/* Names for the values of the `has_arg' field of `struct option'.  */
+
+#define	no_argument		0
+#define required_argument	1
+#define optional_argument	2
+
+#if (defined (__STDC__) && __STDC__) || defined(__cplusplus)
+#if defined(__GNU_LIBRARY__) || defined(WIN32)
+/* Many other libraries have conflicting prototypes for getopt, with
+   differences in the consts, in stdlib.h.  To avoid compilation
+   errors, only prototype getopt for the GNU C library.  */
+extern int getopt (int argc, char *const *argv, const char *shortopts);
+#else /* not __GNU_LIBRARY__ */
+extern int getopt ();
+#endif /* __GNU_LIBRARY__ */
+extern int getopt_long (int argc, char *const *argv, const char *shortopts,
+		        const struct option *longopts, int *longind);
+extern int getopt_long_only (int argc, char *const *argv,
+			     const char *shortopts,
+		             const struct option *longopts, int *longind);
+
+/* Internal only.  Users should not call this directly.  */
+extern int _getopt_internal (int argc, char *const *argv,
+			     const char *shortopts,
+		             const struct option *longopts, int *longind,
+			     int long_only);
+#else /* not __STDC__ */
+extern int getopt ();
+extern int getopt_long ();
+extern int getopt_long_only ();
+
+extern int _getopt_internal ();
+#endif /* __STDC__ */
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif /* _GETOPT_H */
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/mixvops.h
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/mixvops.h	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/mixvops.h	(revision 1097)
@@ -0,0 +1,177 @@
+#ifndef MIXVOPS_INCLUDED // -*- C++ -*-
+#define MIXVOPS_INCLUDED //
+#endif                   // WARNING:  Multiple inclusions allowed
+
+/************************************************************************
+
+  Low-level vector math operations.
+
+  This header file is intended for internal library use only.  You should
+  understand what's going on in here before trying to use it yourself.
+
+  Using the magic __LINKAGE macro, this file can be compiled either as a
+  set of templated functions, or as a series of inline functions whose
+  argument type is determined by the __T macro.  My rationale for this is
+  that some compilers either don't support templated functions or are
+  incapable of inlining them.
+
+  PUBLIC APOLOGY: I really do apologize for the ugliness of the code in
+  this header.  In order to accommodate various types of compilation and
+  to avoid lots of typing, I've made pretty heavy use of macros.
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: mixvops.h,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#ifdef MX_DEFAULT_DIM
+#  define __DIM const int N=MX_DEFAULT_DIM
+#else
+#  define __DIM const int N
+#endif
+
+#if !defined(MIXVOPS_USE_TEMPLATES)
+#  ifndef __T
+#    define __T double
+#  endif
+#  define __LINKAGE inline
+#else
+#  ifdef __T
+#    undef __T
+#  endif
+#  define __LINKAGE template<class __T>inline
+#endif
+
+#define __OP __LINKAGE __T *
+
+#define forall(i, N) for(unsigned int i=0; i<N; i++)
+
+#define def3(name, op) __OP name(__T *r, const __T *u, const __T *v, __DIM) { forall(i,N) op; return r; }
+
+#define def2(name, op) __OP name(__T *r, const __T *u, __DIM) { forall(i,N) op; return r; }
+
+#define def1(name, op) __OP name(__T *r, __DIM) { forall(i,N) op; return r; }
+
+#define def2s(name, op) __OP name(__T *r, const __T *u, __T d, __DIM) { forall(i,N) op; return r; }
+
+#define def1s(name, op) __OP name(__T *r, __T d, __DIM) { forall(i,N) op; return r; }
+
+def3(mxv_add, r[i] = u[i] + v[i])
+def3(mxv_sub, r[i] = u[i] - v[i])
+def3(mxv_mul, r[i] = u[i] * v[i])
+def3(mxv_div, r[i] = u[i] / v[i])
+
+def2(mxv_addinto, r[i] += u[i])
+def2(mxv_subfrom, r[i] -= u[i])
+def2(mxv_mulby, r[i] *= u[i])
+def2(mxv_divby, r[i] /= u[i])
+
+def2(mxv_set, r[i] = u[i])
+def1(mxv_neg, r[i] = -r[i])
+def2(mxv_neg, r[i] = -u[i])
+
+
+def1s(mxv_set, r[i]=d)
+def1s(mxv_scale, r[i] *= d)
+def1s(mxv_invscale, r[i] /= d)
+def2s(mxv_scale, r[i] = u[i]*d)
+def2s(mxv_invscale, r[i] = u[i]/d)
+
+
+__LINKAGE __T mxv_dot(const __T *u, const __T *v, __DIM)
+{
+    __T dot=0.0;  forall(i, N) dot+=u[i]*v[i];  return dot;
+}
+
+__OP mxv_cross3(__T *r, const __T *u, const __T *v)
+{
+    r[0] = u[1]*v[2] - v[1]*u[2]; r[1] = -u[0]*v[2] + v[0]*u[2];
+    r[2] = u[0]*v[1] - v[0]*u[1];  return r;
+}
+
+__LINKAGE __T mxv_norm(const __T *v, __DIM) { return sqrt(mxv_dot(v,v,N)); }
+__LINKAGE __T mxv_norm2(const __T *v, __DIM) { return mxv_dot(v,v,N); }
+
+__LINKAGE __T mxv_unitize(__T *v, __DIM)
+{
+    __T l = mxv_norm2(v, N);
+    if( l!=1.0 && l!=0.0 )  { l = sqrt(l);  mxv_invscale(v, l, N); }
+    return l;
+}
+
+__LINKAGE __T mxv_Linf(const __T *u, const __T *v, __DIM)
+{
+    __T d=0.0;  forall(i, N) { __T p=ABS(u[i]-v[i]); d=MIN(d, p); }  return d;
+}
+
+__LINKAGE __T mxv_L1(const __T *u, const __T *v, __DIM)
+{
+    __T d = 0.0;  forall(i, N) d+=ABS(u[i]-v[i]);  return d;
+}
+
+__LINKAGE __T mxv_L2(const __T *u, const __T *v, __DIM)
+{
+    __T d = 0.0;  forall(i, N) { __T p=u[i]-v[i];  d+=p*p; }  return d;
+}
+
+__LINKAGE bool mxv_eql(const __T *u, const __T *v, __DIM)
+{
+    bool e=true;
+    for(uint i=0; e && i<N; i++) e = e && (u[i]==v[i]);
+    return e;
+}
+
+__LINKAGE bool mxv_equal(const __T *u, const __T *v, __DIM)
+{
+    return mxv_L2(u, v, N) < FEQ_EPS2;
+}
+
+__OP mxv_basis(__T *r, uint b, __DIM)
+{
+    forall(i, N)  r[i] = (i==b)?1.0:0.0;  return r;
+}
+
+__LINKAGE ostream& mxv_write(ostream& out, const __T *v, __DIM)
+{
+    out << v[0];
+    for(unsigned int i=1; i<N; i++)   out << " " << v[i];
+    return out;
+}
+__LINKAGE ostream& mxv_write(const __T *v, __DIM)
+	{return mxv_write(cout, v, N);}
+
+__LINKAGE istream& mxv_read(istream& in, __T *v, __DIM)
+{
+    forall(i,N) in >> v[i];  return in;
+}
+__LINKAGE istream& mxv_read(__T *v, __DIM) { return mxv_read(cin, v, N); }
+
+#ifndef mxv_local_block
+#ifdef __GNUC__
+#  define mxv_local_block(a,T,N)  T a[N]
+#  define mxv_free_local(a)
+#else
+#  ifdef HAVE_ALLOCA
+#    include <alloca.h>
+#    define mxv_local_block(a,T,N)  T *a = (T *)alloca(sizeof(T)*N)
+#    define mxv_free_local(a)
+#  else
+#    define mxv_local_block(a,T,N)  T *a = new T[N]
+#    define mxv_free_local(a)       delete[] a
+#  endif
+#endif
+#endif
+
+#undef __T
+#undef __DIM
+#undef __LINKAGE
+#undef __OP
+#undef forall
+#undef def3
+#undef def2
+#undef def1
+#undef def2s
+#undef def1s
+
+// MIXVOPS_INCLUDED
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxArcball.h
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxArcball.h	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxArcball.h	(revision 1097)
@@ -0,0 +1,62 @@
+#ifndef MXARCBALL_INCLUDED // -*- C++ -*-
+#define MXARCBALL_INCLUDED
+#if !defined(__GNUC__)
+#  pragma once
+#endif
+
+/************************************************************************
+
+  MxArcball
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxArcball.h,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "MxVec4.h"
+#include "MxMat4.h"
+#include "MxManipulator.h"
+
+typedef Vec4 Quat;
+struct BallData;
+
+
+class MxArcball : public MxManipulator
+{
+private:
+    int mousex, mousey;
+    int startx, starty;
+    BallData *ball;
+    Quat center;
+    float radius;
+
+    enum {NoDrag=0, Spin, Dolly, Zoom, LightAdjust} dragging;
+
+    double __proj_save[16];
+
+public:
+    Vec4 vNow;
+    float cam[3];
+
+public:
+    MxArcball() { ball=NULL; }
+    MxArcball(const MxBounds& bounds, float aspect)
+      { ball=NULL; init(bounds,aspect); }
+    ~MxArcball();
+    void init(const MxBounds& bounds, float aspect);
+
+
+    bool mouse_down(int which, int x, int y, int kind=1);
+    bool mouse_up(int which, int x, int y, int kind=2);
+    bool motion(int x, int y);
+
+    void apply();
+    void unapply();
+    void draw();
+
+    double *get_qnow();
+};
+
+// MXARCBALL_INCLUDED
+#endif
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxMat3-jacobi.cxx
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxMat3-jacobi.cxx	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxMat3-jacobi.cxx	(revision 1097)
@@ -0,0 +1,202 @@
+/************************************************************************
+
+  Jacobi iteration on 3x3 matrices.
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+
+  NOTE: This code was adapted from VTK source code (vtkMath.cxx) which
+        seems to have been adapted directly from Numerical Recipes in C.
+	See Hoppe's Recon software for an alternative adaptation of the
+	Numerical Recipes code.
+  
+  $Id: MxMat3-jacobi.cxx,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "stdmix.h"
+#include "MxMat3.h"
+
+#define ROT(a,i,j,k,l) g=a[i][j];h=a[k][l];a[i][j]=g-s*(h+g*tau);a[k][l]=h+s*(g-h*tau);
+
+#define MAX_ROTATIONS 60
+
+// Description:
+// Jacobi iteration for the solution of eigenvectors/eigenvalues of a 3x3
+// real symmetric matrix. Square 3x3 matrix a; output eigenvalues in w;
+// and output eigenvectors in v. Resulting eigenvalues/vectors are sorted
+// in decreasing order; eigenvectors are normalized.
+//
+static
+bool internal_jacobi(double a[3][3], double w[3], double v[3][3])
+{
+    int i, j, k, iq, ip;
+    double tresh, theta, tau, t, sm, s, h, g, c;
+    double b[3], z[3], tmp;
+
+    // initialize
+    for (ip=0; ip<3; ip++) 
+    {
+	for (iq=0; iq<3; iq++) v[ip][iq] = 0.0;
+	v[ip][ip] = 1.0;
+    }
+    for (ip=0; ip<3; ip++) 
+    {
+	b[ip] = w[ip] = a[ip][ip];
+	z[ip] = 0.0;
+    }
+
+    // begin rotation sequence
+    for (i=0; i<MAX_ROTATIONS; i++) 
+    {
+	sm = 0.0;
+	for (ip=0; ip<2; ip++) 
+	{
+	    for (iq=ip+1; iq<3; iq++) sm += fabs(a[ip][iq]);
+	}
+	if (sm == 0.0) break;
+
+	if (i < 4) tresh = 0.2*sm/(9);
+	else tresh = 0.0;
+
+	for (ip=0; ip<2; ip++) 
+	{
+	    for (iq=ip+1; iq<3; iq++) 
+	    {
+		g = 100.0*fabs(a[ip][iq]);
+		if (i > 4 && (fabs(w[ip])+g) == fabs(w[ip])
+		    && (fabs(w[iq])+g) == fabs(w[iq]))
+		{
+		    a[ip][iq] = 0.0;
+		}
+		else if (fabs(a[ip][iq]) > tresh) 
+		{
+		    h = w[iq] - w[ip];
+		    if ( (fabs(h)+g) == fabs(h)) t = (a[ip][iq]) / h;
+		    else 
+		    {
+			theta = 0.5*h / (a[ip][iq]);
+			t = 1.0 / (fabs(theta)+sqrt(1.0+theta*theta));
+			if (theta < 0.0) t = -t;
+		    }
+		    c = 1.0 / sqrt(1+t*t);
+		    s = t*c;
+		    tau = s/(1.0+c);
+		    h = t*a[ip][iq];
+		    z[ip] -= h;
+		    z[iq] += h;
+		    w[ip] -= h;
+		    w[iq] += h;
+		    a[ip][iq]=0.0;
+		    for (j=0;j<ip-1;j++) 
+		    {
+			ROT(a,j,ip,j,iq)
+			    }
+		    for (j=ip+1;j<iq-1;j++) 
+		    {
+			ROT(a,ip,j,j,iq)
+			    }
+		    for (j=iq+1; j<3; j++) 
+		    {
+			ROT(a,ip,j,iq,j)
+			    }
+		    for (j=0; j<3; j++) 
+		    {
+			ROT(v,j,ip,j,iq)
+			    }
+		}
+	    }
+	}
+
+	for (ip=0; ip<3; ip++) 
+	{
+	    b[ip] += z[ip];
+	    w[ip] = b[ip];
+	    z[ip] = 0.0;
+	}
+    }
+
+    if ( i >= MAX_ROTATIONS )
+    {
+	mxmsg_signal(MXMSG_WARN, "Error computing eigenvalues.", "jacobi");
+	return false;
+    }
+
+    // sort eigenfunctions
+    for (j=0; j<3; j++) 
+    {
+	k = j;
+	tmp = w[k];
+	for (i=j; i<3; i++)
+	{
+	    if (w[i] >= tmp) 
+	    {
+		k = i;
+		tmp = w[k];
+	    }
+	}
+	if (k != j) 
+	{
+	    w[k] = w[j];
+	    w[j] = tmp;
+	    for (i=0; i<3; i++) 
+	    {
+		tmp = v[i][j];
+		v[i][j] = v[i][k];
+		v[i][k] = tmp;
+	    }
+	}
+    }
+    // insure eigenvector consistency (i.e., Jacobi can compute vectors that
+    // are negative of one another (.707,.707,0) and (-.707,-.707,0). This can
+    // reek havoc in hyperstreamline/other stuff. We will select the most
+    // positive eigenvector.
+    int numPos;
+    for (j=0; j<3; j++)
+    {
+	for (numPos=0, i=0; i<3; i++) if ( v[i][j] >= 0.0 ) numPos++;
+	if ( numPos < 2 ) for(i=0; i<3; i++) v[i][j] *= -1.0;
+    }
+
+    return true;
+}
+
+#undef ROT
+#undef MAX_ROTATIONS
+
+
+bool jacobi(const Mat3& m, Vec3& eig_vals, Vec3 eig_vecs[3])
+{
+    double a[3][3], w[3], v[3][3];
+    int i,j;
+
+    for(i=0;i<3;i++) for(j=0;j<3;j++) a[i][j] = m(i,j);
+
+    bool result = internal_jacobi(a, w, v);
+    if( result )
+    {
+	for(i=0;i<3;i++) eig_vals[i] = w[i];
+
+	for(i=0;i<3;i++) for(j=0;j<3;j++) eig_vecs[i][j] = v[j][i];
+    }
+
+    return result;
+}
+
+bool jacobi(const Mat3& m, double *eig_vals, double *eig_vecs)
+{
+    double a[3][3],  v[3][3];
+    int i,j;
+
+    for(i=0;i<3;i++) for(j=0;j<3;j++) a[i][j] = m(i,j);
+
+    bool result = internal_jacobi(a, eig_vals, v);
+    if( result )
+    {
+	int index=0;
+	for(i=0;i<3;i++) for(j=0;j<3;j++)
+	    // eig_vecs[i][j] = v[j][i];
+	    eig_vecs[index++] = v[j][i];
+    }
+
+    return result;
+}
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxQMetric.h
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxQMetric.h	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxQMetric.h	(revision 1097)
@@ -0,0 +1,61 @@
+#ifndef MXQMETRIC_INCLUDED // -*- C++ -*-
+#define MXQMETRIC_INCLUDED
+#if !defined(__GNUC__)
+#  pragma once
+#endif
+
+/************************************************************************
+
+  n-D Quadric Error Metric
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxQMetric.h,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "MxQMetric3.h"
+#include "MxVector.h"
+#include "MxMatrix.h"
+
+class MxQuadric
+{
+private:
+    MxMatrix A;
+    MxVector b;
+    double c;
+
+    double r;
+
+public:
+    MxQuadric(unsigned int N) : A(N), b(N) { clear(); }
+    MxQuadric(const MxVector& p1, const MxVector& p2, const MxVector& p3,
+	      double area=1.0);
+    MxQuadric(const MxQuadric3&, unsigned int N);
+    MxQuadric(const MxQuadric& Q)
+	: A(Q.A.dim()), b(Q.b.dim()) { *this = Q; }
+
+    const MxMatrix& tensor() const { return A; }
+    const MxVector& vector() const { return b; }
+    double offset() const { return c; }
+    double area() const { return r; }
+    MxMatrix& homogeneous(MxMatrix& H) const;
+
+    void clear(double val=0.0) { A=val; b=val; c=val; r=val; }
+    MxQuadric& operator=(const MxQuadric& Q)
+	{ A=Q.A; b=Q.b; c=Q.c; r=Q.r; return *this; }
+    MxQuadric& operator+=(const MxQuadric& Q)
+	{ A+=Q.A; b+=Q.b; c+=Q.c; r+=Q.r; return *this; }
+    MxQuadric& operator-=(const MxQuadric& Q)
+	{ A-=Q.A; b-=Q.b; c-=Q.c; r-=Q.r; return *this; }
+    MxQuadric& operator*=(double s)
+	{ A*=s; b*=s; c*=s; return *this; }
+
+    double evaluate(const MxVector& v) const;
+    double operator()(const MxVector& v) const { return evaluate(v); }
+
+    bool optimize(MxVector& v) const;
+};
+
+// MXQMETRIC_INCLUDED
+#endif
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxPropSlim.h
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxPropSlim.h	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxPropSlim.h	(revision 1097)
@@ -0,0 +1,94 @@
+#ifndef MXPROPSLIM_INCLUDED // -*- C++ -*-
+#define MXPROPSLIM_INCLUDED
+#if !defined(__GNUC__)
+#  pragma once
+#endif
+
+/************************************************************************
+
+  MxPropSlim
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxPropSlim.h,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "MxStdSlim.h"
+#include "MxQMetric.h"
+
+
+class MxPropSlim : public MxStdSlim
+{
+private:
+    uint D;
+
+    bool use_color;
+    bool use_texture;
+    bool use_normals;
+
+    class edge_info : public MxHeapable
+    {
+    public:
+	MxVertexID v1, v2;
+	MxVector target;
+
+	edge_info(uint D) : target(D) { }
+    };
+    typedef MxSizedDynBlock<edge_info*, 6> edge_list;
+
+
+    MxBlock<edge_list> edge_links;	// 1 per vertex
+    MxBlock<MxQuadric*> __quadrics;	// 1 per vertex
+
+    //
+    // Temporary variables used by methods
+    MxVertexList star, star2;
+    MxPairContraction conx_tmp;
+
+protected:
+    uint compute_dimension(MxStdModel *);
+    void pack_to_vector(MxVertexID, MxVector&);
+    void unpack_from_vector(MxVertexID, MxVector&);
+    uint prop_count();
+    void pack_prop_to_vector(MxVertexID, MxVector&, uint);
+    void unpack_prop_from_vector(MxVertexID, MxVector&, uint);
+
+    void compute_face_quadric(MxFaceID, MxQuadric&);
+    void collect_quadrics();
+
+    void create_edge(MxVertexID, MxVertexID);
+    void collect_edges();
+    void constrain_boundaries();
+    void discontinuity_constraint(MxVertexID, MxVertexID, const MxFaceList&);
+    void compute_edge_info(edge_info *);
+    void finalize_edge_update(edge_info *);
+    void compute_target_placement(edge_info *);
+
+    void apply_contraction(const MxPairContraction&, edge_info *);
+    void update_pre_contract(const MxPairContraction&);
+
+public:
+    bool will_decouple_quadrics;
+
+public:
+    MxPropSlim(MxStdModel *);
+
+    uint dim() const { return D; }
+
+    void consider_color(bool will=true);
+    void consider_texture(bool will=true);
+    void consider_normals(bool will=true);
+
+    uint quadric_count() const { return __quadrics.length(); }
+    MxQuadric&       quadric(uint i)       { return *(__quadrics(i)); }
+    const MxQuadric& quadric(uint i) const { return *(__quadrics(i)); }
+
+
+    void initialize();
+    bool decimate(uint);
+
+};
+
+// MXPROPSLIM_INCLUDED
+#endif
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/mixmsg.cxx
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/mixmsg.cxx	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/mixmsg.cxx	(revision 1097)
@@ -0,0 +1,135 @@
+/************************************************************************
+
+  Implementation of error reporting and notification facilities.
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: mixmsg.cxx,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "stdmix.h"
+#include "mixio.h"
+#include "mixmsg.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+
+static ostream& error_stream = cerr;
+
+static MxSeverityLevel current_severity =
+#if (SAFETY >= 0)
+	MXMSG_NOTE;
+#else
+	MXMSG_WARN;
+#endif
+
+static MxSeverityLevel current_lethality = MXMSG_ASSERT;
+
+static uint current_indent = 0;
+
+static mxmsg_handler current_handler = mxmsg_default_handler;
+
+
+static void prefix()
+{
+    for(uint i=0; i<current_indent; i++)
+	error_stream << "    ";
+}
+
+void mxmsg_signal(MxSeverityLevel severity,
+		  const char *msg, const char *context,
+		  const char *filename, int line)
+{
+    if( severity <= current_severity )
+    {
+	MxMsgInfo info;
+
+	info.severity = severity;
+	info.message = msg;
+	info.context = context;
+	info.filename = filename;
+	info.line = line;
+
+	bool result = (*current_handler)(&info);
+
+	if( !result )
+	{
+	    cerr << "MXMSG PANIC: Error while reporting signal!" << endl;
+	    exit(1);
+	}
+
+	if( severity <= current_lethality )
+	{
+	    if( severity == MXMSG_ASSERT )  abort();
+	    else                            exit(1);
+	}
+    }
+}
+
+void mxmsg_signalf(MxSeverityLevel severity, const char *format, ...)
+{
+    va_list args;
+
+    // !!BUG: It would be nice not to rely on a fixed-size buffer here.
+    char msg[512];
+
+    va_start(args, format);
+    vsprintf(msg, format, args);
+    va_end(args);
+    mxmsg_signal(severity, msg);
+}
+
+
+bool mxmsg_default_handler(MxMsgInfo *info)
+{
+    prefix();
+    error_stream << mxmsg_severity_name(info->severity) << ": ";
+    error_stream << info->message << endl;
+    if( info->context )
+    {
+	prefix();
+	error_stream << "  [Location: " << info->context << "]" << endl;
+    }
+    if( info->filename )
+    {
+	prefix();
+	error_stream << "  [File: " << info->filename
+		     << " at line " << info->line << "]" << endl;
+    }
+
+    return true;
+}
+
+void mxmsg_set_handler(mxmsg_handler h)
+{
+    current_handler = h;
+}
+
+MxSeverityLevel mxmsg_lethality_level() { return current_lethality; }
+void mxmsg_lethality_level(MxSeverityLevel l) { current_lethality = l; }
+
+MxSeverityLevel mxmsg_severity_level() { return current_severity; }
+void mxmsg_severity_level(MxSeverityLevel l) { current_severity = l; }
+
+static char *severity_names[] =
+{
+    "FATAL ERROR",
+    "ASSERT",
+    "ERROR",
+    "WARNING",
+    "NOTE",
+    "DEBUG",
+    "TRACE"
+};
+
+const char *mxmsg_severity_name(MxSeverityLevel l)
+{
+    if( l <= MXMSG_TRACE )
+	return severity_names[l];
+    else
+	return "USER";
+}
+
+void mxmsg_indent(uint i) { current_indent += i; }
+void mxmsg_dedent(uint i) { current_indent -= i; }
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxBlockModel.h
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxBlockModel.h	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxBlockModel.h	(revision 1097)
@@ -0,0 +1,130 @@
+#ifndef MXBLOCKMODEL_INCLUDED // -*- C++ -*-
+#define MXBLOCKMODEL_INCLUDED
+#if !defined(__GNUC__)
+#  pragma once
+#endif
+
+/************************************************************************
+
+  MxBlockModel
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxBlockModel.h,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "MxDynBlock.h"
+#include "MxGeoPrims.h"
+#include "MxRaster.h"
+
+#define MX_UNBOUND 0x0
+#define MX_PERFACE 0x1
+#define MX_PERVERTEX 0x2
+#define MX_MAX_BINDING 0x2
+
+#define MX_NORMAL_MASK   0x3
+#define MX_COLOR_MASK    (0x3<<2)
+#define MX_TEXTURE_MASK  (0x3<<4)
+#define MX_ALL_MASK      (MX_NORMAL_MASK|MX_COLOR_MASK|MX_TEXTURE_MASK)
+
+class MxBlockModel
+{
+private:
+    unsigned char cbinding, nbinding, tbinding;
+
+    unsigned int flags;
+
+    // Required blocks
+    MxDynBlock<MxVertex> vertices;
+    MxDynBlock<MxFace> faces;
+
+    // Optional blocks
+    MxDynBlock<MxNormal> *normals;
+    MxDynBlock<MxColor> *colors;
+    MxDynBlock<MxTexCoord> *tcoords;
+    // prop_block *properties;  // Indirect block for arbitrary properties
+
+    // Optional texture map
+    MxRaster *tex;
+    char *tex_name;
+
+protected:
+    virtual MxVertexID alloc_vertex(float, float, float);
+    virtual void init_vertex(MxVertexID) { }
+    virtual void free_vertex(MxVertexID) { }
+    virtual MxFaceID alloc_face(MxVertexID, MxVertexID, MxVertexID);
+    virtual void init_face(MxFaceID) { }
+    virtual void free_face(MxFaceID) { }
+
+public:
+    uint binding_mask;
+
+public:
+    MxBlockModel(int nvert, int nface) : vertices(nvert), faces(nface)
+	{
+	    colors = NULL;  normals = NULL;  tcoords = NULL;
+	    cbinding = nbinding = tbinding = MX_UNBOUND;
+	    binding_mask = MX_ALL_MASK;
+	    tex = NULL;
+	    tex_name = NULL;
+	}
+    virtual ~MxBlockModel()
+	{
+	    if( normals ) delete normals;
+	    if( colors ) delete colors;
+	    if( tcoords ) delete tcoords;
+	    if( tex ) delete tex;
+	    if( tex_name ) delete tex_name;
+	}
+
+    unsigned int vert_count() const { return vertices.length(); }
+    unsigned int face_count() const { return faces.length(); }
+    unsigned int color_count() const { return (colors?colors->length():0); }
+    unsigned int normal_count() const { return (normals?normals->length():0); }
+    uint texcoord_count() const { return (tcoords?tcoords->length():0); }
+
+    MxVertexID add_vertex(float, float, float);
+    MxFaceID add_face(uint, uint, uint, bool will_link=true);
+    unsigned int add_color(float, float, float);
+    unsigned int add_normal(float, float, float);
+    unsigned int add_texcoord(float, float);
+
+    MxVertexID add_vertex(float *v) { return add_vertex(v[0], v[1], v[2]); }
+    MxFaceID add_face(unsigned int *f) { return add_face(f[0], f[1], f[2]); }
+
+    void remove_vertex(MxVertexID v);
+    void remove_face(MxFaceID f);
+
+    MxVertex& vertex(unsigned int i) { return vertices(i); }
+    MxFace& face(unsigned int i) { return faces(i); }
+    MxVertex& corner(MxFaceID f, short i) { return vertex(face(f)[i]); }
+    MxColor& color(unsigned int i) { assert(colors);  return (*colors)(i); }
+    MxNormal& normal(unsigned int i) { assert(normals); return (*normals)(i); }
+    MxTexCoord& texcoord(uint i) { assert(tcoords); return (*tcoords)(i); }
+
+    int color_binding() { return (cbinding&(binding_mask>>2)); }
+    int normal_binding() { return (nbinding&binding_mask); }
+    int texcoord_binding() { return (tbinding&(binding_mask>>4)); }
+    void color_binding(unsigned char b);
+    void normal_binding(unsigned char b);
+    void texcoord_binding(unsigned char b);
+
+    const char *binding_name(int);
+    int parse_binding(const char *);
+
+    MxRaster *texmap() const { return tex; }
+    const char *texmap_name() const { return tex_name; }
+    uint add_texmap(MxRaster *, const char *name);
+
+    void compute_face_normal(MxFaceID, double *, bool will_unitize=true);
+    void compute_face_normal(MxFaceID, float *, bool will_unitize=true);
+    double compute_face_area(MxFaceID);
+    double compute_face_perimeter(MxFaceID, bool *edge_flags=NULL);
+
+    double compute_corner_angle(MxFaceID, uint);
+};
+
+
+// MXBLOCKMODEL_INCLUDED
+#endif
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxHeap.h
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxHeap.h	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxHeap.h	(revision 1097)
@@ -0,0 +1,69 @@
+#ifndef MXHEAP_INCLUDED // -*- C++ -*-
+#define MXHEAP_INCLUDED
+#if !defined(__GNUC__)
+#  pragma once
+#endif
+
+/************************************************************************
+
+  Heap
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxHeap.h,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "MxDynBlock.h"
+
+class MxHeapable
+{
+private:
+    float import;
+    int token;
+
+public:
+    MxHeapable() { not_in_heap(); heap_key(0.0f); }
+
+    inline bool is_in_heap() { return token != -47; }
+    inline void not_in_heap() { token = -47; }
+    inline int get_heap_pos() { return token; }
+    inline void set_heap_pos(int t) { token=t; }
+
+    inline void  heap_key(float k) { import=k; }
+    inline float heap_key() const  { return import; }
+};
+
+
+class MxHeap : private MxDynBlock<MxHeapable *>
+{
+private:
+    void place(MxHeapable *x, unsigned int i);
+    void swap(unsigned int i, unsigned int j);
+
+    unsigned int parent(unsigned int i) { return (i-1)/2; }
+    unsigned int left(unsigned int i) { return 2*i+1; }
+    unsigned int right(unsigned int i) { return 2*i+2; }
+
+    void upheap(unsigned int i);
+    void downheap(unsigned int i);
+
+public:
+    MxHeap() : MxDynBlock<MxHeapable *>(8) { }
+    MxHeap(unsigned int n) : MxDynBlock<MxHeapable *>(n) { }
+
+    void insert(MxHeapable *t) { insert(t, t->heap_key()); }
+    void insert(MxHeapable *, float);
+    void update(MxHeapable *t) { update(t, t->heap_key()); }
+    void update(MxHeapable *, float);
+
+    unsigned int size() const { return length(); }
+    MxHeapable       *item(uint i)       { return ref(i); }
+    const MxHeapable *item(uint i) const { return ref(i); }
+    MxHeapable *extract();
+    MxHeapable *top() { return (length()<1 ? (MxHeapable *)NULL : raw(0)); }
+    MxHeapable *remove(MxHeapable *);
+};
+
+// MXHEAP_INCLUDED
+#endif
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxBlock3.h
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxBlock3.h	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxBlock3.h	(revision 1097)
@@ -0,0 +1,59 @@
+#ifndef MXBLOCK3_INCLUDED // -*- C++ -*-
+#define MXBLOCK3_INCLUDED
+#if !defined(__GNUC__)
+#  pragma once
+#endif
+
+/************************************************************************
+
+  MxBlock3 provides typed access to 3D data blocks.
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxBlock3.h,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "MxBlock.h"
+
+template<class T>
+class MxBlock3 : public MxBlock<T>
+{
+private:
+    uint W, H, D;
+
+protected:
+    MxBlock3() { }
+
+    void init_block(uint w, uint h, uint d)
+	{ W=w; H=h; D=d;  MxBlock<T>::init_block(w*h*d); }
+    void resize_block(uint w, uint h, uint d)
+	{ W=w; H=h; D=d;  MxBlock<T>::resize_block(w*h*d); }
+    void free_block() { MxBlock<T>::free_block(); }
+
+    T& raw(uint i, uint j, uint k) { return MxBlock<T>::raw(k*W*H + j*W + i); }
+    const T& raw(uint i, uint j, uint k) const
+		{ return MxBlock<T>::raw(k*W*H + j*W + i); }
+
+#define __MXCK(i,j,k) AssertBound(i<W); AssertBound(j<H); AssertBound(k<D)
+
+public:
+    MxBlock3(uint w, uint h, uint d) { init_block(w, h, d); }
+    ~MxBlock3() { free_block(); }
+
+    T&       ref(uint i,uint j,uint k)       {__MXCK(i,j,k);return raw(i,j,k);}
+    const T& ref(uint i,uint j,uint k) const {__MXCK(i,j,k);return raw(i,j,k);}
+    T&       operator()(uint i,uint j,uint k)       { return ref(i,j,k); }
+    const T& operator()(uint i,uint j,uint k) const { return ref(i,j,k); }
+
+    uint width() const { return W; }
+    uint height() const { return H; }
+    uint depth() const { return D; }
+
+    void resize(uint w, uint h, uint d) { resize_block(w,h,d); }
+
+#undef __MXCK
+};
+
+// MXBLOCK3_INCLUDED
+#endif
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxMat2.cxx
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxMat2.cxx	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxMat2.cxx	(revision 1097)
@@ -0,0 +1,53 @@
+/************************************************************************
+
+  2x2 Matrix class
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxMat2.cxx,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "stdmix.h"
+#include "MxMat2.h"
+
+Mat2 Mat2::I(Vec2(1,0), Vec2(0,1));
+Mat2 Mat2::zero(Vec2(0,0), Vec2(0,0));
+Mat2 Mat2::unit(Vec2(1,1), Vec2(1,1));
+
+Mat2 Mat2::operator*(const Mat2& m) const
+{
+    Mat2 A;
+    int i,j;
+
+    for(i=0;i<2;i++)
+	for(j=0;j<2;j++)
+	    A(i,j) = row[i]*m.col(j);
+
+    return A;
+}
+
+double Mat2::det()
+{
+    return (row[0][0]*row[1][1] - row[0][1]*row[1][0]);
+}
+
+Mat2 Mat2::transpose()
+{
+    return Mat2(col(0), col(1));
+}
+
+double Mat2::invert(Mat2& inv)
+{
+    double d = det();
+
+    if( d==0.0 )
+	return 0.0;
+
+    inv.row[0][0] = row[1][1]/d;
+    inv.row[0][1] = -row[1][0]/d;
+    inv.row[1][0] = -row[0][1]/d;
+    inv.row[1][1] = row[0][0]/d;
+
+    return d;
+}
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxMat3.cxx
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxMat3.cxx	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxMat3.cxx	(revision 1097)
@@ -0,0 +1,90 @@
+/************************************************************************
+
+  3x3 Matrix class
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxMat3.cxx,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "stdmix.h"
+#include "MxMat3.h"
+
+Mat3 Mat3::I(Vec3(1,0,0), Vec3(0,1,0), Vec3(0,0,1));
+Mat3 Mat3::zero(Vec3(0,0,0), Vec3(0,0,0), Vec3(0,0,0));
+Mat3 Mat3::unit(Vec3(1,1,1), Vec3(1,1,1), Vec3(1,1,1));
+
+Mat3 Mat3::diag(const Vec3& v)
+{
+    Mat3 M(zero);
+
+    M(0,0) = v[X];
+    M(1,1) = v[Y];
+    M(2,2) = v[Z];
+
+    return M;
+}
+
+Mat3 Mat3::extend(const Vec3& v)
+{
+    return Mat3(v,v,v);
+}
+
+Mat3 Mat3::outer_product(const Vec3& v)
+{
+    Mat3 A;
+    double x=v[X], y=v[Y], z=v[Z];
+
+    A(0,0) = x*x;  A(0,1) = x*y;  A(0,2) = x*z;
+    A(1,0)=A(0,1); A(1,1) = y*y;  A(1,2) = y*z;
+    A(2,0)=A(0,2); A(2,1)=A(1,2); A(2,2) = z*z;
+
+    return A;
+}
+
+Mat3 Mat3::operator*(const Mat3& m) const
+{
+    Mat3 A;
+    int i,j;
+
+    for(i=0;i<3;i++)
+	for(j=0;j<3;j++)
+	    A(i,j) = row[i]*m.col(j);
+
+    return A;
+}
+
+double Mat3::det()
+{
+    return row[0] * (row[1] ^ row[2]);
+}
+
+double Mat3::trace()
+{
+    return row[0][0] + row[1][1] + row[2][2];
+}
+
+Mat3 Mat3::transpose()
+{
+    return Mat3(col(0), col(1), col(2));
+}
+
+Mat3 Mat3::adjoint()
+{
+    return Mat3(row[1]^row[2],
+		row[2]^row[0],
+		row[0]^row[1]);
+}
+
+double Mat3::invert(Mat3& inv)
+{
+    Mat3 A = adjoint();
+    double d = A.row[0] * row[0];
+
+    if( d==0.0 )
+	return 0.0;
+
+    inv = A.transpose() / d;
+    return d;
+}
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxMatrix.cxx
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxMatrix.cxx	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxMatrix.cxx	(revision 1097)
@@ -0,0 +1,87 @@
+/************************************************************************
+
+  NxN Matrix class
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxMatrix.cxx,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "stdmix.h"
+#include "MxMatrix.h"
+
+// Originally from Paul's matrix library.
+//
+// Returns determinant of a, and b=a inverse.
+// If matrix is singular, returns 0 and leaves trash in b.
+//
+// Uses Gaussian elimination with partial pivoting.
+
+#define SWAP(a, b, t)   {t = a; a = b; b = t;}
+static double internal_invert(MxMatrix& A, MxMatrix& B)
+{
+    uint N = A.dim();
+    uint i, j, k;
+    double max, t, det, pivot;
+
+    /*---------- forward elimination ----------*/
+
+    for (i=0; i<N; i++)                 /* put identity matrix in B */
+        for (j=0; j<N; j++)
+            B(i, j) = (double)(i==j);
+
+    det = 1.0;
+    for (i=0; i<N; i++) {               /* eliminate in column i, below diag */
+        max = -1.;
+        for (k=i; k<N; k++)             /* find pivot for column i */
+            if (fabs(A(k, i)) > max) {
+                max = fabs(A(k, i));
+                j = k;
+            }
+        if (max<=0.) return 0.;         /* if no nonzero pivot, PUNT */
+        if (j!=i) {                     /* swap rows i and j */
+            for (k=i; k<N; k++)
+                SWAP(A(i, k), A(j, k), t);
+            for (k=0; k<N; k++)
+                SWAP(B(i, k), B(j, k), t);
+            det = -det;
+        }
+        pivot = A(i, i);
+        det *= pivot;
+        for (k=i+1; k<N; k++)           /* only do elems to right of pivot */
+            A(i, k) /= pivot;
+        for (k=0; k<N; k++)
+            B(i, k) /= pivot;
+        /* we know that A(i, i) will be set to 1, so don't bother to do it */
+
+        for (j=i+1; j<N; j++) {         /* eliminate in rows below i */
+            t = A(j, i);                /* we're gonna zero this guy */
+            for (k=i+1; k<N; k++)       /* subtract scaled row i from row j */
+                A(j, k) -= A(i, k)*t;   /* (ignore k<=i, we know they're 0) */
+            for (k=0; k<N; k++)
+                B(j, k) -= B(i, k)*t;
+        }
+    }
+
+    /*---------- backward elimination ----------*/
+
+    for (i=N-1; i>0; i--) {             /* eliminate in column i, above diag */
+        for (j=0; j<i; j++) {           /* eliminate in rows above i */
+            t = A(j, i);                /* we're gonna zero this guy */
+            for (k=0; k<N; k++)         /* subtract scaled row i from row j */
+                B(j, k) -= B(i, k)*t;
+        }
+    }
+
+    return det;
+}
+
+#undef SWAP
+
+
+double mxm_invert(MxMatrix& r, const MxMatrix& a)
+{
+    MxMatrix a2(a);
+    return internal_invert(a2, r);
+}
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxMat4.cxx
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxMat4.cxx	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxMat4.cxx	(revision 1097)
@@ -0,0 +1,183 @@
+/************************************************************************
+
+  4x4 Matrix class
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxMat4.cxx,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "stdmix.h"
+#include "MxMat4.h"
+
+Mat4 Mat4::I(Vec4(1,0,0,0),Vec4(0,1,0,0),Vec4(0,0,1,0),Vec4(0,0,0,1));
+Mat4 Mat4::zero(Vec4(0,0,0,0),Vec4(0,0,0,0),Vec4(0,0,0,0),Vec4(0,0,0,0));
+Mat4 Mat4::unit(Vec4(1,1,1,1),Vec4(1,1,1,1),Vec4(1,1,1,1),Vec4(1,1,1,1));
+
+Mat4 Mat4::trans(double x, double y, double z)
+{
+    return Mat4(Vec4(1,0,0,x),
+		Vec4(0,1,0,y),
+		Vec4(0,0,1,z),
+		Vec4(0,0,0,1));
+}
+
+Mat4 Mat4::scale(double x, double y, double z)
+{
+    return Mat4(Vec4(x,0,0,0),
+		Vec4(0,y,0,0),
+		Vec4(0,0,z,0),
+		Vec4(0,0,0,1));
+}
+
+Mat4 Mat4::xrot(double a)
+{
+    double c = cos(a);
+    double s = sin(a);
+
+    return Mat4(Vec4(1, 0, 0, 0),
+		Vec4(0, c,-s, 0),
+		Vec4(0, s, c, 0),
+		Vec4(0, 0, 0, 1));
+}
+
+Mat4 Mat4::yrot(double a)
+{
+    double c = cos(a);
+    double s = sin(a);
+
+    return Mat4(Vec4(c, 0, s, 0),
+		Vec4(0, 1, 0, 0),
+		Vec4(-s,0, c, 0),
+		Vec4(0, 0, 0, 1));
+}
+
+Mat4 Mat4::zrot(double a)
+{
+    double c = cos(a);
+    double s = sin(a);
+
+    return Mat4(Vec4(c,-s, 0, 0),
+		Vec4(s, c, 0, 0),
+		Vec4(0, 0, 1, 0),
+		Vec4(0, 0, 0, 1));
+}
+
+Mat4 Mat4::operator*(const Mat4& m) const
+{
+    Mat4 A;
+    int i,j;
+
+    for(i=0;i<4;i++)
+	for(j=0;j<4;j++)
+	    A(i,j) = row[i]*m.col(j);
+
+    return A;
+}
+
+double Mat4::det() const
+{
+    return row[0] * cross(row[1], row[2], row[3]);
+}
+
+Mat4 Mat4::transpose() const
+{
+    return Mat4(col(0), col(1), col(2), col(3));
+}
+
+Mat4 Mat4::adjoint() const
+{
+    Mat4 A;
+
+    A.row[0] = cross( row[1], row[2], row[3]);
+    A.row[1] = cross(-row[0], row[2], row[3]);
+    A.row[2] = cross( row[0], row[1], row[3]);
+    A.row[3] = cross(-row[0], row[1], row[2]);
+        
+    return A;
+}
+
+double Mat4::cramerInvert(Mat4& inv) const
+{
+    Mat4 A = adjoint();
+    double d = A.row[0] * row[0];
+
+    if( d==0.0 )
+	return 0.0;
+
+    inv = A.transpose() / d;
+    return d;
+}
+
+
+
+
+// Matrix inversion code for 4x4 matrices.
+// Originally ripped off and degeneralized from Paul's matrix library
+// for the view synthesis (Chen) software.
+//
+// Returns determinant of a, and b=a inverse.
+// If matrix is singular, returns 0 and leaves trash in b.
+//
+// Uses Gaussian elimination with partial pivoting.
+
+#define SWAP(a, b, t)   {t = a; a = b; b = t;}
+double Mat4::invert(Mat4& B) const
+{
+    Mat4 A(*this);
+
+    int i, j, k;
+    double max, t, det, pivot;
+
+    /*---------- forward elimination ----------*/
+
+    for (i=0; i<4; i++)                 /* put identity matrix in B */
+        for (j=0; j<4; j++)
+            B(i, j) = (double)(i==j);
+
+    det = 1.0;
+    for (i=0; i<4; i++) {               /* eliminate in column i, below diag */
+        max = -1.;
+        for (k=i; k<4; k++)             /* find pivot for column i */
+            if (fabs(A(k, i)) > max) {
+                max = fabs(A(k, i));
+                j = k;
+            }
+        if (max<=0.) return 0.;         /* if no nonzero pivot, PUNT */
+        if (j!=i) {                     /* swap rows i and j */
+            for (k=i; k<4; k++)
+                SWAP(A(i, k), A(j, k), t);
+            for (k=0; k<4; k++)
+                SWAP(B(i, k), B(j, k), t);
+            det = -det;
+        }
+        pivot = A(i, i);
+        det *= pivot;
+        for (k=i+1; k<4; k++)           /* only do elems to right of pivot */
+            A(i, k) /= pivot;
+        for (k=0; k<4; k++)
+            B(i, k) /= pivot;
+        /* we know that A(i, i) will be set to 1, so don't bother to do it */
+
+        for (j=i+1; j<4; j++) {         /* eliminate in rows below i */
+            t = A(j, i);                /* we're gonna zero this guy */
+            for (k=i+1; k<4; k++)       /* subtract scaled row i from row j */
+                A(j, k) -= A(i, k)*t;   /* (ignore k<=i, we know they're 0) */
+            for (k=0; k<4; k++)
+                B(j, k) -= B(i, k)*t;
+        }
+    }
+
+    /*---------- backward elimination ----------*/
+
+    for (i=4-1; i>0; i--) {             /* eliminate in column i, above diag */
+        for (j=0; j<i; j++) {           /* eliminate in rows above i */
+            t = A(j, i);                /* we're gonna zero this guy */
+            for (k=0; k<4; k++)         /* subtract scaled row i from row j */
+                B(j, k) -= B(i, k)*t;
+        }
+    }
+
+    return det;
+}
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxCmdParser.h
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxCmdParser.h	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxCmdParser.h	(revision 1097)
@@ -0,0 +1,51 @@
+#ifndef MXCMDPARSER_INCLUDED // -*- C++ -*-
+#define MXCMDPARSER_INCLUDED
+#if !defined(__GNUC__)
+#  pragma once
+#endif
+
+/************************************************************************
+
+  MxCmdParser
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxCmdParser.h,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "MxDynBlock.h"
+#include "MxAsp.h"
+
+typedef MxDynBlock<char *> MxCmdPhrase;
+
+class MxCmd
+{
+public:
+    char *op;
+    MxDynBlock<MxCmdPhrase> phrases;
+
+    MxCmd(int N) : phrases(N) { op=NULL; }
+};
+
+class MxCmdParser
+{
+private:
+    MxCmd cmd;
+    MxAspStore store;
+
+public:
+    bool will_ignore_unknown;
+
+public:
+    MxCmdParser();
+
+    MxAspStore *asp_store() { return &store; }
+
+    void parse_line(char *, void *closure=NULL);
+
+    virtual bool execute_command(const MxCmd& cmd, void *closure=NULL);
+};
+
+// MXCMDPARSER_INCLUDED
+#endif
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxEdgeFilter.cxx
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxEdgeFilter.cxx	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxEdgeFilter.cxx	(revision 1097)
@@ -0,0 +1,142 @@
+/************************************************************************
+
+  MxEdgeFilter
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxEdgeFilter.cxx,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "stdmix.h"
+#include "MxEdgeFilter.h"
+#include "MxVector.h"
+
+MxEdgeFilter::MxEdgeFilter(MxStdModel *m0)
+    : heap(3*m0->vert_count()),
+      update_list(8)
+{
+    m = m0;
+
+    current_edge_count = original_edge_count = 0;
+}
+
+void MxEdgeFilter::rank_and_update_edge(MxRankedEdge *edge)
+{
+    float rank = compute_edge_rank(edge);
+
+    edge->heap_key(rank);
+
+    if( edge->is_in_heap() )
+	heap.update(edge);
+    else
+	heap.insert(edge);
+}
+
+MxRankedEdge *MxEdgeFilter::create_edge(MxVertexID v1, MxVertexID v2,
+					bool will_rank)
+{
+    MxRankedEdge *edge = new MxRankedEdge(v1, v2);
+    current_edge_count++;
+    if( will_rank )
+	rank_and_update_edge(edge);
+    return edge;
+}
+
+void MxEdgeFilter::collect_star_for_update(MxVertexID v)
+{
+    MxVertexList star;
+    m->collect_vertex_star(v, star);
+    for(uint i=0; i<star.length(); i++)
+	update_list.add(create_edge(v, star[i], false));
+}
+
+void MxEdgeFilter::collect_edges()
+{
+    MxVertexList star;
+
+    for(MxVertexID i=0; i<m->vert_count(); i++)
+    {
+	star.reset();
+	m->collect_vertex_star(i, star);
+
+	for(uint j=0; j<star.length(); j++)
+	    if( i<star[j] )
+	    {
+		create_edge(i, star[j]);
+		original_edge_count++;
+	    }
+    }
+}
+
+void MxEdgeFilter::initialize()
+{
+    collect_edges();
+}
+
+MxVertexID MxEdgeFilter::split_edge(MxRankedEdge *edge)
+{
+    MxVertexID vnew = m->split_edge(edge->v1, edge->v2);
+
+    collect_star_for_update(vnew);
+
+    return vnew;
+}
+
+bool MxEdgeFilter::filter1()
+{
+    MxRankedEdge *edge = (MxRankedEdge *)heap.extract();
+    if( !edge ) return false;
+
+    update_list.reset();
+
+    filter_target_edge(edge);
+
+    for(uint i=0; i<update_list.length(); i++)
+	rank_and_update_edge(update_list[i]);
+
+	// Allow for the possibility that this edge will be modified
+	// and placed back in the heap with a new rank.
+	//
+    if( !edge->is_in_heap() )
+	delete edge;
+
+    return true;
+}
+
+bool MxEdgeFilter::filter(uint target)
+{
+    while( current_edge_count < target )
+    {
+	if( !filter1() )
+	    return false;
+    }
+
+    return true;
+}
+
+bool MxEdgeFilter::filter_above_rank(float rank)
+{
+    while( heap.top() && heap.top()->heap_key() > rank )
+    {
+	if( !filter1() )
+	    return false;
+    }
+
+    return true;
+}
+
+////////////////////////////////////////////////////////////////////////
+//
+// Default implementations of rank & filter virtual functions.  The
+// effect of the defaults is to split edges based on squared length.
+//
+float MxEdgeFilter::compute_edge_rank(MxRankedEdge *edge)
+{
+    return mxv_L2(m->vertex(edge->v1), m->vertex(edge->v2), 3);
+}
+
+void MxEdgeFilter::filter_target_edge(MxRankedEdge *edge)
+{
+    split_edge(edge);
+}
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxStdModel.cxx
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxStdModel.cxx	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxStdModel.cxx	(revision 1097)
@@ -0,0 +1,670 @@
+/************************************************************************
+
+  MxStdModel
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxStdModel.cxx,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "stdmix.h"
+#include "MxStdModel.h"
+#include "MxVector.h"
+
+MxPairContraction& MxPairContraction::operator=(const MxPairContraction& c)
+{
+    v1 = c.v1;
+    v2 = c.v2;
+    mxv_set(dv1, c.dv1, 3);
+    mxv_set(dv2, c.dv2, 3);
+
+    delta_faces.reset();
+    dead_faces.reset();
+
+    for(uint i=0; i<c.delta_faces.length(); i++)
+	delta_faces.add(c.delta_faces[i]);
+    for(uint j=0; j<c.dead_faces.length(); j++)
+	dead_faces.add(c.dead_faces[j]);
+
+    delta_pivot = c.delta_pivot;
+
+    return *this;
+}
+
+MxStdModel::~MxStdModel()
+{
+    for(uint i=0; i<face_links.length(); i++)  delete face_links[i];
+}
+
+MxVertexID MxStdModel::alloc_vertex(float x, float y, float z)
+{
+    MxVertexID id = MxBlockModel::alloc_vertex(x,y,z);
+    v_data.add();
+    v_data(id).tag = 0x0;
+    v_data(id).user_tag = 0x0;
+    vertex_mark_valid(id);
+
+    unsigned int l = face_links.add(new MxFaceList);
+    SanityCheck( l == id );
+    SanityCheck( neighbors(id).length() == 0 );
+
+    return id;
+}
+
+void MxStdModel::free_vertex(MxVertexID v)
+{
+    delete face_links[v];
+    face_links.remove(v);
+    v_data.remove(v);
+}
+
+MxFaceID MxStdModel::alloc_face(MxVertexID v1, MxVertexID v2, MxVertexID v3)
+{
+    MxFaceID id = MxBlockModel::alloc_face(v1,v2,v3);
+    f_data.add();
+    f_data(id).tag = 0x0;
+    f_data(id).user_tag = 0x0;
+    face_mark_valid(id);
+
+    return id;
+}
+
+void MxStdModel::free_face(MxFaceID f)
+{
+    f_data.remove(f);
+}
+
+void MxStdModel::init_face(MxFaceID id)
+{
+    neighbors(face(id).v[0]).add(id);
+    neighbors(face(id).v[1]).add(id);
+    neighbors(face(id).v[2]).add(id);
+}
+
+void MxStdModel::mark_neighborhood(MxVertexID vid, unsigned short mark)
+{
+    AssertBound( vid < vert_count() ); 
+
+    for(unsigned int i=0; i<neighbors(vid).length(); i++)
+    {
+	unsigned int f = neighbors(vid)(i);
+	fmark(f, mark);
+    }
+}
+
+void MxStdModel::collect_unmarked_neighbors(MxVertexID vid,MxFaceList& faces)
+{
+    AssertBound( vid < vert_count() ); 
+
+    for(unsigned int i=0; i<neighbors(vid).length(); i++)
+    {
+	unsigned int fid = neighbors(vid)(i);
+	if( !fmark(fid) )
+	{
+	    faces.add(fid);
+	    fmark(fid, 1);
+	}
+    }
+}
+
+void MxStdModel::mark_neighborhood_delta(MxVertexID vid, short delta)
+{
+    AssertBound( vid < vert_count() );
+    for(uint i=0; i<neighbors(vid).length(); i++)
+    {
+	uint f = neighbors(vid)(i);
+	fmark(f, fmark(f)+delta);
+    }
+}
+
+void MxStdModel::partition_marked_neighbors(MxVertexID v, unsigned short pivot,
+					    MxFaceList& lo, MxFaceList& hi)
+{
+    AssertBound( v < vert_count() );
+    for(uint i=0; i<neighbors(v).length(); i++)
+    {
+	uint f = neighbors(v)(i);
+	if( fmark(f) )
+	{
+	    if( fmark(f) < pivot )  lo.add(f);
+	    else  hi.add(f);
+	    fmark(f, 0);
+	}
+    }
+}
+
+void MxStdModel::mark_corners(const MxFaceList& faces, unsigned short mark)
+{
+    for(uint i=0; i<faces.length(); i++)
+	for(uint j=0; j<3; j++)
+	    vmark(face(faces(i))(j), mark);
+}
+
+void MxStdModel::collect_unmarked_corners(const MxFaceList& faces,
+					  MxVertexList& verts)
+{
+    for(uint i=0; i<faces.length(); i++)
+	for(uint j=0; j<3; j++)
+	{
+	    MxVertexID v = face(faces(i))(j);
+	    if( !vmark(v) )
+	    {
+		verts.add(v);
+		vmark(v, 1);
+	    }
+	}
+}
+
+void MxStdModel::collect_edge_neighbors(unsigned int v1, unsigned int v2,
+					MxFaceList& faces)
+{
+    mark_neighborhood(v1, 1);
+    mark_neighborhood(v2, 0);
+    collect_unmarked_neighbors(v1, faces);
+}
+
+void MxStdModel::collect_vertex_star(unsigned int v, MxVertexList& verts)
+{
+    const MxFaceList& N = neighbors(v);
+
+    mark_corners(N, 0);
+    vmark(v, 1); // Don't want to include v in the star
+    collect_unmarked_corners(N, verts);
+}
+
+void MxStdModel::compute_vertex_normal(MxVertexID v, float *n)
+{
+    MxFaceList& star = neighbors(v);
+    mxv_set(n, 0.0f, 3);
+
+    unsigned int i;
+    for(i=0; i<star.length(); i++)
+    {
+	float fn[3];
+
+	// Weight normals uniformly
+	compute_face_normal(star(i), fn, false);
+	//
+	// Weight normals by angle around vertex
+	// 		uint c = face(star[i]).find_vertex(v);
+	// 		compute_face_normal(star[i], fn);
+	// 		mxv_scale(fn, compute_corner_angle(star[i], c), 3);
+
+	mxv_addinto(n, fn, 3);
+    }
+    if( i>0 )
+	mxv_unitize(n, 3);
+}
+
+
+void MxStdModel::synthesize_normals()
+{
+    float n[3];
+
+    if( normal_binding() == MX_PERFACE )
+    {
+	for(MxFaceID f=0; f<face_count(); f++)
+	{
+	    compute_face_normal(f, n);
+	    add_normal(n[X], n[Y], n[Z]);
+	}
+    }
+    else if( normal_binding() == MX_PERVERTEX )
+    {
+	for(MxVertexID v=0; v<vert_count(); v++)
+	{
+	    compute_vertex_normal(v, n);
+	    add_normal(n[X], n[Y], n[Z]);
+	}
+    }
+    else
+	mxmsg_signal(MXMSG_WARN, "Unsupported normal binding.",
+		     "MxStdModel::synthesize_normals");
+}
+
+
+
+void MxStdModel::remap_vertex(unsigned int from, unsigned int to)
+{
+    AssertBound( from < vert_count() ); 
+    AssertBound( to < vert_count() ); 
+    SanityCheck( vertex_is_valid(from) );
+    SanityCheck( vertex_is_valid(to) );
+    
+    for(unsigned int i=0; i<neighbors(from).length(); i++)
+	face(neighbors(from)(i)).remap_vertex(from, to);
+
+    mark_neighborhood(from, 0);
+    mark_neighborhood(to, 1);
+    collect_unmarked_neighbors(from, neighbors(to));
+
+    vertex_mark_invalid(from);
+    neighbors(from).reset();   // remove links in old vertex
+}
+
+unsigned int MxStdModel::split_edge(unsigned int a, unsigned int b)
+{
+    float *v1 = vertex(a), *v2 = vertex(b);
+
+    return split_edge(a, b,
+                      (v1[X] + v2[X])/2.0f,
+                      (v1[Y] + v2[Y])/2.0f,
+                      (v1[Z] + v2[Z])/2.0f);
+}
+
+static
+void remove_neighbor(MxFaceList& faces, unsigned int f)
+{
+    unsigned int j;
+    if( faces.find(f, &j) )
+	faces.remove(j);
+}
+
+unsigned int MxStdModel::split_edge(unsigned int v1, unsigned int v2,
+			    float x, float y, float z)
+{
+    AssertBound( v1 < vert_count() );   AssertBound( v2 < vert_count() );
+    SanityCheck( vertex_is_valid(v1) ); SanityCheck( vertex_is_valid(v2) );
+    SanityCheck( v1 != v2 );
+
+    MxFaceList faces;
+    collect_edge_neighbors(v1, v2, faces);
+    SanityCheck( faces.length() > 0 );
+
+    unsigned int vnew = add_vertex(x,y,z);
+
+    for(unsigned int i=0; i<faces.length(); i++)
+    {
+	unsigned int f = faces(i);
+	unsigned int v3 = face(f).opposite_vertex(v1, v2);
+	SanityCheck( v3!=v1 && v3!=v2 );
+	SanityCheck( vertex_is_valid(v3) );
+
+	// in f, remap v2-->vnew
+	face(f).remap_vertex(v2, vnew);
+	neighbors(vnew).add(f);
+
+	// remove f from neighbors(v2)
+	remove_neighbor(neighbors(v2), f);
+
+	// assure orientation is consistent
+	if( face(f).is_inorder(vnew, v3) )
+	    add_face(vnew, v2, v3);
+	else
+	    add_face(vnew, v3, v2);
+    }
+
+    return vnew;
+}
+
+void MxStdModel::flip_edge(unsigned int v1, unsigned int v2)
+{
+    MxFaceList faces;  collect_edge_neighbors(v1, v2, faces);
+    if( faces.length() != 2 ) return;
+
+    unsigned int f1 = faces(0);
+    unsigned int f2 = faces(1);
+    unsigned int v3 = face(f1).opposite_vertex(v1, v2);
+    unsigned int v4 = face(f2).opposite_vertex(v1, v2);
+
+    // ?? Should we check for convexity or assume thats been taken care of?
+
+    remove_neighbor(neighbors(v1), f2);
+    remove_neighbor(neighbors(v2), f1);
+    neighbors(v3).add(f2);
+    neighbors(v4).add(f1);
+
+    face(f1).remap_vertex(v2, v4);
+    face(f2).remap_vertex(v1, v3);
+}
+
+void MxStdModel::split_face4(unsigned int f, unsigned int *newverts)
+{
+    unsigned int v0 = face(f).v[0];
+    unsigned int v1 = face(f).v[1];
+    unsigned int v2 = face(f).v[2];
+
+    unsigned int pivot = split_edge(v0, v1);
+    unsigned int new1 = split_edge(v1, v2);
+    unsigned int new2 = split_edge(v0, v2);
+
+    if( newverts )
+    {
+	newverts[0] = pivot;
+	newverts[1] = new1;
+	newverts[2] = new2;
+    }
+
+    flip_edge(pivot, v2);
+}
+
+void MxStdModel::compact_vertices()
+{
+    MxVertexID oldID;
+    MxVertexID newID = 0;
+
+    for(oldID=0; oldID<vert_count(); oldID++)
+    {
+	if( vertex_is_valid(oldID) )
+	{
+	    if( newID != oldID )
+	    {
+		vertex(newID) = vertex(oldID);
+		if( normal_binding() == MX_PERVERTEX )
+		    normal(newID)=normal(oldID);
+		if( color_binding() == MX_PERVERTEX )
+		    color(newID)=color(oldID);
+		if( texcoord_binding() == MX_PERVERTEX )
+		    texcoord(newID) = texcoord(oldID);
+
+		// Because we'll be freeing the link lists for the
+		// old vertices, we actually have to swap values instead
+		// of the simple copying in the block above.
+		//
+		MxFaceList *t = face_links(newID);
+		face_links(newID) = face_links(oldID);
+		face_links(oldID) = t;
+
+		vertex_mark_valid(newID);
+
+		for(unsigned int i=0; i<neighbors(newID).length(); i++)
+		    face(neighbors(newID)(i)).remap_vertex(oldID, newID);
+	    }
+	    newID++;
+	}
+    }
+
+    for(oldID = newID; newID < vert_count(); )
+	remove_vertex(oldID);
+}
+
+void MxStdModel::unlink_face(MxFaceID fid)
+{
+    MxFace& f = face(fid);
+    face_mark_invalid(fid);
+
+    unsigned int j; int found=0;
+
+    if( neighbors(f(0)).find(fid, &j) )
+    {found++; neighbors(f(0)).remove(j);}
+    if( neighbors(f(1)).find(fid, &j) )
+    { found++; neighbors(f(1)).remove(j); }
+    if( neighbors(f(2)).find(fid, &j) )
+    { found++; neighbors(f(2)).remove(j); }
+    SanityCheck( found > 0 );
+    SanityCheck( !neighbors(f(0)).find(fid, &j) );
+    SanityCheck( !neighbors(f(1)).find(fid, &j) );
+    SanityCheck( !neighbors(f(2)).find(fid, &j) );
+}
+
+void MxStdModel::remove_degeneracy(MxFaceList& faces)
+{
+    for(unsigned int i=0; i<faces.length(); i++)
+    {
+	SanityCheck( face_is_valid(faces(i)) );
+	MxFace& f = face(faces(i));
+
+	if( f(0)==f(1) || f(1)==f(2) || f(0)==f(2) )
+	    unlink_face(faces(i));
+    }
+}
+
+void MxStdModel::compute_contraction(MxVertexID v1, MxVertexID v2,
+				     MxPairContraction *conx,
+				     const float *vnew)
+{
+    conx->v1 = v1;
+    conx->v2 = v2;
+
+    if( vnew )
+    {
+	mxv_sub(conx->dv1, vnew, vertex(v1), 3);
+	mxv_sub(conx->dv2, vnew, vertex(v2), 3);
+    }
+    else
+    {
+	conx->dv1[X] = conx->dv1[Y] = conx->dv1[Z] = 0.0;
+	conx->dv2[X] = conx->dv2[Y] = conx->dv2[Z] = 0.0;
+    }
+
+    conx->delta_faces.reset();
+    conx->dead_faces.reset();
+
+
+    // Mark the neighborhood of (v1,v2) such that each face is
+    // tagged with the number of times the vertices v1,v2 occur
+    // in it.  Possible values are 1 or 2.
+    //
+    mark_neighborhood(v2, 0);
+    mark_neighborhood(v1, 1);
+    mark_neighborhood_delta(v2, 1);
+
+
+    // Now partition the neighborhood of (v1,v2) into those faces
+    // which degenerate during contraction and those which are merely
+    // reshaped.
+    //
+    partition_marked_neighbors(v1, 2, conx->delta_faces, conx->dead_faces);
+    conx->delta_pivot = conx->delta_faces.length();
+    partition_marked_neighbors(v2, 2, conx->delta_faces, conx->dead_faces);
+}
+
+void MxStdModel::apply_contraction(const MxPairContraction& conx)
+{
+    MxVertexID v1=conx.v1, v2=conx.v2;
+
+    // Move v1 to new position
+    mxv_addinto(vertex(v1), conx.dv1, 3);
+
+    uint i;
+    //
+    // Remove dead faces
+    for(i=0; i<conx.dead_faces.length(); i++)
+	unlink_face(conx.dead_faces(i));
+
+    //
+    // Update changed faces
+    for(i=conx.delta_pivot; i<conx.delta_faces.length(); i++)
+    {
+	MxFaceID fid = conx.delta_faces(i);
+	face(fid).remap_vertex(v2, v1);
+	neighbors(v1).add(fid);
+    }
+
+    //
+    // !!HACK: This is really only a temporary solution to the problem
+    if( normal_binding() == MX_PERFACE )
+    {
+		float n[3];
+		for(i=0; i<conx.delta_faces.length(); i++)
+		{
+		    compute_face_normal(conx.delta_faces[i], n);
+		    normal(conx.delta_faces[i]) = MxNormal(n);
+		}
+    }
+
+    //
+    // Kill v2
+    vertex_mark_invalid(v2);
+    neighbors(v2).reset();
+}
+
+void MxStdModel::apply_expansion(const MxPairExpansion& conx)
+{
+    MxVertexID v1=conx.v1, v2=conx.v2;
+
+    mxv_sub(vertex(v2), vertex(v1), conx.dv2, 3);
+    mxv_subfrom(vertex(v1), conx.dv1, 3);
+
+    uint i,j;
+    for(i=0; i<conx.dead_faces.length(); i++)
+    {
+	MxFaceID fid = conx.dead_faces(i);
+	face_mark_valid(fid);
+	neighbors(face(fid)(0)).add(fid);
+	neighbors(face(fid)(1)).add(fid);
+	neighbors(face(fid)(2)).add(fid);
+    }
+
+    for(i=conx.delta_pivot; i<conx.delta_faces.length(); i++)
+    {
+		MxFaceID fid = conx.delta_faces(i);
+		face(fid).remap_vertex(v1, v2);
+		neighbors(v2).add(fid);
+		bool found = neighbors(v1).find(fid, &j);
+		SanityCheck( found );
+		neighbors(v1).remove(j);
+    }
+
+    //
+    // !!HACK: This is really only a temporary solution to the problem
+    if( normal_binding() == MX_PERFACE )
+    {
+		float n[3];
+		for(i=0; i<conx.delta_faces.length(); i++)
+		{
+		    compute_face_normal(conx.delta_faces[i], n);
+		    normal(conx.delta_faces[i]) = MxNormal(n);
+		}
+
+		for(i=0; i<conx.dead_faces.length(); i++)
+		{
+		    compute_face_normal(conx.dead_faces[i], n);
+		    normal(conx.dead_faces[i]) = MxNormal(n);
+		}
+    }
+
+    vertex_mark_valid(v2);
+}
+
+
+void MxStdModel::contract(MxVertexID v1, MxVertexID v2,
+			  const float *vnew, MxPairContraction *conx)
+{
+    compute_contraction(v1, v2, conx);
+    mxv_sub(conx->dv1, vnew, vertex(v1), 3);
+    mxv_sub(conx->dv2, vnew, vertex(v2), 3);
+    apply_contraction(*conx);
+}
+
+void MxStdModel::compute_contraction(MxFaceID fid, MxFaceContraction *conx)
+{
+    const MxFace& f = face(fid);
+
+    conx->f = fid;
+    conx->dv1[X] = conx->dv1[Y] = conx->dv1[Z] = 0.0;
+    conx->dv2[X] = conx->dv2[Y] = conx->dv2[Z] = 0.0;
+    conx->dv3[X] = conx->dv3[Y] = conx->dv3[Z] = 0.0;
+
+    conx->delta_faces.reset();
+    conx->dead_faces.reset();
+
+
+    PARANOID( mark_neighborhood(f[0], 0) );
+    mark_neighborhood(f[1], 0);
+    mark_neighborhood(f[2], 0);
+
+    mark_neighborhood(f[0], 1);
+    mark_neighborhood_delta(f[1], +1);
+    mark_neighborhood_delta(f[2], +1);
+
+    fmark(fid, 0);		// don't include f in dead_faces
+
+    partition_marked_neighbors(f[0], 2, conx->delta_faces, conx->dead_faces);
+    partition_marked_neighbors(f[1], 2, conx->delta_faces, conx->dead_faces);
+    partition_marked_neighbors(f[2], 2, conx->delta_faces, conx->dead_faces);
+}
+
+void MxStdModel::contract(MxVertexID v1, MxVertexID v2, MxVertexID v3,
+			  const float *vnew,
+			  MxFaceList& changed)
+{
+    mark_neighborhood(v1, 0);
+    mark_neighborhood(v2, 0);
+    mark_neighborhood(v3, 0);
+    changed.reset();
+    collect_unmarked_neighbors(v1, changed);
+    collect_unmarked_neighbors(v2, changed);
+    collect_unmarked_neighbors(v3, changed);
+
+    // Move v1 to vnew
+    vertex(v1)(0) = vnew[X];
+    vertex(v1)(1) = vnew[Y];
+    vertex(v1)(2) = vnew[Z];
+
+    // Replace occurrences of v2 & v3 with v1
+    remap_vertex(v2, v1);
+    remap_vertex(v3, v1);
+
+    remove_degeneracy(changed);
+
+    //
+    // !!HACK: Only a temporary solution
+    if( normal_binding() == MX_PERFACE )
+    {
+	float n[3];
+	for(uint i=0; i<changed.length(); i++)
+	    if( face_is_valid(changed[i]) )
+	    {
+		compute_face_normal(changed[i], n);
+		normal(changed[i]) = MxNormal(n);
+	    }
+    }
+}
+
+void MxStdModel::contract(MxVertexID v1, const MxVertexList& rest,
+			  const float *vnew, MxFaceList& changed)
+{
+    uint i;
+
+    // Collect all effected faces
+    mark_neighborhood(v1, 0);
+    for(i=0; i<rest.length(); i++)
+	mark_neighborhood(rest(i), 0);
+
+    changed.reset();
+
+    collect_unmarked_neighbors(v1, changed);
+    for(i=0; i<rest.length(); i++)
+	collect_unmarked_neighbors(rest(i), changed);
+
+    // Move v1 to vnew
+    vertex(v1)(0) = vnew[X];
+    vertex(v1)(1) = vnew[Y];
+    vertex(v1)(2) = vnew[Z];
+
+    // Replace all occurrences of vi with v1
+    for(i=0; i<rest.length(); i++)
+	remap_vertex(rest(i), v1);
+
+    remove_degeneracy(changed);
+}
+
+MxVertexID MxStdModel::resolve_proxies(MxVertexID v)
+{
+    while( vertex_is_proxy(v) )
+	v = vertex(v).as.proxy.parent;
+    return v;
+}
+
+float *MxStdModel::vertex_position(MxVertexID v)
+{
+    return vertex(resolve_proxies(v));
+}
+
+MxVertexID& MxStdModel::vertex_proxy_parent(MxVertexID v)
+{
+    SanityCheck( vertex_is_proxy(v) );
+    return vertex(v).as.proxy.parent;
+}
+
+MxVertexID MxStdModel::add_proxy_vertex(MxVertexID parent)
+{
+    MxVertexID v = alloc_vertex(0, 0, 0); // position will be ignored
+
+    vertex_mark_proxy(v);
+    vertex_proxy_parent(v) = parent;
+
+    return v;
+}
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxBlock.h
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxBlock.h	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxBlock.h	(revision 1097)
@@ -0,0 +1,103 @@
+#ifndef MXBLOCK_INCLUDED // -*- C++ -*-
+#define MXBLOCK_INCLUDED
+#if !defined(__GNUC__)
+#  pragma once
+#endif
+
+/************************************************************************
+
+  MxBlock provides typed access a contiguous block of elements.
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxBlock.h,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+#include "stdmix.h"
+template<class T>
+class MxBlock : public MxEQ
+{
+private:
+    uint N;
+    T *block;
+
+protected:
+    MxBlock() { }
+    void init_block(uint n)
+	{
+	    // Allocate memory for block
+	    N=n; block = (T *)malloc(sizeof(T)*n);
+
+	    // Initialize each entry
+	    for(uint i=0; i<n; i++) new((void *)&block[i], MX_ALLOC_INPLACE) T;
+	}
+    void resize_block(uint n)
+	{
+	    T *old = block;
+
+	    // Allocate new block
+	    block = (T *)realloc(old, sizeof(T)*n);
+
+	    // Initialize all the newly allocated entries
+	    for(uint i=N; i<n; i++) new((void *)&block[i], MX_ALLOC_INPLACE) T;
+
+	    N = n;
+	}
+    void free_block()
+	{
+#ifdef WIN32
+	    // The Microsoft compiler has a problem with the 
+	    // standard syntax below.  For some reason,
+	    // expanding it into the following pointer-based
+	    // version makes it work.  Don't ask me why.
+	    //
+	    for(uint i=0; i<N; i++)  { T *p = &block[i]; p->~T(); }
+	    free(block);
+#else
+	    // Call the relevant destructors for each element before
+	    // freeing the block.  Has now effect for types like 'int'.
+	    //
+	    for(uint i=0; i<N; i++)  block[i].~T();
+	    free(block);
+#endif
+	}
+
+    T&       raw(uint i)       { return block[i]; }
+    const T& raw(uint i) const { return block[i]; }
+
+
+public:
+    MxBlock(uint n) { init_block(n); }
+    ~MxBlock() { free_block(); }
+
+    // Standard accessors
+    //
+    T&       ref(uint i)              { AssertBound(i<N);return block[i]; }
+    const T& ref(uint i) const        { AssertBound(i<N);return block[i]; }
+    T&       operator()(uint i)       { return ref(i);   }
+    const T& operator()(uint i) const { return ref(i);   }
+#ifdef __GNUC__
+    // Most compilers can apply the casting operators and then use the
+    // standard array [].  GCC (2.7.2) seems to need explicit operators.
+    //
+    T&       operator[](uint i)       { return block[i]; }
+    const T& operator[](uint i) const { return block[i]; }
+#endif
+
+    operator const T*() const { return block; }
+    operator       T*()       { return block; }
+    uint length() const { return N; }
+
+    // Primitive methods for altering the data block
+    //
+    void resize(uint n) { resize_block(n); }
+    void bitcopy(const T *array, uint n) // copy bits directly
+	{ memcpy(block, array, MIN(n,N)*sizeof(T)); }
+    void copy(const T *array, const uint n) // copy using assignment operator
+	{ for(uint i=0; i<MIN(n,N); i++) block[i] = array[i]; }
+    void bitcopy(const MxBlock<T>& b) { bitcopy(b, b.length()); }
+    void copy(const MxBlock<T>& b) { copy(b, b.length()); }
+};
+
+// MXBLOCK_INCLUDED
+#endif
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxGLUtils.cxx
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxGLUtils.cxx	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxGLUtils.cxx	(revision 1097)
@@ -0,0 +1,125 @@
+/************************************************************************
+
+  MxGLUtils
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxGLUtils.cxx,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "stdmix.h"
+#include "MxGLUtils.h"
+
+
+void mxgl_default_texinit(MxRaster *tex, bool will_draw_texture)
+{
+    if( tex )
+    {
+	if( will_draw_texture ) glEnable(GL_TEXTURE_2D);
+        // glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
+        glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+//         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+//         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
+        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+
+	glTexImage(tex);
+	// gluMipmaps(tex);
+    }
+}
+
+void mxgl_default_init()
+{
+    glEnable(GL_DEPTH_TEST);
+    glEnable(GL_LIGHTING);
+    glEnable(GL_NORMALIZE);
+    glShadeModel(GL_SMOOTH);
+
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();
+    glMatrixMode(GL_MODELVIEW);
+
+    GLfloat mat_ambient[] = { 0.1f, 0.1f, 0.1f, 1.0f };
+    GLfloat mat_diffuse[] = { 0.5f, 0.5f, 0.5f, 1.0f };
+    GLfloat mat_specular[] = { 0.1f, 0.1f, 0.1f, 1.0f };
+    glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mat_ambient);
+    glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_diffuse);
+    glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular);
+    glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, 40);
+
+    GLfloat light_pos[] = {0.0f, 0.0f, 1.0f, 0.0f};
+    glLightfv(GL_LIGHT0, GL_POSITION, light_pos);
+    glEnable(GL_LIGHT0);
+
+    glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
+    glEnable(GL_COLOR_MATERIAL);
+    glColor3f(0.5f, 0.5f, 0.5f);
+    glClearColor(0.3f, 0.3f, 1.0f, 0.0f);
+
+    CAREFUL(mxgl_check_errors("at end of mxgl_default_init()"));
+}
+
+
+GLenum mxgl_matrix_for_mode(GLenum mode)
+{
+    switch( mode )
+    {
+    case GL_MODELVIEW:  return GL_MODELVIEW_MATRIX;
+    case GL_PROJECTION: return GL_PROJECTION_MATRIX;
+    case GL_TEXTURE:    return GL_TEXTURE_MATRIX;
+    }
+
+    return GL_FALSE;
+}
+
+#define pick_zmax MXID_NIL
+
+
+MxGLPicker::MxGLPicker(int x, int y, double window)
+    : buffer(128)
+{
+    GLint vp[4];
+
+    glMatrixMode(GL_PROJECTION);
+    glGetIntegerv(GL_VIEWPORT, vp);
+    glSelectBuffer(128, buffer);
+    glRenderMode(GL_SELECT);
+
+    gluPickMatrix(x, vp[3] - y, window, window, vp);
+    glInitNames();
+    glPushName(MXID_NIL);
+}
+
+uint MxGLPicker::complete()
+{
+    glFlush();
+
+    GLint nhits = glRenderMode(GL_RENDER);
+    GLuint hit = MXID_NIL;
+    GLuint zmin = pick_zmax;
+    GLuint *ptr = buffer;
+
+    for(uint i=0; i<nhits; i++)
+    {
+	GLuint nnames = *ptr++;
+	assert( nnames==1 ); // assume name stack is always 1 deep
+
+	GLuint cur_zmin = *ptr++;
+	GLuint cur_zmax = *ptr++;
+
+	if( cur_zmin < zmin )
+	{
+	    zmin = cur_zmin;
+	    hit = *ptr;
+	}
+	ptr++;
+    }
+
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();	// get rid of the pick matrix
+
+    return hit;
+}
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/mixmsg.h
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/mixmsg.h	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/mixmsg.h	(revision 1097)
@@ -0,0 +1,67 @@
+#ifndef MIXMSG_INCLUDED // -*- C++ -*-
+#define MIXMSG_INCLUDED
+#if !defined(__GNUC__)
+#  pragma once
+#endif
+
+/************************************************************************
+
+  MixKit error reporting and message notification support.
+
+  This module is meant to provide a small but reasonably flexible way of
+  reporting errors and other interesting events to the user.
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: mixmsg.h,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+//
+// Message severity levels
+//
+enum MxSeverityLevel
+{
+    MXMSG_FATAL = 0,
+    MXMSG_ASSERT,
+    MXMSG_ERROR,
+    MXMSG_WARN,
+    MXMSG_NOTE,
+    MXMSG_DEBUG,
+    MXMSG_TRACE
+};
+
+class MxMsgInfo
+{
+public:
+    MxSeverityLevel severity;
+    const char *message;
+    const char *context;
+    const char *filename;
+    int line;
+};
+
+typedef bool (*mxmsg_handler)(MxMsgInfo *);
+
+extern void mxmsg_signal(MxSeverityLevel severity,
+			 const char *msg, const char *context=NULL,
+			 const char *filename=NULL,
+			 int line=0);
+extern void mxmsg_signalf(MxSeverityLevel severity, const char *format, ...);
+
+
+extern bool mxmsg_default_handler(MxMsgInfo *);
+extern void mxmsg_set_handler(mxmsg_handler h=mxmsg_default_handler);
+
+extern MxSeverityLevel mxmsg_severity_level();
+extern void mxmsg_severity_level(MxSeverityLevel);
+extern const char *mxmsg_severity_name(MxSeverityLevel);
+
+extern MxSeverityLevel mxmsg_lethality_level();
+extern void mxmsg_lethality_level(MxSeverityLevel);
+
+extern void mxmsg_indent(uint i=1);
+extern void mxmsg_dedent(uint i=1);
+
+// MIXMSG_INCLUDED
+#endif
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxRaster.h
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxRaster.h	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxRaster.h	(revision 1097)
@@ -0,0 +1,106 @@
+#ifndef MXRASTER_INCLUDED // -*- C++ -*-
+#define MXRASTER_INCLUDED
+#if !defined(__GNUC__)
+#  pragma once
+#endif
+
+/************************************************************************
+
+  MxRaster
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxRaster.h,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "MxBlock.h"
+
+class MxRaster : private MxBlock<unsigned char>
+{
+private:
+    uint W, H, nchan;
+
+public:
+
+    MxRaster(uint w, uint h, uint c)
+	: MxBlock<unsigned char>(w*h*c)  { W=w;  H=h;  nchan=c; }
+
+    uint width() const { return W; }
+    uint height() const { return H; }
+    uint channels() const { return nchan; }
+    uint length() const { return MxBlock<unsigned char>::length(); }
+
+#ifdef __GNUC__
+    unsigned char& operator[](uint i)       { return raw(i); }
+    unsigned char  operator[](uint i) const { return raw(i); }
+#endif
+    operator unsigned char *()
+	{ return MxBlock<unsigned char>::operator unsigned char*(); }
+    operator const unsigned char *() const
+	{ return MxBlock<unsigned char>::operator const unsigned char*(); }
+
+    unsigned char *pixel(uint i, uint j)
+	{
+	    AssertBound(i<W && j<H);
+	    return ((unsigned char *)*this) + (j*W + i)*nchan;
+	}
+
+    const unsigned char *pixel(uint i, uint j) const
+	{
+	    AssertBound(i<W && j<H);
+	    return ((const unsigned char *)*this) + (j*W + i)*nchan;
+	}
+
+    unsigned char *operator()(uint i, uint j) { return pixel(i,j); }
+    const unsigned char *operator()(uint i, uint j) const {return pixel(i,j);}
+
+    void reverse(uint start=0, uint end=MXID_NIL);
+    void hflip();
+    void vflip();
+};
+
+////////////////////////////////////////////////////////////////////////
+//
+// File I/O primitives for rasters.
+// The basic format supported is PNM files.  Support for this format
+// is built-in, and thus always available.
+// 
+extern ostream& pnm_write_header(ostream&,const MxRaster&, bool is_raw=true);
+extern ostream& pnm_write_data(ostream&,const MxRaster&, bool is_raw=true);
+inline ostream& pnm_write(ostream& out, const MxRaster& r, bool is_raw=true)
+{ pnm_write_header(out,r,is_raw);  return pnm_write_data(out, r, is_raw); }
+
+extern MxRaster *pnm_read(istream&);
+
+// (Optional) support for TIFF files.
+// If libtiff is not available, these procedures will always fail.
+//
+extern bool tiff_write(const char *filename, const MxRaster&);
+extern MxRaster *tiff_read(const char *filename);
+
+////////////////////////////////////////////////////////////////////////
+//
+// OpenGL support
+//
+#ifdef MXGL_INCLUDED
+inline void glTexImage(const MxRaster& tex, GLenum target=GL_TEXTURE_2D)
+{
+    glTexImage2D(target, 0, 3, tex.width(), tex.height(),
+		 0, GL_RGB, GL_UNSIGNED_BYTE, (const unsigned char *)tex);
+}
+
+inline void gluMipmaps(const MxRaster& tex, GLenum target=GL_TEXTURE_2D)
+{
+    gluBuild2DMipmaps(target, 3, tex.width(), tex.height(),
+		      GL_RGB, GL_UNSIGNED_BYTE, (const unsigned char *)tex);
+}
+
+inline void glTexImage(const MxRaster *tex, GLenum target=GL_TEXTURE_2D)
+	{ glTexImage(*tex, target); }
+inline void gluMipmaps(const MxRaster *tex, GLenum target=GL_TEXTURE_2D)
+	{ gluMipmaps(*tex, target); }
+#endif
+
+// MXRASTER_INCLUDED
+#endif
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/CVS/Repository
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/CVS/Repository	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/CVS/Repository	(revision 1097)
@@ -0,0 +1,1 @@
+cvsyare/src/mixkit
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/CVS/Root
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/CVS/Root	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/CVS/Root	(revision 1097)
@@ -0,0 +1,1 @@
+:ext:matt@cvs.cg.tuwien.ac.at:/usr/local/cvsyare
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/CVS/Entries
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/CVS/Entries	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/CVS/Entries	(revision 1097)
@@ -0,0 +1,85 @@
+/Makefile/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxArcball.cxx/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxArcball.h/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxAsp.cxx/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxAsp.h/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxBlock.h/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxBlock2.h/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxBlock3.h/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxBlockModel.cxx/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxBlockModel.h/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxCamera.cxx/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxCamera.h/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxCmdParser.cxx/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxCmdParser.h/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxDynBlock.h/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxEdgeFilter.cxx/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxEdgeFilter.h/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxGL.h/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxGLDebug.cxx/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxGLPane.cxx/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxGLPane.h/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxGLUtils.cxx/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxGLUtils.h/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxGeoPrims.h/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxGeom3D.cxx/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxGeom3D.h/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxHeap.cxx/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxHeap.h/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxLineModel.cxx/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxLineModel.h/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxManipulator.h/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxMat2.cxx/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxMat2.h/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxMat3-jacobi.cxx/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxMat3.cxx/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxMat3.h/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxMat4-jacobi.cxx/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxMat4.cxx/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxMat4.h/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxMath.h/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxMatrix.cxx/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxMatrix.h/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxPropSlim.cxx/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxPropSlim.h/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxQMetric.cxx/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxQMetric.h/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxQMetric2.cxx/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxQMetric2.h/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxQMetric3.cxx/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxQMetric3.h/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxQSlim.cxx/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxQSlim.h/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxQVis3.cxx/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxRaster-tiff.cxx/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxRaster.cxx/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxRaster.h/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxSMF.cxx/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxSMF.h/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxStack.h/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxStdModel.cxx/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxStdModel.h/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxStdPane.cxx/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxStdPane.h/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxStdRender.cxx/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxStdSlim.cxx/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxStdSlim.h/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxTimer.cxx/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxTimer.h/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxTriProject.cxx/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxVec2.h/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxVec3.h/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxVec4.h/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/MxVector.h/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/getopt.c/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/getopt.h/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/getopt1.c/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/mixcfg.h.in/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/mixio.h/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/mixmops.cxx/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/mixmops.h/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/mixmsg.cxx/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/mixmsg.h/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/mixvops.h/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+/stdmix.h/1.1/Tue Sep 24 16:53:54 2002//Tnvocclusion-head
+D
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/CVS/Entries.Extra
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/CVS/Entries.Extra	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/CVS/Entries.Extra	(revision 1097)
@@ -0,0 +1,84 @@
+/Makefile////*///
+/MxArcball.cxx////*///
+/MxArcball.h////*///
+/MxAsp.cxx////*///
+/MxAsp.h////*///
+/MxBlock.h////*///
+/MxBlock2.h////*///
+/MxBlock3.h////*///
+/MxBlockModel.cxx////*///
+/MxBlockModel.h////*///
+/MxCamera.cxx////*///
+/MxCamera.h////*///
+/MxCmdParser.cxx////*///
+/MxCmdParser.h////*///
+/MxDynBlock.h////*///
+/MxEdgeFilter.cxx////*///
+/MxEdgeFilter.h////*///
+/MxGL.h////*///
+/MxGLDebug.cxx////*///
+/MxGLPane.cxx////*///
+/MxGLPane.h////*///
+/MxGLUtils.cxx////*///
+/MxGLUtils.h////*///
+/MxGeoPrims.h////*///
+/MxGeom3D.cxx////*///
+/MxGeom3D.h////*///
+/MxHeap.cxx////*///
+/MxHeap.h////*///
+/MxLineModel.cxx////*///
+/MxLineModel.h////*///
+/MxManipulator.h////*///
+/MxMat2.cxx////*///
+/MxMat2.h////*///
+/MxMat3-jacobi.cxx////*///
+/MxMat3.cxx////*///
+/MxMat3.h////*///
+/MxMat4-jacobi.cxx////*///
+/MxMat4.cxx////*///
+/MxMat4.h////*///
+/MxMath.h////*///
+/MxMatrix.cxx////*///
+/MxMatrix.h////*///
+/MxPropSlim.cxx////*///
+/MxPropSlim.h////*///
+/MxQMetric.cxx////*///
+/MxQMetric.h////*///
+/MxQMetric2.cxx////*///
+/MxQMetric2.h////*///
+/MxQMetric3.cxx////*///
+/MxQMetric3.h////*///
+/MxQSlim.cxx////*///
+/MxQSlim.h////*///
+/MxQVis3.cxx////*///
+/MxRaster-tiff.cxx////*///
+/MxRaster.cxx////*///
+/MxRaster.h////*///
+/MxSMF.cxx////*///
+/MxSMF.h////*///
+/MxStack.h////*///
+/MxStdModel.cxx////*///
+/MxStdModel.h////*///
+/MxStdPane.cxx////*///
+/MxStdPane.h////*///
+/MxStdRender.cxx////*///
+/MxStdSlim.cxx////*///
+/MxStdSlim.h////*///
+/MxTimer.cxx////*///
+/MxTimer.h////*///
+/MxTriProject.cxx////*///
+/MxVec2.h////*///
+/MxVec3.h////*///
+/MxVec4.h////*///
+/MxVector.h////*///
+/getopt.c////*///
+/getopt.h////*///
+/getopt1.c////*///
+/mixcfg.h.in////*///
+/mixio.h////*///
+/mixmops.cxx////*///
+/mixmops.h////*///
+/mixmsg.cxx////*///
+/mixmsg.h////*///
+/mixvops.h////*///
+/stdmix.h////*///
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/CVS/Tag
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/CVS/Tag	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/CVS/Tag	(revision 1097)
@@ -0,0 +1,1 @@
+Tnvocclusion-head
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxVec3.h
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxVec3.h	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxVec3.h	(revision 1097)
@@ -0,0 +1,262 @@
+#ifndef MXVEC3_INCLUDED // -*- C++ -*-
+#define MXVEC3_INCLUDED
+#if !defined(__GNUC__)
+#  pragma once
+#endif
+
+/************************************************************************
+
+  3D Vector class
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxVec3.h,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "MxMath.h"
+#include "MxVec2.h"
+
+#ifdef MIX_USE_TVEC
+#include "MxVector.h"
+
+template<class T>
+class MxTVec3 : public MxVBlock<T, 3>
+{
+public:
+    MxTVec3() { }
+    MxTVec3(T x, T y, T z) { (*this)[0]=x; (*this)[1]=y; (*this)[2]=z; }
+    MxTVec3(const MxVBlock<T, 3>& v) : MxVBlock<T, 3>(v) { }
+    MxTVec3(const float *v) {(*this)[0]=v[0];(*this)[1]=v[1];(*this)[2]=v[2];}
+    MxTVec3(const double *v) {(*this)[0]=v[0];(*this)[1]=v[1];(*this)[2]=v[2];}
+
+    inline MxTVec3<T> operator^(const MxTVec3<T>& v) const
+	{ MxTVec3<T> r; mxv_cross3(r, *this, v); return r; }
+};
+
+typedef MxTVec3<double> Vec3;
+
+#else
+
+class Vec3 {
+private:
+    double elt[3];
+
+protected:
+    inline void copy(const Vec3& v);
+
+public:
+    //
+    // Standard constructors
+    //
+    Vec3(double x=0, double y=0, double z=0) { elt[0]=x; elt[1]=y; elt[2]=z; }
+    Vec3(const Vec2& v, double z) { elt[0]=v[0]; elt[1]=v[1]; elt[2]=z; }
+    Vec3(const Vec3& v) { copy(v); }
+    Vec3(const float *v) { elt[0]=v[0]; elt[1]=v[1]; elt[2]=v[2]; }
+    Vec3(const double *v) { elt[0]=v[0]; elt[1]=v[1]; elt[2]=v[2]; }
+
+    //
+    // Access methods
+    //
+    double& operator()(uint i)       { AssertBound(i<3); return elt[i]; }
+    double  operator()(uint i) const { AssertBound(i<3); return elt[i]; }
+#ifdef __GNUC__
+    double& operator[](uint i)       { return elt[i]; }
+    double  operator[](uint i) const { return elt[i]; }
+#endif
+
+    operator double*() { return elt; }
+    operator const double*() const { return elt; }
+    // operator Vec2&() { return *((Vec2 *)this); }
+
+    //
+    // Comparison operators
+    //
+    inline bool operator==(const Vec3& v) const;
+    inline bool operator!=(const Vec3& v) const;
+
+    //
+    // Assignment and in-place arithmetic methods
+    //
+    inline void set(double x,double y,double z) {elt[0]=x; elt[1]=y; elt[2]=z;}
+    inline Vec3& operator=(const Vec3& v);
+    inline Vec3& operator+=(const Vec3& v);
+    inline Vec3& operator-=(const Vec3& v);
+    inline Vec3& operator*=(double s);
+    inline Vec3& operator/=(double s);
+
+    //
+    // Binary arithmetic methods
+    //
+    inline Vec3 operator+(const Vec3& v) const;
+    inline Vec3 operator-(const Vec3& v) const;
+    inline Vec3 operator-() const;
+
+    inline Vec3 operator*(double s) const;
+    inline Vec3 operator/(double s) const;
+    inline double operator*(const Vec3& v) const;
+    inline Vec3 operator^(const Vec3& v) const;
+};
+
+
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// Method definitions
+//
+
+inline void Vec3::copy(const Vec3& v)
+{
+    elt[0]=v.elt[0]; elt[1]=v.elt[1]; elt[2]=v.elt[2];
+}
+
+inline bool Vec3::operator==(const Vec3& v) const
+{
+    double dx=elt[X]-v[X],  dy=elt[Y]-v[Y],  dz=elt[Z]-v[Z];
+    return (dx*dx + dy*dy + dz*dz) < FEQ_EPS2;
+}
+
+inline bool Vec3::operator!=(const Vec3& v) const
+{
+    double dx=elt[X]-v[X],  dy=elt[Y]-v[Y],  dz=elt[Z]-v[Z];
+    return (dx*dx + dy*dy + dz*dz) > FEQ_EPS2;
+}
+
+inline Vec3& Vec3::operator=(const Vec3& v)
+{
+    copy(v);
+    return *this;
+}
+
+inline Vec3& Vec3::operator+=(const Vec3& v)
+{
+    elt[0] += v[0];   elt[1] += v[1];   elt[2] += v[2];
+    return *this;
+}
+
+inline Vec3& Vec3::operator-=(const Vec3& v)
+{
+    elt[0] -= v[0];   elt[1] -= v[1];   elt[2] -= v[2];
+    return *this;
+}
+
+inline Vec3& Vec3::operator*=(double s)
+{
+    elt[0] *= s;   elt[1] *= s;   elt[2] *= s;
+    return *this;
+}
+
+inline Vec3& Vec3::operator/=(double s)
+{
+    elt[0] /= s;   elt[1] /= s;   elt[2] /= s;
+    return *this;
+}
+
+
+inline Vec3 Vec3::operator+(const Vec3& v) const
+{
+    return Vec3(elt[0]+v[0], elt[1]+v[1], elt[2]+v[2]);
+}
+
+inline Vec3 Vec3::operator-(const Vec3& v) const
+{
+    return Vec3(elt[0]-v[0], elt[1]-v[1], elt[2]-v[2]);
+}
+
+inline Vec3 Vec3::operator-() const
+{
+    return Vec3(-elt[0], -elt[1], -elt[2]);
+}
+
+inline Vec3 Vec3::operator*(double s) const
+{
+    return Vec3(elt[0]*s, elt[1]*s, elt[2]*s);
+}
+
+inline Vec3 Vec3::operator/(double s) const
+{
+    return Vec3(elt[0]/s, elt[1]/s, elt[2]/s);
+}
+
+inline double Vec3::operator*(const Vec3& v) const
+{
+    return elt[0]*v[0] + elt[1]*v[1] + elt[2]*v[2];
+}
+
+inline Vec3 Vec3::operator^(const Vec3& v) const
+{
+    Vec3 w( elt[1]*v[2] - v[1]*elt[2],
+	   -elt[0]*v[2] + v[0]*elt[2],
+	    elt[0]*v[1] - v[0]*elt[1] );
+    return w;
+}
+#endif
+
+// Make scalar multiplication commutative
+inline Vec3 operator*(double s, const Vec3& v) { return v*s; }
+
+
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// Primitive function definitions
+//
+
+inline double norm(const Vec3& v)
+{
+    return sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
+}
+
+inline double norm2(const Vec3& v)
+{
+    return v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
+}
+
+inline double unitize(Vec3& v)
+{
+    double l=norm2(v);
+    if( l!=1.0 && l!=0.0 )
+    {
+	l = sqrt(l);
+	v /= l;
+    }
+    return l;
+}
+
+inline Vec2 proj(const Vec3& v)
+{
+    Vec2 u(v[0], v[1]);
+    if( v[2]!=1.0 && v[2]!=0.0 )
+	u /= v[2];
+    return u;
+}
+
+
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// Misc. function definitions
+//
+
+inline ostream& operator<<(ostream& out, const Vec3& v)
+{
+    return out << v[0] << " " << v[1] << " " << v[2];
+}
+
+inline istream& operator>>(istream& in, Vec3& v)
+{
+    return in >> v[0] >> v[1] >> v[2];
+}
+
+#ifdef MXGL_INCLUDED
+inline void glV(const Vec3& v) { glVertex3d(v[X], v[Y], v[Z]); }
+inline void glN(const Vec3& v) { glNormal3d(v[X], v[Y], v[Z]); }
+inline void glC(const Vec3& v) { glColor3d(v[X], v[Y], v[Z]); }
+#endif
+
+
+// MXVEC3_INCLUDED
+#endif
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxQMetric2.cxx
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxQMetric2.cxx	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxQMetric2.cxx	(revision 1097)
@@ -0,0 +1,112 @@
+/************************************************************************
+
+  2D Quadric Error Metric
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+
+  $Id: MxQMetric2.cxx,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "stdmix.h"
+#include "MxQMetric2.h"
+
+
+void MxQuadric2::init(double a, double b, double c, double len)
+{
+    a2 = a*a;  ab = a*b;  ac = a*c;
+               b2 = b*b;  bc = b*c;
+	                  c2 = c*c;
+
+    r = len;
+}
+
+Mat2 MxQuadric2::tensor() const
+{
+    return Mat2(a2, ab, ab, b2);
+}
+
+Mat3 MxQuadric2::homogeneous() const
+{
+    return Mat3(Vec3(a2, ab, ac),
+		Vec3(ab, b2, bc),
+		Vec3(ac, bc, c2));
+}
+
+MxQuadric2& MxQuadric2::operator=(const MxQuadric2& Q)
+{
+    r = Q.r;
+
+    a2 = Q.a2;  ab = Q.ab;  ac = Q.ac;
+                b2 = Q.b2;  bc = Q.bc;
+		            c2 = Q.c2;
+
+    return *this;
+}
+
+MxQuadric2& MxQuadric2::operator+=(const MxQuadric2& Q)
+{
+    r += Q.r;
+
+    a2 += Q.a2;  ab += Q.ab;  ac += Q.ac;
+                 b2 += Q.b2;  bc += Q.bc;
+		              c2 += Q.c2;
+
+    return *this;
+}
+
+MxQuadric2& MxQuadric2::operator-=(const MxQuadric2& Q)
+{
+    r -= Q.r;
+
+    a2 -= Q.a2;  ab -= Q.ab;  ac -= Q.ac;
+                 b2 -= Q.b2;  bc -= Q.bc;
+		              c2 -= Q.c2;
+
+    return *this;
+}
+
+MxQuadric2& MxQuadric2::operator*=(double s)
+{
+    // Don't scale area
+
+    a2 *= s;  ab *= s;  ac *= s;
+              b2 *= s;  bc *= s;
+	                c2 *= s;
+
+    return *this;
+}
+
+double MxQuadric2::evaluate(double x, double y) const
+{
+    // Evaluate vAv + 2bv + c
+
+    return x*x*a2 + 2*x*y*ab + 2*x*ac
+	          + y*y*b2   + 2*y*bc
+	                     + c2;
+}
+
+bool MxQuadric2::optimize(Vec2& v) const
+{
+    Mat2 Ainv;
+    double det = tensor().invert(Ainv);
+    if( FEQ(det, 0.0, 1e-12) )
+	return false;
+
+    v = -(Ainv*vector());
+
+    return true;
+}
+
+bool MxQuadric2::optimize(float *x, float *y) const
+{
+    Vec2 v;
+
+    bool success = optimize(v);
+    if( success )
+    {
+	*x = (float)v[X];
+	*y = (float)v[Y];
+    }
+    return success;
+}
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxQMetric3.cxx
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxQMetric3.cxx	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxQMetric3.cxx	(revision 1097)
@@ -0,0 +1,217 @@
+/************************************************************************
+
+  3D Quadric Error Metrics
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxQMetric3.cxx,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "stdmix.h"
+#include "MxQMetric3.h"
+
+#include "MxMat2.h"
+
+void MxQuadric3::init(double a, double b, double c, double d, double area)
+{
+    a2 = a*a;  ab = a*b;  ac = a*c;  ad = a*d;
+               b2 = b*b;  bc = b*c;  bd = b*d;
+	                  c2 = c*c;  cd = c*d;
+			             d2 = d*d;
+
+    r = area;
+}
+
+void MxQuadric3::init(const Mat4& Q, double area)
+{
+    a2 = Q(0,0);  ab = Q(0,1);  ac = Q(0,2);  ad = Q(0,3);
+                  b2 = Q(1,1);  bc = Q(1,2);  bd = Q(1,3);
+		                c2 = Q(2,2);  cd = Q(2,3);
+				              d2 = Q(3,3);
+
+    r = area;
+}
+
+Mat3 MxQuadric3::tensor() const
+{
+    return Mat3(Vec3(a2, ab, ac),
+		Vec3(ab, b2, bc),
+		Vec3(ac, bc, c2));
+}
+
+Mat4 MxQuadric3::homogeneous() const
+{
+    return Mat4(Vec4(a2, ab, ac, ad),
+		Vec4(ab, b2, bc, bd),
+		Vec4(ac, bc, c2, cd),
+		Vec4(ad, bd, cd, d2));
+}
+
+void MxQuadric3::set_coefficients(const double *v)
+{
+    a2 = v[0];  ab = v[1];  ac = v[2];  ad = v[3];
+                b2 = v[4];  bc = v[5];  bd = v[6];
+		            c2 = v[7];  cd = v[8];
+                                        d2 = v[9];
+}
+
+MxQuadric3& MxQuadric3::operator=(const MxQuadric3& Q)
+{
+    r = Q.r;
+
+    a2 = Q.a2;  ab = Q.ab;  ac = Q.ac;  ad = Q.ad;
+                b2 = Q.b2;  bc = Q.bc;  bd = Q.bd;
+		            c2 = Q.c2;  cd = Q.cd;
+                                        d2 = Q.d2;
+
+    return *this;
+}
+
+MxQuadric3& MxQuadric3::operator+=(const MxQuadric3& Q)
+{
+    // Accumulate area
+    r += Q.r;
+
+    // Accumulate coefficients
+    a2 += Q.a2;  ab += Q.ab;  ac += Q.ac;  ad += Q.ad;
+                 b2 += Q.b2;  bc += Q.bc;  bd += Q.bd;
+		              c2 += Q.c2;  cd += Q.cd;
+			                   d2 += Q.d2;
+
+    return *this;
+}
+
+MxQuadric3& MxQuadric3::operator-=(const MxQuadric3& Q)
+{
+    r -= Q.r;
+
+    a2 -= Q.a2;  ab -= Q.ab;  ac -= Q.ac;  ad -= Q.ad;
+                 b2 -= Q.b2;  bc -= Q.bc;  bd -= Q.bd;
+		              c2 -= Q.c2;  cd -= Q.cd;
+			                   d2 -= Q.d2;
+
+    return *this;
+}
+
+MxQuadric3& MxQuadric3::operator*=(double s)
+{
+    // Scale coefficients
+    a2 *= s;  ab *= s;  ac *= s;  ad *= s;
+              b2 *= s;  bc *= s;  bd *= s;
+                        c2 *= s;  cd *= s;
+			          d2 *= s;
+
+    return *this;
+}
+
+MxQuadric3& MxQuadric3::transform(const Mat4& P)
+{
+    Mat4 Q = homogeneous();
+    Mat4 Pa = P.adjoint();
+
+    // Compute:  trans(Pa) * Q * Pa
+    // NOTE: Pa is symmetric since Q is symmetric
+
+    Q = Pa * Q * Pa;
+
+
+    // ??BUG: Should we be transforming the area??
+    init(Q, r);
+
+    return *this;
+}
+
+
+double MxQuadric3::evaluate(double x, double y, double z) const
+{
+    // Evaluate vAv + 2bv + c
+
+    return x*x*a2 + 2*x*y*ab + 2*x*z*ac + 2*x*ad
+	          + y*y*b2   + 2*y*z*bc + 2*y*bd
+	                     + z*z*c2   + 2*z*cd
+	                                + d2;
+}
+
+bool MxQuadric3::optimize(Vec3& v) const
+{
+    Mat3 Ainv;
+    double det = tensor().invert(Ainv);
+    if( FEQ(det, 0.0, 1e-12) )
+	return false;
+
+    v = -(Ainv*vector());
+
+    return true;
+}
+
+bool MxQuadric3::optimize(float *x, float *y, float *z) const
+{
+    Vec3 v;
+
+    bool success = optimize(v);
+    if( success )
+    {
+	*x = (float)v[X];
+	*y = (float)v[Y];
+	*z = (float)v[Z];
+    }
+    return success;
+}
+
+bool MxQuadric3::optimize(Vec3& v, const Vec3& v1, const Vec3& v2) const
+{
+    Vec3 d = v1 - v2;
+    Mat3 A = tensor();
+
+    Vec3 Av2 = A*v2;
+    Vec3 Ad  = A*d;
+
+    double denom = 2*d*Ad;
+    if( FEQ(denom, 0.0, 1e-12) )
+	return false;
+
+    double a =  ( -2*(vector()*d) - (d*Av2) - (v2*Ad) ) / ( 2*(d*Ad) );
+
+    if( a<0.0 ) a=0.0; else if( a>1.0 ) a=1.0;
+
+    v = a*d + v2;
+    return true;
+}
+
+
+bool MxQuadric3::optimize(Vec3& v, const Vec3& v1,
+			  const Vec3& v2, const Vec3& v3) const
+{
+    Vec3 d13 = v1 - v3;
+    Vec3 d23 = v2 - v3;
+    Mat3 A = tensor();
+    Vec3 B = vector();
+
+    Vec3 Ad13 = A*d13;
+    Vec3 Ad23 = A*d23;
+    Vec3 Av3  = A*v3;
+
+    double d13_d23 = (d13*Ad23) + (d23*Ad13);
+    double v3_d13  = (d13*Av3) + (v3*Ad13);
+    double v3_d23  = (d23*Av3) + (v3*Ad23);
+
+    double d23Ad23 = d23*Ad23;
+    double d13Ad13 = d13*Ad13;
+
+    double denom = d13Ad13*d23Ad23 - 2*d13_d23;
+    if( FEQ(denom, 0.0, 1e-12) )
+	return false;
+
+    double a = ( d23Ad23*(2*(B*d13) + v3_d13) -
+		  d13_d23*(2*(B*d23) + v3_d23) ) / -denom;
+
+    double b = ( d13Ad13*(2*(B*d23) + v3_d23) -
+		  d13_d23*(2*(B*d13) + v3_d13) ) / -denom;
+
+    if( a<0.0 ) a=0.0; else if( a>1.0 ) a=1.0;
+    if( b<0.0 ) b=0.0; else if( b>1.0 ) b=1.0;
+
+    v = a*d13 + b*d23 + v3;
+    return true;
+}
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxGL.h
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxGL.h	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxGL.h	(revision 1097)
@@ -0,0 +1,172 @@
+#ifndef MXGL_INCLUDED // -*- C++ -*-
+#define MXGL_INCLUDED
+#if !defined(__GNUC__)
+#  pragma once
+#endif
+
+/************************************************************************
+
+  MxGL
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxGL.h,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#ifdef WIN32
+#include <windows.h>
+#else
+#include <GL/glx.h>
+#endif
+
+#include <GL/gl.h>
+#include <GL/glu.h>
+
+/*************************************************************************
+ *
+ * Yes, here it is.  A bunch of nice overloaded routines to make it
+ * easier on the fingers to write OpenGL drawing code.
+ *
+ * The general stuff provided here is:
+ *
+ *      - glV
+ *      - glN
+ *      - glC
+ *
+ *************************************************************************/
+
+inline void glV(short x, short y)   { glVertex2s(x,y); }
+inline void glV(int x, int y)       { glVertex2i(x,y); }
+inline void glV(float x, float y)   { glVertex2f(x,y); }
+inline void glV(double x, double y) { glVertex2d(x,y); }
+
+inline void glV(short x, short y, short z)    { glVertex3s(x,y,z); }
+inline void glV(int x, int y, int z)          { glVertex3i(x,y,z); }
+inline void glV(float x, float y, float z)    { glVertex3f(x,y,z); }
+inline void glV(double x, double y, double z) { glVertex3d(x,y,z); }
+
+inline void glV(short x, short y, short z, short w ) { glVertex4s(x,y,z,w); }
+inline void glV(int x, int y, int z, int w)          { glVertex4i(x,y,z,w); }
+inline void glV(float x, float y, float z, float w)  { glVertex4f(x,y,z,w); }
+inline void glV(double x,double y,double z,double w) { glVertex4d(x,y,z,w); }
+
+inline void glV2(const short *v)  { glVertex2sv(v); }
+inline void glV2(const int *v)    { glVertex2iv(v); }
+inline void glV2(const float *v)  { glVertex2fv(v); }
+inline void glV2(const double *v) { glVertex2dv(v); }
+
+inline void glV3(const short *v)  { glVertex3sv(v); }
+inline void glV3(const int *v)    { glVertex3iv(v); }
+inline void glV3(const float *v)  { glVertex3fv(v); }
+inline void glV3(const double *v) { glVertex3dv(v); }
+
+inline void glV4(const short *v)  { glVertex4sv(v); }
+inline void glV4(const int *v)    { glVertex4iv(v); }
+inline void glV4(const float *v)  { glVertex4fv(v); }
+inline void glV4(const double *v) { glVertex4dv(v); }
+
+////////////////////////////////////
+
+inline void glN(short x, short y, short z)    { glNormal3s(x,y,z); }
+inline void glN(int x, int y, int z)          { glNormal3i(x,y,z); }
+inline void glN(float x, float y, float z)    { glNormal3f(x,y,z); }
+inline void glN(double x, double y, double z) { glNormal3d(x,y,z); }
+
+inline void glN(const short *v)  { glNormal3sv(v); }
+inline void glN(const int *v)    { glNormal3iv(v); }
+inline void glN(const float *v)  { glNormal3fv(v); }
+inline void glN(const double *v) { glNormal3dv(v); }
+
+////////////////////////////////////
+
+inline void glC(short x, short y, short z)    { glColor3s(x,y,z); }
+inline void glC(int x, int y, int z)          { glColor3i(x,y,z); }
+inline void glC(float x, float y, float z)    { glColor3f(x,y,z); }
+inline void glC(double x, double y, double z) { glColor3d(x,y,z); }
+
+inline void glC(short x,short y,short z,short w)     {glColor4s(x,y,z,w);}
+inline void glC(int x, int y, int z, int w)          {glColor4i(x,y,z,w);}
+inline void glC(float x,float y,float z,float w)     {glColor4f(x,y,z,w);}
+inline void glC(double x,double y,double z,double w) {glColor4d(x,y,z,w);}
+
+////////////////////////////////////
+
+inline void glLoadMatrix(const double *m) { glLoadMatrixd(m); }
+inline void glLoadMatrix(const float *m)  { glLoadMatrixf(m); }
+
+inline void glGetMatrix(double *m, GLenum src=GL_PROJECTION_MATRIX)
+{ glGetDoublev(src, m); }
+inline void glGetMatrix(float *m, GLenum src=GL_PROJECTION_MATRIX)
+{ glGetFloatv(src, m); }
+
+/*************************************************************************
+ *
+ * Here's some more useful stuff.
+ *
+ *************************************************************************/
+
+inline void glOffsetForMesh(float factor=1.0, float bias=1e-6)
+{
+#if defined(MIX_HAVE_POLYOFFSET) || defined(WIN32)
+    glEnable(GL_POLYGON_OFFSET_FILL);
+    glPolygonOffset(factor, bias);
+#elif defined(MIX_HAVE_POLYOFFSET_EXT)
+    glEnable(GL_POLYGON_OFFSET_EXT);
+    glPolygonOffsetEXT(factor, bias);
+#endif
+}
+
+
+inline void glNoOffset()
+{
+#if defined(MIX_HAVE_POLYOFFSET) || defined(WIN32)
+    glDisable(GL_POLYGON_OFFSET_FILL);
+#elif defined(MIX_HAVE_POLYOFFSET_EXT)
+    glDisable(GL_POLYGON_OFFSET_EXT);
+#endif
+}
+
+inline void glGetViewport(int *x, int *y, int *w, int *h)
+{
+    GLint viewport[4];
+    glGetIntegerv(GL_VIEWPORT, viewport);
+
+    if( x ) *x = viewport[0];
+    if( y ) *y = viewport[1];
+    if( w ) *w = viewport[2];
+    if( h ) *h = viewport[3];
+}
+
+inline void glUnproject(int win_x, int win_y, int win_z,
+                        double *x, double *y, double *z)
+{
+    GLdouble modelMatrix[16];
+    GLdouble projMatrix[16];
+    GLint viewport[4];
+
+    glGetDoublev(GL_PROJECTION_MATRIX, projMatrix);
+    glGetDoublev(GL_MODELVIEW_MATRIX, modelMatrix);
+    glGetIntegerv(GL_VIEWPORT, viewport);
+
+    gluUnProject(win_x,win_y,win_z,
+                 modelMatrix, projMatrix, viewport,
+                 x, y, z);
+}
+
+inline int glGetRenderMode()
+{
+    int mode; glGetIntegerv(GL_RENDER_MODE, &mode); return mode;
+}
+
+/*************************************************************************
+ *
+ * Debugging and diagnostic tools
+ *
+ *************************************************************************/
+
+extern void mxgl_report_stack_depth();
+extern void mxgl_check_errors(const char *msg=NULL);
+
+// MXGL_INCLUDED
+#endif
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxMat2.h
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxMat2.h	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxMat2.h	(revision 1097)
@@ -0,0 +1,154 @@
+#ifndef MXMAT2_INCLUDED // -*- C++ -*-
+#define MXMAT2_INCLUDED
+#if !defined(__GNUC__)
+#  pragma once
+#endif
+
+/************************************************************************
+
+  2x2 Matrix class
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxMat2.h,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "MxMath.h"
+#include "MxVec2.h"
+
+class Mat2
+{
+private:
+    Vec2 row[2];
+
+protected:
+
+    inline void copy(const Mat2& m);
+    inline Vec2 col(int i) const {return Vec2(row[0][i],row[1][i]);}
+
+public:
+    // Standard matrices
+    static Mat2 I;
+    static Mat2 zero;
+    static Mat2 unit;
+
+    // Standard constructors
+    Mat2() { copy(zero); }
+    Mat2(double a, double b, double c, double d)
+	{ row[0][0]=a; row[0][1]=b; row[1][0]=c; row[1][1]=d; }
+    Mat2(const Vec2& r0,const Vec2& r1) { row[0]=r0; row[1]=r1; }
+    Mat2(const Mat2& m) { copy(m); }
+
+    // Access methods
+    // M(i, j) == row i;col j
+    double& operator()(int i, int j)       { return row[i][j]; }
+    double  operator()(int i, int j) const { return row[i][j]; }
+    Vec2&       operator[](int i)       { return row[i]; }
+    const Vec2& operator[](int i) const { return row[i]; }
+
+    operator       double*()       { return row[0]; }
+    operator const double*() const { return row[0]; }
+
+    // Assignment methods
+    inline Mat2& operator=(const Mat2& m) { copy(m); return *this; }
+    inline Mat2& operator+=(const Mat2& m);
+    inline Mat2& operator-=(const Mat2& m);
+
+    inline Mat2& operator*=(double s);
+    inline Mat2& operator/=(double s);
+
+
+    // Arithmetic methods
+    inline Mat2 operator+(const Mat2& m) const;
+    inline Mat2 operator-(const Mat2& m) const;
+    inline Mat2 operator-() const;
+
+    inline Mat2 operator*(double s) const;
+    inline Mat2 operator/(double s) const;
+    Mat2 operator*(const Mat2& m) const;
+
+    inline Vec2 operator*(const Vec2& v) const; // [x y]
+
+    // Matrix operations
+    double det();
+    Mat2 transpose();
+    double invert(Mat2&);
+};
+
+
+
+
+inline void Mat2::copy(const Mat2& m)
+{
+    row[0] = m.row[0]; row[1] = m.row[1];
+}
+
+inline Mat2& Mat2::operator+=(const Mat2& m)
+{
+    row[0] += m.row[0]; row[1] += m.row[1];
+    return *this;
+}
+
+inline Mat2& Mat2::operator-=(const Mat2& m)
+{
+    row[0] -= m.row[0]; row[1] -= m.row[1];
+    return *this;
+}
+
+inline Mat2& Mat2::operator*=(double s)
+{
+    row[0] *= s; row[1] *= s;
+    return *this;
+}
+
+inline Mat2& Mat2::operator/=(double s)
+{
+    row[0] /= s; row[1] /= s;
+    return *this;
+}
+
+inline Mat2 Mat2::operator+(const Mat2& m) const
+{
+    return Mat2(row[0]+m.row[0],
+		row[1]+m.row[1]);
+}
+
+inline Mat2 Mat2::operator-(const Mat2& m) const
+{
+    return Mat2(row[0]-m.row[0],
+		row[1]-m.row[1]);
+}
+
+inline Mat2 Mat2::operator-() const
+{
+    return Mat2(-row[0], -row[1]);
+}
+
+inline Mat2 Mat2::operator*(double s) const
+{
+    return Mat2(row[0]*s, row[1]*s);
+}
+
+inline Mat2 Mat2::operator/(double s) const
+{
+    return Mat2(row[0]/s, row[1]/s);
+}
+
+inline Vec2 Mat2::operator*(const Vec2& v) const
+{
+    return Vec2(row[0]*v, row[1]*v);
+}
+
+inline ostream& operator<<(ostream& out, const Mat2& M)
+{
+    return out << M[0] << endl  << M[1];
+}
+
+inline istream& operator>>(istream& in, Mat2& M)
+{
+    return in >> M[0] >> M[1];
+}
+
+// MXMAT2_INCLUDED
+#endif
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/stdmix.h
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/stdmix.h	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/stdmix.h	(revision 1097)
@@ -0,0 +1,155 @@
+#ifndef STDMIX_INCLUDED // -*- C++ -*-
+#define STDMIX_INCLUDED
+#if !defined(__GNUC__)
+#  pragma once
+#endif
+
+/************************************************************************
+
+  Standard base include file for the MIX library.  This defines various
+  common stuff that is used elsewhere.
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: stdmix.h,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#ifdef HAVE_MIXCFG_H
+#include "mixcfg.h"
+#endif
+
+#if !defined(MIX_ANSI_IOSTREAMS) && defined(WIN32)
+#define MIX_ANSI_IOSTREAMS
+#endif
+
+#include <stdlib.h>
+#ifdef HAVE_UNISTD_H
+#  include <unistd.h>
+#endif
+#include <string.h>
+#include <limits.h>
+#if defined(MIX_ANSI_IOSTREAMS)
+#  include <iostream>
+#  if _MSC_VER >= 1200
+    //
+    // The "using namespace std" directive causes internal compiler errors in
+    // MS VC6.0 (aka v1200) when using MFC.  Using this explicit list solves
+    // the problem.  This certainly seems like a bug in the MS compiler.
+    using std::istream; using std::ostream; using std::ifstream;
+    using std::ofstream; using std::cin; using std::cout; using std::cerr;
+    using std::endl; using std::ws;
+#  else
+    using namespace std;
+#  endif
+#else
+#  include <iostream.h>
+#endif
+
+#ifdef MIX_NEED_BOOL
+#  ifdef bool
+#    undef bool
+#  endif
+typedef int bool;
+const bool false = 0;
+const bool true = 1;
+#endif
+
+#ifdef UINT_MAX
+#  define MXID_NIL UINT_MAX
+#else
+#  define MXID_NIL 0xffffffffU
+#endif
+
+#if !defined(HAVE_UINT) && !defined(uint)
+typedef unsigned int uint;
+#endif
+
+#if !defined(HAVE_USHORT) && !defined(ushort)
+typedef unsigned short ushort;
+#endif
+
+#ifndef MIN
+#  define MIN(a,b) (((a)>(b))?(b):(a))
+#  define MAX(a,b) (((a)>(b))?(a):(b))
+#endif
+
+#ifndef ABS
+#  define ABS(x) (((x)<0)?-(x):(x))
+#endif
+
+inline bool streq(const char *a, const char *b) { return !strcmp(a,b); }
+
+//
+// Default equality class
+//
+class MxEQ {
+public: bool operator==(const MxEQ& x) const { return this==&x; }
+};
+
+////////////////////////////////////////////////////////////////////////
+//
+// Optimization control, debugging, and error reporting facilities
+//
+
+//
+// Safety levels:
+//
+//       -2 Reckless
+//       -1 Optimized
+//        0 Normal
+//        1 Cautious
+//        2 Paranoid
+//
+#ifndef SAFETY
+// Default safety policy is to take the middle of the road
+#define SAFETY 0
+#endif
+
+#include "mixmsg.h"
+
+#define fatal_error(s) mxmsg_signal(MXMSG_FATAL, s, NULL, __FILE__, __LINE__)
+
+#ifdef assert
+#  undef assert
+#endif
+
+#if SAFETY >= 0
+#  define assert(i) (i)?((void)NULL):mxmsg_signal(MXMSG_ASSERT, # i, \
+						  NULL, __FILE__, __LINE__)
+#  define CAREFUL(x) x
+#else
+#  define assert(i)
+#  define CAREFUL(x)
+#endif
+
+#if SAFETY==2
+#  define SanityCheck(t) assert(t)
+#  define PARANOID(x) x
+#else
+#  define SanityCheck(t)
+#  define PARANOID(x)
+#endif
+
+#if SAFETY > 0
+#  define AssertBound(t)  assert(t)
+#  define PRECAUTION(x) x
+#else
+#  define AssertBound(t)
+#  define PRECAUTION(x)
+#endif
+
+////////////////////////////////////////////////////////////////////////
+//
+// Memory management stuff
+//
+
+enum MxAllocPolicy { MX_ALLOC_INPLACE };
+
+inline void *operator new(size_t, void *spot, MxAllocPolicy)
+{
+    return spot;  // MX_ALLOC_INPLACE
+}
+
+// STDMIX_INCLUDED
+#endif
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxMat4.h
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxMat4.h	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxMat4.h	(revision 1097)
@@ -0,0 +1,209 @@
+#ifndef MXMAT4_INCLUDED // -*- C++ -*-
+#define MXMAT4_INCLUDED
+#if !defined(__GNUC__)
+#  pragma once
+#endif
+
+/************************************************************************
+
+  4x4 Matrix class
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxMat4.h,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "MxMath.h"
+#include "MxVec4.h"
+
+class Mat4
+{
+private:
+    Vec4 row[4];
+
+protected:
+
+    inline void copy(const Mat4& m);
+    inline Vec4 col(int i) const
+        { return Vec4(row[0][i],row[1][i],row[2][i],row[3][i]); }
+
+public:
+    // Standard matrices
+    static Mat4 I;
+    static Mat4 zero;
+    static Mat4 unit;
+
+    static Mat4 trans(double,double,double);
+    static Mat4 scale(double,double,double);
+    static Mat4 xrot(double); //
+    static Mat4 yrot(double); // Arguments are in radians
+    static Mat4 zrot(double); //
+
+
+    // Standard constructors
+    Mat4() { copy(zero); }
+    Mat4(const Vec4& r0,const Vec4& r1,const Vec4& r2,const Vec4& r3)
+    { row[0]=r0; row[1]=r1; row[2]=r2; row[3]=r3; }
+    Mat4(const Mat4& m) { copy(m); }
+
+    // Access methods
+    // M(i, j) == row i;col j
+    double& operator()(int i, int j)       { return row[i][j]; }
+    double  operator()(int i, int j) const { return row[i][j]; }
+    Vec4&       operator[](int i)       { return row[i]; }
+    const Vec4& operator[](int i) const { return row[i]; }
+
+    operator       double*()       { return row[0]; }
+    operator const double*() const { return row[0]; }
+
+    // Comparison methods
+    inline int operator==(const Mat4&);
+
+    // Assignment methods
+    inline Mat4& operator=(const Mat4& m) { copy(m); return *this; }
+    inline Mat4& operator+=(const Mat4& m);
+    inline Mat4& operator-=(const Mat4& m);
+
+    inline Mat4& operator*=(double s);
+    inline Mat4& operator/=(double s);
+
+
+    // Arithmetic methods
+    inline Mat4 operator+(const Mat4& m) const;
+    inline Mat4 operator-(const Mat4& m) const;
+    inline Mat4 operator-() const;
+
+    inline Mat4 operator*(double s) const;
+    inline Mat4 operator/(double s) const;
+    Mat4 operator*(const Mat4& m) const;
+
+    inline Vec4 operator*(const Vec4& v) const; // [x y z w]
+    inline Vec3 operator*(const Vec3& v) const; // [x y z w]
+
+    // Matrix operations
+    double det() const;
+    Mat4 transpose() const;
+    Mat4 adjoint() const;
+    double invert(Mat4&) const;
+    double cramerInvert(Mat4&) const;
+};
+
+
+
+
+inline void Mat4::copy(const Mat4& m)
+{
+    row[0] = m.row[0]; row[1] = m.row[1];
+    row[2] = m.row[2]; row[3] = m.row[3];
+}
+
+inline int Mat4::operator==(const Mat4& m)
+{
+    return row[0]==m.row[0] &&
+	   row[1]==m.row[1] &&
+	   row[2]==m.row[2] &&
+	   row[3]==m.row[3] ;
+}
+
+inline Mat4& Mat4::operator+=(const Mat4& m)
+{
+    row[0] += m.row[0]; row[1] += m.row[1];
+    row[2] += m.row[2]; row[3] += m.row[3];
+    return *this;
+}
+
+inline Mat4& Mat4::operator-=(const Mat4& m)
+{
+    row[0] -= m.row[0]; row[1] -= m.row[1];
+    row[2] -= m.row[2]; row[3] -= m.row[3];
+    return *this;
+}
+
+inline Mat4& Mat4::operator*=(double s)
+{
+    row[0] *= s; row[1] *= s; row[2] *= s; row[3] *= s;
+    return *this;
+}
+
+inline Mat4& Mat4::operator/=(double s)
+{
+    row[0] /= s; row[1] /= s; row[2] /= s; row[3] /= s;
+    return *this;
+}
+
+inline Mat4 Mat4::operator+(const Mat4& m) const
+{
+    return Mat4(row[0]+m.row[0],
+		row[1]+m.row[1],
+		row[2]+m.row[2],
+		row[3]+m.row[3]);
+}
+
+inline Mat4 Mat4::operator-(const Mat4& m) const
+{
+    return Mat4(row[0]-m.row[0],
+		row[1]-m.row[1],
+		row[2]-m.row[2],
+		row[3]-m.row[3]);
+}
+
+inline Mat4 Mat4::operator-() const
+{
+    return Mat4(-row[0], -row[1], -row[2], -row[3]);
+}
+
+inline Mat4 Mat4::operator*(double s) const
+{
+    return Mat4(row[0]*s, row[1]*s, row[2]*s, row[3]*s);
+}
+
+inline Mat4 Mat4::operator/(double s) const
+{
+    return Mat4(row[0]/s, row[1]/s, row[2]/s, row[3]/s);
+}
+
+inline Vec4 Mat4::operator*(const Vec4& v) const
+{
+    return Vec4(row[0]*v, row[1]*v, row[2]*v, row[3]*v);
+}
+
+//
+// Transform a homogeneous 3-vector and reproject into normal 3-space
+//
+inline Vec3 Mat4::operator*(const Vec3& v) const
+{
+    Vec4 u=Vec4(v,1);
+    double w=row[3]*u;
+
+    if(w==0.0)
+	return Vec3(row[0]*u, row[1]*u, row[2]*u);
+    else
+	return Vec3(row[0]*u/w, row[1]*u/w, row[2]*u/w);
+}
+
+inline ostream& operator<<(ostream& out, const Mat4& M)
+{
+    return out<<M[0]<<endl<<M[1]<<endl<<M[2]<<endl<<M[3];
+}
+
+inline istream& operator>>(istream& in, Mat4& M)
+{
+    return in >> M[0] >> M[1] >> M[2] >> M[3];
+}
+
+extern bool jacobi(const Mat4& m, Vec4& vals, Vec4 vecs[4]);
+
+#ifdef MXGL_INCLUDED
+inline void glGetMatrix(Mat4& m, GLenum which=GL_MODELVIEW_MATRIX)
+{ Mat4 tmp;  glGetDoublev(which, &tmp(0,0));  m=tmp.transpose(); }
+
+inline void glLoadMatrix(const Mat4& m)
+{ Mat4 tmp = m.transpose();  glLoadMatrixd(&tmp(0,0)); }
+
+inline void glMultMatrix(const Mat4& m)
+{ Mat4 tmp = m.transpose();  glMultMatrixd(&tmp(0,0)); }
+#endif
+
+// MXMAT4_INCLUDED
+#endif
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxGLPane.h
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxGLPane.h	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxGLPane.h	(revision 1097)
@@ -0,0 +1,238 @@
+#ifndef MXGLPANE_INCLUDED // -*- C++ -*-
+#define MXGLPANE_INCLUDED
+#if !defined(__GNUC__)
+#  pragma once
+#endif
+
+/************************************************************************
+
+  MxGLPane
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxGLPane.h,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#ifdef WIN32
+//
+// Include MFC stuff now so that <windows.h> doesn't get included for GL
+//
+#  define VC_EXTRALEAN
+#  include <afxwin.h>	    // MFC core and standard components
+#  include <afxext.h>	    // MFC extensions
+#endif
+
+#include "MxGL.h"
+#include "MxRaster.h"
+
+#define MX_BUTTONDOWN 1
+#define MX_BUTTONUP 2
+#define MX_POINTERMOTION 3
+// Keep lowest digit unused to avoid clashes with the event symbols
+#define MX_CTRLKEY 0x10
+#define MX_SHIFTKEY 0x20
+
+// Specific ASCII keycodes
+//
+// BUG: This is not an appropriate home for this key stuff.
+//      At some point, we should consolidate this and related items
+//      into a unified event module.
+//
+#define MXKEY_BS  0x08
+#define MXKEY_DEL 0x7f
+#define MXKEY_NL  0x0a
+#define MXKEY_CR  0x0d
+
+#if defined(WIN32)
+
+// Handy alternative to RGB()
+inline COLORREF fRGB(float r, float g, float b)
+{
+    return RGB((uint)(r*255.0f), (uint)(g*255.0f), (uint)(b*255.0f));
+}
+
+class MxGLPane : public CFrameWnd
+{
+private:
+    HGLRC gl_context;
+    int pixel_format;
+    CDC *active_dc;
+
+    bool set_pixel_format(HDC);
+    bool create_glcontext(HDC);
+
+    void handle_mouse(int kind, UINT flags, CPoint point);
+    void do_redraw(CDC& dc);
+
+protected:  // MFC virtual function overrides
+    BOOL PreCreateWindow(CREATESTRUCT& cs);
+
+protected:  // MFC event handlers
+    afx_msg void OnPaint();
+    afx_msg BOOL OnEraseBkgnd(CDC *);
+    afx_msg int  OnCreate(LPCREATESTRUCT lpCreateStruct);
+    afx_msg void OnDestroy();
+    afx_msg void OnSize(UINT nType, int cx, int cy);
+    afx_msg void OnLButtonDown(UINT flags, CPoint point);
+    afx_msg void OnLButtonUp(UINT flags, CPoint point);
+    afx_msg void OnRButtonDown(UINT flags, CPoint point);
+    afx_msg void OnRButtonUp(UINT flags, CPoint point);
+    afx_msg void OnMButtonDown(UINT flags, CPoint point);
+    afx_msg void OnMButtonUp(UINT flags, CPoint point);
+    afx_msg void OnMouseMove(UINT flags, CPoint point);
+    afx_msg void OnChar(UINT ch, UINT repcount, UINT flags);
+    afx_msg void OnTimer(UINT timer_id);
+    DECLARE_MESSAGE_MAP ()
+
+public:
+    float background_color[3];
+
+public:
+    MxGLPane();
+
+    void create(char *name);
+    inline void make_current(HDC dc) { wglMakeCurrent(dc, gl_context); }
+    inline void finish(HDC dc) { SwapBuffers(dc); }
+    void get_canvas_geometry(int *x, int *y, int *w, int *h);
+    void draw_string(int x, int y, const char *str);
+
+    MxRaster *grab_snapshot();
+    void snapshot_ppm(const char *name=NULL);
+    void snapshot_tiff(const char *name=NULL);
+
+    virtual void gl_init();
+    virtual void begin_redraw();
+    virtual void end_redraw();
+
+    void post_redraw();
+    void require_redraw();
+    virtual void redraw();
+    virtual void illustrate();
+    virtual void key(char);
+    virtual void button(int kind, int which, int x, int y);
+    virtual void size(int width, int height);
+
+    unsigned int add_timer(unsigned int id, unsigned int millisecs);
+    bool remove_timer(unsigned int id);
+    virtual void timer(unsigned int);
+};
+
+class MxGLApp : public CWinApp
+{
+
+public:
+    BOOL InitInstance(); // MFC interface
+
+
+    static MxGLApp *application;
+    static bool (*init_hook)(MxGLApp *);
+
+    int argc;
+    char **argv;
+
+    MxGLApp(bool (*h)(MxGLApp *)=NULL)
+    {
+	application = this;
+	init_hook = h;
+    }
+
+    void bind_pane(MxGLPane *, char *name);
+    const char *query_filename(const char *prompt, const char *cwd,
+			       const char *filter, const char *default_name);
+
+    virtual bool init_application() { return true; }
+};
+
+
+#else
+#ifdef MIX_USE_X11_FORMS
+#include <X11/forms.h>
+#else
+#include <forms.h>
+#endif
+
+class MxGLPane
+{
+private:
+    FL_FORM *glpane;
+    FL_OBJECT *canvas;
+    GC gc;
+
+    static MxGLPane *glpane_for_form(FL_FORM *);
+    static void glpane_for_form(FL_FORM *, MxGLPane *);
+    static MxGLPane *glpane_for_object(FL_OBJECT *);
+
+    static int cb_mapnotify(FL_OBJECT *, Window, int, int, XEvent *, void *);
+    static int cb_configure(FL_OBJECT *, Window, int, int, XEvent *, void *);
+    static int    cb_expose(FL_OBJECT *, Window, int, int, XEvent *, void *);
+    static int    cb_button(FL_OBJECT *, Window, int, int, XEvent *, void *);
+    static int       cb_key(FL_OBJECT *, Window, int, int, XEvent *, void *);
+
+public:
+    float background_color[3];
+
+public:
+    MxGLPane();
+    virtual ~MxGLPane();
+
+    void create(char *name,int *x=NULL,int *y=NULL,int *w=NULL,int *h=NULL);
+    inline void make_current()
+	{
+	    glXMakeCurrent(fl_display,
+			   fl_get_canvas_id(canvas),
+			   fl_get_glcanvas_context(canvas));
+	}
+    inline void finish() {glXSwapBuffers(fl_display,fl_get_canvas_id(canvas));}
+    void get_canvas_geometry(int *x, int *y, int *w, int *h);
+    void draw_string(int x, int y, char *str)
+	{
+	    XDrawString(fl_display, fl_get_canvas_id(canvas), gc,
+			x, y+canvas->bw, str, strlen(str));
+	}
+
+    MxRaster *grab_snapshot();
+    void snapshot_ppm(const char *name=NULL);
+    void snapshot_tiff(const char *name=NULL);
+
+    virtual void gl_init();
+    virtual void begin_redraw();
+    virtual void end_redraw();
+
+    void post_redraw();
+    void require_redraw();
+    virtual void redraw();
+    virtual void illustrate();
+    virtual void key(char);
+    virtual void button(int kind, int which, int x, int y);
+    virtual void size(int width, int height);
+    virtual void timer(unsigned int);
+};
+
+class MxGLApp
+{
+public:
+    static MxGLApp *application;
+    static bool (*init_hook)(MxGLApp *);
+
+    int argc;
+    char **argv;
+
+    MxGLApp(bool (*h)(MxGLApp *)=NULL)
+	{
+	    application = this;
+	    init_hook = h;
+	}
+
+    void bind_pane(MxGLPane *, char *name);
+    const char *query_filename(const char *prompt, const char *cwd,
+			       const char *filter, const char *default_name);
+
+    virtual bool init_application() { return true; }
+};
+
+
+#endif
+
+// MXGLPANE_INCLUDED
+#endif
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxStdModel.h
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxStdModel.h	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxStdModel.h	(revision 1097)
@@ -0,0 +1,214 @@
+#ifndef MXSTDMODEL_INCLUDED // -*- C++ -*-
+#define MXSTDMODEL_INCLUDED
+#if !defined(__GNUC__)
+#  pragma once
+#endif
+
+/************************************************************************
+
+  MxStdModel
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxStdModel.h,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+
+#include "MxBlockModel.h"
+
+typedef MxSizedDynBlock<unsigned int, 6> MxFaceList;
+typedef MxSizedDynBlock<unsigned int, 6> MxVertexList;
+
+class MxPairContraction : public MxEQ
+{
+public:
+    MxPairContraction() { }
+    MxPairContraction(const MxPairContraction& c) { *this = c; }
+
+    MxPairContraction& operator=(const MxPairContraction& c);
+
+    MxVertexID v1, v2;
+    float dv1[3], dv2[3];  // dv2 is not really necessary
+
+    uint delta_pivot;
+    MxFaceList delta_faces;
+    MxFaceList dead_faces;
+};
+
+class MxFaceContraction : public MxEQ
+{
+public:
+
+    MxFaceID f;
+    float dv1[3], dv2[3], dv3[3];
+
+    MxFaceList delta_faces;
+    MxFaceList dead_faces;
+};
+
+typedef MxPairContraction MxPairExpansion;
+
+// Masks for internal tag bits
+#define MX_VALID_FLAG 0x01
+#define MX_PROXY_FLAG 0x02
+#define MX_TOUCHED_FLAG 0x04
+
+class MxStdModel : public MxBlockModel
+{
+private:
+    struct vertex_data : public MxEQ {
+        unsigned char mark, tag;             // Internal tag bits
+        unsigned char user_mark, user_tag;   // External tag bits
+    };
+    struct face_data : public MxEQ {
+        unsigned char mark, tag;             // Internal tag bits
+        unsigned char user_mark, user_tag;   // External tag bits
+    };
+
+    MxDynBlock<vertex_data> v_data;
+    MxDynBlock<face_data> f_data;
+    MxDynBlock<MxFaceList *> face_links;
+
+protected:
+
+    //
+    // Accessors for internal tag and mark bits
+    uint v_check_tag(MxVertexID i, uint tag) const {return v_data(i).tag&tag;}
+    void v_set_tag(MxVertexID i, uint tag) { v_data(i).tag |= tag; }
+    void v_unset_tag(MxVertexID i, uint tag) { v_data(i).tag &= ~tag; }
+    unsigned char vmark(MxVertexID i) const { return v_data(i).mark; }
+    void vmark(MxVertexID i, unsigned char m) { v_data(i).mark = m; }
+
+    uint f_check_tag(MxFaceID i, uint tag) const { return f_data(i).tag&tag; }
+    void f_set_tag(MxFaceID i, uint tag) { f_data(i).tag |= tag; }
+    void f_unset_tag(MxFaceID i, uint tag) { f_data(i).tag &= ~tag; }
+    unsigned char fmark(MxFaceID i) const { return f_data(i).mark; }
+    void fmark(MxFaceID i, unsigned char m) { f_data(i).mark = m; }
+
+protected:
+    MxVertexID alloc_vertex(float, float, float);
+    void free_vertex(MxVertexID);
+    void free_face(MxFaceID);
+    MxFaceID alloc_face(MxVertexID, MxVertexID, MxVertexID);
+    void init_face(MxFaceID);
+
+public:
+    MxStdModel(unsigned int nvert, unsigned int nface)
+	: MxBlockModel(nvert,nface),
+	  v_data(nvert), f_data(nface), face_links(nvert)
+	{
+	}
+    virtual ~MxStdModel();
+
+    ////////////////////////////////////////////////////////////////////////
+    //  Tagging and marking
+    //
+    uint vertex_is_valid(MxVertexID i) const
+	{ return v_check_tag(i,MX_VALID_FLAG); }
+    void vertex_mark_valid(MxVertexID i) { v_set_tag(i,MX_VALID_FLAG); }
+    void vertex_mark_invalid(MxVertexID i) { v_unset_tag(i,MX_VALID_FLAG); }
+
+    uint face_is_valid(MxFaceID i) const {return f_check_tag(i,MX_VALID_FLAG);}
+    void face_mark_valid(MxFaceID i) { f_set_tag(i,MX_VALID_FLAG); }
+    void face_mark_invalid(MxFaceID i) { f_unset_tag(i,MX_VALID_FLAG); }
+
+    uint vertex_is_proxy(MxVertexID i) const
+	{ return v_check_tag(i,MX_PROXY_FLAG); }
+    void vertex_mark_proxy(MxVertexID i) { v_set_tag(i,MX_PROXY_FLAG); }
+    void vertex_mark_nonproxy(MxVertexID i) { v_unset_tag(i,MX_PROXY_FLAG); }
+
+    //
+    // Accessors for external tag and mark bits
+    uint vertex_check_tag(MxVertexID i, uint tag) const
+	{ return v_data(i).user_tag&tag; }
+    void vertex_set_tag(MxVertexID i, uint tag) { v_data(i).user_tag|=tag; }
+    void vertex_unset_tag(MxVertexID i, uint tag) {v_data(i).user_tag&= ~tag;}
+    unsigned char vertex_mark(MxVertexID i) { return v_data(i).user_mark; }
+    void vertex_mark(MxVertexID i, unsigned char m) { v_data(i).user_mark=m; }
+
+    uint face_check_tag(MxFaceID i, uint tag) const
+	{ return f_data(i).user_tag&tag; }
+    void face_set_tag(MxFaceID i, uint tag) { f_data(i).user_tag|=tag; }
+    void face_unset_tag(MxFaceID i, uint tag) {f_data(i).user_tag&= ~tag;}
+    unsigned char face_mark(MxFaceID i) { return f_data(i).user_mark; }
+    void face_mark(MxFaceID i, unsigned char m) { f_data(i).user_mark = m; }
+
+
+    ////////////////////////////////////////////////////////////////////////
+    //  Vertex proxy management and proxy-aware accessors
+    //
+    MxVertexID add_proxy_vertex(MxVertexID);
+    MxVertexID& vertex_proxy_parent(MxVertexID);
+    MxVertexID resolve_proxies(MxVertexID v);
+    float *vertex_position(MxVertexID v);
+
+
+    ////////////////////////////////////////////////////////////////////////
+    //  Neighborhood collection and management
+    //
+    void mark_neighborhood(MxVertexID, unsigned short mark=0);
+    void collect_unmarked_neighbors(MxVertexID, MxFaceList& faces);
+    void mark_neighborhood_delta(MxVertexID, short delta);
+    void partition_marked_neighbors(MxVertexID, unsigned short pivot,
+				    MxFaceList& below, MxFaceList& above);
+
+    void mark_corners(const MxFaceList& faces, unsigned short mark=0);
+    void collect_unmarked_corners(const MxFaceList& faces,MxVertexList& verts);
+
+    void collect_edge_neighbors(MxVertexID, MxVertexID, MxFaceList&);
+    void collect_vertex_star(MxVertexID v, MxVertexList& verts);
+
+    MxFaceList& neighbors(MxVertexID v) { return *face_links(v); }
+    const MxFaceList& neighbors(MxVertexID v) const { return *face_links(v); }
+
+    void compute_vertex_normal(MxVertexID v, float *);
+    void synthesize_normals();
+
+    ////////////////////////////////////////////////////////////////////////
+    // Primitive transformation operations
+    //
+    void remap_vertex(MxVertexID from, MxVertexID to);
+    MxVertexID split_edge(MxVertexID v1,MxVertexID v2,float x,float y,float z);
+    MxVertexID split_edge(MxVertexID v1, MxVertexID v2);
+
+    void flip_edge(MxVertexID v1, MxVertexID v2);
+
+    // split_face3
+    void split_face4(MxFaceID f, MxVertexID *newverts=NULL);
+
+    void unlink_face(MxFaceID f);
+
+    ////////////////////////////////////////////////////////////////////////
+    // Contraction and related operations
+    //
+    void compact_vertices();
+    void remove_degeneracy(MxFaceList&);
+
+    // Pair contraction interface
+    void compute_contraction(MxVertexID, MxVertexID,
+			     MxPairContraction *, const float *vnew=NULL);
+    void apply_contraction(const MxPairContraction&);
+    void apply_expansion(const MxPairExpansion&);
+    void contract(MxVertexID v1, MxVertexID v2,
+		  const float *, MxPairContraction *);
+
+    // Triple contraction interface
+    void compute_contraction(MxFaceID, MxFaceContraction *);
+    void contract(MxVertexID v1, MxVertexID v2, MxVertexID v3,
+		  const float *vnew, MxFaceList& changed);
+
+    // Generalized contraction interface
+    void contract(MxVertexID v1, const MxVertexList& rest,
+		  const float *vnew, MxFaceList& changed);
+};
+
+
+extern void mx_render_model(MxStdModel&);
+extern void mx_draw_mesh(MxStdModel&, double *color=NULL);
+extern void mx_draw_wireframe(MxStdModel&, double *color=NULL);
+extern void mx_draw_boundaries(MxStdModel&);
+extern void mx_draw_pointcloud(MxStdModel&);
+
+// MXSTDMODEL_INCLUDED
+#endif
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxArcball.cxx
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxArcball.cxx	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxArcball.cxx	(revision 1097)
@@ -0,0 +1,772 @@
+/************************************************************************
+
+  Arcball rotation control -- The Arcball is a handy manipulator for
+  spinning objects in 3D.  This particular controller also supports
+  some limited camera and light movements as well.
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  The core arcball code was originally published in:
+
+	"Arcball Rotation Control"
+	by Ken Shoemake <shoemake@graphics.cis.upenn.edu>
+	in "Graphics Gems IV", Academic Press, 1994.
+
+  and was placed in the public domain.
+
+  Originally written for IRIS GL, the OpenGL code is based on the
+  modifications of Victor Ng-Thow-Hing <victorng@dgp.toronto.edu>.
+  Over time, I've made various modifications including:
+
+	- Porting from ANSI C to C++
+	- Adding some improvements from Sebastian Grassia <spiff@cs.cmu.edu>
+	- Nominal integration with the MixKit library
+
+  $Id: MxArcball.cxx,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "stdmix.h"
+#include "MxArcball.h"
+
+enum AxisSet {NoAxes, CameraAxes, BodyAxes, OtherAxes, NSets};
+enum BallType { ArcBall, TrackBall };
+typedef Mat4 HMatrix;
+
+
+
+
+/* ***** BallAux.c ***** */
+
+
+Quat qOne(0,0,0,1);
+
+/* Return quaternion product qL * qR.  Note: order is important!
+ * To combine rotations, use the product Mul(qSecond, qFirst),
+ * which gives the effect of rotating by qFirst then qSecond. */
+Quat Qt_Mul(Quat& qL, Quat& qR)
+{
+    Quat qq;
+    qq[W] = qL[W]*qR[W] - qL[X]*qR[X] - qL[Y]*qR[Y] - qL[Z]*qR[Z];
+    qq[X] = qL[W]*qR[X] + qL[X]*qR[W] + qL[Y]*qR[Z] - qL[Z]*qR[Y];
+    qq[Y] = qL[W]*qR[Y] + qL[Y]*qR[W] + qL[Z]*qR[X] - qL[X]*qR[Z];
+    qq[Z] = qL[W]*qR[Z] + qL[Z]*qR[W] + qL[X]*qR[Y] - qL[Y]*qR[X];
+    return (qq);
+}
+
+
+/* Construct rotation matrix from (possibly non-unit) quaternion.
+ * Assumes matrix is used to multiply column vector on the left:
+ * vnew = mat vold.  Works correctly for right-handed coordinate system
+ * and right-handed rotations. */
+HMatrix *Qt_ToMatrix(const Quat& q, HMatrix& out)
+{
+    double Nq = norm2(q);
+    double s = (Nq > 0.0) ? (2.0 / Nq) : 0.0;
+
+    double xs = q[X]*s,  ys = q[Y]*s,  zs = q[Z]*s;
+    double wx = q[W]*xs, wy = q[W]*ys, wz = q[W]*zs;
+    double xx = q[X]*xs, xy = q[X]*ys, xz = q[X]*zs;
+    double yy = q[Y]*ys, yz = q[Y]*zs, zz = q[Z]*zs;
+
+    out(X,X) = 1.0 - (yy + zz); out(Y,X) = xy + wz; out(Z,X) = xz - wy;
+    out(X,Y) = xy - wz; out(Y,Y) = 1.0 - (xx + zz); out(Z,Y) = yz + wx;
+    out(X,Z) = xz + wy; out(Y,Z) = yz - wx; out(Z,Z) = 1.0 - (xx + yy);
+    out(X,W) = out(Y,W) = out(Z,W) = out(W,X) = out(W,Y) = out(W,Z) = 0.0;
+    out(W,W) = 1.0;
+    return ((HMatrix *)&out);
+}
+
+/* Return conjugate of quaternion. */
+Quat Qt_Conj(Quat& q)
+{
+    Quat qq;
+    qq[X] = -q[X]; qq[Y] = -q[Y]; qq[Z] = -q[Z]; qq[W] = q[W];
+    return (qq);
+}
+
+/* Return vector formed from components */
+inline Vec4 V3_(float x, float y, float z)
+{
+    return Vec4(x, y, z, 0);
+}
+
+/* Return norm of v, defined as sum of squares of components */
+inline double V3_Norm(const Vec4& v)
+{
+    return ( v[X]*v[X] + v[Y]*v[Y] + v[Z]*v[Z] );
+}
+
+/* Return unit magnitude vector in direction of v */
+Vec4 V3_Unit(const Vec4& v)
+{
+    static Vec4 u(0, 0, 0, 0);
+    float vlen = sqrt(V3_Norm(v));
+    if (vlen != 0.0) {
+	u[X] = v[X]/vlen; u[Y] = v[Y]/vlen; u[Z] = v[Z]/vlen;
+    }
+    return (u);
+}
+
+/* Return version of v scaled by s */
+inline Vec4 V3_Scale(const Vec4& v, float s)
+{
+    return Vec4(s*v[X], s*v[Y], s*v[Z], v[W]);
+}
+
+/* Return negative of v */
+inline Vec4 V3_Negate(const Vec4& v)
+{
+    return Vec4(-v[X], -v[Y], -v[Z], 0);
+}
+
+/* Return sum of v1 and v2 */
+inline Vec4 V3_Add(const Vec4& v1, const Vec4& v2)
+{
+    return Vec4(v1[X]+v2[X], v1[Y]+v2[Y], v1[Z]+v2[Z], 0);
+}
+
+/* Return difference of v1 minus v2 */
+inline Vec4 V3_Sub(const Vec4& v1, const Vec4& v2)
+{
+    return Vec4(v1[X]-v2[X], v1[Y]-v2[Y], v1[Z]-v2[Z], 0);
+}
+
+/* Halve arc between unit vectors v0 and v1. */
+Vec4 V3_Bisect(const Vec4& v0, const Vec4& v1)
+{
+    Vec4 v(0, 0, 0, 0);
+    v = V3_Add(v0, v1);
+
+    float Nv = V3_Norm(v);
+    if (Nv < 1.0e-5) {
+	v = V3_(0, 0, 1);
+    } else {
+	v = V3_Scale(v, 1/sqrt(Nv));
+    }
+    return (v);
+}
+
+/* Return dot product of v1 and v2 */
+double V3_Dot(const Vec4& v1, const Vec4& v2)
+{
+    return (v1[X]*v2[X] + v1[Y]*v2[Y] + v1[Z]*v2[Z]);
+}
+
+
+/* Return cross product, v1 x v2 */
+inline Vec4 V3_Cross(const Vec4& v1, const Vec4& v2)
+{
+    return Vec4(v1[Y]*v2[Z]-v1[Z]*v2[Y],
+		v1[Z]*v2[X]-v1[X]*v2[Z],
+		v1[X]*v2[Y]-v1[Y]*v2[X],
+		0);
+}
+
+
+
+
+/* ***** Ball.h ***** */
+
+typedef Vec4 *ConstraintSet;
+struct BallData {
+    Vec4 center;
+    double radius, aspect;
+    Quat qNow, qDown, qDrag;
+    Vec4 vNow, vDown, vFrom, vTo, vrFrom, vrTo;
+    HMatrix mNow, mDown;
+    int showResult, dragging;
+    ConstraintSet sets[NSets];
+    int setSizes[NSets];
+    AxisSet axisSet;
+    int axisIndex;
+    BallType ballType;
+};
+
+/* Public routines */
+extern BallData *Ball_Alloc();
+extern void Ball_Free(BallData *);
+extern void Ball_Init(BallData *ball, double aspect);
+extern void Ball_Place(BallData *ball, Vec4 center, double radius
+		       /*, Quat orient*/);
+extern void Ball_Mouse(BallData *ball, Vec4 vNow);
+extern void Ball_UseSet(BallData *ball, AxisSet axisSet);
+extern void Ball_ShowResult(BallData *ball);
+extern void Ball_HideResult(BallData *ball);
+extern void Ball_Update(BallData *ball, int al);
+extern void Ball_Value(BallData *ball, HMatrix& mNow);
+extern void Ball_BeginDrag(BallData *ball);
+extern void Ball_EndDrag(BallData *ball);
+extern void Ball_Draw(BallData *ball, int drawBall,
+		      int drawConstraints, int drawArc);
+extern int Ball_MouseOutsideSphere(BallData *ball, Vec4 vMouse);
+extern void Ball_SetBallType(BallData *ball, BallType bt);
+/* Private routines */
+void DrawAnyArc(Vec4 vFrom, Vec4 vTo);
+void DrawHalfArc(Vec4 n);
+void Ball_DrawConstraints(BallData *ball);
+void Ball_DrawDragArc(BallData *ball);
+void Ball_DrawResultArc(BallData *ball);
+
+
+
+
+/* ***** BallMath.c ***** */
+
+/* Convert window coordinates to sphere coordinates. */
+Vec4 MouseOnSphere(Vec4 mouse, Vec4 ballCenter, double ballRadius)
+{
+    Vec4 ballMouse;
+    register double mag;
+    ballMouse[X] = (mouse[X] - ballCenter[X]) / ballRadius;
+    ballMouse[Y] = (mouse[Y] - ballCenter[Y]) / ballRadius;
+    mag = ballMouse[X]*ballMouse[X] + ballMouse[Y]*ballMouse[Y];
+    if (mag > 1.0) {
+	register double scale = 1.0/sqrt(mag);
+	ballMouse[X] *= scale; ballMouse[Y] *= scale;
+	ballMouse[Z] = 0.0;
+    } else {
+	ballMouse[Z] = sqrt(1 - mag);
+    }
+    ballMouse[W] = 0.0;
+    return (ballMouse);
+}
+
+/* Construct a unit quaternion from two points on unit sphere */
+Quat Qt_FromBallPoints(Vec4 from, Vec4 to, BallType bt)
+{
+    Quat qu;
+    qu[X] = from[Y]*to[Z] - from[Z]*to[Y];
+    qu[Y] = from[Z]*to[X] - from[X]*to[Z];
+    qu[Z] = from[X]*to[Y] - from[Y]*to[X];
+
+    if (bt == ArcBall){
+	qu[W] = from[X]*to[X] + from[Y]*to[Y] + from[Z]*to[Z];
+    }
+    else {
+	float  a, s, mag;
+
+	a = .5*acos(from[X]*to[X] + from[Y]*to[Y] + from[Z]*to[Z]);
+	mag = sqrt(qu[X]*qu[X] + qu[Y]*qu[Y] + qu[Z]*qu[Z]);
+	qu[W] = cos(a); s = sin(a);
+	if (s != 0)
+	  s /= mag;
+	qu[X] *= s;  qu[Y] *= s; qu[Z] *= s;
+    }
+
+    return (qu);
+}
+
+/* Convert a unit quaternion to two points on unit sphere */
+void Qt_ToBallPoints(Quat q, Vec4 *arcFrom, Vec4 *arcTo)
+{
+    double s;
+    s = sqrt(q[X]*q[X] + q[Y]*q[Y]);
+    if (s == 0.0) {
+	*arcFrom = V3_(0.0, 1.0, 0.0);
+    } else {
+	*arcFrom = V3_(-q[Y]/s, q[X]/s, 0.0);
+    }
+    (*arcTo)[X] = q[W]*(*arcFrom)[X] - q[Z]*(*arcFrom)[Y];
+    (*arcTo)[Y] = q[W]*(*arcFrom)[Y] + q[Z]*(*arcFrom)[X];
+    (*arcTo)[Z] = q[X]*(*arcFrom)[Y] - q[Y]*(*arcFrom)[X];
+    if (q[W] < 0.0) *arcFrom = V3_(-(*arcFrom)[X], -(*arcFrom)[Y], 0.0);
+}
+
+/* Force sphere point to be perpendicular to axis. */
+Vec4 ConstrainToAxis(Vec4& loose, Vec4& axis)
+{
+    Vec4 onPlane = V3_Sub(loose, V3_Scale(axis, V3_Dot(axis, loose)));
+    register float norm = V3_Norm(onPlane);
+
+    if (norm > 0.0) {
+	if (onPlane[Z] < 0.0) onPlane = V3_Negate(onPlane);
+	return ( V3_Scale(onPlane, 1/sqrt(norm)) );
+    } /* else drop through */
+    if (axis[Z] == 1) {
+	onPlane = V3_(1.0, 0.0, 0.0);
+    } else {
+	onPlane = V3_Unit(V3_(-axis[Y], axis[X], 0.0));
+    }
+    return (onPlane);
+}
+
+/* Find the index of nearest arc of axis set. */
+int NearestConstraintAxis(Vec4& loose, Vec4 *axes, int nAxes)
+{
+    Vec4 onPlane;
+    register float max, dot;
+    register int i, nearest;
+    max = -1; nearest = 0;
+    for (i=0; i<nAxes; i++) {
+	onPlane = ConstrainToAxis(loose, axes[i]);
+	dot = V3_Dot(onPlane, loose);
+	if (dot>max) {
+	    max = dot; nearest = i;
+	}
+    }
+    return (nearest);
+}
+
+
+
+
+/* ***** Ball.c ***** */
+/* Ken Shoemake, 1993 */
+/* Modified by Victor Ng, Jan. 1996 for OpenGL */
+
+
+#include "MxGLPane.h"
+
+#define FALSE 0
+#define TRUE 1
+
+#define LG_NSEGS 4
+#define NSEGS (1<<LG_NSEGS)
+#define RIMCOLOR()    glColor3f(0.0f, 1.0f, 1.0f);
+#define FARCOLOR()    glColor3f(0.8f, 0.5f, 0.0f);
+#define NEARCOLOR()   glColor3f(1.0f, 0.8f, 0.0f);
+#define DRAGCOLOR()   glColor3f(0.0f, 1.0f, 1.0f);
+#define RESCOLOR()    glColor3f(0.8f, 0.0f, 0.0f);
+
+
+
+Vec4 otherAxis(-0.48, 0.80, 0.36, 1);
+
+BallData *Ball_Alloc()
+{
+    return (BallData *)malloc( sizeof(BallData) );
+}
+
+void Ball_Free(BallData *ball)
+{
+    free(ball);
+}
+
+/* Establish reasonable initial values for controller. */
+void Ball_Init(BallData *ball, double aspect)
+{
+    ball->center = qOne;
+    ball->radius = 1.0;
+    ball->aspect = aspect;
+    ball->ballType = ArcBall;
+    ball->vDown = ball->vNow = qOne;
+    ball->qDown = ball->qNow = qOne;
+
+    ball->mNow = Mat4::I;
+    ball->mDown = Mat4::I;
+
+    ball->showResult = ball->dragging = FALSE;
+    ball->axisSet = NoAxes;
+
+    ball->sets[CameraAxes]     = (Vec4 *)&Mat4::I(0,0);  // Mat4::I.row(0)
+    ball->setSizes[CameraAxes] = 3;
+
+    ball->sets[BodyAxes] = (Vec4 *)&ball->mDown(0,0);  // mDown.row(0)
+    ball->setSizes[BodyAxes] = 3;
+
+    ball->sets[OtherAxes] = &otherAxis;
+    ball->setSizes[OtherAxes] = 1;
+}
+
+/* Set the center and size of the controller. */
+void Ball_Place(BallData *ball, Vec4 center, double radius)
+{
+    ball->center = center;
+    ball->radius = radius;
+}
+
+/* Incorporate new mouse position. */
+void Ball_Mouse(BallData *ball, Vec4 vNow)
+{
+    ball->vNow = vNow;
+}
+
+/* Choose a constraint set, or none. */
+void Ball_UseSet(BallData *ball, AxisSet axisSet)
+{
+    /* if (!ball->dragging) */
+	ball->axisSet = axisSet;
+}
+
+/* Begin drawing arc for all drags combined. */
+void Ball_ShowResult(BallData *ball)
+{
+    ball->showResult = TRUE;
+}
+
+/* Stop drawing arc for all drags combined. */
+void Ball_HideResult(BallData *ball)
+{
+    ball->showResult = FALSE;
+}
+
+/* Using vDown, vNow, dragging, and axisSet, compute rotation etc. */
+/* To use closest constraint axis, set aI to -1 */
+void Ball_Update(BallData *ball, int aI)
+{
+    int setSize = ball->setSizes[ball->axisSet];
+    Vec4 *set = (Vec4 *)(ball->sets[ball->axisSet]);
+    ball->vFrom = MouseOnSphere(ball->vDown, ball->center, ball->radius);
+    ball->vTo = MouseOnSphere(ball->vNow, ball->center, ball->radius);
+    if (ball->dragging) {
+        if (ball->axisSet!=NoAxes) {
+	    aI = (aI==-1) ? ball->axisIndex : aI;
+            ball->vFrom = ConstrainToAxis(ball->vFrom, set[aI]);
+            ball->vTo = ConstrainToAxis(ball->vTo, set[aI]);
+        }
+        ball->qDrag =Qt_FromBallPoints(ball->vFrom, ball->vTo, ball->ballType);
+        ball->qNow = Qt_Mul(ball->qDrag, ball->qDown);
+    } else {
+        if (ball->axisSet!=NoAxes) {
+            ball->axisIndex = (aI==-1) ?
+	                      NearestConstraintAxis(ball->vTo, set, setSize) :
+	                      aI;
+        }
+    }
+    Qt_ToBallPoints(ball->qDown, &ball->vrFrom, &ball->vrTo);
+    Qt_ToMatrix(Qt_Conj(ball->qNow), ball->mNow); /* Gives transpose for GL. */
+}
+
+/* Returns TRUE iff vMouse is a point off the arcball sphere */
+int Ball_MouseOutsideSphere(BallData *ball, Vec4 vMouse)
+{
+    Vec4  vTest = MouseOnSphere(vMouse, ball->center, ball->radius);
+
+    return vTest[Z] == 0.0;
+}
+
+/* Set the BallType: 'ArcBall' rotates through _twice_ the angle
+ * between the two points on the sphere, and exhibits no
+ * hysteresis. 'TrackBall' rotates through exactly the angle between
+ * the two points on the sphere, like a physical trackball, and
+ * consequently exhibits hysteresis. */
+void Ball_SetBallType(BallData *ball, BallType bt)
+{
+    ball->ballType = bt;
+}
+
+/* Return rotation matrix defined by controller use. */
+void Ball_Value(BallData *ball, HMatrix& mNow)
+{
+    mNow = ball->mNow;
+}
+
+
+/* Begin drag sequence. */
+void Ball_BeginDrag(BallData *ball)
+{
+    ball->dragging = TRUE;
+    ball->vDown = ball->vNow;
+}
+
+/* Stop drag sequence. */
+void Ball_EndDrag(BallData *ball)
+{
+    ball->dragging = FALSE;
+    ball->qDown = ball->qNow;
+
+    ball->mDown = ball->mNow;
+}
+
+/* Draw the controller with all its arcs. */
+void Ball_Draw(BallData *ball, int drawBall, int drawConstraints, int drawArc)
+{
+    GLdouble __save[16];
+    float r = ball->radius;
+    
+    glPushAttrib(GL_LIGHTING_BIT|GL_CURRENT_BIT);
+    glDisable(GL_LIGHTING);
+
+    glMatrixMode(GL_PROJECTION);
+    glGetDoublev(GL_PROJECTION_MATRIX, __save);	//  vs. glPushMatrix();
+    glLoadIdentity();
+
+    // Must use near and far clip planes at -1.0 and 1.0 or
+    // risk clipping out the circle and arcs drawn.
+    // glOrtho(-1.0,1.0,-1.0,1.0,-1.0,1.0);
+
+    if (ball->aspect > 1)
+	glOrtho(-ball->aspect, ball->aspect, -1.0, 1.0, -1.0, 1.0);
+    else
+	glOrtho(-1.0, 1.0, -1.0/ball->aspect, 1.0/ball->aspect, -1.0, 1.0);
+
+
+    glMatrixMode(GL_MODELVIEW);
+    glPushMatrix();
+    glLoadIdentity();
+    glScalef(r,r,r);
+
+    RIMCOLOR();
+    if( drawBall ) {
+	glBegin(GL_LINE_LOOP);
+	for (int i=0; i < 36; i++)
+	    glVertex3f(cos((float)i*2.0*M_PI/36.0),
+		       sin((float)i*2.0*M_PI/36.0),0.0);
+	glEnd();
+    } 
+
+    if( drawArc ) Ball_DrawResultArc(ball);
+    if( drawConstraints ) Ball_DrawConstraints(ball);
+    if( drawArc ) Ball_DrawDragArc(ball);
+
+    glPopMatrix();
+    glMatrixMode(GL_PROJECTION);
+    glLoadMatrixd(__save);	// vs. glPopMatrix();
+    glMatrixMode(GL_MODELVIEW);
+
+    glPopAttrib();
+}
+
+/* Draw an arc defined by its ends. */
+void DrawAnyArc(Vec4 vFrom, Vec4 vTo)
+{
+    int i;
+    Vec4 pts[NSEGS+1];
+    double dot;
+    pts[0] = vFrom;
+    pts[1] = pts[NSEGS] = vTo;
+    for (i=0; i<LG_NSEGS; i++) pts[1] = V3_Bisect(pts[0], pts[1]);
+    dot = 2.0*V3_Dot(pts[0], pts[1]);
+    for (i=2; i<NSEGS; i++) {
+	pts[i] = V3_Sub(V3_Scale(pts[i-1], dot), pts[i-2]);
+    }
+    glBegin(GL_LINE_STRIP);
+    for (i=0; i<=NSEGS; i++)
+	glVertex3fv((float *)&pts[i]);
+    glEnd();
+}
+
+/* Draw the arc of a semi-circle defined by its axis. */
+void DrawHalfArc(Vec4 n)
+{
+    Vec4 p, m;
+    p[Z] = 0;
+    if (n[Z] != 1.0) {
+	p[X] = n[Y]; p[Y] = -n[X];
+	p = V3_Unit(p);
+    } else {
+	p[X] = 0; p[Y] = 1;
+    }
+    m = V3_Cross(p, n);
+    DrawAnyArc(p, m);
+    DrawAnyArc(m, V3_Negate(p));
+}
+
+/* Draw all constraint arcs. */
+void Ball_DrawConstraints(BallData *ball)
+{
+    ConstraintSet set;
+    Vec4 axis;
+    int i, axisI, setSize = ball->setSizes[ball->axisSet];
+    if (ball->axisSet==NoAxes) return;
+    set = ball->sets[ball->axisSet];
+    for (axisI=0; axisI<setSize; axisI++) {
+	if (ball->axisIndex!=axisI) {
+	    if (ball->dragging) continue;
+	    FARCOLOR();
+	} else NEARCOLOR();
+	axis = *(Vec4 *)&set[4*axisI];
+	if (axis[Z]==1.0) {
+	    glBegin(GL_LINE_LOOP);
+	    for (i=0; i < 36; i++) 
+		glVertex3f(cos((float)i*2.0*M_PI/36.0),sin((float)i*M_PI/36.0),0.0);
+	    glEnd();
+	} else {
+	    DrawHalfArc(axis);
+	}
+    }
+}
+
+/* Draw "rubber band" arc during dragging. */
+void Ball_DrawDragArc(BallData *ball)
+{
+    DRAGCOLOR();
+    if (ball->dragging) DrawAnyArc(ball->vFrom, ball->vTo);
+}
+
+/* Draw arc for result of all drags. */
+void Ball_DrawResultArc(BallData *ball)
+{
+    RESCOLOR();
+    if (ball->showResult) DrawAnyArc(ball->vrFrom, ball->vrTo);
+}
+
+
+
+
+MxArcball::~MxArcball()
+{
+    if( ball ) Ball_Free(ball);
+}
+
+void MxArcball::init(const MxBounds& bounds, float aspect)
+{
+    if( ball ) Ball_Free(ball);  // Don't try to reuse old Balls
+    ball = Ball_Alloc();
+    Ball_Init(ball, aspect);
+
+    Ball_UseSet(ball, NoAxes);
+    Ball_SetBallType(ball, ArcBall);
+
+    center[X] = bounds.center[X];
+    center[Y] = bounds.center[Y];
+    center[Z] = bounds.center[Z];
+    center[W] = 1;
+
+    radius = bounds.radius;
+    cam[X] = cam[Y] = cam[Z] = 0.0f;
+    dragging = NoDrag;
+
+    Ball_Place(ball, qOne, 0.9 /* 0.75 */);
+}
+
+bool MxArcball::mouse_down(int button, int x, int y, int kind)
+{
+    mousex = startx = x;
+    mousey = starty = y;
+
+    if( kind&MX_SHIFTKEY )
+    {
+	dragging = LightAdjust;
+    }
+    else if( button == 1 )
+    {
+        int width, height;
+        glGetViewport(NULL, NULL, &width, &height);
+
+        vNow[X] = 2.0*startx/(float)width-1.0;
+        vNow[Y] = -2.0*starty/(float)height+1.0;
+
+        Ball_Mouse(ball, vNow);
+
+        Ball_BeginDrag(ball);
+
+        dragging = Spin;
+    }
+    else if( button == 2 )
+    {
+        dragging = Dolly;
+    }
+    else if( button == 3 )
+    {
+        dragging = Zoom;
+    }
+
+    return true;
+}
+
+bool MxArcball::mouse_up(int /*button*/, int /*x*/, int /*y*/, int /*kind*/)
+{
+    startx = mousex = 0;
+    starty = mousey = 0;
+
+    if( dragging == Spin )
+        Ball_EndDrag(ball);
+
+    dragging = NoDrag;
+
+    return false;
+}
+
+bool MxArcball::motion(int x, int y)
+{
+    if( !dragging )
+        return false;
+
+    if( dragging == Spin )
+    {
+        mousex = x;
+        mousey = y;
+
+        int width, height;
+        glGetViewport(NULL, NULL, &width, &height);
+
+        vNow[X] = 2.0*mousex/(float)width-1.0;
+        vNow[Y] = -2.0*mousey/(float)height+1.0;
+
+        Ball_Mouse(ball, vNow);
+    }
+    else if( dragging == Dolly )
+    {
+	int width, height;
+	glGetViewport(NULL, NULL, &width, &height);
+
+	cam[X] += radius * (float)(x - mousex) / (float)width;
+	cam[Y] += radius * (float)(mousey - y) / (float)height;
+
+        mousex = x;
+        mousey = y;
+    }
+    else if( dragging == Zoom )
+    {
+        cam[Z] += 0.02*radius*(float)(y - mousey);
+        mousey = y;
+    }
+    else if( dragging == LightAdjust )
+    {
+	int width, height;
+	glGetViewport(NULL, NULL, &width, &height);
+
+	float light_pos[4];
+	glGetLightfv(GL_LIGHT0, GL_POSITION, light_pos);
+	light_pos[X] += (x - mousex) / (float)width;
+	light_pos[Y] += (mousey - y) / (float)height;
+	glLightfv(GL_LIGHT0, GL_POSITION, light_pos);
+	mousex = x;
+	mousey = y;
+    }
+
+    return true;
+}
+
+void MxArcball::apply()
+{
+    Ball_Update(ball, -1);
+
+    GLint last_mode; glGetIntegerv(GL_MATRIX_MODE, &last_mode);
+
+    Ball_Draw(ball, 0, 0, 0);
+
+
+    glMatrixMode(GL_PROJECTION);
+    glGetDoublev(GL_PROJECTION_MATRIX, __proj_save); // vs. glPushMatrix();
+    glTranslatef(cam[X], cam[Y], cam[Z]);
+
+
+    glMatrixMode(GL_MODELVIEW);
+    glPushMatrix();
+
+         // glLoadIdentity();
+         // panning translation
+         // gluLookAt()??
+
+    HMatrix mNow;
+    Ball_Value(ball, mNow);
+
+    glTranslatef(center[X], center[Y], center[Z]);
+    glMultMatrixd((double *)&mNow);
+    glTranslatef(-center[X], -center[Y], -center[Z]);
+
+    glMatrixMode((GLenum)last_mode);
+}
+
+void MxArcball::unapply()
+{
+    GLint last_mode; glGetIntegerv(GL_MATRIX_MODE, &last_mode);
+
+    glMatrixMode(GL_PROJECTION);
+    glLoadMatrixd(__proj_save);	// vs. glPopMatrix();
+
+    glMatrixMode(GL_MODELVIEW);
+    glPopMatrix();
+
+    glMatrixMode((GLenum)last_mode);
+}
+
+void MxArcball::draw()
+{
+    Ball_Draw(ball, true, true, true);
+}
+
+double *MxArcball::get_qnow() { return ball->qNow; }
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxQMetric.cxx
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxQMetric.cxx	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxQMetric.cxx	(revision 1097)
@@ -0,0 +1,104 @@
+/************************************************************************
+
+  n-D Quadric Error Metrics
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxQMetric.cxx,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "stdmix.h"
+#include "MxQMetric.h"
+
+static
+void symmetric_subfrom(MxMatrix& A, const MxVector& a, const MxVector& b)
+{
+    for(int i=0; i<A.dim(); i++)  for(int j=0; j<A.dim(); j++)
+	A(i,j) -= a[i]*b[j];
+}
+
+MxQuadric::MxQuadric(const MxVector& p1,const MxVector& p2,const MxVector& p3,
+		     double area)
+    : A(p1.dim()), b(p1.dim())
+{
+    AssertBound( p1.dim()==p2.dim() && p1.dim()==p3.dim() );
+
+    MxVector e1=p2; e1-=p1; unitize(e1); // e1 = p2-p1; unitize
+    MxVector e2=p3; e2-=p1;              // e2 = p3-p1
+    MxVector t = e1;
+    t*=e1*e2; e2-=t; unitize(e2);        // e2 = p3-p1-e1*(e1*(p3-p1)); unitize
+
+    double p1e1 = p1*e1;
+    double p1e2 = p1*e2;
+
+    mxm_identity(A, A.dim());
+    symmetric_subfrom(A, e1,e1);
+    symmetric_subfrom(A, e2,e2);
+
+    // b = e1*p1e1 + e2*p1e2 - p1
+    b=e1; b*=p1e1; t=e2; t*=p1e2; b += t; b -= p1;
+
+    c = p1*p1 - p1e1*p1e1 - p1e2*p1e2;
+
+    r = area;
+}
+
+MxQuadric::MxQuadric(const MxQuadric3& Q3, unsigned int N)
+    : A(N), b(N)
+{
+    uint i, j;
+
+    clear();
+
+    Mat3 A3 = Q3.tensor();
+    Vec3 b3 = Q3.vector();
+
+    for(i=0; i<3; i++)
+    {
+	for(j=0; j<3; j++)
+	    A(i,j) = A3(i,j);
+
+	b[i] = b3[i];
+    }
+
+    c = Q3.offset();
+    r = Q3.area();
+}
+
+MxMatrix& MxQuadric::homogeneous(MxMatrix& H) const
+{
+    AssertBound( H.dim() == A.dim()+1 );
+
+    uint i, j;
+
+    for(i=0; i<A.dim(); i++)  for(j=0; j<A.dim(); i++)
+	H(i,j) = A(i,j);
+
+    for(i=0; i<b.dim(); i++)
+	H(i, b.dim()) = H(b.dim(), i) = b[i];
+
+    H(b.dim(), b.dim()) = c;
+
+    return H;
+}
+
+double MxQuadric::evaluate(const MxVector& v) const
+{
+    AssertBound( v.dim() == b.dim() );
+    return v*(A*v) + 2*(b*v) + c;
+}
+
+bool MxQuadric::optimize(MxVector& v) const
+{
+    MxMatrix Ainv(A.dim());
+
+    double det = A.invert(Ainv);
+    if( FEQ(det, 0.0, 1e-12) )
+	return false;
+
+    v = (Ainv * b);
+    mxv_neg(v, v.dim());
+
+    return true;
+}
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/mixio.h
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/mixio.h	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/mixio.h	(revision 1097)
@@ -0,0 +1,42 @@
+#ifndef MIXIO_INCLUDED // -*- C++ -*-
+#define MIXIO_INCLUDED
+#if !defined(__GNUC__)
+#  pragma once
+#endif
+
+/************************************************************************
+
+  Standard IO header for MixKit programs.  It deals with things like
+  the unpleasantness of multiple IO packages in VC++.
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: mixio.h,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#if defined(MIX_ANSI_IOSTREAMS)
+#include <fstream>
+
+#else
+#include <fstream.h>
+
+#endif
+
+
+
+#ifdef WIN32
+//
+// Win32 provides support for POSIX low-level I/O routines.
+// However, for some reason Microsoft felt compelled to prefix the
+// function names with underscores.
+//
+
+#include <io.h>
+
+inline int dup(int fd) { return _dup(fd); }
+
+#endif
+
+// MIXIO_INCLUDED
+#endif
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxGLUtils.h
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxGLUtils.h	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxGLUtils.h	(revision 1097)
@@ -0,0 +1,74 @@
+#ifndef MXGLUTILS_INCLUDED // -*- C++ -*-
+#define MXGLUTILS_INCLUDED
+#if !defined(__GNUC__)
+#  pragma once
+#endif
+
+/************************************************************************
+
+  MxGLUtils
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxGLUtils.h,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+#include "MxBlock.h"
+#include "MxGL.h"
+#include "MxRaster.h"
+
+
+extern void mxgl_default_texinit(MxRaster *tex, bool will_draw_texture=true);
+extern void mxgl_default_init();
+extern GLenum mxgl_matrix_for_mode(GLenum mode);
+
+extern void mxgl_pick_begin(int x, int y, double window);
+extern uint mxgl_pick_complete();
+
+
+class MxGLPicker
+{
+private:
+    MxBlock<GLuint> buffer;
+
+public:
+    MxGLPicker(int x, int y, double window);
+    uint complete();
+};
+
+
+//
+// The OpenGL projection matrix stack is often very small.  For instance,
+// it's only 2 levels deep on an Impact.  So we often wind up having to
+// manage that stack manually.  And that's exactly what this little
+// class is for.
+//
+class MxGLMatrixCache
+{
+private:
+    GLdouble saved_mat[16];
+    GLenum mode, saved_mode;
+
+    void save_mode() { glGetIntegerv(GL_MATRIX_MODE, (GLint *)&saved_mode); }
+    void restore_mode() { glMatrixMode(saved_mode); }
+
+public:
+    MxGLMatrixCache(GLenum m=GL_PROJECTION) { mode=m; }
+
+    void save_matrix()
+	{ glGetDoublev(mxgl_matrix_for_mode(mode), saved_mat); }
+
+    void restore_matrix()
+	{
+	    save_mode();
+	    glMatrixMode(mode);  glLoadMatrixd(saved_mat);
+	    restore_mode();
+	}
+};
+
+
+
+
+// MXGLUTILS_INCLUDED
+#endif
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/VspOspTree.cpp
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/VspOspTree.cpp	(revision 1093)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/VspOspTree.cpp	(revision 1097)
@@ -3552,45 +3552,3 @@
 }
 
-
-
-/********************************************************/
-/*             SplitHeap implementation                 */
-/********************************************************/
-
-
-SplitHeap::SplitHeap():mRoot(NULL)
-{}
-
-void SplitHeap::Push(SplitCandidate *candidate)
-{
-	InsertTail(candidate);
-
-	// Swap until heap constaints fullfilled
-	while (HeapViolated(candidate))
-	{
-		Swap(candidate, candidate->mParent);
-	}
-}
-
-
-void SplitHeap::InsertTail(SplitCandidate *candidate)
-{
-}
-
-
-bool SplitHeap::HeapViolated(SplitCandidate *candidate)
-{
-	return true;
-}
-	
-SplitCandidate *SplitHeap::Pop()
-{
-
-	return mRoot;
-}
-
-void SplitHeap::Remove(SplitCandidate *candidate)
-{
-}
-
-}
+}
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/VspOspTree.h
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/VspOspTree.h	(revision 1093)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/VspOspTree.h	(revision 1097)
@@ -10,4 +10,5 @@
 #include "RayInfo.h"
 #include "gzstream.h"
+#include "mixkit/MxHeap.h"
 
 
@@ -47,5 +48,5 @@
 /** Candidate for a view space / object space split.
 */
-class SplitCandidate
+class SplitCandidate: public MxHeapable
 {  
 public:
@@ -1720,23 +1721,4 @@
 };
 
-/** Implements a heap for split candidates.
-*/
-class SplitHeap
-{
-	SplitHeap();
-
-	void Push(SplitCandidate *candidate);
-    
-	SplitCandidate *Pop();
-
-	void Remove(SplitCandidate *candidate);
-
-	void InsertTail(SplitCandidate *candidate);
-    
-	bool HeapViolated(SplitCandidate *candidate);
-
-	SplitCandidate *mRoot;
-};
-
 }
 
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/MxHeap.cxx
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/MxHeap.cxx	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/MxHeap.cxx	(revision 1097)
@@ -0,0 +1,135 @@
+/************************************************************************
+
+  Heap data structure
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxHeap.cxx,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+//#include "stdmix.h"
+#include "MxHeap.h"
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// Internal functions for manipulating the heap
+
+inline void MxHeap::place(MxHeapable *x, unsigned int i)
+{
+    ref(i) = x;
+    x->set_heap_pos(i);
+}
+
+void MxHeap::swap(unsigned int i, unsigned int j)
+{
+    MxHeapable *tmp = ref(i);
+
+    place(ref(j), i);
+    place(tmp, j);
+}
+
+void MxHeap::upheap(unsigned int i)
+{
+    MxHeapable *moving = ref(i);
+    uint index = i;
+    uint p = parent(i);
+
+    while( index>0 && moving->heap_key() > ref(p)->heap_key() )
+    {
+	place(ref(p), index);
+	index = p;
+	p = parent(p);
+    }
+
+    if( index != i )
+	place(moving, index);
+}
+
+void MxHeap::downheap(unsigned int i)
+{
+    MxHeapable *moving = ref(i);
+    uint index = i;
+    uint l = left(i);
+    uint r = right(i);
+    uint largest;
+
+    while( l<length() )
+    {
+	if( r<length() && ref(l)->heap_key() < ref(r)->heap_key() )
+	    largest = r;
+	else 
+	    largest = l;
+
+	if( moving->heap_key() < ref(largest)->heap_key() )
+	{
+	    place(ref(largest), index);
+	    index = largest;
+	    l = left(index);
+	    r = right(index);
+	}
+	else
+	    break;
+    }
+
+    if( index != i )
+	place(moving, index);
+}
+
+////////////////////////////////////////////////////////////////////////
+//
+// Exported interface to the heap
+//
+
+void MxHeap::insert(MxHeapable *t, float v)
+{
+    t->heap_key(v);
+
+    unsigned int i = add(t);
+    t->set_heap_pos(i);
+
+    upheap(i);
+}
+
+void MxHeap::update(MxHeapable *t, float v)
+{
+    SanityCheck( t->is_in_heap() );
+    t->heap_key(v);
+
+    unsigned int i = t->get_heap_pos();
+
+    if( i>0 && v>ref(parent(i))->heap_key() )
+	upheap(i);
+    else
+	downheap(i);
+}
+
+MxHeapable *MxHeap::extract()
+{
+    if( length() < 1 ) return NULL;
+
+    swap(0, length()-1);
+    MxHeapable *dead=drop();
+
+    downheap(0);
+    dead->not_in_heap();
+    return dead;
+}
+
+MxHeapable *MxHeap::remove(MxHeapable *t)
+{
+    if( !t->is_in_heap() ) return NULL;
+
+    int i = t->get_heap_pos();
+    swap(i, length()-1);
+    drop();
+    t->not_in_heap();
+
+    if( ref(i)->heap_key() < t->heap_key() )
+	downheap(i);
+    else
+	upheap(i);
+
+    return t;
+}
Index: /GTP/trunk/Lib/Vis/Preprocessing/src/MxHeap.h
===================================================================
--- /GTP/trunk/Lib/Vis/Preprocessing/src/MxHeap.h	(revision 1097)
+++ /GTP/trunk/Lib/Vis/Preprocessing/src/MxHeap.h	(revision 1097)
@@ -0,0 +1,70 @@
+#ifndef MXHEAP_INCLUDED // -*- C++ -*-
+#define MXHEAP_INCLUDED
+#if !defined(__GNUC__)
+#  pragma once
+#endif
+
+/************************************************************************
+
+  Heap
+
+  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
+  
+  $Id: MxHeap.h,v 1.1 2002/09/24 16:53:54 wimmer Exp $
+
+ ************************************************************************/
+
+//#include "MxDynBlock.h"
+typedef unsigned int uint;
+
+class MxHeapable
+{
+private:
+    float import;
+    int token;
+
+public:
+    MxHeapable() { not_in_heap(); heap_key(0.0f); }
+
+    inline bool is_in_heap() { return token != -47; }
+    inline void not_in_heap() { token = -47; }
+    inline int get_heap_pos() { return token; }
+    inline void set_heap_pos(int t) { token=t; }
+
+    inline void  heap_key(float k) { import=k; }
+    inline float heap_key() const  { return import; }
+};
+
+
+class MxHeap// : private MxDynBlock<MxHeapable *>
+{
+private:
+    void place(MxHeapable *x, unsigned int i);
+    void swap(unsigned int i, unsigned int j);
+
+    unsigned int parent(unsigned int i) { return (i-1)/2; }
+    unsigned int left(unsigned int i) { return 2*i+1; }
+    unsigned int right(unsigned int i) { return 2*i+2; }
+
+    void upheap(unsigned int i);
+    void downheap(unsigned int i);
+
+public:
+    MxHeap()/* : MxDynBlock<MxHeapable *>(8)*/ { }
+   // MxHeap(unsigned int n) : MxDynBlock<MxHeapable *>(n) { }
+
+    void insert(MxHeapable *t) { insert(t, t->heap_key()); }
+    void insert(MxHeapable *, float);
+    void update(MxHeapable *t) { update(t, t->heap_key()); }
+    void update(MxHeapable *, float);
+
+    unsigned int size() const { return length(); }
+    MxHeapable       *item(uint i)       { return ref(i); }
+    const MxHeapable *item(uint i) const { return ref(i); }
+    MxHeapable *extract();
+    MxHeapable *top() { return (length()<1 ? (MxHeapable *)NULL : raw(0)); }
+    MxHeapable *remove(MxHeapable *);
+};
+
+// MXHEAP_INCLUDED
+#endif
