Libcurvecollection

From VrlWiki
Jump to navigation Jump to search
This page is incomplete and currently under development.

The Curve Collection Library (libcurvecollection) provides a representation of streamlines ("curves") in memory and an interface to access this information in a convenient (but memory-safe!) manner. It can also read and write to disk, freely converting between several file formats.

Currently, the supported formats are:


Introduction

Tubegen represents streamlines/tubes in several different formats in memory and on disk, which are distinct from the representations used by well-established third parties, for example FSL, Camino, and DTK. The core of any representation, though, is quite simple: a collection of streamlines, in which each streamline is just an ordered list of vertex points in 3-space. The tricky bit is that we want to be able to associate scalars with these datasets at various levels:

  • each individual streamline (ex: the length of the streamline)
  • each vertex point of each streamline (ex: the interpolated FA value at that point)

Some of the data formats also include a description (i.e., a string) for each scalar value.

libcurvecollection provides a unified interface for handling these various formats, while simplifying access to the information in memory by presenting it in an object-oriented fashion.

Installation

The Curve Collection library can be found under $G/common/mri/curvecollection/. To compile and install it, run make all, then make install.

To use the library after it has been installed, include the following lines:

#include <mri/curveCollection.h>
#include <mri/curve.h> 
#include <mri/curveVertex.h> 

near the top of your file.

Structure

The library consists of three mutually dependent components:

  1. CurveVertex
  2. Curve
  3. CurveCollection

If you look at the library source code, each component has a header (.h) and a .cpp file associated with it.

CurveVertex

A CurveVertex represents a point in 3D space. It holds the point's coordinates and any metadata (in the form of doubles) that the point may have.

Constructors

CurveVertex(double, double, double)

The main constructor takes three doubles: the x, y, and z coordinates of the point.


Copy constructors
CurveVertex(CurveVertex const &)
CurveVertex(CurveVertex const *)

A vertex instantiated using a copy constructor will have the same coordinates as the original, but won't have any properties and will not belong to any Curve (or CurveCollection). Hence, a warning: calling functions like property or getPropertyNames on a copy-constructed curve will result in a runtime_error.


Accessors

double x() const
double y() const
double z() const

Access the x, y, or z coordinate of the vertex, respectively.


Property accessors and mutators

double & property(std::string const &)

double const & property(std::string const &) const

The parameter of this function is the vertex property name. This function looks up the given property name and returns a reference to the vertex property (in the current CurveVertex) that it identifies. Because the return value is a reference, you can modify the stored property value (assuming your reference to the object is non-const).

All curve and vertex property names in libcurvecollection are case-insensitive. However, they are processed and stored in their lower-case form.

Note that the Curve Collection Library stores property names only at the highest level (i.e., in a CurveCollection). Therefore, the CurveVertex in question must be in a Curve, and that Curve must be in a CurveCollection before you can call this function. If you call it before this has happened, the program will exit with a runtime_error (CurveVertex::checkForContainer: ...). [1]

If the lookup fails (i.e., the given property name was not found in the CurveCollection), the function will throw an invalid_argument exception.


double & property(int)
double const & property(int) const

The parameter of this function is the integer Property ID. Returns a reference the vertex property identified by the Property ID. Throws an invalid_argument exception if the given ID is out of bounds.

What is a Property ID?

A Property ID is the index of the position in the vector where a property is stored. You can look it up using the CurveCollection::getVertexPropertyID function.

Why use a Property ID?
Those wishing to call getProperty from within a loop may want to avoid the efficiency loss associated with looking up the name at each call. Instead, they can perform the lookup once using curveCollection::getVertexPropertyID, and pass the resulting int ID

to property inside their loop."

Other property functions

int propertyCount() const

Returns the number of properties this vertex has.


std::vector<std::string> const & getPropertyNames() const

Returns a vector of all the property names of this CurveVertex (in the order in which they were set). Throws a runtime_error if the CurveVertex is not in a Curve, or if that Curve is not in a CurveCollection. Returns an empty vector if this CurveVertex is in a CurveCollection, but no properties have been set.


bool hasProperty(std::string const &) const

Returns true if this vertex has the property identified by the given name. (Specifically, checks that the CurveCollection knows this property name.) Hence, throws a runtime_error if the CurveVertex is not in a Curve, or if that Curve is not in a CurveCollection.


Other functions

