Browse Source

Initial commit

Gis-Y 6 months ago
commit
b4323b52ca
41 changed files with 18057 additions and 0 deletions
  1. 1528 0
      ModelIO/BaseIO.h
  2. BIN
      ModelIO/BaseIO.zip
  3. 110 0
      ModelIO/CurveAdaptiveDiscrete.h
  4. 285 0
      ModelIO/FaceProperty.h
  5. 309 0
      ModelIO/GeoAPIUtil.h
  6. 424 0
      ModelIO/ModelIO.h
  7. 246 0
      ModelIO/MurmurHash.h
  8. 76 0
      ModelIO/RandomColorGenerator.h
  9. 158 0
      ModelIO/TreeLabel.h
  10. 447 0
      ModelIO/jsoncpp/json/json-forwards.h
  11. 2375 0
      ModelIO/jsoncpp/json/json.h
  12. 5342 0
      ModelIO/jsoncpp/jsoncpp.cpp
  13. 96 0
      ModelIO/occ_compatible.h
  14. 459 0
      ModelIO/poly_connect_ex.h
  15. BIN
      ModelIO/tcl_5.0.6/TCL.chm
  16. 23 0
      ModelIO/tcl_5.0.6/alpha.h
  17. 172 0
      ModelIO/tcl_5.0.6/associative_tree.h
  18. 284 0
      ModelIO/tcl_5.0.6/associative_tree.inl
  19. 107 0
      ModelIO/tcl_5.0.6/basic_tree.h
  20. 93 0
      ModelIO/tcl_5.0.6/basic_tree.inl
  21. 250 0
      ModelIO/tcl_5.0.6/child_iterator.h
  22. 225 0
      ModelIO/tcl_5.0.6/child_node_iterator.h
  23. 308 0
      ModelIO/tcl_5.0.6/descendant_iterator.h
  24. 222 0
      ModelIO/tcl_5.0.6/descendant_iterator.inl
  25. 296 0
      ModelIO/tcl_5.0.6/descendant_node_iterator.h
  26. 221 0
      ModelIO/tcl_5.0.6/descendant_node_iterator.inl
  27. 135 0
      ModelIO/tcl_5.0.6/multitree.h
  28. 76 0
      ModelIO/tcl_5.0.6/multitree.inl
  29. 111 0
      ModelIO/tcl_5.0.6/ordered_iterator.h
  30. 114 0
      ModelIO/tcl_5.0.6/populateAlphabet.h
  31. 124 0
      ModelIO/tcl_5.0.6/reverse_iterator.h
  32. 119 0
      ModelIO/tcl_5.0.6/reverse_node_iterator.h
  33. 283 0
      ModelIO/tcl_5.0.6/sequential_tree.h
  34. 333 0
      ModelIO/tcl_5.0.6/sequential_tree.inl
  35. 135 0
      ModelIO/tcl_5.0.6/tree.h
  36. 76 0
      ModelIO/tcl_5.0.6/tree.inl
  37. 183 0
      ModelIO/tcl_5.0.6/unique_tree.h
  38. 445 0
      ModelIO/tcl_5.0.6/unique_tree.inl
  39. 227 0
      js_ext_comx_cascade_core.cc
  40. 675 0
      js_ext_comx_cascade_io.cc
  41. 965 0
      js_ext_comx_cascade_render.cc

File diff suppressed because it is too large
+ 1528 - 0
ModelIO/BaseIO.h


BIN
ModelIO/BaseIO.zip


+ 110 - 0
ModelIO/CurveAdaptiveDiscrete.h

@@ -0,0 +1,110 @@
+/*******************************************************************************
+
+程序说明
+
+曲线离散程序,对Curve数据进行离散,用于后续的显示;
+
+*******************************************************************************/
+
+#ifndef CURVEADAPTIVEDISCRETE_H
+#define CURVEADAPTIVEDISCRETE_H
+
+#include <vector>
+#include <BRepAdaptor_Curve.hxx>
+#include <GCPnts_QuasiUniformDeflection.hxx>
+#include <GCPnts_TangentialDeflection.hxx>
+#include <GCPnts_UniformDeflection.hxx>
+
+using namespace std;
+
+enum CurveDiscreteMethod {
+        TangentialDeflection = 0,
+        QuasiUniformDeflection = 1,
+        UniformDeflection = 2
+};
+
+
+void CurveAdaptiveDiscrete(const BRepAdaptor_Curve &adaptorCurve,
+                                 vector<double> &points, vector<int> &lines,
+                                 CurveDiscreteMethod discreteMethod) {
+
+        points.clear();
+        lines.clear();
+
+        Standard_Integer pointsLength = 0;
+
+        double edgeLength = CPnts_AbscissaPoint::Length(adaptorCurve, 1e-7);
+        // double adaptingDeflection = 0.1 * edgeLength;
+
+        switch (discreteMethod) {
+        case TangentialDeflection: {
+
+                double adaptingDeflection = 0.005 * edgeLength;
+                GCPnts_TangentialDeflection thePointsOnCurve;
+                Standard_Real AngularDeflection = 0.3;
+                Standard_Real CurvatureDeflection = adaptingDeflection;
+                thePointsOnCurve.Initialize(adaptorCurve, AngularDeflection,
+                                            CurvatureDeflection);
+                pointsLength = thePointsOnCurve.NbPoints();
+
+                for (Standard_Integer i = 1; i <= pointsLength; ++i) {
+                        gp_Pnt pt;
+
+                        pt = adaptorCurve.Value(thePointsOnCurve.Parameter(i));
+
+                        points.push_back(pt.X());
+                        points.push_back(pt.Y());
+                        points.push_back(pt.Z());
+
+                        if (i != pointsLength) {
+                                lines.push_back(i - 1);
+                                lines.push_back(i);
+                        }
+                }
+        } break;
+        case QuasiUniformDeflection: {
+
+                double adaptingDeflection = 0.007 * edgeLength;
+                GCPnts_QuasiUniformDeflection thePointsOnCurve;
+                thePointsOnCurve.Initialize(adaptorCurve, adaptingDeflection);
+                pointsLength = thePointsOnCurve.NbPoints();
+                for (Standard_Integer i = 1; i <= pointsLength; ++i) {
+                        gp_Pnt pt;
+
+                        pt = adaptorCurve.Value(thePointsOnCurve.Parameter(i));
+
+                        points.push_back(pt.X());
+                        points.push_back(pt.Y());
+                        points.push_back(pt.Z());
+
+                        if (i != pointsLength) {
+                                lines.push_back(i - 1);
+                                lines.push_back(i);
+                        }
+                }
+        } break;
+        default: {
+                // cout << "UniformDeflection" << endl;
+                GCPnts_UniformDeflection thePointsOnCurve;
+                double adaptingDeflection = 0.007 * edgeLength;
+                thePointsOnCurve.Initialize(adaptorCurve, adaptingDeflection);
+                pointsLength = thePointsOnCurve.NbPoints();
+                for (Standard_Integer i = 1; i <= pointsLength; ++i) {
+                        gp_Pnt pt;
+
+                        pt = adaptorCurve.Value(thePointsOnCurve.Parameter(i));
+
+                        points.push_back(pt.X());
+                        points.push_back(pt.Y());
+                        points.push_back(pt.Z());
+
+                        if (i != pointsLength) {
+                                lines.push_back(i - 1);
+                                lines.push_back(i);
+                        }
+                }
+        } break;
+        }
+}
+
+#endif

+ 285 - 0
ModelIO/FaceProperty.h

@@ -0,0 +1,285 @@
+
+/*******************************************************************************
+
+程序说明
+
+Poly_Connect_ex.h:
+	这个文件的基础文件是Opencascade的Poly_Connect.hxx
+	由于调用Poly_Connect类计算法线时,会出现程序执行完毕,polyedge释放错误的Bug,
+	因此在原来的基础上重新对文件进行了编辑,实际Poly_Connect.hxx文件中包含释放polyedge代码
+	但是,注释掉了,因此将这段重新打开;
+
+计算法线注释掉的ComputeNormals()函数是通过计算相邻单元的平均法线法计算的法线,不准确
+保留的ComputeNormals()函数是通过OCC内部函数,基于几何,计算曲面上点的法线方向
+
+*******************************************************************************/
+
+#pragma once
+
+#include <string>
+#include <vector>
+#include <TopoDS_Face.hxx>
+#include <TColgp_Array1OfPnt.hxx>
+#include <TopLoc_Location.hxx>
+#include <Poly_Array1OfTriangle.hxx>
+#include <Poly_Triangle.hxx>
+#include <Quantity_Color.hxx>
+#include <TDF_Label.hxx>
+#include <TCollection_AsciiString.hxx>
+#include <TDF_Tool.hxx>
+#include <BRep_Tool.hxx>
+#include <TopoDS.hxx>
+#include <Geom_Surface.hxx>
+
+#include "Poly_Connect_ex.h"
+
+using namespace std;
+
+enum EdgeType
+{
+	FreeEdge,		// Single Edge in Ansa
+	InnerEdge,		// Double Edge in Ansa
+	ShareEdge		// Triple Edge in Ansa
+};
+
+struct EdgeProperty
+{
+	EdgeType edgeType;
+	int id;
+	vector<int> edges;
+};
+
+inline bool operator<(const EdgeProperty& p1, const EdgeProperty& p2)
+{
+	if (p1.edges < p2.edges)
+	{
+		return true;
+	}
+	else
+	{
+		return false;
+	}
+}
+
+class FaceProperty
+{
+public:
+	FaceProperty()
+	{
+		red = 0;
+		green = 0;
+		blue = 255;
+		label = "Null";
+		name = "NoName";
+	}
+
+	int red;
+	int green;
+	int blue;
+
+	int id;
+
+	//int faceId;
+	////int alpha;
+	//int sid;
+
+	//int hashCode;
+
+	TopoDS_Face faceObj;
+
+	//unsigned long long faceAddress;
+
+	string label;
+	string name;
+
+	// 这里重新构建节点单元法线的数据结构,而不是使用OCC中的已有的数据,原因是构建的数据可以直接输入到OpenGL中
+	// 否则,DCiP中进行渲染时,一样需要建立相同的vector,才能把结果传递到渲染引擎
+	vector<double> points;
+	vector<double> normals;
+	vector<int> elements;
+	set<EdgeProperty> edgeProperties;
+public:
+	void BuildPoints(const TColgp_Array1OfPnt &aNodes, const TopLoc_Location &location)
+	{
+		//for (TColgp_Array1OfPnt::Iterator anIter(aNodes); anIter.More(); anIter.Next())
+		for (int i = 1; i <= aNodes.Length(); i++)
+		{
+			gp_Pnt vertex = aNodes.Value(i).Transformed(location.Transformation());
+
+			points.push_back(vertex.X());
+			points.push_back(vertex.Y());
+			points.push_back(vertex.Z());
+		}
+	}
+
+	void BuildElements(const Poly_Array1OfTriangle &aTri)
+	{
+		for (Standard_Integer i = 1; i <= aTri.Length(); i++)
+		{
+			Standard_Integer nVertexIndex1 = 0;
+			Standard_Integer nVertexIndex2 = 0;
+			Standard_Integer nVertexIndex3 = 0;
+
+			Poly_Triangle aTriangle = aTri.Value(i);
+			aTriangle.Get(nVertexIndex1, nVertexIndex2, nVertexIndex3);
+
+			// -1是为了从1开始变为0开始
+			elements.push_back(nVertexIndex1 - 1);
+			elements.push_back(nVertexIndex2 - 1);
+			elements.push_back(nVertexIndex3 - 1);
+		}
+	}
+
+	void SetColor(Quantity_Color& aColor)
+	{
+		red = int(aColor.Red() * 255);
+		green = int(aColor.Green() * 255);
+		blue = int(aColor.Blue() * 255);
+	}
+
+	void SetFaceLabel(const TDF_Label& _label)
+	{
+		TCollection_AsciiString entry;
+		TDF_Tool::Entry(_label, entry);
+		label = entry.ToCString();
+	}
+	//*
+	//OCC获取节点法线,更精确
+	void ComputeNormals()
+	{
+		TopLoc_Location location;
+		Handle(Poly_Triangulation) theTris = BRep_Tool::Triangulation(faceObj, location);
+
+		if (theTris.IsNull())
+		{
+			return;
+		}
+		if (theTris->HasNormals()) {
+
+			//normals = POLY_TRIGULATION_NORMALS(theTris);
+			return;
+		}
+
+		// take in face the surface location
+		const TopoDS_Face aZeroFace =
+			TopoDS::Face(faceObj.Located(TopLoc_Location()));
+		Handle(Geom_Surface) aSurf = BRep_Tool::Surface(aZeroFace);
+		const Poly_Array1OfTriangle &aTriangles = POLY_TRIGULATION_TRIANGLES(theTris);
+		if (!theTris->HasUVNodes() || aSurf.IsNull()) {
+			// compute normals by averaging triangulation normals sharing
+			// the same vertex
+			Poly::ComputeNormals(theTris);
+			return;
+		}
+
+		const Standard_Real aTol = Precision::Confusion();
+		//const TColgp_Array1OfPnt2d &aNodesUV = theTris->UVNodes();
+		const TColgp_Array1OfPnt2d &aNodesUV = POLY_TRIGULATION_UVNODES(theTris);
+		//const TColgp_Array1OfPnt &aNodes = theTris->Nodes();
+		const TColgp_Array1OfPnt &aNodes = POLY_TRIGULATION_NODES(theTris);
+		gp_Dir aNorm;
+
+		for (Standard_Integer aNodeIter = aNodes.Lower(); aNodeIter <= aNodes.Upper(); ++aNodeIter)
+		{
+			if (GeomLib::NormEstim(aSurf, aNodesUV.Value(aNodeIter), aTol, aNorm) > 1)
+			{
+				Poly_Connect_Ex thePolyConnect;
+				thePolyConnect.Load(theTris);
+
+				// compute flat normals
+				gp_XYZ eqPlan(0.0, 0.0, 0.0);
+				Standard_Integer aTri[3];
+				for (thePolyConnect.Initialize(aNodeIter); thePolyConnect.More(); thePolyConnect.Next())
+				{
+					aTriangles(thePolyConnect.Value()).Get(aTri[0], aTri[1], aTri[2]);
+					const gp_XYZ v1(aNodes(aTri[1]).Coord() - aNodes(aTri[0]).Coord());
+					const gp_XYZ v2(aNodes(aTri[2]).Coord() - aNodes(aTri[1]).Coord());
+					const gp_XYZ vv = v1 ^ v2;
+					const Standard_Real aMod = vv.Modulus();
+					if (aMod >= aTol) {
+						eqPlan += vv / aMod;
+					}
+				}
+				const Standard_Real aModMax = eqPlan.Modulus();
+				aNorm = (aModMax > aTol) ? gp_Dir(eqPlan) : gp::DZ();
+			}
+
+			normals.push_back(aNorm.X());
+			normals.push_back(aNorm.Y());
+			normals.push_back(aNorm.Z());
+		}
+
+	}
+	//*/
+	/*
+	// 平均法线法计算节点法线
+	void ComputeNormals()
+	{
+		normals.resize(points.size());
+
+		for (unsigned int i = 0, il = elements.size(); i < il; i += 3) {
+
+			// elements从1开始,而不是0,所以-1
+			int vA = elements[i + 0];
+			int vB = elements[i + 1];
+			int vC = elements[i + 2];
+
+			if (vA == 0 || vB == 0 || vC == 0)
+			{
+				int a = 1;
+			}
+
+			gp_Vec pA(points[vA * 3], points[vA * 3 + 1], points[vA * 3 + 2]);
+			gp_Vec pB(points[vB * 3], points[vB * 3 + 1], points[vB * 3 + 2]);
+			gp_Vec pC(points[vC * 3], points[vC * 3 + 1], points[vC * 3 + 2]);
+
+			gp_Vec cb = pC - pB;
+			gp_Vec ab = pA - pB;
+			cb = cb ^ ab;
+
+			gp_Vec nA(normals[vA * 3], normals[vA * 3 + 1], normals[vA * 3 + 2]);
+			gp_Vec nB(normals[vB * 3], normals[vB * 3 + 1], normals[vB * 3 + 2]);
+			gp_Vec nC(normals[vC * 3], normals[vC * 3 + 1], normals[vC * 3 + 2]);
+
+			nA = nA + cb;
+			nB = nB + cb;
+			nC = nC + cb;
+
+			normals[vA * 3] = nA.X();
+			normals[vA * 3 + 1] = nA.Y();
+			normals[vA * 3 + 2] = nA.Z();
+
+			normals[vB * 3] = nB.X();
+			normals[vB * 3 + 1] = nB.Y();
+			normals[vB * 3 + 2] = nB.Z();
+
+			normals[vC * 3] = nC.X();
+			normals[vC * 3 + 1] = nC.Y();
+			normals[vC * 3 + 2] = nC.Z();
+		}
+
+		for (unsigned int i = 0, il = normals.size(); i < il; i += 3) {
+			gp_XYZ _nor(normals[i], normals[i + 1], normals[i + 2]);
+
+			const Standard_Real aModMax = _nor.Modulus();
+			gp_Dir aNorm = (aModMax > 1e-6) ? gp_Dir(_nor) : gp::DZ();
+
+			normals[i] = aNorm.X();
+			normals[i + 1] = aNorm.Y();
+			normals[i + 2] = aNorm.Z();
+		}
+	}
+	*/
+	void Dump()
+	{
+		cout << "Face Property: " << endl;
+		cout << "Color Red  : " << red << endl;
+		cout << "Color Green: " << green << endl;
+		cout << "Color Blue : " << blue << endl;
+		cout << "id   : " << id << endl;
+		cout << "points size: " << points.size() << endl;
+		cout << "elems  size: " << elements.size() << endl;
+		cout << endl;
+	}
+
+};

+ 309 - 0
ModelIO/GeoAPIUtil.h

@@ -0,0 +1,309 @@
+/*******************************************************************************
+
+程序说明
+
+提供了一些处理模型的方法,ModelIO.h中并未使用
+
+*******************************************************************************/
+
+#ifndef GEOAPIUTIL_H
+#define GEOAPIUTIL_H
+
+#include <XCAFApp_Application.hxx>
+#include <BinXCAFDrivers.hxx>
+#include <STEPCAFControl_Writer.hxx>
+#include <gp_Pnt.hxx>
+#include <TopoDS_Face.hxx>
+#include <TopoDS_Shape.hxx>
+#include <TopExp_Explorer.hxx>
+#include <GProp_GProps.hxx>
+#include <BRepGProp.hxx>
+#include <Geom_Surface.hxx>
+#include <BRep_Tool.hxx>
+#include <BRepAdaptor_Curve.hxx>
+#include <BRepAdaptor_Surface.hxx>
+#include <BRepAlgoAPI_Common.hxx>
+#include <BRepPrimAPI_MakeSphere.hxx>
+#include <BRep_Builder.hxx>
+#include <TopoDS_Compound.hxx>
+#include <BRepTools.hxx>
+#include <BRepAlgoAPI_Cut.hxx>
+#include <TopoDS.hxx>
+#include <Geom_SphericalSurface.hxx>
+#include <Geom_CylindricalSurface.hxx>
+#include <STANDARD_TYPE.hxx>
+#include <BRepExtrema_DistShapeShape.hxx>
+#include <BRepBuilderAPI_MakeEdge.hxx>
+#include <StlAPI_Writer.hxx>
+#include <GeomAPI_ProjectPointOnSurf.hxx>
+#include <BRepBuilderAPI_MakeVertex.hxx>
+#include <gp_Lin.hxx>
+#include <string>
+
+using namespace std;
+
+namespace GeoAPIUtil
+{
+
+	// 获取一个Shape的中心点,是多个Face中心点的平均值
+	// Face为柱面时中心点为中轴的中点
+	// Face为球面时,中心点为圆心
+	inline gp_Pnt GetShapeCentroid(const TopoDS_Shape &shape)
+	{
+		gp_Pnt centroid;
+		int centroidCount = 0;
+		for (TopExp_Explorer faceExp(shape, TopAbs_FACE); faceExp.More(); faceExp.Next())
+		{
+			const TopoDS_Face face = TopoDS::Face(faceExp.Current());
+			const Handle(Geom_Surface)& surface = BRep_Tool::Surface(face);
+
+			gp_Pnt center;
+
+			// 如果是圆柱面则取圆柱的中心,否则计算其质心
+			if (surface->IsInstance(STANDARD_TYPE(Geom_CylindricalSurface)))
+			{
+				Handle(Geom_CylindricalSurface) cylindricalSurface = Handle(Geom_CylindricalSurface)::DownCast(surface);
+				center = cylindricalSurface->Location();
+			}
+			else if (surface->IsInstance(STANDARD_TYPE(Geom_SphericalSurface)))
+			{
+				Handle(Geom_SphericalSurface) sphericalSurface = Handle(Geom_SphericalSurface)::DownCast(surface);
+				center = sphericalSurface->Location();
+			}
+			else
+			{
+				GProp_GProps properties;
+				BRepGProp::SurfaceProperties(face, properties);
+				center = properties.CentreOfMass();
+			}
+
+			centroid.SetX(centroid.X() + center.X());
+			centroid.SetX(centroid.Y() + center.Y());
+			centroid.SetX(centroid.Z() + center.Z());
+			centroidCount++;
+		}
+
+		centroid.SetX(centroid.X() / centroidCount);
+		centroid.SetX(centroid.Y() / centroidCount);
+		centroid.SetX(centroid.Z() / centroidCount);
+
+		return centroid;
+	}
+	inline void CreateFaceCentroid(const TopoDS_Face &face, gp_Pnt &center)
+	{
+
+		Handle(Geom_Surface) surface = BRep_Tool::Surface(face);
+
+		// 如果是圆柱面则取圆柱的中心,否则计算其质心
+		if (surface->IsInstance(STANDARD_TYPE(Geom_CylindricalSurface)))
+		{
+			Handle(Geom_CylindricalSurface) cylindricalSurface = Handle(Geom_CylindricalSurface)::DownCast(surface);
+			center = cylindricalSurface->Location();
+		}
+		else if (surface->IsInstance(STANDARD_TYPE(Geom_SphericalSurface)))
+		{
+			Handle(Geom_SphericalSurface) sphericalSurface = Handle(Geom_SphericalSurface)::DownCast(surface);
+			center = sphericalSurface->Location();
+		}
+		else
+		{
+			GProp_GProps properties;
+			BRepGProp::SurfaceProperties(face, properties);
+			center = properties.CentreOfMass();
+		}
+	}
+	// 获取中心点,并且投影到平面上
+	inline void CreateFaceCentroidOnSurface(const TopoDS_Face &face, gp_Pnt &center)
+	{
+		Handle(Geom_Surface) surface = BRep_Tool::Surface(face);
+
+		gp_Pnt _center;
+
+		GProp_GProps properties;
+		BRepGProp::SurfaceProperties(face, properties);
+		_center = properties.CentreOfMass();
+
+		GeomAPI_ProjectPointOnSurf geomProj(_center, surface);
+
+		if (geomProj.IsDone())
+		{
+			double disMin = 1e6;
+
+			for (int i = 1; i <= geomProj.NbPoints(); i++)
+			{
+				gp_Pnt _pt = geomProj.Point(i);
+
+				double squareDis = _center.SquareDistance(_pt);
+				if (squareDis < disMin)
+				{
+					disMin = squareDis;
+					center = _pt;
+				}
+			}
+		}
+		else
+		{
+			center = _center;
+		}
+
+	}
+
+	// 用一个球体截取一个曲面,并且生成BRep数据
+	// 输出为Brep文件,参数依次为球的圆心,半径,以及要裁剪的面TopoDS_Shape类型,最后是输出的BRep文件的路径
+	inline bool SphereSurfaceIntersection(const gp_Pnt &center, const double &R, const TopoDS_Shape &shape, const string &brepfilePath, const string &stlfilePath)
+	{
+		TopoDS_Shape sphereShape = BRepPrimAPI_MakeSphere(center, R);
+
+		TopoDS_Compound aCompound;
+		BRep_Builder    aBuildTool;
+		aBuildTool.MakeCompound(aCompound);
+
+		for (TopExp_Explorer faceExp(shape, TopAbs_FACE); faceExp.More(); faceExp.Next())
+		{
+			TopoDS_Shape shapeChild = faceExp.Current();
+
+			BRepAlgoAPI_Common section(shapeChild, sphereShape);
+			section.Build();
+
+			TopExp_Explorer faceChildExp(section.Shape(), TopAbs_FACE);
+			if (faceChildExp.More())
+			{
+				aBuildTool.Add(aCompound, section.Shape());
+			}
+		}
+
+		if (!BRepTools::Write(aCompound, brepfilePath.c_str()))
+		{
+			return false;
+		}
+
+		BRepMesh_IncrementalMesh anAlgo;
+		anAlgo.ChangeParameters().Deflection = 0.2;
+		anAlgo.ChangeParameters().Angle = 20.0 * M_PI / 180.0; // 20 degrees
+		anAlgo.ChangeParameters().InParallel = true;
+		anAlgo.SetShape(aCompound);
+		anAlgo.Perform();
+
+		StlAPI_Writer anStlWriter;
+
+		if (anStlWriter.Write(aCompound, stlfilePath.c_str()))
+		{
+			return true;
+		}
+		else
+		{
+			return false;
+		}
+	}
+
+	// 用一个球体截取一个曲面,并且生成TopoDS_Compound
+	// 返回为TopoDS_Compound,参数依次为球的圆心,半径,以及要裁剪的面TopoDS_Shape类型
+	inline TopoDS_Compound SphereSurfaceIntersection(const gp_Pnt &center, const double &R, const TopoDS_Shape &shape)
+	{
+		TopoDS_Shape sphereShape = BRepPrimAPI_MakeSphere(center, R);
+
+		TopoDS_Compound aCompound;
+		BRep_Builder    aBuildTool;
+		aBuildTool.MakeCompound(aCompound);
+
+		for (TopExp_Explorer faceExp(shape, TopAbs_FACE); faceExp.More(); faceExp.Next())
+		{
+			TopoDS_Shape shapeChild = faceExp.Current();
+
+			BRepAlgoAPI_Common section(shapeChild, sphereShape);
+			section.Build();
+
+			TopExp_Explorer faceChildExp(section.Shape(), TopAbs_FACE);
+			if (faceChildExp.More())
+			{
+				aBuildTool.Add(aCompound, section.Shape());
+			}
+		}
+
+		return aCompound;
+	}
+
+	// 删除Face
+	inline void RemoveFace(TopoDS_Shape& shape, const TopoDS_Face& faceToRemove)
+	{
+		BRepAlgoAPI_Cut cut(shape, faceToRemove);
+		TopoDS_Shape resultShape = cut.Shape();
+		shape = resultShape;
+	}
+
+	inline void CreatePoint(const double &x, const double &y, const double &z, gp_Pnt &aPoint)
+	{
+		aPoint.SetCoord(x, y, z);
+
+	}
+	inline void CreatePoint(const double &x, const double &y, const double &z, TopoDS_Vertex &vertex)
+	{
+		gp_Pnt aPoint(x, y, z);
+		vertex = BRepBuilderAPI_MakeVertex(aPoint);
+	}
+
+	inline bool GetLineSurfaceIntersectionPoint(const gp_Pnt &pt, const gp_Dir &dir, const TopoDS_Face &face, gp_Pnt &intersectionPoint)
+	{
+		gp_Lin line(pt, dir);
+		TopoDS_Edge lineEdge = BRepBuilderAPI_MakeEdge(line);
+		BRepExtrema_DistShapeShape distSS(lineEdge, face, Extrema_ExtFlag_MIN);
+		distSS.Perform();
+
+		if (distSS.IsDone() && distSS.NbSolution() > 0 && distSS.Value() < 1e-3)
+		{
+			double minDistance = 1e6;
+			for (int i = 1; i <= distSS.NbSolution(); i++)
+			{
+
+				double dis = distSS.PointOnShape2(i).Distance(pt);
+
+				if (dis < minDistance)
+				{
+					minDistance = dis;
+					intersectionPoint = distSS.PointOnShape2(i);
+				}
+			}
+
+			return true;
+		}
+		else {
+			return false;
+		}
+	}
+
+	inline bool CreateStpByShape(const TopoDS_Shape& aShape, const string &filePath)
+	{
+		Handle(TDocStd_Document) localDoc;
+		Handle(XCAFApp_Application) anApp = XCAFApp_Application::GetApplication();
+		BinXCAFDrivers::DefineFormat(anApp);
+		anApp->NewDocument("BinXCAF", localDoc);
+		Handle(XCAFDoc_ShapeTool)shapeTool = XCAFDoc_DocumentTool::ShapeTool(localDoc->Main());
+
+		// 将形状添加到文档中
+		TDF_Label label;
+		shapeTool->AddShape(aShape);
+
+		STEPControl_StepModelType mode = STEPControl_AsIs;
+
+		STEPCAFControl_Writer aWriter;
+		aWriter.SetColorMode(true);
+		aWriter.SetNameMode(true);
+
+		// Translating document (conversion) to STEP
+		if (!aWriter.Transfer(localDoc, mode)) {
+			return false;
+		}
+		// Writing the File
+		IFSelect_ReturnStatus status = aWriter.Write(filePath.c_str());
+
+		// 检查是否成功写入
+		if (status != IFSelect_RetDone) {
+			return false;
+		}
+
+		return true;
+	}
+
+
+};
+#endif // GEOAPIUTIL_H

+ 424 - 0
ModelIO/ModelIO.h

@@ -0,0 +1,424 @@
+/*******************************************************************************
+
+程序说明
+
+用于模型的输入输出,主要实现在BaseIO.h中
+
+这里读入gltf模型仅限于模型,不能读动画
+
+另外读取gltf模型后不能转存为stp,igs文件,程序会出错,当然,这么做本身也没有意义
+
+*******************************************************************************/
+
+
+#ifndef MODELIO_H
+#define MODELIO_H
+
+#include "BaseIO.h"
+
+#include <BinXCAFDrivers.hxx>
+#include <XCAFApp_Application.hxx>
+#include <BRep_Builder.hxx>
+
+#include <TDF_Label.hxx>
+#include <TDF_Tool.hxx>
+#include <TDF_Attribute.hxx>
+#include <TDF_LabelMap.hxx>
+#include <TDF_LabelSequence.hxx>
+#include <IFSelect_ReturnStatus.hxx>
+#include <Interface_Static.hxx>
+#include <Interface_EntityIterator.hxx>
+#include <Interface_Check.hxx>
+#include <Standard_CString.hxx>
+#include <Standard_Boolean.hxx>
+#include <Standard_Integer.hxx>
+#include <Standard_OStream.hxx>
+
+#include <XCAFDoc_Color.hxx>
+
+#include <STEPControl_StepModelType.hxx>
+#include <UnitsMethods.hxx>
+#include <Prs3d_Drawer.hxx>
+
+#include <IGESCAFControl_Reader.hxx>
+#include <IGESCAFControl_Writer.hxx>
+
+#include <STEPCAFControl_Reader.hxx>
+#include <STEPCAFControl_Writer.hxx>
+
+#include <RWGltf_CafReader.hxx>
+#include <RWGltf_CafWriter.hxx>
+
+#include <StlAPI_Writer.hxx>
+#include <StlAPI_Reader.hxx>
+
+enum GeomType
+{
+	GeomSTP,
+	GeomIGS,
+	GeomSTL,
+	GeomBREP,
+	GeomGLTF
+};
+
+class ModelIO : public BaseIO
+{
+public:
+	ModelIO() {
+		defaultColor.SetValues(static_cast<float>(0.644479692), static_cast<float>(0.644479692), static_cast<float>(1.00000000), static_cast<float>(1.00000000));
+	}
+	bool Read(const string &fileName, const GeomType &modelType);
+	bool Write(const string &fileName, const GeomType &modelType);
+
+private:
+	bool ReadIGS(const string &fileName);
+	bool ReadSTP(const string &fileName);
+	bool ReadBREP(const string &filename);
+	bool ReadSTL(const string &filename);
+	bool ReadGLTF(const string &filename);
+
+	bool WriteSTP(const string &fileName);
+	bool WriteIGS(const string &fileName);
+	bool WriteBREP(const string &fileName);
+	bool WriteSTL(const string &fileName);
+	bool WriteGLTF(const string &fileName);
+
+	GeomType modelFormat;
+	Quantity_ColorRGBA defaultColor;
+};
+
+inline bool ModelIO::Read(const string &fileName, const GeomType &modelType)
+{
+	modelFormat = modelType;
+
+	switch (modelType)
+	{
+	case GeomSTP:
+		return ReadSTP(fileName);
+	case GeomIGS:
+		return ReadIGS(fileName);
+	case GeomSTL:
+		return ReadSTL(fileName);
+	case GeomBREP:
+		return ReadBREP(fileName);
+	case GeomGLTF:
+		return ReadGLTF(fileName);
+	default:
+		break;
+	}
+
+	return false;
+}
+
+inline bool ModelIO::Write(const string &fileName, const GeomType &modelType)
+{
+	switch (modelType)
+	{
+	case GeomSTP:
+		return WriteSTP(fileName);
+	case GeomIGS:
+		return WriteIGS(fileName);
+	case GeomSTL:
+		return WriteSTL(fileName);
+	case GeomBREP:
+		return WriteBREP(fileName);
+	case GeomGLTF:
+		return WriteGLTF(fileName);
+	default:
+		break;
+	}
+
+	return false;
+}
+
+inline bool ModelIO::ReadIGS(const string &fileName)
+{
+	IGESCAFControl_Reader aIgesReader;
+	aIgesReader.SetColorMode(true);
+	aIgesReader.SetNameMode(true);
+
+	IFSelect_ReturnStatus status = aIgesReader.ReadFile(fileName.c_str());
+
+	Handle(XCAFApp_Application) anApp = XCAFApp_Application::GetApplication();
+	BinXCAFDrivers::DefineFormat(anApp);
+	anApp->NewDocument("BinXCAF", doc);
+
+	if (status == IFSelect_RetDone)
+	{
+		aIgesReader.Transfer(doc);
+		return true;
+	}
+
+	return false;
+}
+
+inline bool ModelIO::ReadSTP(const string &fileName)
+{
+
+	Handle(XCAFApp_Application) anApp = XCAFApp_Application::GetApplication();
+	BinXCAFDrivers::DefineFormat(anApp);
+	anApp->NewDocument("BinXCAF", doc);
+
+	STEPCAFControl_Reader aStepReader;
+	aStepReader.SetColorMode(true);
+	aStepReader.SetNameMode(true);
+
+	IFSelect_ReturnStatus status = aStepReader.ReadFile(fileName.c_str());
+
+
+	//--------------
+	//TopoDS_Shape shape_Step;
+
+	//STEPControl_Reader aReader_Step = aStepReader.Reader();
+	//	int j = 1;
+
+	//for (Standard_Integer i = 1; i <= aReader_Step.NbRootsForTransfer(); i++)
+	//	aReader_Step.TransferRoot(i);
+	//for (Standard_Integer i = 1; i <= aReader_Step.NbShapes(); i++)
+	//	shape_Step = aReader_Step.Shape(i);
+
+	//TopTools_IndexedMapOfShape solids_map, shells_map, faces_map, wires_map, edges_map, vertices_map;
+	//TopExp_Explorer exp_solids, exp_shells, exp_faces, exp_wires, exp_edges, exp_vertices;
+	//for (exp_faces.Init(shape_Step, TopAbs_FACE); exp_faces.More(); exp_faces.Next())
+	//{
+	//	TopoDS_Face face = TopoDS::Face(exp_faces.Current().Composed(shape_Step.Orientation()));
+
+	//	cout << face.HashCode()
+
+	//	j++;
+	//}
+
+	//--------------
+
+	if (status == IFSelect_RetDone)
+	{
+		aStepReader.Transfer(doc);
+		return true;
+	}
+
+	return false;
+}
+
+inline bool ModelIO::ReadBREP(const string &filename)
+{
+	TopoDS_Shape aShape;
+	BRep_Builder aBuilder;
+
+	if (!BRepTools::Read(aShape, filename.c_str(), aBuilder))
+	{
+		return false;
+	}	
+
+	doc = new TDocStd_Document("BRep");
+
+	Handle(XCAFDoc_ShapeTool) ST = XCAFDoc_DocumentTool::ShapeTool(doc->Main());
+
+	ST->AddShape(aShape);
+
+	return true;
+}
+
+inline bool ModelIO::ReadSTL(const string &filename)
+{
+	TopoDS_Shape aShape;
+
+	StlAPI_Reader anStlReader;
+
+	if (!anStlReader.Read(aShape, filename.c_str()))
+	{
+		return false;
+	}
+
+	doc = new TDocStd_Document("STL");
+
+	Handle(XCAFDoc_ShapeTool) ST = XCAFDoc_DocumentTool::ShapeTool(doc->Main());
+	Handle(XCAFDoc_ColorTool) CT = XCAFDoc_DocumentTool::ColorTool(doc->Main());
+	Quantity_ColorRGBA aColor(defaultColor);
+
+	TDF_Label aLabel = ST->AddShape(aShape);
+	CT->SetColor(aShape, aColor, XCAFDoc_ColorSurf);
+
+	TDataStd_Name::Set(aLabel, "STL_Shape");
+
+	return true;
+}
+
+inline bool ModelIO::ReadGLTF(const string &filename)
+{
+	Handle(XCAFApp_Application) anApp = XCAFApp_Application::GetApplication();
+	BinXCAFDrivers::DefineFormat(anApp);
+	anApp->NewDocument("BinXCAF", doc);
+
+	RWGltf_CafReader aReader;
+	Standard_Real aSystemUnitFactor = UnitsMethods::GetCasCadeLengthUnit() * 0.001;
+	aReader.SetSystemLengthUnit(aSystemUnitFactor);
+	aReader.SetSystemCoordinateSystem(RWMesh_CoordinateSystem_Zup);
+	aReader.SetDocument(doc);
+	aReader.SetParallel(Standard_True);
+	Message_ProgressRange theProgress;
+
+	if (aReader.Perform(filename.c_str(), theProgress))
+	{
+		Handle(XCAFDoc_ColorTool) CT = XCAFDoc_DocumentTool::ColorTool(doc->Main());
+		Quantity_ColorRGBA aColor(defaultColor);
+		CT->SetColor(doc->Main(), aColor, XCAFDoc_ColorSurf);
+		return true;
+	}
+	else
+	{
+		return false;
+	}
+}
+// ------------------------------------------
+// Write Files
+// ------------------------------------------
+inline bool ModelIO::WriteSTP(const string &fileName)
+{
+	if (modelFormat == GeomGLTF)
+	{
+		return false;
+	}
+
+	STEPControl_StepModelType mode = STEPControl_AsIs;
+
+	STEPCAFControl_Writer aWriter;
+	aWriter.SetColorMode(true);
+	aWriter.SetNameMode(true);
+
+	// Translating document (conversion) to STEP
+	if (!aWriter.Transfer(doc, mode)) {
+		return false;
+	}
+	// Writing the File
+	IFSelect_ReturnStatus status = aWriter.Write(fileName.c_str());
+
+	// 检查是否成功写入
+	if (status != IFSelect_RetDone) {
+		return false;		
+	}
+
+	return true;
+}
+
+inline bool ModelIO::WriteIGS(const string &fileName)
+{
+	if (modelFormat == GeomGLTF)
+	{
+		return false;
+	}
+
+	IGESCAFControl_Writer aWriter;
+	aWriter.SetColorMode(true);
+	aWriter.SetNameMode(true);
+
+	return aWriter.Perform(doc, fileName.c_str());
+}
+
+inline bool ModelIO::WriteBREP(const string &fileName)
+{
+	Handle(XCAFDoc_ShapeTool) aShapeTool = XCAFDoc_DocumentTool::ShapeTool(doc->Main());
+
+	TDF_LabelSequence aRootLabels;
+	aShapeTool->GetFreeShapes(aRootLabels);
+
+	TopoDS_Compound aCompound;
+	BRep_Builder    aBuildTool;
+	aBuildTool.MakeCompound(aCompound);
+	for (TDF_LabelSequence::Iterator aRootIter(aRootLabels); aRootIter.More(); aRootIter.Next())
+	{
+		const TDF_Label& aRootLabel = aRootIter.Value();
+		TopoDS_Shape aRootShape;
+		if (XCAFDoc_ShapeTool::GetShape(aRootLabel, aRootShape))
+		{
+			aBuildTool.Add(aCompound, aRootShape);
+		}
+	}
+
+	return BRepTools::Write(aCompound, fileName.c_str());
+}
+
+
+inline bool ModelIO::WriteSTL(const string &fileName)
+{
+	cout << "WriteSTL " << endl;
+	Handle(XCAFDoc_ShapeTool) aShapeTool = XCAFDoc_DocumentTool::ShapeTool(doc->Main());
+
+	TDF_LabelSequence aRootLabels;
+	aShapeTool->GetFreeShapes(aRootLabels);
+
+	TopoDS_Compound aCompound;
+	BRep_Builder    aBuildTool;
+	aBuildTool.MakeCompound(aCompound);
+	for (TDF_LabelSequence::Iterator aRootIter(aRootLabels); aRootIter.More(); aRootIter.Next())
+	{
+		const TDF_Label& aRootLabel = aRootIter.Value();
+		TopoDS_Shape aRootShape;
+		if (XCAFDoc_ShapeTool::GetShape(aRootLabel, aRootShape))
+		{
+			aBuildTool.Add(aCompound, aRootShape);
+		}
+	}
+
+	// perform meshing
+	Handle(Prs3d_Drawer) aDrawer = new Prs3d_Drawer(); // holds visualization defaults
+	BRepMesh_IncrementalMesh anAlgo;
+	anAlgo.ChangeParameters().Deflection = 0.2;
+	anAlgo.ChangeParameters().Angle = 20.0 * M_PI / 180.0; // 20 degrees
+	anAlgo.ChangeParameters().InParallel = true;
+	anAlgo.SetShape(aCompound);
+	anAlgo.Perform();	
+
+	StlAPI_Writer anStlWriter;
+	//anStlWriter.ASCIIMode() = false;
+
+	cout << "Start Writing STL." << endl;
+
+	if (anStlWriter.Write(aCompound, fileName.c_str()))
+	{
+		return true;
+	}
+	return false;
+}
+
+inline bool ModelIO::WriteGLTF(const string &fileName)
+{
+	Handle(XCAFDoc_ShapeTool) aShapeTool = XCAFDoc_DocumentTool::ShapeTool(doc->Main());
+
+	TDF_LabelSequence aRootLabels;
+	aShapeTool->GetFreeShapes(aRootLabels);
+
+	TopoDS_Compound aCompound;
+	BRep_Builder    aBuildTool;
+	aBuildTool.MakeCompound(aCompound);
+	for (TDF_LabelSequence::Iterator aRootIter(aRootLabels); aRootIter.More(); aRootIter.Next())
+	{
+		const TDF_Label& aRootLabel = aRootIter.Value();
+		TopoDS_Shape aRootShape;
+		if (XCAFDoc_ShapeTool::GetShape(aRootLabel, aRootShape))
+		{
+			aBuildTool.Add(aCompound, aRootShape);
+		}
+	}
+
+	// perform meshing
+	Handle(Prs3d_Drawer) aDrawer = new Prs3d_Drawer(); // holds visualization defaults
+	BRepMesh_IncrementalMesh anAlgo;
+	anAlgo.ChangeParameters().Deflection = 0.2;
+	anAlgo.ChangeParameters().Angle = 20.0 * M_PI / 180.0; // 20 degrees
+	anAlgo.ChangeParameters().InParallel = true;
+	anAlgo.SetShape(aCompound);
+	anAlgo.Perform();
+
+	TColStd_IndexedDataMapOfStringString aMetadata;
+	Message_ProgressRange theProgress;
+	RWGltf_CafWriter aGltfWriter(fileName.c_str(), true);
+	// STEP reader translates into mm units by default
+	aGltfWriter.ChangeCoordinateSystemConverter().SetInputLengthUnit(0.001);
+	aGltfWriter.ChangeCoordinateSystemConverter().SetInputCoordinateSystem(RWMesh_CoordinateSystem_Zup);
+	if (aGltfWriter.Perform(doc, aMetadata, theProgress))
+	{
+		return true;
+	}
+	return false;
+}
+#endif

+ 246 - 0
ModelIO/MurmurHash.h

@@ -0,0 +1,246 @@
+/*******************************************************************************
+
+程序说明
+
+计算Hash值的函数,参考7.8.0版本的计算哈希值函数,调用方式与7.8.0一致
+
+*******************************************************************************/
+
+#ifndef MURMURHASH_H
+#define MURMURHASH_H
+
+#include <TopoDS_Edge.hxx>
+#include <TopoDS_Face.hxx>
+#include <TopoDS_Shape.hxx>
+#include <TopLoc_Datum3D.hxx>
+#include <TopLoc_SListOfItemLocation.hxx>
+#include <TopLoc_Location.hxx>
+#include <TopLoc_ItemLocation.hxx>
+#include <string>
+
+namespace opencascade
+{
+	namespace MurmurHash
+	{
+		inline uint64_t shift_mix(uint64_t theV)
+		{
+			return theV ^ (theV >> 47);
+		}
+
+		// Loads n bytes, where 1 <= n < 8.
+		inline uint64_t load_bytes(const char* thePnt, int theNb)
+		{
+			uint64_t aRes = 0;
+			--theNb;
+			do
+				aRes = (aRes << 8) + static_cast<unsigned char>(thePnt[theNb]);
+			while (--theNb >= 0);
+			return aRes;
+		}
+		template <typename T>
+		inline T unaligned_load(const char* thePnt)
+		{
+			T aRes;
+			memcpy(&aRes, thePnt, sizeof(aRes));
+			return aRes;
+		}
+
+		//=======================================================================
+		//function : MurmurHash64A
+		//purpose  :
+		//=======================================================================
+		inline uint64_t MurmurHash64A(const void* theKey, int theLen, uint64_t theSeed)
+		{
+			static constexpr uint64_t aMul = (((uint64_t)0xc6a4a793UL) << 32UL)
+				+ (uint64_t)0x5bd1e995UL;
+			const char* const aBuf = static_cast<const char*>(theKey);
+
+			// Remove the bytes not divisible by the sizeof(uint64_t).  This
+			// allows the main loop to process the data as 64-bit integers.
+			const uint64_t aLenAligned = theLen & ~(uint64_t)0x7;
+			const char* const anEnd = aBuf + aLenAligned;
+			uint64_t aHash = theSeed ^ (theLen * aMul);
+			for (const char* aPnt = aBuf; aPnt != anEnd; aPnt += 8)
+			{
+				const uint64_t aData = shift_mix(unaligned_load<uint64_t>(aPnt) * aMul) * aMul;
+				aHash ^= aData;
+				aHash *= aMul;
+			}
+			if ((theLen & 0x7) != 0)
+			{
+				const uint64_t data = load_bytes(anEnd, theLen & 0x7);
+				aHash ^= data;
+				aHash *= aMul;
+			}
+			aHash = shift_mix(aHash) * aMul;
+			aHash = shift_mix(aHash);
+			return aHash;
+		}
+
+		//=======================================================================
+		//function : MurmurHash2A
+		//purpose  :
+		//=======================================================================
+		inline uint32_t MurmurHash2A(const void* theKey, int theLen, uint32_t theSeed)
+		{
+			const uint32_t aMul = 0x5bd1e995;
+			uint32_t aHash = theSeed ^ theLen;
+			const char* aBuf = static_cast<const char*>(theKey);
+
+			// Mix 4 bytes at a time into the hash.
+			while (theLen >= 4)
+			{
+				uint32_t aKey = unaligned_load<uint32_t>(aBuf);
+				aKey *= aMul;
+				aKey ^= aKey >> 24;
+				aKey *= aMul;
+				aHash *= aMul;
+				aHash ^= aKey;
+				aBuf += 4;
+				theLen -= 4;
+			}
+
+			uint32_t aKey;
+			// Handle the last few bytes of the input array.
+			switch (theLen)
+			{
+			case 3:
+				aKey = static_cast<unsigned char>(aBuf[2]);
+				aHash ^= aKey << 16;
+				Standard_FALLTHROUGH
+			case 2:
+				aKey = static_cast<unsigned char>(aBuf[1]);
+				aHash ^= aKey << 8;
+				Standard_FALLTHROUGH
+			case 1:
+				aKey = static_cast<unsigned char>(aBuf[0]);
+				aHash ^= aKey;
+				aHash *= aMul;
+			};
+
+			// Do a few final mixes of the hash.
+			aHash ^= aHash >> 13;
+			aHash *= aMul;
+			aHash ^= aHash >> 15;
+			return aHash;
+		}
+
+
+		template <typename T1, typename T = size_t>
+		typename std::enable_if<sizeof(T) == 8, uint64_t>::type
+			hash_combine(const T1& theValue, const int theLen = sizeof(T1), const T theSeed = 0xA329F1D3A586ULL)
+		{
+			return MurmurHash::MurmurHash64A(&theValue, theLen, theSeed);
+		}
+
+		template <typename T1, typename T = size_t>
+		typename std::enable_if<sizeof(T) != 8, T>::type
+			hash_combine(const T1& theValue, const int theLen = sizeof(T1), const T theSeed = 0xc70f6907U)
+		{
+			return static_cast<T>(MurmurHash::MurmurHash2A(&theValue, theLen, theSeed));
+		}
+
+		template <typename T = size_t>
+		constexpr T optimalSeed()
+		{
+			return sizeof(T) == 8 ? static_cast<T>(0xA329F1D3A586ULL) : static_cast<T>(0xc70f6907U);
+		}
+	};
+
+	template <typename T1, typename T = size_t>
+	T hash(const T1 theValue) noexcept
+	{
+		return opencascade::MurmurHash::hash_combine<T1, T>(theValue);
+	}
+
+	template <typename T1, typename T = size_t>
+	T hashBytes(const T1* theKey, int theLen)
+	{
+		return opencascade::MurmurHash::hash_combine<T1, T>(*theKey, theLen);
+	}
+
+	template <typename T1, typename T = size_t>
+	T hash_combine(const T1 theValue, const int theLen, const T theSeed)
+	{
+		return opencascade::MurmurHash::hash_combine<T1, T>(theValue, theLen, theSeed);
+	}
+};
+
+
+namespace std
+{
+	inline size_t GetLocationHashCode(const TopLoc_Location& loc)
+	{
+		gp_Trsf T = loc.Transformation();
+		TopLoc_SListOfItemLocation myItems;
+		Handle(TopLoc_Datum3D) D = new TopLoc_Datum3D(T);
+		myItems.Construct(TopLoc_ItemLocation(D, 1));
+
+		// Hashing base on IsEqual function
+		if (myItems.IsEmpty())
+		{
+			return 0;
+		}
+		size_t aHash = opencascade::MurmurHash::optimalSeed<size_t>();
+		TopLoc_SListOfItemLocation items = myItems;
+		size_t aCombined[3];
+		while (items.More())
+		{
+			//aCombined[0] = std::hash<Handle(TopLoc_Datum3D)>{}(items.Value().myDatum);
+			aCombined[0] = static_cast<size_t>(reinterpret_cast<std::uintptr_t>(D.get()));
+			aCombined[1] = opencascade::hash(1);
+			aCombined[2] = aHash;
+			aHash = opencascade::hashBytes(aCombined, sizeof(aCombined));
+			items.Next();
+		}
+		return aHash;
+	}
+
+	template <class TheTransientType>
+	struct hash<Handle(TheTransientType)>
+	{
+		size_t operator()(const Handle(TheTransientType)& theHandle) const noexcept
+		{
+			return static_cast<size_t>(reinterpret_cast<std::uintptr_t>(theHandle.get()));
+		}
+	};
+
+	template <>
+	struct hash<TopLoc_Location>
+	{
+		size_t operator()(const TopLoc_Location& theLocation) const
+		{
+			return std::GetLocationHashCode(theLocation);
+		}
+	};
+
+	template <>
+	struct hash<TopoDS_Shape>
+	{
+		size_t operator()(const TopoDS_Shape& theShape) const noexcept
+		{
+			const size_t aHL = std::hash<TopLoc_Location>{}(theShape.Location());
+			return aHL == 0 ? opencascade::hash(theShape.TShape().get())
+				: opencascade::MurmurHash::hash_combine(theShape.TShape().get(), sizeof(void*), aHL);
+		}
+	};
+
+	template <>
+	struct hash<TopoDS_Face>
+	{
+		size_t operator()(const TopoDS_Face& theShape) const
+		{
+			return std::hash<TopoDS_Shape>{}(theShape);
+		}
+	};
+
+	template <>
+	struct hash<TopoDS_Edge>
+	{
+		size_t operator()(const TopoDS_Edge& theShape) const
+		{
+			return std::hash<TopoDS_Shape>{}(theShape);
+		}
+	};
+};
+#endif // MURMURHASH_H

+ 76 - 0
ModelIO/RandomColorGenerator.h

@@ -0,0 +1,76 @@
+/*******************************************************************************
+
+	基于HSV色彩模式定义的一个颜色生成器,过滤掉一些不适合显示模型的颜色,比如纯色
+	另外,生成的相邻颜色差别也较大,避免颜色过于相似
+
+*******************************************************************************/
+
+
+#pragma once
+
+#include <Quantity_Color.hxx>
+#include <vector>
+
+#define HUESTEP			360
+#define SATURATIONSTEP	17
+#define LIGHTNESSSTEP	19
+
+
+class RandomColorGenerator
+{
+public:
+	RandomColorGenerator() {
+		Ref = 0;
+		for (int i = 1; i <= HUESTEP; i++)
+		{
+			HueSamplers.push_back((83 * i) % HUESTEP);
+		}
+
+		// 饱和度 0.0 - 1.0
+		for (int i = 1; i <= SATURATIONSTEP; i++)
+		{
+			double randomNum = (7 * i) % SATURATIONSTEP;
+			SaturationSamplers.push_back(0.5 * randomNum / SATURATIONSTEP + 0.5);
+		}
+
+		// 亮度 0.2 - 0.8
+		for (int i = 1; i <= LIGHTNESSSTEP; i++)
+		{
+			int randomNum = (11 * i) % LIGHTNESSSTEP;
+			LightSamplers.push_back(0.5 * randomNum / LIGHTNESSSTEP + 0.5);
+		}
+
+	}
+	~RandomColorGenerator() {}
+
+	Quantity_Color GetColor()
+	{
+		int indexHue = Ref % HUESTEP;
+		int indexSaturation = Ref % SATURATIONSTEP;
+		int indexLight = Ref % LIGHTNESSSTEP;
+
+		color.SetValues(HueSamplers[indexHue], LightSamplers[indexLight], SaturationSamplers[indexSaturation], Quantity_TOC_HLS);
+		Ref++;
+
+		return color;
+	}
+
+	void ResetRef()
+	{
+		Ref = 0;
+	}
+
+	void SetRefBegin(const int _Ref)
+	{
+		Ref = _Ref;
+	}
+
+
+private:
+	int Ref;
+	std::vector<int> HueSamplers;
+	std::vector<double> SaturationSamplers;
+	std::vector<double> LightSamplers;
+	Quantity_Color color;
+
+};

+ 158 - 0
ModelIO/TreeLabel.h

@@ -0,0 +1,158 @@
+/*******************************************************************************
+
+用于显示模型的结构树
+
+根节点名称定义为Model
+
+节点分为两种类型,一种为TreeShape,包含子节点,但不包含具体的Face的数据,faceId均为0;
+一种为TreeFace,从属于TreeShape,存储了真正的Face数据,faceId大于0;
+
+
+*******************************************************************************/
+
+
+#pragma once
+
+#include <TopoDS_Shape.hxx>
+#include <TDF_Label.hxx>
+#include <string>
+#include <vector>
+
+//#define UPPERBOUND		2147483647
+#define UPPERBOUND			1999999999
+
+using namespace std;
+
+enum TreeType
+{
+	TreeShape,
+	TreeFace
+};
+struct TreeLabel
+{
+	TreeLabel()
+	{
+		id = 0;
+		Name = "Model";
+	}
+	TreeLabel(const TopoDS_Shape &_Shape, TreeType _NodeType = TreeShape, int _Level = 0) :
+		Shape(_Shape), NodeType(_NodeType), Level(_Level)
+	{
+		Name = GetName();
+	}
+	TreeLabel(const TDF_Label &_Label, const TopoDS_Shape &_Shape, TreeType _NodeType = TreeShape, int _Level = 0) :
+		Label(_Label), Shape(_Shape), NodeType(_NodeType), Level(_Level)
+	{
+		Name = GetName();
+	}
+
+	TDF_Label Label;
+	TopoDS_Shape Shape;
+	TreeType NodeType;
+	int id;
+	int Level;	
+	string Name;
+	vector<int> subFaceIds;
+	//int HashCode;
+	//int faceId;
+	//int sid;
+	//vector<int> subFaceHashCodes;
+
+	friend bool operator < (const TreeLabel& lhs, const TreeLabel& rhs)
+	{
+		return lhs.id < rhs.id;
+	}
+	friend bool operator == (const TreeLabel& lhs, const TreeLabel& rhs)
+	{
+		return lhs.id == rhs.id;
+	}
+
+	string GetName()
+	{
+		TCollection_ExtendedString str = "";
+
+		if (Label.IsNull() && Shape.IsNull())
+		{
+			str = "Model";
+		}
+
+		if (!Label.IsNull())
+		{
+			Handle(TDataStd_Name) anAttribute;
+
+			if (Label.FindAttribute(TDataStd_Name::GetID(), anAttribute))
+			{
+				str = anAttribute->Get();
+			}
+		}
+
+		if (str == "")
+		{
+			switch (Shape.ShapeType())
+			{
+			case TopAbs_COMPOUND:
+				str = "Compound";
+				break;
+			case TopAbs_COMPSOLID:
+				str = "CSolid";
+				break;
+			case TopAbs_SOLID:
+				str = "Solid";
+				break;
+			case  TopAbs_SHELL:
+				str = "Shell";
+				break;
+			case TopAbs_FACE:
+				str = "Face";
+				break;
+			case TopAbs_WIRE:
+				str = "Wire";
+				break;
+			case TopAbs_EDGE:
+				str = "Edge";
+				break;
+			case TopAbs_VERTEX:
+				str = "Vertex";
+				break;
+			case TopAbs_SHAPE:
+				str = "Shape";
+				break;
+			default:
+				break;
+			}
+		}
+
+		char* ch = new char[str.LengthOfCString() + 1];
+		str.ToUTF8CString(ch);
+		return ch;
+	}
+
+	string GetJsonName()
+	{
+		string tail;
+
+		//if (id < 10)
+		//{
+		//	tail = "_0000" + to_string(id);
+		//}
+		//else if (id < 100)
+		//{
+		//	tail = "_000" + to_string(id);
+		//}
+		//else if (id < 1000)
+		//{
+		//	tail = "_00" + to_string(id);
+		//}
+		//else if (id < 10000)
+		//{
+		//	tail = "_0" + to_string(id);
+		//}
+		//else
+		//{
+		//	tail = "_" + to_string(id);
+		//}
+
+		tail = "_" + to_string(id);
+		return Name + tail;
+	}
+};

+ 447 - 0
ModelIO/jsoncpp/json/json-forwards.h

@@ -0,0 +1,447 @@
+/// Json-cpp amalgamated forward header (http://jsoncpp.sourceforge.net/).
+/// It is intended to be used with #include "json/json-forwards.h"
+/// This header provides forward declaration for all JsonCpp types.
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: LICENSE
+// //////////////////////////////////////////////////////////////////////
+
+/*
+The JsonCpp library's source code, including accompanying documentation,
+tests and demonstration applications, are licensed under the following
+conditions...
+
+Baptiste Lepilleur and The JsonCpp Authors explicitly disclaim copyright in all
+jurisdictions which recognize such a disclaimer. In such jurisdictions,
+this software is released into the Public Domain.
+
+In jurisdictions which do not recognize Public Domain property (e.g. Germany as of
+2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur and
+The JsonCpp Authors, and is released under the terms of the MIT License (see below).
+
+In jurisdictions which recognize Public Domain property, the user of this
+software may choose to accept it either as 1) Public Domain, 2) under the
+conditions of the MIT License (see below), or 3) under the terms of dual
+Public Domain/MIT License conditions described here, as they choose.
+
+The MIT License is about as close to Public Domain as a license can get, and is
+described in clear, concise terms at:
+
+   http://en.wikipedia.org/wiki/MIT_License
+
+The full text of the MIT License follows:
+
+========================================================================
+Copyright (c) 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use, copy,
+modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+========================================================================
+(END LICENSE TEXT)
+
+The MIT license is compatible with both the GPL and commercial
+software, affording one all of the rights of Public Domain with the
+minor nuisance of being required to keep the above copyright notice
+and license text in the source code. Note also that by accepting the
+Public Domain "license" you can re-license your copy using whatever
+license you like.
+
+*/
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: LICENSE
+// //////////////////////////////////////////////////////////////////////
+
+
+
+
+
+#ifndef JSON_FORWARD_AMALGAMATED_H_INCLUDED
+# define JSON_FORWARD_AMALGAMATED_H_INCLUDED
+/// If defined, indicates that the source file is amalgamated
+/// to prevent private header inclusion.
+#define JSON_IS_AMALGAMATION
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: include/json/version.h
+// //////////////////////////////////////////////////////////////////////
+
+#ifndef JSON_VERSION_H_INCLUDED
+#define JSON_VERSION_H_INCLUDED
+
+// Note: version must be updated in three places when doing a release. This
+// annoying process ensures that amalgamate, CMake, and meson all report the
+// correct version.
+// 1. /meson.build
+// 2. /include/json/version.h
+// 3. /CMakeLists.txt
+// IMPORTANT: also update the SOVERSION!!
+
+#define JSONCPP_VERSION_STRING "1.9.5"
+#define JSONCPP_VERSION_MAJOR 1
+#define JSONCPP_VERSION_MINOR 9
+#define JSONCPP_VERSION_PATCH 5
+#define JSONCPP_VERSION_QUALIFIER
+#define JSONCPP_VERSION_HEXA                                                   \
+  ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) |             \
+   (JSONCPP_VERSION_PATCH << 8))
+
+#ifdef JSONCPP_USING_SECURE_MEMORY
+#undef JSONCPP_USING_SECURE_MEMORY
+#endif
+#define JSONCPP_USING_SECURE_MEMORY 0
+// If non-zero, the library zeroes any memory that it has allocated before
+// it frees its memory.
+
+#endif // JSON_VERSION_H_INCLUDED
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: include/json/version.h
+// //////////////////////////////////////////////////////////////////////
+
+
+
+
+
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: include/json/allocator.h
+// //////////////////////////////////////////////////////////////////////
+
+// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef JSON_ALLOCATOR_H_INCLUDED
+#define JSON_ALLOCATOR_H_INCLUDED
+
+#include <cstring>
+#include <memory>
+
+#pragma pack(push)
+#pragma pack()
+
+namespace Json {
+template <typename T> class SecureAllocator {
+public:
+  // Type definitions
+  using value_type = T;
+  using pointer = T*;
+  using const_pointer = const T*;
+  using reference = T&;
+  using const_reference = const T&;
+  using size_type = std::size_t;
+  using difference_type = std::ptrdiff_t;
+
+  /**
+   * Allocate memory for N items using the standard allocator.
+   */
+  pointer allocate(size_type n) {
+    // allocate using "global operator new"
+    return static_cast<pointer>(::operator new(n * sizeof(T)));
+  }
+
+  /**
+   * Release memory which was allocated for N items at pointer P.
+   *
+   * The memory block is filled with zeroes before being released.
+   */
+  void deallocate(pointer p, size_type n) {
+    // memset_s is used because memset may be optimized away by the compiler
+    memset_s(p, n * sizeof(T), 0, n * sizeof(T));
+    // free using "global operator delete"
+    ::operator delete(p);
+  }
+
+  /**
+   * Construct an item in-place at pointer P.
+   */
+  template <typename... Args> void construct(pointer p, Args&&... args) {
+    // construct using "placement new" and "perfect forwarding"
+    ::new (static_cast<void*>(p)) T(std::forward<Args>(args)...);
+  }
+
+  size_type max_size() const { return size_t(-1) / sizeof(T); }
+
+  pointer address(reference x) const { return std::addressof(x); }
+
+  const_pointer address(const_reference x) const { return std::addressof(x); }
+
+  /**
+   * Destroy an item in-place at pointer P.
+   */
+  void destroy(pointer p) {
+    // destroy using "explicit destructor"
+    p->~T();
+  }
+
+  // Boilerplate
+  SecureAllocator() {}
+  template <typename U> SecureAllocator(const SecureAllocator<U>&) {}
+  template <typename U> struct rebind { using other = SecureAllocator<U>; };
+};
+
+template <typename T, typename U>
+bool operator==(const SecureAllocator<T>&, const SecureAllocator<U>&) {
+  return true;
+}
+
+template <typename T, typename U>
+bool operator!=(const SecureAllocator<T>&, const SecureAllocator<U>&) {
+  return false;
+}
+
+} // namespace Json
+
+#pragma pack(pop)
+
+#endif // JSON_ALLOCATOR_H_INCLUDED
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: include/json/allocator.h
+// //////////////////////////////////////////////////////////////////////
+
+
+
+
+
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: include/json/config.h
+// //////////////////////////////////////////////////////////////////////
+
+// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef JSON_CONFIG_H_INCLUDED
+#define JSON_CONFIG_H_INCLUDED
+#include <cstddef>
+#include <cstdint>
+#include <istream>
+#include <memory>
+#include <ostream>
+#include <sstream>
+#include <string>
+#include <type_traits>
+
+// If non-zero, the library uses exceptions to report bad input instead of C
+// assertion macros. The default is to use exceptions.
+#ifndef JSON_USE_EXCEPTION
+#define JSON_USE_EXCEPTION 1
+#endif
+
+// Temporary, tracked for removal with issue #982.
+#ifndef JSON_USE_NULLREF
+#define JSON_USE_NULLREF 1
+#endif
+
+/// If defined, indicates that the source file is amalgamated
+/// to prevent private header inclusion.
+/// Remarks: it is automatically defined in the generated amalgamated header.
+// #define JSON_IS_AMALGAMATION
+
+// Export macros for DLL visibility
+#if defined(JSON_DLL_BUILD)
+#if defined(_MSC_VER) || defined(__MINGW32__)
+#define JSON_API __declspec(dllexport)
+#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING
+#elif defined(__GNUC__) || defined(__clang__)
+#define JSON_API __attribute__((visibility("default")))
+#endif // if defined(_MSC_VER)
+
+#elif defined(JSON_DLL)
+#if defined(_MSC_VER) || defined(__MINGW32__)
+#define JSON_API __declspec(dllimport)
+#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING
+#endif // if defined(_MSC_VER)
+#endif // ifdef JSON_DLL_BUILD
+
+#if !defined(JSON_API)
+#define JSON_API
+#endif
+
+#if defined(_MSC_VER) && _MSC_VER < 1800
+#error                                                                         \
+    "ERROR:  Visual Studio 12 (2013) with _MSC_VER=1800 is the oldest supported compiler with sufficient C++11 capabilities"
+#endif
+
+#if defined(_MSC_VER) && _MSC_VER < 1900
+// As recommended at
+// https://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010
+extern JSON_API int msvc_pre1900_c99_snprintf(char* outBuf, size_t size,
+                                              const char* format, ...);
+#define jsoncpp_snprintf msvc_pre1900_c99_snprintf
+#else
+#define jsoncpp_snprintf std::snprintf
+#endif
+
+// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for
+// integer
+// Storages, and 64 bits integer support is disabled.
+// #define JSON_NO_INT64 1
+
+// JSONCPP_OVERRIDE is maintained for backwards compatibility of external tools.
+// C++11 should be used directly in JSONCPP.
+#define JSONCPP_OVERRIDE override
+
+#ifdef __clang__
+#if __has_extension(attribute_deprecated_with_message)
+#define JSONCPP_DEPRECATED(message) __attribute__((deprecated(message)))
+#endif
+#elif defined(__GNUC__) // not clang (gcc comes later since clang emulates gcc)
+#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5))
+#define JSONCPP_DEPRECATED(message) __attribute__((deprecated(message)))
+#elif (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
+#define JSONCPP_DEPRECATED(message) __attribute__((__deprecated__))
+#endif                  // GNUC version
+#elif defined(_MSC_VER) // MSVC (after clang because clang on Windows emulates
+                        // MSVC)
+#define JSONCPP_DEPRECATED(message) __declspec(deprecated(message))
+#endif // __clang__ || __GNUC__ || _MSC_VER
+
+#if !defined(JSONCPP_DEPRECATED)
+#define JSONCPP_DEPRECATED(message)
+#endif // if !defined(JSONCPP_DEPRECATED)
+
+#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ >= 6))
+#define JSON_USE_INT64_DOUBLE_CONVERSION 1
+#endif
+
+#if !defined(JSON_IS_AMALGAMATION)
+
+#include "allocator.h"
+#include "version.h"
+
+#endif // if !defined(JSON_IS_AMALGAMATION)
+
+namespace Json {
+using Int = int;
+using UInt = unsigned int;
+#if defined(JSON_NO_INT64)
+using LargestInt = int;
+using LargestUInt = unsigned int;
+#undef JSON_HAS_INT64
+#else                 // if defined(JSON_NO_INT64)
+// For Microsoft Visual use specific types as long long is not supported
+#if defined(_MSC_VER) // Microsoft Visual Studio
+using Int64 = __int64;
+using UInt64 = unsigned __int64;
+#else                 // if defined(_MSC_VER) // Other platforms, use long long
+using Int64 = int64_t;
+using UInt64 = uint64_t;
+#endif                // if defined(_MSC_VER)
+using LargestInt = Int64;
+using LargestUInt = UInt64;
+#define JSON_HAS_INT64
+#endif // if defined(JSON_NO_INT64)
+
+template <typename T>
+using Allocator =
+    typename std::conditional<JSONCPP_USING_SECURE_MEMORY, SecureAllocator<T>,
+                              std::allocator<T>>::type;
+using String = std::basic_string<char, std::char_traits<char>, Allocator<char>>;
+using IStringStream =
+    std::basic_istringstream<String::value_type, String::traits_type,
+                             String::allocator_type>;
+using OStringStream =
+    std::basic_ostringstream<String::value_type, String::traits_type,
+                             String::allocator_type>;
+using IStream = std::istream;
+using OStream = std::ostream;
+} // namespace Json
+
+// Legacy names (formerly macros).
+using JSONCPP_STRING = Json::String;
+using JSONCPP_ISTRINGSTREAM = Json::IStringStream;
+using JSONCPP_OSTRINGSTREAM = Json::OStringStream;
+using JSONCPP_ISTREAM = Json::IStream;
+using JSONCPP_OSTREAM = Json::OStream;
+
+#endif // JSON_CONFIG_H_INCLUDED
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: include/json/config.h
+// //////////////////////////////////////////////////////////////////////
+
+
+
+
+
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: include/json/forwards.h
+// //////////////////////////////////////////////////////////////////////
+
+// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef JSON_FORWARDS_H_INCLUDED
+#define JSON_FORWARDS_H_INCLUDED
+
+#if !defined(JSON_IS_AMALGAMATION)
+#include "config.h"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+
+namespace Json {
+
+// writer.h
+class StreamWriter;
+class StreamWriterBuilder;
+class Writer;
+class FastWriter;
+class StyledWriter;
+class StyledStreamWriter;
+
+// reader.h
+class Reader;
+class CharReader;
+class CharReaderBuilder;
+
+// json_features.h
+class Features;
+
+// value.h
+using ArrayIndex = unsigned int;
+class StaticString;
+class Path;
+class PathArgument;
+class Value;
+class ValueIteratorBase;
+class ValueIterator;
+class ValueConstIterator;
+
+} // namespace Json
+
+#endif // JSON_FORWARDS_H_INCLUDED
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: include/json/forwards.h
+// //////////////////////////////////////////////////////////////////////
+
+
+
+
+
+#endif //ifndef JSON_FORWARD_AMALGAMATED_H_INCLUDED

File diff suppressed because it is too large
+ 2375 - 0
ModelIO/jsoncpp/json/json.h


File diff suppressed because it is too large
+ 5342 - 0
ModelIO/jsoncpp/jsoncpp.cpp


+ 96 - 0
ModelIO/occ_compatible.h

@@ -0,0 +1,96 @@
+/*******************************************************************************
+
+³ÌÐò˵Ã÷
+
+½â¾öOCC7.5Óë7.8¼æÈÝÐÔ
+
+*******************************************************************************/
+
+#ifndef OCC_COMPATIBLE_H
+#define OCC_COMPATIBLE_H
+
+#include <vector>
+#include <Standard_Version.hxx>
+
+using namespace std;
+
+namespace occ_compatible
+{
+	//
+//#define OCCT_VERSION_LESS_THAN_7_8 \
+//    ((OCC_VERSION_MAJOR < 7) || \
+//    ((OCC_VERSION_MAJOR == 7) && (OCC_VERSION_MINOR < 8)))
+
+#define OCC_VERSION_OPTION_7_5 ((OCC_VERSION_MAJOR == 7) && (OCC_VERSION_MINOR == 5))
+#define OCC_VERSION_OPTION_7_8 ((OCC_VERSION_MAJOR == 7) && (OCC_VERSION_MINOR == 8))
+
+#if OCC_VERSION_OPTION_7_5
+vector<double> GetNormals(opencascade::handle<Poly_Triangulation> theTris)
+{
+	vector<double> res;
+	for (int i = 1; i <= theTris->Normals().Size(); i++)
+	{
+		res.push_back(theTris->Normals().Value(i));
+	}
+	return res;
+}
+
+
+#define POLY_TRIGULATION_TRIANGLES(triFace) triFace->Triangles()
+#define POLY_TRIGULATION_NODES(triFace) triFace->Nodes()
+#define POLY_TRIGULATION_NORMALS(triFace) occ_compatible::GetNormals(triFace)
+#define POLY_TRIGULATION_UVNODES(triFace) triFace->UVNodes()
+
+
+#elif OCC_VERSION_OPTION_7_8
+#include <gp_Vec3f.hxx>
+
+	TColgp_Array1OfPnt GetNodes(opencascade::handle<Poly_Triangulation> theTris)
+	{
+		const Poly_ArrayOfNodes &aNodes = theTris->InternalNodes();
+		TColgp_Array1OfPnt aPnt(1, aNodes.Size());
+		for (int i = 1; i <= aNodes.Size(); i++)
+		{
+			gp_Pnt pt = aNodes.Value(i - 1);
+			aPnt[i] = pt;
+		}
+
+		return aPnt;
+	}
+
+	vector<double> GetNormals(opencascade::handle<Poly_Triangulation> theTris)
+	{
+		vector<double> res;
+		NCollection_Array1<gp_Vec3f> aNormals = theTris->InternalNormals();
+		for (int i = 1; i <= aNormals.Size(); i++)
+		{
+			res.push_back(aNormals.Value(i - 1).x());
+			res.push_back(aNormals.Value(i - 1).y());
+			res.push_back(aNormals.Value(i - 1).z());
+		}
+		return res;
+	}
+
+	TColgp_Array1OfPnt2d GetUVNodes(opencascade::handle<Poly_Triangulation> theTris)
+	{
+		const Poly_ArrayOfUVNodes &aNodes = theTris->InternalUVNodes();
+		cout << "aNodes Size: " << aNodes.Size() << endl;
+		TColgp_Array1OfPnt2d aPnt(1, aNodes.Size());
+		for (int i = 1; i <= aNodes.Size(); i++)
+		{
+			aPnt[i] = aNodes.Value(i - 1);
+		}
+
+		return aPnt;
+	}
+	
+
+#define POLY_TRIGULATION_TRIANGLES(triFace) triFace->InternalTriangles()
+#define POLY_TRIGULATION_NODES(triFace) occ_compatible::GetNodes(triFace)
+#define POLY_TRIGULATION_NORMALS(triFace) occ_compatible::GetNormals(triFace)
+#define POLY_TRIGULATION_UVNODES(triFace) occ_compatible::GetUVNodes(triFace)
+#endif
+};
+
+
+#endif

+ 459 - 0
ModelIO/poly_connect_ex.h

@@ -0,0 +1,459 @@
+/*******************************************************************************
+
+程序说明
+
+该文件源于poly_connect.hxx
+
+由于使用poly_connect进行法线的计算时,当程序执行完毕释放内存时会出现错误;
+所以在poly_connect.hxx的基础上进行了更改,将Load函数进行了更改,
+加入释放edge array的代码
+
+  // destroy the edges array - can be skipped when using NCollection_IncAllocator
+  for (Standard_Integer aNodeIter = anEdges.Lower(); aNodeIter <= anEdges.Upper(); ++aNodeIter)
+  {
+    for (polyedge* anEdgeIter = anEdges[aNodeIter]; anEdgeIter != NULL;)
+    {
+      polyedge* aTmp = anEdgeIter->next;
+      anIncAlloc->Free (anEdgeIter);
+      anEdgeIter = aTmp;
+    }
+  }
+
+*******************************************************************************/
+
+
+// Created on: 1995-03-06
+// Created by: Laurent PAINNOT
+// Copyright (c) 1995-1999 Matra Datavision
+// Copyright (c) 1999-2014 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#ifndef _Poly_Connect_Ex_HeaderFile
+#define _Poly_Connect_Ex_HeaderFile
+
+#include <Standard.hxx>
+#include <Standard_DefineAlloc.hxx>
+#include <Standard_Handle.hxx>
+
+#include <TColStd_Array1OfInteger.hxx>
+#include <Standard_Integer.hxx>
+#include <Standard_Boolean.hxx>
+
+#include <NCollection_IncAllocator.hxx>
+#include <Poly_Triangle.hxx>
+#include <Poly_Triangulation.hxx>
+
+struct polyedge
+{
+  polyedge* next;         // the next edge in the list
+  Standard_Integer nt[2]; // the two adjacent triangles
+  Standard_Integer nn[2]; // the two adjacent nodes
+  Standard_Integer nd;    // the second node of the edge
+  DEFINE_STANDARD_ALLOC
+};
+
+
+class Poly_Triangulation;
+
+//! Provides an algorithm to explore, inside a triangulation, the
+//! adjacency data for a node or a triangle.
+//! Adjacency data for a node consists of triangles which
+//! contain the node.
+//! Adjacency data for a triangle consists of:
+//! -   the 3 adjacent triangles which share an edge of the triangle,
+//! -   and the 3 nodes which are the other nodes of these adjacent triangles.
+//! Example
+//! Inside a triangulation, a triangle T
+//! has nodes n1, n2 and n3.
+//! It has adjacent triangles AT1, AT2 and AT3 where:
+//! - AT1 shares the nodes n2 and n3,
+//! - AT2 shares the nodes n3 and n1,
+//! - AT3 shares the nodes n1 and n2.
+//! It has adjacent nodes an1, an2 and an3 where:
+//! - an1 is the third node of AT1,
+//! - an2 is the third node of AT2,
+//! - an3 is the third node of AT3.
+//! So triangle AT1 is composed of nodes n2, n3 and an1.
+//! There are two ways of using this algorithm.
+//! -   From a given node you can look for one triangle that
+//! passes through the node, then look for the triangles
+//! adjacent to this triangle, then the adjacent nodes. You
+//! can thus explore the triangulation step by step (functions
+//! Triangle, Triangles and Nodes).
+//! -   From a given node you can look for all the triangles
+//! that pass through the node (iteration method, using the
+//! functions Initialize, More, Next and Value).
+//! A Connect object can be seen as a tool which analyzes a
+//! triangulation and translates it into a series of triangles. By
+//! doing this, it provides an interface with other tools and
+//! applications working on basic triangles, and which do not
+//! work directly with a Poly_Triangulation.
+class Poly_Connect_Ex
+{
+public:
+
+  DEFINE_STANDARD_ALLOC
+
+    //=======================================================================
+    //function : Poly_Connect
+    //purpose  :
+    //=======================================================================
+	  Poly_Connect_Ex()
+    : mytr    (0),
+      myfirst (0),
+      mynode  (0),
+      myothernode (0),
+      mysense (false),
+      mymore  (false)
+    {
+      //
+    }
+
+    //=======================================================================
+    //function : Poly_Connect
+    //purpose  :
+    //=======================================================================
+  Poly_Connect_Ex(const Handle(Poly_Triangulation)& theTriangulation)
+    : myTriangulation (theTriangulation),
+      myTriangles (1, theTriangulation->NbNodes()),
+      myAdjacents (1, 6 * theTriangulation->NbTriangles()),
+      mytr    (0),
+      myfirst (0),
+      mynode  (0),
+      myothernode (0),
+      mysense (false),
+      mymore  (false)
+    {
+      Load (theTriangulation);
+    }
+
+
+  //! Initialize the algorithm to explore the adjacency data of
+  //! nodes or triangles for the triangulation theTriangulation.
+  Standard_EXPORT void Load (const Handle(Poly_Triangulation)& theTriangulation);
+
+  //! Returns the triangulation analyzed by this tool.
+  const Handle(Poly_Triangulation)& Triangulation() const { return myTriangulation; }
+
+  //! Returns the index of a triangle containing the node at
+  //! index N in the nodes table specific to the triangulation analyzed by this tool
+  Standard_Integer Triangle (const Standard_Integer N) const { return myTriangles (N); }
+
+  //! Returns in t1, t2 and t3, the indices of the 3 triangles
+  //! adjacent to the triangle at index T in the triangles table
+  //! specific to the triangulation analyzed by this tool.
+  //! Warning
+  //! Null indices are returned when there are fewer than 3
+  //! adjacent triangles.
+  void Triangles (const Standard_Integer T, Standard_Integer& t1, Standard_Integer& t2, Standard_Integer& t3) const
+  {
+    Standard_Integer index = 6*(T-1);
+    t1 = myAdjacents(index+1);
+    t2 = myAdjacents(index+2);
+    t3 = myAdjacents(index+3);
+  }
+
+  //! Returns, in n1, n2 and n3, the indices of the 3 nodes
+  //! adjacent to the triangle referenced at index T in the
+  //! triangles table specific to the triangulation analyzed by this tool.
+  //! Warning
+  //! Null indices are returned when there are fewer than 3 adjacent nodes.
+  void Nodes (const Standard_Integer T, Standard_Integer& n1, Standard_Integer& n2, Standard_Integer& n3) const
+  {
+    Standard_Integer index = 6*(T-1);
+    n1 = myAdjacents(index+4);
+    n2 = myAdjacents(index+5);
+    n3 = myAdjacents(index+6);
+  }
+
+public:
+
+  //! Initializes an iterator to search for all the triangles
+  //! containing the node referenced at index N in the nodes
+  //! table, for the triangulation analyzed by this tool.
+  //! The iterator is managed by the following functions:
+  //! -   More, which checks if there are still elements in the iterator
+  //! -   Next, which positions the iterator on the next element
+  //! -   Value, which returns the current element.
+  //! The use of such an iterator provides direct access to the
+  //! triangles around a particular node, i.e. it avoids iterating on
+  //! all the component triangles of a triangulation.
+  //! Example
+  //! Poly_Connect C(Tr);
+  //! for
+  //! (C.Initialize(n1);C.More();C.Next())
+  //! {
+  //! t = C.Value();
+  //! }
+  Standard_EXPORT void Initialize (const Standard_Integer N);
+  
+  //! Returns true if there is another element in the iterator
+  //! defined with the function Initialize (i.e. if there is another
+  //! triangle containing the given node).
+  Standard_Boolean More() const { return mymore; }
+
+  //! Advances the iterator defined with the function Initialize to
+  //! access the next triangle.
+  //! Note: There is no action if the iterator is empty (i.e. if the
+  //! function More returns false).-
+  Standard_EXPORT void Next();
+  
+  //! Returns the index of the current triangle to which the
+  //! iterator, defined with the function Initialize, points. This is
+  //! an index in the triangles table specific to the triangulation
+  //! analyzed by this tool
+  Standard_Integer Value() const { return mytr; }
+
+private:
+
+  Handle(Poly_Triangulation) myTriangulation;
+  TColStd_Array1OfInteger myTriangles;
+  TColStd_Array1OfInteger myAdjacents;
+  Standard_Integer mytr;
+  Standard_Integer myfirst;
+  Standard_Integer mynode;
+  Standard_Integer myothernode;
+  Standard_Boolean mysense;
+  Standard_Boolean mymore;
+
+};
+
+//=======================================================================
+//function : Load
+//purpose  :
+//=======================================================================
+inline void Poly_Connect_Ex::Load (const Handle(Poly_Triangulation)& theTriangulation)
+{
+  myTriangulation = theTriangulation;
+  mytr = 0;
+  myfirst = 0;
+  mynode  = 0;
+  myothernode = 0;
+  mysense = false;
+  mymore  = false;
+
+  const Standard_Integer aNbNodes = myTriangulation->NbNodes();
+  const Standard_Integer aNbTris  = myTriangulation->NbTriangles();
+  {
+    const Standard_Integer aNbAdjs = 6 * aNbTris;
+    if (myTriangles.Size() != aNbNodes)
+    {
+      myTriangles.Resize (1, aNbNodes, Standard_False);
+    }
+    if (myAdjacents.Size() != aNbAdjs)
+    {
+      myAdjacents.Resize (1, aNbAdjs, Standard_False);
+    }
+  }
+
+  myTriangles.Init(0);
+  myAdjacents.Init(0);
+
+  // We first build an array of the list of edges connected to the nodes
+  // create an array to store the edges starting from the vertices
+  NCollection_Array1<polyedge*> anEdges (1, aNbNodes);
+  anEdges.Init (NULL);
+  // use incremental allocator for small allocations
+  Handle(NCollection_IncAllocator) anIncAlloc = new NCollection_IncAllocator();
+
+  // loop on the triangles
+  NCollection_Vec3<Standard_Integer> aTriNodes;
+  NCollection_Vec2<Standard_Integer> anEdgeNodes;
+  for (Standard_Integer aTriIter = 1; aTriIter <= aNbTris; ++aTriIter)
+  {
+    // get the nodes
+    myTriangulation->Triangle (aTriIter).Get (aTriNodes[0], aTriNodes[1], aTriNodes[2]);
+
+    // Update the myTriangles array
+    myTriangles.SetValue (aTriNodes[0], aTriIter);
+    myTriangles.SetValue (aTriNodes[1], aTriIter);
+    myTriangles.SetValue (aTriNodes[2], aTriIter);
+
+    // update the edge lists
+    for (Standard_Integer aNodeInTri = 0; aNodeInTri < 3; ++aNodeInTri)
+    {
+      const Standard_Integer aNodeNext = (aNodeInTri + 1) % 3;  // the following node of the edge
+      if (aTriNodes[aNodeInTri] < aTriNodes[aNodeNext])
+      {
+        anEdgeNodes[0] = aTriNodes[aNodeInTri];
+        anEdgeNodes[1] = aTriNodes[aNodeNext];
+      }
+      else
+      {
+        anEdgeNodes[0] = aTriNodes[aNodeNext];
+        anEdgeNodes[1] = aTriNodes[aNodeInTri];
+      }
+
+      // edge from node 0 to node 1 with node 0 < node 1
+      // insert in the list of node 0
+      polyedge* ced = anEdges[anEdgeNodes[0]];
+      for (; ced != NULL; ced = ced->next)
+      {
+        // the edge already exists
+        if (ced->nd == anEdgeNodes[1])
+        {
+          // just mark the adjacency if found
+          ced->nt[1] = aTriIter;
+          ced->nn[1] = aTriNodes[3 - aNodeInTri - aNodeNext];  // the third node
+          break;
+        }
+      }
+
+      if (ced == NULL)
+      {
+        // create the edge if not found
+        ced = (polyedge* )anIncAlloc->Allocate (sizeof(polyedge));
+        ced->next = anEdges[anEdgeNodes[0]];
+        anEdges[anEdgeNodes[0]] = ced;
+        ced->nd = anEdgeNodes[1];
+        ced->nt[0] = aTriIter;
+        ced->nn[0] = aTriNodes[3 - aNodeInTri - aNodeNext];  // the third node
+        ced->nt[1] = 0;
+        ced->nn[1] = 0;
+      }
+    }
+  }
+
+  // now complete the myAdjacents array
+  Standard_Integer anAdjIndex = 1;
+  for (Standard_Integer aTriIter = 1; aTriIter <= aNbTris; ++aTriIter)
+  {
+    // get the nodes
+    myTriangulation->Triangle (aTriIter).Get (aTriNodes[0], aTriNodes[1], aTriNodes[2]);
+
+    // for each edge in triangle
+    for (Standard_Integer aNodeInTri = 0; aNodeInTri < 3; ++aNodeInTri)
+    {
+      const Standard_Integer aNodeNext = (aNodeInTri + 1) % 3;  // the following node of the edge
+      if (aTriNodes[aNodeInTri] < aTriNodes[aNodeNext])
+      {
+        anEdgeNodes[0] = aTriNodes[aNodeInTri];
+        anEdgeNodes[1] = aTriNodes[aNodeNext];
+      }
+      else
+      {
+        anEdgeNodes[0] = aTriNodes[aNodeNext];
+        anEdgeNodes[1] = aTriNodes[aNodeInTri];
+      }
+
+      // edge from node 0 to node 1 with node 0 < node 1
+      // find in the list of node 0
+      const polyedge* ced = anEdges[anEdgeNodes[0]];
+      while (ced->nd != anEdgeNodes[1])
+      {
+        ced = ced->next;
+      }
+
+      // Find the adjacent triangle
+      const Standard_Integer l = ced->nt[0] == aTriIter ? 1 : 0;
+
+      myAdjacents.SetValue (anAdjIndex,     ced->nt[l]);
+      myAdjacents.SetValue (anAdjIndex + 3, ced->nn[l]);
+      ++anAdjIndex;
+    }
+    anAdjIndex += 3;
+  }
+
+  // destroy the edges array - can be skipped when using NCollection_IncAllocator
+  for (Standard_Integer aNodeIter = anEdges.Lower(); aNodeIter <= anEdges.Upper(); ++aNodeIter)
+  {
+    for (polyedge* anEdgeIter = anEdges[aNodeIter]; anEdgeIter != NULL;)
+    {
+      polyedge* aTmp = anEdgeIter->next;
+      anIncAlloc->Free (anEdgeIter);
+      anEdgeIter = aTmp;
+    }
+  }
+}
+
+//=======================================================================
+//function : Initialize
+//purpose  : 
+//=======================================================================
+
+inline void Poly_Connect_Ex::Initialize(const Standard_Integer N)
+{
+  mynode = N;
+  myfirst = Triangle(N);
+  mytr = myfirst;
+  mysense = Standard_True;
+  mymore = (myfirst != 0);
+  if (mymore)
+  {
+    Standard_Integer i, no[3];
+    //const Poly_Array1OfTriangle& triangles = myTriangulation->Triangles();
+	const Poly_Array1OfTriangle& triangles = POLY_TRIGULATION_TRIANGLES(myTriangulation);
+    triangles(myfirst).Get(no[0], no[1], no[2]);
+    for (i = 0; i < 3; i++)
+      if (no[i] == mynode) break;
+    myothernode = no[(i+2)%3];
+  }
+}
+
+//=======================================================================
+//function : Next
+//purpose  : 
+//=======================================================================
+
+inline void Poly_Connect_Ex::Next()
+{
+  Standard_Integer i, j;
+  Standard_Integer n[3];
+  Standard_Integer t[3];
+  //const Poly_Array1OfTriangle& triangles = myTriangulation->Triangles();
+  const Poly_Array1OfTriangle& triangles = POLY_TRIGULATION_TRIANGLES(myTriangulation);
+  Triangles(mytr, t[0], t[1], t[2]);
+  if (mysense) {
+    for (i = 0; i < 3; i++) {
+      if (t[i] != 0) {
+	triangles(t[i]).Get(n[0], n[1], n[2]);
+	for (j = 0; j < 3; j++) {
+	  if ((n[j] == mynode) && (n[(j+1)%3] == myothernode)) {
+	    mytr = t[i];
+	    myothernode = n[(j+2)%3];
+	    mymore = (mytr != myfirst);
+	    return;
+	  }
+	}
+      }
+    }
+    // sinon, depart vers la gauche.
+    triangles(myfirst).Get(n[0], n[1], n[2]);
+    for (i = 0; i < 3; i++)
+      if (n[i] == mynode) break;
+    myothernode = n[(i+1)%3];
+    mysense = Standard_False;
+    mytr = myfirst;
+    Triangles(mytr, t[0], t[1], t[2]);
+  }
+  if (!mysense) {
+    for (i = 0; i < 3; i++) {
+      if (t[i] != 0) {
+	triangles(t[i]).Get(n[0], n[1], n[2]);
+	for (j = 0; j < 3; j++) {
+	  if ((n[j] == mynode) && (n[(j+2)%3] == myothernode)) {
+	    mytr = t[i];
+	    myothernode = n[(j+1)%3];
+	    mymore = Standard_True;
+	    return;
+	  }
+	}
+      }
+    }
+  }
+  mymore = Standard_False;
+}
+
+
+
+#endif // _Poly_Connect_HeaderFile

BIN
ModelIO/tcl_5.0.6/TCL.chm


+ 23 - 0
ModelIO/tcl_5.0.6/alpha.h

@@ -0,0 +1,23 @@
+#pragma once
+#include <string>
+
+class Alpha
+{
+public:
+	// constructors/destructor
+	Alpha() : letter(0) {}
+	Alpha(const char _letter ) : letter(_letter) {}
+	~Alpha() {}
+
+	// interface
+	friend bool operator < (const Alpha& lhs, const Alpha& rhs) 
+	{ return lhs.getLetter() < rhs.getLetter(); }
+	friend bool operator == (const Alpha& lhs, const Alpha& rhs)
+	{ return lhs.getLetter() == rhs.getLetter(); }
+	char getLetter() const { return letter; }
+
+private:
+	// data
+	char letter;
+};
+

+ 172 - 0
ModelIO/tcl_5.0.6/associative_tree.h

@@ -0,0 +1,172 @@
+/*******************************************************************************
+Tree Container Library: Generic container library to store data in tree-like structures.
+Copyright (c) 2006  Mitchel Haas
+
+This software is provided 'as-is', without any express or implied warranty. 
+In no event will the author be held liable for any damages arising from 
+the use of this software.
+
+Permission is granted to anyone to use this software for any purpose, 
+including commercial applications, and to alter it and redistribute it freely, 
+subject to the following restrictions:
+
+1.	The origin of this software must not be misrepresented; 
+you must not claim that you wrote the original software. 
+If you use this software in a product, an acknowledgment in the product 
+documentation would be appreciated but is not required.
+
+2.	Altered source versions must be plainly marked as such, 
+and must not be misrepresented as being the original software.
+
+3.	The above copyright notice and this permission notice may not be removed 
+or altered from any source distribution.
+
+For complete documentation on this library, see http://www.datasoftsolutions.net
+Email questions, comments or suggestions to mhaas@datasoftsolutions.net
+*******************************************************************************/
+#pragma once
+#include "basic_tree.h"
+#include "child_iterator.h"
+#include "child_node_iterator.h"
+#include "descendant_iterator.h"
+#include "descendant_node_iterator.h"
+#include "reverse_iterator.h"
+#include "reverse_node_iterator.h"
+#include <memory>
+
+namespace tcl 
+{
+	template<typename T, typename U, typename X> class associative_tree;
+
+	// overloaded comparison operations
+	template<typename T, typename U, typename V> bool operator == (const associative_tree<T, U, V>& lhs, const associative_tree<T, U, V>& rhs);
+	template<typename T, typename U, typename V> bool operator <  (const associative_tree<T, U, V>& lhs, const associative_tree<T, U, V>& rhs);
+	template<typename T, typename U, typename V> bool operator != (const associative_tree<T, U, V>& lhs, const associative_tree<T, U, V>& rhs) { return !(lhs == rhs); }
+	template<typename T, typename U, typename V> bool operator >  (const associative_tree<T, U, V>& lhs, const associative_tree<T, U, V>& rhs) { return rhs < lhs; }
+	template<typename T, typename U, typename V> bool operator <= (const associative_tree<T, U, V>& lhs, const associative_tree<T, U, V>& rhs) { return !(rhs < lhs); }
+	template<typename T, typename U, typename V> bool operator >= (const associative_tree<T, U, V>& lhs, const associative_tree<T, U, V>& rhs) { return !(lhs < rhs); }
+}
+
+// stored_type:				type stored in container
+// tree_type:				one of three tree types derived from this base
+// container_type:		type of contain to hold children (can be set or multiset)
+
+template< typename stored_type, typename tree_type,  typename container_type >
+class tcl::associative_tree : public basic_tree<stored_type, tree_type, container_type>
+{
+protected:
+	typedef basic_tree<stored_type, tree_type, container_type> basic_tree_type;
+	explicit associative_tree( const stored_type& stored_obj ) : basic_tree_type(stored_obj) {}
+	virtual ~associative_tree() {}
+
+public:
+	// typedefs
+	typedef associative_tree<stored_type, tree_type, container_type> associative_tree_type;
+	typedef stored_type key_type;
+	using basic_tree_type::size_type;
+
+	// element iterator typedefs
+	typedef const_associative_iterator<stored_type, tree_type, container_type>																				const_iterator;
+	typedef associative_iterator<stored_type, tree_type, container_type>																							iterator;
+	typedef const_pre_order_descendant_iterator<stored_type, tree_type, container_type, associative_tree_type>				const_pre_order_iterator;
+	typedef pre_order_descendant_iterator<stored_type, tree_type, container_type, associative_tree_type>							pre_order_iterator;
+	typedef const_post_order_descendant_iterator<stored_type, tree_type, container_type, associative_tree_type>				const_post_order_iterator;
+	typedef post_order_descendant_iterator<stored_type, tree_type, container_type, associative_tree_type>							post_order_iterator;
+	typedef const_level_order_descendant_iterator<stored_type, tree_type, container_type, associative_tree_type>			const_level_order_iterator;
+	typedef level_order_descendant_iterator<stored_type, tree_type, container_type, associative_tree_type>						level_order_iterator;
+	typedef associative_reverse_iterator<stored_type, tree_type, container_type>																			reverse_iterator;
+	typedef const_associative_reverse_iterator<stored_type, tree_type, container_type>																const_reverse_iterator;
+
+	// node iterator typedefs
+	typedef const_associative_node_iterator<stored_type, tree_type, container_type>																		const_node_iterator;
+	typedef associative_node_iterator<stored_type, tree_type, container_type>																					node_iterator;
+	typedef const_pre_order_descendant_node_iterator<stored_type, tree_type, container_type, associative_tree_type>		const_pre_order_node_iterator;
+	typedef pre_order_descendant_node_iterator<stored_type, tree_type, container_type, associative_tree_type>					pre_order_node_iterator;
+	typedef const_post_order_descendant_node_iterator<stored_type, tree_type, container_type, associative_tree_type>	const_post_order_node_iterator;
+	typedef post_order_descendant_node_iterator<stored_type, tree_type, container_type, associative_tree_type>				post_order_node_iterator;
+	typedef const_level_order_descendant_node_iterator<stored_type, tree_type, container_type, associative_tree_type> const_level_order_node_iterator;
+	typedef level_order_descendant_node_iterator<stored_type, tree_type, container_type, associative_tree_type>				level_order_node_iterator;
+	typedef associative_reverse_node_iterator<stored_type, tree_type, container_type>																	reverse_node_iterator;
+	typedef const_associative_reverse_node_iterator<stored_type, tree_type, container_type>														const_reverse_node_iterator;
+
+	// child element iterator accessors
+	const_iterator begin() const { return const_iterator(basic_tree_type::children.begin(), this); }
+	const_iterator end() const { return const_iterator(basic_tree_type::children.end(), this); }
+	iterator begin() { return iterator(basic_tree_type::children.begin(), this); }
+	iterator end() { return iterator(basic_tree_type::children.end(), this); }
+	
+	// child node iterator accessors
+	const_node_iterator node_begin() const { return const_node_iterator(basic_tree_type::children.begin(), this); }
+	const_node_iterator node_end() const { return const_node_iterator(basic_tree_type::children.end(), this); }
+	node_iterator node_begin() { return node_iterator(basic_tree_type::children.begin(), this); }
+	node_iterator node_end() { return node_iterator(basic_tree_type::children.end(), this); }
+
+	// child element reverse iterator accessors
+	const_reverse_iterator rbegin() const {return const_reverse_iterator(end()); }
+	const_reverse_iterator rend() const {return const_reverse_iterator(begin()); }
+	reverse_iterator rbegin() {return reverse_iterator(end()); }
+	reverse_iterator rend() { return reverse_iterator(begin()); }
+
+	// child node reverse iterator accessors
+	const_reverse_node_iterator node_rbegin() const {return const_reverse_node_iterator(node_end()); }
+	const_reverse_node_iterator node_rend() const {return const_reverse_node_iterator(node_begin()); }
+	reverse_node_iterator node_rbegin() {return reverse_node_iterator(node_end()); }
+	reverse_node_iterator node_rend() { return reverse_node_iterator(node_begin()); }
+
+	// public interface
+	iterator find(const stored_type& value);
+	const_iterator find(const stored_type& value) const;
+	bool erase(const stored_type& value);
+	void erase(iterator it);
+	void erase(iterator it_beg, iterator it_end);
+	void clear();
+	typename basic_tree_type::size_type count(const stored_type& value) const;
+	iterator lower_bound(const stored_type& value);
+	const_iterator lower_bound(const stored_type& value) const;
+	iterator upper_bound(const stored_type& value);
+	const_iterator upper_bound(const stored_type& value) const;
+	std::pair<iterator, iterator> equal_range(const stored_type& value)
+	{
+		tree_type node_obj(value); // create a search node and search local children
+		iterator lower_it(basic_tree_type::children.lower_bound(&node_obj), this);
+		iterator upper_it(basic_tree_type::children.upper_bound(&node_obj), this);
+		return std::make_pair(lower_it, upper_it);
+	}
+	std::pair<const_iterator, const_iterator> equal_range(const stored_type& value) const
+	{
+		tree_type node_obj(value); // create a search node and search local children
+		const_iterator lower_it(basic_tree_type::children.lower_bound(&node_obj), this);
+		const_iterator upper_it(basic_tree_type::children.upper_bound(&node_obj), this);
+		return std::make_pair(lower_it, upper_it);
+	}
+
+protected:
+	iterator insert( const stored_type& value, tree_type* parent ) { return insert(end(), value, parent); }
+	iterator insert(const const_iterator& pos, const stored_type& value, tree_type* parent);
+	iterator insert(const tree_type& tree_obj, tree_type* parent) { return insert(end(), tree_obj, parent); }
+	iterator insert(const const_iterator pos, const tree_type& tree_obj, tree_type* parent);
+	void set(const tree_type& tree_obj, tree_type* parent);
+
+	// friends
+	#if defined(_MSC_VER) && _MSC_VER < 1300
+		friend class const_pre_order_descendant_iterator<stored_type, tree_type, container_type, associative_tree_type>;
+		friend class const_post_order_descendant_iterator<stored_type, tree_type, container_type, associative_tree_type>;
+		friend class const_level_order_descendant_iterator<stored_type, tree_type, container_type, associative_tree_type>;
+		friend class const_pre_order_descendant_node_iterator<stored_type, tree_type, container_type, associative_tree_type>;
+		friend class const_post_order_descendant_node_iterator<stored_type, tree_type, container_type, associative_tree_type>;
+		friend class const_level_order_descendant_node_iterator<stored_type, tree_type, container_type, associative_tree_type>;
+		friend bool operator == (const associative_tree_type& lhs, const associative_tree_type& rhs);
+		friend bool operator < (const associative_tree_type& lhs, const associative_tree_type& rhs);
+	#else 
+		template<typename T, typename U, typename V, typename W> friend class const_pre_order_descendant_iterator;
+		template<typename T, typename U, typename V, typename W> friend class const_post_order_descendant_iterator;
+		template<typename T, typename U, typename V, typename W> friend class const_level_order_descendant_iterator;
+		template<typename T, typename U, typename V, typename W> friend class const_pre_order_descendant_node_iterator;
+		template<typename T, typename U, typename V, typename W> friend class const_post_order_descendant_node_iterator;
+		template<typename T, typename U, typename V, typename W> friend class const_level_order_descendant_node_iterator;
+		friend bool operator ==<> (const associative_tree_type& lhs, const associative_tree_type& rhs);
+		friend bool operator < <> (const associative_tree_type& lhs, const associative_tree_type& rhs);
+	#endif
+};
+
+#include "associative_tree.inl"

+ 284 - 0
ModelIO/tcl_5.0.6/associative_tree.inl

@@ -0,0 +1,284 @@
+/*******************************************************************************
+Tree Container Library: Generic container library to store data in tree-like structures.
+Copyright (c) 2006  Mitchel Haas
+
+This software is provided 'as-is', without any express or implied warranty. 
+In no event will the author be held liable for any damages arising from 
+the use of this software.
+
+Permission is granted to anyone to use this software for any purpose, 
+including commercial applications, and to alter it and redistribute it freely, 
+subject to the following restrictions:
+
+1.	The origin of this software must not be misrepresented; 
+you must not claim that you wrote the original software. 
+If you use this software in a product, an acknowledgment in the product 
+documentation would be appreciated but is not required.
+
+2.	Altered source versions must be plainly marked as such, 
+and must not be misrepresented as being the original software.
+
+3.	The above copyright notice and this permission notice may not be removed 
+or altered from any source distribution.
+
+For complete documentation on this library, see http://www.datasoftsolutions.net
+Email questions, comments or suggestions to mhaas@datasoftsolutions.net
+*******************************************************************************/
+
+// find(const stored_type&)
+template< typename stored_type, typename tree_type, typename container_type >
+typename tcl::associative_tree<stored_type, tree_type, container_type>::iterator 
+tcl::associative_tree<stored_type, tree_type, container_type>::find(const stored_type& value) 
+{
+	tree_type node_obj(value); // create a search node and search local children
+	iterator it(basic_tree_type::children.find(&node_obj), this);
+	return it;
+}
+
+// find(const stored_type&) const
+template< typename stored_type, typename tree_type, typename container_type >
+typename tcl::associative_tree<stored_type, tree_type, container_type>::const_iterator 
+tcl::associative_tree<stored_type, tree_type, container_type>::find(const stored_type& value) const
+{
+	tree_type node_obj(value);
+	const_iterator it(basic_tree_type::children.find(&node_obj), this);
+	return it;
+}
+
+
+// erase(const stored_type&)
+template< typename stored_type, typename tree_type, typename container_type >
+bool tcl::associative_tree<stored_type, tree_type, container_type>::
+erase(const stored_type& value)
+{
+	bool erased_nodes = false;
+	tree_type node_obj(value); // create search node
+	typename container_type::iterator it = basic_tree_type::children.find(&node_obj);
+
+	while ( it != basic_tree_type::children.end() ) { // could be multiple nodes (with multitree)
+		deallocate_tree_type(*it); // delete node and remove from children
+		basic_tree_type::children.erase(it);  
+		it = basic_tree_type::children.find(&node_obj);  // any more?
+		erased_nodes = true;
+	}
+	return erased_nodes;
+}
+
+// count(const stored_type&)
+template< typename stored_type, typename tree_type, typename container_type >
+typename tcl::basic_tree<stored_type, tree_type, container_type>::size_type 
+tcl::associative_tree<stored_type, tree_type, container_type>::count(const stored_type& value) const
+{
+	const_iterator it = find(value);
+	const_iterator it_end = end();
+
+	typename basic_tree_type::size_type cnt = 0;
+
+	while (it != it_end && !(*it < value || value < *it)) {
+		++cnt;
+		++it;
+	}
+	return cnt;
+}
+
+// lower_bound(const stored_type&)
+template< typename stored_type, typename tree_type, typename container_type>
+typename tcl::associative_tree<stored_type, tree_type, container_type>::iterator
+tcl::associative_tree<stored_type, tree_type, container_type>::lower_bound(const stored_type& value)
+{
+	tree_type node_obj(value); // create a search node and search local children
+	iterator it(basic_tree_type::children.lower_bound(&node_obj), this);
+	return it;
+}
+
+// lower_bound(const stored_type&) const
+template< typename stored_type, typename tree_type, typename container_type>
+typename tcl::associative_tree<stored_type, tree_type, container_type>::const_iterator
+tcl::associative_tree<stored_type, tree_type, container_type>::lower_bound(const stored_type& value) const
+{
+	tree_type node_obj(value); // create a search node and search local children
+	const_iterator it(basic_tree_type::children.lower_bound(&node_obj), this);
+	return it;
+}
+
+// upper_bound(const stored_type&)
+template< typename stored_type, typename tree_type, typename container_type>
+typename tcl::associative_tree<stored_type, tree_type, container_type>::iterator
+tcl::associative_tree<stored_type, tree_type, container_type>::upper_bound(const stored_type& value)
+{
+	tree_type node_obj(value); // create a search node and search local children
+	iterator it(basic_tree_type::children.upper_bound(&node_obj), this);
+	return it;
+}
+
+// upper_bound(const stored_type&) const
+template< typename stored_type, typename tree_type, typename container_type>
+typename tcl::associative_tree<stored_type, tree_type, container_type>::const_iterator
+tcl::associative_tree<stored_type, tree_type, container_type>::upper_bound(const stored_type& value) const
+{
+	tree_type node_obj(value); // create a search node and search local children
+	const_iterator it(basic_tree_type::children.upper_bound(&node_obj), this);
+	return it;
+}
+
+// insert(iterator, const stored_type&, tree_type*)
+template< typename stored_type, typename tree_type, typename container_type>
+typename tcl::associative_tree<stored_type, tree_type, container_type>::iterator 
+tcl::associative_tree<stored_type, tree_type, container_type>::insert(const const_iterator& pos, const stored_type& value, tree_type* pParent)
+{
+	// create a new tree_type object to hold the node object
+	tree_type* pNew_node; 
+	basic_tree_type::allocate_tree_type(pNew_node, tree_type(value));
+	pNew_node->set_parent(pParent);
+
+	const typename basic_tree_type::size_type sz = basic_tree_type::children.size();
+
+	typename container_type::iterator children_pos;
+	if ( pos == pParent->end()) {
+		children_pos = basic_tree_type::children.end();
+	} else {
+		// get non-const iterator position from pos
+		children_pos = basic_tree_type::children.begin();
+		typename container_type::const_iterator const_children_pos = basic_tree_type::children.begin();
+		while ( const_children_pos != pos.it && const_children_pos != basic_tree_type::children.end()) {
+			++children_pos;
+			++const_children_pos;
+		}
+	}
+
+	// insert the tree node into the children container
+	const typename container_type::iterator it = basic_tree_type::children.insert(children_pos, pNew_node);
+
+	if ( sz == basic_tree_type::children.size() ) { // check for successful insertion
+		basic_tree_type::deallocate_tree_type(pNew_node);  // not successful.  delete new node and return end()
+		return iterator(basic_tree_type::children.end(), this);
+	}
+	return iterator(it, this);
+}
+
+// insert(iterator, const tree_type&, tree_type*)
+template< typename stored_type, typename tree_type, typename container_type>
+typename tcl::associative_tree<stored_type, tree_type, container_type>::iterator 
+tcl::associative_tree<stored_type, tree_type, container_type>::insert(const const_iterator pos, const tree_type& tree_obj, tree_type* pParent)
+{
+	// insert current node
+	iterator base_it = pParent->insert(pos, *tree_obj.get());
+
+	if ( base_it != pParent->end() ) {
+		const_iterator it = tree_obj.begin();
+		const const_iterator it_end = tree_obj.end();
+
+		// call this function recursively thru derived tree for children
+		for ( ; it != it_end; ++it )
+			base_it.node()->insert(*it.node());
+	}
+	return base_it;
+}
+
+// set(const tree_type&, tree_type*)
+template< typename stored_type, typename tree_type, typename container_type>
+void tcl::associative_tree<stored_type, tree_type, container_type>::set(const tree_type& tree_obj, tree_type* pParent)
+{
+	set(*tree_obj.get()); // set data for this node
+
+	const_iterator it = tree_obj.begin();
+	const const_iterator it_end = tree_obj.end();
+	for ( ; it != it_end; ++it ) { // and insert all descendants of passed tree
+		insert(*it.node(), pParent );
+	}
+}
+
+// clear()
+template< typename stored_type, typename tree_type, typename container_type>
+void tcl::associative_tree<stored_type, tree_type, container_type>::clear()
+{
+	iterator it = begin();
+	const iterator it_end = end();
+	for ( ; it != it_end; ++it )
+	{
+		basic_tree_type::deallocate_tree_type(it.node()); // delete all child nodes
+	}
+	basic_tree_type::children.clear();  // and remove them from set
+}
+
+// erase(iterator)
+template< typename stored_type, typename tree_type, typename container_type>
+void tcl::associative_tree<stored_type, tree_type, container_type>::erase(iterator it) 
+{ 
+	// check for node presence
+	if (it.pParent != this)
+		return;
+
+	// clear children
+	it.node()->clear(); 
+	deallocate_tree_type(it.node());
+
+	const iterator beg_it = begin();
+	typename container_type::iterator pos_it = basic_tree_type::children.begin();
+	for ( ; it != beg_it; --it, ++pos_it) ;  // get child iterator position
+
+	basic_tree_type::children.erase(pos_it);
+}
+
+// erase(iterator, iterator)
+template< typename stored_type, typename tree_type, typename container_type>
+void tcl::associative_tree<stored_type, tree_type, container_type>::erase(iterator it_beg, iterator it_end)
+{
+	while (it_beg != it_end) {
+		erase(it_beg++);
+	}
+}
+
+
+// operator ==
+template<typename stored_type, typename tree_type, typename container_type>
+bool tcl::operator == (const associative_tree<stored_type, tree_type, container_type>& lhs, const associative_tree<stored_type, tree_type, container_type>& rhs)
+{
+	// check this node
+	if ((*lhs.get() < *rhs.get()) || (*rhs.get() < *lhs.get()))
+		return false;
+
+	typename associative_tree<stored_type, tree_type, container_type>::const_iterator lhs_it = lhs.begin();
+	const typename associative_tree<stored_type, tree_type, container_type>::const_iterator lhs_end = lhs.end();
+	typename associative_tree<stored_type, tree_type, container_type>::const_iterator rhs_it = rhs.begin();
+	const typename associative_tree<stored_type, tree_type, container_type>::const_iterator rhs_end = rhs.end();
+
+	for ( ; lhs_it != lhs_end && rhs_it != rhs_end; ++lhs_it, ++rhs_it ) {
+		if (*lhs_it.node() != *rhs_it.node()) {
+			return false;
+		}
+	}
+
+	if (lhs_it != lhs.end() || rhs_it != rhs.end())
+		return false;
+
+	return true;
+}
+
+
+// operator <
+template<typename stored_type, typename tree_type, typename container_type>
+bool tcl::operator < (const associative_tree<stored_type, tree_type, container_type>& lhs, const associative_tree<stored_type, tree_type, container_type>& rhs) 
+{
+	// check this node
+	if (*lhs.get() < *rhs.get())
+		return true;
+
+	typename associative_tree<stored_type, tree_type, container_type>::const_iterator lhs_it = lhs.begin();
+	const typename associative_tree<stored_type, tree_type, container_type>::const_iterator lhs_end = lhs.end();
+	typename associative_tree<stored_type, tree_type, container_type>::const_iterator rhs_it = rhs.begin();
+	const typename associative_tree<stored_type, tree_type, container_type>::const_iterator rhs_end = rhs.end();
+
+	for ( ; lhs_it != lhs_end && rhs_it != rhs_end; ++lhs_it, ++rhs_it ) {
+		if (*lhs_it.node() < *rhs_it.node()) {
+			return true;
+		}
+	}
+
+	if (lhs.size() != rhs.size()) {
+		return lhs.size() < rhs.size();
+	}
+
+	return false;
+}
+

+ 107 - 0
ModelIO/tcl_5.0.6/basic_tree.h

@@ -0,0 +1,107 @@
+/*******************************************************************************
+Tree Container Library: Generic container library to store data in tree-like structures.
+Copyright (c) 2006  Mitchel Haas
+
+This software is provided 'as-is', without any express or implied warranty. 
+In no event will the author be held liable for any damages arising from 
+the use of this software.
+
+Permission is granted to anyone to use this software for any purpose, 
+including commercial applications, and to alter it and redistribute it freely, 
+subject to the following restrictions:
+
+1.	The origin of this software must not be misrepresented; 
+	you must not claim that you wrote the original software. 
+	If you use this software in a product, an acknowledgment in the product 
+	documentation would be appreciated but is not required.
+
+2.	Altered source versions must be plainly marked as such, 
+	and must not be misrepresented as being the original software.
+
+3.	The above copyright notice and this permission notice may not be removed 
+	or altered from any source distribution.
+
+For complete documentation on this library, see http://www.datasoftsolutions.net
+Email questions, comments or suggestions to mhaas@datasoftsolutions.net
+*******************************************************************************/
+#pragma once
+#include <set>
+#include <stack>
+#include <queue>
+#include <algorithm>
+#include <limits>
+
+namespace tcl 
+{
+	template<typename T, typename U, typename V> class basic_tree;
+}
+
+// stored_type:			type stored in container
+// tree_type:			one of three tree types derived from this base
+// container_type:		type of contain to hold children (can be set or multiset)
+
+template< typename stored_type, typename tree_type,  typename container_type >
+class tcl::basic_tree 
+{
+	public:
+	// typedefs
+		typedef basic_tree<stored_type, tree_type, container_type> basic_tree_type;
+		typedef stored_type* (*tClone_fcn) (const stored_type&);
+		typedef stored_type value_type;
+		typedef stored_type& reference;
+		typedef const stored_type& const_reference;
+		typedef size_t size_type;
+		typedef std::allocator<stored_type> allocator_type;
+
+		//typedef typename allocator_type::difference_type difference_type;
+		typedef typename std::allocator_traits<std::allocator<stored_type>>::difference_type difference_type;
+
+	protected:
+	// constructors/destructor
+		basic_tree() : pElement(0), pParent_node(0)  {}
+		explicit basic_tree(const stored_type& value);
+		basic_tree(const basic_tree_type& rhs);  // copy constructor
+		virtual ~basic_tree();
+
+	public:
+	// public interface
+		const stored_type* get() const { return pElement; }
+		stored_type* get() { return pElement; }
+		bool is_root() const { return pParent_node == 0; }
+		size_type size() const { return children.size(); }
+		size_type max_size() const { return (std::numeric_limits<int>().max)(); }
+		bool empty() const { return children.empty(); }
+		tree_type* parent() { return pParent_node; }
+		const tree_type* parent() const { return pParent_node; }
+		static void set_clone(const tClone_fcn& fcn) { pClone_fcn = fcn; }
+
+
+	protected:
+		void set_parent(tree_type* pParent) { pParent_node = pParent; }
+		basic_tree_type& operator = (const basic_tree_type& rhs); // assignment operator
+		void set(const stored_type& stored_obj);
+		void allocate_stored_type(stored_type*& element_ptr, const stored_type& value) 
+			{ element_ptr = stored_type_allocator.allocate(1,0); stored_type_allocator.construct(element_ptr, value); }
+		void deallocate_stored_type(stored_type* element_ptr) 
+			{ stored_type_allocator.destroy(element_ptr); stored_type_allocator.deallocate(element_ptr, 1); }
+		void allocate_tree_type(tree_type*& tree_ptr, const tree_type& tree_obj)
+			{ tree_ptr = tree_type_allocator.allocate(1,0); tree_type_allocator.construct(tree_ptr, tree_obj); }
+		void deallocate_tree_type(tree_type* tree_ptr)
+			{ tree_type_allocator.destroy(tree_ptr); tree_type_allocator.deallocate(tree_ptr, 1); }
+		
+	// data
+	protected:
+		container_type children;
+	private:
+		stored_type* pElement;   // data accessor
+		mutable tree_type* pParent_node;
+		static tClone_fcn pClone_fcn;
+		std::allocator<stored_type> stored_type_allocator;
+		//template <typename T>
+		//using stored_type_allocator = std::allocator_traits<std::allocator<T>>::allocator_type;
+		std::allocator<tree_type> tree_type_allocator;
+		//template <typename T>
+		//using tree_type_allocator = std::allocator_traits<std::allocator<T>>::allocator_type;
+};
+
+#include "basic_tree.inl"

+ 93 - 0
ModelIO/tcl_5.0.6/basic_tree.inl

@@ -0,0 +1,93 @@
+/*******************************************************************************
+Tree Container Library: Generic container library to store data in tree-like structures.
+Copyright (c) 2006  Mitchel Haas
+
+This software is provided 'as-is', without any express or implied warranty. 
+In no event will the author be held liable for any damages arising from 
+the use of this software.
+
+Permission is granted to anyone to use this software for any purpose, 
+including commercial applications, and to alter it and redistribute it freely, 
+subject to the following restrictions:
+
+1.	The origin of this software must not be misrepresented; 
+you must not claim that you wrote the original software. 
+If you use this software in a product, an acknowledgment in the product 
+documentation would be appreciated but is not required.
+
+2.	Altered source versions must be plainly marked as such, 
+and must not be misrepresented as being the original software.
+
+3.	The above copyright notice and this permission notice may not be removed 
+or altered from any source distribution.
+
+For complete documentation on this library, see http://www.datasoftsolutions.net
+Email questions, comments or suggestions to mhaas@datasoftsolutions.net
+*******************************************************************************/
+
+// static member variable definition
+template< typename stored_type, typename tree_type, typename container_type >
+typename tcl::basic_tree<stored_type, tree_type, container_type>::tClone_fcn
+tcl::basic_tree<stored_type, tree_type, container_type>::pClone_fcn = 0;
+
+// constructor
+template< typename stored_type, typename tree_type, typename container_type >
+tcl::basic_tree<stored_type, tree_type, container_type>::basic_tree(const stored_type& value) 
+:	children(container_type()), pElement(0), pParent_node(0), 
+	stored_type_allocator(std::allocator<stored_type>()), tree_type_allocator(std::allocator<tree_type>())
+{
+	// use clone function if available
+	if ( pClone_fcn )
+		pElement = pClone_fcn(value);
+	else
+		allocate_stored_type(pElement, value);
+}
+
+
+// copy constructor
+template< typename stored_type, typename tree_type, typename container_type >
+tcl::basic_tree<stored_type, tree_type, container_type>::basic_tree(const basic_tree_type& rhs) 
+:	children(container_type()), pElement(0), pParent_node(0), 
+	stored_type_allocator(std::allocator<stored_type>()), tree_type_allocator(std::allocator<tree_type>())
+{
+	pParent_node = 0; // new tree obj is always root node
+	set(*rhs.get()); // set data obj
+}
+
+// assignment operator
+template< typename stored_type, typename tree_type, typename container_type >
+tcl::basic_tree<stored_type, tree_type, container_type>& tcl::basic_tree<stored_type, tree_type, container_type>::operator = (const basic_tree_type& rhs)
+{
+	if ( &rhs == this )
+		return *this;
+
+	set(*rhs.get());  // set data obj
+
+	return *this;
+}
+
+// destructor
+template< typename stored_type, typename tree_type, typename container_type >
+tcl::basic_tree<stored_type, tree_type, container_type>::~basic_tree()
+{
+	deallocate_stored_type(pElement);
+}
+
+
+
+// set(stored_type&)
+template< typename stored_type, typename tree_type, typename container_type >
+void  tcl::basic_tree<stored_type, tree_type, container_type>::set(const stored_type& value) 
+{ 
+	if ( pElement ) // if data node already exists, free memory
+		deallocate_stored_type(pElement); 
+
+	if ( pClone_fcn )  // use clone fcn if available
+		pElement = pClone_fcn(value);
+	else
+		allocate_stored_type(pElement, value);
+}
+
+
+
+

+ 250 - 0
ModelIO/tcl_5.0.6/child_iterator.h

@@ -0,0 +1,250 @@
+/*******************************************************************************
+Tree Container Library: Generic container library to store data in tree-like structures.
+Copyright (c) 2006  Mitchel Haas
+
+This software is provided 'as-is', without any express or implied warranty. 
+In no event will the author be held liable for any damages arising from 
+the use of this software.
+
+Permission is granted to anyone to use this software for any purpose, 
+including commercial applications, and to alter it and redistribute it freely, 
+subject to the following restrictions:
+
+1.	The origin of this software must not be misrepresented; 
+you must not claim that you wrote the original software. 
+If you use this software in a product, an acknowledgment in the product 
+documentation would be appreciated but is not required.
+
+2.	Altered source versions must be plainly marked as such, 
+and must not be misrepresented as being the original software.
+
+3.	The above copyright notice and this permission notice may not be removed 
+or altered from any source distribution.
+
+For complete documentation on this library, see http://www.datasoftsolutions.net
+Email questions, comments or suggestions to mhaas@datasoftsolutions.net
+*******************************************************************************/
+#pragma once
+#include <set>
+#include <stack>
+#include <queue>
+#include <algorithm>
+#include <iterator>
+#include <iostream>
+
+namespace tcl 
+{
+	// forward declaration
+	template<typename T, typename U, typename V> class basic_tree;
+	template<typename T> class sequential_tree;
+	template<typename T, typename U, typename V> class associative_tree;
+	template<typename T, typename U, typename V> class associative_reverse_iterator;
+	template<typename T, typename U, typename V> class sequential_reverse_iterator;
+	template<typename T, typename U, typename V, typename W> class const_pre_order_descendant_iterator;
+	template<typename T, typename U, typename V, typename W> class const_post_order_descendant_iterator;
+
+	template<typename T, typename U, typename V> class const_associative_iterator;
+	template<typename T, typename U, typename V> class associative_iterator;
+	template<typename T, typename U, typename V> class const_sequential_iterator;
+	template<typename T, typename U, typename V> class sequential_iterator;
+
+	// comparison operators
+	template<typename T, typename U, typename V> bool operator == (const const_associative_iterator<T, U, V>& lhs, const const_associative_iterator<T, U, V>& rhs) { return lhs.pParent == rhs.pParent && lhs.it == rhs.it; }
+	template<typename T, typename U, typename V> bool operator != (const const_associative_iterator<T, U, V>& lhs, const const_associative_iterator<T, U, V>& rhs) { return !(lhs == rhs); }
+
+	template<typename T, typename U, typename V> bool operator == (const const_sequential_iterator<T, U, V>& lhs, const const_sequential_iterator<T, U, V>& rhs ) { return lhs.pParent == rhs.pParent && lhs.it == rhs.it; }
+	template<typename T, typename U, typename V> bool operator != (const const_sequential_iterator<T, U, V>& lhs, const const_sequential_iterator<T, U, V>& rhs ) { return !(lhs == rhs); }
+	template<typename T, typename U, typename V> bool operator < (const const_sequential_iterator<T, U, V>& lhs, const const_sequential_iterator<T, U, V>& rhs) { return lhs.it < rhs.it && lhs.pParent == rhs.pParent; }
+	template<typename T, typename U, typename V> bool operator <= (const const_sequential_iterator<T, U, V>& lhs, const const_sequential_iterator<T, U, V>& rhs) { return lhs < rhs || lhs == rhs; }
+	template<typename T, typename U, typename V> bool operator > (const const_sequential_iterator<T, U, V>& lhs, const const_sequential_iterator<T, U, V>& rhs) { return !(lhs <= rhs); }
+	template<typename T, typename U, typename V> bool operator >= (const const_sequential_iterator<T, U, V>& lhs, const const_sequential_iterator<T, U, V>& rhs) { return !(lhs < rhs); }
+
+}
+
+
+/************************************************************************/
+/* associative tree child iterators                                     */
+/************************************************************************/
+
+
+template<typename stored_type, typename tree_type, typename container_type>
+class tcl::const_associative_iterator : public std::iterator<std::bidirectional_iterator_tag, stored_type>
+{
+public:
+	// constructors/destructor
+	const_associative_iterator() : pParent(0) {}
+	virtual ~const_associative_iterator() {}
+protected:
+	explicit const_associative_iterator(typename container_type::const_iterator iter, const associative_tree<stored_type, tree_type, container_type>* pCalled_node) : it(iter), pParent(pCalled_node) {}
+	// copy constructor, and assignment operator will be compiler generated correctly
+
+public:
+	// overloaded operators
+	const stored_type& operator*() const { return  *(*it)->get(); }
+	const stored_type* operator->() const { return (*it)->get(); }
+
+	const_associative_iterator& operator ++() { ++it; return *this; }
+	const_associative_iterator operator ++(int) { const_associative_iterator old(*this); ++*this; return old; }
+	const_associative_iterator& operator --() { --it; return *this; }
+	const_associative_iterator operator --(int) { const_associative_iterator old(*this); --*this; return old; }
+
+	// public interface
+	const tree_type* node() const { return *it; }
+
+	// data
+protected:
+	typename container_type::const_iterator it;
+	const associative_tree<stored_type, tree_type, container_type>* pParent;
+
+	// friends
+	#if defined(_MSC_VER) && _MSC_VER < 1300
+		friend class basic_tree<stored_type, tree_type, container_type>;
+		friend class associative_tree<stored_type, tree_type, container_type>;
+		friend class const_pre_order_descendant_iterator<stored_type, tree_type, container_type, associative_tree<stored_type, tree_type, container_type> >;
+		friend class const_post_order_descendant_iterator<stored_type, tree_type, container_type, associative_tree<stored_type, tree_type, container_type> >;
+		friend bool operator == (const const_associative_iterator& lhs, const const_associative_iterator& rhs);
+	#else
+		template<typename T, typename U, typename V> friend class basic_tree;
+		template<typename T, typename U, typename V> friend class associative_tree;
+		template<typename T, typename U, typename V, typename W> friend class const_pre_order_descendant_iterator;
+		template<typename T, typename U, typename V, typename W> friend class const_post_order_descendant_iterator;
+		friend bool operator ==<> (const const_associative_iterator& lhs, const const_associative_iterator& rhs);
+	#endif
+};
+
+template<typename stored_type, typename tree_type, typename container_type>
+class tcl::associative_iterator : public tcl::const_associative_iterator<stored_type, tree_type, container_type>
+{
+private:
+public:
+	// constructors/destructor
+	associative_iterator() : const_associative_iterator<stored_type, tree_type, container_type>() {}
+private:
+	explicit associative_iterator(typename container_type::iterator iter, associative_tree<stored_type, tree_type, container_type>* pCalled_node) : const_associative_iterator<stored_type, tree_type, container_type>(iter, pCalled_node) {}
+	// destructor, copy constructor, and assignment operator will be compiler generated correctly
+
+public:
+	// overloaded operators
+	stored_type& operator*() const { return *(*it)->get(); }
+	stored_type* operator->() const { return (*it)->get(); }
+	associative_iterator& operator ++() { ++it;  return *this; }
+	associative_iterator operator ++(int) { associative_iterator old(*this); ++*this; return old; }
+	associative_iterator& operator --() { --it; return *this; }
+	associative_iterator operator --(int) { associative_iterator old(*this); --*this; return old; }
+
+	tree_type* node() const 
+	{ 
+		return *it; 
+	}
+
+	// friends
+	using const_associative_iterator<stored_type, tree_type, container_type>::it;
+	#if defined(_MSC_VER) && _MSC_VER < 1300
+		friend class associative_tree<stored_type, tree_type, container_type>;
+		friend class associative_reverse_iterator<stored_type, tree_type, container_type>;
+	#else
+		template<typename T, typename U, typename V> friend class associative_tree;
+		template<typename T, typename U, typename V> friend class associative_reverse_iterator;
+	#endif
+};
+
+/************************************************************************/
+/* sequential tree child iterators                                      */
+/************************************************************************/
+
+
+template<typename stored_type, typename tree_type, typename container_type>
+class tcl::const_sequential_iterator : public std::iterator<std::random_access_iterator_tag, stored_type>
+{
+public:
+	// constructors/destructor
+	const_sequential_iterator() : pParent(0) {}
+	virtual ~const_sequential_iterator() {}
+protected:
+	explicit const_sequential_iterator(typename container_type::const_iterator iter, const tree_type* pCalled_node) : it(iter), pParent(pCalled_node) {}
+	// copy constructor, and assignment operator will be compiler generated correctly
+
+public:
+	// typedefs
+	typedef size_t size_type;
+	#if defined(_MSC_VER) && _MSC_VER < 1300
+		typedef std::iterator_traits<std::iterator<std::random_access_iterator_tag, stored_type> >::distance_type difference_type;
+	#else
+		typedef typename std::iterator_traits<const_sequential_iterator>::difference_type difference_type;
+	#endif
+
+	// overloaded operators
+	const stored_type& operator*() const { return  *(*it)->get(); }
+	const stored_type* operator->() const { return (*it)->get(); }
+
+	const_sequential_iterator& operator ++() { ++it; return *this; }
+	const_sequential_iterator operator ++(int) { const_sequential_iterator old(*this); ++*this; return old; }
+	const_sequential_iterator& operator --() { --it; return *this; }
+	const_sequential_iterator operator --(int) { const_sequential_iterator old(*this); --*this; return old; }
+	const_sequential_iterator& operator +=(difference_type n) { it += n; return *this; }
+	const_sequential_iterator& operator -=(difference_type n) { it -= n; return *this; }
+	difference_type operator -(const const_sequential_iterator& rhs) const { return it - rhs.it; }
+	const tree_type* node() const { return *it; }
+
+	// data
+protected:
+	typename container_type::const_iterator it;
+	const tree_type* pParent;
+
+	// friends 
+	#if defined(_MSC_VER) && _MSC_VER < 1300
+		friend class sequential_tree<stored_type>;
+		friend class const_pre_order_descendant_iterator<stored_type, tree_type, container_type, sequential_tree<stored_type> >;
+		friend class const_post_order_descendant_iterator<stored_type, tree_type, container_type, sequential_tree<stored_type> >;
+		friend bool operator == (const const_sequential_iterator& lhs, const const_sequential_iterator& rhs );
+		friend bool operator <  (const const_sequential_iterator& lhs, const const_sequential_iterator& rhs);
+	#else
+		friend bool operator ==<> (const const_sequential_iterator& lhs, const const_sequential_iterator& rhs );
+		friend bool operator < <> (const const_sequential_iterator& lhs, const const_sequential_iterator& rhs);
+		template<typename T> friend class sequential_tree;
+		template<typename T, typename U, typename V, typename W> friend class const_pre_order_descendant_iterator;
+		template<typename T, typename U, typename V, typename W> friend class const_post_order_descendant_iterator;
+	#endif
+};
+
+
+
+
+template<typename stored_type, typename tree_type, typename container_type>
+class tcl::sequential_iterator : public tcl::const_sequential_iterator<stored_type, tree_type, container_type>
+{
+public:
+	// constructors/destructor
+	sequential_iterator() : const_sequential_iterator<stored_type, tree_type, container_type>() {}
+private:
+	explicit sequential_iterator(const typename container_type::iterator& iter, const tree_type* const pCalled_node) : const_sequential_iterator<stored_type, tree_type, container_type>(iter, pCalled_node) {}
+	// destructor, copy constructor, and assignment operator will be compiler generated correctly
+
+public:
+	// overloaded operators
+	stored_type& operator*() const { return *(*it)->get(); }
+	stored_type* operator->() const { return (*it)->get(); }
+	sequential_iterator& operator ++() { ++it;  return *this; }
+	sequential_iterator operator ++(int) { sequential_iterator old(*this); ++*this; return old; }
+	sequential_iterator& operator --() { --it; return *this; }
+	sequential_iterator operator --(int) { sequential_iterator old(*this); --*this; return old; }
+	tree_type* node() const { return *it; }
+
+	// friends
+	using const_sequential_iterator<stored_type, tree_type, container_type>::it;
+	#if defined(_MSC_VER) && _MSC_VER < 1300
+		friend class sequential_tree<stored_type>;
+		friend class sequential_reverse_iterator<stored_type, tree_type, container_type>;
+	#else
+		template<typename T> friend class sequential_tree;
+		template<typename T, typename U, typename V> friend class sequential_reverse_iterator;
+	#endif
+};
+
+
+
+
+
+
+
+

+ 225 - 0
ModelIO/tcl_5.0.6/child_node_iterator.h

@@ -0,0 +1,225 @@
+/*******************************************************************************
+Tree Container Library: Generic container library to store data in tree-like structures.
+Copyright (c) 2006  Mitchel Haas
+
+This software is provided 'as-is', without any express or implied warranty. 
+In no event will the author be held liable for any damages arising from 
+the use of this software.
+
+Permission is granted to anyone to use this software for any purpose, 
+including commercial applications, and to alter it and redistribute it freely, 
+subject to the following restrictions:
+
+1.	The origin of this software must not be misrepresented; 
+you must not claim that you wrote the original software. 
+If you use this software in a product, an acknowledgment in the product 
+documentation would be appreciated but is not required.
+
+2.	Altered source versions must be plainly marked as such, 
+and must not be misrepresented as being the original software.
+
+3.	The above copyright notice and this permission notice may not be removed 
+or altered from any source distribution.
+
+For complete documentation on this library, see http://www.datasoftsolutions.net
+Email questions, comments or suggestions to mhaas@datasoftsolutions.net
+*******************************************************************************/
+#pragma once
+#include <set>
+#include <stack>
+#include <queue>
+#include <algorithm>
+#include <iterator>
+
+namespace tcl 
+{
+	// forward declaration
+	template<typename stored_type, typename tree_type, typename container_type> class basic_tree;
+	template<typename stored_type> class sequential_tree;
+	template<typename stored_type, typename tree_type, typename container_type> class associative_tree;
+	template<typename stored_type, typename tree_type, typename container_type> class associative_reverse_iterator;
+	template<typename stored_type, typename tree_type, typename container_type> class sequential_reverse_iterator;
+	template<typename stored_type, typename tree_type, typename container_type> class associative_reverse_node_iterator;
+	template<typename stored_type, typename tree_type, typename container_type> class sequential_reverse_node_iterator;
+
+	template<typename T, typename U, typename V> class const_associative_node_iterator;
+	template<typename T, typename U, typename V> class associative_node_iterator;
+	template<typename T, typename U, typename V> class const_sequential_node_iterator;
+	template<typename T, typename U, typename V> class sequential_node_iterator;
+
+	// comparison operators
+	template<typename T, typename U, typename V> bool operator == (const const_associative_node_iterator<T, U, V>& lhs, const const_associative_node_iterator<T, U, V>& rhs ) { return lhs.pParent == rhs.pParent && lhs.it == rhs.it; }
+	template<typename T, typename U, typename V> bool operator != (const const_associative_node_iterator<T, U, V>& lhs, const const_associative_node_iterator<T, U, V>& rhs ) { return !(lhs == rhs); }
+
+	template<typename T, typename U, typename V> bool operator == (const const_sequential_node_iterator<T, U, V>& lhs, const const_sequential_node_iterator<T, U, V>& rhs) { return lhs.pParent == rhs.pParent && lhs.it == rhs.it; }
+	template<typename T, typename U, typename V> bool operator != (const const_sequential_node_iterator<T, U, V>& lhs, const const_sequential_node_iterator<T, U, V>& rhs) { return !(lhs == rhs); }
+	template<typename T, typename U, typename V> bool operator < (const const_sequential_node_iterator<T, U, V>& lhs, const const_sequential_node_iterator<T, U, V>& rhs) { return lhs.it < rhs.it && lhs.pParent == rhs.pParent; }
+	template<typename T, typename U, typename V> bool operator <= (const const_sequential_node_iterator<T, U, V>& lhs, const const_sequential_node_iterator<T, U, V>& rhs) { return lhs <= rhs || lhs == rhs; }
+	template<typename T, typename U, typename V> bool operator > (const const_sequential_node_iterator<T, U, V>& lhs, const const_sequential_node_iterator<T, U, V>& rhs) { return !(lhs <= rhs); }
+	template<typename T, typename U, typename V> bool operator >= (const const_sequential_node_iterator<T, U, V>& lhs, const const_sequential_node_iterator<T, U, V>& rhs) { return !(lhs < rhs); }
+}
+
+
+/************************************************************************/
+/* associative tree child node iterators                                */
+/************************************************************************/
+
+
+template<typename stored_type, typename tree_type, typename container_type>
+class tcl::const_associative_node_iterator : public std::iterator<std::bidirectional_iterator_tag, tree_type>
+{
+private:
+public:
+	// constructors/destructor
+	const_associative_node_iterator() : pParent(0) {}
+	explicit const_associative_node_iterator(typename container_type::const_iterator iter, const associative_tree<stored_type, tree_type, container_type>* pCalled_node) : it(iter), pParent(pCalled_node) {}
+	// destructor, copy constructor, and assignment operator will be compiler generated correctly
+
+	// overloaded operators
+	const tree_type& operator*() const { return  *(*it); }
+	const tree_type* operator->() const { return *it; }
+
+	const_associative_node_iterator& operator ++() { ++it; return *this; }
+	const_associative_node_iterator operator ++(int) { const_associative_node_iterator old(*this); ++*this; return old; }
+	const_associative_node_iterator& operator --() { --it; return *this; }
+	const_associative_node_iterator operator --(int) { const_associative_node_iterator old(*this); --*this; return old; }
+
+	// data
+protected:
+	typename container_type::const_iterator it;
+	const associative_tree<stored_type, tree_type, container_type>* pParent;
+
+	// friends
+	#if defined(_MSC_VER) && _MSC_VER < 1300
+		friend class basic_tree<stored_type, tree_type, container_type>;
+		friend class associative_tree<stored_type, tree_type, container_type>;
+		friend bool operator == (const const_associative_node_iterator& lhs, const const_associative_node_iterator& rhs );
+	#else
+		template<typename T, typename U, typename V> friend class basic_tree;
+		template<typename T, typename U, typename V> friend class associative_tree;
+		friend bool operator ==<> (const const_associative_node_iterator& lhs, const const_associative_node_iterator& rhs );
+	#endif
+};
+
+template<typename stored_type, typename tree_type, typename container_type>
+class tcl::associative_node_iterator : public tcl::const_associative_node_iterator<stored_type, tree_type, container_type>
+{
+public:
+	// constructors/destructor
+	associative_node_iterator() : const_associative_node_iterator<stored_type, tree_type, container_type>() {}
+	explicit associative_node_iterator(typename container_type::iterator iter, associative_tree<stored_type, tree_type, container_type>* pCalled_node) : const_associative_node_iterator<stored_type, tree_type, container_type>(iter, pCalled_node) {}
+	// destructor, copy constructor, and assignment operator will be compiler generated correctly
+
+	// overloaded operators
+	tree_type& operator*() const { return *(*it); }
+	tree_type* operator->() const { return *it; }
+	associative_node_iterator& operator ++() { ++it;  return *this; }
+	associative_node_iterator operator ++(int) { associative_node_iterator old(*this); ++*this; return old; }
+	associative_node_iterator& operator --() { --it; return *this; }
+	associative_node_iterator operator --(int) { associative_node_iterator old(*this); --*this; return old; }
+
+	// friends
+	using const_associative_node_iterator<stored_type, tree_type, container_type>::it;
+	#if defined(_MSC_VER) && _MSC_VER < 1300
+		friend class associative_tree<stored_type, tree_type, container_type>;
+		friend class associative_reverse_node_iterator<stored_type, tree_type, container_type>;
+	#else
+		template<typename T, typename U, typename V> friend class associative_tree;
+		template<typename T, typename U, typename V> friend class associative_reverse_node_iterator;
+	#endif
+};
+
+/************************************************************************/
+/* sequential tree child iterators                                      */
+/************************************************************************/
+
+template<typename stored_type, typename tree_type, typename container_type>
+class tcl::const_sequential_node_iterator : public std::iterator<std::random_access_iterator_tag, tree_type>
+{
+public:
+
+	// constructors/destructor
+	const_sequential_node_iterator() : pParent(0) {}
+	explicit const_sequential_node_iterator(typename container_type::const_iterator it_, const tree_type* pParent_) : it(it_), pParent(pParent_) {}
+	virtual ~const_sequential_node_iterator() {}
+	// copy constructor, and assignment operator will be compiler generated correctly
+
+	// typedefs
+	typedef size_t size_type;
+	#if defined(_MSC_VER) && _MSC_VER < 1300
+		typedef std::iterator_traits<std::iterator<std::random_access_iterator_tag, tree_type> >::distance_type difference_type;
+	#else
+		typedef typename std::iterator_traits<const_sequential_node_iterator>::difference_type difference_type;
+	#endif
+
+	// overloaded operators
+	const tree_type& operator*() const { return  *(*it); }
+	const tree_type* operator->() const { return *it; }
+
+	const_sequential_node_iterator& operator ++() { ++it; return *this; }
+	const_sequential_node_iterator operator ++(int) { const_sequential_node_iterator old(*this); ++*this; return old; }
+	const_sequential_node_iterator& operator --() { --it; return *this; }
+	const_sequential_node_iterator operator --(int) { const_sequential_node_iterator old(*this); --*this; return old; }
+	const_sequential_node_iterator& operator +=(size_type n) { it += n; return *this; }
+	const_sequential_node_iterator& operator -=(size_type n) { it -= n; return *this; }
+	difference_type operator -(const const_sequential_node_iterator& rhs) const { return it - rhs.it; }
+
+	// data
+protected:
+	typename container_type::const_iterator it;
+	const tree_type* pParent;
+
+	// friends 
+	#if defined(_MSC_VER) && _MSC_VER < 1300
+		friend class sequential_tree<stored_type>;
+		friend bool operator == (const const_sequential_node_iterator& lhs, const const_sequential_node_iterator& rhs);
+		friend bool operator < (const const_sequential_node_iterator& lhs, const const_sequential_node_iterator& rhs);
+	#else
+		template<typename T> friend class sequential_tree;
+		friend bool operator ==<> (const const_sequential_node_iterator& lhs, const const_sequential_node_iterator& rhs);
+		friend bool operator < <> (const const_sequential_node_iterator& lhs, const const_sequential_node_iterator& rhs);
+	#endif
+};
+
+
+
+
+template<typename stored_type, typename tree_type, typename container_type>
+class tcl::sequential_node_iterator : public tcl::const_sequential_node_iterator<stored_type, tree_type, container_type>
+{
+private:
+public:
+	// constructors/destructor
+	sequential_node_iterator() : const_sequential_node_iterator<stored_type, tree_type, container_type>() {}
+	explicit sequential_node_iterator(typename container_type::iterator it_, tree_type* pParent_) : const_sequential_node_iterator<stored_type, tree_type, container_type>(it_, pParent_) {}
+	// destructor, copy constructor, and assignment operator will be compiler generated correctly
+
+	// overloaded operators
+	tree_type& operator*() const { return *(*it); }
+	tree_type* operator->() const { return *it; }
+	sequential_node_iterator& operator ++() { ++it;  return *this; }
+	sequential_node_iterator operator ++(int) { sequential_node_iterator old(*this); ++*this; return old; }
+	sequential_node_iterator& operator --() { --it; return *this; }
+	sequential_node_iterator operator --(int) { sequential_node_iterator old(*this); --*this; return old; }
+
+	// public interface
+	tree_type* node() const { return *it; }
+
+	// friends
+	using const_sequential_node_iterator<stored_type, tree_type, container_type>::it;
+#if defined(_MSC_VER) && _MSC_VER < 1300
+	friend class sequential_tree<stored_type>;
+	friend class sequential_reverse_node_iterator<stored_type, tree_type, container_type>;
+#else
+	template<typename T> friend class sequential_tree;
+	template<typename T, typename U, typename V> friend class sequential_reverse_node_iterator;
+#endif
+};
+
+
+
+
+
+
+
+

+ 308 - 0
ModelIO/tcl_5.0.6/descendant_iterator.h

@@ -0,0 +1,308 @@
+/*******************************************************************************
+Tree Container Library: Generic container library to store data in tree-like structures.
+Copyright (c) 2006  Mitchel Haas
+
+This software is provided 'as-is', without any express or implied warranty. 
+In no event will the author be held liable for any damages arising from 
+the use of this software.
+
+Permission is granted to anyone to use this software for any purpose, 
+including commercial applications, and to alter it and redistribute it freely, 
+subject to the following restrictions:
+
+1.	The origin of this software must not be misrepresented; 
+you must not claim that you wrote the original software. 
+If you use this software in a product, an acknowledgment in the product 
+documentation would be appreciated but is not required.
+
+2.	Altered source versions must be plainly marked as such, 
+and must not be misrepresented as being the original software.
+
+3.	The above copyright notice and this permission notice may not be removed 
+or altered from any source distribution.
+
+For complete documentation on this library, see http://www.datasoftsolutions.net
+Email questions, comments or suggestions to mhaas@datasoftsolutions.net
+*******************************************************************************/
+#pragma once
+#include "child_iterator.h"
+#include <set>
+#include <stack>
+#include <queue>
+#include <algorithm>
+
+namespace tcl 
+{
+	template<typename T, typename U, typename V, typename W> class const_pre_order_descendant_iterator;
+	template<typename T, typename U, typename V, typename W> class pre_order_descendant_iterator;
+	template<typename T, typename U, typename V, typename W> class const_post_order_descendant_iterator;
+	template<typename T, typename U, typename V, typename W> class post_order_descendant_iterator;
+	template<typename T, typename U, typename V, typename W> class const_level_order_descendant_iterator;
+	template<typename T, typename U, typename V, typename W> class level_order_descendant_iterator;
+	template<typename T, typename U> class tree;
+	template<typename T, typename U> class multitree;
+	template<typename T, typename U, typename V> class unique_tree;
+
+	// comparison operators
+	template<typename T, typename U, typename V, typename W> bool operator == (const const_pre_order_descendant_iterator<T, U, V, W>& lhs, const const_pre_order_descendant_iterator<T, U, V, W>& rhs ) { return lhs.it == rhs.it && lhs.at_top == rhs.at_top; }
+	template<typename T, typename U, typename V, typename W> bool operator != (const const_pre_order_descendant_iterator<T, U, V, W>& lhs, const const_pre_order_descendant_iterator<T, U, V, W>& rhs ) { return !(lhs == rhs); }
+	template<typename T, typename U, typename V, typename W> bool operator == ( const const_post_order_descendant_iterator<T, U, V, W>& lhs, const const_post_order_descendant_iterator<T, U, V, W>& rhs ) { return lhs.it == rhs.it && lhs.at_top == rhs.at_top; }
+	template<typename T, typename U, typename V, typename W> bool operator != ( const const_post_order_descendant_iterator<T, U, V, W>& lhs, const const_post_order_descendant_iterator<T, U, V, W>& rhs ) { return !(lhs == rhs); }
+	template<typename T, typename U, typename V, typename W> bool operator == (const const_level_order_descendant_iterator<T, U, V, W>& lhs, const const_level_order_descendant_iterator<T, U, V, W>& rhs) { return lhs.it == rhs.it && lhs.at_top == rhs.at_top; }
+	template<typename T, typename U, typename V, typename W> bool operator != (const const_level_order_descendant_iterator<T, U, V, W>& lhs, const const_level_order_descendant_iterator<T, U, V, W>& rhs) { return !(lhs == rhs); }
+}
+
+
+/************************************************************************/
+/* descendant iterators                                                 */
+/************************************************************************/
+
+template<typename stored_type, typename tree_type, typename container_type, typename tree_category_type>
+class tcl::const_pre_order_descendant_iterator : public std::iterator<std::bidirectional_iterator_tag, stored_type>
+{
+public:
+	// constructors/destructor
+	const_pre_order_descendant_iterator() : pTop_node(0), at_top(false) {}
+	virtual ~const_pre_order_descendant_iterator() {}
+	//  copy constructor, and assignment operator will be compiler generated correctly
+protected:
+	explicit const_pre_order_descendant_iterator(const tree_type* pCalled_node, bool beg) : it(beg ? pCalled_node->begin() : pCalled_node->end()), pTop_node(pCalled_node), at_top(beg) {}
+
+public:
+	// overloaded operators
+	const_pre_order_descendant_iterator& operator ++(); 
+	const_pre_order_descendant_iterator operator ++(int) { const_pre_order_descendant_iterator old(*this); ++*this; return old; }
+	const_pre_order_descendant_iterator& operator --();
+	const_pre_order_descendant_iterator operator --(int) { const_pre_order_descendant_iterator old(*this); --*this; return old; }
+
+	// public interface
+	const stored_type& operator*() const { return  at_top ? *pTop_node->get() : it.operator *(); }
+	const stored_type* operator->() const { return at_top ? pTop_node->get() : it.operator ->(); }
+	const tree_type* node() const { return at_top ? pTop_node : it.node(); }
+
+	// data
+protected:
+	typename tree_category_type::const_iterator it;
+	std::stack<typename tree_category_type::const_iterator> node_stack;   
+	const tree_type* pTop_node;
+	typename container_type::const_reverse_iterator rit;
+	bool at_top;
+
+	// friends
+	#if defined(_MSC_VER) && _MSC_VER < 1300
+    typedef tree_type tr_type;
+		friend typename tr_type;
+		friend class sequential_tree<stored_type>;
+		friend bool operator == (const const_pre_order_descendant_iterator& lhs, const const_pre_order_descendant_iterator& rhs );
+	#else
+		template<typename T, typename U> friend class tree;
+		template<typename T, typename U> friend class multitree;
+		template<typename T, typename U, typename V> friend class unique_tree;
+		template<typename T> friend class sequential_tree;
+		friend bool operator ==<> (const const_pre_order_descendant_iterator& lhs, const const_pre_order_descendant_iterator& rhs );
+	#endif
+};
+
+template<typename stored_type, typename tree_type, typename container_type, typename tree_category_type>
+class tcl::pre_order_descendant_iterator : public tcl::const_pre_order_descendant_iterator<stored_type, tree_type, container_type, tree_category_type>
+{
+public:
+	// constructors/destructor
+	pre_order_descendant_iterator() : const_pre_order_descendant_iterator<stored_type, tree_type, container_type, tree_category_type>() {}
+	// destructor, copy constructor, and assignment operator will be compiler generated correctly
+protected:
+	explicit pre_order_descendant_iterator(const tree_type* const pCalled_node, bool beg) : const_pre_order_descendant_iterator<stored_type, tree_type, container_type, tree_category_type>(pCalled_node, beg) {}
+
+public:
+	// overloaded operators
+	pre_order_descendant_iterator& operator ++() { ++(*static_cast<const_pre_order_descendant_iterator<stored_type, tree_type, container_type, tree_category_type>*>(this)); return *this; }
+	pre_order_descendant_iterator operator ++(int) { pre_order_descendant_iterator old(*this); ++*this; return old; }
+	pre_order_descendant_iterator& operator --() { --(*static_cast<const_pre_order_descendant_iterator<stored_type, tree_type, container_type, tree_category_type>*>(this)); return *this; }
+	pre_order_descendant_iterator operator --(int) { pre_order_descendant_iterator old(*this); --*this; return old; }
+
+	// public interface
+	stored_type& operator*() const { return at_top ? const_cast<stored_type&>(*pTop_node->get()) : const_cast<stored_type&>(it.operator *()); }
+	stored_type* operator->() const { return at_top ? const_cast<stored_type*>(pTop_node->get()) : const_cast<stored_type*>(it.operator ->()); }
+	tree_type* node() const { return at_top ? const_cast<tree_type*>(pTop_node) : const_cast<tree_type*>(it.node()); }
+
+	// friends
+	using const_pre_order_descendant_iterator<stored_type, tree_type, container_type, tree_category_type>::it;
+	using const_pre_order_descendant_iterator<stored_type, tree_type, container_type, tree_category_type>::pTop_node;
+	using const_pre_order_descendant_iterator<stored_type, tree_type, container_type, tree_category_type>::at_top;
+	#if defined(_MSC_VER) && _MSC_VER < 1300
+    typedef tree_type tr_type;
+		friend typename tr_type;
+		friend class sequential_tree<stored_type>;
+	#else
+		template<typename T, typename U> friend class tree;
+		template<typename T, typename U> friend class multitree;
+		template<typename T, typename U, typename V> friend class unique_tree;
+		template<typename T> friend class sequential_tree;
+	#endif
+};
+
+template<typename stored_type, typename tree_type, typename container_type, typename tree_category_type>
+class tcl::const_post_order_descendant_iterator : public std::iterator<std::bidirectional_iterator_tag, stored_type>
+{
+public:
+	// constructors/destructor
+	const_post_order_descendant_iterator() : pTop_node(0) {}
+	virtual ~const_post_order_descendant_iterator() {}
+	// copy constructor, and assignment operator will be compiler generated correctly
+protected:
+	explicit const_post_order_descendant_iterator(const tree_type* pCalled_node, bool beg); 
+
+public:
+	// overloaded operators
+	const_post_order_descendant_iterator& operator ++(); 
+	const_post_order_descendant_iterator operator ++(int) { const_post_order_descendant_iterator old(*this); ++*this; return old; }
+	const_post_order_descendant_iterator& operator --(); 
+	const_post_order_descendant_iterator operator --(int) { const_post_order_descendant_iterator old(*this); --*this; return old; }
+
+	// public interface
+	const stored_type& operator*() const { return at_top ? *pTop_node->get() : it.operator *(); }
+	const stored_type* operator->() const { return at_top ? pTop_node->get() : it.operator ->(); }
+	const tree_type* node() const { return at_top ? pTop_node : it.node(); }
+
+	// data
+protected:
+	std::stack<typename tree_category_type::const_iterator > node_stack;   
+	typename tree_category_type::const_iterator it;
+	const tree_type* pTop_node;
+	typename container_type::const_reverse_iterator rit;
+	bool at_top;
+
+	// friends
+	#if defined(_MSC_VER) && _MSC_VER < 1300
+		friend class sequential_tree<stored_type>;
+    typedef tree_type tr_type;
+		friend typename tr_type;
+		friend bool operator == ( const const_post_order_descendant_iterator& lhs, const const_post_order_descendant_iterator& rhs );
+	#else
+		template<typename T> friend class sequential_tree;
+		template<typename T, typename U> friend class tree;
+		template<typename T, typename U> friend class multitree;
+		template<typename T, typename U, typename V> friend class unique_tree;
+		friend bool operator ==<> ( const const_post_order_descendant_iterator& lhs, const const_post_order_descendant_iterator& rhs );
+	#endif
+};
+
+template<typename stored_type, typename tree_type, typename container_type, typename tree_category_type>
+class tcl::post_order_descendant_iterator : public tcl::const_post_order_descendant_iterator<stored_type, tree_type, container_type, tree_category_type>
+{
+public:
+	// constructors/destructor
+	post_order_descendant_iterator() : const_post_order_descendant_iterator<stored_type, tree_type, container_type, tree_category_type>() {}
+	// destructor, copy constructor, and assignment operator will be compiler generated correctly
+protected:
+	explicit post_order_descendant_iterator(const tree_type* pCalled_node, bool beg) : const_post_order_descendant_iterator<stored_type, tree_type, container_type, tree_category_type>(pCalled_node, beg) { }
+
+public:
+	// overloaded operators
+	post_order_descendant_iterator& operator ++() { ++(*static_cast<const_post_order_descendant_iterator<stored_type, tree_type, container_type, tree_category_type>*>(this)); return *this; }
+	post_order_descendant_iterator operator ++(int) { post_order_descendant_iterator old(*this); ++*this; return old; }
+	post_order_descendant_iterator& operator --() { --(*static_cast<const_post_order_descendant_iterator<stored_type, tree_type, container_type, tree_category_type>*>(this)); return *this; }
+	post_order_descendant_iterator operator --(int) { post_order_descendant_iterator old(*this); --*this; return old; }
+
+	// public interface
+	stored_type& operator*() const { return at_top ? const_cast<stored_type&>(*pTop_node->get()) : const_cast<stored_type&>(it.operator *()); }
+	stored_type* operator->() const { return at_top ? const_cast<stored_type*>(pTop_node->get()) : const_cast<stored_type*>(it.operator ->()); }
+	tree_type* node() const { return at_top ? const_cast<tree_type*>(pTop_node) : const_cast<tree_type*>(it.node()); }
+
+	// friends
+	using const_post_order_descendant_iterator<stored_type, tree_type, container_type, tree_category_type>::it;
+	using const_post_order_descendant_iterator<stored_type, tree_type, container_type, tree_category_type>::pTop_node;
+	using const_post_order_descendant_iterator<stored_type, tree_type, container_type, tree_category_type>::at_top;
+	#if defined(_MSC_VER) && _MSC_VER < 1300
+    typedef tree_type tr_type;
+		friend typename tr_type;
+		friend class sequential_tree<stored_type>;
+	#else
+		template<typename T, typename U> friend class tree;
+		template<typename T, typename U> friend class multitree;
+		template<typename T, typename U, typename V> friend class unique_tree;
+		template<typename T> friend class sequential_tree;
+	#endif
+};
+
+template<typename stored_type, typename tree_type, typename container_type, typename tree_category_type>
+class tcl::const_level_order_descendant_iterator : public std::iterator<std::forward_iterator_tag, stored_type>
+{
+public:
+	// constructors/destructor
+	const_level_order_descendant_iterator() : pTop_node(0), at_top(false) {}
+	virtual ~const_level_order_descendant_iterator() {}
+	// copy constructor, and assignment operator will be compiler generated correctly
+protected:
+	explicit const_level_order_descendant_iterator(const tree_type* pCalled_node, bool beg) : it(beg ? pCalled_node->begin() : pCalled_node->end()), pTop_node(pCalled_node), at_top(beg) {}
+
+public:
+	// overloaded operators
+	const_level_order_descendant_iterator& operator ++();
+	const_level_order_descendant_iterator operator ++(int) { const_level_order_descendant_iterator old(*this); ++*this; return old; }
+
+	// public interface
+	const stored_type& operator*() const { return at_top ? *pTop_node->get() : it.operator *(); }
+	const stored_type* operator->() const { return at_top ? pTop_node->get() : it.operator ->(); }
+	const tree_type* node() const { return at_top ? pTop_node : it.node(); }
+
+	// data
+protected:
+	typename tree_category_type::const_iterator it;
+	std::queue<typename tree_category_type::const_iterator> node_queue;
+	const tree_type* pTop_node;
+	bool at_top;
+
+	// friends
+	#if defined(_MSC_VER) && _MSC_VER < 1300
+    typedef tree_type tr_type;
+		friend typename tr_type;
+		friend class sequential_tree<stored_type>;
+		friend bool operator == (const const_level_order_descendant_iterator& lhs, const const_level_order_descendant_iterator& rhs);
+	#else
+		template<typename T, typename U> friend class tree;
+		template<typename T, typename U> friend class multitree;
+		template<typename T, typename U, typename V> friend class unique_tree;
+		template<typename T> friend class sequential_tree;
+		friend bool operator ==<> (const const_level_order_descendant_iterator& lhs, const const_level_order_descendant_iterator& rhs);
+	#endif
+};
+
+template<typename stored_type, typename tree_type, typename container_type, typename tree_category_type>
+class tcl::level_order_descendant_iterator : public tcl::const_level_order_descendant_iterator<stored_type, tree_type, container_type, tree_category_type>
+{
+public:
+	// constructors/destructor
+	level_order_descendant_iterator() : const_level_order_descendant_iterator<stored_type, tree_type, container_type, tree_category_type>() {}
+	// destructor, copy constructor, and assignment operator will be compiler generated correctly
+protected:
+	explicit level_order_descendant_iterator(const tree_type* const pCalled_node, bool beg) : const_level_order_descendant_iterator<stored_type, tree_type, container_type, tree_category_type>(pCalled_node, beg) {}
+
+public:
+	// overloaded operators
+	level_order_descendant_iterator& operator ++() { ++(*static_cast<const_level_order_descendant_iterator<stored_type, tree_type, container_type, tree_category_type>*>(this)); return *this; }
+	level_order_descendant_iterator operator ++(int) { level_order_descendant_iterator old(*this); ++*this; return old; }
+
+	// public interface
+	stored_type& operator*() const { return at_top ? const_cast<stored_type&>(*pTop_node->get()) : const_cast<stored_type&>(it.operator *()); }
+	stored_type* operator->() const { return at_top ? const_cast<stored_type*>(pTop_node->get()) : const_cast<stored_type*>(it.operator ->()); }
+	tree_type* node() const { return at_top ? const_cast<tree_type*>(pTop_node) : const_cast<tree_type*>(it.node()); }
+
+	// friends
+	using const_level_order_descendant_iterator<stored_type, tree_type, container_type, tree_category_type>::it;
+	using const_level_order_descendant_iterator<stored_type, tree_type, container_type, tree_category_type>::pTop_node;
+	using const_level_order_descendant_iterator<stored_type, tree_type, container_type, tree_category_type>::at_top;
+	#if defined(_MSC_VER) && _MSC_VER < 1300
+    typedef tree_type tr_type;
+		friend typename tr_type;
+		friend class sequential_tree<stored_type>;
+	#else
+		template<typename T, typename U> friend class multitree;
+		template<typename T, typename U, typename V> friend class unique_tree;
+		template<typename T, typename U> friend class tree;
+		template<typename T> friend class sequential_tree;
+	#endif
+};
+
+
+#include "descendant_iterator.inl"

+ 222 - 0
ModelIO/tcl_5.0.6/descendant_iterator.inl

@@ -0,0 +1,222 @@
+/*******************************************************************************
+Tree Container Library: Generic container library to store data in tree-like structures.
+Copyright (c) 2006  Mitchel Haas
+
+This software is provided 'as-is', without any express or implied warranty. 
+In no event will the author be held liable for any damages arising from 
+the use of this software.
+
+Permission is granted to anyone to use this software for any purpose, 
+including commercial applications, and to alter it and redistribute it freely, 
+subject to the following restrictions:
+
+1.	The origin of this software must not be misrepresented; 
+you must not claim that you wrote the original software. 
+If you use this software in a product, an acknowledgment in the product 
+documentation would be appreciated but is not required.
+
+2.	Altered source versions must be plainly marked as such, 
+and must not be misrepresented as being the original software.
+
+3.	The above copyright notice and this permission notice may not be removed 
+or altered from any source distribution.
+
+For complete documentation on this library, see http://www.datasoftsolutions.net
+Email questions, comments or suggestions to mhaas@datasoftsolutions.net
+*******************************************************************************/
+
+// pre_order_iterator ++()
+template<typename stored_type, typename tree_type, typename container_type, typename tree_category_type>
+tcl::const_pre_order_descendant_iterator<stored_type, tree_type, container_type, tree_category_type>& tcl::const_pre_order_descendant_iterator<stored_type, tree_type, container_type, tree_category_type>::operator ++()
+{
+	if (at_top) {  // at top node?
+		at_top = false; // iterator will be used going forward from here
+		it = pTop_node->begin();
+	} else if ( !it.node()->empty() ) { // any children?
+		node_stack.push(it); // yes. push current pos
+		it = it.node()->begin(); // and goto first child
+	} else {
+		++it; // no children. incr to next sibling if present
+		// while stack not empty and no next sibling
+		while ( !node_stack.empty() && it == (node_stack.top()).node()->end() ) {
+			it = node_stack.top(); // pop parent
+			node_stack.pop();
+			++it; // and see if it's got a next sibling
+		}
+	}
+	return *this; 
+}
+
+// pre_order_iterator --()
+template<typename stored_type, typename tree_type, typename container_type, typename tree_category_type>
+tcl::const_pre_order_descendant_iterator<stored_type, tree_type, container_type, tree_category_type>& tcl::const_pre_order_descendant_iterator<stored_type, tree_type, container_type, tree_category_type>::operator --()
+{
+	typedef typename tree_category_type::const_iterator iterator_type;
+	if ( it == pTop_node->end() ) { // at end?
+		// yes. is top node empty?
+		if (pTop_node->empty()) {
+			at_top = true;
+			return *this;
+		}
+		//need to set up stack to state just before end
+		rit = pTop_node->children.rbegin(); // going backwards
+		if ( rit != pTop_node->children.rend() ) { // insure there's children
+			if ( !(*rit)->empty() ) { // last node have children?
+				do {  // find the last child of this node
+					++rit; // incr reverse iter..
+					it = iterator_type(rit.base(), (it != pTop_node->end() ? it.node() : pTop_node)); // ..to convert to fwd iter correctly
+					node_stack.push(it); // push parents on the way down
+					rit = it.node()->children.rbegin(); // get last child again
+				} while ( !(*rit)->empty() ); // while last child has children
+			}
+			++rit; // incr reverse iter
+			it = iterator_type(rit.base(), (it != pTop_node->end() ? node() : pTop_node)); // to convert to forward iter correctly
+		}
+	} else { // not at end.
+		if ( it != it.node()->parent()->begin() ) { // is this first sibling?
+			--it; // no.  ok to decr to next sibling
+			if (!it.node()->empty()) { // children present?
+				do { // yes.  get deepest last child
+					node_stack.push(it); // first push current 
+					it = iterator_type(it.node()->children.end(), it.node());
+					--it;  // then go to last child
+				} while ( !it.node()->empty() ); // while children present
+			}
+		} else if (!node_stack.empty()){ // first sibling.  Check for parent
+			it = node_stack.top(); // just need to goto parent
+			node_stack.pop();
+		} else {
+			if (!at_top) { // not at top node?
+				at_top = true;  // set at top (first) node
+			} else {
+				--it;  // decrementing beyond top.  this will make the iterator invalid
+				at_top = false;
+			}
+		}
+	}
+	return *this;
+}
+
+// post_order_iterator constructor
+template<typename stored_type, typename tree_type, typename container_type, typename tree_category_type>
+tcl::const_post_order_descendant_iterator<stored_type, tree_type, container_type, tree_category_type>::const_post_order_descendant_iterator(const tree_type* pCalled_node, bool beg) : pTop_node(pCalled_node), at_top(false)
+{
+	if (!beg) {
+		it = pTop_node->end();
+	} else {
+		it = pCalled_node->begin();  // goto first child
+		if ( it != pTop_node->end()) {
+			if ( !it.node()->empty() ) { // have children of it's own?
+				do {  // goto deepest first child, while pushing parents
+					node_stack.push(it);
+					it = it.node()->begin();
+				} while ( !it.node()->empty() );
+			}
+		} else {
+			// no children.  set top node as current
+			at_top = true;
+		}
+	}
+}
+
+// post_order_iterator ++()
+template<typename stored_type, typename tree_type, typename container_type, typename tree_category_type>
+tcl::const_post_order_descendant_iterator<stored_type, tree_type, container_type, tree_category_type>& tcl::const_post_order_descendant_iterator<stored_type, tree_type, container_type, tree_category_type>::operator ++()
+{
+	if (at_top) { // at last (called) node?
+		// yes.  
+		at_top = false;
+		it = pTop_node->end();
+		return *this;
+	} else if (pTop_node->empty()) {
+		++it;  // iterator has just traversed past end
+		return *this;
+	}
+
+	const typename tree_category_type::const_iterator it_end = it.node()->parent()->end(); // end sibling
+	++it; // advance to next sibling, if present
+	if ( it != it_end && !it.node()->empty() ) { // next sibling present, and has children?
+		do {  // goto deepest first child while pushing parents
+			node_stack.push(it);
+			it = it.node()->begin();
+		} while ( !it.node()->empty() );
+	} else { // it is past last sibling, or it has no children
+		// if valid it and it has no children, were done
+		if ( !node_stack.empty() && it == (node_stack.top()).node()->end() ) {
+			// it is past last sibling, and pushed parents exist.  move back up to parent
+			it = node_stack.top();
+			node_stack.pop();
+		} else if (node_stack.empty() && it == pTop_node->end()) {
+			// at top node.  
+			at_top = true; // no.  now at top node.
+		}
+	}
+	return *this;
+}
+
+// post_order_iterator --()
+template<typename stored_type, typename tree_type, typename container_type, typename tree_category_type>
+tcl::const_post_order_descendant_iterator<stored_type, tree_type, container_type, tree_category_type>& tcl::const_post_order_descendant_iterator<stored_type, tree_type, container_type, tree_category_type>::operator --()
+{
+	typedef typename tree_category_type::const_iterator iterator_type;
+	
+	if (at_top) { // at top node
+		at_top = false;
+		typename container_type::const_reverse_iterator rit = pTop_node->children.rbegin();
+		++rit;
+		it = iterator_type(rit.base(), pTop_node); // goto last sibling of top node
+	} else if ( it == pTop_node->end() ) { // at end of descendants?
+		at_top = true;
+	} else { // not at end
+		if ( !it.node()->empty() ) { // children present?
+			typename container_type::const_reverse_iterator rit = it.node()->children.rbegin();
+			node_stack.push(it);
+			++rit; // push parent and go to last child
+			it = iterator_type(rit.base(), it.node());
+		} else { // no children present
+			if ( it != it.node()->parent()->begin() ) { // at first sibling?
+				--it; // no.  just goto prev sibling
+			} else { // at first sibling. work our way up until not first sibling
+				while ( !node_stack.empty() && it == node_stack.top().node()->begin())
+				{
+					it = node_stack.top();
+					node_stack.pop();
+				}
+				--it; // then goto prev sibling
+			}
+		}
+	}
+	return *this;
+}
+
+// level_order_iterator ++()
+template<typename stored_type, typename tree_type, typename container_type, typename tree_category_type>
+tcl::const_level_order_descendant_iterator<stored_type, tree_type, container_type, tree_category_type>& tcl::const_level_order_descendant_iterator<stored_type, tree_type, container_type, tree_category_type>::operator ++()
+{
+	if (at_top) {  // at top node?
+		// yes.  
+		at_top = false;
+		it = pTop_node->begin();
+		return *this;
+	}
+
+	const typename tree_category_type::const_iterator it_end = it.node()->parent()->end(); 
+	node_queue.push(it); // push current pos node in queue
+	++it;  // and goto next sibling if present
+
+	if ( it == it_end ) { // past last sibling?  If not, we're done.
+		while ( !node_queue.empty() ) { // yes. Insure queue not empty
+			it = node_queue.front(); // pull pos off queue
+			node_queue.pop(); // this should be the start pos of level just traversed
+			if ( !it.node()->empty() ) { // have children?
+				it = node()->begin(); // yes. descend to start of next level
+				break;
+			} else if ( node_queue.empty() ) { // no children.  is queue empty?
+				it = pTop_node->end(); // yes. at end
+				return *this;
+			}
+		} 
+	}
+	return *this;
+}
+

+ 296 - 0
ModelIO/tcl_5.0.6/descendant_node_iterator.h

@@ -0,0 +1,296 @@
+/*******************************************************************************
+Tree Container Library: Generic container library to store data in tree-like structures.
+Copyright (c) 2006  Mitchel Haas
+
+This software is provided 'as-is', without any express or implied warranty. 
+In no event will the author be held liable for any damages arising from 
+the use of this software.
+
+Permission is granted to anyone to use this software for any purpose, 
+including commercial applications, and to alter it and redistribute it freely, 
+subject to the following restrictions:
+
+1.	The origin of this software must not be misrepresented; 
+you must not claim that you wrote the original software. 
+If you use this software in a product, an acknowledgment in the product 
+documentation would be appreciated but is not required.
+
+2.	Altered source versions must be plainly marked as such, 
+and must not be misrepresented as being the original software.
+
+3.	The above copyright notice and this permission notice may not be removed 
+or altered from any source distribution.
+
+For complete documentation on this library, see http://www.datasoftsolutions.net
+Email questions, comments or suggestions to mhaas@datasoftsolutions.net
+*******************************************************************************/
+#pragma once
+#include "child_node_iterator.h"
+#include <set>
+#include <stack>
+#include <queue>
+#include <algorithm>
+
+namespace tcl 
+{
+	template<typename T, typename U, typename V, typename W> class const_pre_order_descendant_node_iterator;
+	template<typename T, typename U, typename V, typename W> class pre_order_descendant_node_iterator;
+	template<typename T, typename U, typename V, typename W> class const_post_order_descendant_node_iterator;
+	template<typename T, typename U, typename V, typename W> class post_order_descendant_node_iterator;
+	template<typename T, typename U, typename V, typename W> class const_level_order_descendant_node_iterator;
+	template<typename T, typename U, typename V, typename W> class level_order_descendant_node_iterator;
+
+	// comparison operators
+	template<typename T, typename U, typename V, typename W> bool operator == (const const_pre_order_descendant_node_iterator<T, U, V, W>& lhs, const const_pre_order_descendant_node_iterator<T, U, V, W>& rhs) { return lhs.it == rhs.it && lhs.at_top == rhs.at_top; }
+	template<typename T, typename U, typename V, typename W> bool operator != (const const_pre_order_descendant_node_iterator<T, U, V, W>& lhs, const const_pre_order_descendant_node_iterator<T, U, V, W>& rhs) { return !(lhs == rhs); }
+	template<typename T, typename U, typename V, typename W> bool operator == (const const_post_order_descendant_node_iterator<T, U, V, W>& lhs, const const_post_order_descendant_node_iterator<T, U, V, W>& rhs) { return lhs.it == rhs.it && lhs.at_top == rhs.at_top; }
+	template<typename T, typename U, typename V, typename W> bool operator != (const const_post_order_descendant_node_iterator<T, U, V, W>& lhs, const const_post_order_descendant_node_iterator<T, U, V, W>& rhs) { return !(lhs == rhs); }
+	template<typename T, typename U, typename V, typename W> bool operator == (const const_level_order_descendant_node_iterator<T, U, V, W>& lhs, const const_level_order_descendant_node_iterator<T, U, V, W>& rhs) { return lhs.it == rhs.it && lhs.at_top == rhs.at_top; }
+	template<typename T, typename U, typename V, typename W> bool operator != (const const_level_order_descendant_node_iterator<T, U, V, W>& lhs, const const_level_order_descendant_node_iterator<T, U, V, W>& rhs) { return !(lhs == rhs); }
+
+}
+
+/************************************************************************/
+/* descendant iterators                                                 */
+/************************************************************************/
+
+template<typename stored_type, typename tree_type, typename container_type, typename tree_category_type>
+class tcl::const_pre_order_descendant_node_iterator : public std::iterator<std::bidirectional_iterator_tag, tree_type>
+{
+public:
+	// constructors/destructor
+	const_pre_order_descendant_node_iterator() : pTop_node(0), at_top(false) {}
+	// destructor, copy constructor, and assignment operator will be compiler generated correctly
+protected:
+	explicit const_pre_order_descendant_node_iterator(const tree_type* pCalled_node, bool beg) : it(beg ? pCalled_node->node_begin() : pCalled_node->node_end()), pTop_node(pCalled_node), at_top(beg) {}
+
+public:
+	// overloaded operators
+	const_pre_order_descendant_node_iterator& operator ++(); 
+	const_pre_order_descendant_node_iterator operator ++(int) { const_pre_order_descendant_node_iterator old(*this); ++*this; return old; }
+	const_pre_order_descendant_node_iterator& operator --();
+	const_pre_order_descendant_node_iterator operator --(int) { const_pre_order_descendant_node_iterator old(*this); --*this; return old; }
+	const tree_type& operator*() const { return at_top ? *pTop_node : it.operator *(); }
+	const tree_type* operator->() const { return at_top ? pTop_node : it.operator ->(); }
+
+	// data
+protected:
+	typename tree_category_type::const_node_iterator it;
+	std::stack<typename tree_category_type::const_node_iterator> node_stack;   
+	const tree_type* pTop_node;
+	typename container_type::const_reverse_iterator rit;
+	bool at_top;
+
+	// friends
+	#if defined(_MSC_VER) && _MSC_VER < 1300
+		typedef tree_type tr_type;
+		friend typename tr_type;
+		friend class sequential_tree<stored_type>;
+		friend bool operator == (const const_pre_order_descendant_node_iterator& lhs, const const_pre_order_descendant_node_iterator& rhs);
+	#else
+		template<typename T, typename U> friend class tree;
+		template<typename T, typename U> friend class multitree;
+		template<typename T, typename U, typename V> friend class unique_tree;
+		template<typename T> friend class sequential_tree;
+		friend bool operator ==<> (const const_pre_order_descendant_node_iterator& lhs, const const_pre_order_descendant_node_iterator& rhs);
+	#endif
+};
+
+template<typename stored_type, typename tree_type, typename container_type, typename tree_category_type>
+class tcl::pre_order_descendant_node_iterator : public tcl::const_pre_order_descendant_node_iterator<stored_type, tree_type, container_type, tree_category_type>
+{
+public:
+	// constructors/destructor
+	pre_order_descendant_node_iterator() : const_pre_order_descendant_node_iterator<stored_type, tree_type, container_type, tree_category_type>() {}
+	// destructor, copy constructor, and assignment operator will be compiler generated correctly
+protected:
+	explicit pre_order_descendant_node_iterator(const tree_type* const pCalled_node, bool beg) : const_pre_order_descendant_node_iterator<stored_type, tree_type, container_type, tree_category_type>(pCalled_node, beg) {}
+
+public:
+	// overloaded operators
+	pre_order_descendant_node_iterator& operator ++() { ++(*static_cast<const_pre_order_descendant_node_iterator<stored_type, tree_type, container_type, tree_category_type>*>(this)); return *this; }
+	pre_order_descendant_node_iterator operator ++(int) { pre_order_descendant_node_iterator old(*this); ++*this; return old; }
+	pre_order_descendant_node_iterator& operator --() { --(*static_cast<const_pre_order_descendant_node_iterator<stored_type, tree_type, container_type, tree_category_type>*>(this)); return *this; }
+	pre_order_descendant_node_iterator operator --(int) { pre_order_descendant_node_iterator old(*this); --*this; return old; }
+
+	// public interface
+	tree_type& operator*() const { return at_top ? const_cast<tree_type&>(*pTop_node) : const_cast<tree_type&>(it.operator *()); }
+	tree_type* operator->() const { return at_top ? const_cast<tree_type*>(pTop_node) : const_cast<tree_type*>(it.operator ->()); }
+
+	// friends
+	using const_pre_order_descendant_node_iterator<stored_type, tree_type, container_type, tree_category_type>::it;
+	using const_pre_order_descendant_node_iterator<stored_type, tree_type, container_type, tree_category_type>::pTop_node;
+	using const_pre_order_descendant_node_iterator<stored_type, tree_type, container_type, tree_category_type>::at_top;
+	#if defined(_MSC_VER) && _MSC_VER < 1300
+		typedef tree_type tr_type;
+		friend typename tr_type;
+		friend class sequential_tree<stored_type>;
+	#else
+		template<typename T, typename U> friend class tree;
+		template<typename T, typename U> friend class multitree;
+		template<typename T, typename U, typename V> friend class unique_tree;
+		template<typename T> friend class sequential_tree;
+	#endif
+};
+
+
+template<typename stored_type, typename tree_type, typename container_type, typename tree_category_type>
+class tcl::const_post_order_descendant_node_iterator : public std::iterator<std::bidirectional_iterator_tag, tree_type>
+{
+public:
+	// constructors/destructor
+	const_post_order_descendant_node_iterator() : pTop_node(0), at_top(false) {}
+	// destructor, copy constructor, and assignment operator will be compiler generated correctly
+protected:
+	explicit const_post_order_descendant_node_iterator(const tree_type* pCalled_node, bool beg); 
+
+public:
+	// overloaded operators
+	const_post_order_descendant_node_iterator& operator ++(); 
+	const_post_order_descendant_node_iterator operator ++(int) { const_post_order_descendant_node_iterator old(*this); ++*this; return old; }
+	const_post_order_descendant_node_iterator& operator --(); 
+	const_post_order_descendant_node_iterator operator --(int) { const_post_order_descendant_node_iterator old(*this); --*this; return old; }
+
+	// public interface
+	const tree_type& operator*() const { return at_top ? *pTop_node : it.operator *(); }
+	const tree_type* operator->() const { return at_top ? pTop_node : it.operator ->(); }
+
+	// data
+protected:
+	std::stack<typename tree_category_type::const_node_iterator > node_stack;   
+	typename tree_category_type::const_node_iterator it;
+	const tree_type* pTop_node;
+	typename container_type::const_reverse_iterator rit;
+	bool at_top;
+
+	// friends
+	#if defined(_MSC_VER) && _MSC_VER < 1300
+		typedef tree_type tr_type;
+		friend typename tr_type;
+		friend class sequential_tree<stored_type>;
+		friend bool operator == (const const_post_order_descendant_node_iterator& lhs, const const_post_order_descendant_node_iterator& rhs);
+	#else
+		template<typename T, typename U> friend class tree;
+		template<typename T, typename U> friend class multitree;
+		template<typename T, typename U, typename V> friend class unique_tree;
+		template<typename T> friend class sequential_tree;
+		friend bool operator ==<> (const const_post_order_descendant_node_iterator& lhs, const const_post_order_descendant_node_iterator& rhs);
+	#endif
+};
+
+template<typename stored_type, typename tree_type, typename container_type, typename tree_category_type>
+class tcl::post_order_descendant_node_iterator : public tcl::const_post_order_descendant_node_iterator<stored_type, tree_type, container_type, tree_category_type>
+{
+public:
+	// constructors/destructor
+	post_order_descendant_node_iterator() : const_post_order_descendant_node_iterator<stored_type, tree_type, container_type, tree_category_type>() {}
+	// destructor, copy constructor, and assignment operator will be compiler generated correctly
+protected:
+	explicit post_order_descendant_node_iterator(const tree_type* pCalled_node, bool beg) : const_post_order_descendant_node_iterator<stored_type, tree_type, container_type, tree_category_type>(pCalled_node, beg) { }
+
+public:
+	// overloaded operators
+	post_order_descendant_node_iterator& operator ++() { ++(*static_cast<const_post_order_descendant_node_iterator<stored_type, tree_type, container_type, tree_category_type>*>(this)); return *this; }
+	post_order_descendant_node_iterator operator ++(int) { post_order_descendant_node_iterator old(*this); ++*this; return old; }
+	post_order_descendant_node_iterator& operator --() { --(*static_cast<const_post_order_descendant_node_iterator<stored_type, tree_type, container_type, tree_category_type>*>(this)); return *this; }
+	post_order_descendant_node_iterator operator --(int) { post_order_descendant_node_iterator old(*this); --*this; return old; }
+
+	// public interface
+	tree_type& operator*() const { return at_top ? const_cast<tree_type&>(*pTop_node) : const_cast<tree_type&>(it.operator *()); }
+	tree_type* operator->() const { return at_top ? const_cast<tree_type*>(pTop_node) : const_cast<tree_type*>(it.operator ->()); }
+
+	// friends
+	using const_post_order_descendant_node_iterator<stored_type, tree_type, container_type, tree_category_type>::it;
+	using const_post_order_descendant_node_iterator<stored_type, tree_type, container_type, tree_category_type>::pTop_node;
+	using const_post_order_descendant_node_iterator<stored_type, tree_type, container_type, tree_category_type>::at_top;
+	#if defined(_MSC_VER) && _MSC_VER < 1300
+		typedef tree_type tr_type;
+		friend typename tr_type;
+		friend class sequential_tree<stored_type>;
+	#else
+		template<typename T, typename U> friend class tree;
+		template<typename T, typename U> friend class multitree;
+		template<typename T, typename U, typename V> friend class unique_tree;
+		template<typename T> friend class sequential_tree;
+	#endif
+};
+
+
+template<typename stored_type, typename tree_type, typename container_type, typename tree_category_type>
+class tcl::const_level_order_descendant_node_iterator : public std::iterator<std::forward_iterator_tag, tree_type>
+{
+public:
+	// constructors/destructor
+	const_level_order_descendant_node_iterator() : pTop_node(0), at_top(false) {}
+	// destructor, copy constructor, and assignment operator will be compiler generated correctly
+protected:
+	explicit const_level_order_descendant_node_iterator(const tree_type* pCalled_node, bool beg) : it(beg ? pCalled_node->node_begin() : pCalled_node->node_end()), pTop_node(pCalled_node), at_top(beg) {}
+
+public:
+	// overloaded operators
+	const_level_order_descendant_node_iterator& operator ++();
+	const_level_order_descendant_node_iterator operator ++(int) { const_level_order_descendant_node_iterator old(*this); ++*this; return old; }
+
+	// public interface
+	const tree_type& operator*() const { return at_top ? *pTop_node : it.operator *(); }
+	const tree_type* operator->() const { return at_top ? pTop_node : it.operator ->(); }
+
+	// data
+protected:
+	typename tree_category_type::const_node_iterator it;
+	std::queue<typename tree_category_type::const_node_iterator> node_queue;
+	const tree_type* pTop_node;
+	bool at_top;
+
+	// friends
+	#if defined(_MSC_VER) && _MSC_VER < 1300
+		typedef tree_type tr_type;
+		friend typename tr_type;
+		friend class sequential_tree<stored_type>;
+		friend bool operator == (const const_level_order_descendant_node_iterator& lhs, const const_level_order_descendant_node_iterator& rhs);
+	#else
+		template<typename T, typename U> friend class tree;
+		template<typename T, typename U> friend class multitree;
+		template<typename T, typename U, typename V> friend class unique_tree;
+		template<typename T> friend class sequential_tree;
+		friend bool operator ==<> (const const_level_order_descendant_node_iterator& lhs, const const_level_order_descendant_node_iterator& rhs);
+	#endif
+};
+
+template<typename stored_type, typename tree_type, typename container_type, typename tree_category_type>
+class tcl::level_order_descendant_node_iterator : public tcl::const_level_order_descendant_node_iterator<stored_type, tree_type, container_type, tree_category_type>
+{
+public:
+	// constructors/destructor
+	level_order_descendant_node_iterator() : const_level_order_descendant_node_iterator<stored_type, tree_type, container_type, tree_category_type>() {}
+	// destructor, copy constructor, and assignment operator will be compiler generated correctly
+protected:
+	explicit level_order_descendant_node_iterator(const tree_type* pCalled_node, bool beg) : const_level_order_descendant_node_iterator<stored_type, tree_type, container_type, tree_category_type>(pCalled_node, beg) {}
+
+public:
+	// overloaded operators
+	level_order_descendant_node_iterator& operator ++() { ++(*static_cast<const_level_order_descendant_node_iterator<stored_type, tree_type, container_type, tree_category_type>*>(this)); return *this; }
+	level_order_descendant_node_iterator operator ++(int) { level_order_descendant_node_iterator old(*this); ++*this; return old; }
+
+	// public interface
+	tree_type& operator*() const { return at_top ? const_cast<tree_type&>(*pTop_node) : const_cast<tree_type&>(it.operator *()); }
+	tree_type* operator->() const { return at_top ? const_cast<tree_type*>(pTop_node) : const_cast<tree_type*>(it.operator ->()); }
+
+	// friends
+	using const_level_order_descendant_node_iterator<stored_type, tree_type, container_type, tree_category_type>::it;
+	using const_level_order_descendant_node_iterator<stored_type, tree_type, container_type, tree_category_type>::pTop_node;
+	using const_level_order_descendant_node_iterator<stored_type, tree_type, container_type, tree_category_type>::at_top;
+	#if defined(_MSC_VER) && _MSC_VER < 1300
+		typedef tree_type tr_type;
+		friend typename tr_type;
+		friend class sequential_tree<stored_type>;
+	#else
+		template<typename T, typename U> friend class tree;
+		template<typename T, typename U> friend class multitree;
+		template<typename T, typename U, typename V> friend class unique_tree;
+		template<typename T> friend class sequential_tree;
+	#endif
+};
+
+
+#include "descendant_node_iterator.inl"

+ 221 - 0
ModelIO/tcl_5.0.6/descendant_node_iterator.inl

@@ -0,0 +1,221 @@
+/*******************************************************************************
+Tree Container Library: Generic container library to store data in tree-like structures.
+Copyright (c) 2006  Mitchel Haas
+
+This software is provided 'as-is', without any express or implied warranty. 
+In no event will the author be held liable for any damages arising from 
+the use of this software.
+
+Permission is granted to anyone to use this software for any purpose, 
+including commercial applications, and to alter it and redistribute it freely, 
+subject to the following restrictions:
+
+1.	The origin of this software must not be misrepresented; 
+you must not claim that you wrote the original software. 
+If you use this software in a product, an acknowledgment in the product 
+documentation would be appreciated but is not required.
+
+2.	Altered source versions must be plainly marked as such, 
+and must not be misrepresented as being the original software.
+
+3.	The above copyright notice and this permission notice may not be removed 
+or altered from any source distribution.
+
+For complete documentation on this library, see http://www.datasoftsolutions.net
+Email questions, comments or suggestions to mhaas@datasoftsolutions.net
+*******************************************************************************/
+
+// pre_order_iterator ++()
+template<typename stored_type, typename tree_type, typename container_type, typename tree_category_type>
+tcl::const_pre_order_descendant_node_iterator<stored_type, tree_type, container_type, tree_category_type>& tcl::const_pre_order_descendant_node_iterator<stored_type, tree_type, container_type, tree_category_type>::operator ++()
+{
+	if (at_top) {  // at top node?
+		at_top = false; // iterator will be used going forward from here
+		it = pTop_node->node_begin();
+	} else if ( !it->empty() ) { // any children?
+		node_stack.push(it); // yes. push current pos
+		it = it->node_begin(); // and goto first child
+	} else {
+		++it; // no children. incr to next sibling if present
+		// while stack not empty and no next sibling
+		while ( !node_stack.empty() && it == (node_stack.top())->node_end() ) {
+			it = node_stack.top(); // pop parent
+			node_stack.pop();
+			++it; // and see if it's got a next sibling
+		}
+	}
+	return *this; 
+}
+
+// pre_order_iterator --()
+template<typename stored_type, typename tree_type, typename container_type, typename tree_category_type>
+tcl::const_pre_order_descendant_node_iterator<stored_type, tree_type, container_type, tree_category_type>& tcl::const_pre_order_descendant_node_iterator<stored_type, tree_type, container_type, tree_category_type>::operator --()
+{
+	typedef typename tree_category_type::const_node_iterator iterator_type;
+	if ( it == pTop_node->node_end() ) { // at end?
+		// yes. is top node empty?
+		if (pTop_node->empty()) {
+			at_top = true;
+			return *this;
+		}
+		// yes. need to set up stack to state just before end
+		rit = pTop_node->children.rbegin(); // going backwards
+		if ( rit != pTop_node->children.rend() ) { // insure there's children
+			if ( !(*rit)->empty() ) { // last node have children?
+				do {  // find the last child of this node
+					++rit; // incr reverse iter..
+					it = iterator_type(rit.base(), (it != pTop_node->node_end() ? &(*it) : pTop_node)); // ..to convert to fwd iter correctly
+					node_stack.push(it); // push parents on the way down
+					rit = it->children.rbegin(); // get last child again
+				} while ( !(*rit)->empty() ); // while last child has children
+			}
+			++rit; // incr reverse iter
+			it = iterator_type(rit.base(), (it != pTop_node->node_end() ? &(*it) : pTop_node)); // to convert to forward iter correctly
+		}
+	} else { // not at end.
+		if ( it != it->parent()->node_begin() ) { // is this first sibling?
+			--it; // no.  ok to decr to next sibling
+			if (!it->empty()) { // children present?
+				do { // yes.  get deepest last child
+					node_stack.push(it); // first push current 
+					it = iterator_type(it->children.end(), &(*it));
+					--it;  // then go to last child
+				} while ( !it->empty() ); // while children present
+			}
+		} else if (!node_stack.empty()) { // first sibling.  Check for parent
+			it = node_stack.top(); // just need to goto parent
+			node_stack.pop();
+		} else {
+			if (!at_top) { // not at top node?
+				at_top = true;  // set at top (first) node
+			} else {
+				--it;  // decrementing beyond top.  this will make the iterator invalid
+				at_top = false;
+			}
+		}
+	}
+	return *this;
+}
+
+// post_order_iterator constructor
+template<typename stored_type, typename tree_type, typename container_type, typename tree_category_type>
+tcl::const_post_order_descendant_node_iterator<stored_type, tree_type, container_type, tree_category_type>::const_post_order_descendant_node_iterator(const tree_type* pCalled_node, bool beg) : pTop_node(pCalled_node), at_top(false)
+{
+	if (!beg) {
+		it = pTop_node->node_end();
+	} else {
+		it = pTop_node->node_begin(); // goto first child
+		if ( it != pTop_node->node_end()) {
+			if ( !it->empty() ) { // have children of it's own?
+				do {  // goto deepest first child, while pushing parents
+					node_stack.push(it);
+					it = it->node_begin();
+				} while ( !it->empty() );
+			}
+		} else {
+			// no children.  set top node as current
+			at_top = true;
+		}
+	}
+}
+
+// post_order_iterator ++()
+template<typename stored_type, typename tree_type, typename container_type, typename tree_category_type>
+tcl::const_post_order_descendant_node_iterator<stored_type, tree_type, container_type, tree_category_type>& tcl::const_post_order_descendant_node_iterator<stored_type, tree_type, container_type, tree_category_type>::operator ++()
+{
+	if (at_top) { // at last (called) node?
+		// yes. 
+		at_top = false;
+		it = pTop_node->node_end();
+		return *this;
+	} else if (pTop_node->empty()) {
+		++it;  // iterator has just traversed past end
+		return *this;
+	}
+
+	const typename tree_category_type::const_node_iterator it_end = it->parent()->node_end(); // end sibling
+	++it; // advance to next sibling, if present
+	if ( it != it_end && !it->empty() ) { // next sibling present, and has children?
+		do {  // goto deepest first child while pushing parents
+			node_stack.push(it);
+			it = it->node_begin();
+		} while ( !it->empty() );
+	} else { // it is past last sibling, or it has no children
+		// if valid it and it has no childrent, were done
+		if ( !node_stack.empty() && it == node_stack.top()->node_end() ) {
+			// it is past last sibling, and pushed parents exist.  move back up to parent
+			it = node_stack.top();
+			node_stack.pop();
+		} else if (node_stack.empty() && it == pTop_node->node_end()) {
+			// at top node. 
+			at_top = true;  
+		}
+	}
+	return *this;
+}
+
+// post_order_iterator --()
+template<typename stored_type, typename tree_type, typename container_type, typename tree_category_type>
+tcl::const_post_order_descendant_node_iterator<stored_type, tree_type, container_type, tree_category_type>& tcl::const_post_order_descendant_node_iterator<stored_type, tree_type, container_type, tree_category_type>::operator --()
+{
+	typedef typename tree_category_type::const_node_iterator iterator_type;
+
+	if (at_top) { // at top node
+		at_top = false;
+		typename container_type::const_reverse_iterator rit = pTop_node->children.rbegin();
+		++rit;
+		it = iterator_type(rit.base(), pTop_node); // goto last sibling of top node
+	} else if ( it == pTop_node->node_end() ) { // at end?
+		at_top = true;
+	} else { // not at end
+		if ( !it->empty() ) { // children present?
+			typename container_type::const_reverse_iterator rit = it->children.rbegin();
+			node_stack.push(it);
+			++rit; // push parent and go to last child
+			it = iterator_type(rit.base(), &(*it));
+		} else { // no children present
+			if ( it != it->parent()->node_begin() ) { // at first sibling?
+				--it; // no.  just goto prev sibling
+			} else { // at first sibling. work our way up until not first sibling
+				while ( !node_stack.empty() && it == node_stack.top()->node_begin())
+				{
+					it = node_stack.top();
+					node_stack.pop();
+				}
+				--it; // then goto prev sibling
+			}
+		}
+	}
+	return *this;
+}
+
+// level_order_iterator ++()
+template<typename stored_type, typename tree_type, typename container_type, typename tree_category_type>
+tcl::const_level_order_descendant_node_iterator<stored_type, tree_type, container_type, tree_category_type>& tcl::const_level_order_descendant_node_iterator<stored_type, tree_type, container_type, tree_category_type>::operator ++()
+{
+	if (at_top) { // at top?
+		// yes.  
+		at_top = false;
+		it = pTop_node->node_begin();
+		return *this;
+	}
+
+	const typename tree_category_type::const_node_iterator it_end = it->parent()->node_end(); 
+	node_queue.push(it); // push current pos node in queue
+	++it;  // and goto next sibling if present
+
+	if ( it == it_end ) { // past last sibling?  If not, we're done.
+		while ( !node_queue.empty() ) { // yes. Insure queue not empty
+			it = node_queue.front(); // pull pos off queue
+			node_queue.pop(); // this should be the start pos of level just traversed
+			if ( !it->empty() ) { // have children?
+				it = it->node_begin(); // yes. descend to start of next level
+				break;
+			} else if ( node_queue.empty() ) { // no children.  is queue empty?
+				it = pTop_node->node_end(); // yes. at end
+				return *this;
+			}
+		} 
+	}
+	return *this;
+}

+ 135 - 0
ModelIO/tcl_5.0.6/multitree.h

@@ -0,0 +1,135 @@
+/*******************************************************************************
+Tree Container Library: Generic container library to store data in tree-like structures.
+Copyright (c) 2006  Mitchel Haas
+
+This software is provided 'as-is', without any express or implied warranty. 
+In no event will the author be held liable for any damages arising from 
+the use of this software.
+
+Permission is granted to anyone to use this software for any purpose, 
+including commercial applications, and to alter it and redistribute it freely, 
+subject to the following restrictions:
+
+1.	The origin of this software must not be misrepresented; 
+you must not claim that you wrote the original software. 
+If you use this software in a product, an acknowledgment in the product 
+documentation would be appreciated but is not required.
+
+2.	Altered source versions must be plainly marked as such, 
+and must not be misrepresented as being the original software.
+
+3.	The above copyright notice and this permission notice may not be removed 
+or altered from any source distribution.
+
+For complete documentation on this library, see http://www.datasoftsolutions.net
+Email questions, comments or suggestions to mhaas@datasoftsolutions.net
+*******************************************************************************/
+#pragma once 
+#include "associative_tree.h"
+#include <set>
+
+namespace tcl
+{
+	// forward declaration for deref comparison functor
+	template<typename stored_type, typename node_compare_type > class multitree;
+
+	// deref comparison functor, derive from binary function per Scott Meyer
+	template<typename stored_type, typename node_compare_type >
+	struct multitree_deref_less : public std::binary_function<const multitree<stored_type, node_compare_type>*, const multitree<stored_type, node_compare_type>*, bool>
+	{
+		bool operator () (const multitree<stored_type, node_compare_type>* lhs, const multitree<stored_type, node_compare_type>* rhs) const
+		{
+			// call < on actual object
+			return node_compare_type()(*lhs->get(), *rhs->get());
+		}
+	};
+}
+
+
+
+// node object type.  forwards most operations to base_tree_type, 
+// instanciates base_tree_type with type of container (set of unique_tree ptrs) to use for node and key comparisons
+template<typename stored_type, typename node_compare_type = std::less<stored_type> >
+class tcl::multitree : public tcl::associative_tree<stored_type, tcl::multitree<stored_type, node_compare_type>,  std::multiset<tcl::multitree<stored_type, node_compare_type>*, tcl::multitree_deref_less<stored_type, node_compare_type> > >
+{
+public:
+	// typedefs
+	typedef multitree<stored_type, node_compare_type> tree_type;
+	typedef multitree_deref_less<stored_type, node_compare_type> key_compare;
+	typedef multitree_deref_less<stored_type, node_compare_type> value_compare;
+	typedef std::multiset<tree_type*, key_compare> container_type;
+	typedef basic_tree<stored_type, tree_type, container_type> basic_tree_type;
+	typedef associative_tree<stored_type, tree_type, container_type> associative_tree_type;
+
+	// constructors/destructor
+	explicit multitree( const stored_type& value = stored_type() ) : associative_tree_type(value) {}
+	template<typename iterator_type> multitree(iterator_type it_beg, iterator_type it_end, const stored_type& value = stored_type()) : associative_tree_type(value) { while (it_beg != it_end) { insert(*it_beg); ++it_beg; } }
+	multitree( const tree_type& rhs ); // copy constructor
+	~multitree() { associative_tree_type::clear(); }
+
+ 	// assignment operator
+	tree_type& operator = (const tree_type& rhs);
+
+	// public interface
+public:
+	typename associative_tree_type::iterator insert(const stored_type& value) { return associative_tree_type::insert(value, this); }
+	typename associative_tree_type::iterator insert(const typename associative_tree_type::const_iterator pos, const stored_type& value) { return associative_tree_type::insert(pos, value, this); }
+	typename associative_tree_type::iterator insert(const tree_type& tree_obj ) { return associative_tree_type::insert(tree_obj, this); }
+	typename associative_tree_type::iterator insert(const typename associative_tree_type::const_iterator pos, const tree_type& tree_obj) { return associative_tree_type::insert(pos, tree_obj, this); }
+	#if !defined(_MSC_VER) || _MSC_VER >= 1300 // insert range not available for VC6
+		template<typename iterator_type> void insert(iterator_type it_beg, iterator_type it_end) { while ( it_beg != it_end ) insert(*it_beg++); }
+	#endif
+	void swap(tree_type& rhs);
+
+	// descendant element iterator accessors
+	typedef typename associative_tree_type::post_order_iterator post_order_iterator_type;
+	typedef typename associative_tree_type::const_post_order_iterator const_post_order_iterator_type;
+	typedef typename associative_tree_type::pre_order_iterator pre_order_iterator_type;
+	typedef typename associative_tree_type::const_pre_order_iterator const_pre_order_iterator_type;
+	typedef typename associative_tree_type::level_order_iterator level_order_iterator_type;
+	typedef typename associative_tree_type::const_level_order_iterator const_level_order_iterator_type;
+
+	pre_order_iterator_type pre_order_begin() { return pre_order_iterator_type(this, true); }
+	pre_order_iterator_type pre_order_end() { return pre_order_iterator_type(this, false); }
+	const_pre_order_iterator_type pre_order_begin() const { return const_pre_order_iterator_type(this, true); }
+	const_pre_order_iterator_type pre_order_end() const { return const_pre_order_iterator_type(this, false); }
+	post_order_iterator_type post_order_begin() { return post_order_iterator_type(this, true); }
+	post_order_iterator_type post_order_end() { return post_order_iterator_type(this, false); }
+	const_post_order_iterator_type post_order_begin() const { return const_post_order_iterator_type(this, true); }
+	const_post_order_iterator_type post_order_end() const { return const_post_order_iterator_type(this, false); }
+	level_order_iterator_type level_order_begin() { return level_order_iterator_type(this, true); }
+	level_order_iterator_type level_order_end() { return level_order_iterator_type(this, false); }
+	const_level_order_iterator_type level_order_begin() const { return const_level_order_iterator_type(this, true); }
+	const_level_order_iterator_type level_order_end() const { return const_level_order_iterator_type(this, false); }
+
+	// descendant node iterator accessors
+	typedef typename associative_tree_type::pre_order_node_iterator pre_order_node_iterator_type;
+	typedef typename associative_tree_type::const_pre_order_node_iterator const_pre_order_node_iterator_type;
+	typedef typename associative_tree_type::post_order_node_iterator post_order_node_iterator_type;
+	typedef typename associative_tree_type::const_post_order_node_iterator const_post_order_node_iterator_type;
+	typedef typename associative_tree_type::level_order_node_iterator level_order_node_iterator_type;
+	typedef typename associative_tree_type::const_level_order_node_iterator const_level_order_node_iterator_type;
+
+	pre_order_node_iterator_type pre_order_node_begin() { return pre_order_node_iterator_type(this, true); }
+	pre_order_node_iterator_type pre_order_node_end() { return pre_order_node_iterator_type(this, false); }
+	const_pre_order_node_iterator_type pre_order_node_begin() const { return const_pre_order_node_iterator_type(this, true); }
+	const_pre_order_node_iterator_type pre_order_node_end() const { return const_pre_order_node_iterator_type(this, false); }
+	post_order_node_iterator_type post_order_node_begin() { return post_order_node_iterator_type(this, true); }
+	post_order_node_iterator_type post_order_node_end() { return post_order_node_iterator_type(this, false); }
+	const_post_order_node_iterator_type post_order_node_begin() const { return const_post_order_node_iterator_type(this, true); }
+	const_post_order_node_iterator_type post_order_node_end() const { return const_post_order_node_iterator_type(this, false); }
+	level_order_node_iterator_type level_order_node_begin() { return level_order_node_iterator_type(this, true); }
+	level_order_node_iterator_type level_order_node_end() { return level_order_node_iterator_type(this, false); }
+	const_level_order_node_iterator_type level_order_node_begin() const { return const_level_order_node_iterator_type(this, true); }
+	const_level_order_node_iterator_type level_order_node_end() const { return const_level_order_node_iterator_type(this, false); }
+
+	// friends
+	#if defined(_MSC_VER) && _MSC_VER < 1300
+		friend class basic_tree<stored_type, tree_type, container_type>;
+	#else
+		template<typename T, typename U, typename V> friend class basic_tree;
+	#endif
+};
+
+
+#include "multitree.inl"

+ 76 - 0
ModelIO/tcl_5.0.6/multitree.inl

@@ -0,0 +1,76 @@
+/*******************************************************************************
+Tree Container Library: Generic container library to store data in tree-like structures.
+Copyright (c) 2006  Mitchel Haas
+
+This software is provided 'as-is', without any express or implied warranty. 
+In no event will the author be held liable for any damages arising from 
+the use of this software.
+
+Permission is granted to anyone to use this software for any purpose, 
+including commercial applications, and to alter it and redistribute it freely, 
+subject to the following restrictions:
+
+1.	The origin of this software must not be misrepresented; 
+you must not claim that you wrote the original software. 
+If you use this software in a product, an acknowledgment in the product 
+documentation would be appreciated but is not required.
+
+2.	Altered source versions must be plainly marked as such, 
+and must not be misrepresented as being the original software.
+
+3.	The above copyright notice and this permission notice may not be removed 
+or altered from any source distribution.
+
+For complete documentation on this library, see http://www.datasoftsolutions.net
+Email questions, comments or suggestions to mhaas@datasoftsolutions.net
+*******************************************************************************/
+
+// copy constructor
+template<typename stored_type, typename node_compare_type>
+tcl::multitree<stored_type, node_compare_type>::multitree( const tree_type& rhs ) : associative_tree_type(rhs)
+{
+	typename associative_tree_type::const_iterator it = rhs.begin();
+	const typename associative_tree_type::const_iterator it_end = rhs.end();
+	for ( ; it != it_end; ++it )  // do deep copy by inserting children (and descendants)
+	{
+		associative_tree_type::insert(*it.node(), this);
+	}
+}
+
+
+// assignment operator
+template<typename stored_type, typename node_compare_type>
+tcl::multitree<stored_type, node_compare_type>& 
+tcl::multitree<stored_type, node_compare_type>::operator = (const tree_type& rhs)
+{
+	if (!associative_tree_type::is_root()) // can assign only to root node
+		return *this;
+
+	if ( this == &rhs ) // check for self assignment
+		return *this;
+
+	associative_tree_type::clear();
+	basic_tree_type::operator =(rhs);  // call base class operation
+
+	typename associative_tree_type::const_iterator it = rhs.begin();
+	const typename associative_tree_type::const_iterator it_end = rhs.end();
+	for ( ; it != it_end; ++it )  // insert children and descendants
+	{
+		associative_tree_type::insert(*it.node(), this);
+	}
+	return *this;
+}
+
+// swap
+template<typename stored_type, typename node_compare_type>
+void tcl::multitree<stored_type, node_compare_type>::swap(tree_type& rhs)
+{
+	tree_type temp(*this);
+
+	associative_tree_type::clear();
+	*this = rhs;
+
+	rhs.clear();
+	rhs = temp;
+}
+

+ 111 - 0
ModelIO/tcl_5.0.6/ordered_iterator.h

@@ -0,0 +1,111 @@
+/*******************************************************************************
+Tree Container Library: Generic container library to store data in tree-like structures.
+Copyright (c) 2006  Mitchel Haas
+
+This software is provided 'as-is', without any express or implied warranty. 
+In no event will the author be held liable for any damages arising from 
+the use of this software.
+
+Permission is granted to anyone to use this software for any purpose, 
+including commercial applications, and to alter it and redistribute it freely, 
+subject to the following restrictions:
+
+1.	The origin of this software must not be misrepresented; 
+you must not claim that you wrote the original software. 
+If you use this software in a product, an acknowledgment in the product 
+documentation would be appreciated but is not required.
+
+2.	Altered source versions must be plainly marked as such, 
+and must not be misrepresented as being the original software.
+
+3.	The above copyright notice and this permission notice may not be removed 
+or altered from any source distribution.
+
+For complete documentation on this library, see http://www.datasoftsolutions.net
+Email questions, comments or suggestions to mhaas@datasoftsolutions.net
+*******************************************************************************/
+#pragma once
+#include "child_iterator.h"
+
+namespace tcl 
+{
+	template<typename stored_type, typename node_compare_type, typename node_order_compare_type> class unique_tree;
+	template< typename stored_type, typename tree_type,  typename container_type > class associative_tree;
+	template<typename tree_type, typename node_order_compare_type> struct deref_ordered_compare;
+	template<typename stored_type, typename node_compare_type, typename node_order_compare_type > struct unique_tree_deref_less;
+
+	template<typename T, typename U, typename V> class const_unique_tree_ordered_iterator;
+	template<typename T, typename U, typename V> class unique_tree_ordered_iterator;
+
+	// comparison operators
+	template<typename T, typename U, typename V> bool operator == ( const const_unique_tree_ordered_iterator<T, U, V>& lhs, const const_unique_tree_ordered_iterator<T, U, V>& rhs ) { return lhs.it == rhs.it; }
+	template<typename T, typename U, typename V> bool operator != ( const const_unique_tree_ordered_iterator<T, U, V>& lhs, const const_unique_tree_ordered_iterator<T, U, V>& rhs ) { return !(lhs == rhs); }
+}
+
+
+/************************************************************************/
+/* ordered iterators (for unique_tree)                                  */
+/************************************************************************/
+
+
+template<typename stored_type, typename node_compare_type, typename node_order_compare_type>
+class tcl::const_unique_tree_ordered_iterator : public std::iterator<std::bidirectional_iterator_tag, stored_type>
+{
+protected:
+	// typedefs
+	typedef unique_tree<stored_type, node_compare_type, node_order_compare_type> tree_type;
+	typedef std::multiset<tree_type*, deref_ordered_compare<tree_type, node_order_compare_type> > ordered_container_type;
+
+public:
+	// constructors/destructor
+	const_unique_tree_ordered_iterator() {}
+	explicit const_unique_tree_ordered_iterator(typename ordered_container_type::const_iterator iter) : it(iter) {}
+	virtual ~const_unique_tree_ordered_iterator() {}
+
+	// overloaded operators
+	const_unique_tree_ordered_iterator& operator ++() { ++it; return *this; }
+	const_unique_tree_ordered_iterator operator ++(int) { const_unique_tree_ordered_iterator old(*this); ++*this; return old; }
+	const_unique_tree_ordered_iterator& operator --() { --it; return *this; }
+	const_unique_tree_ordered_iterator operator --(int) { const_unique_tree_ordered_iterator old(*this); --*this; return old; }
+	const stored_type& operator*() const { return  *(*it)->get(); }
+	const stored_type* operator->() const { return (*it)->get(); }
+
+	const tree_type* node() const { return *it; }
+
+	// data
+protected:
+	typename ordered_container_type::const_iterator it;
+
+	// friends
+	#if defined(_MSC_VER) && _MSC_VER < 1300
+		friend bool operator == ( const const_unique_tree_ordered_iterator& lhs, const const_unique_tree_ordered_iterator& rhs );
+	#else
+		friend bool operator ==<> ( const const_unique_tree_ordered_iterator& lhs, const const_unique_tree_ordered_iterator& rhs );
+	#endif
+};
+
+template<typename stored_type, typename node_compare_type, typename node_order_compare_type>
+class tcl::unique_tree_ordered_iterator : public tcl::const_unique_tree_ordered_iterator<stored_type, node_compare_type, node_order_compare_type>
+{
+	// typedefs
+	typedef unique_tree<stored_type, node_compare_type, node_order_compare_type> tree_type;
+	typedef std::multiset<tree_type*, deref_ordered_compare<tree_type, node_order_compare_type> > ordered_container_type;
+	using const_unique_tree_ordered_iterator<stored_type, node_compare_type, node_order_compare_type>::it;
+
+public:
+	// constructors/destructor
+	unique_tree_ordered_iterator() {}
+	explicit unique_tree_ordered_iterator(const typename const_unique_tree_ordered_iterator<stored_type, node_compare_type, node_order_compare_type>::ordered_container_type::const_iterator& iter) 
+		: const_unique_tree_ordered_iterator<stored_type, node_compare_type, node_order_compare_type>(iter) {}
+
+	// overloaded operators
+	stored_type& operator*() const { return *(*it)->get(); }
+	stored_type* operator->() const { return (*it)->get(); }
+	unique_tree_ordered_iterator& operator ++() { ++it; return *this; }
+	unique_tree_ordered_iterator operator ++(int) { unique_tree_ordered_iterator old(*this); ++*this; return old; }
+	unique_tree_ordered_iterator& operator --() { --it; return *this; }
+	unique_tree_ordered_iterator operator --(int) { unique_tree_ordered_iterator old(*this); --*this; return old; }
+
+	tree_type* node() const { return *it; }
+};
+

+ 114 - 0
ModelIO/tcl_5.0.6/populateAlphabet.h

@@ -0,0 +1,114 @@
+#pragma once
+#include <cassert>
+#include <iostream>
+
+template<typename TreeType>
+void populateAlphabet(TreeType& alphaTree, bool duplicateVowels = false, bool verbose = false)
+{
+	// create a child iterator
+	typename TreeType::iterator it;  
+
+	// insert first node, A
+	it = alphaTree.insert(Alpha('A'));
+	assert(it != alphaTree.end() && it->getLetter() == 'A' );
+	if (duplicateVowels) {
+		// try to insert another A.  Should fail for tree & unique_tree
+		it = alphaTree.insert(Alpha('A'));
+		if ( it == alphaTree.end() && verbose)
+			std::cout << alphaTree.get()->getLetter() << ": Couldn't insert second A." << std::endl;
+	}
+
+	// insert D and E under A
+	it = alphaTree.begin();
+	assert(it != alphaTree.end() && it->getLetter() == 'A');
+	typename TreeType::iterator child_it = it.node()->insert(Alpha('D'));
+	assert(child_it != it.node()->end() && child_it->getLetter() == 'D');  
+	it.node()->insert(Alpha('E'));
+
+
+	it = it.node()->begin();
+	// insert  J under D
+	it.node()->insert(Alpha('J'));
+	// insert K under D and remember inserted node
+	child_it = it.node()->insert(Alpha('K'));
+	assert(child_it != it.node()->end() && child_it->getLetter() == 'K');
+	// insert R and S under K
+	child_it.node()->insert(Alpha('R'));
+	child_it.node()->insert(Alpha('S'));
+
+	// increment it (now at D) to point to E
+	++it;
+	// insert L under E
+	it.node()->insert(Alpha('L'));
+
+	it = alphaTree.insert(Alpha('B'));
+	// insert second E and F under B
+	if (duplicateVowels) {
+		child_it = it.node()->insert(Alpha('E'));  // should fail for unique_tree
+		if ( child_it == it.node()->end() && verbose)
+			std::cout << alphaTree.get()->getLetter() << ": Couldn't insert second E." << std::endl;
+	}
+	child_it = it.node()->insert(Alpha('F'));
+	// insert M under F
+	it = child_it;
+	child_it = it.node()->insert(Alpha('M'));
+	// insert T and U under M
+	child_it.node()->insert(Alpha('T'));
+	child_it.node()->insert(Alpha('U'));
+
+	// insert N under F  (it still points to F)
+	child_it = it.node()->insert(Alpha('N'));
+	// insert second U and V under N
+	if (duplicateVowels) {
+		if ( child_it.node()->insert(Alpha('U')) == child_it.node()->end() && verbose) // should fail for unique_tree
+			std::cout << alphaTree.get()->getLetter() << ": Couldn't insert second U." << std::endl;
+	}
+
+	child_it.node()->insert(Alpha('V'));
+
+	it = alphaTree.insert(Alpha('C'));
+	// insert G and H under C
+	it.node()->insert(Alpha('G'));
+	child_it = it.node()->insert(Alpha('H'));
+	// insert O under H
+	it = child_it;
+	child_it = it.node()->insert(Alpha('O'));
+	if (duplicateVowels) {
+		// try to insert another O
+		child_it = it.node()->insert(Alpha('O')); // should fail for tree/unique_tree
+		if ( child_it == it.node()->end() && verbose)
+			std::cout << alphaTree.get()->getLetter() << ": Couldn't insert second O." << std::endl;
+	}
+
+	child_it = it.node()->begin();
+	assert(child_it != it.node()->end() && child_it->getLetter() == 'O');
+	// insert W under O
+	child_it.node()->insert(Alpha('W'));
+	// insert P under H
+	it.node()->insert(Alpha('P'));
+
+	// insert I under C using parent of H (which is C)
+	child_it = it.node()->parent()->insert(Alpha('I'));
+	assert(child_it->getLetter() == 'I');
+	// insert second I under I
+	it = child_it;
+	if (duplicateVowels) {
+		child_it = it.node()->insert(Alpha('I'));  // should fail for unique tree
+		if ( child_it == it.node()->end() && verbose)
+			std::cout << alphaTree.get()->getLetter() << ": Couldn't insert second I." << std::endl;
+	}
+
+	// insert Q under original I
+	child_it = it.node()->insert(Alpha('Q'));
+	// insert X under Q
+	it = child_it;
+	child_it = it.node()->insert(Alpha('X'));
+	// insert Y and Z under X
+	child_it.node()->insert(Alpha('Y'));
+	child_it.node()->insert(Alpha('Z'));
+
+  if (verbose)
+	  std::cout << std::endl << std::endl;
+}
+
+

+ 124 - 0
ModelIO/tcl_5.0.6/reverse_iterator.h

@@ -0,0 +1,124 @@
+/*******************************************************************************
+Tree Container Library: Generic container library to store data in tree-like structures.
+Copyright (c) 2006  Mitchel Haas
+
+This software is provided 'as-is', without any express or implied warranty. 
+In no event will the author be held liable for any damages arising from 
+the use of this software.
+
+Permission is granted to anyone to use this software for any purpose, 
+including commercial applications, and to alter it and redistribute it freely, 
+subject to the following restrictions:
+
+1.	The origin of this software must not be misrepresented; 
+you must not claim that you wrote the original software. 
+If you use this software in a product, an acknowledgment in the product 
+documentation would be appreciated but is not required.
+
+2.	Altered source versions must be plainly marked as such, 
+and must not be misrepresented as being the original software.
+
+3.	The above copyright notice and this permission notice may not be removed 
+or altered from any source distribution.
+
+For complete documentation on this library, see http://www.datasoftsolutions.net
+Email questions, comments or suggestions to mhaas@datasoftsolutions.net
+*******************************************************************************/
+#pragma once
+#include "child_iterator.h"
+#include <iterator>
+
+namespace tcl 
+{
+	template<typename stored_type, typename tree_type, typename container_type> class associative_reverse_iterator;
+
+	template<typename T, typename U, typename V> class const_associative_reverse_iterator;
+	template<typename T, typename U, typename V> class associative_reverse_iterator;
+	template<typename T, typename U, typename V> class const_sequential_reverse_iterator;
+	template<typename T, typename U, typename V> class const_sequential_reverse_iterator;
+}
+
+
+
+template<typename stored_type, typename tree_type, typename container_type>
+class tcl::const_associative_reverse_iterator : public tcl::const_associative_iterator<stored_type, tree_type, container_type>
+{
+	typedef const_associative_iterator<stored_type, tree_type, container_type> associative_iterator_type;
+public:
+	const_associative_reverse_iterator() : associative_iterator_type() {}
+	explicit const_associative_reverse_iterator(const associative_iterator_type& _it) : associative_iterator_type(_it) {}
+	const_associative_reverse_iterator(associative_reverse_iterator<stored_type, tree_type, container_type>& _it) : associative_iterator_type(_it.it) {}
+
+	const stored_type& operator*() const { associative_iterator_type tmp(*this);  return (*--tmp); }
+	const stored_type* operator->() const { associative_iterator_type tmp(*this); --tmp; return tmp.operator ->(); }
+	const_associative_reverse_iterator& operator ++() { associative_iterator_type::operator --(); return *this; }
+	const_associative_reverse_iterator operator ++(int) { const_associative_reverse_iterator old(*this); ++*this; return old; }
+	const_associative_reverse_iterator& operator --() { associative_iterator_type::operator ++(); return *this; }
+	const_associative_reverse_iterator operator --(int) { const_associative_reverse_iterator old(*this); --*this; return old; }
+
+	const tree_type* node() const { associative_iterator_type tmp(*this); --tmp; return tmp.node(); }
+	associative_iterator_type base() const { return associative_iterator_type(*this); }
+};
+
+template<typename stored_type, typename tree_type, typename container_type>
+class tcl::associative_reverse_iterator : public tcl::const_associative_reverse_iterator<stored_type, tree_type, container_type>
+{
+	typedef associative_iterator<stored_type, tree_type, container_type> associative_iterator_type;
+	typedef const_associative_iterator<stored_type, tree_type, container_type> const_associative_iterator_type;
+	typedef const_associative_reverse_iterator<stored_type, tree_type, container_type> base_reverse_iterator_type;
+public:
+	associative_reverse_iterator() : base_reverse_iterator_type() {}
+	explicit associative_reverse_iterator(const associative_iterator_type& _it) : const_associative_reverse_iterator<stored_type, tree_type, container_type>(_it) {}
+
+	stored_type& operator*() const {return const_cast<stored_type&>(base_reverse_iterator_type::operator*()); }
+	stored_type* operator->() const { return const_cast<stored_type*>(base_reverse_iterator_type::operator->()); }
+	associative_reverse_iterator& operator ++() { base_reverse_iterator_type::operator ++(); return *this; }
+	associative_reverse_iterator operator ++(int) { associative_reverse_iterator old(*this); ++*this; return old; }
+	associative_reverse_iterator& operator --() { base_reverse_iterator_type::operator --(); return *this; }
+	associative_reverse_iterator operator --(int) { associative_reverse_iterator old(*this); --*this; return old; }
+
+	tree_type* node() const { return const_cast<tree_type*>(base_reverse_iterator_type::node()); }
+	associative_iterator_type base() const { associative_iterator_type _it; _it.it = const_associative_iterator_type::it; _it.pParent = const_associative_iterator_type::pParent; return _it; }
+};
+
+
+template<typename stored_type, typename tree_type, typename container_type>
+class tcl::const_sequential_reverse_iterator : public tcl::const_sequential_iterator<stored_type, tree_type, container_type>
+{
+	typedef const_sequential_iterator<stored_type, tree_type, container_type> sequential_iterator_type;
+public:
+	const_sequential_reverse_iterator() : sequential_iterator_type() {}
+	explicit const_sequential_reverse_iterator(const sequential_iterator_type& _it) : sequential_iterator_type(_it) {}
+
+	const stored_type& operator*() const { sequential_iterator_type tmp(*this);  return (*--tmp); }
+	const stored_type* operator->() const { sequential_iterator_type tmp(*this); --tmp; return tmp.operator ->(); }
+	const_sequential_reverse_iterator& operator ++() { sequential_iterator_type::operator --(); return *this; }
+	const_sequential_reverse_iterator operator ++(int) { const_sequential_reverse_iterator old(*this); ++*this; return old; }
+	const_sequential_reverse_iterator& operator --() { sequential_iterator_type::operator ++(); return *this; }
+	const_sequential_reverse_iterator operator --(int) { const_sequential_reverse_iterator old(*this); --*this; return old; }
+
+	const tree_type* node() const { sequential_iterator_type tmp(*this); --tmp; return tmp.node(); }
+	sequential_iterator_type base() const { return sequential_iterator_type(*this); }
+};
+
+template<typename stored_type, typename tree_type, typename container_type>
+class tcl::sequential_reverse_iterator : public tcl::const_sequential_reverse_iterator<stored_type, tree_type, container_type>
+{
+	typedef sequential_iterator<stored_type, tree_type, container_type> sequential_iterator_type;
+	typedef const_sequential_iterator<stored_type, tree_type, container_type> const_sequential_iterator_type;
+	typedef const_sequential_reverse_iterator<stored_type, tree_type, container_type> base_reverse_iterator_type;
+public:
+	sequential_reverse_iterator() : base_reverse_iterator_type() {}
+	explicit sequential_reverse_iterator(const sequential_iterator_type& _it) : const_sequential_reverse_iterator<stored_type, tree_type, container_type>(_it) {}
+
+	stored_type& operator*() const { return const_cast<stored_type&>(base_reverse_iterator_type::operator*()); }
+	stored_type* operator->() const { return const_cast<stored_type*>(base_reverse_iterator_type::operator->()); }
+	sequential_reverse_iterator& operator ++() { base_reverse_iterator_type::operator ++(); return *this; }
+	sequential_reverse_iterator operator ++(int) { sequential_reverse_iterator old(*this); ++*this; return old; }
+	sequential_reverse_iterator& operator --() { base_reverse_iterator_type::operator --(); return *this; }
+	sequential_reverse_iterator operator --(int) { sequential_reverse_iterator old(*this); --*this; return old; }
+
+	tree_type* node() const { return const_cast<tree_type*>(base_reverse_iterator_type::node()); }
+	sequential_iterator_type base() const { sequential_iterator_type _it; _it.it = const_sequential_iterator_type::it; _it.pParent = const_sequential_iterator_type::pParent; return _it; }
+};
+

+ 119 - 0
ModelIO/tcl_5.0.6/reverse_node_iterator.h

@@ -0,0 +1,119 @@
+/*******************************************************************************
+Tree Container Library: Generic container library to store data in tree-like structures.
+Copyright (c) 2006  Mitchel Haas
+
+This software is provided 'as-is', without any express or implied warranty. 
+In no event will the author be held liable for any damages arising from 
+the use of this software.
+
+Permission is granted to anyone to use this software for any purpose, 
+including commercial applications, and to alter it and redistribute it freely, 
+subject to the following restrictions:
+
+1.	The origin of this software must not be misrepresented; 
+you must not claim that you wrote the original software. 
+If you use this software in a product, an acknowledgment in the product 
+documentation would be appreciated but is not required.
+
+2.	Altered source versions must be plainly marked as such, 
+and must not be misrepresented as being the original software.
+
+3.	The above copyright notice and this permission notice may not be removed 
+or altered from any source distribution.
+
+For complete documentation on this library, see http://www.datasoftsolutions.net
+Email questions, comments or suggestions to mhaas@datasoftsolutions.net
+*******************************************************************************/
+#pragma once
+#include "child_node_iterator.h"
+#include <iterator>
+
+namespace tcl 
+{
+	template<typename stored_type, typename tree_type, typename container_type> class associative_reverse_node_iterator;
+
+	template<typename T, typename U, typename V> class const_associative_reverse_node_iterator;
+	template<typename T, typename U, typename V> class associative_reverse_node_iterator;
+	template<typename T, typename U, typename V> class const_sequential_reverse_node_iterator;
+	template<typename T, typename U, typename V> class sequential_reverse_node_iterator;
+}
+
+
+template<typename stored_type, typename tree_type, typename container_type>
+class tcl::const_associative_reverse_node_iterator : public tcl::const_associative_node_iterator<stored_type, tree_type, container_type>
+{
+	typedef const_associative_node_iterator<stored_type, tree_type, container_type> associative_iterator_type;
+public:
+	const_associative_reverse_node_iterator() : associative_iterator_type() {}
+	explicit const_associative_reverse_node_iterator(const associative_iterator_type& _it) : associative_iterator_type(_it) {}
+	const_associative_reverse_node_iterator(associative_reverse_node_iterator<stored_type, tree_type, container_type>& _it) : associative_iterator_type(_it.it) {}
+
+	const tree_type& operator*() const { associative_iterator_type tmp(*this);  return (*--tmp); }
+	const tree_type* operator->() const { associative_iterator_type tmp(*this); --tmp; return tmp.operator ->(); }
+	const_associative_reverse_node_iterator& operator ++() { associative_iterator_type::operator --(); return *this; }
+	const_associative_reverse_node_iterator operator ++(int) { const_associative_reverse_node_iterator old(*this); ++*this; return old; }
+	const_associative_reverse_node_iterator& operator --() { associative_iterator_type::operator ++(); return *this; }
+	const_associative_reverse_node_iterator operator --(int) { const_associative_reverse_node_iterator old(*this); --*this; return old; }
+
+	associative_iterator_type base() const { return associative_iterator_type(*this); }
+};
+
+template<typename stored_type, typename tree_type, typename container_type>
+class tcl::associative_reverse_node_iterator : public tcl::const_associative_reverse_node_iterator<stored_type, tree_type, container_type>
+{
+	typedef associative_node_iterator<stored_type, tree_type, container_type> associative_iterator_type;
+	typedef const_associative_node_iterator<stored_type, tree_type, container_type> const_associative_iterator_type;
+	typedef const_associative_reverse_node_iterator<stored_type, tree_type, container_type> base_reverse_iterator_type;
+public:
+	associative_reverse_node_iterator() : base_reverse_iterator_type() {}
+	explicit associative_reverse_node_iterator(const associative_iterator_type& _it) : const_associative_reverse_node_iterator<stored_type, tree_type, container_type>(_it) {}
+
+	tree_type& operator*() const {return const_cast<tree_type&>(base_reverse_iterator_type::operator*()); }
+	tree_type* operator->() const { return const_cast<tree_type*>(base_reverse_iterator_type::operator->()); }
+	associative_reverse_node_iterator& operator ++() { base_reverse_iterator_type::operator ++(); return *this; }
+	associative_reverse_node_iterator operator ++(int) { associative_reverse_node_iterator old(*this); ++*this; return old; }
+	associative_reverse_node_iterator& operator --() { base_reverse_iterator_type::operator --(); return *this; }
+	associative_reverse_node_iterator operator --(int) { associative_reverse_node_iterator old(*this); --*this; return old; }
+
+	associative_iterator_type base() const { associative_iterator_type _it; _it.it = const_associative_iterator_type::it; _it.pParent = const_associative_iterator_type::pParent; return _it; }
+};
+
+
+template<typename stored_type, typename tree_type, typename container_type>
+class tcl::const_sequential_reverse_node_iterator : public tcl::const_sequential_node_iterator<stored_type, tree_type, container_type>
+{
+	typedef const_sequential_node_iterator<stored_type, tree_type, container_type> sequential_iterator_type;
+public:
+	const_sequential_reverse_node_iterator() : sequential_iterator_type() {}
+	explicit const_sequential_reverse_node_iterator(const sequential_iterator_type& _it) : sequential_iterator_type(_it) {}
+
+	const tree_type& operator*() const { sequential_iterator_type tmp(*this);  return (*--tmp); }
+	const tree_type* operator->() const { sequential_iterator_type tmp(*this); --tmp; return tmp.operator ->(); }
+	const_sequential_reverse_node_iterator& operator ++() { sequential_iterator_type::operator --(); return *this; }
+	const_sequential_reverse_node_iterator operator ++(int) { const_sequential_reverse_node_iterator old(*this); ++*this; return old; }
+	const_sequential_reverse_node_iterator& operator --() { sequential_iterator_type::operator ++(); return *this; }
+	const_sequential_reverse_node_iterator operator --(int) { const_sequential_reverse_node_iterator old(*this); --*this; return old; }
+
+	sequential_iterator_type base() const { return sequential_iterator_type(*this); }
+};
+
+template<typename stored_type, typename tree_type, typename container_type>
+class tcl::sequential_reverse_node_iterator : public tcl::const_sequential_reverse_node_iterator<stored_type, tree_type, container_type>
+{
+	typedef sequential_node_iterator<stored_type, tree_type, container_type> sequential_iterator_type;
+	typedef const_sequential_node_iterator<stored_type, tree_type, container_type> const_sequential_iterator_type;
+	typedef const_sequential_reverse_node_iterator<stored_type, tree_type, container_type> base_reverse_iterator_type;
+public:
+	sequential_reverse_node_iterator() : base_reverse_iterator_type() {}
+	explicit sequential_reverse_node_iterator(const sequential_iterator_type& _it) : const_sequential_reverse_node_iterator<stored_type, tree_type, container_type>(_it) {}
+
+	tree_type& operator*() const { return const_cast<tree_type&>(base_reverse_iterator_type::operator*()); }
+	tree_type* operator->() const { return const_cast<tree_type*>(base_reverse_iterator_type::operator->()); }
+	sequential_reverse_node_iterator& operator ++() { base_reverse_iterator_type::operator ++(); return *this; }
+	sequential_reverse_node_iterator operator ++(int) { sequential_reverse_node_iterator old(*this); ++*this; return old; }
+	sequential_reverse_node_iterator& operator --() { base_reverse_iterator_type::operator --(); return *this; }
+	sequential_reverse_node_iterator operator --(int) { sequential_reverse_node_iterator old(*this); --*this; return old; }
+
+	sequential_iterator_type base() const { sequential_iterator_type _it; _it.it = const_sequential_iterator_type::it; _it.pParent = const_sequential_iterator_type::pParent; return _it; }
+};
+

+ 283 - 0
ModelIO/tcl_5.0.6/sequential_tree.h

@@ -0,0 +1,283 @@
+/*******************************************************************************
+Tree Container Library: Generic container library to store data in tree-like structures.
+Copyright (c) 2006  Mitchel Haas
+
+This software is provided 'as-is', without any express or implied warranty. 
+In no event will the author be held liable for any damages arising from 
+the use of this software.
+
+Permission is granted to anyone to use this software for any purpose, 
+including commercial applications, and to alter it and redistribute it freely, 
+subject to the following restrictions:
+
+1.	The origin of this software must not be misrepresented; 
+you must not claim that you wrote the original software. 
+If you use this software in a product, an acknowledgment in the product 
+documentation would be appreciated but is not required.
+
+2.	Altered source versions must be plainly marked as such, 
+and must not be misrepresented as being the original software.
+
+3.	The above copyright notice and this permission notice may not be removed 
+or altered from any source distribution.
+
+For complete documentation on this library, see http://www.datasoftsolutions.net
+Email questions, comments or suggestions to mhaas@datasoftsolutions.net
+*******************************************************************************/
+#pragma once
+#include "basic_tree.h"
+#include "child_iterator.h"
+#include "child_node_iterator.h"
+#include "descendant_iterator.h"
+#include "descendant_node_iterator.h"
+#include "reverse_iterator.h"
+#include "reverse_node_iterator.h"
+#include <vector>
+#include <algorithm>
+#include <stdexcept>
+
+namespace tcl 
+{
+	template<typename T> class sequential_tree;
+
+	// overloaded comparison operations
+	template<typename T> bool operator == (const sequential_tree<T>& lhs, const sequential_tree<T>& rhs);
+	template<typename T> bool operator <  (const sequential_tree<T>& lhs, const sequential_tree<T>& rhs);
+	template<typename T> bool operator != (const sequential_tree<T>& lhs, const sequential_tree<T>& rhs) { return !(lhs == rhs); }
+	template<typename T> bool operator >  (const sequential_tree<T>& lhs, const sequential_tree<T>& rhs) { return rhs < lhs; }
+	template<typename T> bool operator <= (const sequential_tree<T>& lhs, const sequential_tree<T>& rhs) { return !(rhs < lhs); }
+	template<typename T> bool operator >= (const sequential_tree<T>& lhs, const sequential_tree<T>& rhs) { return !(lhs < rhs); }
+}
+
+template<typename stored_type>
+class tcl::sequential_tree : public tcl::basic_tree<stored_type, sequential_tree<stored_type>, std::vector<sequential_tree<stored_type>* > >
+{
+public:
+	// typedefs
+	typedef sequential_tree<stored_type> tree_type;
+	typedef std::vector<tree_type*> container_type;
+	typedef basic_tree<stored_type, tree_type, container_type > basic_tree_type;
+	typedef typename basic_tree_type::size_type basic_size_type;
+	using basic_tree_type::size_type;
+
+	// element iterator typedefs
+	typedef const_sequential_iterator<stored_type, tree_type, container_type>															const_iterator;
+	typedef sequential_iterator<stored_type, tree_type, container_type>																		iterator;
+	typedef const_pre_order_descendant_iterator<stored_type, tree_type, container_type, tree_type>				const_pre_order_iterator;
+	typedef pre_order_descendant_iterator<stored_type, tree_type, container_type, tree_type>							pre_order_iterator;
+	typedef const_post_order_descendant_iterator<stored_type, tree_type, container_type, tree_type>				const_post_order_iterator;
+	typedef post_order_descendant_iterator<stored_type, tree_type, container_type, tree_type>							post_order_iterator;
+	typedef const_level_order_descendant_iterator<stored_type, tree_type, container_type, tree_type>			const_level_order_iterator;
+	typedef level_order_descendant_iterator<stored_type, tree_type, container_type, tree_type>						level_order_iterator;
+	typedef sequential_reverse_iterator<stored_type, tree_type, container_type>														reverse_iterator;
+	typedef const_sequential_reverse_iterator<stored_type, tree_type, container_type>											const_reverse_iterator;
+
+	// node iterator typedefs
+	typedef const_sequential_node_iterator<stored_type, tree_type, container_type>												const_node_iterator;
+	typedef sequential_node_iterator<stored_type, tree_type, container_type>															node_iterator;
+	typedef const_pre_order_descendant_node_iterator<stored_type, tree_type, container_type, tree_type>		const_pre_order_node_iterator;
+	typedef pre_order_descendant_node_iterator<stored_type, tree_type, container_type, tree_type>					pre_order_node_iterator;
+	typedef const_post_order_descendant_node_iterator<stored_type, tree_type, container_type, tree_type>	const_post_order_node_iterator;
+	typedef post_order_descendant_node_iterator<stored_type, tree_type, container_type, tree_type>				post_order_node_iterator;
+	typedef const_level_order_descendant_node_iterator<stored_type, tree_type, container_type, tree_type> const_level_order_node_iterator;
+	typedef level_order_descendant_node_iterator<stored_type, tree_type, container_type, tree_type>				level_order_node_iterator;
+	typedef sequential_reverse_node_iterator<stored_type, tree_type, container_type>											reverse_node_iterator;
+	typedef const_sequential_reverse_node_iterator<stored_type, tree_type, container_type>								const_reverse_node_iterator;
+
+	// constructors/destructor
+	explicit sequential_tree(const stored_type& value = stored_type()) : basic_tree_type(value) {}
+	explicit sequential_tree(typename basic_tree_type::size_type sz, const stored_type& value = stored_type()) : basic_tree_type(stored_type()) { insert(end(), sz, value); }
+	sequential_tree(const tree_type& rhs);  // copy constructor
+	template<typename iterator_type> sequential_tree(iterator_type it_beg, iterator_type it_end, const stored_type& value = stored_type()) : basic_tree_type(value) { while (it_beg != it_end) { insert(*it_beg); ++it_beg; } }
+	~sequential_tree() {clear(); }
+
+	// assignment operator
+	tree_type& operator = (const tree_type& rhs);
+
+	// child element iterator accessors
+	const_iterator begin() const { return const_iterator(basic_tree_type::children.begin(), this); }
+	const_iterator end() const { return const_iterator(basic_tree_type::children.end(), this); }
+	iterator begin() { return iterator(basic_tree_type::children.begin(), this); }
+	iterator end() { return iterator(basic_tree_type::children.end(), this); }
+
+	// child node iterator accessors
+	const_node_iterator node_begin() const { return const_node_iterator(basic_tree_type::children.begin(), this); }
+	const_node_iterator node_end() const { return const_node_iterator(basic_tree_type::children.end(), this); }
+	node_iterator node_begin() { return node_iterator(basic_tree_type::children.begin(), this); }
+	node_iterator node_end() { return node_iterator(basic_tree_type::children.end(), this); }
+	
+
+	// child element reverse iterator accessors
+	const_reverse_iterator rbegin() const {return const_reverse_iterator(end()); }
+	const_reverse_iterator rend() const {return const_reverse_iterator(begin()); }
+	reverse_iterator rbegin() {return reverse_iterator(end()); }
+	reverse_iterator rend() { return reverse_iterator(begin()); }
+
+	// descendant element iterator accessors
+	pre_order_iterator pre_order_begin() { return pre_order_iterator(this, true); }
+	pre_order_iterator pre_order_end() { return pre_order_iterator(this, false); }
+	const_pre_order_iterator pre_order_begin() const { return const_pre_order_iterator(this, true); }
+	const_pre_order_iterator pre_order_end() const { return const_pre_order_iterator(this, false); }
+	post_order_iterator post_order_begin() { return post_order_iterator(this, true); }
+	post_order_iterator post_order_end() { return post_order_iterator(this, false); }
+	const_post_order_iterator post_order_begin() const { return const_post_order_iterator(this, true); }
+	const_post_order_iterator post_order_end() const { return const_post_order_iterator(this, false); }
+	level_order_iterator level_order_begin() { return level_order_iterator(this, true); }
+	level_order_iterator level_order_end() { return level_order_iterator(this, false); }
+	const_level_order_iterator level_order_begin() const { return const_level_order_iterator(this, true); }
+	const_level_order_iterator level_order_end() const { return const_level_order_iterator(this, false); }
+
+	// child node reverse iterator accessors
+	const_reverse_node_iterator node_rbegin() const {return const_reverse_node_iterator(node_end()); }
+	const_reverse_node_iterator node_rend() const {return const_reverse_node_iterator(node_begin()); }
+	reverse_node_iterator node_rbegin() {return reverse_node_iterator(node_end()); }
+	reverse_node_iterator node_rend() { return reverse_node_iterator(node_begin()); }
+
+	// descendant node iterator accessors
+	pre_order_node_iterator pre_order_node_begin() { return pre_order_node_iterator(this, true); }
+	pre_order_node_iterator pre_order_node_end() { return pre_order_node_iterator(this, false); }
+	const_pre_order_node_iterator pre_order_node_begin() const { return const_pre_order_node_iterator(this, true); }
+	const_pre_order_node_iterator pre_order_node_end() const { return const_pre_order_node_iterator(this, false); }
+	post_order_node_iterator post_order_node_begin() { return post_order_node_iterator(this, true); }
+	post_order_node_iterator post_order_node_end() { return post_order_node_iterator(this, false); }
+	const_post_order_node_iterator post_order_node_begin() const { return const_post_order_node_iterator(this, true); }
+	const_post_order_node_iterator post_order_node_end() const { return const_post_order_node_iterator(this, false); }
+	level_order_node_iterator level_order_node_begin() { return level_order_node_iterator(this, true); }
+	level_order_node_iterator level_order_node_end() { return level_order_node_iterator(this, false); }
+	const_level_order_node_iterator level_order_node_begin() const { return const_level_order_node_iterator(this, true); }
+	const_level_order_node_iterator level_order_node_end() const { return const_level_order_node_iterator(this, false); }
+	
+
+	// public interface
+	typename basic_tree_type::size_type capacity() const { return basic_tree_type::children.capacity(); }
+	void reserve(typename basic_tree_type::size_type sz) { basic_tree_type::children.reserve(sz); }
+	tree_type& front() { return *basic_tree_type::children.front(); }
+	tree_type& back() { return *basic_tree_type::children.back(); }
+	const tree_type& front() const { return *basic_tree_type::children.front(); }
+	const tree_type& back() const { return *basic_tree_type::children.back(); }
+	void push_back(const stored_type& value);
+	void pop_back() { iterator it = end(); erase(--it); }
+
+	iterator insert(const stored_type& value);
+	iterator insert(const tree_type& tree_obj );
+	iterator insert(const_iterator pos, const stored_type& value);
+	iterator insert(const const_iterator& pos, const tree_type& tree_obj);
+	void insert(const_iterator pos, typename basic_tree_type::size_type num, const stored_type& value);
+	#if !defined(_MSC_VER) || _MSC_VER >= 1300 // insert range not available for VC6
+	template<typename iterator_type> void insert(const_iterator pos, iterator_type it_beg, iterator_type it_end) 
+	{ while (it_beg != it_end) { pos = insert(pos, *it_beg++); ++pos; } }
+	#endif
+	void set(const stored_type& value) { basic_tree_type::set(value); }
+	void set(const tree_type& tree_obj);
+	void swap(tree_type& rhs);
+	iterator erase(iterator it);
+	iterator erase(iterator beg_it, iterator end_it);
+	void clear();
+
+	// subscript operators
+	tree_type& operator [](basic_size_type index);
+	const tree_type& operator [](basic_size_type index) const; 
+
+	// children sort operations
+	template<typename T> void sort(const T& comparer) { std::sort(basic_tree_type::children.begin(), basic_tree_type::children.end(), sort_functor_deref<T>(comparer)); }
+	void sort() { std::sort(basic_tree_type::children.begin(), basic_tree_type::children.end(), sort_deref()); }
+
+	// descendant sort operations
+	template<typename T> void sort_descendants(const T& comparer)
+	{
+		post_order_iterator it = post_order_begin(), it_end = post_order_end();
+		for ( ; it != it_end; ++it )
+		{
+			it.node()->sort(comparer);
+		}
+	}
+	void sort_descendants(); 
+
+	// overloaded iterator arithmetic operators
+	friend const_iterator operator +(const const_iterator& lhs, typename basic_tree_type::size_type n) 
+	{ const_iterator temp(lhs); temp += n; return temp; }
+
+	friend const_iterator operator +(typename basic_tree_type::size_type n, const const_iterator& rhs)
+	{ const_iterator temp(rhs); temp += n; return temp; }
+
+	friend const_iterator operator -(const const_iterator& lhs, typename basic_tree_type::size_type n)
+	{ const_iterator temp(lhs); temp -= n; return temp; }
+
+	friend iterator operator +(const iterator& lhs, typename basic_tree_type::size_type n)
+	{ iterator temp(lhs); temp += n; return temp; }
+
+	friend iterator operator +(typename basic_tree_type::size_type n, const iterator& rhs)
+	{ iterator temp(rhs); temp += n; return temp; }
+
+	friend iterator operator -(const iterator& lhs, typename basic_tree_type::size_type n)
+	{ iterator temp(lhs); temp -= n; return temp; }
+
+	// overloaded node iterator arithmetic operators
+	friend const_node_iterator operator +(const const_node_iterator& lhs, typename basic_tree_type::size_type n) 
+	{ const_node_iterator temp(lhs); temp += n; return temp; }
+
+	friend const_node_iterator operator +(typename basic_tree_type::size_type n, const const_node_iterator& rhs)
+	{ const_node_iterator temp(rhs); temp += n; return temp; }
+
+	friend const_node_iterator operator -(const const_node_iterator& lhs, typename basic_tree_type::size_type n)
+	{ const_node_iterator temp(lhs); temp -= n; return temp; }
+
+	friend node_iterator operator +(const node_iterator& lhs, typename basic_tree_type::size_type n)
+	{ node_iterator temp(lhs); temp += n; return temp; }
+
+	friend node_iterator operator +(typename basic_tree_type::size_type n, const node_iterator& rhs)
+	{ node_iterator temp(rhs); temp += n; return temp; }
+
+	friend node_iterator operator -(const node_iterator& lhs, typename basic_tree_type::size_type n)
+	{ node_iterator temp(lhs); temp -= n; return temp; }
+
+
+private:
+	// sort() dereference functor
+	struct sort_deref
+	{
+		bool operator() (const tree_type* lhs, const tree_type* rhs)
+		{
+			return *lhs->get() < *rhs->get();
+		}
+	};
+
+	// sort<T>() dereference functor
+	template<typename T>
+	struct sort_functor_deref 
+	{
+		explicit sort_functor_deref(const T& sort_functor_) : sort_functor(sort_functor_) {}
+		bool operator() (const tree_type* lhs, const tree_type* rhs) const
+		{
+			return sort_functor(*lhs->get(), *rhs->get());
+		}
+		sort_functor_deref& operator = (const sort_functor_deref& rhs) { sort_functor = rhs->sort_functor; return *this; }
+		const T& sort_functor;
+	};
+
+	// friends
+	#if defined(_MSC_VER) && _MSC_VER < 1300
+		friend class const_pre_order_descendant_iterator<stored_type, tree_type, container_type, tree_type>;
+		friend class const_post_order_descendant_iterator<stored_type, tree_type, container_type, tree_type>;
+		friend class const_level_order_descendant_iterator<stored_type, tree_type, container_type, tree_type>;
+		friend class const_pre_order_descendant_node_iterator<stored_type, tree_type, container_type, tree_type>;
+		friend class const_post_order_descendant_node_iterator<stored_type, tree_type, container_type, tree_type>;
+		friend class const_level_order_descendant_node_iterator<stored_type, tree_type, container_type, tree_type>;
+		friend bool operator == (const tree_type& lhs, const tree_type& rhs);
+		friend bool operator <  (const tree_type& lhs, const tree_type& rhs);
+	#else
+		template<typename T, typename U, typename V, typename W> friend class const_pre_order_descendant_iterator;
+		template<typename T, typename U, typename V, typename W> friend class const_post_order_descendant_iterator;
+		template<typename T, typename U, typename V, typename W> friend class const_level_order_descendant_iterator;
+		template<typename T, typename U, typename V, typename W> friend class const_pre_order_descendant_node_iterator;
+		template<typename T, typename U, typename V, typename W> friend class const_post_order_descendant_node_iterator;
+		template<typename T, typename U, typename V, typename W> friend class const_level_order_descendant_node_iterator;
+		friend bool operator ==<> (const tree_type& lhs, const tree_type& rhs);
+		friend bool operator < <> (const tree_type& lhs, const tree_type& rhs);
+	#endif
+};
+
+
+
+
+#include "sequential_tree.inl"

+ 333 - 0
ModelIO/tcl_5.0.6/sequential_tree.inl

@@ -0,0 +1,333 @@
+/*******************************************************************************
+Tree Container Library: Generic container library to store data in tree-like structures.
+Copyright (c) 2006  Mitchel Haas
+
+This software is provided 'as-is', without any express or implied warranty. 
+In no event will the author be held liable for any damages arising from 
+the use of this software.
+
+Permission is granted to anyone to use this software for any purpose, 
+including commercial applications, and to alter it and redistribute it freely, 
+subject to the following restrictions:
+
+1.	The origin of this software must not be misrepresented; 
+you must not claim that you wrote the original software. 
+If you use this software in a product, an acknowledgment in the product 
+documentation would be appreciated but is not required.
+
+2.	Altered source versions must be plainly marked as such, 
+and must not be misrepresented as being the original software.
+
+3.	The above copyright notice and this permission notice may not be removed 
+or altered from any source distribution.
+
+For complete documentation on this library, see http://www.datasoftsolutions.net
+Email questions, comments or suggestions to mhaas@datasoftsolutions.net
+*******************************************************************************/
+
+// copy constructor
+template<typename stored_type>
+tcl::sequential_tree<stored_type>::sequential_tree(const tree_type& rhs) : basic_tree_type(rhs)
+{
+	const_iterator it = rhs.begin();
+	const const_iterator it_end = rhs.end();
+	for ( ; it != it_end; ++it ) // do a deep copy by inserting children (and descendants)
+	{
+		insert(*it.node());
+	}
+}
+
+// assignment operator
+template<typename stored_type>
+tcl::sequential_tree<stored_type>& tcl::sequential_tree<stored_type>::operator = (const tree_type& rhs)
+{
+	if ( this == &rhs ) // check for self assignment
+		return *this;
+
+	clear();
+	basic_tree_type::operator =(rhs); // call base class operation
+
+	const_iterator it = rhs.begin(), it_end = rhs.end();
+	for ( ; it != it_end; ++it ) // insert children and descendants
+	{
+		insert(*it.node());
+	}
+	return *this;
+}
+
+// swap
+template<typename stored_type>
+void tcl::sequential_tree<stored_type>::swap(tree_type& rhs)
+{
+	tree_type temp(*this);
+
+	clear();
+	*this = rhs;
+
+	rhs.clear();
+	rhs = temp;
+}
+
+// insert(const stored_type&)
+template< typename stored_type>
+typename tcl::sequential_tree<stored_type>::iterator 
+tcl::sequential_tree<stored_type>::insert( const stored_type& value)
+{
+	// create a new tree_type object to hold the node object
+	tree_type* pNew_node; 
+	basic_tree_type::allocate_tree_type(pNew_node, tree_type(value));
+	pNew_node->set_parent(this);
+
+	const typename basic_tree_type::size_type sz = basic_tree_type::children.size();
+
+	// insert the tree node into the children container
+	const typename container_type::iterator it = basic_tree_type::children.insert(basic_tree_type::children.end(), pNew_node);
+
+	if ( sz == basic_tree_type::children.size() ) { // check for successful insertion
+		basic_tree_type::deallocate_tree_type(pNew_node);  // not successful.  delete new node and return end()
+		return iterator(basic_tree_type::children.end(), this);
+	}
+
+	return iterator(it, this);
+}
+
+// insert(const tree_type&)
+template< typename stored_type>
+typename tcl::sequential_tree<stored_type>::iterator 
+tcl::sequential_tree<stored_type>::insert(const tree_type& tree_obj)
+{
+	// insert current node
+	const iterator base_it = insert(*tree_obj.get());
+
+	if ( base_it != end() ) {
+		const_iterator it = tree_obj.begin();
+		const const_iterator it_end = tree_obj.end();
+
+		// call this function recursively thru derived tree for children
+		for ( ; it != it_end; ++it )
+			base_it.node()->insert(*it.node());
+	}
+	return base_it;
+}
+
+// push_back(const stored_type&)
+template< typename stored_type>
+void tcl::sequential_tree<stored_type>::push_back(const stored_type& value)
+{
+	// create a new tree_type object to hold the node object
+	tree_type* pNew_node; 
+	basic_tree_type::allocate_tree_type(pNew_node, tree_type(value));
+	pNew_node->set_parent(this);
+
+	basic_tree_type::children.push_back(pNew_node);
+}
+
+// insert(const_iterator, const stored_type&)
+template<typename stored_type>
+typename tcl::sequential_tree<stored_type>::iterator 
+tcl::sequential_tree<stored_type>::insert(const_iterator pos, const stored_type& value)
+{
+	// create a new tree_type object to hold the node object
+	tree_type* pNew_node = 0; 
+	basic_tree_type::allocate_tree_type(pNew_node, tree_type(value));
+	pNew_node->set_parent(this);
+
+	const typename std::vector<stored_type>::size_type sz = basic_tree_type::children.size();
+
+	// calculate the insertion point
+	const const_iterator beg_it = begin();
+	typename container_type::iterator pos_it = basic_tree_type::children.begin(); 
+	for ( ; pos != beg_it; --pos, ++pos_it) ;
+	// insert the tree node into the children container
+	const typename container_type::iterator it = basic_tree_type::children.insert(pos_it, pNew_node);
+
+	if ( sz == basic_tree_type::children.size() ) { // check for successful insertion
+		basic_tree_type::deallocate_tree_type(pNew_node);  // not successful.  delete new node and return end()
+		iterator end_it(basic_tree_type::children.end(), this);
+		return end_it;
+	}
+
+	iterator node_it(it, this);
+	return node_it;
+}
+
+// insert(const_iterator, size_type, const stored_type&)
+template<typename stored_type>
+void 
+tcl::sequential_tree<stored_type>::insert(const_iterator pos, const typename basic_tree_type::size_type num, const stored_type& value)
+{
+	for (typename basic_tree_type::size_type i = 0; i < num; ++i) {
+		pos = insert(pos, value);
+		++pos;
+	}
+}
+
+// insert(const_iterator, const tree_type&)
+template<typename stored_type>
+typename tcl::sequential_tree<stored_type>::iterator 
+tcl::sequential_tree<stored_type>::insert(const const_iterator& pos, const tree_type& tree_obj)
+{
+	// insert current node
+	const iterator base_it = insert(pos, *tree_obj.get());
+
+	if ( base_it != end() ) {
+		const_iterator it = tree_obj.begin();
+		const const_iterator it_end = tree_obj.end();
+
+		// call this function recursively thru derived tree for children
+		for ( ; it != it_end; ++it )
+			base_it.node()->insert(*it.node());
+	}
+	return base_it;
+}
+
+
+// set(const tree_type&)
+template< typename stored_type >
+void tcl::sequential_tree<stored_type>::set(const sequential_tree<stored_type>& tree_obj)
+{
+	set(*tree_obj.get()); // set data for this node
+
+	const_iterator it = tree_obj.begin();
+	const const_iterator it_end = tree_obj.end();
+	for ( ; it != it_end; ++it ) { // and insert all descendants of passed tree
+		insert(*it.node());
+	}
+}
+
+// clear()
+template< typename stored_type >
+void tcl::sequential_tree<stored_type>::clear()
+{
+	iterator it = begin();
+	const iterator it_end = end();
+	for ( ; it != it_end; ++it )
+	{
+		basic_tree_type::deallocate_tree_type(it.node()); // delete all child nodes
+	}
+	basic_tree_type::children.clear();  // and remove them from set
+}
+
+// erase(iterator)
+template<typename stored_type>
+typename tcl::sequential_tree<stored_type>::iterator 
+tcl::sequential_tree<stored_type>::erase(iterator it)
+{
+	// check for node presence
+	if (it.pParent != this)
+		return end();
+
+	// clear children
+	it.node()->clear(); 
+	deallocate_tree_type(it.node());
+
+	const iterator beg_it = begin();
+	typename container_type::iterator pos_it = basic_tree_type::children.begin();
+	for ( ; it != beg_it; --it, ++pos_it) ;  // get child iterator position
+
+	return iterator(basic_tree_type::children.erase(pos_it), this);
+}
+
+// erase(iterator, iterator)
+template<typename stored_type>
+typename tcl::sequential_tree<stored_type>::iterator 
+tcl::sequential_tree<stored_type>::erase(iterator beg_it, iterator end_it) 
+{
+	int delete_count = 0;
+	for (; beg_it != end_it; --end_it)
+		++delete_count;
+
+	for (int i = 0; i < delete_count; ++i) {
+		beg_it = erase(beg_it);
+	}
+
+	return beg_it;
+}
+
+// operator [](size_type)
+template<typename stored_type>
+tcl::sequential_tree<stored_type>& tcl::sequential_tree<stored_type>::operator [](basic_size_type index) 
+{ 
+	if (index >= basic_tree_type::size())
+		throw std::out_of_range("sequential_tree index out of range");
+
+	return *(begin() + index).node();
+}
+
+// operator [](size_type) const
+template<typename stored_type>
+const tcl::sequential_tree<stored_type>& tcl::sequential_tree<stored_type>::operator [](basic_size_type index) const 
+{ 
+	if (index >= basic_tree_type::size())
+		throw std::out_of_range("sequential_tree index out of range");
+
+	return *(begin() + index).node();
+}
+
+
+// operator ==
+template<typename stored_type>
+bool tcl::operator == (const sequential_tree<stored_type>& lhs, const sequential_tree<stored_type>& rhs) 
+{
+	// check this node
+	if (!(*lhs.get() == *rhs.get()))
+		return false;
+
+	typename sequential_tree<stored_type>::const_iterator lhs_it = lhs.begin();
+	const typename sequential_tree<stored_type>::const_iterator lhs_end = lhs.end();
+	typename sequential_tree<stored_type>::const_iterator rhs_it = rhs.begin();
+	const typename sequential_tree<stored_type>::const_iterator rhs_end = rhs.end();
+
+	for ( ; lhs_it != lhs_end && rhs_it != rhs_end; ++lhs_it, ++rhs_it ) {
+		if (!(*lhs_it.node() == *rhs_it.node())) {
+			return false;
+		}
+	}
+
+	if (lhs_it != lhs.end() || rhs_it != rhs.end())
+		return false;
+
+	return true;
+}
+
+
+// operator <
+template<typename stored_type>
+bool tcl::operator < (const sequential_tree<stored_type>& lhs, const sequential_tree<stored_type>& rhs) 
+{
+	// check this node
+	if (*lhs.get() < *rhs.get())
+		return true;
+
+	typename sequential_tree<stored_type>::const_iterator lhs_it = lhs.begin();
+	const typename sequential_tree<stored_type>::const_iterator lhs_end = lhs.end();
+	typename sequential_tree<stored_type>::const_iterator rhs_it = rhs.begin();
+	const typename sequential_tree<stored_type>::const_iterator rhs_end = rhs.end();
+
+	for ( ; lhs_it != lhs_end && rhs_it != rhs_end; ++lhs_it, ++rhs_it ) {
+		if (*lhs_it.node() < *rhs_it.node()) {
+			return true;
+		}
+	}
+
+	if (lhs.size() != rhs.size()) {
+		return lhs.size() < rhs.size();
+	}
+
+	return false;
+}
+
+// sort_descendants()
+template<typename stored_type>
+void tcl::sequential_tree<stored_type>::sort_descendants() 
+{
+	post_order_iterator it = post_order_begin();
+	const post_order_iterator it_end = post_order_end();
+	for ( ; it != it_end; ++it )
+	{
+		it.node()->sort();
+	}
+}
+
+
+

+ 135 - 0
ModelIO/tcl_5.0.6/tree.h

@@ -0,0 +1,135 @@
+/*******************************************************************************
+Tree Container Library: Generic container library to store data in tree-like structures.
+Copyright (c) 2006  Mitchel Haas
+
+This software is provided 'as-is', without any express or implied warranty. 
+In no event will the author be held liable for any damages arising from 
+the use of this software.
+
+Permission is granted to anyone to use this software for any purpose, 
+including commercial applications, and to alter it and redistribute it freely, 
+subject to the following restrictions:
+
+1.	The origin of this software must not be misrepresented; 
+you must not claim that you wrote the original software. 
+If you use this software in a product, an acknowledgment in the product 
+documentation would be appreciated but is not required.
+
+2.	Altered source versions must be plainly marked as such, 
+and must not be misrepresented as being the original software.
+
+3.	The above copyright notice and this permission notice may not be removed 
+or altered from any source distribution.
+
+For complete documentation on this library, see http://www.datasoftsolutions.net
+Email questions, comments or suggestions to mhaas@datasoftsolutions.net
+*******************************************************************************/
+#pragma once
+#include "associative_tree.h"
+#include <set>
+
+namespace tcl
+{
+// forward declaration for deref comparison functor
+template<typename stored_type, typename node_compare_type > class tree;
+
+	// deref comparison functor, derive from binary function per Scott Meyer
+	template<typename stored_type, typename node_compare_type >
+	struct tree_deref_less/* : public std::binary_function<const tree<stored_type, node_compare_type>*, const tree<stored_type, node_compare_type>*, bool>*/
+	{
+		bool operator () (const tree<stored_type, node_compare_type>* lhs, const tree<stored_type, node_compare_type>* rhs) const 
+		{
+			// call < on actual object
+			return node_compare_type()(*lhs->get(), *rhs->get());
+		}
+	};
+}
+
+
+
+
+// node object type.  forwards most operations to base_tree_type, 
+// instanciates base_tree_type with type of container (set of unique_tree ptrs) to use for node and key comparisons
+template<typename stored_type, typename node_compare_type = std::less<stored_type> >
+class tcl::tree : public tcl::associative_tree<stored_type, tcl::tree<stored_type, node_compare_type>,  std::set<tcl::tree<stored_type, node_compare_type>*, tcl::tree_deref_less<stored_type, node_compare_type> > >
+{
+public:
+	// typedefs
+	typedef tree<stored_type, node_compare_type> tree_type;
+	typedef tree_deref_less<stored_type, node_compare_type> key_compare;
+	typedef tree_deref_less<stored_type, node_compare_type> value_compare;
+	typedef std::set<tree_type*, key_compare> container_type;
+	typedef basic_tree<stored_type, tree_type,  container_type> basic_tree_type;
+	typedef associative_tree<stored_type, tree_type,  container_type> associative_tree_type;
+
+	// constructors/destructor
+	explicit tree( const stored_type& value = stored_type() ) : associative_tree_type(value) {}
+	template<typename iterator_type> tree(iterator_type it_beg, iterator_type it_end, const stored_type& value = stored_type()) : associative_tree_type(value) { while (it_beg != it_end) { insert(*it_beg); ++it_beg; } }
+	tree( const tree_type& rhs ); // copy constructor
+	~tree() { associative_tree_type::clear(); }
+
+	// assignment operator
+	tree_type& operator = (const tree_type& rhs);
+
+	// public interface
+public:
+	typename associative_tree_type::iterator insert(const stored_type& value) { return associative_tree_type::insert(value, this); }
+	typename associative_tree_type::iterator insert(const typename associative_tree_type::const_iterator pos, const stored_type& value) { return associative_tree_type::insert(pos, value, this); }
+	typename associative_tree_type::iterator insert(const tree_type& tree_obj ) { return associative_tree_type::insert(tree_obj, this); }
+	typename associative_tree_type::iterator insert(const typename associative_tree_type::const_iterator pos, const tree_type& tree_obj) { return associative_tree_type::insert(pos, tree_obj, this); }
+	#if !defined(_MSC_VER) || _MSC_VER >= 1300 // insert range not available for VC6
+	template<typename iterator_type> void insert(iterator_type it_beg, iterator_type it_end) { while ( it_beg != it_end ) insert(*it_beg++); }
+	#endif
+	void swap(tree_type& rhs);
+
+	// descendant element iterator accessors
+	typedef typename associative_tree_type::post_order_iterator post_order_iterator_type;
+	typedef typename associative_tree_type::const_post_order_iterator const_post_order_iterator_type;
+	typedef typename associative_tree_type::pre_order_iterator pre_order_iterator_type;
+	typedef typename associative_tree_type::const_pre_order_iterator const_pre_order_iterator_type;
+	typedef typename associative_tree_type::level_order_iterator level_order_iterator_type;
+	typedef typename associative_tree_type::const_level_order_iterator const_level_order_iterator_type;
+
+	pre_order_iterator_type pre_order_begin() { return pre_order_iterator_type(this, true); }
+	pre_order_iterator_type pre_order_end() { return pre_order_iterator_type(this, false); }
+	const_pre_order_iterator_type pre_order_begin() const { return const_pre_order_iterator_type(this, true); }
+	const_pre_order_iterator_type pre_order_end() const { return const_pre_order_iterator_type(this, false); }
+	post_order_iterator_type post_order_begin() { return post_order_iterator_type(this, true); }
+	post_order_iterator_type post_order_end() { return post_order_iterator_type(this, false); }
+	const_post_order_iterator_type post_order_begin() const { return const_post_order_iterator_type(this, true); }
+	const_post_order_iterator_type post_order_end() const { return const_post_order_iterator_type(this, false); }
+	level_order_iterator_type level_order_begin() { return level_order_iterator_type(this, true); }
+	level_order_iterator_type level_order_end() { return level_order_iterator_type(this, false); }
+	const_level_order_iterator_type level_order_begin() const { return const_level_order_iterator_type(this, true); }
+	const_level_order_iterator_type level_order_end() const { return const_level_order_iterator_type(this, false); }
+
+	// descendant node iterator accessors
+	typedef typename associative_tree_type::pre_order_node_iterator pre_order_node_iterator_type;
+	typedef typename associative_tree_type::const_pre_order_node_iterator const_pre_order_node_iterator_type;
+	typedef typename associative_tree_type::post_order_node_iterator post_order_node_iterator_type;
+	typedef typename associative_tree_type::const_post_order_node_iterator const_post_order_node_iterator_type;
+	typedef typename associative_tree_type::level_order_node_iterator level_order_node_iterator_type;
+	typedef typename associative_tree_type::const_level_order_node_iterator const_level_order_node_iterator_type;
+
+	pre_order_node_iterator_type pre_order_node_begin() { return pre_order_node_iterator_type(this, true); }
+	pre_order_node_iterator_type pre_order_node_end() { return pre_order_node_iterator_type(this, false); }
+	const_pre_order_node_iterator_type pre_order_node_begin() const { return const_pre_order_node_iterator_type(this, true); }
+	const_pre_order_node_iterator_type pre_order_node_end() const { return const_pre_order_node_iterator_type(this, false); }
+	post_order_node_iterator_type post_order_node_begin() { return post_order_node_iterator_type(this, true); }
+	post_order_node_iterator_type post_order_node_end() { return post_order_node_iterator_type(this, false); }
+	const_post_order_node_iterator_type post_order_node_begin() const { return const_post_order_node_iterator_type(this, true); }
+	const_post_order_node_iterator_type post_order_node_end() const { return const_post_order_node_iterator_type(this, false); }
+	level_order_node_iterator_type level_order_node_begin() { return level_order_node_iterator_type(this, true); }
+	level_order_node_iterator_type level_order_node_end() { return level_order_node_iterator_type(this, false); }
+	const_level_order_node_iterator_type level_order_node_begin() const { return const_level_order_node_iterator_type(this, true); }
+	const_level_order_node_iterator_type level_order_node_end() const { return const_level_order_node_iterator_type(this, false); }
+
+	// friends
+	#if defined(_MSC_VER) && _MSC_VER < 1300
+		friend class basic_tree<stored_type, tree_type, container_type>;
+	#else
+		template<typename T, typename U, typename V> friend class basic_tree;
+	#endif
+};
+
+#include "tree.inl"

+ 76 - 0
ModelIO/tcl_5.0.6/tree.inl

@@ -0,0 +1,76 @@
+/*******************************************************************************
+Tree Container Library: Generic container library to store data in tree-like structures.
+Copyright (c) 2006  Mitchel Haas
+
+This software is provided 'as-is', without any express or implied warranty. 
+In no event will the author be held liable for any damages arising from 
+the use of this software.
+
+Permission is granted to anyone to use this software for any purpose, 
+including commercial applications, and to alter it and redistribute it freely, 
+subject to the following restrictions:
+
+1.	The origin of this software must not be misrepresented; 
+you must not claim that you wrote the original software. 
+If you use this software in a product, an acknowledgment in the product 
+documentation would be appreciated but is not required.
+
+2.	Altered source versions must be plainly marked as such, 
+and must not be misrepresented as being the original software.
+
+3.	The above copyright notice and this permission notice may not be removed 
+or altered from any source distribution.
+
+For complete documentation on this library, see http://www.datasoftsolutions.net
+Email questions, comments or suggestions to mhaas@datasoftsolutions.net
+*******************************************************************************/
+
+// copy constructor
+template<typename stored_type, typename node_compare_type>
+tcl::tree<stored_type, node_compare_type>::tree( const tree_type& rhs ) : associative_tree_type(rhs)
+{
+	typename associative_tree_type::const_iterator it = rhs.begin();
+	const typename associative_tree_type::const_iterator it_end = rhs.end();
+	for ( ; it != it_end; ++it ) // do a deep copy by inserting children (and descendants)
+	{
+		associative_tree_type::insert(*it.node(), this);
+	}
+}
+
+// assignment operator
+template<typename stored_type, typename node_compare_type>
+tcl::tree<stored_type, node_compare_type>& 
+tcl::tree<stored_type, node_compare_type>::operator = (const tree_type& rhs)
+{
+	if (!associative_tree_type::is_root()) // can assign only to root node
+		return *this;
+
+	if ( this == &rhs ) // check for self assignment
+		return *this;
+
+	associative_tree_type::clear();
+	basic_tree_type::operator =(rhs); // call base class operation
+
+	typename associative_tree_type::const_iterator it = rhs.begin();
+	const typename associative_tree_type::const_iterator it_end = rhs.end();
+	for ( ; it != it_end; ++it ) // insert children and descendants
+	{
+		associative_tree_type::insert(*it.node(), this);
+	}
+	return *this;
+}
+
+// swap
+template<typename stored_type, typename node_compare_type>
+void tcl::tree<stored_type, node_compare_type>::swap(tree_type& rhs)
+{
+	tree_type temp(*this);
+
+	associative_tree_type::clear();
+	*this = rhs;
+
+	rhs.clear();
+	rhs = temp;
+}
+
+

+ 183 - 0
ModelIO/tcl_5.0.6/unique_tree.h

@@ -0,0 +1,183 @@
+/*******************************************************************************
+Tree Container Library: Generic container library to store data in tree-like structures.
+Copyright (c) 2006  Mitchel Haas
+
+This software is provided 'as-is', without any express or implied warranty. 
+In no event will the author be held liable for any damages arising from 
+the use of this software.
+
+Permission is granted to anyone to use this software for any purpose, 
+including commercial applications, and to alter it and redistribute it freely, 
+subject to the following restrictions:
+
+1.	The origin of this software must not be misrepresented; 
+you must not claim that you wrote the original software. 
+If you use this software in a product, an acknowledgment in the product 
+documentation would be appreciated but is not required.
+
+2.	Altered source versions must be plainly marked as such, 
+and must not be misrepresented as being the original software.
+
+3.	The above copyright notice and this permission notice may not be removed 
+or altered from any source distribution.
+
+For complete documentation on this library, see http://www.datasoftsolutions.net
+Email questions, comments or suggestions to mhaas@datasoftsolutions.net
+*******************************************************************************/
+#pragma once
+#include "associative_tree.h"
+#include "ordered_iterator.h"
+#include <set>
+
+namespace tcl
+{
+	// deref less for ordered children set
+	template<typename tree_type, typename node_order_compare_type>
+	struct deref_ordered_compare
+	{
+		bool operator() (const tree_type* lhs, const tree_type* rhs) const { return node_order_compare_type() (*lhs->get(), *rhs->get()); }
+	};
+
+	// forward declaration for deref comparison functor
+	template<typename stored_type, typename node_compare_type, typename node_order_compare_type >
+	class unique_tree;
+
+	// deref comparison functor, derive from binary function per Scott Meyer
+	template<typename stored_type, typename node_compare_type, typename node_order_compare_type >
+	struct unique_tree_deref_less : public std::binary_function<const unique_tree<stored_type, node_compare_type, node_order_compare_type>*, const unique_tree<stored_type, node_compare_type, node_order_compare_type>*, bool>
+	{
+		bool operator () (const unique_tree<stored_type, node_compare_type, node_order_compare_type>* lhs, const unique_tree<stored_type, node_compare_type, node_order_compare_type>* rhs) const
+		{
+			// call < on actual object
+			return node_compare_type()(*lhs->get(), *rhs->get());
+		}
+	};
+}
+
+
+
+
+// instanciates base_tree_type with type of container (set of unique_tree ptrs) to use for node and key comparisons
+template<typename stored_type, typename node_compare_type = std::less<stored_type>, typename node_order_compare_type = node_compare_type >
+class tcl::unique_tree : public tcl::associative_tree<stored_type, tcl::unique_tree<stored_type, node_compare_type, node_order_compare_type>,  std::set<tcl::unique_tree<stored_type, node_compare_type, node_order_compare_type>*, tcl::unique_tree_deref_less<stored_type, node_compare_type, node_order_compare_type> > >
+{
+public:
+	// typedefs
+	typedef unique_tree<stored_type, node_compare_type, node_order_compare_type> tree_type;
+	typedef unique_tree_deref_less<stored_type, node_compare_type, node_order_compare_type> key_compare;
+	typedef unique_tree_deref_less<stored_type, node_compare_type, node_order_compare_type> value_compare;
+	typedef std::set<tree_type*, key_compare> container_type;
+	typedef basic_tree<stored_type, tree_type, container_type> basic_tree_type;
+	typedef associative_tree<stored_type, tree_type, container_type> associative_tree_type;
+	typedef typename associative_tree_type::iterator associative_iterator_type;
+	typedef typename associative_tree_type::const_iterator associative_const_iterator_type;
+
+	typedef const_unique_tree_ordered_iterator<stored_type, node_compare_type, node_order_compare_type> const_ordered_iterator;
+	typedef unique_tree_ordered_iterator<stored_type, node_compare_type, node_order_compare_type> ordered_iterator;
+
+	// needed for inl function definitions in VC8
+	typedef typename associative_tree_type::iterator child_iterator;
+	typedef typename associative_tree_type::const_iterator const_child_iterator;
+
+	// constructors/destructor
+	explicit unique_tree( const stored_type& value = stored_type() ) : associative_tree_type(value), pOrphans(0), allowing_orphans(false) {}
+	unique_tree( const tree_type& rhs ); // copy constructor
+	template<typename iterator_type> unique_tree(iterator_type it_beg, iterator_type it_end, const stored_type& value = stored_type()) : associative_tree_type(value), pOrphans(0), allowing_orphans(false) { while (it_beg != it_end) { insert(*it_beg); ++it_beg; } }
+	~unique_tree() { clear(); if ( pOrphans ) basic_tree_type::deallocate_tree_type(pOrphans); }
+
+	// public interface
+public:
+	tree_type& operator = (const tree_type& rhs);  // assignment operator
+	typename associative_tree_type::iterator insert(const stored_type& value);
+	typename associative_tree_type::iterator insert(const typename associative_tree_type::const_iterator pos, const stored_type& value) { return associative_tree_type::insert(pos, value, this); }
+	typename associative_tree_type::iterator insert(const tree_type& tree_obj );
+	typename associative_tree_type::iterator insert(const typename associative_tree_type::const_iterator pos, const tree_type& tree_obj) { return associative_tree_type::insert(pos, tree_obj, this); }
+	void swap(tree_type& rhs);
+
+	typename associative_tree_type::iterator insert( const stored_type& parent_obj, const stored_type& value);
+	#if !defined(_MSC_VER) || _MSC_VER >= 1300 // insert range not available for VC6
+	template<typename iterator_type> void insert(iterator_type it_beg, iterator_type it_end) { while ( it_beg != it_end ) insert(*it_beg++); }
+	#endif
+	typename associative_tree_type::iterator find_deep(const stored_type& value);
+	typename associative_tree_type::const_iterator find_deep(const stored_type& value) const;
+
+	const_ordered_iterator ordered_begin() const { return const_ordered_iterator(ordered_children.begin()); }
+	const_ordered_iterator ordered_end() const { return const_ordered_iterator(ordered_children.end()); }
+	ordered_iterator ordered_begin() { return ordered_iterator(ordered_children.begin()); }
+	ordered_iterator ordered_end() { return ordered_iterator(ordered_children.end()); }
+	ordered_iterator find_ordered(const stored_type& value);
+	const_ordered_iterator find_ordered(const stored_type& value) const;
+	bool erase(const stored_type& value);
+	void erase(associative_iterator_type it);
+	void erase(associative_iterator_type it_beg, associative_iterator_type it_end);
+	void clear();
+	bool allow_orphans() const { return get_root()->allowing_orphans; }
+	void allow_orphans(const bool allow) const { get_root()->allowing_orphans = allow; }
+	const tree_type* get_orphans() const { return get_root()->pOrphans; }
+	bool is_orphan() const { const tree_type* const root = get_root(); return (!root->empty() && root->ordered_children.empty()); }
+
+	// descendant element iterator accessors
+	typedef typename associative_tree_type::post_order_iterator post_order_iterator_type;
+	typedef typename associative_tree_type::const_post_order_iterator const_post_order_iterator_type;
+	typedef typename associative_tree_type::pre_order_iterator pre_order_iterator_type;
+	typedef typename associative_tree_type::const_pre_order_iterator const_pre_order_iterator_type;
+	typedef typename associative_tree_type::level_order_iterator level_order_iterator_type;
+	typedef typename associative_tree_type::const_level_order_iterator const_level_order_iterator_type;
+
+	pre_order_iterator_type pre_order_begin() { return pre_order_iterator_type(this, true); }
+	pre_order_iterator_type pre_order_end() { return pre_order_iterator_type(this, false); }
+	const_pre_order_iterator_type pre_order_begin() const { return const_pre_order_iterator_type(this, true); }
+	const_pre_order_iterator_type pre_order_end() const { return const_pre_order_iterator_type(this, false); }
+	post_order_iterator_type post_order_begin() { return post_order_iterator_type(this, true); }
+	post_order_iterator_type post_order_end() { return post_order_iterator_type(this, false); }
+	const_post_order_iterator_type post_order_begin() const { return const_post_order_iterator_type(this, true); }
+	const_post_order_iterator_type post_order_end() const { return const_post_order_iterator_type(this, false); }
+	level_order_iterator_type level_order_begin() { return level_order_iterator_type(this, true); }
+	level_order_iterator_type level_order_end() { return level_order_iterator_type(this, false); }
+	const_level_order_iterator_type level_order_begin() const { return const_level_order_iterator_type(this, true); }
+	const_level_order_iterator_type level_order_end() const { return const_level_order_iterator_type(this, false); }
+
+	// descendant node iterator accessors
+	typedef typename associative_tree_type::pre_order_node_iterator pre_order_node_iterator_type;
+	typedef typename associative_tree_type::const_pre_order_node_iterator const_pre_order_node_iterator_type;
+	typedef typename associative_tree_type::post_order_node_iterator post_order_node_iterator_type;
+	typedef typename associative_tree_type::const_post_order_node_iterator const_post_order_node_iterator_type;
+	typedef typename associative_tree_type::level_order_node_iterator level_order_node_iterator_type;
+	typedef typename associative_tree_type::const_level_order_node_iterator const_level_order_node_iterator_type;
+
+	pre_order_node_iterator_type pre_order_node_begin() { return pre_order_node_iterator_type(this, true); }
+	pre_order_node_iterator_type pre_order_node_end() { return pre_order_node_iterator_type(this, false); }
+	const_pre_order_node_iterator_type pre_order_node_begin() const { return const_pre_order_node_iterator_type(this, true); }
+	const_pre_order_node_iterator_type pre_order_node_end() const { return const_pre_order_node_iterator_type(this, false); }
+	post_order_node_iterator_type post_order_node_begin() { return post_order_node_iterator_type(this, true); }
+	post_order_node_iterator_type post_order_node_end() { return post_order_node_iterator_type(this, false); }
+	const_post_order_node_iterator_type post_order_node_begin() const { return const_post_order_node_iterator_type(this, true); }
+	const_post_order_node_iterator_type post_order_node_end() const { return const_post_order_node_iterator_type(this, false); }
+	level_order_node_iterator_type level_order_node_begin() { return level_order_node_iterator_type(this, true); }
+	level_order_node_iterator_type level_order_node_end() { return level_order_node_iterator_type(this, false); }
+	const_level_order_node_iterator_type level_order_node_begin() const { return const_level_order_node_iterator_type(this, true); }
+	const_level_order_node_iterator_type level_order_node_end() const { return const_level_order_node_iterator_type(this, false); }
+
+private:
+	void set(const stored_type& value) { basic_tree_type::set(value); }
+	void set(const tree_type& tree_obj);
+	void inform_grandparents( tree_type* pNew_child, tree_type* pParent );
+	bool check_for_duplicate(const stored_type& value, const tree_type* pParent) const;
+	const tree_type* get_root() const;
+
+private:
+	// data
+	mutable std::set<tree_type*, key_compare > descendents;
+	std::multiset<tree_type*, deref_ordered_compare<tree_type, node_order_compare_type> > ordered_children;
+	mutable tree_type* pOrphans;
+	mutable bool allowing_orphans;
+
+	// friends
+	#if defined(_MSC_VER) && _MSC_VER < 1300
+		friend class basic_tree<stored_type, tree_type, container_type>;
+	#else
+		template<typename T, typename U, typename V> friend class basic_tree;
+	#endif
+};
+
+#include "unique_tree.inl"

+ 445 - 0
ModelIO/tcl_5.0.6/unique_tree.inl

@@ -0,0 +1,445 @@
+/*******************************************************************************
+Tree Container Library: Generic container library to store data in tree-like structures.
+Copyright (c) 2006  Mitchel Haas
+
+This software is provided 'as-is', without any express or implied warranty. 
+In no event will the author be held liable for any damages arising from 
+the use of this software.
+
+Permission is granted to anyone to use this software for any purpose, 
+including commercial applications, and to alter it and redistribute it freely, 
+subject to the following restrictions:
+
+1.	The origin of this software must not be misrepresented; 
+you must not claim that you wrote the original software. 
+If you use this software in a product, an acknowledgment in the product 
+documentation would be appreciated but is not required.
+
+2.	Altered source versions must be plainly marked as such, 
+and must not be misrepresented as being the original software.
+
+3.	The above copyright notice and this permission notice may not be removed 
+or altered from any source distribution.
+
+For complete documentation on this library, see http://www.datasoftsolutions.net
+Email questions, comments or suggestions to mhaas@datasoftsolutions.net
+*******************************************************************************/
+#include <algorithm>
+
+// copy constructor
+template<typename stored_type, typename node_compare_type, typename node_order_compare_type>
+tcl::unique_tree<stored_type, node_compare_type, node_order_compare_type>::unique_tree( const tree_type& rhs ) 
+	: associative_tree_type(rhs), pOrphans(0), allowing_orphans(false)
+{
+	allowing_orphans = rhs.allowing_orphans;  // copy orphan flag
+
+	if (rhs.pOrphans) { // orphans present?
+		basic_tree_type::allocate_tree_type(pOrphans, tree_type());
+		associative_const_iterator_type it = rhs.pOrphans->begin();
+		const associative_const_iterator_type it_end = rhs.pOrphans->end();
+		for ( ; it != it_end; ++it ) { // copy orphans
+			pOrphans->insert(*it.node());
+		}
+	} else 
+		pOrphans = 0;
+
+	associative_const_iterator_type it = rhs.begin();
+	const associative_const_iterator_type it_end = rhs.end();
+	for ( ; it != it_end; ++it ) { // do deep copy by inserting children (and descendants)
+		insert(*it.node());
+	}
+}
+
+// assignment operator
+template<typename stored_type, typename node_compare_type, typename node_order_compare_type>
+tcl::unique_tree<stored_type, node_compare_type, node_order_compare_type>& 
+tcl::unique_tree<stored_type, node_compare_type, node_order_compare_type>::operator = (const tree_type& rhs)
+{
+	if (!associative_tree_type::is_root()) // can assign only to root node
+		return *this;
+
+	if ( this == &rhs )  // check for self assignment
+		return *this;
+
+	clear();
+	basic_tree_type::operator =(rhs); // base class operation
+
+	allowing_orphans = rhs.allowing_orphans;
+
+	if (rhs.pOrphans) { // orphans present?
+		basic_tree_type::allocate_tree_type(pOrphans, tree_type());  // yes.  copy them
+		associative_const_iterator_type it = rhs.pOrphans->begin();
+		const associative_const_iterator_type it_end = rhs.pOrphans->end();
+		for ( ; it != it_end; ++it ) {
+			pOrphans->insert(*it.node());
+		}
+	} else 
+		pOrphans = 0;
+
+	associative_const_iterator_type it = rhs.begin();
+	const associative_const_iterator_type it_end = rhs.end();
+	for ( ; it != it_end; ++it ) {  // copy all children (and descendants)
+		insert(*it.node());
+	}
+
+	return *this;
+}
+
+
+// set(const tree_type&)
+template<typename stored_type, typename node_compare_type, typename node_order_compare_type>
+void tcl::unique_tree<stored_type, node_compare_type, node_order_compare_type>::set(const tree_type& tree_obj)
+{
+	if ( !check_for_duplicate(*tree_obj.get(), this)) { // duplicate node exist in tree?
+		// no.  OK to set this node
+		basic_tree_type::set(*tree_obj.get());
+
+		associative_const_iterator_type it = tree_obj.begin(), it_end = tree_obj.end();
+		for ( ; it != it_end; ++it ) { // insert any children
+			insert(*it.node());
+		}
+
+		if ( tree_obj.pOrphans && allow_orphans() ) { // copy orphans if any present
+			get_root()->pOrphans->set(*tree_obj.pOrphans );
+		}  
+
+	}
+}
+
+
+// insert(const stored_type&)
+template<typename stored_type, typename node_compare_type, typename node_order_compare_type>
+typename tcl::unique_tree<stored_type, node_compare_type, node_order_compare_type>::child_iterator 
+tcl::unique_tree<stored_type, node_compare_type, node_order_compare_type>::insert(const stored_type& value) 
+{ 
+	const tree_type* const pRoot = get_root();
+	if ( allow_orphans() && pRoot->pOrphans ) { // orphans present?
+		// yes.  check orphans for child
+		const associative_iterator_type oit = pRoot->pOrphans->find_deep(value);
+		if ( oit != pRoot->pOrphans->end() ) { 
+			// child is an orphan.  update orphan with new data
+			oit.node()->set(stored_type(value));
+			tree_type orphan;
+			orphan.set(*oit.node());
+			pRoot->pOrphans->erase(*oit);
+			return insert(orphan);
+		} 
+	} 
+	
+	// stored obj doesn't already exist in an orphan
+	if ( !check_for_duplicate(value, this)) { // check for duplication
+		const associative_iterator_type it = associative_tree_type::insert(value, this);
+		ordered_children.insert(it.node());  // no duplicate exists.  insert new node
+		inform_grandparents(it.node(), this );
+		return it;
+	} else
+		return associative_tree_type::end(); // duplicate node exists.  don't insert
+
+}
+
+// insert(const tree_type&)
+template<typename stored_type, typename node_compare_type, typename node_order_compare_type>
+typename tcl::unique_tree<stored_type, node_compare_type, node_order_compare_type>::child_iterator 
+tcl::unique_tree<stored_type, node_compare_type, node_order_compare_type>::insert(const tree_type& tree_obj )
+{
+	if ( tree_obj.pOrphans && allow_orphans() ) { // have orphans?
+		get_root()->pOrphans->insert(*tree_obj.pOrphans ); // yes.  copy orphans
+	}  
+
+	// insert current node
+	associative_iterator_type base_it = insert(*tree_obj.get());
+
+	if ( base_it == associative_tree_type::end() ) { // insert successful?
+		// no.  but, the node may have existed here previously.  check if so
+		base_it = associative_tree_type::find(*tree_obj.get()); 
+	}
+
+	if ( base_it != associative_tree_type::end() ) {  // node exist?
+		associative_const_iterator_type it = tree_obj.begin();
+		const associative_const_iterator_type it_end = tree_obj.end();
+
+		// call this function recursively to insert children and descendants
+		for ( ; it != it_end; ++it )
+			base_it.node()->insert(*it.node());
+	}
+	return base_it;
+}
+
+// insert(const stored_type&, const stored_type&)
+template<typename stored_type, typename node_compare_type, typename node_order_compare_type>
+typename tcl::unique_tree<stored_type, node_compare_type, node_order_compare_type>::child_iterator 
+tcl::unique_tree<stored_type, node_compare_type, node_order_compare_type>::insert( const stored_type& parent_obj, const stored_type& value)
+{
+	if ( !(parent_obj < (*basic_tree_type::get())) && !((*basic_tree_type::get()) < parent_obj) ) { // is this node the parent?	
+		return insert(value);  // yes.  insert the node here.
+	}
+
+	// find parent node
+	associative_iterator_type it;
+	const associative_iterator_type it_parent = find_deep(parent_obj);
+
+	const tree_type* const pRoot = get_root();
+	if ( it_parent != associative_tree_type::end() ) {
+		// found parent node, 
+		if ( allow_orphans() && pRoot->pOrphans ) {
+			// orphans present.  check orphans for child
+			const associative_iterator_type oit = pRoot->pOrphans->find_deep(value);
+			if ( oit != pRoot->pOrphans->end() ) {
+				// child is an orphan.  update orphan with new data
+				oit.node()->set(stored_type(value));
+				tree_type orphan;
+				orphan.set(*oit.node());
+				pRoot->pOrphans->erase(*oit);
+				it = it_parent.node()->insert(orphan);
+			} else
+				it = it_parent.node()->insert(value); // child not an orphan. inset child node in parent 
+		} else {
+			it = it_parent.node()->insert(value); // no orphans.  insert child node in parent
+		}
+		if ( it == it_parent.node()->end() ) // was node inserted successfully?
+			return associative_tree_type::end(); // no.  return proper end()
+	} else if (allow_orphans() ) { 
+		// parent not found.  do we have orphans?
+		if ( !pRoot->pOrphans ) {
+			basic_tree_type::allocate_tree_type(pRoot->pOrphans, tree_type());  // no, instanciate them
+		}
+
+		associative_iterator_type oit = pRoot->pOrphans->find_deep(parent_obj);
+
+		// orphans contain parent?
+		if ( oit == pRoot->pOrphans->end() ) {
+			// no.  create parent in orphans
+			oit = pRoot->pOrphans->insert(parent_obj);
+			pRoot->pOrphans->ordered_children.clear();  // orphans need no ordered children
+		} 
+
+		const associative_iterator_type child_oit = pRoot->pOrphans->find_deep(value);
+		if ( child_oit != pRoot->pOrphans->end() ) {
+			// child is an orphan.  update orphan with new data
+			child_oit.node()->set(stored_type(value));
+			tree_type orphan;
+			orphan.set(*child_oit.node());
+			pRoot->pOrphans->erase(*child_oit);
+			it = oit.node()->insert(orphan);
+			oit.node()->ordered_children.clear();
+		} else {
+			it = oit.node()->insert(value); // child not an orphan.  insert child in parent orphan
+			oit.node()->ordered_children.clear();
+		}
+
+		if ( it == oit.node()->end() ) // was child inserted as orphan?
+			return associative_tree_type::end();  // no.  return proper end()
+	} else {
+		return associative_tree_type::end(); // couldn't find parent, and orphans not allowed
+	}
+
+	return it;
+}
+
+
+// find_deep(const stored_type&)
+template<typename stored_type, typename node_compare_type, typename node_order_compare_type>
+typename tcl::unique_tree<stored_type, node_compare_type, node_order_compare_type>::child_iterator 
+tcl::unique_tree<stored_type, node_compare_type, node_order_compare_type>::find_deep(const stored_type& value) 
+{
+	tree_type tree_node(value);  // create seach node
+	const typename std::set<tree_type*, key_compare>::iterator desc_it = descendents.find(&tree_node);
+	if (desc_it == descendents.end()) // node found in descendants?
+		return associative_tree_type::end();  // no.  node not a descendant of this node
+
+	// node is some type of descendant.  check if it's an immediate child
+	associative_iterator_type it = associative_tree_type::find(value);
+	if ( it != associative_tree_type::end() )
+		return it;
+
+	// node not an immediate child.  
+	it = associative_tree_type::begin();
+	const associative_iterator_type it_end = associative_tree_type::end();
+	for ( ; it != it_end; ++it ) {  // iterate over children and call this fcn recursively
+		const associative_iterator_type grandchild_it = it.node()->find_deep(value);
+		if ( grandchild_it != it.node()->end() ) 
+			return grandchild_it;  // found it
+	}
+
+	return associative_tree_type::end();
+}
+
+// find_deep(const stored_type&) const
+template<typename stored_type, typename node_compare_type, typename node_order_compare_type>
+typename tcl::unique_tree<stored_type, node_compare_type, node_order_compare_type>::const_child_iterator 
+tcl::unique_tree<stored_type, node_compare_type, node_order_compare_type>::find_deep(const stored_type& value) const
+{
+	associative_const_iterator_type it_end = associative_tree_type::end();
+	tree_type tree_node(value);  // create seach node
+	typename std::set<tree_type*, key_compare>::const_iterator desc_it = descendents.find(&tree_node);
+	if (desc_it == descendents.end())  // node found in descendants?
+		return it_end;  // no.  node not a descendant of this node
+
+	// node is some type of descendant.  check if it's an immediate child
+	associative_const_iterator_type it = associative_tree_type::find(value);
+	if ( it != it_end )
+		return it;
+
+	// node not an immediate child.  
+	it = associative_tree_type::begin();
+	for ( ; it != it_end; ++it ) { // iterate over children and call this fcn recursively
+		associative_const_iterator_type grandchild_it = it.node()->find_deep(value);
+		associative_const_iterator_type grandchild_it_end = it.node()->end();
+		if ( grandchild_it != grandchild_it_end )
+			return grandchild_it;  // found it
+	}
+
+	return it_end;
+}
+
+
+// clear()
+template<typename stored_type, typename node_compare_type, typename node_order_compare_type>
+void tcl::unique_tree<stored_type, node_compare_type, node_order_compare_type>::clear()
+{
+	// create descendant remove set
+	std::set<tree_type*, key_compare> remove_set;
+	remove_set.swap(descendents);  // get a copy of the descendants, and clear them
+
+	tree_type* pParent = basic_tree_type::parent();
+	while ( pParent != 0 ) {  // climb up to the root node
+		std::set<tree_type*, key_compare> dest_set;  // create a difference set
+		std::set_difference( pParent->descendents.begin(), pParent->descendents.end(),
+			remove_set.begin(), remove_set.end(), std::inserter(dest_set, dest_set.begin()), key_compare() );
+		pParent->descendents.swap(dest_set);  // and remove the deleted descendants
+		pParent = pParent->parent();
+	}
+
+	associative_tree_type::clear(); // call base class operation
+	ordered_children.clear();
+	descendents.clear();
+
+	if ( pOrphans ) { // if this is the root, clear orphans also
+		pOrphans->clear();
+	}
+}
+
+
+// inform_grandparents(tree_type*, tree_type*)
+template<typename stored_type, typename node_compare_type, typename node_order_compare_type>
+void tcl::unique_tree<stored_type, node_compare_type, node_order_compare_type>::inform_grandparents( tree_type* new_child, tree_type* pParent  )
+{
+	if ( pParent) {  // traverse to root, adding new child to descendants to every node
+		pParent->descendents.insert(new_child);
+		inform_grandparents(new_child, pParent->parent());
+	}
+}
+
+// find_ordered(const stored_type&)  
+template<typename stored_type, typename node_compare_type, typename node_order_compare_type>
+typename tcl::unique_tree<stored_type, node_compare_type, node_order_compare_type>::ordered_iterator 
+tcl::unique_tree<stored_type, node_compare_type, node_order_compare_type>::find_ordered(const stored_type& value) 
+{
+	tree_type tree_node(value);  // search node
+	return ordered_iterator(ordered_children.find(&tree_node));
+}
+
+// find_ordered(const stored_type&) const 
+template<typename stored_type, typename node_compare_type, typename node_order_compare_type>
+typename tcl::unique_tree<stored_type, node_compare_type, node_order_compare_type>::const_ordered_iterator 
+tcl::unique_tree<stored_type, node_compare_type, node_order_compare_type>::find_ordered(const stored_type& value) const
+{
+	tree_type tree_node(value);  // search node
+	return const_ordered_iterator(ordered_children.find(&tree_node));
+}
+
+// erase(const stored_type&)
+template<typename stored_type, typename node_compare_type, typename node_order_compare_type>
+bool tcl::unique_tree<stored_type, node_compare_type, node_order_compare_type>::
+erase(const stored_type& value)
+{
+	const associative_iterator_type it = find_deep(value);  // see if node is a descendant
+	if ( it != associative_tree_type::end() ) {
+		tree_type* const pParent = it.node()->parent();  // it is.  get it's parent
+		tree_type* pAncestor = pParent;
+
+		while ( pAncestor ) {  // update all ancestors of removed child
+			pAncestor->descendents.erase(it.node());
+			pAncestor = pAncestor->parent();
+		}
+
+		tree_type* const pNode = it.node();
+		pParent->ordered_children.erase(pNode);
+		dynamic_cast<associative_tree_type*>(pParent)->erase(*pNode->get()); // erase node
+
+		return true;
+	}
+
+	return false;
+}
+
+// erase(iterator)
+template<typename stored_type, typename node_compare_type, typename node_order_compare_type>
+void tcl::unique_tree<stored_type, node_compare_type, node_order_compare_type>::erase(associative_iterator_type it) 
+{
+	tree_type* pAncestor = this;
+
+	while (pAncestor) { // update all ancestors of removed child
+		pAncestor->descendents.erase(it.node());
+		pAncestor = pAncestor->parent();
+	}
+
+	tree_type* pNode = it.node();
+	ordered_children.erase(pNode);
+
+	associative_tree_type::erase(*pNode->get()); 
+}
+
+// erase(iterator, iterator)
+template<typename stored_type, typename node_compare_type, typename node_order_compare_type>
+void tcl::unique_tree<stored_type, node_compare_type, node_order_compare_type>::erase(associative_iterator_type it_beg, associative_iterator_type it_end) 
+{
+	while (it_beg != it_end) {
+		erase(it_beg++);
+	}
+}
+
+// check_for_duplicate()
+template<typename stored_type, typename node_compare_type, typename node_order_compare_type>
+bool tcl::unique_tree<stored_type, node_compare_type, node_order_compare_type>::check_for_duplicate(const stored_type& value, const tree_type* pParent) const
+{
+	while ( pParent && !pParent->is_root() ) {  // find root node
+		pParent = pParent->parent();
+	}
+
+	// check if node is root
+	if (!(value < *pParent->get()) && !(*pParent->get() < value))
+		return true;
+
+	associative_const_iterator_type it = pParent->find_deep(value);  // check if node is descendant of root
+	associative_const_iterator_type it_end = pParent->end();
+
+	return ( it != it_end );  
+}
+
+// get_root()
+template<typename stored_type, typename node_compare_type, typename node_order_compare_type>
+const tcl::unique_tree<stored_type, node_compare_type, node_order_compare_type>*
+tcl::unique_tree<stored_type, node_compare_type, node_order_compare_type>::get_root() const
+{
+	const tree_type* pParent = this;
+
+	while ( pParent->parent() ) {  // traverse up to root
+		pParent = pParent->parent();
+	}
+
+	return pParent;
+}
+
+// swap
+template<typename stored_type, typename node_compare_type, typename node_order_compare_type>
+void tcl::unique_tree<stored_type, node_compare_type, node_order_compare_type>::swap(tree_type& rhs)
+{
+	tree_type temp(*this);
+
+	clear();
+	*this = rhs;
+
+	rhs.clear();
+	rhs = temp;
+}

+ 227 - 0
js_ext_comx_cascade_core.cc

@@ -0,0 +1,227 @@
+#include <comx_napi.hxx>
+#include <type_cast.hxx>
+using namespace KMAS::type;
+
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+
+using namespace std;
+
+#include <base/function.hxx>
+#include <base/type_cast.hxx>
+using namespace KMAS::type;
+
+// Open Cascade library.
+#include <BRepBuilderAPI_MakeEdge.hxx>
+#include <BRepBuilderAPI_MakeFace.hxx>
+#include <BRepBuilderAPI_MakeWire.hxx>
+#include <BRepPrimAPI_MakeBox.hxx>
+#include <BRepPrimAPI_MakeCone.hxx>
+#include <BRepPrimAPI_MakeCylinder.hxx>
+#include <BRepPrimApI_MakeSphere.hxx>
+#include <BRepTools.hxx>
+#include <BRep_ListIteratorOfListOfCurveRepresentation.hxx>
+#include <BRep_Tool.hxx>
+#include <Brep_TEdge.hxx>
+#include <Standard.hxx>
+#include <Standard_DefineAlloc.hxx>
+#include <Standard_Handle.hxx>
+#include <Standard_TypeDef.hxx>
+#include <TopTools_HSequenceOfShape.hxx>
+#include <TopTools_ListIteratorOfListOfShape.hxx>
+#include <TopoDS.hxx>
+#include <TopoDS_Edge.hxx>
+#include <TopoDS_Face.hxx>
+#include <TopoDS_Wire.hxx>
+#include <gp_Pln.hxx>
+#include <gp_Pnt.hxx>
+// #include <BRepMesh.hxx>
+#include <BRepMesh_IncrementalMesh.hxx>
+#include <Poly_Triangulation.hxx>
+#include <TShort_Array1OfShortReal.hxx>
+#include <TopExp.hxx>
+#include <TopExp_Explorer.hxx>
+
+#include <Poly.hxx>
+#include <Poly_Connect.hxx>
+#include <Poly_Triangulation.hxx>
+
+#include <Geom2dAdaptor.hxx>
+#include <Geom2dAdaptor_curve.hxx>
+
+#include <GeomAdaptor.hxx>
+#include <GeomAdaptor_curve.hxx>
+
+#include <BRepBuilderAPI_NurbsConvert.hxx>
+#include <Geom2dConvert.hxx>
+#include <Geom2d_TrimmedCurve.hxx>
+#include <Geom_Plane.hxx>
+
+#include <BRepLib_FindSurface.hxx>
+#include <GeomConvert.hxx>
+#include <Geom_BSplineSurface.hxx>
+
+#include <BRepLib.hxx>
+#include <GeomLib.hxx>
+
+#include <IGESCAFControl_Reader.hxx>
+#include <Quantity_Color.hxx>
+#include <STEPCAFControl_Reader.hxx>
+#include <TDF_ChildIterator.hxx>
+#include <TDF_Label.hxx>
+#include <TDocStd_Document.hxx>
+#include <XCAFApp_Application.hxx>
+#include <XCAFDoc_ColorTool.hxx>
+#include <XCAFDoc_ColorType.hxx>
+#include <XCAFDoc_DocumentTool.hxx>
+#include <XCAFDoc_ShapeTool.hxx>
+
+#include <ModelIO/ModelIO.h>
+
+TopTools_HSequenceOfShape
+    g_aHSequenceOfShape; // new TopTools_HSequenceOfShape();
+TopTools_IndexedMapOfShape g_mapFace;
+TopTools_IndexedMapOfShape g_mapEdge;
+
+NCollection_IndexedDataMap<TopoDS_Shape, Quantity_Color> aShapeGroup;
+
+ModelIO g_modelIO;
+
+////////////////////////////////////////////////////////////////////////////
+// system pre-define segment, please don't modify the following codes.
+
+JS_EXT_DATA_DECLARE()
+
+///////////////////////////////////////////////////////////////////////////
+// implement GetExEntry function
+
+#define GETENTRYEX_FUNC_USAGE                                                  \
+        "GetEntryEx Usage: var exEntry =  comx.occore.GetEntryEx();"
+JS_EXT_FUNC_BEGIN(GetEntryEx, 0, GETENTRYEX_FUNC_USAGE) {
+        unsigned long long ulRet = (unsigned long long)((void *)&g_modelIO);
+
+        string ret_val = type_cast<string>(ulRet);
+        JS_EXT_FUNC_ASSIGN_RET(ret_val);
+}
+JS_EXT_FUNC_END()
+///////////////////////////////////////////////////////////////////////////
+// implement GetEntry function
+
+#define GETENTRY_FUNC_USAGE                                                    \
+        "GetEntry Usage: var entry =  comx.occore.GetEntry();"
+JS_EXT_FUNC_BEGIN(GetEntry, 0, GETENTRY_FUNC_USAGE) {
+        // para_type p0 = JS_EXT_PARA(para_type, 0);
+
+        unsigned long long ulRet =
+            (unsigned long long)((void *)&g_aHSequenceOfShape);
+
+        string ret_val = type_cast<string>(ulRet);
+        JS_EXT_FUNC_ASSIGN_RET(ret_val);
+}
+JS_EXT_FUNC_END()
+///////////////////////////////////////////////////////////////////////////
+// implement IsEmpty function
+
+#define ISEMPTY_FUNC_USAGE                                                     \
+        "IsEmpty Usage: var is_empty =  comx.occore.IsEmpty();"
+JS_EXT_FUNC_BEGIN(IsEmpty, 0, ISEMPTY_FUNC_USAGE) {
+        // para_type p0 = JS_EXT_PARA(para_type, 0);
+
+        string ret_val = type_cast<string>(g_aHSequenceOfShape.IsEmpty());
+        JS_EXT_FUNC_ASSIGN_RET(ret_val);
+}
+JS_EXT_FUNC_END()
+///////////////////////////////////////////////////////////////////////////
+// implement Clear function
+
+#define CLEAR_FUNC_USAGE "Clear Usage: comx.occore.Clear();"
+JS_EXT_FUNC_BEGIN(Clear, 0, CLEAR_FUNC_USAGE) {
+        // para_type p0 = JS_EXT_PARA(para_type, 0);
+
+        g_aHSequenceOfShape.Clear();
+
+        string ret_val = type_cast<string>("undefined");
+        JS_EXT_FUNC_ASSIGN_RET(ret_val);
+}
+JS_EXT_FUNC_END()
+///////////////////////////////////////////////////////////////////////////
+// implement GetBrepInfo function
+
+#define GetBrepInfo_FUNC_USAGE                                                 \
+        "GetBrepInfo Usage: var res =  comx.occore.GetBrepInfo(face_id);"
+JS_EXT_FUNC_BEGIN(GetBrepInfo, 1, GetBrepInfo_FUNC_USAGE) {
+        Standard_Integer id = JS_EXT_PARA(Standard_Integer, 0);
+        stringstream sstr;
+
+        if (id > g_mapFace.Extent()) {
+                const TopoDS_Shape &objEdge =
+                    g_mapEdge.FindKey(id - g_mapFace.Extent());
+                BRepTools::Write(objEdge, sstr);
+
+        } else {
+                const TopoDS_Shape &objFace = g_mapFace.FindKey(id);
+
+                /*const TopoDS_Face &F = TopoDS::Face(objFace);
+                Handle(Geom_Surface) S = BRep_Tool::Surface(F);
+
+                Handle(Geom_BSplineSurface) BSurface =
+                GeomConvert::SurfaceToBSplineSurface(S); BRep_Builder builder;
+                TopoDS_Face Face;
+                builder.MakeFace(Face, BSurface, 0.1);*/
+
+                TopoDS_Face F = TopoDS::Face(objFace);
+                BRepBuilderAPI_NurbsConvert nurbs(F);
+                Handle(Geom_Surface) geom_extrusion =
+                    BRepLib_FindSurface(nurbs).Surface();
+                Handle(Geom_BSplineSurface) geombspline_extrusion =
+                    GeomConvert::SurfaceToBSplineSurface(geom_extrusion);
+                BRep_Builder builder;
+                TopoDS_Face Face;
+                builder.MakeFace(Face, geombspline_extrusion,
+                                 Precision::Confusion());
+
+                BRepTools::Write(/*objFace*/ Face, sstr);
+
+                for (TopExp_Explorer edgeExp(objFace, TopAbs_EDGE);
+                     edgeExp.More(); edgeExp.Next()) {
+                        const TopoDS_Shape &objEdge = edgeExp.Current();
+                        /*const TopoDS_Edge E = TopoDS::Edge(objEdge);
+                        BRepBuilderAPI_NurbsConvert nurbs(E);
+                        Handle(Geom_Curve) geom_extrusion = nurbs->*/
+
+                        BRepTools::Write(objEdge, sstr);
+                }
+        }
+
+        string ret_val = type_cast<string>(sstr.str());
+        JS_EXT_FUNC_ASSIGN_RET(ret_val);
+}
+JS_EXT_FUNC_END()
+// 0x4cc0c89c-0x0090-0x47e3-0xb7-0x63-0xc1-0xaf-0xf1-0xe7-0x99-0x4e
+// please don't modify or delete the previous line codes.
+
+////////////////////////////////////////////////////////////////////////////
+// please set your js.ext namespace in the following codes.
+
+#define JS_EXT_NS "comx.occore"
+
+////////////////////////////////////////////////////////////////////////////
+// entry segment, please replace your function name in the following codes.
+
+JS_EXT_ENTRY_BEGIN()
+JS_EXT_ENTRY(GetEntryEx)
+JS_EXT_ENTRY(GetEntry)
+JS_EXT_ENTRY(IsEmpty)
+JS_EXT_ENTRY(Clear)
+JS_EXT_ENTRY(GetBrepInfo)
+JS_EXT_ENTRY_END()
+
+JS_EXT_MAIN_BEGIN(JS_EXT_NS, 5)
+JS_EXT_FUNC_REG(GetEntryEx)
+JS_EXT_FUNC_REG(GetEntry)
+JS_EXT_FUNC_REG(IsEmpty)
+JS_EXT_FUNC_REG(Clear)
+JS_EXT_FUNC_REG(GetBrepInfo)
+JS_EXT_MAIN_END()

+ 675 - 0
js_ext_comx_cascade_io.cc

@@ -0,0 +1,675 @@
+#include <comx_napi.hxx>
+#include <type_cast.hxx>
+using namespace KMAS::type;
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+
+using namespace std;
+// Open Cascade library.
+#include <BRepBuilderAPI_MakeEdge.hxx>
+#include <BRepBuilderAPI_MakeFace.hxx>
+#include <BRepBuilderAPI_MakeWire.hxx>
+#include <BRepPrimAPI_MakeBox.hxx>
+#include <BRepPrimAPI_MakeCone.hxx>
+#include <BRepPrimAPI_MakeCylinder.hxx>
+#include <BRepPrimApI_MakeSphere.hxx>
+#include <BRep_Tool.hxx>
+#include <Standard_TypeDef.hxx>
+#include <TopTools_HSequenceOfShape.hxx>
+#include <TopTools_ListIteratorOfListOfShape.hxx>
+#include <TopoDS.hxx>
+#include <TopoDS_Edge.hxx>
+#include <TopoDS_Face.hxx>
+#include <TopoDS_Wire.hxx>
+#include <gp_Pln.hxx>
+#include <gp_Pnt.hxx>
+
+#include <BRepTools.hxx>
+
+#include <IGESControl_Controller.hxx>
+#include <IGESControl_Reader.hxx>
+#include <IGESControl_Writer.hxx>
+
+#include <Interface_Static.hxx>
+#include <STEPControl_Controller.hxx>
+#include <STEPControl_Reader.hxx>
+#include <STEPControl_Writer.hxx>
+
+#include <STEPConstruct.hxx>
+#include <STEPConstruct_Styles.hxx>
+#include <StepVisual_StyledItem.hxx>
+#include <TColStd_HSequenceOfTransient.hxx>
+#include <XSControl_TransferReader.hxx>
+#include <XSControl_WorkSession.hxx>
+
+// #include <BRepMesh.hxx>
+#include <Poly_Triangulation.hxx>
+#include <TShort_Array1OfShortReal.hxx>
+#include <TopExp_Explorer.hxx>
+
+#include <IGESCAFControl_Reader.hxx>
+#include <Quantity_Color.hxx>
+#include <STEPCAFControl_Reader.hxx>
+#include <TDF_ChildIterator.hxx>
+#include <TDF_Label.hxx>
+#include <TDocStd_Document.hxx>
+#include <XCAFApp_Application.hxx>
+#include <XCAFDoc_ColorTool.hxx>
+#include <XCAFDoc_ColorType.hxx>
+#include <XCAFDoc_DocumentTool.hxx>
+#include <XCAFDoc_ShapeTool.hxx>
+
+// Model IO Begin
+#include <ModelIO/ModelIO.h>
+// Model IO End
+
+string ReadSTEPEx(const Standard_CString &aFileName, ModelIO &readStep) {
+        readStep.Read(aFileName, GeomSTP);
+        readStep.Perform();
+        string ret_val = readStep.GetJson();
+        return ret_val;
+}
+
+string ReadIGESEx(const Standard_CString &aFileName, ModelIO &readIgs) {
+        readIgs.Read(aFileName, GeomIGS);
+        readIgs.Perform();
+        string ret_val = readIgs.GetJson();
+        return ret_val;
+}
+
+string ReadBREPEx(const Standard_CString &aFileName, ModelIO &readBRep) {
+        readBRep.Read(aFileName, GeomBREP);
+        readBRep.Perform();
+        string ret_val = readBRep.GetJson();
+        return ret_val;
+}
+
+string ReadSTLEx(const Standard_CString &aFileName, ModelIO &readStl) {
+        readStl.Read(aFileName, GeomSTL);
+        readStl.Perform();
+        string ret_val = readStl.GetJson();
+        return ret_val;
+}
+string ReadGLTFEx(const Standard_CString &aFileName, ModelIO &readGltf) {
+        readGltf.Read(aFileName, GeomGLTF);
+        readGltf.Perform();
+        string ret_val = readGltf.GetJson();
+        return ret_val;
+}
+
+bool WriteSTEPEx(const Standard_CString &aFileName, ModelIO &model) {
+        return model.Write(aFileName, GeomSTP);
+}
+
+bool WriteIGESEx(const Standard_CString &aFileName, ModelIO &model) {
+        return model.Write(aFileName, GeomSTP);
+}
+bool WriteBREPEx(const Standard_CString &aFileName, ModelIO &model) {
+        return model.Write(aFileName, GeomBREP);
+}
+
+bool WriteSTLEx(const Standard_CString &aFileName, ModelIO &model) {
+        return model.Write(aFileName, GeomSTL);
+}
+bool WriteGLTFEx(const Standard_CString &aFileName, ModelIO &model) {
+        return model.Write(aFileName, GeomGLTF);
+}
+
+bool ReadIGES(const Standard_CString &aFileName,
+              TopTools_HSequenceOfShape &aHSequenceOfShape) {
+        // aHSequenceOfShape.Clear();
+
+        IGESControl_Reader Reader;
+        Standard_Integer status = Reader.ReadFile(aFileName);
+
+        if (status != IFSelect_RetDone) {
+                return false;
+        }
+
+        Reader.TransferRoots();
+
+        TopoDS_Shape aShape = Reader.OneShape();
+        aHSequenceOfShape.Append(aShape);
+
+        return true;
+}
+
+bool SaveIges(const std::string &igesFile,
+              TopTools_HSequenceOfShape &aHSequenceOfShape) {
+        IGESControl_Controller::Init();
+        IGESControl_Writer igesWriter;
+
+        for (int index = 1; index <= aHSequenceOfShape.Length(); ++index) {
+                TopoDS_Shape shape = aHSequenceOfShape.ChangeValue(index);
+                igesWriter.AddShape(shape);
+        }
+
+        igesWriter.ComputeModel();
+
+        return igesWriter.Write(igesFile.c_str());
+}
+
+bool ReadSTEP(const Standard_CString &aFileName,
+              TopTools_HSequenceOfShape &aHSequenceOfShape) {
+        // aHSequenceOfShape.Clear();
+
+        // create additional log file
+        STEPControl_Reader aReader;
+
+        IFSelect_ReturnStatus status = aReader.ReadFile(aFileName);
+        if (status != IFSelect_RetDone)
+                return false;
+
+        aReader.WS()->TransferReader()->TransientProcess()->SetTraceLevel(
+            1); // increase default trace level
+
+        Standard_Boolean failsonly = Standard_False;
+        aReader.PrintCheckLoad(failsonly, IFSelect_ItemsByEntity);
+
+        // Root transfers
+        Standard_Integer nbr = aReader.NbRootsForTransfer();
+
+        aReader.PrintCheckTransfer(failsonly, IFSelect_ItemsByEntity);
+
+        for (Standard_Integer n = 1; n <= nbr; n++) {
+                /*Standard_Boolean ok =*/aReader.TransferRoot(n);
+        }
+
+        // Collecting resulting entities
+        Standard_Integer nbs = aReader.NbShapes();
+        if (nbs == 0) {
+                return false;
+        }
+        for (Standard_Integer i = 1; i <= nbs; i++) {
+                aHSequenceOfShape.Append(aReader.Shape(i));
+        }
+
+        return true;
+}
+
+// STEPControl_AsIs
+bool SaveSTEP(const std::string &aFileName,
+              TopTools_HSequenceOfShape &aHSequenceOfShape) {
+        // CREATE THE WRITER
+
+        STEPControl_Writer aWriter;
+
+        IFSelect_ReturnStatus status;
+        for (Standard_Integer i = 1; i <= aHSequenceOfShape.Length(); i++) {
+                status = aWriter.Transfer(aHSequenceOfShape.Value(i),
+                                          STEPControl_AsIs);
+                if (status != IFSelect_RetDone)
+                        return false;
+        }
+        status = aWriter.Write(aFileName.c_str());
+        return true;
+}
+
+bool SaveBREP(const std::string &aFileName,
+              TopTools_HSequenceOfShape &aHSequenceOfShape) {
+        // CREATE THE WRITER
+
+        std::filebuf aFileBuf;
+        std::ostream aStream(&aFileBuf);
+        if (!aFileBuf.open(aFileName, ios::out)) {
+                return false;
+        }
+
+        for (Standard_Integer i = 1; i <= aHSequenceOfShape.Length(); i++) {
+                BRepTools::Write(aHSequenceOfShape.Value(i), aStream);
+        }
+        return true;
+}
+
+bool OpenBREP(const std::string &aFileName,
+              TopTools_HSequenceOfShape &aHSequenceOfShape) {
+        TopoDS_Face aShape;
+
+        std::filebuf aFileBuf;
+        std::istream aStream(&aFileBuf);
+        if (!aFileBuf.open(aFileName, ios::in)) {
+                return false;
+        }
+
+        BRep_Builder aBuilder;
+        BRepTools::Read(aShape, aStream, aBuilder);
+
+        aHSequenceOfShape.Append(aShape);
+
+        return true;
+}
+
+////////////////////////////////////////////////////////////////////////////
+// system pre-define segment, please don't modify the following codes.
+
+JS_EXT_DATA_DECLARE()
+
+///////////////////////////////////////////////////////////////////////////
+// implement ImportIgesEx function
+
+//#define GETFACEHASHCODES_FUNC_USAGE                                            \
+//        "GetFaceHashCodes Usage: var res =  comx.occio.GetFaceHashCodes(db);"
+// JS_EXT_FUNC_BEGIN(GetFaceHashCodes, 1, GETFACEHASHCODES_FUNC_USAGE) {
+//         unsigned long long ullDB = JS_EXT_PARA(unsigned long long, 0);
+//
+//         ModelIO &rDB = (*(ModelIO *)((void *)ullDB));
+//         string ret_val = rDB.GetFaceHashCodes();
+//
+//         JS_EXT_FUNC_ASSIGN_RET(ret_val);
+// }
+// JS_EXT_FUNC_END()
+std::vector<int> splitAndConvertToInt(const std::string& input,
+    char delimiter) {
+    std::vector<int> result;
+    std::stringstream ss(input);
+    std::string token;
+
+    // ʹ�� std::getline �ָ��ַ���
+    while (std::getline(ss, token, delimiter)) {
+        // ת��Ϊ���������ӵ� vector
+        try {
+            int number = std::stoi(token); // ת��Ϊ����
+            result.push_back(number);
+        }
+        catch (const std::invalid_argument& e) {
+            std::cerr << "Invalid number: " << token << std::endl;
+        }
+        catch (const std::out_of_range& e) {
+            std::cerr << "Number out of range: " << token
+                << std::endl;
+        }
+    }
+
+    return result;
+}
+#define GETCOMPONMENTSTEP_FUNC_USAGE                                                 \
+        "GetComponentStep Usage: var res =  comx.occio.GetComponentStep(id, path);"
+JS_EXT_FUNC_BEGIN(GetComponentStep, 3, GETCOMPONMENTSTEP_FUNC_USAGE) {
+    unsigned long long ullDB = JS_EXT_PARA(unsigned long long, 0);
+    int id = JS_EXT_PARA(int, 1);
+    string path = JS_EXT_PARA(string, 2);
+
+    ModelIO& rDB = (*(ModelIO*)((void*)ullDB));
+
+    //rDB.CreateComponentStpById(id, path.c_str());
+
+    // JS_EXT_FUNC_ASSIGN_RET(ret_val);
+}
+JS_EXT_FUNC_END()
+
+#define GETFACEBREP_FUNC_USAGE                                                 \
+        "GetFaceBrep Usage: var res =  comx.occio.GetFaceBrep(id, path);"
+JS_EXT_FUNC_BEGIN(GetFaceBrep, 3, GETFACEBREP_FUNC_USAGE) {
+        unsigned long long ullDB = JS_EXT_PARA(unsigned long long, 0);
+        string StringID = JS_EXT_PARA(string, 1);
+        string path = JS_EXT_PARA(string, 2);
+
+		vector<int> Id = splitAndConvertToInt(StringID, ',');
+        ModelIO &rDB = (*(ModelIO *)((void *)ullDB));
+
+        rDB.CreateBrepById(Id, path.c_str());
+
+        // JS_EXT_FUNC_ASSIGN_RET(ret_val);
+}
+JS_EXT_FUNC_END()
+
+#define GETFACEPOINT_FUNC_USAGE                                                \
+        "GetFacePoint Usage: var res =  comx.occio.GetFacePoint(id);"
+JS_EXT_FUNC_BEGIN(GetFacePoint, 2, GETFACEPOINT_FUNC_USAGE) {
+        unsigned long long ullDB = JS_EXT_PARA(unsigned long long, 0);
+        int id = JS_EXT_PARA(int, 1);
+
+        ModelIO &rDB = (*(ModelIO *)((void *)ullDB));
+        double x = 0;
+        double y = 0;
+        double z = 0;
+        rDB.CreateCenterById(id, x, y, z);
+        string ret_val =
+            "point:" + to_string(x) + " " + to_string(y) + " " + to_string(z);
+        JS_EXT_FUNC_ASSIGN_RET(ret_val);
+}
+JS_EXT_FUNC_END()
+
+///////////////////////////////////////////////////////////////////////////
+// implement ImportIgesEx function
+
+#define IMPORTIGESEX_FUNC_USAGE                                                \
+        "ImportIgesEx Usage: var res =  comx.occio.ImportIgesEx(db, "          \
+        "filename);"
+JS_EXT_FUNC_BEGIN(ImportIgesEx, 2, IMPORTIGESEX_FUNC_USAGE) {
+        unsigned long long ullDB = JS_EXT_PARA(unsigned long long, 0);
+
+        string strFilename = JS_EXT_PARA(string, 1);
+        ModelIO &rDB = (*(ModelIO *)((void *)ullDB));
+
+        string ret_val = ReadIGESEx(strFilename.c_str(), rDB);
+
+        JS_EXT_FUNC_ASSIGN_RET(ret_val);
+}
+JS_EXT_FUNC_END()
+
+///////////////////////////////////////////////////////////////////////////
+// implement ImportStepEx function
+
+#define IMPORTSTEPEX_FUNC_USAGE                                                \
+        "ImportStepEx Usage: var res =  comx.occio.ImportStepEx(db, "          \
+        "filename);"
+JS_EXT_FUNC_BEGIN(ImportStepEx, 2, IMPORTSTEPEX_FUNC_USAGE) {
+
+        unsigned long long ullDB = JS_EXT_PARA(unsigned long long, 0);
+
+        string strFilename = JS_EXT_PARA(string, 1);
+        ModelIO &rDB = (*(ModelIO *)((void *)ullDB));
+
+        string ret_val = ReadSTEPEx(strFilename.c_str(), rDB);
+        //cout << 11 << endl;
+        //rDB.modelTrees = ret_val;
+        //cout << rDB.modelTrees << endl;
+        JS_EXT_FUNC_ASSIGN_RET(ret_val);
+}
+JS_EXT_FUNC_END()
+
+//////////////////////////////////////////////////////////////////////////
+// implement ImportBRepEx function
+
+#define IMPORTBREPEX_FUNC_USAGE                                                \
+        "ImportBRepEx Usage: var res =  comx.occio.ImportBRepEx(db, "          \
+        "filename);"
+JS_EXT_FUNC_BEGIN(ImportBRepEx, 2, IMPORTBREPEX_FUNC_USAGE) {
+
+        unsigned long long ullDB = JS_EXT_PARA(unsigned long long, 0);
+
+        string strFilename = JS_EXT_PARA(string, 1);
+        ModelIO &rDB = (*(ModelIO *)((void *)ullDB));
+
+        string ret_val = ReadBREPEx(strFilename.c_str(), rDB);
+
+        JS_EXT_FUNC_ASSIGN_RET(ret_val);
+}
+JS_EXT_FUNC_END()
+
+//////////////////////////////////////////////////////////////////////////
+// implement ImportStlEx function
+
+#define IMPORTSTLEX_FUNC_USAGE                                                 \
+        "ImportStlEx Usage: var res =  comx.occio.ImportStlEx(db, "            \
+        "filename);"
+JS_EXT_FUNC_BEGIN(ImportStlEx, 2, IMPORTSTLEX_FUNC_USAGE) {
+
+        unsigned long long ullDB = JS_EXT_PARA(unsigned long long, 0);
+
+        string strFilename = JS_EXT_PARA(string, 1);
+        ModelIO &rDB = (*(ModelIO *)((void *)ullDB));
+
+        string ret_val = ReadSTLEx(strFilename.c_str(), rDB);
+
+        JS_EXT_FUNC_ASSIGN_RET(ret_val);
+}
+JS_EXT_FUNC_END()
+//////////////////////////////////////////////////////////////////////////
+// implement ImportGltfEx function
+
+#define IMPORTGLTFEX_FUNC_USAGE                                                \
+        "ImportGltfEx Usage: var res =  comx.occio.ImportGltfEx(db, "          \
+        "filename);"
+JS_EXT_FUNC_BEGIN(ImportGltfEx, 2, IMPORTGLTFEX_FUNC_USAGE) {
+
+        unsigned long long ullDB = JS_EXT_PARA(unsigned long long, 0);
+
+        string strFilename = JS_EXT_PARA(string, 1);
+        ModelIO &rDB = (*(ModelIO *)((void *)ullDB));
+
+        string ret_val = ReadGLTFEx(strFilename.c_str(), rDB);
+
+        JS_EXT_FUNC_ASSIGN_RET(ret_val);
+}
+JS_EXT_FUNC_END()
+///////////////////////////////////////////////////////////////////////////
+// implement ExportIges function
+
+#define EXPORTIGESEX_FUNC_USAGE                                                \
+        "ExportIgesEx Usage: var res =  comx.occio.ExportIgesEx(db, "          \
+        "filename);"
+JS_EXT_FUNC_BEGIN(ExportIgesEx, 2, EXPORTIGESEX_FUNC_USAGE) {
+        unsigned long long ullDB = JS_EXT_PARA(unsigned long long, 0);
+
+        string strFilename = JS_EXT_PARA(string, 1);
+        ModelIO &rDB = (*(ModelIO *)((void *)ullDB));
+
+        bool ret_val = WriteIGESEx(strFilename.c_str(), rDB);
+        JS_EXT_FUNC_ASSIGN_RET(ret_val);
+}
+JS_EXT_FUNC_END()
+///////////////////////////////////////////////////////////////////////////
+// implement ExportStep function
+
+#define EXPORTSTEPEX_FUNC_USAGE                                                \
+        "ExportStepEx Usage: var res =  comx.occio.ExportStepEx(db, "          \
+        "filename);"
+JS_EXT_FUNC_BEGIN(ExportStepEx, 2, EXPORTSTEPEX_FUNC_USAGE) {
+        unsigned long long ullDB = JS_EXT_PARA(unsigned long long, 0);
+
+        string strFilename = JS_EXT_PARA(string, 1);
+        ModelIO &rDB = (*(ModelIO *)((void *)ullDB));
+
+        bool ret_val = WriteSTEPEx(strFilename.c_str(), rDB);
+        JS_EXT_FUNC_ASSIGN_RET(ret_val);
+}
+JS_EXT_FUNC_END()
+///////////////////////////////////////////////////////////////////////////
+// implement ExportBRep function
+
+#define EXPORTBREPEX_FUNC_USAGE                                                \
+        "ExportBRepEx Usage: var res =  comx.occio.ExportBRepEx(db, "          \
+        "filename);"
+JS_EXT_FUNC_BEGIN(ExportBRepEx, 2, EXPORTBREPEX_FUNC_USAGE) {
+        unsigned long long ullDB = JS_EXT_PARA(unsigned long long, 0);
+
+        string strFilename = JS_EXT_PARA(string, 1);
+        ModelIO &rDB = (*(ModelIO *)((void *)ullDB));
+
+        cout << "ExportBRepEx" << endl;
+
+        bool ret_val = WriteBREPEx(strFilename.c_str(), rDB);
+        JS_EXT_FUNC_ASSIGN_RET(ret_val);
+}
+JS_EXT_FUNC_END()
+///////////////////////////////////////////////////////////////////////////
+// implement ExportStl function
+
+#define EXPORTSTLEX_FUNC_USAGE                                                 \
+        "ExportStlEx Usage: var res =  comx.occio.ExportStlEx(db, "            \
+        "filename);"
+JS_EXT_FUNC_BEGIN(ExportStlEx, 2, EXPORTSTLEX_FUNC_USAGE) {
+        unsigned long long ullDB = JS_EXT_PARA(unsigned long long, 0);
+
+        string strFilename = JS_EXT_PARA(string, 1);
+        ModelIO &rDB = (*(ModelIO *)((void *)ullDB));
+
+        bool ret_val = WriteSTLEx(strFilename.c_str(), rDB);
+        JS_EXT_FUNC_ASSIGN_RET(ret_val);
+}
+JS_EXT_FUNC_END()
+///////////////////////////////////////////////////////////////////////////
+// implement ExportStl function
+
+#define EXPORTGLTFEX_FUNC_USAGE                                                \
+        "ExportGltfEx Usage: var res =  comx.occio.ExportGltfEx(db, "          \
+        "filename);"
+JS_EXT_FUNC_BEGIN(ExportGltfEx, 2, EXPORTGLTFEX_FUNC_USAGE) {
+        unsigned long long ullDB = JS_EXT_PARA(unsigned long long, 0);
+
+        string strFilename = JS_EXT_PARA(string, 1);
+        ModelIO &rDB = (*(ModelIO *)((void *)ullDB));
+
+        bool ret_val = WriteGLTFEx(strFilename.c_str(), rDB);
+        JS_EXT_FUNC_ASSIGN_RET(ret_val);
+}
+JS_EXT_FUNC_END()
+///////////////////////////////////////////////////////////////////////////
+// implement ImportIges function
+
+#define IMPORTIGES_FUNC_USAGE                                                  \
+        "ImportIges Usage: var res =  comx.occio.ImportIges(db, filename);"
+JS_EXT_FUNC_BEGIN(ImportIges, 2, IMPORTIGES_FUNC_USAGE) {
+        unsigned long long ullDB = JS_EXT_PARA(unsigned long long, 0);
+        string strFilename = JS_EXT_PARA(string, 1);
+
+        TopTools_HSequenceOfShape &rDB =
+            (*(TopTools_HSequenceOfShape *)((void *)ullDB));
+
+        string ret_val = type_cast<string>(ReadIGES(strFilename.c_str(), rDB));
+        JS_EXT_FUNC_ASSIGN_RET(ret_val);
+}
+JS_EXT_FUNC_END()
+///////////////////////////////////////////////////////////////////////////
+// implement ImportStep function
+
+#define IMPORTSTEP_FUNC_USAGE                                                  \
+        "ImportStep Usage: var res =  comx.occio.ImportStep(db, filename);"
+JS_EXT_FUNC_BEGIN(ImportStep, 2, IMPORTSTEP_FUNC_USAGE) {
+        unsigned long long ullDB = JS_EXT_PARA(unsigned long long, 0);
+        string strFilename = JS_EXT_PARA(string, 1);
+
+        TopTools_HSequenceOfShape &rDB =
+            (*(TopTools_HSequenceOfShape *)((void *)ullDB));
+
+        string ret_val = type_cast<string>(ReadSTEP(strFilename.c_str(), rDB));
+        JS_EXT_FUNC_ASSIGN_RET(ret_val);
+}
+JS_EXT_FUNC_END()
+///////////////////////////////////////////////////////////////////////////
+// implement ExportIges function
+
+#define EXPORTIGES_FUNC_USAGE                                                  \
+        "ExportIges Usage: var res =  comx.occio.ExportIges(db, filename);"
+JS_EXT_FUNC_BEGIN(ExportIges, 2, EXPORTIGES_FUNC_USAGE) {
+        unsigned long long ullDB = JS_EXT_PARA(unsigned long long, 0);
+        string strFilename = JS_EXT_PARA(string, 1);
+
+        TopTools_HSequenceOfShape &rDB =
+            (*(TopTools_HSequenceOfShape *)((void *)ullDB));
+
+        string ret_val = type_cast<string>(SaveIges(strFilename, rDB));
+        JS_EXT_FUNC_ASSIGN_RET(ret_val);
+}
+JS_EXT_FUNC_END()
+///////////////////////////////////////////////////////////////////////////
+// implement ExportStep function
+
+#define EXPORTSTEP_FUNC_USAGE                                                  \
+        "ExportStep Usage: var res =  comx.occio.ExportStep(db, filename);"
+JS_EXT_FUNC_BEGIN(ExportStep, 2, EXPORTSTEP_FUNC_USAGE) {
+        unsigned long long ullDB = JS_EXT_PARA(unsigned long long, 0);
+        string strFilename = JS_EXT_PARA(string, 1);
+
+        TopTools_HSequenceOfShape &rDB =
+            (*(TopTools_HSequenceOfShape *)((void *)ullDB));
+
+        string ret_val = type_cast<string>(SaveSTEP(strFilename, rDB));
+        JS_EXT_FUNC_ASSIGN_RET(ret_val);
+}
+JS_EXT_FUNC_END()
+///////////////////////////////////////////////////////////////////////////
+// implement SaveBrep function
+
+#define SAVEBREP_FUNC_USAGE                                                    \
+        "SaveBrep Usage: var res =  comx.occio.SaveBrep(db, filename);"
+JS_EXT_FUNC_BEGIN(SaveBrep, 2, SAVEBREP_FUNC_USAGE) {
+        unsigned long long ullDB = JS_EXT_PARA(unsigned long long, 0);
+        string strFilename = JS_EXT_PARA(string, 1);
+
+        TopTools_HSequenceOfShape &rDB =
+            (*(TopTools_HSequenceOfShape *)((void *)ullDB));
+
+        string ret_val = type_cast<string>(SaveBREP(strFilename, rDB));
+        JS_EXT_FUNC_ASSIGN_RET(ret_val);
+}
+JS_EXT_FUNC_END()
+///////////////////////////////////////////////////////////////////////////
+// implement OpenBrep function
+
+#define OPENBREP_FUNC_USAGE                                                    \
+        "OpenBrep Usage: var res =  comx.occio.OpenBrep(db, filename);"
+JS_EXT_FUNC_BEGIN(OpenBrep, 2, OPENBREP_FUNC_USAGE) {
+        unsigned long long ullDB = JS_EXT_PARA(unsigned long long, 0);
+        string strFilename = JS_EXT_PARA(string, 1);
+
+        TopTools_HSequenceOfShape &rDB =
+            (*(TopTools_HSequenceOfShape *)((void *)ullDB));
+
+        string ret_val = type_cast<string>(OpenBREP(strFilename, rDB));
+        JS_EXT_FUNC_ASSIGN_RET(ret_val);
+}
+JS_EXT_FUNC_END()
+///////////////////////////////////////////////////////////////////////////
+// implement Plus function
+
+#define PLUS_FUNC_USAGE "Plus Usage: var res =  comx.occio.Plus(left, right);"
+JS_EXT_FUNC_BEGIN(Plus, 2, PLUS_FUNC_USAGE) {
+        // para_type p0 = JS_EXT_PARA(para_type, 0);
+        double left = JS_EXT_PARA(double, 0);
+        double right = JS_EXT_PARA(double, 1);
+
+        string ret_val = type_cast<string>(left + right);
+        JS_EXT_FUNC_ASSIGN_RET(ret_val);
+}
+JS_EXT_FUNC_END()
+// 0x4cc0c89c-0x0090-0x47e3-0xb7-0x63-0xc1-0xaf-0xf1-0xe7-0x99-0x4e
+// please don't modify or delete the previous line codes.
+
+////////////////////////////////////////////////////////////////////////////
+// please set your js.ext namespace in the following codes.
+
+#define JS_EXT_NS "comx.occio"
+
+////////////////////////////////////////////////////////////////////////////
+// entry segment, please replace your function name in the following codes.
+
+JS_EXT_ENTRY_BEGIN()
+JS_EXT_ENTRY(ImportIgesEx)
+JS_EXT_ENTRY(ImportStepEx)
+JS_EXT_ENTRY(ImportBRepEx)
+JS_EXT_ENTRY(ImportStlEx)
+JS_EXT_ENTRY(ImportGltfEx)
+JS_EXT_ENTRY(ExportIgesEx)
+JS_EXT_ENTRY(ExportStepEx)
+JS_EXT_ENTRY(ExportBRepEx)
+JS_EXT_ENTRY(ExportStlEx)
+JS_EXT_ENTRY(ExportGltfEx)
+JS_EXT_ENTRY(ImportIges)
+JS_EXT_ENTRY(ImportStep)
+JS_EXT_ENTRY(ExportIges)
+JS_EXT_ENTRY(ExportStep)
+JS_EXT_ENTRY(SaveBrep)
+JS_EXT_ENTRY(OpenBrep)
+JS_EXT_ENTRY(Plus)
+JS_EXT_ENTRY(GetFaceBrep)
+JS_EXT_ENTRY(GetFacePoint)
+JS_EXT_ENTRY(GetComponentStep)
+JS_EXT_ENTRY_END()
+
+JS_EXT_MAIN_BEGIN(JS_EXT_NS, 20)
+JS_EXT_FUNC_REG(ImportIgesEx)
+JS_EXT_FUNC_REG(ImportStepEx)
+JS_EXT_FUNC_REG(ImportBRepEx)
+JS_EXT_FUNC_REG(ImportStlEx)
+JS_EXT_FUNC_REG(ImportGltfEx)
+JS_EXT_FUNC_REG(ExportIgesEx)
+JS_EXT_FUNC_REG(ExportStepEx)
+JS_EXT_FUNC_REG(ExportBRepEx)
+JS_EXT_FUNC_REG(ExportStlEx)
+JS_EXT_FUNC_REG(ExportGltfEx)
+JS_EXT_FUNC_REG(ImportIges)
+JS_EXT_FUNC_REG(ImportStep)
+JS_EXT_FUNC_REG(ExportIges)
+JS_EXT_FUNC_REG(ExportStep)
+JS_EXT_FUNC_REG(SaveBrep)
+JS_EXT_FUNC_REG(OpenBrep)
+JS_EXT_FUNC_REG(Plus)
+JS_EXT_FUNC_REG(GetFaceBrep)
+JS_EXT_FUNC_REG(GetFacePoint)
+JS_EXT_FUNC_REG(GetComponentStep)
+JS_EXT_MAIN_END()

+ 965 - 0
js_ext_comx_cascade_render.cc

@@ -0,0 +1,965 @@
+#include <comx_napi.hxx>
+#include <type_cast.hxx>
+using namespace KMAS::type;
+using namespace comx::napi;
+
+#include <fstream>
+#include <iostream>
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+
+using namespace std;
+
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+
+using namespace std;
+
+#include <base/function.hxx>
+#include <base/type_cast.hxx>
+using namespace KMAS::type;
+
+// Open Cascade library.
+#include <BRepBuilderAPI_MakeEdge.hxx>
+#include <BRepBuilderAPI_MakeFace.hxx>
+#include <BRepBuilderAPI_MakeWire.hxx>
+#include <BRepPrimAPI_MakeBox.hxx>
+#include <BRepPrimAPI_MakeCone.hxx>
+#include <BRepPrimAPI_MakeCylinder.hxx>
+#include <BRepPrimApI_MakeSphere.hxx>
+#include <BRepTools.hxx>
+#include <BRep_ListIteratorOfListOfCurveRepresentation.hxx>
+#include <BRep_Tool.hxx>
+#include <Brep_TEdge.hxx>
+#include <Standard.hxx>
+#include <Standard_DefineAlloc.hxx>
+#include <Standard_Handle.hxx>
+#include <Standard_TypeDef.hxx>
+#include <TopTools_HSequenceOfShape.hxx>
+#include <TopTools_ListIteratorOfListOfShape.hxx>
+#include <TopoDS.hxx>
+#include <TopoDS_Edge.hxx>
+#include <TopoDS_Face.hxx>
+#include <TopoDS_Wire.hxx>
+#include <gp_Pln.hxx>
+#include <gp_Pnt.hxx>
+// #include <BRepMesh.hxx>
+#include <BRepMesh_IncrementalMesh.hxx>
+#include <Poly_Triangulation.hxx>
+#include <TShort_Array1OfShortReal.hxx>
+#include <TopExp.hxx>
+#include <TopExp_Explorer.hxx>
+
+#include <Poly.hxx>
+#include <Poly_Connect.hxx>
+#include <Poly_Triangulation.hxx>
+
+#include <Geom2dAdaptor.hxx>
+#include <Geom2dAdaptor_curve.hxx>
+
+#include <GeomAdaptor.hxx>
+#include <GeomAdaptor_curve.hxx>
+
+#include <BRepBuilderAPI_NurbsConvert.hxx>
+#include <Geom2dConvert.hxx>
+#include <Geom2d_TrimmedCurve.hxx>
+#include <Geom_Plane.hxx>
+
+#include <BRepLib_FindSurface.hxx>
+#include <GeomConvert.hxx>
+#include <Geom_BSplineSurface.hxx>
+
+#include <BRepLib.hxx>
+#include <GeomLib.hxx>
+
+#include <AIS_Shape.hxx>
+#include <BRepAdaptor_Curve.hxx>
+#include <BRepBuilderAPI_Sewing.hxx>
+#include <CPnts_AbscissaPoint.hxx>
+
+#include <IMeshTools_Parameters.hxx>
+#include <Poly_Polygon3D.hxx>
+#include <Quantity_Color.hxx>
+
+#include <ModelIO/CurveAdaptiveDiscrete.h>
+#include <ModelIO/ModelIO.h>
+
+// TopTools_HSequenceOfShape g_aHSequenceOfShape;//new
+// TopTools_HSequenceOfShape();
+
+////////////////////////////////////////////////////////////////////////////
+// system pre-define segment, please don't modify the following codes.
+
+JS_EXT_DATA_DECLARE()
+
+///////////////////////////////////////////////////////////////////////////
+// implement RenderToGLCache function
+
+struct point_t {
+        Standard_Real x, y, z;
+
+      public:
+        point_t(Standard_Real vx = 0., Standard_Real vy = 0.,
+                Standard_Real vz = 0.)
+            : x(vx), y(vy), z(vz) {}
+};
+
+template <typename T> void ExportArray2File(string fileName, T arr) {
+        ofstream exportFile;
+        exportFile.open(fileName.c_str(), ios::out);
+
+        for (int i = 0; i < arr.size(); i++) {
+                exportFile << arr[i] << endl;
+        }
+        exportFile.close();
+}
+
+void ComputeNormals(const TopoDS_Face &theFace,
+                    const Handle(Poly_Triangulation) & theTris,
+                    Poly_Connect &thePolyConnect,
+                    vector<KMAS::vector3d_t> &ret) {
+        if (theTris.IsNull() || theTris->HasNormals()) {
+                return;
+        }
+
+        // take in face the surface location
+        const TopoDS_Face aZeroFace =
+            TopoDS::Face(theFace.Located(TopLoc_Location()));
+        Handle(Geom_Surface) aSurf = BRep_Tool::Surface(aZeroFace);
+        const Poly_Array1OfTriangle &aTriangles = theTris->Triangles();
+        if (!theTris->HasUVNodes() || aSurf.IsNull()) {
+                // compute normals by averaging triangulation normals sharing
+                // the same vertex
+                Poly::ComputeNormals(theTris);
+                return;
+        }
+
+        const Standard_Real aTol = Precision::Confusion();
+        // Handle(TShort_HArray1OfShortReal) aNormals = new
+        // TShort_HArray1OfShortReal(1, theTris->NbNodes() * 3);
+        const TColgp_Array1OfPnt2d &aNodesUV = theTris->UVNodes();
+        Standard_Integer aTri[3];
+        const TColgp_Array1OfPnt &aNodes = theTris->Nodes();
+        gp_Dir aNorm;
+        for (Standard_Integer aNodeIter = aNodes.Lower();
+             aNodeIter <= aNodes.Upper(); ++aNodeIter) {
+                // try to retrieve normal from real surface first, when UV
+                // coordinates are available
+                if (GeomLib::NormEstim(aSurf, aNodesUV.Value(aNodeIter), aTol,
+                                       aNorm) > 1) {
+                        if (thePolyConnect.Triangulation() != theTris) {
+                                thePolyConnect.Load(theTris);
+                        }
+
+                        // compute flat normals
+                        gp_XYZ eqPlan(0.0, 0.0, 0.0);
+                        for (thePolyConnect.Initialize(aNodeIter);
+                             thePolyConnect.More(); thePolyConnect.Next()) {
+                                aTriangles(thePolyConnect.Value())
+                                    .Get(aTri[0], aTri[1], aTri[2]);
+                                const gp_XYZ v1(aNodes(aTri[1]).Coord() -
+                                                aNodes(aTri[0]).Coord());
+                                const gp_XYZ v2(aNodes(aTri[2]).Coord() -
+                                                aNodes(aTri[1]).Coord());
+                                const gp_XYZ vv = v1 ^ v2;
+                                const Standard_Real aMod = vv.Modulus();
+                                if (aMod >= aTol) {
+                                        eqPlan += vv / aMod;
+                                }
+                        }
+                        const Standard_Real aModMax = eqPlan.Modulus();
+                        aNorm = (aModMax > aTol) ? gp_Dir(eqPlan) : gp::DZ();
+                }
+
+                KMAS::vector3d_t nor;
+                nor.x = aNorm.X();
+                nor.y = aNorm.Y();
+                nor.z = aNorm.Z();
+
+                ret.push_back(nor);
+        }
+}
+
+bool IsPlanar(const TopoDS_Face &objFace) {
+        Handle(Geom_Surface) surface = BRep_Tool::Surface(objFace);
+        if (surface->DynamicType() == STANDARD_TYPE(Geom_Plane)) {
+                return true;
+        }
+
+        return false;
+}
+
+bool CreateGlBuffer4Face(const TopoDS_Face &objFace, vector<double> &triangles,
+                         vector<double> &triangles_normal) {
+        TopLoc_Location location;
+
+        opencascade::handle<Poly_Triangulation> triFace =
+            BRep_Tool::Triangulation(objFace, location);
+
+        if (triFace.IsNull()) {
+                BRepMesh_IncrementalMesh(objFace, 0.01);
+                triFace = BRep_Tool::Triangulation(objFace, location);
+
+                if (triFace.IsNull()) {
+                        return false;
+                }
+        }
+
+        vector<KMAS::vector3d_t> normals;
+        ComputeNormals(objFace, triFace, Poly_Connect(), normals);
+
+        Standard_Integer nTriangles = triFace->NbTriangles();
+
+        gp_Pnt vertex1;
+        gp_Pnt vertex2;
+        gp_Pnt vertex3;
+
+        Standard_Integer nVertexIndex1 = 0;
+        Standard_Integer nVertexIndex2 = 0;
+        Standard_Integer nVertexIndex3 = 0;
+
+        TColgp_Array1OfPnt nodes(1, triFace->NbNodes());
+        Poly_Array1OfTriangle objTriangles(1, triFace->NbTriangles());
+
+        nodes = triFace->Nodes();
+        objTriangles = triFace->Triangles();
+
+        for (Standard_Integer i = 1; i <= triFace->NbTriangles(); i++) {
+                Poly_Triangle aTriangle = objTriangles.Value(i);
+
+                aTriangle.Get(nVertexIndex1, nVertexIndex2, nVertexIndex3);
+
+                vertex1 = nodes.Value(nVertexIndex1)
+                              .Transformed(location.Transformation());
+                vertex2 = nodes.Value(nVertexIndex2)
+                              .Transformed(location.Transformation());
+                vertex3 = nodes.Value(nVertexIndex3)
+                              .Transformed(location.Transformation());
+
+                point_t pt1(vertex1.X(), vertex1.Y(), vertex1.Z());
+                point_t pt2(vertex2.X(), vertex2.Y(), vertex2.Z());
+                point_t pt3(vertex3.X(), vertex3.Y(), vertex3.Z());
+
+                triangles.push_back(pt1.x);
+                triangles.push_back(pt1.y);
+                triangles.push_back(pt1.z);
+
+                KMAS::vector3d_t nor1 = normals[nVertexIndex1 - 1];
+                triangles_normal.push_back(nor1.x);
+                triangles_normal.push_back(nor1.y);
+                triangles_normal.push_back(nor1.z);
+
+                triangles.push_back(pt2.x);
+                triangles.push_back(pt2.y);
+                triangles.push_back(pt2.z);
+
+                KMAS::vector3d_t nor2 = normals[nVertexIndex2 - 1];
+                triangles_normal.push_back(nor2.x);
+                triangles_normal.push_back(nor2.y);
+                triangles_normal.push_back(nor2.z);
+
+                triangles.push_back(pt3.x);
+                triangles.push_back(pt3.y);
+                triangles.push_back(pt3.z);
+
+                KMAS::vector3d_t nor3 = normals[nVertexIndex3 - 1];
+                triangles_normal.push_back(nor3.x);
+                triangles_normal.push_back(nor3.y);
+                triangles_normal.push_back(nor3.z);
+        }
+
+        return true;
+}
+
+bool CreateGlBuffer4FaceEx(const TopoDS_Face &objFace, vector<double> &points,
+                           vector<double> &vnormals, vector<int> &triangles) {
+
+        TopLoc_Location location;
+
+        opencascade::handle<Poly_Triangulation> triFace =
+            BRep_Tool::Triangulation(objFace, location);
+
+        if (triFace.IsNull()) {
+
+                cout << "triFace is Null" << endl;
+                BRepMesh_IncrementalMesh(objFace, 0.01);
+                triFace = BRep_Tool::Triangulation(objFace, location);
+
+                if (triFace.IsNull()) {
+                        return false;
+                }
+        }
+
+        vector<KMAS::vector3d_t> normals;
+        ComputeNormals(objFace, triFace, Poly_Connect(), normals);
+        vnormals.resize(normals.size() * 3);
+        copy(&normals[0].x, &normals[0].x + normals.size() * 3, &vnormals[0]);
+
+        Standard_Integer nTriangles = triFace->NbTriangles();
+
+        Standard_Integer nVertexIndex1 = 0;
+        Standard_Integer nVertexIndex2 = 0;
+        Standard_Integer nVertexIndex3 = 0;
+
+        TColgp_Array1OfPnt nodes(1, triFace->NbNodes());
+        Poly_Array1OfTriangle objTriangles(1, triFace->NbTriangles());
+
+        nodes = triFace->Nodes();
+
+        points.resize(nodes.Size() * 3);
+        for (int nid = 0; nid < nodes.Size(); ++nid) {
+                gp_Pnt vertex =
+                    nodes.Value(nid + 1).Transformed(location.Transformation());
+                points[nid * 3 + 0] = vertex.X();
+                points[nid * 3 + 1] = vertex.Y();
+                points[nid * 3 + 2] = vertex.Z();
+        }
+
+        objTriangles = triFace->Triangles();
+
+        triangles.clear();
+        for (Standard_Integer i = 1; i <= triFace->NbTriangles(); i++) {
+                Poly_Triangle aTriangle = objTriangles.Value(i);
+
+                aTriangle.Get(nVertexIndex1, nVertexIndex2, nVertexIndex3);
+
+                triangles.push_back(nVertexIndex1 - 1);
+                triangles.push_back(nVertexIndex2 - 1);
+                triangles.push_back(nVertexIndex3 - 1);
+        }
+
+        return true;
+}
+
+bool CreateGlBuffer4FaceEdge(const TopoDS_Face &objFace, vector<double> &points,
+                             vector<double> &vnormals, vector<int> &lines) {
+        TopLoc_Location location;
+
+        opencascade::handle<Poly_Triangulation> triFace =
+            BRep_Tool::Triangulation(objFace, location);
+
+        if (triFace.IsNull()) {
+                BRepMesh_IncrementalMesh(objFace, 0.01);
+                triFace = BRep_Tool::Triangulation(objFace, location);
+
+                if (triFace.IsNull()) {
+                        return false;
+                }
+        }
+
+        vector<KMAS::vector3d_t> normals;
+        ComputeNormals(objFace, triFace, Poly_Connect(), normals);
+        vnormals.resize(normals.size() * 3);
+        copy(&normals[0].x, &normals[0].x + normals.size() * 3, &vnormals[0]);
+
+        Standard_Integer nTriangles = triFace->NbTriangles();
+
+        Standard_Integer nVertexIndex1 = 0;
+        Standard_Integer nVertexIndex2 = 0;
+        Standard_Integer nVertexIndex3 = 0;
+
+        TColgp_Array1OfPnt nodes(1, triFace->NbNodes());
+        Poly_Array1OfTriangle objTriangles(1, triFace->NbTriangles());
+
+        nodes = triFace->Nodes();
+
+        points.resize(nodes.Size() * 3);
+        for (int nid = 0; nid < nodes.Size(); ++nid) {
+                gp_Pnt vertex =
+                    nodes.Value(nid + 1).Transformed(location.Transformation());
+                points[nid * 3 + 0] = vertex.X();
+                points[nid * 3 + 1] = vertex.Y();
+                points[nid * 3 + 2] = vertex.Z();
+        }
+
+        objTriangles = triFace->Triangles();
+
+        lines.clear();
+
+        for (Standard_Integer i = 1; i <= triFace->NbTriangles(); i++) {
+                Poly_Triangle aTriangle = objTriangles.Value(i);
+
+                aTriangle.Get(nVertexIndex1, nVertexIndex2, nVertexIndex3);
+
+                // triangles.push_back(nVertexIndex1 - 1);
+                // triangles.push_back(nVertexIndex2 - 1);
+                // triangles.push_back(nVertexIndex3 - 1);
+
+                lines.push_back(nVertexIndex1 - 1);
+                lines.push_back(nVertexIndex2 - 1);
+
+                lines.push_back(nVertexIndex2 - 1);
+                lines.push_back(nVertexIndex3 - 1);
+
+                lines.push_back(nVertexIndex3 - 1);
+                lines.push_back(nVertexIndex1 - 1);
+        }
+
+        return true;
+}
+
+void CreateGlBuffer4Edge(const TopoDS_Edge &objEdge, vector<double> &lines) {
+        Standard_Real firstParam, lastParam;
+        TopLoc_Location location;
+        Handle(Geom_Curve) curve3D =
+            BRep_Tool::Curve(objEdge, location, firstParam, lastParam);
+
+        TopAbs_ShapeEnum t = objEdge.ShapeType();
+
+        lines.clear();
+        if (curve3D.IsNull()) {
+                return;
+        }
+
+        GeomAdaptor_Curve adaptedCurve(curve3D);
+
+        int LINE_SEG_NUM = 100;
+        Standard_Real rParaStep = (lastParam - firstParam) / LINE_SEG_NUM;
+
+        for (Standard_Integer i = 0; i < LINE_SEG_NUM; ++i) {
+                gp_Pnt firstPoint, lastPoint;
+                Standard_Real p1 = firstParam + i * rParaStep;
+                Standard_Real p2 = firstParam + (i + 1) * rParaStep;
+
+                adaptedCurve.D0(p1, firstPoint);
+                adaptedCurve.D0(p2, lastPoint);
+
+                firstPoint = firstPoint.Transformed(location.Transformation());
+                lastPoint = lastPoint.Transformed(location.Transformation());
+
+                lines.push_back(firstPoint.X());
+                lines.push_back(firstPoint.Y());
+                lines.push_back(firstPoint.Z());
+
+                lines.push_back(lastPoint.X());
+                lines.push_back(lastPoint.Y());
+                lines.push_back(lastPoint.Z());
+        }
+}
+
+void GetGlBuffer4Edge(const TopoDS_Edge &E, vector<double> &points,
+                      vector<int> &lines) {
+        TopLoc_Location L;
+        opencascade::handle<Poly_Polygon3D> edge = BRep_Tool::Polygon3D(E, L);
+
+        if (edge.IsNull()) {
+                return;
+        }
+}
+
+void CreateGlBuffer4EdgeEx(const TopoDS_Edge &objEdge, vector<double> &points,
+                           vector<int> &lines) {
+        Standard_Real firstParam, lastParam;
+        TopLoc_Location location;
+        Handle(Geom_Curve) curve3D =
+            BRep_Tool::Curve(objEdge, location, firstParam, lastParam);
+
+        TopAbs_ShapeEnum t = objEdge.ShapeType();
+
+        points.clear();
+        lines.clear();
+        if (curve3D.IsNull()) {
+                return;
+        }
+
+        GeomAdaptor_Curve adaptedCurve(curve3D);
+
+        int LINE_SEG_NUM = 100;
+        Standard_Real rParaStep = (lastParam - firstParam) / LINE_SEG_NUM;
+
+        for (Standard_Integer i = 0; i <= LINE_SEG_NUM; ++i) {
+                gp_Pnt pt;
+                Standard_Real para = firstParam + i * rParaStep;
+
+                adaptedCurve.D0(para, pt);
+
+                pt = pt.Transformed(location.Transformation());
+
+                points.push_back(pt.X());
+                points.push_back(pt.Y());
+                points.push_back(pt.Z());
+
+                if (i < LINE_SEG_NUM) {
+                        lines.push_back(i);
+                        lines.push_back(i + 1);
+                }
+        }
+}
+
+TopTools_IndexedMapOfShape g_mapFace;
+TopTools_IndexedMapOfShape g_mapEdge;
+
+///////////////////////////////////////////////////////////////////////////
+// implement RenderToBuffer function
+
+#define RenderToBufferEx_FUNC_USAGE                                            \
+        "RenderToBufferEx Usage: var res =  "                                  \
+        "comx.occrender.RenderToBufferEx(db);"
+JS_EXT_FUNC_BEGIN(RenderToBufferEx, 3, RenderToBufferEx_FUNC_USAGE) {
+        unsigned long long ullDB = JS_EXT_PARA(unsigned long long, 0);
+        ModelIO &rDB = (*(ModelIO *)((void *)ullDB));
+        g_mapEdge.Clear();
+        g_mapFace.Clear();
+
+        bool faceFlag = JS_EXT_PARA(bool, 1);
+        bool edgeFlag = JS_EXT_PARA(bool, 2);
+
+        uint32_t arr_idx = 0;
+
+        Napi::Array ret = Napi::Array::New(info.Env());
+        Napi::Object retObj = ret.As<Napi::Object>();
+
+        NCollection_IndexedDataMap<int, FaceProperty> faceMap;
+        rDB.GetFaceMap(faceMap);
+
+        for (NCollection_IndexedDataMap<int, FaceProperty>::Iterator
+                 aKeyFaceIter(faceMap);
+             aKeyFaceIter.More(); aKeyFaceIter.Next()) {
+                int faceId = aKeyFaceIter.Key();
+                FaceProperty faceProp = aKeyFaceIter.Value();
+
+                if (faceFlag) {
+                        Napi::Value tri_buf = GL::createBufferEx(
+                            info.Env(), 2025, faceId, faceProp.points,
+                            faceProp.normals, faceProp.elements, {}, {}, {}, {},
+                            {}, faceProp.red, faceProp.green, faceProp.blue);
+
+                        retObj.Set(arr_idx++, tri_buf);
+                }
+
+                if (edgeFlag) {
+
+                        for (auto it = faceProp.edgeProperties.begin();
+                             it != faceProp.edgeProperties.end(); it++) {
+
+                                vector<int> freeLines;
+                                vector<int> innerLines;
+                                vector<int> shareLines;
+
+                                int edge_id = (*it).id;
+
+                                if ((*it).edgeType == FreeEdge) {
+                                        for (int i = 0;
+                                             i < (*it).edges.size() - 1; i++) {
+                                                freeLines.push_back(
+                                                    (*it).edges[i]);
+                                                freeLines.push_back(
+                                                    (*it).edges[i + 1]);
+                                        }
+                                        Napi::Value freeLine_buf =
+                                            GL::createBufferEx(
+                                                info.Env(), 2026, edge_id,
+                                                faceProp.points, {}, {}, {},
+                                                freeLines, {}, {}, {}, 255, 0,
+                                                0);
+
+                                        retObj.Set(arr_idx++, freeLine_buf);
+
+                                } else if ((*it).edgeType == InnerEdge) {
+                                        for (int i = 0;
+                                             i < (*it).edges.size() - 1; i++) {
+                                                innerLines.push_back(
+                                                    (*it).edges[i]);
+                                                innerLines.push_back(
+                                                    (*it).edges[i + 1]);
+                                        }
+
+                                        Napi::Value innerLine_buf =
+                                            GL::createBufferEx(
+                                                info.Env(), 2027, edge_id,
+                                                faceProp.points, {}, {}, {},
+                                                innerLines, {}, {}, {}, 255,
+                                                255, 0);
+
+                                        retObj.Set(arr_idx++, innerLine_buf);
+                                } else {
+                                        for (int i = 0;
+                                             i < (*it).edges.size() - 1; i++) {
+                                                shareLines.push_back(
+                                                    (*it).edges[i]);
+                                                shareLines.push_back(
+                                                    (*it).edges[i + 1]);
+                                        }
+
+                                        Napi::Value shareLine_buf =
+                                            GL::createBufferEx(
+                                                info.Env(), 2028, edge_id,
+                                                faceProp.points, {}, {}, {},
+                                                shareLines, {}, {}, {}, 0, 255,
+                                                255);
+
+                                        retObj.Set(arr_idx++, shareLine_buf);
+                                }
+                        }
+                }
+        }
+
+        return ret;
+}
+JS_EXT_FUNC_END()
+
+///////////////////////////////////////////////////////////////////////////
+// implement RenderToBuffer function
+
+#define RenderToBuffer_FUNC_USAGE                                              \
+        "RenderToBuffer Usage: var res =  comx.occrender.RenderToBuffer(db);"
+JS_EXT_FUNC_BEGIN(RenderToBuffer, 1, RenderToBuffer_FUNC_USAGE) {
+
+        cout << "Get into RenderToBuffer" << endl;
+        unsigned long long ullDB = JS_EXT_PARA(unsigned long long, 0);
+        TopTools_HSequenceOfShape &rDB =
+            (*(TopTools_HSequenceOfShape *)((void *)ullDB));
+
+        // cout << "info.Env(): " << info.Env() << endl;
+
+        Napi::Array ret = Napi::Array::New(info.Env());
+        Napi::Object retObj = ret.As<Napi::Object>();
+
+        g_mapEdge.Clear();
+        g_mapFace.Clear();
+
+        uint32_t arr_idx = 0;
+
+        int totalPointCounts = 0;
+        int totalLineCounts = 0;
+
+        Standard_Integer iNumOfShape = rDB.Length();
+
+        for (int idx = 1; idx <= iNumOfShape; ++idx) {
+                // TopoDS_Shape &objShape = rDB.ChangeValue(idx);
+                // BRepTools::Clean(objShape);
+
+                TopoDS_Shape &_objShape = rDB.ChangeValue(idx);
+                BRepTools::Clean(_objShape);
+
+                BRepBuilderAPI_Sewing aSewingTool;
+                aSewingTool.Init();
+
+                aSewingTool.Load(_objShape);
+                aSewingTool.Perform();
+                TopoDS_Shape objShape = aSewingTool.SewedShape();
+                if (objShape.IsNull())
+                        objShape = _objShape;
+                BRepTools::Clean(objShape);
+
+                BRepMesh_IncrementalMesh(objShape, 0.01, true, 0.2, false);
+
+                TopExp::MapShapes(objShape, TopAbs_EDGE, g_mapEdge);
+                TopExp::MapShapes(objShape, TopAbs_FACE, g_mapFace);
+
+                TColStd_Array1OfInteger arrFaceCountOfEdge(1,
+                                                           g_mapEdge.Extent());
+                arrFaceCountOfEdge.Init(0);
+
+                // Create Face
+
+                for (TopExp_Explorer faceExp(objShape, TopAbs_FACE);
+                     faceExp.More(); faceExp.Next()) {
+                        const TopoDS_Face &objFace =
+                            TopoDS::Face(faceExp.Current());
+
+                        Standard_Integer face_id = g_mapFace.FindIndex(objFace);
+                        string strFaceID = type_cast<string>(face_id);
+                        string face_comments =
+                            "render-cascade.face" + strFaceID;
+
+                        int color[] = {255, 255, 0};
+
+                        vector<double> points;
+                        vector<double> normals;
+                        vector<int> triangles;
+
+                        if (!CreateGlBuffer4FaceEx(objFace, points, normals,
+                                                   triangles)) {
+                                continue;
+                        }
+
+                        Napi::Value tri_buf = GL::createBuffer(
+                            info.Env(), 2025, face_id, points, normals,
+                            triangles, {}, {}, {}, {}, {});
+
+                        retObj.Set(arr_idx++, tri_buf);
+
+                        for (TopExp_Explorer edgeExp(faceExp.Current(),
+                                                     TopAbs_EDGE);
+                             edgeExp.More(); edgeExp.Next()) {
+                                arrFaceCountOfEdge(
+                                    g_mapEdge.FindIndex(edgeExp.Current()))++;
+                        }
+                }
+
+                // Create Trangles Edge
+                int flag = 1;
+                for (TopExp_Explorer faceExp(objShape, TopAbs_FACE);
+                     faceExp.More(); faceExp.Next()) {
+                        const TopoDS_Face &objFace =
+                            TopoDS::Face(faceExp.Current());
+
+                        Standard_Integer edge_id =
+                            flag + g_mapFace.FindIndex(objFace);
+                        flag++;
+                        string strEdgeID = type_cast<string>(edge_id);
+                        string face_comments =
+                            "render-cascade.edge" + strEdgeID;
+
+                        int color[] = {255, 255, 0};
+
+                        vector<double> points;
+                        vector<double> normals;
+                        vector<int> lines;
+
+                        if (!CreateGlBuffer4FaceEdge(objFace, points, normals,
+                                                     lines)) {
+                                continue;
+                        }
+
+                        Napi::Value line_buf =
+                            GL::createBuffer(info.Env(), 2026, edge_id, points,
+                                             {}, {}, {}, lines, {}, {}, {});
+
+                        // retObj.Set(arr_idx++, line_buf);
+                }
+
+                for (TopExp_Explorer edgeExp(objShape, TopAbs_EDGE);
+                     edgeExp.More(); edgeExp.Next()) {
+                        const TopoDS_Edge &objEdge =
+                            TopoDS::Edge(edgeExp.Current());
+
+                        vector<double> points;
+                        vector<int> lines;
+
+                        GetGlBuffer4Edge(objEdge, points, lines);
+                }
+
+                // Create Shape Edge
+
+                for (Standard_Integer idx_edge = 1;
+                     idx_edge <= g_mapEdge.Extent(); ++idx_edge) {
+                        vector<double> points;
+                        vector<int> lines;
+
+                        BRepAdaptor_Curve adaptorCurve(
+                            TopoDS::Edge(g_mapEdge(idx_edge)));
+
+                        CurveAdaptiveDiscrete(adaptorCurve, points, lines,
+                                              QuasiUniformDeflection);
+                        Standard_Integer edge_id =
+                            idx_edge + g_mapFace.Extent();
+
+                        string strEdgeID = type_cast<string>(edge_id);
+                        string edge_comments =
+                            "render-cascade.face" + strEdgeID;
+
+                        totalPointCounts += points.size() / 3;
+                        totalLineCounts += lines.size() / 3;
+
+                        if (lines.empty()) {
+                                continue;
+                        }
+
+                        switch (arrFaceCountOfEdge(idx_edge)) {
+                        case 0:
+                                // Free Edge
+                                {
+                                        int color[] = {255, 0, 0};
+                                        // JS_EXT_GL_CACHE_ENTRY_EX(&points[0],
+                                        // NULL, points.size() / 3,
+                                        //     NULL, NULL&triangles_prop[0], 0,
+                                        //     &lines[0], NULL, lines.size() /
+                                        //     2, NULL, NULL, 0,
+                                        //     edge_comments.c_str(), 1, color,
+                                        //     2026, edge_id, true);
+
+                                        Napi::Value line_buf = GL::createBuffer(
+                                            info.Env(), 2026, edge_id, points,
+                                            {}, {}, {}, lines, {}, {}, {});
+
+                                        retObj.Set(arr_idx++, line_buf);
+                                }
+                                break;
+                        case 1: {
+                                int color[] = {255, 255, 255};
+                                // JS_EXT_GL_CACHE_ENTRY_EX(&points[0], NULL,
+                                // points.size() / 3,
+                                //     NULL, NULL&triangles_prop[0], 0,
+                                //    &lines[0], NULL, lines.size() / 2,
+                                //     NULL, NULL, 0,
+                                //     edge_comments.c_str(), 1, color, 2027,
+                                //     edge_id, true);
+
+                                Napi::Value line_buf = GL::createBuffer(
+                                    info.Env(), 2027, edge_id, points, {}, {},
+                                    {}, lines, {}, {}, {});
+
+                                retObj.Set(arr_idx++, line_buf);
+                        }
+                        // Border Edge
+                        break;
+                        default: // Shared Edge
+                        {
+                                int color[] = {5, 5, 5};
+                                // JS_EXT_GL_CACHE_ENTRY_EX(&points[0], NULL,
+                                // points.size() / 3,
+                                //     NULL, NULL&triangles_prop[0], 0,
+                                //     &lines[0], NULL, lines.size() / 2,
+                                //     NULL, NULL, 0,
+                                //     edge_comments.c_str(), 1, color, 2028,
+                                //     edge_id, true);
+
+                                Napi::Value line_buf = GL::createBuffer(
+                                    info.Env(), 2028, edge_id, points, {}, {},
+                                    {}, lines, {}, {}, {});
+
+                                retObj.Set(arr_idx++, line_buf);
+                        } break;
+                        }
+                }
+        }
+
+        return ret;
+}
+JS_EXT_FUNC_END()
+
+///////////////////////////////////////////////////////////////////////////
+// implement RenderToBufferGLTF function
+
+#include <gltf/threeAnimation.hxx>
+#include <gltf/threeMath.hxx>
+
+using namespace three;
+
+vector<GLTFMesh> gltfMeshes;
+
+ofstream logFile;
+
+vector<string> split(const string &str, string delim) {
+        vector<string> res;
+        if ("" == str)
+                return res;
+
+        char *strs = new char[str.length() + 1];
+        strcpy_s(strs, strlen(str.c_str()) + 1, str.c_str());
+
+        char *d = new char[delim.length() + 1];
+        strcpy_s(d, strlen(delim.c_str()) + 1, delim.c_str());
+        char *buf;
+        char *p = strtok_s(strs, d, &buf);
+        while (p) {
+                string s = p;
+                res.push_back(s);
+
+                p = strtok_s(NULL, d, &buf);
+        }
+        return res;
+}
+
+bool readPropertyFile(string propFile) {
+        ifstream inPropFile;
+        inPropFile.open(propFile.c_str(), ios::in);
+
+        if (!inPropFile.is_open()) {
+                cout << "Open File: " << propFile << " Failed" << endl;
+                return false;
+        }
+
+        while (!inPropFile.eof()) {
+                string temp;
+                inPropFile >> temp;
+
+                vector<string> props;
+                props = split(temp, ",");
+
+                if (props.size() != 10) {
+                        continue;
+                }
+
+                GLTFMesh _gltfMesh;
+                _gltfMesh.id = props[0];
+                _gltfMesh.name = props[1];
+                _gltfMesh.uid = props[2];
+                //_gltfMesh.duration = props[3];
+                _gltfMesh.frameCounts = atoi(props[4].c_str());
+                _gltfMesh.animationCounts = atoi(props[5].c_str());
+                _gltfMesh.morphTargetInfluencesCounts = atoi(props[6].c_str());
+
+                if (strcmp(props[7].c_str(), "true") == 0) {
+                        _gltfMesh.morphTargetsRelative = true;
+                } else {
+                        _gltfMesh.morphTargetsRelative = false;
+                }
+
+                _gltfMesh.bindMode = props[8];
+                _gltfMesh.bonesCounts = atoi(props[9].c_str());
+
+                gltfMeshes.push_back(_gltfMesh);
+        }
+
+        return true;
+}
+
+#define RenderToBufferGLTF_FUNC_USAGE                                          \
+        "RenderToBufferGLTF Usage: var res =  "                                \
+        "comx.occrender.RenderToBufferGLTF(db);"
+JS_EXT_FUNC_BEGIN(RenderToBufferGLTF, 1, RenderToBufferGLTF_FUNC_USAGE) {
+        logFile.open("F:\\gltfLog.txt", ios::out);
+        logFile << "Get into RenderToBuffer gltf" << endl;
+        string cacheFileBaseName = JS_EXT_PARA(string, 0);
+        Napi::Array ret = Napi::Array::New(info.Env());
+        Napi::Object retObj = ret.As<Napi::Object>();
+        uint32_t arr_idx = 0;
+        Standard_Integer face_id = 1;
+
+        gltfMeshes.clear();
+
+        if (!readPropertyFile(cacheFileBaseName + ".prop")) {
+                return ret;
+        }
+
+        for (unsigned int i = 0; i < gltfMeshes.size(); i++) {
+                gltfMeshes[i].ReadCache(cacheFileBaseName);
+                gltfMeshes[i].parseAnimation();
+        }
+
+        for (int idx = 0; idx < gltfMeshes.size(); ++idx) {
+                // if (idx != 0) continue;
+                Napi::Value tri_buf = GL::createBuffer(
+                    info.Env(), 2025, face_id++,
+                    gltfMeshes[idx].animations[0].frames[20].position,
+                    gltfMeshes[idx].animations[0].frames[20].normals,
+                    gltfMeshes[idx].index, {}, {}, {}, {}, {});
+
+                retObj.Set(arr_idx++, tri_buf);
+        }
+
+        logFile.close();
+
+        return ret;
+}
+JS_EXT_FUNC_END()
+
+// 0x4cc0c89c-0x0090-0x47e3-0xb7-0x63-0xc1-0xaf-0xf1-0xe7-0x99-0x4e
+// please don't modify or delete the previous line codes.
+
+////////////////////////////////////////////////////////////////////////////
+// please set your js.ext namespace in the following codes.
+
+#define JS_EXT_NS "comx.occrender"
+
+////////////////////////////////////////////////////////////////////////////
+// entry segment, please replace your function name in the following codes.
+
+JS_EXT_ENTRY_BEGIN()
+JS_EXT_ENTRY(RenderToBufferGLTF)
+JS_EXT_ENTRY(RenderToBufferEx)
+JS_EXT_ENTRY(RenderToBuffer)
+JS_EXT_ENTRY_END()
+
+JS_EXT_MAIN_BEGIN(JS_EXT_NS, 3)
+JS_EXT_FUNC_REG(RenderToBufferGLTF)
+JS_EXT_FUNC_REG(RenderToBufferEx)
+JS_EXT_FUNC_REG(RenderToBuffer)
+JS_EXT_MAIN_END()