Libcurvecollection
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:
- DTK/TrackVis
- Tubegen's custom format (.data and .nocr files)
- CCF
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 a object-oriented fashion.
Installation
The Curve Collection library can be found under $G/common/libcurvecollection/. To install it, run make clean all. Anything else???
To use the library after it has been installed, include the following lines:
#include <brain/curveCollection.h> #include <brain/curve.h> #include <brain/curveVertex.h>
near the top of your file.
Structure
The library consists of three mutually dependent components, each with a header (.h) and a .cpp file:
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.
CurveVertex(CurveVertex const & v)
A vertex instantiated using a copy constructor will have the same coordinates and properties as the source, but will not belong to any Curve. Thus, the properties can only be accessed by calling property(int) (and not property(string)).
Accessors
double x() const
double y() const
double z() const
Property accessors & mutators
double & property(std::string const & name)
double const & property(std::string const & name) const
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 you called the non-const version of the function).
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 method. 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 string name was not found in the CurveCollection), the method will throw an invalid_argument exception.
double & property(int id)
double const & property(int id) const
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 essentially the index of the position in the vector where a property is stored. You can look it up using the CurveCollection::getVertexPropertyID method.
Why use a Property ID?
As the library explains, "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 IDto getProperty inside their loop."
Other property methods
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.
TODO: rethink this?
bool hasProperty(std::string const & name) 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 & v, 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 & v) 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.
Constructors
Curve(std::vector<CurveVertex> const & p_vertices);
Initializes Curve with given vertices and no curve properties. Warning: if the given vertices have any properties, they will be cleared.
Curve(Curve const & c)
Copy constructor. The new Curve will not be in any CurveCollection. Thus while any curve and vertex properties will be copied over, they may only be accessed using the property(int) accessor.
Curve()
Empty constructor
Populating a curve
void addVertex(CurveVertex const & v)
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 method 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 all of the vertices this Curve contains.
CurveVertex const & operator[](int index) const
CurveVertex & operator[](int index)
Returns the CurveVertex at the given index in the curve. Throws a 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 & name) const
Returns a vector with the identified property value from each of this Curve's vertices. Throws 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 & mutators
double & property(std::string const & name)
double const & property(std::string const & name) const
double & property(int id)
double const & property(int id) const
See the documentation for the CurveVertex property accessor methods — these work just like they do.
Other curve property methods
int propertyCount() const
std::string const & getPropertyNames() const
bool hasProperty(std::string const & name) const
See the documentation for the CurveVertex property methods — their behavior is identical.
bool propertiesMatch(Curve const & other) const
Returns true when the curve and vertex properties in the two curves are identical in quantity, name, and order.
Other curve methods
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.
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 }
CurveCollection
- ↑ libcurvecollection uses exceptions built into the C++ Standard Library (stdexcept).
- ↑ Whenever the library wants to check that the properties of two curves match, it calls the (public) Curve::propertiesMatch method, which checks that the curve and vertex properties are identical in their quantity, names, and ordering.