Пример #1
0
void HexBin::filter(PointView& view)
{
    for (PointId idx = 0; idx < view.size(); ++idx)
    {
        double x = view.getFieldAs<double>(pdal::Dimension::Id::X, idx);
        double y = view.getFieldAs<double>(pdal::Dimension::Id::Y, idx);
        m_grid->addPoint(x, y);
    }
    m_count += view.size();
}
Пример #2
0
PDAL_DLL Eigen::MatrixXd pointViewToEigen(const PointView& view)
{
    Eigen::MatrixXd matrix(view.size(), 3);
    for (PointId i = 0; i < view.size(); ++i)
    {
        matrix(i, 0) = view.getFieldAs<double>(Dimension::Id::X, i);
        matrix(i, 1) = view.getFieldAs<double>(Dimension::Id::Y, i);
        matrix(i, 2) = view.getFieldAs<double>(Dimension::Id::Z, i);
    }
    return matrix;
}
Пример #3
0
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);
        }
    }
}
Пример #4
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);
}
Пример #5
0
void ProgrammableFilter::filter(PointView& view)
{
    log()->get(LogLevel::Debug5) << "Python script " << *m_script <<
        " processing " << view.size() << " points." << std::endl;
    m_pythonMethod->resetArguments();
    m_pythonMethod->begin(view, m_totalMetadata);
    m_pythonMethod->execute();
    m_pythonMethod->end(view, getMetadata());
}
Пример #6
0
void ColorizationFilter::filter(PointView& view)
{
    PointRef point = view.point(0);
    for (PointId idx = 0; idx < view.size(); ++idx)
    {
        point.setPointId(idx);
        processOne(point);
    }
}
Пример #7
0
void TransformationFilter::filter(PointView& view)
{
    PointRef point(view, 0);
    for (PointId idx = 0; idx < view.size(); ++idx)
    {
        point.setPointId(idx);
        processOne(point);
    }
}
Пример #8
0
void FerryFilter::filter(PointView& view)
{
    PointRef point(view, 0);
    for (PointId id = 0; id < view.size(); ++id)
    {
        point.setPointId(id);
        processOne(point);
    }
}
Пример #9
0
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));
    }
}
Пример #10
0
Eigen::MatrixXd extendedLocalMinimum(PointView& view, int rows, int cols,
                                     double cell_size, BOX2D bounds)
{
    using namespace Dimension;
    using namespace Eigen;

    // Index elevation values by row and column.
    std::map<uint32_t, std::vector<double>> hash;
    for (PointId i = 0; i < view.size(); ++i)
    {
        double x = view.getFieldAs<double>(Id::X, i);
        double y = view.getFieldAs<double>(Id::Y, i);
        double z = view.getFieldAs<double>(Id::Z, i);

        int c = Utils::clamp(static_cast<int>(floor(x-bounds.minx)/cell_size), 0, cols-1);
        int r = Utils::clamp(static_cast<int>(floor(y-bounds.miny)/cell_size), 0, rows-1);

        hash[r*cols+c].push_back(z);
    }

    // For each grid cell, sort elevations and detect local minimum, rejecting low
    // outliers.
    MatrixXd ZImin(rows, cols);
    ZImin.setConstant(std::numeric_limits<double>::quiet_NaN());
    for (int c = 0; c < cols; ++c)
    {
        for (int r = 0; r < rows; ++r)
        {
            std::vector<double> cp(hash[r*cols+c]);
            if (cp.empty())
                continue;
            std::sort(cp.begin(), cp.end());
            if (cp.size() == 1)
            {
                ZImin(r, c) = cp[0];
                continue;
            }
            for (size_t i = 0; i < cp.size()-1; ++i)
            {
                if (std::fabs(cp[i] - cp[i+1]) < 1.0)
                {
                    ZImin(r, c) = cp[i];
                    break;
                }
            }
        }
    }

    return ZImin;
}
Пример #11
0
void BufferedInvocation::begin(PointView& view, MetadataNode m)
{
    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);
        void *data = malloc(dd->size() * view.size());
        m_buffers.push_back(data);  // Hold pointer for deallocation
        char *p = (char *)data;
        for (PointId idx = 0; idx < view.size(); ++idx)
        {
            view.getFieldInternal(d, idx, (void *)p);
            p += dd->size();
        }
        std::string name = layout->dimName(*di);
        insertArgument(name, (uint8_t *)data, dd->type(), view.size());
    }
    Py_XDECREF(m_metaIn);
    m_metaIn = plang::fromMetadata(m);
}
Пример #12
0
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);
    }
}
Пример #13
0
point_count_t OciReader::readPointMajor(PointView& view,
    BlockPtr block, point_count_t numPts)
{
    size_t numRemaining = block->numRemaining();
    PointId nextId = view.size();
    point_count_t numRead = 0;

    if (m_compression)
    {
#ifdef PDAL_HAVE_LAZPERF
        LazPerfBuf buf(block->chunk);
        LazPerfDecompressor<LazPerfBuf> decompressor(buf, dbDimTypes());

        std::vector<char> ptBuf(decompressor.pointSize());
        while (numRead < numPts && numRemaining > 0)
        {
            point_count_t numWritten =
                decompressor.decompress(ptBuf.data(), ptBuf.size());
            writePoint(view, nextId, ptBuf.data());
            if (m_cb)
                m_cb(view, nextId);
            numRemaining--;
            nextId++;
            numRead++;
        }
#else
        throw pdal_error("Can't decompress without LAZperf.");
#endif
    }
    else
    {
        char *pos = seekPointMajor(block);
        while (numRead < numPts && numRemaining > 0)
        {
            writePoint(view, nextId, pos);

            if (m_cb)
                m_cb(view, nextId);

            pos += packedPointSize();
            numRemaining--;
            nextId++;
            numRead++;
        }
    }
    block->setNumRemaining(numRemaining);
    return numRead;
}
Пример #14
0
point_count_t LasWriter::fillWriteBuf(const PointView& view,
    PointId startId, std::vector<char>& buf)
{
    point_count_t blocksize = buf.size() / m_lasHeader.pointLen();
    blocksize = (std::min)(blocksize, view.size() - startId);
    PointId lastId = startId + blocksize;

    LeInserter ostream(buf.data(), buf.size());
    PointRef point = (const_cast<PointView&>(view)).point(0);
    for (PointId idx = startId; idx < lastId; idx++)
    {
        point.setPointId(idx);
        fillPointBuf(point, ostream);
    }
    return blocksize;
}
Пример #15
0
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);
}
Пример #16
0
point_count_t OciReader::readPointMajor(PointView& view,
    BlockPtr block, point_count_t numPts)
{
    PointId nextId = view.size();
    point_count_t numRead = 0;

    if (m_compression)
    {
#ifdef PDAL_HAVE_LAZPERF
        auto cb = [this, &view, &nextId, &numRead](char *buf, size_t bufsize)
        {
            writePoint(view, nextId, buf);
            if (m_cb)
                m_cb(view, nextId);
            nextId++;
            numRead++;
        };
        const char *src = reinterpret_cast<const char *>(block->chunk.data());
        size_t srcsize = block->chunk.size();
        LazPerfDecompressor(cb, dbDimTypes(), block->numRemaining()).
            decompress(src, srcsize);
#else
        throwError("Can't decompress without LAZperf.");
#endif
    }
    else
    {
        char *pos = seekPointMajor(block);

        size_t cnt = block->numRemaining();
        while (numRead < numPts && cnt--)
        {
            writePoint(view, nextId, pos);

            if (m_cb)
                m_cb(view, nextId);

            pos += packedPointSize();
            nextId++;
            numRead++;
        }
    }
    block->setNumRemaining(block->numRemaining() - numRead);
    return numRead;
}
Пример #17
0
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);
    }
}
Пример #18
0
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);
            }

        }
    }
}
Пример #19
0
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;
        }
    }
}
Пример #20
0
void DiffKernel::checkPoints(const PointView& source_data,
                             const PointView& candidate_data, MetadataNode errors)
{
    uint32_t MAX_BADBYTES(20);
    uint32_t badbytes(0);

    // Both schemas have already been determined to be equal, so are the
    // same size and in the same order.
    Dimension::IdList const& sourceDims = source_data.dims();
    Dimension::IdList const& candidateDims = candidate_data.dims();

    char sbuf[8];
    char cbuf[8];
    for (PointId idx = 0; idx < source_data.size(); ++idx)
    {
        for (size_t d = 0; d < sourceDims.size(); ++d)
        {
            Dimension::Id sd = sourceDims[d];
            Dimension::Id cd = candidateDims[d];

            source_data.getRawField(sd, idx, (void *)sbuf);
            candidate_data.getRawField(cd, idx, (void *)cbuf);
            Dimension::Type t = Dimension::defaultType(cd);
            size_t size = Dimension::size(t);
            if (memcmp(sbuf, cbuf, size))
            {
                std::ostringstream oss;

                oss << "Point " << idx << " differs for dimension \"" <<
                    Dimension::name(sd) << "\" for source and candidate";
                errors.add("data.error", oss.str());
                badbytes++;
            }
        }
        if (badbytes > MAX_BADBYTES )
            break;
    }
}
Пример #21
0
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);
}
Пример #22
0
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;
}
Пример #23
0
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]));
    }
}
Пример #24
0
Eigen::MatrixXd createDSM(PointView& view, int rows, int cols, double cell_size,
                          BOX2D bounds)
{
    using namespace Dimension;
    using namespace Eigen;

    MatrixXd ZImin(rows, cols);
    ZImin.setConstant(std::numeric_limits<double>::quiet_NaN());

    for (PointId i = 0; i < view.size(); ++i)
    {
        double x = view.getFieldAs<double>(Id::X, i);
        double y = view.getFieldAs<double>(Id::Y, i);
        double z = view.getFieldAs<double>(Id::Z, i);

        int c = Utils::clamp(static_cast<int>(floor(x-bounds.minx)/cell_size), 0, cols-1);
        int r = Utils::clamp(static_cast<int>(floor(y-bounds.miny)/cell_size), 0, rows-1);

        if (z < ZImin(r, c) || std::isnan(ZImin(r, c)))
            ZImin(r, c) = z;
    }

    return ZImin;
}
Пример #25
0
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);
    }
}
Пример #26
0
void DecimationFilter::decimate(PointView& input, PointView& output)
{
    PointId last_idx = std::min(m_limit, input.size());
    for (PointId idx = m_offset; idx < last_idx; idx += m_step)
        output.appendPoint(input, idx);
}
Пример #27
0
std::vector<std::vector<PointId>> extractClusters(PointView& view,
                                                  uint64_t min_points,
                                                  uint64_t max_points,
                                                  double tolerance)
{
    // Index the incoming PointView for subsequent radius searches.
    KD3Index kdi(view);
    kdi.build();

    // Create variables to track PointIds that have already been added to
    // clusters and to build the list of cluster indices.
    std::vector<PointId> processed(view.size(), 0);
    std::vector<std::vector<PointId>> clusters;

    for (PointId i = 0; i < view.size(); ++i)
    {
        // Points can only belong to a single cluster.
        if (processed[i])
            continue;

        // Initialize list of indices belonging to current cluster, marking the
        // seed point as processed.
        std::vector<PointId> seed_queue;
        size_t sq_idx = 0;
        seed_queue.push_back(i);
        processed[i] = 1;

        // Check each point in the cluster for additional neighbors within the
        // given tolerance, remembering that the list can grow if we add points
        // to the cluster.
        while (sq_idx < seed_queue.size())
        {
            // Find neighbors of the next cluster point.
            PointId j = seed_queue[sq_idx];
            std::vector<PointId> ids = kdi.radius(j, tolerance);

            // The case where the only neighbor is the query point.
            if (ids.size() == 1)
            {
                sq_idx++;
                continue;
            }

            // Skip neighbors that already belong to a cluster and add the rest
            // to this cluster.
            for (auto const& k : ids)
            {
                if (processed[k])
                    continue;
                seed_queue.push_back(k);
                processed[k] = 1;
            }

            sq_idx++;
        }

        // Keep clusters that are within the min/max number of points.
        if (seed_queue.size() >= min_points && seed_queue.size() <= max_points)
            clusters.push_back(seed_queue);
    }

    return clusters;
}
Пример #28
0
point_count_t LasWriter::fillWriteBuf(const PointView& view,
    PointId startId, std::vector<char>& buf)
{
    point_count_t blocksize = buf.size() / m_lasHeader.pointLen();
    blocksize = std::min(blocksize, view.size() - startId);

    bool hasColor = m_lasHeader.hasColor();
    bool hasTime = m_lasHeader.hasTime();
    PointId lastId = startId + blocksize;
    static const size_t maxReturnCount = m_lasHeader.maxReturnCount();
    LeInserter ostream(buf.data(), buf.size());
    for (PointId idx = startId; idx < lastId; idx++)
    {
        // we always write the base fields
        using namespace Dimension;

        uint8_t returnNumber(1);
        uint8_t numberOfReturns(1);
        if (view.hasDim(Id::ReturnNumber))
        {
            returnNumber = view.getFieldAs<uint8_t>(Id::ReturnNumber,
                idx);
            if (returnNumber < 1 || returnNumber > maxReturnCount)
                m_error.returnNumWarning(returnNumber);
        }
        if (view.hasDim(Id::NumberOfReturns))
            numberOfReturns = view.getFieldAs<uint8_t>(
                Id::NumberOfReturns, idx);
        if (numberOfReturns == 0)
            m_error.numReturnsWarning(0);
        if (numberOfReturns > maxReturnCount)
        {
            if (m_discardHighReturnNumbers)
            {
                // If this return number is too high, pitch the point.
                if (returnNumber > maxReturnCount)
                    continue;
                numberOfReturns = maxReturnCount;
            }
            else
                m_error.numReturnsWarning(numberOfReturns);
        }

        double xOrig = view.getFieldAs<double>(Id::X, idx);
        double yOrig = view.getFieldAs<double>(Id::Y, idx);
        double zOrig = view.getFieldAs<double>(Id::Z, idx);

        double x = (xOrig - m_xXform.m_offset) / m_xXform.m_scale;
        double y = (yOrig - m_yXform.m_offset) / m_yXform.m_scale;
        double z = (zOrig - m_zXform.m_offset) / m_zXform.m_scale;

        ostream << boost::numeric_cast<int32_t>(lround(x));
        ostream << boost::numeric_cast<int32_t>(lround(y));
        ostream << boost::numeric_cast<int32_t>(lround(z));

        uint16_t intensity = 0;
        if (view.hasDim(Id::Intensity))
            intensity = view.getFieldAs<uint16_t>(Id::Intensity, idx);
        ostream << intensity;

        uint8_t scanDirectionFlag(0);
        if (view.hasDim(Id::ScanDirectionFlag))
            scanDirectionFlag = view.getFieldAs<uint8_t>(
                Id::ScanDirectionFlag, idx);

        uint8_t edgeOfFlightLine(0);
        if (view.hasDim(Id::EdgeOfFlightLine))
            edgeOfFlightLine = view.getFieldAs<uint8_t>(
                Id::EdgeOfFlightLine, idx);

        uint8_t bits = returnNumber | (numberOfReturns<<3) |
            (scanDirectionFlag << 6) | (edgeOfFlightLine << 7);
        ostream << bits;

        uint8_t classification = 0;
        if (view.hasDim(Id::Classification))
            classification = view.getFieldAs<uint8_t>(Id::Classification,
                idx);
        ostream << classification;

        int8_t scanAngleRank = 0;
        if (view.hasDim(Id::ScanAngleRank))
            scanAngleRank = view.getFieldAs<int8_t>(Id::ScanAngleRank,
                idx);
        ostream << scanAngleRank;

        uint8_t userData = 0;
        if (view.hasDim(Id::UserData))
            userData = view.getFieldAs<uint8_t>(Id::UserData, idx);
        ostream << userData;

        uint16_t pointSourceId = 0;
        if (view.hasDim(Id::PointSourceId))
            pointSourceId = view.getFieldAs<uint16_t>(Id::PointSourceId,
                idx);
        ostream << pointSourceId;

        if (hasTime)
        {
            double t = 0.0;
            if (view.hasDim(Id::GpsTime))
                t = view.getFieldAs<double>(Id::GpsTime, idx);
            ostream << t;
        }

        if (hasColor)
        {
            uint16_t red = 0;
            uint16_t green = 0;
            uint16_t blue = 0;
            if (view.hasDim(Id::Red))
                red = view.getFieldAs<uint16_t>(Id::Red, idx);
            if (view.hasDim(Id::Green))
                green = view.getFieldAs<uint16_t>(Id::Green, idx);
            if (view.hasDim(Id::Blue))
                blue = view.getFieldAs<uint16_t>(Id::Blue, idx);

            ostream << red << green << blue;
        }

        Everything e;
        for (auto& dim : m_extraDims)
        {
            view.getField((char *)&e, dim.m_dimType.m_id,
                dim.m_dimType.m_type, idx);
            ostream.put(dim.m_dimType.m_type, e);
        }

        using namespace Dimension;
        m_summaryData.addPoint(xOrig, yOrig, zOrig, returnNumber);
    }
    return blocksize;
}