PipelineManagerPtr InfoKernel::makePipeline(const std::string& filename, bool noPoints) { if (!pdal::FileUtils::fileExists(filename)) throw pdal_error("File not found: " + filename); PipelineManagerPtr output(new PipelineManager); if (filename == "STDIN") { output->readPipeline(std::cin); } else if (FileUtils::extension(filename) == ".xml" || FileUtils::extension(filename) == ".json") { output->readPipeline(filename); } else { StageFactory factory; std::string driver = factory.inferReaderDriver(filename); if (driver.empty()) throw pdal_error("Cannot determine input file type of " + filename); Stage& reader = output->addReader(driver); Options ro; ro.add("filename", filename); if (noPoints) ro.add("count", 0); reader.setOptions(ro); m_reader = &reader; } return output; }
bool ossimPdalFileReader::open(const ossimFilename& fname) { // PDAL opens the file here. m_inputFilename = fname; pdal::Stage* reader = 0; try { if (m_inputFilename.contains("fauxreader")) { // Debug generated image: reader = new FauxReader; m_pdalPipe = reader; m_pdalOptions.add("mode", "ramp"); BOX3D bbox(-0.001, -0.001, -100.0, 0.001, 0.001, 100.0); m_pdalOptions.add("bounds", bbox); m_pdalOptions.add("num_points", "11"); m_pdalPipe->setOptions(m_pdalOptions); } else { StageFactory factory; const string driver = factory.inferReaderDriver(m_inputFilename.string()); if (driver == "") throw pdal_error("File type not supported by PDAL"); reader = factory.createStage(driver); if (!reader) throw pdal_error("No reader created by PDAL"); m_pdalOptions.add("filename", m_inputFilename.string()); reader->setOptions(m_pdalOptions); // Stick a stats filter in the pipeline: m_pdalPipe = new StatsFilter(); m_pdalPipe->setInput(*reader); } m_pointTable = PointTablePtr(new PointTable); m_pdalPipe->prepare(*m_pointTable); m_pvs = m_pdalPipe->execute(*m_pointTable); if (!m_pvs.empty()) { m_currentPV = *(m_pvs.begin()); // Determine available data fields: establishAvailableFields(); } std::string wkt; const SpatialReference& srs = reader->getSpatialReference(); wkt = srs.getWKT(SpatialReference::eCompoundOK, false); m_geometry = new ossimPointCloudGeometry(wkt); } catch (std::exception& e) { //ossimNotify() << e.what() << endl; return false; } // Establish the bounds (geographic & radiometric). These are stored in two extreme point records // maintained by the base class: establishMinMax(); return true; }
int TranslateKernel::execute() { // setting common options for each stage propagates the debug flag and // verbosity level Options readerOptions, filterOptions, writerOptions; setCommonOptions(readerOptions); setCommonOptions(filterOptions); setCommonOptions(writerOptions); m_manager = std::unique_ptr<PipelineManager>(new PipelineManager); if (!m_readerType.empty()) { m_manager->addReader(m_readerType); } else { StageFactory factory; std::string driver = factory.inferReaderDriver(m_inputFile); if (driver.empty()) throw app_runtime_error("Cannot determine input file type of " + m_inputFile); m_manager->addReader(driver); } if (m_manager == NULL) throw pdal_error("Error making pipeline\n"); Stage* reader = m_manager->getStage(); if (reader == NULL) throw pdal_error("Error getting reader\n"); readerOptions.add("filename", m_inputFile); reader->setOptions(readerOptions); Stage* stage = reader; // add each filter provided on the command-line, updating the stage pointer for (auto const f : m_filterType) { std::string filter_name(f); if (!Utils::startsWith(f, "filters.")) filter_name.insert(0, "filters."); Stage* filter = &(m_manager->addFilter(filter_name)); if (filter == NULL) { std::ostringstream oss; oss << "Unable to add filter " << filter_name << ". Filter " "is invalid or plugin could not be loaded. Check " "'pdal --drivers'."; throw pdal_error("Error getting filter\n"); } filter->setOptions(filterOptions); filter->setInput(*stage); stage = filter; } if (!m_writerType.empty()) { m_manager->addWriter(m_writerType); } else { StageFactory factory; std::string driver = factory.inferWriterDriver(m_outputFile); if (driver.empty()) throw app_runtime_error("Cannot determine output file type of " + m_outputFile); Options options = factory.inferWriterOptionsChanges(m_outputFile); writerOptions += options; m_manager->addWriter(driver); } Stage* writer = m_manager->getStage(); if (writer == NULL) throw pdal_error("Error getting writer\n"); writerOptions.add("filename", m_outputFile); writer->setOptions(writerOptions); writer->setInput(*stage); // be sure to recurse through any extra stage options provided by the user applyExtraStageOptionsRecursive(writer); m_manager->execute(); if (m_pipelineOutput.size() > 0) PipelineWriter::writePipeline(m_manager->getStage(), m_pipelineOutput); return 0; }
int HeightAboveGroundKernel::execute() { // we require separate contexts for the input and ground files PointContextRef input_ctx; PointContextRef ground_ctx; // because we are appending HeightAboveGround to the input buffer, we must // register it's Dimension input_ctx.registerDim(Dimension::Id::HeightAboveGround); // StageFactory will be used to create required stages StageFactory f; // setup the reader, inferring driver type from the filename std::string reader_driver = f.inferReaderDriver(m_input_file); std::unique_ptr<Reader> input(f.createReader(reader_driver)); Options readerOptions; readerOptions.add("filename", m_input_file); input->setOptions(readerOptions); // go ahead and execute to get the PointBuffer input->prepare(input_ctx); PointBufferSet pbSetInput = input->execute(input_ctx); PointBufferPtr input_buf = *pbSetInput.begin(); PointBufferSet pbSetGround; PointBufferPtr ground_buf; if (m_use_classification) { // the user has indicated that the classification dimension exists, so // we will find all ground returns Option source("source", "import numpy as np\n" "def yow1(ins,outs):\n" " cls = ins['Classification']\n" " keep_classes = [2]\n" " keep = np.equal(cls, keep_classes[0])\n" " outs['Mask'] = keep\n" " return True\n" ); Option module("module", "MyModule"); Option function("function", "yow1"); Options opts; opts.add(source); opts.add(module); opts.add(function); // and create a PointBuffer of only ground returns std::unique_ptr<Filter> pred(f.createFilter("filters.predicate")); pred->setOptions(opts); pred->setInput(input.get()); pred->prepare(ground_ctx); pbSetGround = pred->execute(ground_ctx); ground_buf = *pbSetGround.begin(); } else { // the user has provided a file containing only ground returns, setup // the reader, inferring driver type from the filename std::string ground_driver = f.inferReaderDriver(m_ground_file); std::unique_ptr<Reader> ground(f.createReader(ground_driver)); Options ro; ro.add("filename", m_ground_file); ground->setOptions(ro); // go ahead and execute to get the PointBuffer ground->prepare(ground_ctx); pbSetGround = ground->execute(ground_ctx); ground_buf = *pbSetGround.begin(); } typedef pcl::PointXYZ PointT; typedef pcl::PointCloud<PointT> Cloud; typedef Cloud::Ptr CloudPtr; // convert the input PointBuffer to a PointCloud CloudPtr cloud(new Cloud); BOX3D const& bounds = input_buf->calculateBounds(); pclsupport::PDALtoPCD(*input_buf, *cloud, bounds); // convert the ground PointBuffer to a PointCloud CloudPtr cloud_g(new Cloud); // here, we offset the ground cloud by the input bounds so that the two are aligned pclsupport::PDALtoPCD(*ground_buf, *cloud_g, bounds); // create a set of planar coefficients with X=Y=0,Z=1 pcl::ModelCoefficients::Ptr coefficients(new pcl::ModelCoefficients()); coefficients->values.resize(4); coefficients->values[0] = coefficients->values[1] = 0; coefficients->values[2] = 1.0; coefficients->values[3] = 0; // create the filtering object and project ground returns into xy plane pcl::ProjectInliers<PointT> proj; proj.setModelType(pcl::SACMODEL_PLANE); proj.setInputCloud(cloud_g); proj.setModelCoefficients(coefficients); CloudPtr cloud_projected(new Cloud); proj.filter(*cloud_projected); // setup the KdTree pcl::KdTreeFLANN<PointT> tree; tree.setInputCloud(cloud_projected); // loop over all points in the input cloud, finding the nearest neighbor in // the ground returns (XY plane only), and calculating the difference in z int32_t k = 1; for (size_t idx = 0; idx < cloud->points.size(); ++idx) { // Search for nearesrt neighbor of the query point std::vector<int32_t> neighbors(k); std::vector<float> distances(k); PointT temp_pt = cloud->points[idx]; temp_pt.z = 0.0f; int num_neighbors = tree.nearestKSearch(temp_pt, k, neighbors, distances); double hag = cloud->points[idx].z - cloud_g->points[neighbors[0]].z; input_buf->setField(Dimension::Id::HeightAboveGround, idx, hag); } // populate BufferReader with the input PointBuffer, which now has the // HeightAboveGround dimension BufferReader bufferReader; bufferReader.addBuffer(input_buf); // we require that the output be BPF for now, to house our non-standard // dimension Options wo; wo.add("filename", m_output_file); std::unique_ptr<Writer> writer(f.createWriter("writers.bpf")); writer->setOptions(wo); writer->setInput(&bufferReader); writer->prepare(input_ctx); writer->execute(input_ctx); return 0; }
TIndexKernel::FileInfo TIndexKernel::getFileInfo(KernelFactory& factory, const std::string& filename) { FileInfo fileInfo; StageFactory f; std::string driverName = f.inferReaderDriver(filename); Stage *s = f.createStage(driverName); Options ops; ops.add("filename", filename); setCommonOptions(ops); s->setOptions(ops); applyExtraStageOptionsRecursive(s); if (m_fastBoundary) { QuickInfo qi = s->preview(); std::stringstream polygon; polygon << "POLYGON (("; polygon << qi.m_bounds.minx << " " << qi.m_bounds.miny; polygon << ", " << qi.m_bounds.maxx << " " << qi.m_bounds.miny; polygon << ", " << qi.m_bounds.maxx << " " << qi.m_bounds.maxy; polygon << ", " << qi.m_bounds.minx << " " << qi.m_bounds.maxy; polygon << ", " << qi.m_bounds.minx << " " << qi.m_bounds.miny; polygon << "))"; fileInfo.m_boundary = polygon.str(); if (!qi.m_srs.empty()) fileInfo.m_srs = qi.m_srs.getWKT(); } else { PointTable table; Stage *hexer = f.createStage("filters.hexbin"); if (! hexer) { std::ostringstream oss; oss << "Unable to create hexer stage to create boundaries. " << "Is PDAL_DRIVER_PATH environment variable set?"; throw pdal_error(oss.str()); } hexer->setInput(*s); hexer->prepare(table); PointViewSet set = hexer->execute(table); MetadataNode m = table.metadata(); m = m.findChild("filters.hexbin:boundary"); fileInfo.m_boundary = m.value(); PointViewPtr v = *set.begin(); if (!v->spatialReference().empty()) fileInfo.m_srs = v->spatialReference().getWKT(); } FileUtils::fileTimes(filename, &fileInfo.m_ctime, &fileInfo.m_mtime); fileInfo.m_filename = filename; return fileInfo; }
void TIndexKernel::mergeFile() { using namespace gdal; std::ostringstream out; if (!openDataset(m_idxFilename)) { std::ostringstream out; out << "Couldn't open index dataset file '" << m_idxFilename << "'."; throw pdal_error(out.str()); } if (!openLayer(m_layerName)) { std::ostringstream out; out << "Couldn't open layer '" << m_layerName << "' in output file '" << m_idxFilename << "'."; throw pdal_error(out.str()); } FieldIndexes indexes = getFields(); SpatialRef outSrs(m_tgtSrsString); if (!outSrs) throw pdal_error("Couldn't interpret target SRS string."); if (!m_wkt.empty()) { Geometry g(m_wkt, outSrs); if (!g) throw pdal_error("Couldn't interpret geometry filter string."); OGR_L_SetSpatialFilter(m_layer, g.get()); } std::vector<FileInfo> files; // Docs are bad here. You need this call even if you haven't read anything // or nothing happens. OGR_L_ResetReading(m_layer); while (true) { OGRFeatureH feature = OGR_L_GetNextFeature(m_layer); if (!feature) break; FileInfo fileInfo; fileInfo.m_filename = OGR_F_GetFieldAsString(feature, indexes.m_filename); fileInfo.m_srs = OGR_F_GetFieldAsString(feature, indexes.m_srs); files.push_back(fileInfo); OGR_F_Destroy(feature); } StageFactory factory; MergeFilter merge; Options cropOptions; if (!m_bounds.empty()) cropOptions.add("bounds", m_bounds); else cropOptions.add("polygon", m_wkt); for (auto f : files) { Stage *premerge = NULL; std::string driver = factory.inferReaderDriver(f.m_filename); Stage *reader = factory.createStage(driver); if (!reader) { out << "Unable to create reader for file '" << f.m_filename << "'."; throw pdal_error(out.str()); } Options readerOptions; readerOptions.add("filename", f.m_filename); reader->setOptions(readerOptions); premerge = reader; if (m_tgtSrsString != f.m_srs) { Stage *repro = factory.createStage("filters.reprojection"); repro->setInput(*reader); Options reproOptions; reproOptions.add("out_srs", m_tgtSrsString); reproOptions.add("in_srs", f.m_srs); repro->setOptions(reproOptions); premerge = repro; } // WKT is set, even if we're using a bounding box for fitering, so // can be used as a test here. if (!m_wkt.empty()) { Stage *crop = factory.createStage("filters.crop"); crop->setOptions(cropOptions); crop->setInput(*premerge); premerge = crop; } merge.setInput(*premerge); } std::string driver = factory.inferWriterDriver(m_filespec); Options factoryOptions = factory.inferWriterOptionsChanges(m_filespec); Stage *writer = factory.createStage(driver); if (!writer) { out << "Unable to create reader for file '" << m_filespec << "'."; throw pdal_error(out.str()); } writer->setInput(merge); applyExtraStageOptionsRecursive(writer); Options writerOptions(factoryOptions); setCommonOptions(writerOptions); writerOptions.add("filename", m_filespec); writerOptions.add("offset_x", "auto"); writerOptions.add("offset_y", "auto"); writerOptions.add("offset_z", "auto"); writer->addConditionalOptions(writerOptions); PointTable table; writer->prepare(table); writer->execute(table); }