bool equals(CurveVertex const &, double EPSILON = 1e-6) const

Compares the positions of two vertices in 3D space, returning true if each pair of coordinates (x, y, z) is within EPSILON of each other. Does not check for equality of properties.


double distance(CurveVertex const &) const

Computes the distance between two vertices in 3D space.


Curve

A Curve represents a track or streamline in 3D space, and consists of an ordered sequence of vertices and any metadata (in the form of doubles) that is common to them.

Curves are built on the assumption of piecewise linearity. That is, the model assumes that adjacent vertices are linearly connected. (This is used, for example, by the length() function.)


Constructors

Curve(std::vector<CurveVertex> const &)
Curve(std::vector<CurveVertex*> const &)

Initializes Curve with a copy of the given vertices and no curve properties. If the given vertices had any properties, they will not appear in the new Curve.


Curve(Curve const & c)

Copy constructor. The new Curve will have no properties and will not be in any CurveCollection.


Curve()

Empty constructor: the new Curve will have no vertices and no properties.


Destructor

~Curve()

The destructor will delete all vertices that constituted this curve and all properties.


Populating a curve

void addVertex(CurveVertex const &)

Appends the given CurveVertex to the end of the current Curve. Since you are adding to an already-existing curve, the properties of the new vertex must match[2] the properties of the vertices that are already in the curve. In the event of a mismatch, an invalid_argument exception is thrown.

There is one exception: if you are adding a vertex with no properties to a curve that does have properties, the vertex will be added to the curve (and no exception will be thrown), but the vertex will get zeros (0.0) for each of the properties.

Note: this function checks for matching properties on every call, so — depending on your situation — a more efficient way to populate a curve may be to store a vector of vertices and pass them to the constructor. (But remember to store the vertex properties separately, or they will be erased!)


Accessors

std::vector<CurveVertex*> const & getVertices() const

Returns a vector with pointers to all of the vertices this Curve contains.


CurveVertex const & operator[](int) const
CurveVertex & operator[](int)

Returns the CurveVertex at the given index in the curve. Throws an invalid_argument exception if the index is out of bounds.

Usage example: CurveVertex& firstVertex = someCurve[0];


Accessing vertex properties

std::vector<double> getVertexProperty(std::string const &) const

Returns a vector with the identified property value from each of this Curve's vertices. Throws a runtime_error if the Curve is not in any CurveCollection. Throws invalid_argument exception if the given string was not found among the vertex property names.

Usage example:
If Curve someCurve consists of three vertices aVertex, anotherVertex, and aThirdVertex, each of which has a property propertyX with values 10, 20, and 30, respectively, someCurve.getVertexProperty("propertyX") will return the vector [10, 20, 30].


Curve property accessors and mutators

double & property(std::string const &)
double const & property(std::string const &) const
double & property(int id)
double const & property(int id) const


See the documentation for the CurveVertex property accessor functions — these work just like they do.


Other curve property functions

int propertyCount() const

std::string const & getPropertyNames() const

bool hasProperty(std::string const &) const


See the documentation for the CurveVertex property functions — their behavior is identical.


bool propertiesMatch(Curve const &) const

Returns true when the curve and vertex properties in the two curves are identical in quantity, name, and order.


Other curve functions

int size() const

Returns the number of vertices in this curve.


double length() const

The actual length of the curve (sum of vertex-to-vertex distances).


Curve & operator=(Curve const & c)

Assignment operator: replaces this curve's vertices and properties with those of the given curve. The properties of the current curve and new curves must match; otherwise, a domain_error is thrown.


Iterator

const_iterator begin() const
const_iterator end() const

Works like your typical iterator by pointing to the first and last CurveVertex in this Curve (respectively).

Important: the iterator points to a pointer to a CurveVertex. To reiterate: if you dereference the iterator, you get the pointer to a CurveVertex. (This design choice is motivated by the internal representation of a Curve.)

Usage example:

Curve myCurve; // already populated
for(Curve::const_iterator vertexIterator = myCurve.begin(); 
    vertexIterator != myCurve.end(); 
    ++vertexIterator) 
{
    CurveVertex const * currentVertex = *cc_it;

    // do something with currentVertex
}

Warning: a Curve has a const_iterator but no iterator. If you use an iterator in your code, you will have problems!

CurveCollection

An instance of CurveCollection holds an arbitrary number of Curve objects and information about the Curve and CurveVertex properties (name/description strings). It also provides functions for the import and export of this data.


