Example #1
0
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();
}
Example #2
0
/// 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;
}