Skip to content
Commits on Source (6)
Changes
================================================================================
2.0.0
--------------------------------------------------------------------------------
* PDAL Python extension is now in its own repository on its own release
schedule at https://github.com/PDAL/python
* Extension now builds and works under PDAL OSGeo4W64 on Windows.
Metadata-Version: 1.1
Metadata-Version: 1.2
Name: PDAL
Version: 2.0.0
Version: 2.1.0rc1
Summary: Point cloud data processing
Home-page: http://pdal.io
Author: Howard Butler
Author-email: howard@hobu.co
Maintainer: Howard Butler
Maintainer-email: howard@hobu.co
License: BSD
Description-Content-Type: UNKNOWN
Description: ================================================================================
PDAL
================================================================================
......@@ -44,7 +45,7 @@ Description: ===================================================================
import pdal
pipeline = pdal.Pipeline(json)
pipeline.validate() # check if our JSON and options were good
pipeline.loglevel = 9 #really noisy
pipeline.loglevel = 8 #really noisy
count = pipeline.execute()
arrays = pipeline.arrays
metadata = pipeline.metadata
......@@ -55,17 +56,32 @@ Description: ===================================================================
.. _`schema`: http://www.pdal.io/dimensions.html
.. _`metadata`: http://www.pdal.io/development/metadata.html
.. image:: https://travis-ci.org/PDAL/python.svg?branch=master
:target: https://travis-ci.org/PDAL/python
Requirements
================================================================================
* PDAL 1.7+
* Python >=2.7 (including Python 3.x)
* Cython (eg :code:`pip install cython`)
* Packaging (eg :code:`pip install packaging`)
Changes
================================================================================
2.0.0
--------------------------------------------------------------------------------
* PDAL Python extension is now in its own repository on its own release
schedule at https://github.com/PDAL/python
* Extension now builds and works under PDAL OSGeo4W64 on Windows.
Keywords: point cloud spatial
Platform: UNKNOWN
......@@ -78,3 +94,4 @@ Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Scientific/Engineering :: GIS
Requires: Python (>=2.7)
Requires: Numpy
......@@ -35,7 +35,7 @@ sorts it by the ``X`` dimension:
import pdal
pipeline = pdal.Pipeline(json)
pipeline.validate() # check if our JSON and options were good
pipeline.loglevel = 9 #really noisy
pipeline.loglevel = 8 #really noisy
count = pipeline.execute()
arrays = pipeline.arrays
metadata = pipeline.metadata
......@@ -46,9 +46,15 @@ sorts it by the ``X`` dimension:
.. _`schema`: http://www.pdal.io/dimensions.html
.. _`metadata`: http://www.pdal.io/development/metadata.html
.. image:: https://travis-ci.org/PDAL/python.svg?branch=master
:target: https://travis-ci.org/PDAL/python
Requirements
================================================================================
* PDAL 1.7+
* Python >=2.7 (including Python 3.x)
* Cython (eg :code:`pip install cython`)
* Packaging (eg :code:`pip install packaging`)
2.0.0
\ No newline at end of file
2.1.0rc1
\ No newline at end of file
python-pdal (2.0.0+ds-3) UNRELEASED; urgency=medium
python-pdal (2.1.0~rc1+ds-1) UNRELEASED; urgency=medium
* New upstream release candidate.
* Bump Standards-Version to 4.2.1, no changes.
* Drop autopkgtests to test installability & module import.
* Add lintian override for testsuite-autopkgtest-missing.
* Update copyright years for Howard Butler.
* Remove package name from lintian overrides.
* Require at least libpdal-dev 1.8~ and its python plugin.
-- Bas Couwenberg <sebastic@debian.org> Thu, 05 Jul 2018 11:09:02 +0200
-- Bas Couwenberg <sebastic@debian.org> Wed, 31 Oct 2018 17:52:12 +0100
python-pdal (2.0.0+ds-2) unstable; urgency=medium
......
......@@ -6,7 +6,8 @@ Uploaders: Bas Couwenberg <sebastic@debian.org>
Build-Depends: debhelper (>= 9),
dh-python,
cython,
libpdal-dev (>= 1.7.0),
libpdal-dev (>= 1.8~),
libpdal-plugin-python (>= 1.8~),
python-all-dev,
python-numpy,
python-packaging,
......
......@@ -8,7 +8,7 @@ Files-Excluded: PDAL.egg-info/*
Files: *
Copyright: 2015, Hobu, Inc. <howard@hobu.co>
2016, Howard Butler <howard@hobu.co>
2016, 2018, Howard Butler <howard@hobu.co>
2011, Michael P. Gerlek <mpg@flaxen.com>
License: BSD-3-Clause
......
# False positive, part of NormalX, NormalY, NormalZ
python-pdal: spelling-error-in-binary * NormalY Normally
spelling-error-in-binary * NormalY Normally
......@@ -66,8 +66,23 @@ class PDAL_DLL Array
{
public:
Array() : m_py_array(0)
{}
Array() : m_py_array(0), m_own_array(true)
{
#undef NUMPY_IMPORT_ARRAY_RETVAL
#define NUMPY_IMPORT_ARRAY_RETVAL
import_array();
}
Array(PyObject* array) : m_py_array(array), m_own_array(false)
{
#undef NUMPY_IMPORT_ARRAY_RETVAL
#define NUMPY_IMPORT_ARRAY_RETVAL
import_array();
if (!PyArray_Check(array))
throw pdal::pdal_error("pdal::python::Array constructor object is not a numpy array");
Py_XINCREF(array);
}
~Array()
{
......@@ -85,13 +100,13 @@ public:
npy_intp* ndims = &mydims;
std::vector<npy_intp> strides(dims.size());
DataPtr pdata( new std::vector<uint8_t>(view->pointSize()* view->size(), 0));
PyArray_Descr *dtype(0);
PyArray_Descr *dtype = nullptr;
PyObject * dtype_dict = (PyObject*)buildNumpyDescription(view);
if (!dtype_dict)
throw pdal_error("Unable to build numpy dtype description dictionary");
int did_convert = PyArray_DescrConverter(dtype_dict, &dtype);
if (did_convert == NPY_FAIL)
throw pdal_error("Unable to build numpy dtype");
......@@ -126,18 +141,24 @@ public:
}
inline PyObject* getPythonArray() const { return m_py_array; }
inline PyObject* getPythonArray() const
{
return m_py_array;
}
private:
inline void cleanup()
{
PyObject* p = (PyObject*)(m_py_array);
Py_XDECREF(p);
if (m_own_array)
{
m_data_array.reset();
}
Py_XDECREF(p);
}
inline PyObject* buildNumpyDescription(PointViewPtr view) const
{
......@@ -170,6 +191,8 @@ private:
Dimension::BaseType b = Dimension::base(t);
if (b == Dimension::BaseType::Unsigned)
kind = "u";
else if (b == Dimension::BaseType::Signed)
kind = "i";
else if (b == Dimension::BaseType::Floating)
kind = "f";
else
......@@ -201,8 +224,12 @@ private:
return dict;
}
PyObject* m_py_array;
std::unique_ptr<std::vector<uint8_t> > m_data_array;
bool m_own_array;
Array& operator=(Array const& rhs);
};
......
/******************************************************************************
* Copyright (c) 2018, Howard Butler (howard@hobu.co)
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following
* conditions are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Hobu, Inc. or Flaxen Geo Consulting nor the
* names of its contributors may be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
****************************************************************************/
#pragma once
#include <pdal/PointView.hpp>
#include <pdal/Dimension.hpp>
#include <algorithm>
#include <vector>
typedef struct Dimension
{
std::string name;
std::string description;
std::string type;
int size;
std::string units;
} Dimension;
inline std::vector<Dimension> getValidDimensions()
{
std::vector<Dimension> output;
int id = (int)pdal::Dimension::Id::Unknown + 1;
while(1)
{
pdal::Dimension::Id pid = (pdal::Dimension::Id)id;
std::string name(pdal::Dimension::name(pid));
if (name.empty())
break;
pdal::Dimension::Type t = pdal::Dimension::defaultType(pid);
Dimension d;
d.name = name;
d.description = pdal::Dimension::description(pid);
d.size = pdal::Dimension::size(t);
std::string kind("i");
pdal::Dimension::BaseType b = pdal::Dimension::base(t);
if (b == pdal::Dimension::BaseType::Unsigned)
kind = "u";
else if (b == pdal::Dimension::BaseType::Signed)
kind = "i";
else if (b == pdal::Dimension::BaseType::Floating)
kind = "f";
else
{
std::stringstream oss;
oss << "unable to map kind '" << kind <<"' to PDAL dimension type";
throw pdal::pdal_error(oss.str());
}
d.type = kind;
output.push_back(d);
id++;
}
return output;
}
......@@ -46,14 +46,67 @@
#include <numpy/arrayobject.h>
#include "PyArray.hpp"
#include <pdal/Stage.hpp>
#include <pdal/PipelineWriter.hpp>
#include <pdal/io/NumpyReader.hpp>
namespace libpdalpython
{
using namespace pdal::python;
Pipeline::Pipeline(std::string const& json, std::vector<Array*> arrays)
{
#ifndef _WIN32
::dlopen("libpdal_base.so", RTLD_NOLOAD | RTLD_GLOBAL);
::dlopen("libpdal_plugin_reader_numpy.so", RTLD_NOLOAD | RTLD_GLOBAL);
#endif
#undef NUMPY_IMPORT_ARRAY_RETVAL
#define NUMPY_IMPORT_ARRAY_RETVAL
import_array();
m_executor = std::shared_ptr<pdal::PipelineExecutor>(new pdal::PipelineExecutor(json));
pdal::PipelineManager& manager = m_executor->getManager();
std::stringstream strm(json);
manager.readPipeline(strm);
pdal::Stage *r = manager.getStage();
if (!r)
throw pdal::pdal_error("pipeline had no stages!");
int counter = 1;
for (auto array: arrays)
{
// Create numpy reader for each array
pdal::Options options;
std::stringstream tag;
tag << "readers_numpy" << counter;
pdal::StageCreationOptions opts { "", "readers.numpy", nullptr, options, tag.str()};
pdal::Stage& reader = manager.makeReader(opts);
pdal::NumpyReader* np_reader = dynamic_cast<pdal::NumpyReader*>(&reader);
if (!np_reader)
throw pdal::pdal_error("couldn't cast reader!");
PyObject* parray = (PyObject*)array->getPythonArray();
if (!parray)
throw pdal::pdal_error("array was none!");
np_reader->setArray(parray);
r->setInput(reader);
counter++;
}
manager.validateStageOptions();
}
Pipeline::Pipeline(std::string const& json)
: m_executor(json)
{
// Make the symbols in pdal_base global so that they're accessible
// to PDAL plugins. Python dlopen's this extension with RTLD_LOCAL,
......@@ -67,6 +120,8 @@ Pipeline::Pipeline(std::string const& json)
#undef NUMPY_IMPORT_ARRAY_RETVAL
#define NUMPY_IMPORT_ARRAY_RETVAL
import_array();
m_executor = std::shared_ptr<pdal::PipelineExecutor>(new pdal::PipelineExecutor(json));
}
Pipeline::~Pipeline()
......@@ -75,34 +130,34 @@ Pipeline::~Pipeline()
void Pipeline::setLogLevel(int level)
{
m_executor.setLogLevel(level);
m_executor->setLogLevel(level);
}
int Pipeline::getLogLevel() const
{
return static_cast<int>(m_executor.getLogLevel());
return static_cast<int>(m_executor->getLogLevel());
}
int64_t Pipeline::execute()
{
int64_t count = m_executor.execute();
int64_t count = m_executor->execute();
return count;
}
bool Pipeline::validate()
{
return m_executor.validate();
return m_executor->validate();
}
std::vector<Array *> Pipeline::getArrays() const
{
std::vector<Array *> output;
if (!m_executor.executed())
if (!m_executor->executed())
throw python_error("call execute() before fetching arrays");
const pdal::PointViewSet& pvset = m_executor.getManagerConst().views();
const pdal::PointViewSet& pvset = m_executor->getManagerConst().views();
for (auto i: pvset)
{
......
......@@ -41,6 +41,8 @@
#include <string>
#include <sstream>
#include <memory>
#undef toupper
#undef tolower
#undef isspace
......@@ -65,26 +67,27 @@ public:
class Pipeline {
public:
Pipeline(std::string const& xml);
Pipeline(std::string const& json);
Pipeline(std::string const& json, std::vector<pdal::python::Array*> arrays);
~Pipeline();
int64_t execute();
bool validate();
inline std::string getPipeline() const
{
return m_executor.getPipeline();
return m_executor->getPipeline();
}
inline std::string getMetadata() const
{
return m_executor.getMetadata();
return m_executor->getMetadata();
}
inline std::string getSchema() const
{
return m_executor.getSchema();
return m_executor->getSchema();
}
inline std::string getLog() const
{
return m_executor.getLog();
return m_executor->getLog();
}
std::vector<pdal::python::Array *> getArrays() const;
......@@ -92,7 +95,7 @@ public:
int getLogLevel() const;
private:
pdal::PipelineExecutor m_executor;
std::shared_ptr<pdal::PipelineExecutor> m_executor;
};
}
__version__='2.0.0'
__version__='2.1.0rc1'
from .pipeline import Pipeline
from .array import Array
from .dimension import dimensions
import numpy as np
from pdal import libpdalpython
class Array(object):
"""A Numpy Array that can speak PDAL"""
def __init__(self, data):
self.p = libpdalpython.PyArray(data)
import numpy as np
from pdal import libpdalpython
from pdal.libpdalpython import getDimensions
dimensions = getDimensions()
This diff is collapsed.
# distutils: language = c++
# cython: c_string_type=unicode, c_string_encoding=utf8
from libcpp.vector cimport vector
from libcpp.string cimport string
......@@ -14,11 +15,13 @@ from cython.operator cimport dereference as deref, preincrement as inc
cdef extern from "PyArray.hpp" namespace "pdal::python":
cdef cppclass Array:
Array(object) except +
void* getPythonArray() except+
cdef extern from "PyPipeline.hpp" namespace "libpdalpython":
cdef cppclass Pipeline:
Pipeline(const char* ) except +
Pipeline(const char*, vector[Array*]& ) except +
int64_t execute() except +
bool validate() except +
string getPipeline() except +
......@@ -29,26 +32,86 @@ cdef extern from "PyPipeline.hpp" namespace "libpdalpython":
int getLogLevel()
void setLogLevel(int)
cdef class PyArray:
cdef Array *thisptr
def __cinit__(self, object array):
self.thisptr = new Array(array)
def __dealloc__(self):
del self.thisptr
cdef extern from "PyDimension.hpp":
ctypedef struct Dimension:
string name;
string description;
int size;
string type;
## string units; // Not defined by PDAL yet
cdef vector[Dimension] getValidDimensions() except +
def getDimensions():
cdef vector[Dimension] c_dims;
c_dims = getValidDimensions()
output = []
cdef vector[Dimension].iterator it = c_dims.begin()
while it != c_dims.end():
ptr = deref(it)
d = {}
d['name'] = ptr.name
d['description'] = ptr.description
kind = ptr.type + str(ptr.size)
d['dtype'] = np.dtype(kind)
ptr = deref(it)
output.append(d)
inc(it)
return output
cdef class PyPipeline:
cdef Pipeline *thisptr # hold a c++ instance which we're wrapping
def __cinit__(self, unicode json):
cdef char* x
def __cinit__(self, unicode json, list arrays=None):
cdef char* x = NULL
cdef int n_arrays;
if arrays:
n_arrays = len(arrays)
cdef vector[Array*] c_arrays;
cdef np.ndarray np_array;
cdef Array* a
if arrays is not None:
for array in arrays:
a = new Array(array)
c_arrays.push_back(a)
if PY_MAJOR_VERSION >= 3:
py_byte_string = json.encode('UTF-8')
x= py_byte_string
self.thisptr = new Pipeline(x)
if arrays:
self.thisptr = new Pipeline(json.encode('UTF-8'), c_arrays)
else:
self.thisptr = new Pipeline(json.encode('UTF-8'))
else:
if arrays:
self.thisptr = new Pipeline(json, c_arrays)
else:
self.thisptr = new Pipeline(json)
# if arrays:
# self.thisptr = new Pipeline(json.encode('UTF-8'), c_arrays)
# else:
# self.thisptr = new Pipeline(json.encode('UTF-8'))
def __dealloc__(self):
del self.thisptr
property pipeline:
def __get__(self):
return self.thisptr.getPipeline().decode('UTF-8')
return self.thisptr.getPipeline()
property metadata:
def __get__(self):
return self.thisptr.getMetadata().decode('UTF-8')
return self.thisptr.getMetadata()
property loglevel:
def __get__(self):
......@@ -59,13 +122,13 @@ cdef class PyPipeline:
property log:
def __get__(self):
return self.thisptr.getLog().decode('UTF-8')
return self.thisptr.getLog()
property schema:
def __get__(self):
import json
j = self.thisptr.getSchema().decode('UTF-8')
j = self.thisptr.getSchema()
return json.loads(j)
property arrays:
......
from pdal import libpdalpython
import numpy as np
class Pipeline(object):
"""A PDAL pipeline object, defined by JSON. See http://www.pdal.io/pipeline.html for more
information on how to define one"""
def __init__(self, json):
if isinstance(json, str):
data = json
def __init__(self, json, arrays=None):
if arrays:
self.p = libpdalpython.PyPipeline(json, arrays)
else:
data = json.decode('UTF-8')
self.p = libpdalpython.PyPipeline(data)
self.p = libpdalpython.PyPipeline(json)
def get_metadata(self):
return self.p.metadata
......
......@@ -110,7 +110,7 @@ extra_compile_args = []
if os.name in ['nt']:
library_dirs = ['c:/OSGeo4W64/lib']
libraries = ['pdalcpp','pdal_util','ws2_32']
libraries = ['pdalcpp','pdal_plugin_reader_numpy','pdal_util','ws2_32']
extra_compile_args = ['/DNOMINMAX',]
from setuptools.extension import Extension as DistutilsExtension
......@@ -154,11 +154,15 @@ include_dirs.append(numpy.get_include())
if os.name != 'nt':
extra_compile_args = ['-std=c++11','-Wno-unknown-pragmas']
DEBUG=False
if platform.system() == 'Darwin':
extra_link_args.append('-Wl,-rpath,'+library_dirs[0])
DEBUG=True
if DEBUG:
if os.name != 'nt':
extra_compile_args += ['-g','-O0']
libraries.append('pdal_plugin_reader_numpy')
sources=['pdal/libpdalpython'+ext, "pdal/PyPipeline.cpp" ]
extensions = [DistutilsExtension("*",
sources,
......@@ -174,7 +178,7 @@ if USE_CYTHON and "clean" not in sys.argv:
setup_args = dict(
name = 'PDAL',
version = str(module_version),
requires = ['Python (>=2.7)', ],
requires = ['Python (>=2.7)', 'Numpy'],
description = 'Point cloud data processing',
license = 'BSD',
keywords = 'point cloud spatial',
......@@ -199,7 +203,7 @@ setup_args = dict(
'Topic :: Scientific/Engineering :: GIS',
],
cmdclass = {},
install_requires = ['numpy', 'packaging'],
install_requires = ['numpy', 'packaging', 'cython'],
)
setup(ext_modules=extensions, **setup_args)
import unittest
import pdal
import os
import numpy as np
DATADIRECTORY = "./test/data"
......@@ -16,9 +17,9 @@ bad_json = u"""
}
"""
print (os.path.abspath(os.path.join(DATADIRECTORY, 'sort.json')))
class TestPipeline(unittest.TestCase):
class PDALTest(unittest.TestCase):
def fetch_json(self, filename):
import os
......@@ -28,55 +29,60 @@ class TestPipeline(unittest.TestCase):
output = f.read().decode('UTF-8')
return output
class TestPipeline(PDALTest):
#
@unittest.skipUnless(os.path.exists(os.path.join(DATADIRECTORY, 'sort.json')),
"missing test data")
def test_construction(self):
"""Can we construct a PDAL pipeline"""
json = self.fetch_json('sort.json')
r = pdal.Pipeline(json)
#
@unittest.skipUnless(os.path.exists(os.path.join(DATADIRECTORY, 'sort.json')),
"missing test data")
def test_execution(self):
"""Can we execute a PDAL pipeline"""
x = self.fetch_json('sort.json')
r = pdal.Pipeline(x)
r.validate()
r.execute()
self.assertGreater(len(r.pipeline), 200)
#
def test_validate(self):
"""Do we complain with bad pipelines"""
r = pdal.Pipeline(bad_json)
with self.assertRaises(RuntimeError):
r.validate()
#
@unittest.skipUnless(os.path.exists(os.path.join(DATADIRECTORY, 'sort.json')),
"missing test data")
def test_array(self):
"""Can we fetch PDAL data as a numpy array"""
json = self.fetch_json('sort.json')
r = pdal.Pipeline(json)
r.validate()
r.execute()
arrays = r.arrays
self.assertEqual(len(arrays), 1)
#
a = arrays[0]
self.assertAlmostEqual(a[0][0], 635619.85, 7)
self.assertAlmostEqual(a[1064][2], 456.92, 7)
#
@unittest.skipUnless(os.path.exists(os.path.join(DATADIRECTORY, 'sort.json')),
"missing test data")
def test_metadata(self):
"""Can we fetch PDAL metadata"""
json = self.fetch_json('sort.json')
r = pdal.Pipeline(json)
r.validate()
r.execute()
metadata = r.metadata
import json
j = json.loads(metadata)
self.assertEqual(j["metadata"]["readers.las"]["count"], 1065)
self.assertEqual(j["metadata"]["readers.las"][0]["count"], 1065)
#
#
@unittest.skipUnless(os.path.exists(os.path.join(DATADIRECTORY, 'sort.json')),
"missing test data")
def test_no_execute(self):
......@@ -85,7 +91,7 @@ class TestPipeline(unittest.TestCase):
r = pdal.Pipeline(json)
with self.assertRaises(RuntimeError):
r.arrays
#
@unittest.skipUnless(os.path.exists(os.path.join(DATADIRECTORY, 'reproject.json')),
"missing test data")
def test_logging(self):
......@@ -93,32 +99,69 @@ class TestPipeline(unittest.TestCase):
json = self.fetch_json('reproject.json')
r = pdal.Pipeline(json)
r.loglevel = 8
r.validate()
count = r.execute()
self.assertEqual(count, 789)
self.assertEqual(r.log.split()[0], '(pypipeline')
#
@unittest.skipUnless(os.path.exists(os.path.join(DATADIRECTORY, 'sort.json')),
"missing test data")
def test_schema(self):
"""Fetching a schema works"""
json = self.fetch_json('sort.json')
r = pdal.Pipeline(json)
r.validate()
r.execute()
self.assertEqual(r.schema['schema']['dimensions'][0]['name'], 'X')
#
@unittest.skipUnless(os.path.exists(os.path.join(DATADIRECTORY, 'chip.json')),
"missing test data")
def test_merged_arrays(self):
"""Can we fetch multiple point views from merged PDAL data """
json = self.fetch_json('chip.json')
r = pdal.Pipeline(json)
r.validate()
r.execute()
arrays = r.arrays
self.assertEqual(len(arrays), 43)
#
class TestArrayLoad(PDALTest):
def test_merged_arrays(self):
"""Can we load data from a a list of arrays to PDAL"""
data = np.load(os.path.join(DATADIRECTORY, 'perlin.npy'))
arrays = [data, data, data]
json = self.fetch_json('chip.json')
chip =u"""{
"pipeline":[
{
"type":"filters.range",
"limits":"Intensity[0:0.10]"
}
]
}"""
p = pdal.Pipeline(chip, arrays)
p.loglevel = 8
count = p.execute()
arrays = p.arrays
self.assertEqual(len(arrays), 3)
data = arrays[0]
self.assertEqual(len(data), 1836)
self.assertEqual(sum([len(i) for i in arrays]), 3*1836)
class TestDimensions(PDALTest):
def test_fetch_dimensions(self):
"""Ask PDAL for its valid dimensions list"""
dims = pdal.dimensions
self.assertEqual(len(dims), 72)
def test_suite():
return unittest.TestSuite(
[TestXML])
[TestPipeline])
if __name__ == '__main__':
unittest.main()