int main(int argc, char *argv[]) { ArgParse::ArgParse ap; bool printVersion = false; bool printHelp = false; int maxPointCount = 200000000; std::string serverName; double yaw = -DBL_MAX, pitch = -DBL_MAX, roll = -DBL_MAX; double viewRadius = -DBL_MAX; std::string shaderName; bool useServer = true; bool clearFiles = false; bool addFiles = false; bool rmTemp = false; bool quitRemote = false; bool queryCursor = false; ap.options( "displaz - A lidar point cloud viewer\n" "Usage: displaz [opts] [file1.las ...]", "%*", storeFileName, "", "<SEPARATOR>", "\nInitial settings / remote commands:", "-maxpoints %d", &maxPointCount, "Maximum number of points to load at a time", "-noserver %!", &useServer, "Don't attempt to open files in existing window", "-server %s", &serverName, "Name of displaz instance to message on startup", "-shader %s", &shaderName, "Name of shader file to load on startup", "-viewangles %F %F %F", &yaw, &pitch, &roll, "Set view angles in degrees [yaw, pitch, roll]", "-viewradius %F", &viewRadius, "Set distance to view point", "-clear", &clearFiles, "Remote: clear all currently loaded files", "-quit", &quitRemote, "Remote: close the existing displaz window", "-add", &addFiles, "Remote: add files to currently open set", "-rmtemp", &rmTemp, "*Delete* files after loading - use with caution to clean up single-use temporary files after loading", "-querycursor", &queryCursor, "Query 3D cursor location from displaz instance", "<SEPARATOR>", "\nAdditional information:", "-version", &printVersion, "Print version number", "-help", &printHelp, "Print command line usage help", NULL ); attachToParentConsole(); if(ap.parse(argc, const_cast<const char**>(argv)) < 0) { ap.usage(); std::cerr << "ERROR: " << ap.geterror() << std::endl; return EXIT_FAILURE; } if (printVersion) { std::cout << "version " DISPLAZ_VERSION_STRING "\n"; return EXIT_SUCCESS; } if (printHelp) { ap.usage(); return EXIT_SUCCESS; } QString socketName = displazSocketName(QString::fromStdString(serverName)); if (useServer) { // Alas, using sockets requires QCoreApplication/QApplication to be // instantiated. However, on linux each QApplication appears to consume // GUI resources, regardless of whether it exits before we actually create // any widgets. This means we may run out of resources if too many displaz // instances are launched by a script. int dummyArgc = 0; char** dummyArgv = 0; QCoreApplication coreApp(dummyArgc, dummyArgv); // TODO: Factor out this socket comms code - sending and recieving of // messages should happen in a centralised place. QDir currentDir = QDir::current(); // Attempt to locate a running displaz instance std::unique_ptr<IpcChannel> channel = IpcChannel::connectToServer(socketName); if (channel) { QByteArray command; if (!g_initialFileNames.empty()) { command = addFiles ? "ADD_FILES" : "OPEN_FILES"; if (rmTemp) command += "\nRMTEMP"; for (int i = 0; i < g_initialFileNames.size(); ++i) { command += "\n"; command += currentDir.absoluteFilePath(g_initialFileNames[i]).toUtf8(); } } else if (clearFiles) { command = "CLEAR_FILES"; } else if (yaw != -DBL_MAX) { command = "SET_VIEW_ANGLES\n" + QByteArray().setNum(yaw) + "\n" + QByteArray().setNum(pitch) + "\n" + QByteArray().setNum(roll); } else if (viewRadius != -DBL_MAX) { command = "SET_VIEW_RADIUS\n" + QByteArray().setNum(viewRadius); } else if (quitRemote) { command = "QUIT"; } else if (queryCursor) { command = "QUERY_CURSOR"; } else { std::cerr << "WARNING: Existing window found, but no remote " "command specified - exiting\n"; return EXIT_FAILURE; } channel->sendMessage(command); if (queryCursor) { QByteArray msg = channel->receiveMessage(); std::cout.write(msg.data(), msg.length()); std::cout << "\n"; } channel->disconnectFromServer(); return EXIT_SUCCESS; } else { // Some remote commands fail when no instance is found if (queryCursor) { std::cerr << "ERROR: No remote displaz instance found\n"; return EXIT_FAILURE; } // Some remote commands succeed when no instance is found if (quitRemote || clearFiles) { return EXIT_SUCCESS; } } } else if (quitRemote) { // If no remote found, assume -quit was successful std::cerr << "ERROR: -quit cannot be combined with -noserver\n"; return EXIT_FAILURE; } QApplication app(argc, argv); setupQFileSearchPaths(); Q_INIT_RESOURCE(resource); qRegisterMetaType<std::shared_ptr<Geometry>>("std::shared_ptr<Geometry>"); // Multisampled antialiasing - this makes rendered point clouds look much // nicer, but also makes the render much slower, especially on lower // powered graphics cards. //QGLFormat f = QGLFormat::defaultFormat(); //f.setSampleBuffers(true); //QGLFormat::setDefaultFormat(f); PointViewerMainWindow window; window.setMaxPointCount(maxPointCount); if (useServer) window.startIpcServer(socketName); if (!shaderName.empty()) window.openShaderFile(QString::fromStdString(shaderName)); window.show(); for (int i = 0; i < g_initialFileNames.size(); ++i) window.fileLoader().loadFile(g_initialFileNames[i], rmTemp); return app.exec(); }
/// dvox: A batch voxelizer for unstructured point clouds int main(int argc, char* argv[]) { Imath::V3d boundMin = Imath::V3d(0); double rootNodeWidth = 1000; float pointRadius = 0.2f; int brickRes = 8; double leafNodeWidth = 2.5; double dbTileSize = 100; double dbCacheSize = 100; bool logProgress = false; int logLevel = Logger::Info; ArgParse::ArgParse ap; ap.options( "dvox - voxelize unstructured point clouds (version " DISPLAZ_VERSION_STRING ")\n" "\n" "Usage: dvox input1 [input2 ...] output\n" "\n" "input can be .las or .pointdb\n" "output can be .pointdb or .hcloud", "%*", storePositionalArg, "", "<SEPARATOR>", "\nVoxelization Options:", "-bound %F %F %F %F", &boundMin.x, &boundMin.y, &boundMin.z, &rootNodeWidth, "Bounding box for hcloud (min_x min_y min_z width)", "-pointradius %f", &pointRadius, "Assumed radius of points used during voxelization", "-brickresolution %d", &brickRes, "Resolution of octree bricks", "-leafnoderadius %F", &leafNodeWidth, "Desired width for octree leaf nodes", "<SEPARATOR>", "\nPoint Database options:", "-dbtilesize %F", &dbTileSize, "Tile size of temporary point database", "-dbcachesize %F", &dbCacheSize, "In-memory cache size for database in MB (default 100 MB)", "<SEPARATOR>", "\nInformational options:", "-loglevel %d", &logLevel, "Logger verbosity (default 3 = info, greater is more verbose)", "-progress", &logProgress, "Log processing progress", NULL ); StreamLogger logger(std::cerr); if (ap.parse(argc, const_cast<const char**>(argv)) < 0) { ap.usage(); logger.error("%s", ap.geterror()); return EXIT_FAILURE; } if (argc == 1) { ap.usage(); return EXIT_FAILURE; } logger.setLogLevel(Logger::LogLevel(logLevel)); logger.setLogProgress(logProgress); try { if (g_positionalArgs.size() < 2) { logger.error("Expected at least two positional arguments"); ap.usage(); return EXIT_FAILURE; } std::string outputPath = g_positionalArgs.back(); std::vector<std::string> inputPaths(g_positionalArgs.begin(), g_positionalArgs.end()-1); if (endswith(outputPath.toLower(), ".pointdb")) { convertLasToPointDb(outputPath, inputPaths, Imath::Box3d(), dbTileSize, logger); } else { if (!endswith(g_positionalArgs[0].toLower(), ".pointdb") || inputPaths.size() != 1) { logger.error("Need exactly one input .pointdb file"); return EXIT_FAILURE; } if (!endswith(outputPath.toLower(), ".hcloud")) { logger.error("Expected .hcloud file as output path"); return EXIT_FAILURE; } SimplePointDb pointDb(inputPaths[0], (size_t)(dbCacheSize*1024*1024), logger); int leafDepth = (int)floor(log(rootNodeWidth/leafNodeWidth)/log(2) + 0.5); logger.info("Leaf node width = %.3f", rootNodeWidth / (1 << leafDepth)); std::ofstream outputFile(outputPath); voxelizePointCloud(outputFile, pointDb, pointRadius, boundMin, rootNodeWidth, leafDepth, brickRes, logger); } } catch (std::exception& e) { logger.error("Caught exception: %s", e.what()); return EXIT_FAILURE; } return EXIT_SUCCESS; }