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; }
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)&✓ 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(); }