Ejemplo n.º 1
0
PointBufferSet Splitter::run(PointBufferPtr buf)
{
    PointBufferSet pbSet;
    if (!buf->size())
        return pbSet;

    CoordCompare compare;
    std::map<Coord, PointBufferPtr, CoordCompare> buffers(compare);

    // Use the location of the first point as the origin.
    double xOrigin = buf->getFieldAs<double>(Dimension::Id::X, 0);
    double yOrigin = buf->getFieldAs<double>(Dimension::Id::Y, 0);

    // Overlay a grid of squares on the points (m_length sides).  Each square
    // corresponds to a new point buffer.  Place the points falling in the
    // each square in the corresponding point buffer.
    for (PointId idx = 0; idx < buf->size(); idx++)
    {
        int xpos = (buf->getFieldAs<double>(Dimension::Id::X, idx) - xOrigin) /
            m_length;
        int ypos = (buf->getFieldAs<double>(Dimension::Id::Y, idx) - yOrigin) /
            m_length;
        Coord loc(xpos, ypos);
        PointBufferPtr& outbuf = buffers[loc];
        if (!outbuf)
            outbuf = buf->makeNew();
        outbuf->appendPoint(*buf, idx);
    }

    // Pull the buffers out of the map and stick them in the standard
    // output set, setting the bounds as we go.
    for (auto bi = buffers.begin(); bi != buffers.end(); ++bi)
        pbSet.insert(bi->second);
    return pbSet;
}
Ejemplo n.º 2
0
BOX3D PointBuffer::calculateBounds(const PointBufferSet& set, bool is3d)
{
    BOX3D out;
    for (auto iter = set.begin(); iter != set.end(); ++iter)
    {
        PointBufferPtr buf = *iter;
        out.grow(buf->calculateBounds(is3d));
    }
    return out;
}
Ejemplo n.º 3
0
TEST(IcebridgeReaderTest, testRead)
{
    StageFactory f;
    ReaderPtr reader(f.createReader("readers.icebridge"));
    EXPECT_TRUE(reader.get());

    Option filename("filename", getFilePath(), "");
    Options options(filename);
    reader->setOptions(options);

    PointContext ctx;
    reader->prepare(ctx);
    PointBufferSet pbSet = reader->execute(ctx);
    EXPECT_EQ(pbSet.size(), 1u);
    PointBufferPtr buf = *pbSet.begin();
    EXPECT_EQ(buf->size(), 2u);

    checkPoint(
            *buf,
            0,
            141437548,     // time
            82.605319,      // latitude
            301.406196,     // longitude
            18.678,         // elevation
            2408,           // xmtSig
            181,            // rcvSig
            49.91,          // azimuth
            -4.376,         // pitch
            0.608,          // roll
            2.9,            // gpsPdop
            20.0,           // pulseWidth
            0.0);           // relTime

    checkPoint(
            *buf,
            1,
            141437548,     // time
            82.605287,      // latitude
            301.404862,     // longitude
            18.688,         // elevation
            2642,           // xmtSig
            173,            // rcvSig
            52.006,         // azimuth
            -4.376,         // pitch
            0.609,          // roll
            2.9,            // gpsPdop
            17.0,           // pulseWidth
            0.0);           // relTime
}
Ejemplo n.º 4
0
PointBufferSet Crop::run(PointBufferPtr buffer)
{
    PointBufferSet pbSet;
    PointBufferPtr output = buffer->makeNew();
    crop(*buffer, *output);
    pbSet.insert(output);
    return pbSet;
}
void LVRMainWindow::exportSelectedModel()
{
    // Get selected point cloud
    QList<QTreeWidgetItem*> items = treeWidget->selectedItems();
    if(items.size() > 0)
    {
        QTreeWidgetItem* item = items.first();
        if(item->type() == LVRPointCloudItemType)
        {
            if(item->parent() && item->parent()->type() == LVRModelItemType)
            {
                QString qFileName = QFileDialog::getSaveFileName(this, tr("Export Point Cloud As..."), "", tr("Point cloud Files(*.ply *.3d)"));

                LVRModelItem* model_item = static_cast<LVRModelItem*>(item->parent());
                LVRPointCloudItem* pc_item = static_cast<LVRPointCloudItem*>(item);
                PointBufferPtr points = pc_item->getPointBuffer();

                // Get transformation matrix
                Pose p = model_item->getPose();
                Matrix4f mat(Vertexf(p.x, p.y, p.z), Vertexf(p.r, p.t, p.p));

                // Allocate target buffer and insert transformed points
                size_t n;
                floatArr transformedPoints(new float[3 * points->getNumPoints()]);
                floatArr pointArray = points->getPointArray(n);
                for(size_t i = 0; i < points->getNumPoints(); i++)
                {
                    Vertexf v(pointArray[3 * i], pointArray[3 * i + 1], pointArray[3 * i + 2]);
                    Vertexf vt = mat * v;

                    transformedPoints[3 * i    ] = vt[0];
                    transformedPoints[3 * i + 1] = vt[1];
                    transformedPoints[3 * i + 2] = vt[2];
                }

                // Save transformed points
                PointBufferPtr trans(new PointBuffer);
                trans->setPointArray(transformedPoints, n);
                ModelPtr model(new Model(trans));
                ModelFactory::saveModel(model, qFileName.toStdString());
            }
        }
    }
}
Ejemplo n.º 6
0
TEST(SortFilterTest, pipeline)
{
    PipelineManager mgr;
    PipelineReader reader(mgr);

    reader.readPipeline(Support::configuredpath("filters/sort.xml"));
    mgr.execute();

    PointBufferSet pbSet = mgr.buffers();

    EXPECT_EQ(pbSet.size(), 1u);
    PointBufferPtr buf = *pbSet.begin();

    for (PointId i = 1; i < buf->size(); ++i)
    {
        double d1 = buf->getFieldAs<double>(Dimension::Id::X, i - 1);
        double d2 = buf->getFieldAs<double>(Dimension::Id::X, i);
        EXPECT_TRUE(d1 <= d2);
    }
}
Ejemplo n.º 7
0
TEST(LasReaderTest, test_sequential)
{
    PointContext ctx;

    Options ops1;
    ops1.add("filename", Support::datapath("las/1.2-with-color.las"));
    ops1.add("count", 103);
    LasReader reader;
    reader.setOptions(ops1);

    reader.prepare(ctx);
    PointBufferSet pbSet = reader.execute(ctx);
    EXPECT_EQ(pbSet.size(), 1u);
    PointBufferPtr buf = *pbSet.begin();
    Support::check_p0_p1_p2(*buf);
    PointBufferPtr buf2 = buf->makeNew();
    buf2->appendPoint(*buf, 100);
    buf2->appendPoint(*buf, 101);
    buf2->appendPoint(*buf, 102);
    Support::check_p100_p101_p102(*buf2);
}
void MultiPointCloud::init(PointBufferPtr buffer)
{
	if(buffer)
	{
		vector<indexPair> pairs = buffer->getSubClouds();
		vector<indexPair>::iterator it;

		int c(1);
		size_t n;
		coord3fArr points = buffer->getIndexedPointArray( n );
		color3bArr colors = buffer->getIndexedPointColorArray( n );

		for(it = pairs.begin(); it != pairs.end(); it ++)
		{
			indexPair p = *it;

			// Create new point cloud from scan
			PointCloud* pc = new PointCloud;
			for(size_t a = p.first; a <= p.second; a++)
			{
				if(colors)
				{
					pc->addPoint(points[a][0], points[a][1], points[a][2], colors[a][0], colors[a][1], colors[a][2]);
				}
				else
				{
					pc->addPoint(points[a][0], points[a][1], points[a][2], 255, 0, 0);
				}
			}
			stringstream ss;

			pc->updateDisplayLists();
			pc->setName(ss.str());
			addCloud(pc);
			c++;
		}
	}
}
Ejemplo n.º 9
0
static void test_a_format(const std::string& file, boost::uint8_t majorVersion, boost::uint8_t minorVersion, int pointFormat,
                          double xref, double yref, double zref, double tref, boost::uint16_t rref,  boost::uint16_t gref,  boost::uint16_t bref)
{
    PointContext ctx;

    Options ops1;
    ops1.add("filename", Support::datapath(file));
    ops1.add("count", 1);
    pdal::drivers::las::Reader reader;
    reader.setOptions(ops1);
    reader.prepare(ctx);

    BOOST_CHECK_EQUAL(reader.header().pointFormat(), pointFormat);
    BOOST_CHECK_EQUAL(reader.header().versionMajor(), majorVersion);
    BOOST_CHECK_EQUAL(reader.header().versionMinor(), minorVersion);

    PointBufferSet pbSet = reader.execute(ctx);
    BOOST_CHECK_EQUAL(pbSet.size(), 1);
    PointBufferPtr buf = *pbSet.begin();
    BOOST_CHECK_EQUAL(buf->size(), 1);

    Support::check_pN(*buf, 0, xref, yref, zref, tref, rref, gref, bref);
}
Ejemplo n.º 10
0
void  DatIO::save(string filename)
{
	PointBufferPtr pointBuffer = m_model->m_pointCloud;
	float buffer[4];
	if(pointBuffer)
	{
		ofstream out(filename.c_str(), std::ios::binary);
		if(out.good())
		{
			size_t numPoints;
			size_t numIntensities;
			floatArr pointArray = pointBuffer->getPointArray(numPoints);
			floatArr intensityArray = pointBuffer->getPointIntensityArray(numIntensities);
			float buffer[4];
			cout << timestamp << "Writing " << numPoints << " to " << filename << endl;
			for(size_t i = 0; i < numPoints; i++)
			{
				memset(buffer, 0, 4 * sizeof(float));
				size_t pos = i * 3;
				buffer[0] = pointArray[pos];
				buffer[1] = pointArray[pos + 1];
				buffer[2] = pointArray[pos + 2];
				if(intensityArray)
				{
					buffer[3] = intensityArray[i];
				}
				out.write((char*)buffer, 4 * sizeof(float));
			}
			out.close();
		}
		else
		{
			cout << timestamp << "DatIO: Unable to open file " << filename << " for writing." << endl;
		}
	}
}
void InteractivePointCloud::updateBuffer(PointBufferPtr buffer)
{
	if(buffer)
	{
		if(!m_boundingBox)
		{
			m_boundingBox = new BoundingBox<Vertex<float> >;
			m_boundingBox->expand(8000, 8000, 8000);
		}

		size_t num_vertices;
		float* vertices = buffer->getPointArray(num_vertices).get();

//		m_boundingBox = new BoundingBox<Vertex<float> >;
//		for (int i = 0; i < int(num_vertices); i++)
//		{
//			int index = 3 * i;
//			m_boundingBox->expand(vertices[index], vertices[index + 1], vertices[index + 2]);
//		}

		glVertexPointer(3, GL_FLOAT, 0, vertices);
		m_buffer = buffer;
	}
}
Ejemplo n.º 12
0
int main(int argc, char** argv)
{

	// Read given file
	ModelPtr model = ModelFactory::readModel(argv[1]);

	std::list<PointVectorPair> points;

	std::cout << timestamp <<  "Creating model.." << std::endl;

	// Get point buffer and convert to
	size_t n;
	floatArr b = model->m_pointCloud->getPointArray(n);
	for(size_t i = 0; i < n; i++)
	{
		points.push_back(PointVectorPair(Point(b[3 * i], b[3 * i + 1], b[3 * i + 2]), Vector(0.0, 0.0, 0.0)));
	}

	std::cout << timestamp << "Estimating normals..." << std::endl;

	// Estimates normals direction.
	// Note: pca_estimate_normals() requires an iterator over points
	// as well as property maps to access each point's position and normal.


	const int nb_neighbors = atoi(argv[2]); // K-nearest neighbors = 3 rings
	CGAL::pca_estimate_normals(points.begin(), points.end(),
			CGAL::First_of_pair_property_map<PointVectorPair>(),
			CGAL::Second_of_pair_property_map<PointVectorPair>(),
			nb_neighbors);

	std::cout << timestamp << "Orientating normals..." << std::endl;

	// Orients normals.
	// Note: mst_orient_normals() requires an iterator over points
	// as well as property maps to access each point's position and normal.
	std::list<PointVectorPair>::iterator unoriented_points_begin =
			CGAL::mst_orient_normals(points.begin(), points.end(),
					CGAL::First_of_pair_property_map<PointVectorPair>(),
					CGAL::Second_of_pair_property_map<PointVectorPair>(),
					nb_neighbors);

	// Optional: delete points with an unoriented normal
	// if you plan to call a reconstruction algorithm that expects oriented normals.
	points.erase(unoriented_points_begin, points.end());

	// Optional: after erase(), use Scott Meyer's "swap trick" to trim excess capacity
	std::list<PointVectorPair>(points).swap(points);

	std::cout << timestamp << "Creating output buffer" << std::endl;

	PointBufferPtr buffer = PointBufferPtr(new PointBuffer);
	std::list<PointVectorPair>::iterator it;
	floatArr pts(new float[3 * points.size()]);
	floatArr normals(new float[3 * points.size()]);
	int c = 0;
	for(it = points.begin(); it != points.end(); it++)
	{
		Point p = it->first;
		Vector n = it->second;
		pts[3 * c    ] = p[0];
		pts[3 * c + 1] = p[1];
		pts[3 * c + 2] = p[2];

		normals[3 * c    ] = n[0];
		normals[3 * c + 1] = n[1];
		normals[3 * c + 2] = n[2];
		//std::cout << p[0] << " " << p[1] << " " << p[2] << std::endl;
		c++;
	}
	//std::cout << c << " & " << points.size() << std::endl;

	std::cout << timestamp << "Creating model" << std::endl;
	buffer->setPointArray(pts, points.size());
	buffer->setPointNormalArray(normals, points.size());

	ModelPtr outModel(new Model(buffer));


	std::cout << timestamp << "Saving result" << std::endl;
	ModelFactory::saveModel(outModel, "normals.ply");

}
Ejemplo n.º 13
0
TEST(NitfReaderTest, test_one)
{
    StageFactory f;

    Options nitf_opts;
    nitf_opts.add("filename", Support::datapath("nitf/autzen-utm10.ntf"));
    nitf_opts.add("count", 750);

    PointContext ctx;

    ReaderPtr nitf_reader(f.createReader("readers.nitf"));
    EXPECT_TRUE(nitf_reader.get());
    nitf_reader->setOptions(nitf_opts);
    nitf_reader->prepare(ctx);
    PointBufferSet pbSet = nitf_reader->execute(ctx);
    EXPECT_EQ(nitf_reader->getDescription(), "NITF Reader");
    EXPECT_EQ(pbSet.size(), 1u);
    PointBufferPtr buf = *pbSet.begin();

    // check metadata
//ABELL
/**
    {
        Metadata metadata = nitf_reader.getMetadata();
        /////////////////////////////////////////////////EXPECT_EQ(metadatums.size(), 80u);
        EXPECT_EQ(metadata.toPTree().get<std::string>("metadata.FH_FDT.value"), "20120323002946");
    }
**/

    //
    // read LAS
    //
    Options las_opts;
    las_opts.add("count", 750);
    las_opts.add("filename", Support::datapath("nitf/autzen-utm10.las"));

    PointContext ctx2;

    ReaderPtr las_reader(f.createReader("readers.las"));
    EXPECT_TRUE(las_reader.get());
    las_reader->setOptions(las_opts);
    las_reader->prepare(ctx2);
    PointBufferSet pbSet2 = las_reader->execute(ctx2);
    EXPECT_EQ(pbSet2.size(), 1u);
    PointBufferPtr buf2 = *pbSet.begin();
    //
    //
    // compare the two buffers
    //
    EXPECT_EQ(buf->size(), buf2->size());

    for (PointId i = 0; i < buf2->size(); i++)
    {
        int32_t nitf_x = buf->getFieldAs<int32_t>(Dimension::Id::X, i);
        int32_t nitf_y = buf->getFieldAs<int32_t>(Dimension::Id::Y, i);
        int32_t nitf_z = buf->getFieldAs<int32_t>(Dimension::Id::Z, i);

        int32_t las_x = buf2->getFieldAs<int32_t>(Dimension::Id::X, i);
        int32_t las_y = buf2->getFieldAs<int32_t>(Dimension::Id::Y, i);
        int32_t las_z = buf2->getFieldAs<int32_t>(Dimension::Id::Z, i);

        EXPECT_EQ(nitf_x, las_x);
        EXPECT_EQ(nitf_y, las_y);
        EXPECT_EQ(nitf_z, las_z);
    }
}
Ejemplo n.º 14
0
int main( int argc, char ** argv )
{

    // Parse command line arguments
    convert::Options options(argc, argv);

    // Exit if options had to generate a usage message
    // (this means required parameters are missing)
    if ( options.printUsage() )
    {
        return 0;
    }

    ::std::cout << options << ::std::endl;

    // Read input file
    ModelPtr model = ModelFactory::readModel(options.getInputFile());

    if(model)
    {

        if(model->m_pointCloud)
        {
            // Get parameters
            bool convert           = options.convertIntensity();
            bool filterIntensity   = options.getMinIntensity() > -1e10 || options.getMaxIntensity() < 1e10;

            // Check if we have to modify some data
            if(convert || filterIntensity)
            {
                PointBufferPtr points = model->m_pointCloud;
                size_t numPoints = points->getNumPoints();
                if(points)
                {
                    size_t n;
                    if(convert && !points->getPointColorArray(n))
                    {
                        cout << timestamp << "Allocating new point color array." << endl;
                        ucharArr colors(new unsigned char[numPoints * 3]);
                        points->setPointColorArray(colors, numPoints);
                    }

                    float max_i = -1e10;
                    float min_i = +1e10;
                    float maxCutOff = options.getMaxIntensity();
                    float minCutOff = options.getMinIntensity();

                    floatArr intensities = points->getPointIntensityArray(n);
                    if(intensities)
                    {
                        // Cutoff intensity values
                        for(size_t i = 0; i < numPoints; i++)
                        {
                            //cout << intensities[i] << endl;
                            if(intensities[i] < minCutOff) intensities[i] = minCutOff;
                            if(intensities[i] > maxCutOff) intensities[i] = maxCutOff;
                            if(intensities[i] < min_i) min_i = intensities[i];
                            if(intensities[i] > max_i) max_i = intensities[i];
                        }

                        // Map intensities to 0 .. 255
                        cout << max_i << " " << min_i << endl;
                        float r_diff = max_i - min_i;
                        if(r_diff > 0)
                        {
                            float b_size = r_diff / 255.0;
                            for(int a = 0; a < numPoints; a++)
                            {
                                //cout << intensities[a] << endl;
                                float value = intensities[a];
                                value -= min_i;
                                value /= b_size;
                                intensities[a] = value;
                                //cout << intensities[a] << endl << endl;
                            }
                        }

                        // Convert
                        if(convert)
                        {
                            ucharArr colors = points->getPointColorArray(n);

                            GradientType gradType = GREY;
                            string gradientName = options.getColorMap();

                            if(gradientName == "HOT")   gradType = HOT;
                            if(gradientName == "HSV")   gradType = HSV;
                            if(gradientName == "SHSV")  gradType = SHSV;
                            if(gradientName == "JET")   gradType = JET;

                            ColorMap colorMap(255);

                            for(size_t i = 0; i < numPoints; i++)
                            {
                                float color[3];

                                colorMap.getColor(color, (size_t)intensities[i], gradType );

                                colors[3 * i    ] = (unsigned char)(color[0] * 255);
                                colors[3 * i + 1] = (unsigned char)(color[1] * 255);
                                colors[3 * i + 2] = (unsigned char)(color[2] * 255);
                                //cout << intensities[i] << endl;
                                //cout << (int) colors[3 * i    ] << " " << (int)colors[3 * i + 1] << " " << (int)colors[3 * i + 2] << endl;

                            }

                            points->setPointColorArray(colors, numPoints);
                        }
                        model->m_pointCloud = points;
                    }
                    else
                    {
                        cout << timestamp << "Model contains no point intensities to convert." << endl;
                    }

                }
            }
        }
        ModelFactory::saveModel(model, options.getOutputFile());

    }
    else
    {
        cout << timestamp << "Error reading file " << options.getInputFile() << endl;
    }
}
Ejemplo n.º 15
0
ModelPtr ModelFactory::readModel( std::string filename )
{
    ModelPtr m;

    // Check extension
    boost::filesystem::path selectedFile( filename );
    std::string extension = selectedFile.extension().string();

    // Try to parse given file
    BaseIO* io = 0;
    if(extension == ".ply")
    {
        io = new PLYIO;
    }
    else if(extension == ".pts" || extension == ".3d" || extension == ".xyz")
    {
        io = new AsciiIO;
    }
    else if (extension == ".obj")
    {
        io = new ObjIO;
    }
    else if (extension == ".las")
    {
        io = new LasIO;
    }
    else if (extension ==".dat")
    {
    	io = new DatIO;
    }
#ifdef LVR_USE_PCL
    else if (extension == ".pcd")
    {
        io = new PCDIO;
    }
#endif /* LVR_USE_PCL */
    else if (extension == "")
    {
        bool found_3d = false;
        bool found_boctree = false;

        // Check for supported data in directory.
        boost::filesystem::directory_iterator lastFile;

        for(boost::filesystem::directory_iterator it(filename); it != lastFile; it++ )
        {
            boost::filesystem::path p = it->path();

            // Check for 3d files
            if(p.extension().string() == ".3d")
            {
                // Check for naming convention "scanxxx.3d"
                int num = 0;
				if(sscanf(p.filename().string().c_str(), "scan%3d", &num))
                {
                    found_3d = true;
                }
            }

            // Check for .oct files
            if(p.extension().string() == ".oct")
            {
                // Check for naming convention "scanxxx.3d"
                int num = 0;
                if(sscanf(p.filename().string().c_str(), "scan%3d", &num))
                {
                    found_boctree = true;
                }
            }


        }

        // Check and create io
        if(!found_boctree && found_3d)
        {
            io = new UosIO;
        }
        else if(found_boctree && found_3d)
        {
            cout << timestamp << "Found 3d files and octrees. Loading octrees per default." << endl;
            io = new BoctreeIO;
        }
        else if(found_boctree && !found_3d)
        {
            io = new BoctreeIO;
        }
        else
        {
            cout << timestamp << "Given directory does not contain " << endl;
        }
    }

    // Return data model
    if( io )
    {
        m = io->read( filename );

        if(m_transform.convert)
        {
        	// Convert coordinates in model
        	PointBufferPtr points = m->m_pointCloud;
        	size_t n_points = 0;
        	size_t n_normals = 0;

        	floatArr p = points->getPointArray(n_points);
        	floatArr n = points->getPointNormalArray(n_normals);

        	// If normals are present every point should habe one
        	if(n_normals)
        	{
        		assert(n_normals == n_points);
        	}

        	// Convert coordinates
        	float point[3];
        	float normal[3];

        	for(size_t i = 0; i < n_points; i++)
        	{
        		// Re-order and scale point coordinates
        		point[0] = p[3 * i + m_transform.x] * m_transform.sx;
        		point[1] = p[3 * i + m_transform.y] * m_transform.sy;
        		point[2] = p[3 * i + m_transform.z] * m_transform.sz;

        		p[3 * i] 		= point[0];
        		p[3 * i + 1]	= point[1];
        		p[3 * i + 2]    = point[2];
        		if(n_normals)
        		{
        			normal[0] = n[3 * i + m_transform.x] * m_transform.sx;
        			normal[1] = n[3 * i + m_transform.y] * m_transform.sy;
        			normal[2] = n[3 * i + m_transform.z] * m_transform.sz;

            		n[3 * i] 		= normal[0];
            		n[3 * i + 1]	= normal[1];
            		n[3 * i + 2]    = normal[2];
        		}
        	}
        }

        delete io;
    }

    return m;

}
Ejemplo n.º 16
0
int Diff::execute()
{
    PointContext sourceCtx;

    Options sourceOptions;
    {
        sourceOptions.add<std::string>("filename", m_sourceFile);
        sourceOptions.add<bool>("debug", isDebug());
        sourceOptions.add<boost::uint32_t>("verbose", getVerboseLevel());
    }
    std::unique_ptr<Stage> source(AppSupport::makeReader(m_sourceFile));
    source->setOptions(sourceOptions);
    source->prepare(sourceCtx);
    PointBufferSet sourceSet = source->execute(sourceCtx);

    ptree errors;

    PointContext candidateCtx;
    Options candidateOptions;
    {
        candidateOptions.add<std::string>("filename", m_candidateFile);
        candidateOptions.add<bool>("debug", isDebug());
        candidateOptions.add<boost::uint32_t>("verbose", getVerboseLevel());
    }

    std::unique_ptr<Stage> candidate(AppSupport::makeReader(m_candidateFile));
    candidate->setOptions(candidateOptions);
    candidate->prepare(candidateCtx);
    PointBufferSet candidateSet = candidate->execute(candidateCtx);

    assert(sourceSet.size() == 1);
    assert(candidateSet.size() == 1);
    PointBufferPtr sourceBuf = *sourceSet.begin();
    PointBufferPtr candidateBuf = *candidateSet.begin();
    if (candidateBuf->size() != sourceBuf->size())
    {
        std::ostringstream oss;

        oss << "Source and candidate files do not have the same point count";
        errors.put("count.error", oss.str());
        errors.put("count.candidate", candidateBuf->size());
        errors.put("count.source", sourceBuf->size());
    }

    MetadataNode source_metadata = sourceCtx.metadata();
    MetadataNode candidate_metadata = candidateCtx.metadata();
    if (source_metadata != candidate_metadata)
    {
        std::ostringstream oss;

        oss << "Source and candidate files do not have the same metadata count";
        errors.put("metadata.error", oss.str());
        errors.put_child("metadata.source", pdal::utils::toPTree(source_metadata));
        errors.put_child("metadata.candidate", pdal::utils::toPTree(candidate_metadata));
    }

    if (candidateCtx.dims().size() != sourceCtx.dims().size())
    {
        std::ostringstream oss;

        oss << "Source and candidate files do not have the same "
            "number of dimensions";
        errors.put<std::string>("schema.error", oss.str());
        //Need to "ptree" the PointContext dimension list in some way
        // errors.put_child("schema.source", sourceCtx.schema()->toPTree());
        // errors.put_child("schema.candidate",
        //     candidateCtx.schema()->toPTree());
    }

    if (errors.size())
    {
        write_json(std::cout, errors);
        return 1;
    }
    else
    {
        // If we made it this far with no errors, now we'll
        // check the points.
        checkPoints(*sourceBuf, *candidateBuf, errors);
        if (errors.size())
        {
            write_json(std::cout, errors);
            return 1;
        }
    }
    return 0;
}