/// Write a point's packed data into a buffer. /// \param[in] view PointView to write to. /// \param[in] idx Index of point to write. /// \param[in] buf Pointer to packed DB point data. void DbReader::writePoint(PointView& view, PointId idx, const char *buf) { using namespace Dimension; for (auto di = m_dims.begin(); di != m_dims.end(); ++di) { DimType dimType = di->m_dimType; // If we read X, Y or Z as a signed 32, apply the transform and write // the transformed value (double). if (dimType.m_type == Type::Signed32 && (dimType.m_id == Id::X || dimType.m_id == Id::Y || dimType.m_id == Id::Z)) { int32_t i; memcpy(&i, buf, sizeof(int32_t)); double d = (i * dimType.m_xform.m_scale) + dimType.m_xform.m_offset; view.setField(dimType.m_id, idx, d); } else { view.setField(dimType.m_id, dimType.m_type, idx, buf); } buf += Dimension::size(dimType.m_type); } }
void ReprojectionFilter::filter(PointView& view) { for (PointId id = 0; id < view.size(); ++id) { double x = view.getFieldAs<double>(Dimension::Id::X, id); double y = view.getFieldAs<double>(Dimension::Id::Y, id); double z = view.getFieldAs<double>(Dimension::Id::Z, id); transform(x, y, z); view.setField(Dimension::Id::X, id, x); view.setField(Dimension::Id::Y, id, y); view.setField(Dimension::Id::Z, id, z); } }
void ColorizationFilter::filter(PointView& view) { int32_t pixel(0); int32_t line(0); std::array<double, 2> pix = { {0.0, 0.0} }; for (PointId idx = 0; idx < view.size(); ++idx) { double x = view.getFieldAs<double>(Dimension::Id::X, idx); double y = view.getFieldAs<double>(Dimension::Id::Y, idx); if (!getPixelAndLinePosition(x, y, m_inverse_transform, pixel, line, m_ds)) continue; for (auto bi = m_bands.begin(); bi != m_bands.end(); ++bi) { BandInfo& b = *bi; GDALRasterBandH hBand = GDALGetRasterBand(m_ds, b.m_band); if (hBand == NULL) { std::ostringstream oss; oss << "Unable to get band " << b.m_band << " from data source!"; throw pdal_error(oss.str()); } if (GDALRasterIO(hBand, GF_Read, pixel, line, 1, 1, &pix[0], 1, 1, GDT_CFloat64, 0, 0) == CE_None) view.setField(b.m_dim, idx, pix[0] * b.m_scale); } } }
void HAGFilter::filter(PointView& view) { PointViewPtr gView = view.makeNew(); PointViewPtr ngView = view.makeNew(); std::vector<PointId> gIdx, ngIdx; // First pass: Separate into ground and non-ground views. for (PointId i = 0; i < view.size(); ++i) { double c = view.getFieldAs<double>(Dimension::Id::Classification, i); if (c == 2) { gView->appendPoint(view, i); gIdx.push_back(i); } else { ngView->appendPoint(view, i); ngIdx.push_back(i); } } // Bail if there weren't any points classified as ground. if (gView->size() == 0) throwError("Input PointView does not have any points classified " "as ground"); // Build the 2D KD-tree. KD2Index kdi(*gView); kdi.build(); // Second pass: Find Z difference between non-ground points and the nearest // neighbor (2D) in the ground view. for (PointId i = 0; i < ngView->size(); ++i) { PointRef point = ngView->point(i); double z0 = point.getFieldAs<double>(Dimension::Id::Z); auto ids = kdi.neighbors(point, 1); double z1 = gView->getFieldAs<double>(Dimension::Id::Z, ids[0]); view.setField(Dimension::Id::HeightAboveGround, ngIdx[i], z0 - z1); } // Final pass: Ensure that all ground points have height value pegged at 0. for (auto const& i : gIdx) view.setField(Dimension::Id::HeightAboveGround, i, 0.0); }
void AttributeFilter::filter(PointView& view) { if (m_value == m_value) for (PointId i = 0; i < view.size(); ++i) view.setField(m_dim, i, m_value); else UpdateGEOSBuffer(view); }
void DbReader::writeField(PointView& view, const char *pos, const DimType& dim, PointId idx) { using namespace Dimension; if (dim.m_id == Id::X || dim.m_id == Id::Y || dim.m_id == Id::Z) { Everything e; memcpy(&e, pos, Dimension::size(dim.m_type)); double d = Utils::toDouble(e, dim.m_type); d = (d * dim.m_xform.m_scale.m_val) + dim.m_xform.m_offset.m_val; view.setField(dim.m_id, idx, d); } else view.setField(dim.m_id, dim.m_type, idx, pos); }
void NormalFilter::filter(PointView& view) { KD3Index& kdi = view.build3dIndex(); for (PointId i = 0; i < view.size(); ++i) { // find the k-nearest neighbors auto ids = kdi.neighbors(i, m_knn); // compute covariance of the neighborhood auto B = eigen::computeCovariance(view, ids); // perform the eigen decomposition Eigen::SelfAdjointEigenSolver<Eigen::Matrix3f> solver(B); if (solver.info() != Eigen::Success) throwError("Cannot perform eigen decomposition."); auto eval = solver.eigenvalues(); Eigen::Vector3f normal = solver.eigenvectors().col(0); if (m_viewpointArg->set()) { PointRef p = view.point(i); Eigen::Vector3f vp( m_viewpoint.x - p.getFieldAs<double>(Dimension::Id::X), m_viewpoint.y - p.getFieldAs<double>(Dimension::Id::Y), m_viewpoint.z - p.getFieldAs<double>(Dimension::Id::Z)); if (vp.dot(normal) < 0) normal *= -1.0; } else if (m_up) { if (normal[2] < 0) normal *= -1.0; } view.setField(Dimension::Id::NormalX, i, normal[0]); view.setField(Dimension::Id::NormalY, i, normal[1]); view.setField(Dimension::Id::NormalZ, i, normal[2]); double sum = eval[0] + eval[1] + eval[2]; view.setField(Dimension::Id::Curvature, i, sum ? std::fabs(eval[0] / sum) : 0); } }
void DbReader::writeField(PointView& view, const char *pos, const DimType& dim, PointId idx) { using namespace Dimension; if (dim.m_type == Type::Signed32 && (dim.m_id == Id::X || dim.m_id == Id::Y || dim.m_id == Id::Z)) { int32_t i; memcpy(&i, pos, sizeof(int32_t)); double d = (i * dim.m_xform.m_scale) + dim.m_xform.m_offset; view.setField(dim.m_id, idx, d); } else { view.setField(dim.m_id, dim.m_type, idx, pos); } }
void EstimateRankFilter::filter(PointView& view) { KD3Index& kdi = view.build3dIndex(); for (PointId i = 0; i < view.size(); ++i) { // find the k-nearest neighbors auto ids = kdi.neighbors(i, m_knn); view.setField(m_rank, i, eigen::computeRank(view, ids, m_thresh)); } }
void AttributeFilter::filter(PointView& view) { for (auto& dim_par : m_dimensions) { if (dim_par.second.isogr) { UpdateGEOSBuffer(view, dim_par.second); } else { for (PointId i = 0; i < view.size(); ++i) { double v = boost::lexical_cast<double>(dim_par.second.value); view.setField(dim_par.second.dim, i, v); } } } }
void ColorizationFilter::filter(PointView& view) { std::vector<double> data; for (PointId idx = 0; idx < view.size(); ++idx) { double x = view.getFieldAs<double>(Dimension::Id::X, idx); double y = view.getFieldAs<double>(Dimension::Id::Y, idx); if (!m_raster->read(x, y, data)) continue; int i(0); for (auto bi = m_bands.begin(); bi != m_bands.end(); ++bi) { BandInfo& b = *bi; view.setField(b.m_dim, idx, data[i] * b.m_scale); ++i; } } }
void BufferedInvocation::end(PointView& view, MetadataNode m) { // for each entry in the script's outs dictionary, // look up that entry's name in the schema and then // copy the data into the right dimension spot in the // buffer std::vector<std::string> names; getOutputNames(names); PointLayoutPtr layout(view.m_pointTable.layout()); Dimension::IdList const& dims = layout->dims(); for (auto di = dims.begin(); di != dims.end(); ++di) { Dimension::Id::Enum d = *di; const Dimension::Detail *dd = layout->dimDetail(d); std::string name = layout->dimName(*di); auto found = std::find(names.begin(), names.end(), name); if (found == names.end()) continue; // didn't have this dim in the names assert(name == *found); assert(hasOutputVariable(name)); size_t size = dd->size(); void *data = extractResult(name, dd->type()); char *p = (char *)data; for (PointId idx = 0; idx < view.size(); ++idx) { view.setField(d, dd->type(), idx, (void *)p); p += size; } } for (auto bi = m_buffers.begin(); bi != m_buffers.end(); ++bi) free(*bi); m_buffers.clear(); addMetadata(m_metaOut, m); }
point_count_t OciReader::readDimMajor(PointView& view, BlockPtr block, point_count_t numPts) { using namespace Dimension; point_count_t numRemaining = block->numRemaining(); PointId startId = view.size(); point_count_t blockRemaining = numRemaining; point_count_t numRead = 0; DimTypeList dims = dbDimTypes(); for (auto di = dims.begin(); di != dims.end(); ++di) { PointId nextId = startId; char *pos = seekDimMajor(*di, block); blockRemaining = numRemaining; numRead = 0; while (numRead < numPts && blockRemaining > 0) { writeField(view, pos, *di, nextId); pos += Dimension::size(di->m_type); if (di->m_id == Id::PointSourceId && m_updatePointSourceId) view.setField(Id::PointSourceId, nextId, block->obj_id); if (m_cb && di == dims.rbegin().base() - 1) m_cb(view, nextId); nextId++; numRead++; blockRemaining--; } } block->setNumRemaining(blockRemaining); return numRead; }
void KDistanceFilter::filter(PointView& view) { using namespace Dimension; // Build the 3D KD-tree. log()->get(LogLevel::Debug) << "Building 3D KD-tree...\n"; KD3Index index(view); index.build(); // Increment the minimum number of points, as knnSearch will be returning // the neighbors along with the query point. m_k++; // Compute the k-distance for each point. The k-distance is the Euclidean // distance to k-th nearest neighbor. log()->get(LogLevel::Debug) << "Computing k-distances...\n"; for (PointId i = 0; i < view.size(); ++i) { std::vector<PointId> indices(m_k); std::vector<double> sqr_dists(m_k); index.knnSearch(i, m_k, &indices, &sqr_dists); view.setField(m_kdist, i, std::sqrt(sqr_dists[m_k-1])); } }
void LOFFilter::filter(PointView& view) { using namespace Dimension; KD3Index& index = view.build3dIndex(); // Increment the minimum number of points, as knnSearch will be returning // the neighbors along with the query point. m_minpts++; // First pass: Compute the k-distance for each point. // The k-distance is the Euclidean distance to k-th nearest neighbor. log()->get(LogLevel::Debug) << "Computing k-distances...\n"; for (PointId i = 0; i < view.size(); ++i) { std::vector<PointId> indices(m_minpts); std::vector<double> sqr_dists(m_minpts); index.knnSearch(i, m_minpts, &indices, &sqr_dists); view.setField(m_kdist, i, std::sqrt(sqr_dists[m_minpts-1])); } // Second pass: Compute the local reachability distance for each point. // For each neighbor point, the reachability distance is the maximum value // of that neighbor's k-distance and the distance between the neighbor and // the current point. The lrd is the inverse of the mean of the reachability // distances. log()->get(LogLevel::Debug) << "Computing lrd...\n"; for (PointId i = 0; i < view.size(); ++i) { std::vector<PointId> indices(m_minpts); std::vector<double> sqr_dists(m_minpts); index.knnSearch(i, m_minpts, &indices, &sqr_dists); double M1 = 0.0; point_count_t n = 0; for (PointId j = 0; j < indices.size(); ++j) { double k = view.getFieldAs<double>(m_kdist, indices[j]); double reachdist = (std::max)(k, std::sqrt(sqr_dists[j])); M1 += (reachdist - M1) / ++n; } view.setField(m_lrd, i, 1.0 / M1); } // Third pass: Compute the local outlier factor for each point. // The LOF is the average of the lrd's for a neighborhood of points. log()->get(LogLevel::Debug) << "Computing LOF...\n"; for (PointId i = 0; i < view.size(); ++i) { double lrdp = view.getFieldAs<double>(m_lrd, i); std::vector<PointId> indices(m_minpts); std::vector<double> sqr_dists(m_minpts); index.knnSearch(i, m_minpts, &indices, &sqr_dists); double M1 = 0.0; point_count_t n = 0; for (auto const& j : indices) { M1 += (view.getFieldAs<double>(m_lrd, j) / lrdp - M1) / ++n; } view.setField(m_lof, i, M1); } }
void AttributeFilter::UpdateGEOSBuffer(PointView& view, AttributeInfo& info) { QuadIndex idx(view); if (!info.lyr) // wake up the layer { if (info.layer.size()) info.lyr = OGR_DS_GetLayerByName(info.ds.get(), info.layer.c_str()); else if (info.query.size()) { info.lyr = OGR_DS_ExecuteSQL(info.ds.get(), info.query.c_str(), 0, 0); } else info.lyr = OGR_DS_GetLayer(info.ds.get(), 0); if (!info.lyr) { std::ostringstream oss; oss << "Unable to select layer '" << info.layer << "'"; throw pdal_error(oss.str()); } } OGRFeaturePtr feature = OGRFeaturePtr(OGR_L_GetNextFeature(info.lyr), OGRFeatureDeleter()); int field_index(1); // default to first column if nothing was set if (info.column.size()) { field_index = OGR_F_GetFieldIndex(feature.get(), info.column.c_str()); if (field_index == -1) { std::ostringstream oss; oss << "No column name '" << info.column << "' was found."; throw pdal_error(oss.str()); } } while(feature) { OGRGeometryH geom = OGR_F_GetGeometryRef(feature.get()); OGRwkbGeometryType t = OGR_G_GetGeometryType(geom); if (!(t == wkbPolygon || t == wkbMultiPolygon || t == wkbPolygon25D || t == wkbMultiPolygon25D)) { std::ostringstream oss; oss << "Geometry is not Polygon or MultiPolygon!"; throw pdal::pdal_error(oss.str()); } OGRGeometry* ogr_g = (OGRGeometry*) geom; GEOSGeometry* geos_g (0); if (!m_geosEnvironment) { #if (GDAL_VERSION_MINOR < 11) && (GDAL_VERSION_MAJOR == 1) geos_g = ogr_g->exportToGEOS(); #else m_geosEnvironment = ogr_g->createGEOSContext(); geos_g = ogr_g->exportToGEOS(m_geosEnvironment); #endif } GEOSPreparedGeometry const* geos_pg = GEOSPrepare_r(m_geosEnvironment, geos_g); if (!geos_pg) throw pdal_error("unable to prepare geometry for index-accelerated intersection"); // Compute a total bounds for the geometry. Query the QuadTree to // find out the points that are inside the bbox. Then test each // point in the bbox against the prepared geometry. BOX3D box = computeBounds(m_geosEnvironment, geos_g); std::vector<PointId> ids = idx.getPoints(box); for (const auto& i : ids) { double x = view.getFieldAs<double>(Dimension::Id::X, i); double y = view.getFieldAs<double>(Dimension::Id::Y, i); double z = view.getFieldAs<double>(Dimension::Id::Z, i); GEOSGeometry* p = createGEOSPoint(m_geosEnvironment, x, y ,z); if (static_cast<bool>(GEOSPreparedContains_r(m_geosEnvironment, geos_pg, p))) { // We're in the poly, write the attribute value int32_t v = OGR_F_GetFieldAsInteger(feature.get(), field_index); view.setField(info.dim, i, v); // log()->get(LogLevel::Debug) << "Setting value: " << v << std::endl; } GEOSGeom_destroy_r(m_geosEnvironment, p); } feature = OGRFeaturePtr(OGR_L_GetNextFeature(info.lyr), OGRFeatureDeleter()); } }
void AttributeFilter::UpdateGEOSBuffer(PointView& view) { QuadIndex idx(view); if (m_layer.size()) m_lyr = OGR_DS_GetLayerByName(m_ds.get(), m_layer.c_str()); else if (m_query.size()) m_lyr = OGR_DS_ExecuteSQL(m_ds.get(), m_query.c_str(), 0, 0); else m_lyr = OGR_DS_GetLayer(m_ds.get(), 0); if (!m_lyr) { std::ostringstream oss; oss << getName() << ": Unable to select layer '" << m_layer << "'"; throw pdal_error(oss.str()); } OGRFeaturePtr feature = OGRFeaturePtr(OGR_L_GetNextFeature(m_lyr), OGRFeatureDeleter()); int field_index(1); // default to first column if nothing was set if (m_column.size()) { field_index = OGR_F_GetFieldIndex(feature.get(), m_column.c_str()); if (field_index == -1) { std::ostringstream oss; oss << getName() << ": No column name '" << m_column << "' was found."; throw pdal_error(oss.str()); } } while (feature) { OGRGeometryH geom = OGR_F_GetGeometryRef(feature.get()); OGRwkbGeometryType t = OGR_G_GetGeometryType(geom); int32_t fieldVal = OGR_F_GetFieldAsInteger(feature.get(), field_index); if (!(t == wkbPolygon || t == wkbMultiPolygon || t == wkbPolygon25D || t == wkbMultiPolygon25D)) { std::ostringstream oss; oss << getName() << ": Geometry is not Polygon or MultiPolygon!"; throw pdal::pdal_error(oss.str()); } pdal::Polygon p(geom, view.spatialReference(), GlobalEnvironment::get().geos()); // Compute a total bounds for the geometry. Query the QuadTree to // find out the points that are inside the bbox. Then test each // point in the bbox against the prepared geometry. BOX3D box = p.bounds(); std::vector<PointId> ids = idx.getPoints(box); for (const auto& i : ids) { PointRef ref(view, i); if (p.covers(ref)) view.setField(m_dim, i, fieldVal); } feature = OGRFeaturePtr(OGR_L_GetNextFeature(m_lyr), OGRFeatureDeleter()); } }