bool CommandCrossSection::process(ccCommandLineInterface &cmd)
{
	cmd.print("[CROSS SECTION]");

	static QString s_xmlCloudCompare = "CloudCompare";
	static QString s_xmlBoxThickness = "BoxThickness";
	static QString s_xmlBoxCenter = "BoxCenter";
	static QString s_xmlRepeatDim = "RepeatDim";
	static QString s_xmlRepeatGap = "RepeatGap";
	static QString s_xmlFilePath = "FilePath";
	static QString s_outputXmlFilePath = "OutputFilePath";

	//expected argument: XML file
	if (cmd.arguments().empty())
		return cmd.error(QString("Missing parameter: XML parameters file after \"-%1\"").arg(COMMAND_CROSS_SECTION));
	QString xmlFilename = cmd.arguments().takeFirst();

	//read the XML file
	CCVector3 boxCenter(0, 0, 0), boxThickness(0, 0, 0);
	bool repeatDim[3] = { false, false, false };
	double repeatGap = 0.0;
	bool inside = true;
	bool autoCenter = true;
	QString inputFilePath;
	QString outputFilePath;
	{
		QFile file(xmlFilename);
		if (!file.open(QFile::ReadOnly | QFile::Text))
		{
			return cmd.error(QString("Couldn't open XML file '%1'").arg(xmlFilename));
		}

		//read file content
		QXmlStreamReader stream(&file);

		//expected: CloudCompare
		if (!stream.readNextStartElement()
		        || stream.name() != s_xmlCloudCompare)
		{
			return cmd.error(QString("Invalid XML file (should start by '<%1>')").arg(s_xmlCloudCompare));
		}

		unsigned mandatoryCount = 0;
		while (stream.readNextStartElement()) //loop over the elements
		{
			if (stream.name() == s_xmlBoxThickness)
			{
				QXmlStreamAttributes attributes = stream.attributes();
				if (!readVector(attributes, boxThickness, s_xmlBoxThickness, cmd))
					return false;
				stream.skipCurrentElement();
				++mandatoryCount;
			}
			else if (stream.name() == s_xmlBoxCenter)
			{
				QXmlStreamAttributes attributes = stream.attributes();
				if (!readVector(attributes, boxCenter, s_xmlBoxCenter, cmd))
					return false;
				stream.skipCurrentElement();
				autoCenter = false;
			}
			else if (stream.name() == s_xmlRepeatDim)
			{
				QString itemValue = stream.readElementText();
				bool ok = false;
				int dim = itemValue.toInt(&ok);
				if (!ok || dim < 0 || dim > 2)
				{
					return cmd.error(QString("Invalid XML file (invalid value for '<%1>')").arg(s_xmlRepeatDim));
				}
				repeatDim[dim] = true;
			}
			else if (stream.name() == s_xmlRepeatGap)
			{
				QString itemValue = stream.readElementText();
				bool ok = false;
				repeatGap = itemValue.toDouble(&ok);
				if (!ok)
				{
					return cmd.error(QString("Invalid XML file (invalid value for '<%1>')").arg(s_xmlRepeatGap));
				}
			}
			else if (stream.name() == s_xmlFilePath)
			{
				inputFilePath = stream.readElementText();
				if (!QDir(inputFilePath).exists())
				{
					return cmd.error(QString("Invalid file path (directory pointed by '<%1>' doesn't exist)").arg(s_xmlFilePath));
				}
				//++mandatoryCount;
			}
			else if (stream.name() == s_outputXmlFilePath)
			{
				outputFilePath = stream.readElementText();
				if (!QDir(outputFilePath).exists())
				{
					return cmd.error(QString("Invalid output file path (directory pointed by '<%1>' doesn't exist)").arg(s_outputXmlFilePath));
				}
				//++mandatoryCount;
			}
			else
			{
				cmd.warning(QString("Unknown element: %1").arg(stream.name().toString()));
				stream.skipCurrentElement();
			}
		}

		if (mandatoryCount < 1 || (!repeatDim[0] && !repeatDim[1] && !repeatDim[2]))
		{
			return cmd.error(QString("Some mandatory elements are missing in the XML file (see documentation)"));
		}
	}

	//safety checks
	if (	boxThickness.x < ZERO_TOLERANCE
	        ||	boxThickness.y < ZERO_TOLERANCE
	        ||	boxThickness.z < ZERO_TOLERANCE
	        )
	{
		return cmd.error(QString("Invalid box thickness"));
	}

	CCVector3 repeatStep = boxThickness + CCVector3(repeatGap, repeatGap, repeatGap);
	if (	(repeatDim[0] && repeatStep.x < ZERO_TOLERANCE)
	        ||	(repeatDim[1] && repeatStep.y < ZERO_TOLERANCE)
	        ||	(repeatDim[2] && repeatStep.z < ZERO_TOLERANCE)
	        )
	{
		return cmd.error(QString("Repeat gap can't be equal or smaller than 'minus' box width"));
	}

	if (outputFilePath.isEmpty())
	{
		outputFilePath = inputFilePath;
	}

	int iterationCount = 1;

	//shall we load the entities?
	QStringList files;
	QDir dir;
	bool fromFiles = false;
	if (!inputFilePath.isEmpty())
	{
		//look for all files in the input directory
		dir = QDir(inputFilePath);
		assert(dir.exists());
		files = dir.entryList(QDir::Files);
		iterationCount = files.size();
		fromFiles = true;

		//remove any cloud or mesh in memory!
		cmd.removeClouds();
		cmd.removeMeshes();
	}

	for (int f = 0; f < iterationCount; ++f)
	{
		//shall we load files?
		QString filename;
		if (fromFiles)
		{
			assert(f < files.size());
			filename = dir.absoluteFilePath(files[f]);
			QFileInfo fileinfo(filename);
			if (!fileinfo.isFile() || fileinfo.suffix().toUpper() == "XML")
			{
				continue;
			}

			//let's try to load the file
			cmd.print(QString("Processing file: '%1'").arg(files[f]));

			bool result = false;
			{
				//hack: replace the current argument list by a fake 'load file' sequence
				QStringList realArguments = cmd.arguments();

				QStringList loadArguments;
				loadArguments << filename;
				cmd.arguments() = loadArguments;
				result = CommandLoad().process(cmd);

				//end of hack: restore the current argument list
				cmd.arguments() = realArguments;
			}

			if (!result)
			{
				cmd.warning("\tFailed to load file!");
				continue;
			}
		}
		else
		{
			assert(iterationCount == 1);
		}

		//repeat crop process on each file (or do it only once on the currently loaded entities)
		{
			ccHObject::Container entities;
			try
			{
				for (size_t i = 0; i < cmd.clouds().size(); ++i)
					entities.push_back(cmd.clouds()[i].pc);
				for (size_t j = 0; j < cmd.meshes().size(); ++j)
					entities.push_back(cmd.meshes()[j].mesh);
			}
			catch (const std::bad_alloc&)
			{
				return cmd.error("Not enough memory!");
			}

			for (size_t i = 0; i < entities.size(); ++i)
			{
				//check entity bounding-box
				ccHObject* ent = entities[i];
				ccBBox bbox = ent->getOwnBB();
				if (!bbox.isValid())
				{
					cmd.warning(QString("Entity '%1' has an invalid bounding-box!").arg(ent->getName()));
					continue;
				}

				//browse to/create a subdirectory with the (base) filename as name
				QString basename;
				if (fromFiles)
				{
					basename = QFileInfo(filename).baseName();
				}
				else
				{
					basename = i < cmd.clouds().size() ? cmd.clouds()[i].basename : cmd.meshes()[i - cmd.clouds().size()].basename;
				}

				if (entities.size() > 1)
					basename += QString("_%1").arg(i + 1);

				QDir outputDir(outputFilePath);
				if (outputFilePath.isEmpty())
				{
					if (fromFiles)
					{
						assert(false);
						outputDir = QDir::current();
					}
					else
					{
						outputDir = QDir(i < cmd.clouds().size() ? cmd.clouds()[i].path : cmd.meshes()[i - cmd.clouds().size()].path);
					}
				}

				assert(outputDir.exists());
				if (outputDir.cd(basename))
				{
					//if the directory already exists...
					cmd.warning(QString("Subdirectory '%1' already exists").arg(basename));
				}
				else if (outputDir.mkdir(basename))
				{
					outputDir.cd(basename);
				}
				else
				{
					cmd.warning(QString("Failed to create subdirectory '%1' (check access rights and base name validity!)").arg(basename));
					continue;
				}

				int toto = ceil(-0.4);
				int toto2 = ceil(-0.6);

				//place the initial box at the beginning of the entity bounding box
				CCVector3 C0 = autoCenter ? bbox.getCenter() : boxCenter;
				unsigned steps[3] = { 1, 1, 1 };
				for (unsigned d = 0; d < 3; ++d)
				{
					if (repeatDim[d])
					{
						PointCoordinateType boxHalfWidth = boxThickness.u[d] / 2;
						PointCoordinateType distToMinBorder = C0.u[d] - boxHalfWidth - bbox.minCorner().u[d];
						int stepsToMinBorder = static_cast<int>(ceil(distToMinBorder / repeatStep.u[d]));
						C0.u[d] -= stepsToMinBorder * repeatStep.u[d];

						PointCoordinateType distToMaxBorder = bbox.maxCorner().u[d] - C0.u[d] - boxHalfWidth;
						int stepsToMaxBoder = static_cast<int>(ceil(distToMaxBorder / repeatStep.u[d]) + 1);
						assert(stepsToMaxBoder >= 0);
						steps[d] = std::max<unsigned>(stepsToMaxBoder, 1);
					}
				}

				cmd.print(QString("Will extract up to (%1 x %2 x %3) = %4 sections").arg(steps[0]).arg(steps[1]).arg(steps[2]).arg(steps[0] * steps[1] * steps[2]));

				//now extract the slices
				for (unsigned dx = 0; dx < steps[0]; ++dx)
				{
					for (unsigned dy = 0; dy < steps[1]; ++dy)
					{
						for (unsigned dz = 0; dz < steps[2]; ++dz)
						{
							CCVector3 C = C0 + CCVector3(dx*repeatStep.x, dy*repeatStep.y, dz*repeatStep.z);
							ccBBox cropBox(C - boxThickness / 2, C + boxThickness / 2);
							cmd.print(QString("Box (%1;%2;%3) --> (%4;%5;%6)")
							          .arg(cropBox.minCorner().x).arg(cropBox.minCorner().y).arg(cropBox.minCorner().z)
							          .arg(cropBox.maxCorner().x).arg(cropBox.maxCorner().y).arg(cropBox.maxCorner().z)
							          );
							ccHObject* croppedEnt = ccCropTool::Crop(ent, cropBox, inside);
							if (croppedEnt)
							{
								QString outputBasename = basename + QString("_%1_%2_%3").arg(C.x).arg(C.y).arg(C.z);
								QString errorStr;
								//original entity is a cloud?
								if (i < cmd.clouds().size())
								{
									CLCloudDesc desc(static_cast<ccPointCloud*>(croppedEnt),
									                 outputBasename,
									                 outputDir.absolutePath(),
									                 entities.size() > 1 ? static_cast<int>(i) : -1);
									errorStr = cmd.exportEntity(desc);
								}
								else //otherwise it's a mesh
								{
									CLMeshDesc desc(static_cast<ccMesh*>(croppedEnt),
									                outputBasename,
									                outputDir.absolutePath(),
									                entities.size() > 1 ? static_cast<int>(i) : -1);
									errorStr = cmd.exportEntity(desc);
								}

								delete croppedEnt;
								croppedEnt = 0;

								if (!errorStr.isEmpty())
									return cmd.error(errorStr);
							}
						}
					}
				}
			}

			if (fromFiles)
			{
				//unload entities
				cmd.removeClouds();
				cmd.removeMeshes();
			}
		}
	}

	return true;
}
Example #2
0
int main(int argc, char **argv)
{
//	std::cerr << "Now starting...\n";
//	malloc_stats();
	int i=1;
	char cmdLine[15];
	BOOL end=FALSE;

	compdists=IOread=IOwrite=objs=0;
	std::cout << "**  MTree: An M-Tree based on Generalized Search Trees\n";
	while(strcmp(cmdLine, "quit")) {
		scanf("%s", cmdLine);
		if(!strcmp(cmdLine, "drop")) {
			CommandDrop("graphs.M3");
			if(argc<5) {
				std::cout << "Usage is: MTree [min_util] [split_f] [promote_f] [sec_promote_f] ([vote_f] ([n_cand]|[radius_f]))\n";
				exit(-1);
			}
			MIN_UTIL=atof(argv[1]);
			SPLIT_FUNCTION=(s_function)atoi(argv[2]);
			PROMOTE_PART_FUNCTION=(pp_function)atoi(argv[3]);
			SECONDARY_PART_FUNCTION=(pp_function)atoi(argv[4]);
			if(SECONDARY_PART_FUNCTION==CONFIRMED) {
				std::cout << "The secondary promotion function must be an unconfirmed one\n";
				exit(-1);
			}
			if(PROMOTE_PART_FUNCTION==SAMPLING) {
				if(argc<6) {
					std::cout << "Usage is: MTree [min_util] [split_f] [promote_f] ([vote_f] ([n_cand]|[radius_f]))\n";
					exit(-1);
				}
				NUM_CANDIDATES=atoi(argv[5]);
			}
			if(PROMOTE_PART_FUNCTION==CONFIRMED) {
				if(argc<6) {
					std::cout << "Usage is: MTree [min_util] [split_f] [promote_f] [sec_promote_f] ([vote_f] ([n_cand]|[radius_f]))\n";
					exit(-1);
				}
				PROMOTE_VOTE_FUNCTION=(pv_function)atoi(argv[5]);
				if(PROMOTE_VOTE_FUNCTION==SAMPLINGV) {
					if(argc<7) {
						std::cout << "Usage is: MTree [min_util] [split_f] [promote_f] ([vote_f] ([n_cand]|[radius_f]))\n";
						exit(-1);
					}
					NUM_CANDIDATES=atoi(argv[6]);
				}
				else if(PROMOTE_VOTE_FUNCTION==mM_RAD) {
					if(argc<7) {
						std::cout << "Usage is: MTree [min_util] [split_f] [promote_f] ([vote_f] ([n_cand]|[radius_f]))\n";
						exit(-1);
					}
					RADIUS_FUNCTION=(r_function)atoi(argv[6]);
				}
			}
			switch(SPLIT_FUNCTION) {
				case G_HYPERPL:
					std::cout << "G_HYPL, ";
					break;
				case BAL_G_HYPERPL:
					std::cout << "BAL_G_HYPL, ";
					break;
				case BALANCED:
					std::cout << "BAL, ";
					break;
			}
			switch(PROMOTE_PART_FUNCTION) {
				case RANDOM:
					std::cout << "RAN_2 ";
					break;
				case MAX_UB_DIST:
					std::cout << "M_UB_d ";
					break;
				case SAMPLING:
					std::cout << "SAMP" << NUM_CANDIDATES << "_2 ";
					break;
				case MIN_RAD:
					std::cout << "m_R_2 ";
					break;
				case MIN_OVERLAPS:
					std::cout << "m_O_2 ";
					break;
				case CONFIRMED:
				switch(PROMOTE_VOTE_FUNCTION) {
					case RANDOMV:
						std::cout << "RAN_1 ";
						break;
					case SAMPLINGV:
						std::cout << "SAMP" << NUM_CANDIDATES << "_1 ";
						break;
					case MAX_LB_DIST:
						std::cout << "M_LB_d ";
						break;
					case mM_RAD:
						std::cout << "mM_";
						switch(RADIUS_FUNCTION) {
							case LB:
								std::cout << "m";
								break;
							case AVG:
								std::cout << "A";
								break;
							case UB:
								std::cout << "M";
								break;
						}
						std::cout << "_r ";
						break;
				}
				break;
			}
			switch(SECONDARY_PART_FUNCTION) {
				case RANDOM:
					std::cout << "(RAN_2)\n";
					break;
				case MAX_UB_DIST:
					std::cout << "(M_UB_d)\n";
					break;
				case SAMPLING:
					std::cout << "(SAMP" << NUM_CANDIDATES << "_2)\n";
					break;
				case MIN_RAD:
					std::cout << "(m_R_2)\n";
					break;
				case MIN_OVERLAPS:
					std::cout << "(m_O_2)\n";
					break;
			}
			CommandCreate("mtree", "graphs.M3");
		}
		else if(!strcmp(cmdLine, "select")) {
			MTobject *obj=Read();
			Pred *pred=new Pred(*obj);
			double r;

			scanf("%s", cmdLine);
			r=atof(cmdLine);

			SimpleQuery query(pred, r);

			delete obj;
			delete pred;
			if(!gist) CommandOpen("mtree", "graphs.M3");
			CommandSelect(query);
			CommandClose();
		}
		else if((!strcmp(cmdLine, "nearest"))||(!strcmp(cmdLine, "farthest"))) {
			int k;
			BOOL nearest=strcmp(cmdLine, "farthest");
			MTpred *pred;
			MTobject *obj=Read();

			scanf("%s", cmdLine);
			k=atoi(cmdLine);
			if(nearest) pred=new Pred(*obj);
			else {
				MTpred *npred=new Pred(*obj);

				pred=new NotPred(npred);
				delete npred;
			}
//			eps=atof(argv[1]);
			TopQuery query(pred, k);

			delete pred;
			if(!gist) CommandOpen("mtree", "graphs.M3");
			CommandNearest(query);
			CommandClose();
			delete obj;
		}
		else if(!strcmp(cmdLine, "cursor")) {
			MTobject *obj=Read();
			Pred pred(*obj);

			if(!gist) CommandOpen("mtree", "graphs.M3");
			MTcursor cursor(*gist, pred);

			scanf("%s", cmdLine);
			while(strcmp(cmdLine, "close")) {
				if(!strcmp(cmdLine, "next")) {
					int k;
					GiSTlist<MTentry *> list;

					scanf("%s", cmdLine);
					k=atoi(cmdLine);

//					std::cout << "Fetching next " << k << " entries...\n";
					for(; k>0; k--) list.Append(cursor.Next());
					while(!list.IsEmpty()) {
						MTentry *e=list.RemoveFront();
//						std::cout << e;
						delete e;
						objs++;
					}
				}
				scanf("%s", cmdLine);
			}
			delete obj;
			CommandClose();
		}
/*		else if(!strcmp(cmdLine, "find")) {
			int n, k, l, oldcompdists, oldIOread, oldobjs;

			scanf("%s", cmdLine);
			n=atoi(cmdLine);

			double **x=(double **)calloc(n, sizeof(double *));
			for(i=0; i<n; i++) x[i]=(double *)calloc(dimension, sizeof(double));
			MTpred **p=(MTpred **)calloc(n, sizeof(MTpred *));
			AndPred **ap=(AndPred **)calloc(n-1, sizeof(AndPred *));

			for(i=0; i<n; i++) {
				for(int j=0; j<dimension; j++) {
					scanf("%s", cmdLine);
					x[i][j]=atof(cmdLine);
				}
				if(x[i][0]>=0) {
					MTobject obj(x[i]);
//					std::cout << "obj=" << obj << std::endl;
					p[i]=new Pred(obj);
				}
				else {
					x[i][0]=-x[i][0];
					MTobject obj(x[i]);
//					std::cout << "obj=" << obj << std::endl;
					Pred *pr=new Pred(obj);
					p[i]=new NotPred(pr);
					delete pr;
				}
//				std::cout << "pred=" << *p[i] << std::endl;
			}
			if(n==2) std::cout << "d=" << p[1]->distance(((Pred *)p[0])->obj()) << std::endl;
			ap[0]=new AndPred(p[0], p[1]);
			for(i=1; i<n-1; i++) ap[i]=new AndPred(ap[i-1], p[i+1]);
//			std::cout << "Query: " << *ap[n-2] << std::endl;
			scanf("%s", cmdLine);
			k=atoi(cmdLine);
			compdists=IOread=IOwrite=0;

			TopQuery q(ap[n-2], k);

			if(!gist) CommandOpen("mtree", "graphs.M3");
			CommandNearest(q);
			std::cout << "Computed dists=" << compdists << "\nIO reads=" << IOread << "\nIO writes=" << IOwrite << "\nObjs=" << objs << std::endl;

			BOOL (*obs)[IndObjs]=new BOOL [n][IndObjs], pass=FALSE;

			l=-90;
			do {
				int j;

				for(j=0; j<IndObjs; j++)
					for(i=0; i<n; i++) obs[i][j]=FALSE;
				compdists=IOread=IOwrite=objs=0;
				l+=100;
				for(i=0; i<n; i++) {
					TopQuery qi(p[i], l);
					GiSTlist<GiSTobject *> list=gist->TopSearch(qi);

					while(!list.IsEmpty()) {
						MTentry *e=(MTentry *)list.RemoveFront();

						obs[i][e->Ptr()]=TRUE;
						delete e;
					}
				}
				for(j=0; j<IndObjs; j++) {
					BOOL check=TRUE;

					for(i=0; (i<n)&&check; i++) check=obs[i][j];
					if(check) objs++;
				}
//				std::cout << l << "=>" << objs << std::endl;
				if(objs>k) {
					pass=TRUE;
					l-=110;
					oldcompdists=compdists;
					oldIOread=IOread;
					oldobjs=objs;
				}
				if(!pass) {
					oldcompdists=compdists;
					oldIOread=IOread;
					oldobjs=objs;
				}
//				else if(objs==0) l+=90; // dangerous: could lead to infinite loops...
			} while(((objs<k)&&!pass)||((objs>k)&&pass));
			std::cout << l << "=>" << objs << std::endl;
			if(objs<k) std::cout << "Computed dists=" << oldcompdists << "\nIO reads=" << oldIOread << "\nObjs=" << oldobjs << std::endl;
			else std::cout << "Computed dists=" << compdists << "\nIO reads=" << IOread << "\nObjs=" << objs << std::endl;
			delete []obs;
			for(i=0; i<n; i++) delete x[i];
			free(x);
			for(i=0; i<n; i++) delete p[i];
			free(p);
			for(i=0; i<n-1; i++) delete ap[i];
			free(ap);
			compdists=IOread=IOwrite=objs=0;
			CommandClose();
		}
*/		else if(!strcmp(cmdLine, "check")) {
			if(!gist) CommandOpen("mtree", "graphs.M3");
			CommandCheck();
			CommandClose();
		}
		else if(!strcmp(cmdLine, "dump")) {
			if(!gist) CommandOpen("mtree", "graphs.M3");
			CommandDump();
			CommandClose();
		}
		else if(!strcmp(cmdLine, "stats")) {
			if(!gist) CommandOpen("mtree", "graphs.M3");
			CommandStats();
			CommandClose();
		}
		else if(!strcmp(cmdLine, "add")) {
			if(!gist) CommandOpen("mtree", "graphs.M3");
			scanf("%s", cmdLine);
			i=atoi(cmdLine);
			if(argc<5) {
				std::cout << "Usage is: MTree [min_util] [split_f] [promote_f] [sec_promote_f] ([vote_f] ([n_cand]|[radius_f]))\n";
				exit(-1);
			}
			MIN_UTIL=atof(argv[1]);
			SPLIT_FUNCTION=(s_function)atoi(argv[2]);
			PROMOTE_PART_FUNCTION=(pp_function)atoi(argv[3]);
			SECONDARY_PART_FUNCTION=(pp_function)atoi(argv[4]);
			if(SECONDARY_PART_FUNCTION==CONFIRMED) {
				std::cout << "The secondary promotion function must be an unconfirmed one\n";
				exit(-1);
			}
			if(PROMOTE_PART_FUNCTION==SAMPLING) {
				if(argc<6) {
					std::cout << "Usage is: MTree [min_util] [split_f] [promote_f] ([vote_f] ([n_cand]|[radius_f]))\n";
					exit(-1);
				}
				NUM_CANDIDATES=atoi(argv[5]);
			}
			if(PROMOTE_PART_FUNCTION==CONFIRMED) {
				if(argc<6) {
					std::cout << "Usage is: MTree [min_util] [split_f] [promote_f] [sec_promote_f] ([vote_f] ([n_cand]|[radius_f]))\n";
					exit(-1);
				}
				PROMOTE_VOTE_FUNCTION=(pv_function)atoi(argv[5]);
				if(PROMOTE_VOTE_FUNCTION==SAMPLINGV) {
					if(argc<7) {
						std::cout << "Usage is: MTree [min_util] [split_f] [promote_f] ([vote_f] ([n_cand]|[radius_f]))\n";
						exit(-1);
					}
					NUM_CANDIDATES=atoi(argv[6]);
				}
				else if(PROMOTE_VOTE_FUNCTION==mM_RAD) {
					if(argc<7) {
						std::cout << "Usage is: MTree [min_util] [split_f] [promote_f] ([vote_f] ([n_cand]|[radius_f]))\n";
						exit(-1);
					}
					RADIUS_FUNCTION=(r_function)atoi(argv[6]);
				}
			}
			switch(SPLIT_FUNCTION) {
				case G_HYPERPL:
					std::cout << "G_HYPL, ";
					break;
				case BAL_G_HYPERPL:
					std::cout << "BAL_G_HYPL, ";
					break;
				case BALANCED:
					std::cout << "BAL, ";
					break;
			}
			switch(PROMOTE_PART_FUNCTION) {
				case RANDOM:
					std::cout << "RAN_2 ";
					break;
				case MAX_UB_DIST:
					std::cout << "M_UB_d ";
					break;
				case SAMPLING:
					std::cout << "SAMP" << NUM_CANDIDATES << "_2 ";
					break;
				case MIN_RAD:
					std::cout << "m_R_2 ";
					break;
				case MIN_OVERLAPS:
					std::cout << "m_O_2 ";
					break;
				case CONFIRMED:
					switch(PROMOTE_VOTE_FUNCTION) {
						case RANDOMV:
							std::cout << "RAN_1 ";
							break;
						case SAMPLINGV:
							std::cout << "SAMP" << NUM_CANDIDATES << "_1 ";
							break;
						case MAX_LB_DIST:
							std::cout << "M_LB_d ";
							break;
						case mM_RAD:
							std::cout << "mM_";
							switch(RADIUS_FUNCTION) {
								case LB:
									std::cout << "m";
									break;
								case AVG:
									std::cout << "A";
									break;
								case UB:
									std::cout << "M";
									break;
							}
							std::cout << "_r ";
							break;
					}
					break;
			}
			switch(SECONDARY_PART_FUNCTION) {
				case RANDOM:
					std::cout << "(RAN_2)\n";
					break;
				case MAX_UB_DIST:
					std::cout << "(M_UB_d)\n";
					break;
				case SAMPLING:
					std::cout << "(SAMP" << NUM_CANDIDATES << "_2)\n";
					break;
				case MIN_RAD:
					std::cout << "(m_R_2)\n";
					break;
				case MIN_OVERLAPS:
					std::cout << "(m_O_2)\n";
					break;
			}
		}
		else if(!strcmp(cmdLine, "insert")) {
			MTobject *obj=Read();

			if(!gist) CommandOpen("mtree", "graphs.M3");
			CommandInsert(MTkey(*obj, 0, 0), i++);
			delete obj;
		}
		else if(!strcmp(cmdLine, "load")) {
			MTentry **entries;
			int n;

			if(argc<2) {
				std::cout << "Usage is: MTree [min_util]\n";
				exit(-1);
			}
			MIN_UTIL=atof(argv[1]);
			i=0;
			scanf("%s", cmdLine);
			n=atoi(cmdLine);
			entries=new MTentry*[n];
			for(i=0; i<n; i++) {
				MTobject *obj=Read();

				entries[i]=new MTentry(MTkey(*obj, 0, 0), i);
				delete obj;
			}
			CommandLoad("graphs.M3", entries, n);
			for(i=0; i<n; i++) delete entries[i];
			delete []entries;
		}
	}
	std::cout << "Computed dists=" << compdists << "\nIO reads=" << IOread << "\nIO writes=" << IOwrite << "\nObjs=" << objs << std::endl;
	CommandQuit();
//	std::cerr << "Now exiting...\n";
//	malloc_stats();
}