-
Notifications
You must be signed in to change notification settings - Fork 7
Aardvark Point Clouds Quick Reference
Aardvark encompasses libraries for viewing and working with point clouds. This includes parsers for common file formats, out-of-core/on-disk storage for large clouds, filtering and querying and reconstruction facilities, and pretty rendering. This document shows example code, and entry points for customizing your point cloud experience.
Point data is read from a data source (file, url) and persisted into a store.
-
File format parsing: Aardvark.Algodat contains libraries to parse common point cloud file formats in a lazy/stream-like fashion:
-
E57 parser (implemented here) retrieves points from an e57 file in close adherence to the spec. File contents can be accessed via
Aardvark.Data.E57.ASTM_E57
. Example usage here. More in-depth e57 parsing here. -
ply parser (implemented here) Uses Ply.Net open ply files and parses
vertex
point data and attributes. Example usage here. Comprehensive ply vertex data parsing here. - Las(Zip) parser (implemented here) parses points and various attributes from Las(-Zip) formats. Example usage here. Full-featured importer here.
- Custom formats are supplied via the
Chunk
datatype (usage here). Definition and supported attributes here.
-
E57 parser (implemented here) retrieves points from an e57 file in close adherence to the spec. File contents can be accessed via
-
Importing: All file parsers produce
Chunk
s, which are persisted to aStore
. During import, points are arranged in spatial subdivision datastructure, are given Level of Detail representation, and receive estimated Normals (if not present). References to on-disk data are stored inPersistentRef<T>
. - Our commandline importer/viewer tool is available here.
- Change the colors of points using a custom shader (code)
Point clouds are stored in an Octree-like data structure for fast spatial querying. The node type is IPointCloudNode
. Starting from the Root node, the tree is recursively traversed via its Subnodes.
-
Filters create an immutable copy of a tree defining "inside" and "outside" points. Example use here. Spatial filters include Sphere3d, Box3d, Hulls3d, Prism3d. Non-spatial filters include Classification, Intensity. Custom filters are implemented with the
IFilter
interface. - Queries enumerate points from the current (filtered) point cloud. Example use here. Geometric queries include Box3d, Ray3d, V3d, Hull3d and other queries are AllPoints, Cells, Grid, ViewFrustum. Custom queries are supplied with these functions.
- Delete actively erases points from a store. The call is here.
- Normal Estimation exists as part of LOD generation. The code can be found here.
- Linear Regression: The functionality to establish best-fit planes (lines) in 3D (2D) points can be found here.
Our rendering is geared towards showing and interacting with many large-scale point clouds.
- Our commandline importer/viewer tool is available here.
- Viewer: Our viewer includes graphical effects to make viewing of complicated or uncolored point clouds easier, including surface smoothing, SSAO and anti-aliasing.
-
Scene Graph Node: If using Aardvark.Rendering, our point cloud rendering can be accessed in the SceneGraph Api using
Sg.pointSets
. TheIPointCloudNode
is wrapped usingPointTreeNode.Create
, which is then wrapped inLodTreeInstance
(example code here). The visual effects are controlled using a config, example code here. -
Pixel Picking framebuffer-readback style is enabled via the config's field
pickCallback
for a pixel position and pixel radius. The definition is here. Additional support for custom attributes is available in the visual picking implementation using the lower level Api andSimplePickTree
. -
Custom per-point Attributes:
PointTreeNode.Create
allows supplying custom per-point attributes. These show up as per-primitive attribute in the shader under the supplied name, i.e. :
type CrazyVertex =
{
[<Semantic("MyAttrib")>] myattrib : float32
[<Color>] c : V4d
[<Position>] wp : V4d
}
-
Per-cloud Uniforms:
LodTreeInstance
allows supplying per-cloud uniforms. These are transferred to the GPU as a storage buffer, and can be accessed via the Aardvark uniforms Api, i.e.
type UniformScope with
member x.MyUniform : V4d[] = uniform?StorageBuffer?MyUniform
Point clouds can be loaded like this:
var a = PointCloud.Import("scan.pts"); // in-memory, limited size
WriteLine(a.PointCount);
WriteLine(a.Bounds);
By specifying an additional location for out-of-core data, all size limits will be removed.
var a = PointCloud.Import("scan.pts", @"C:\Data\mystore"); // out-of-core, unlimited size
var key = a.Id;
When using a store, the imported dataset will also be stored permanently and can be loaded again directly from the store, which is very fast:
var a = PointCloud.Load(key, @"C:\Data\mystore");
Point clouds can be merged into larger ones.
var a = PointCloud.Import("scan1.pts");
var b = PointCloud.Import("scan2.pts");
var m = a.Merge(b);
By the way, a and b are not touched by the merge operation and are still valid. Internally, m will of course efficiently reuse the data already stored for a and b.
// All points within maxDistance of given plane.
QueryPointsNearPlane(Plane3d plane, double maxDistance)
// All points within maxDistance of ANY of the given planes.
QueryPointsNearPlanes(Plane3d[] planes, double maxDistance)
// All points NOT within maxDistance of given plane.
QueryPointsNotNearPlane(Plane3d plane, double maxDistance)
// All points NOT within maxDistance of ALL the given planes.
QueryPointsNotNearPlanes(Plane3d[] planes, double maxDistance)
// All points within maxDistance of given polygon.
QueryPointsNearPolygon(Polygon3d plane, double maxDistance)
// All points within maxDistance of ANY of the given polygons.
QueryPointsNearPolygons(Polygon3d[] planes, double maxDistance)
// All points NOT within maxDistance of given polygon.
QueryPointsNotNearPolygon(Polygon3d plane, double maxDistance)
// All points NOT within maxDistance of ALL the given polygons.
QueryPointsNotNearPolygons(Polygon3d[] planes, double maxDistance)
// All points inside axis-aligned box (including boundary).
QueryPointsInsideBox(Box3d box)
// All points outside axis-aligned box (excluding boundary).
QueryPointsOutsideBox(Box3d box)
// All points inside convex hull (including boundary).
QueryPointsInsideConvexHull(Hull3d convexHull)
// All points outside convex hull (excluding boundary).
QueryPointsOutsideConvexHull(Hull3d convexHull)
// Enumerates (out-of-core) all points in a point cloud in chunks.
// A chunk corresponds to an octree cell of size given by by cellExponent.
// Cell size is 2^cellExponent, e.g. -2 gives 0.25, -1 gives 0.50, 0 gives 1.00, 1 gives 2.00, and so on.
EnumerateCells(int cellExponent)
The EnumerateCells
function returns a sequence of CellQueryResult
objects (one per cell).
A CellQueryResult
does not contain actual point data, so it is very cheap and fast to generate, and the sequence can be used for filtering out relevant cells (e.g. cells in a certain region).
// get all cells of size 1 (=2^0) with a Z location between -1 and +1
var xs = pointcloud
.EnumerateCells(0)
.Where(x => x.Cell.Z >= -1 && x.Cell.Z <= +1)
;
Use GetPoints
on a CellQueryResult
to extract points located within the cell,
where the fromRelativeDepth
parameter controls the density of the extracted points.
You can use a large value (e.g. int.MaxValue) to extract the most detailed LoD.
// Returns points inside cell from LoD at given relative depth,
// where 0 means points in cell itself, 1 means points from subcells, aso.
Chunk GetPoints(int fromRelativeDepth)
You can also include points from neighboring cells by specifying an additional kernel
size,
Chunk GetPoints(int fromRelativeDepth, Box3i kernel)
where Box3i(V3i(-1,-1,-1), V3i(+1,+1,+1))
will include all direct neighbours, i.e. a total of 3 x 3 x 3 = 27
cells.
The kernel size does not need to be the same in all directions.
For example, if you want to include an additional ring of 2 cells in X- and Y-direction, but none in Z-direction, you would use Box3i(V3i(-2,-2,-0), V3i(+2,+2,0))
. This would include a total of 5 x 5 x 1 = 25
cells.