A note on properties

Every CurveVertex stores its own (vertex) properties. Likewise, every Curve stores its own curve properties. However, all curves and vertices in a CurveCollection must have the same properties. In fact, the only way to set properties is through functions that are located in CurveCollection.

Why is this the case? For metadata such as curve and vertex properties to be meaningful, there must be some string associated with them: a name (or a description). But storing a string with every data point in a collection is cost-prohibitive (in memory consumed). Since data in most collections shares the same properties, we have chosen to store the property names at the top level — in a CurveCollection. Enforcing this invariant is why all properties must be set at the same time and why a Curve and CurveVertex cannot have properties when they are not in a CurveCollection — without it, there simply isn't a way to look up the properties to access them.


Constructors

CurveCollection(std::vector<Curve*> const &)
CurveCollection(std::vector<Curve> const &)

The constructors take vectors of curves (or pointers to them) as parameters and construct a new CurveCollection using copies of those curves.

If the curves contain any curve and/or vertex properties, they will be preserved. However, for this to happen, the curves and vertex property names must match (including same order) across all curves. If this is not the case, a domain_error is thrown, and the constructor exits.

The constructor will also do its best to preserve the dimensions and voxel size of the source image. In cases of conflicting dimensions and voxel sizes, the constructor will use smallest voxel size among the candidates and the dimensions that went with that value. Note that these values are only meaningful when writing to (or reading from) TrackVis (.trk) files (see note at CurveCollection::writeTrackVisFile).


CurveCollection(CurveCollection const &)

Copy constructor. Will produce a curve collection identical to the given one.


CurveCollection()

Constructs a blank curve collection, much like you'd expect it to.


Destructor

~CurveCollection()

Clears and deletes everything in the CurveCollection.


Populating a CurveCollection

void addCurve(Curve const &)

Appends the given curve to this CurveCollection.

For this to happen, the properties of the given curve match those of this CurveCollection. Otherwise, a domain_error is thrown.

However, there are two exceptions:

Special case 1
If the CurveCollection is empty, it will take on the properties (if any) of the given curve. That is, if a curve C with properties (or vertex properties) is added to a blank CurveCollection, no error is thrown; instead, the CurveCollection "adopts" C's properties, and the properties of any subsequent curves will be required to match those of C.

Special case 2
If a CurveCollection has properties, but the given curve has none, the given curve will be assigned zeros (0.0) in place of all the properties it does not have.


Accessors

std::vector<Curve*> const & getCurves() const

Returns a reference to the vector of pointers to the curves that comprise this CurveCollection.


Curve const & operator[](int) const
Curve & operator[](int)

Overloaded random access operators for CurveCollection return a reference to the curve at the specified index.

Usage examples:
Curve& firstCurve = aCurveCollection[0];
Curve& lastCurve = aCurveCollection[aCurveCollection.size() - 1];


Setting properties

Curve properties

void defineCurveProperty(std::string const &, std::vector<double> const &)

Assigns the given double values to the curves as properties.

The properties are assigned in order. That is, the nth curve in the CurveCollection will get the nth property from the given vector. If the number of curves and the number of properties given do not match, an invalid_argument error is thrown.

The curves can be retrieved using the string name they were saved with, or using their Property ID (found using CurveCollection::getCurvePropertyID) . Note that property name strings are converted to lowercase before being saved.


Vertex properties

void defineVertexProperty(std::string const &, std::vector<std::vector<double> > const &)

Assigns the given double values to the vertices as properties.

The properties are assigned in order. That is, the kth vertex in the nth curve in the CurveCollection will get the kth property from the nth vector. If the number of curves and the number of properties given do not match, an invalid_argument error is thrown.

The curves can be retrieved using the string name they were saved with, or using their Property ID (found using CurveCollection::getVertexPropertyID) . Note that property name strings are converted to lowercase before being saved.


Accessing properties and information about them

Curve properties

Vertex properties

Clearing properties

Curve properties

Vertex properties

I/O functions

Other functions

int size() const

Returns the number of curves in this collection.






CCF

Notes

  1. libcurvecollection uses exceptions built into the C++ Standard Library (stdexcept).
  2. Whenever the library wants to check that the properties of two curves match, it calls the (public) Curve::propertiesMatch function, which checks that the curve and vertex properties are identical in their quantity, names, and ordering.