summaryrefslogtreecommitdiffstats
path: root/doc/manual2
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 11:57:42 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 11:57:42 +0000
commit61f3ab8f23f4c924d455757bf3e65f8487521b5a (patch)
tree885599a36a308f422af98616bc733a0494fe149a /doc/manual2
parentInitial commit. (diff)
downloadlib2geom-upstream.tar.xz
lib2geom-upstream.zip
Adding upstream version 1.3.upstream/1.3upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'doc/manual2')
-rw-r--r--doc/manual2/ack47
-rw-r--r--doc/manual2/concepts128
-rw-r--r--doc/manual2/d2106
-rw-r--r--doc/manual2/geometric primitives65
-rw-r--r--doc/manual2/introduction41
-rw-r--r--doc/manual2/piecewise134
-rw-r--r--doc/manual2/s-basis91
7 files changed, 612 insertions, 0 deletions
diff --git a/doc/manual2/ack b/doc/manual2/ack
new file mode 100644
index 0000000..c6325fd
--- /dev/null
+++ b/doc/manual2/ack
@@ -0,0 +1,47 @@
+h1. Acknowledgements and History
+2Geom is a group project, having many authors and contributors. The
+original code was sketched out by Nathan Hurst and Peter Moulder for
+the Inkscape vector graphics program to provide well typed, correct
+and easy to use C++ classes. Since then many people have refined and
+debugged the code. One of the earliest C++ification projects for
+inkscape was replacing NRPoint with NR::Point.
+
+A conspicuous absence was a Path datatype, and indeed Inkscape
+developed at least 3 different internal path datatypes, plus several
+others in related projects. Considering the core importance of path
+operations in vector graphics, this led to much re-implementation of
+algorithms, numerous bugs, and many round trips converting between
+forms.
+
+Many attempts have been made to try and develop a single path data
+structure, but all were fated to sit in random SCMs scattered across
+the web.
+
+Several unrelated projects had copied out various portions of the NR
+code from Inkscape and in 2006 MenTaLguY and Nathan felt that it was
+time to separate out the geometry portions of inkscape into a
+separate library for general use and improvement. The namespace was
+changed from NR to Geom and a prototype for paths sketched out.
+Nathan studied the state of the art for computational geometry whilst
+MenTaLguY focused on the design of Paths.
+
+Before the re-merging of 2Geom with the inkscape svn HEAD it was felt
+that a few smaller projects should be ported to use 2Geom. Michael
+Wybrow's libavoid advanced connector routing system was ported first.
+
+(TODO: did this happen? also, add the rest of history..)
+
+h2. People who have contributed to 2Geom
+* Aaron C. Spike
+* Alex Mac
+* Fred: livarot
+* Javier Sanchez-Reyes
+* Jean-Francois Barraud
+* Jonathon Wright
+* Joshua Blocher
+* Kim Marriott
+* MenTaLguY
+* Michael J. Wybrow
+* Michael G. Sloan
+* Nathan J. Hurst
+* Peter J. R. Moulder
diff --git a/doc/manual2/concepts b/doc/manual2/concepts
new file mode 100644
index 0000000..e89bf55
--- /dev/null
+++ b/doc/manual2/concepts
@@ -0,0 +1,128 @@
+h1. Concept Checking
+
+The C++ Standard Template Library introduces the notion of _concepts_,
+which specify families of types related by a common interface. In
+template-based programming with the STL, concepts serve a similar
+purpose to type classes in Haskell. While, unlike Haskell's language-level
+support for type classes, concept-checking is not directly supported by the
+C++ compiler or language, C++ libraries have been written which use template
+techniques to provide compile-time checking and enforcement of concepts.
+We use the Boost Concept Checking library.
+
+h2. Lib2geom's 'Concepts'
+
+There are several important lib2geom 'concepts'.
+
+h3. *FragmentConcept*
+
+This is perhaps the most important concept within lib2geom, as it defines
+the interface for the basic, one-dimensional functions. Fragments are
+defined on the interval [0,1], which is referred to as the _intended domain_
+of the function. Functions may be well defined for all values (many are),
+but the 0-to-1 domain has significant semantic value. When the functions
+are used to represent a *Curve*, 0 is the start and 1 is the end.
+
+h4. @ T::output_type @
+
+Every fragment must typedef an *output_type*. This is usually *Coord*, however,
+in order to support considering @D2<T>@ a fragment, this typedef was added.
+This information is also used by the compiler to infer the proper bounds and
+sbasis types.
+
+h4. Value Query
+
+<pre><code>
+output_type T::valueAt(double);
+output_type T::operator()(double);
+output_type T::at0();
+output_type T::at1();
+</code></pre>
+
+*FragmentConcept* defines several methods for retrieving the value at a point.
+One method is to use the *valueAt* function, which returns output_type given
+a t-value. Fragments are also functors, which in C++ lingo means they look
+like function calls, as they overload the () operator. This is essentially
+the same as calling valueAt. The functions *at0* and *at1* are also
+provided, and should be used whenever the start or end of the function is
+required, as many functions directly store this information.
+
+h4. @ sbasis_type T::toSBasis() @
+
+As *SBasis* will be the main function representation, it is desirable to always
+be able to approximate and deal with other functions in this way. Therefore,
+the *toSBasis* function is required. When *output_type* is @double@,
+@sbasis_type@ is *SBasis*. When *output_type* is *Point*, @sbasis_type@ is
+*SBasisCurve*.
+
+(TODO: in writing this it occurs to me that toSBasis should take a tolerance)
+
+h4. @ T reverse(T) @
+
+As most of the implementors of fragment consider functions in a fairly
+symmetric way, the *reverse* function was included in the *FragmentConcept*.
+*reverse* flips the function's domain on 0.5, such that f'(t) = f(1-t).
+
+h4. Bounds
+
+<code><pre>
+bounds_type bounds_fast(T);
+bounds_type bounds_exact(T);
+bounds_type bounds_local(T, Interval);
+</pre></code>
+
+Finding the bounds of a function is essential for many optimizations and
+algorithms. This is why we provide 3 functions to do it. *bounds_fast*
+provides a quick bounds which contains the actual bounds of the function.
+This form is ideal for optimization, as it hopefully does not require too
+much computation. *bounds_exact*, on the other hand, provides the exact
+bounds of the function. *bounds_local* only returns the bounds of an
+interval on the function - at the moment it is unclear if this is exact.
+When *output_type* is @double@, @bounds_type@ is *Interval*. When
+*output_type* is @Point@, @bounds_type@ is *Rect*.
+
+See the linear.h code for an example of an implementation of *FragmentConcept*.
+
+h3. *OffsetableConcept*
+
+*OffsetableConcept* defines what it means to be offsetable. Like
+*FragmentConcept*, this concept requires an output_type, which is used
+as the offset type. This still makes since when the implementor is
+also a fragment, as in pretty much all cases you would want to offset
+a function using the same type it outputs.
+
+The following operators are defined by *OffsetableConcept*:
+
+@T + output_type, T - output_type, T += output_type, T -= output_type@,
+
+h3. *ScalableConcept*
+
+*ScalableConcept* defines what it means to be scalable. Like
+*OffsetableConcept*, it requires an output_type, which is used as the
+scalar-type. This is an assumption that may not pan out in the future,
+however, for all function types we've used this always applies.
+Technically points should not be multiplicable, however, they provide a
+convenient storage mechanism for non-uniform scaling. If this changes
+in the future, the implementations will remain the same, while the
+concept definitions are loosened.
+
+The following operators are defined by *ScalableConcept*:
+@T * scalar_type, T / scalar_type, T *= scalar_type, T /= scalar_type, -x@,
+
+h3. *AddableConcept*
+
+*AddableConcept* defines a concept for classes which are closed under
+addition (the classes may be added to themselves, and the result is the
+same type). The following operators are included:
+
+@x + y, x - y, x += y, x -= y@
+
+h3. *MultiplicableConcept*
+
+*MultiplicableConcept* defines a concept for classes which are closed under
+multiplication (the classes may be multiplied by themselves, and the result
+is the same type). The following operators are included:
+
+@x * y, x *= y@
+
+At some point a DividableConcept may be implemented, however, at the moment
+it is not very useful.
diff --git a/doc/manual2/d2 b/doc/manual2/d2
new file mode 100644
index 0000000..b4769e0
--- /dev/null
+++ b/doc/manual2/d2
@@ -0,0 +1,106 @@
+h1. Dealing with two Dimensions: *D2*
+
+After writing a few classes for two dimensional objects, we realized
+that there is a lot of boilerplate associated with what is essentially
+lifting one dimensional concepts into two. Instead of frequently
+rewriting this code, we instead created the *D2* template class.
+
+For example, a point in space might be represented by *D2<double>*.
+This may, in fact, become the actual representation for Point.
+We have not yet replaced Point with this, as not all of Points
+operations have been ported (or are applicable), and we are not
+yet sure if there is 0 performance loss.
+
+(TODO remove previous stuff if D2<double> becomes point repr)
+
+h2. Component Access
+
+One might expect such an object to have @.x@ and @.y@ fields, however,
+it instead consists of 2 element array. With LibNR, it was found that
+the availability of @.x@ and @.y@ encouraged people to attempt to
+inline operations rather than using the operators, perhaps in (vain)
+pursuit of a performance enhancement. By using an array, we encourage
+people to think about points as symmetric objects and discourage
+direct use of the components. However, we still provide direct access
+for the rare occasion that it is needed. Even in these cases, the array
+method reduces bugs by encouraging iteration over the array rather than
+explicit element reference.
+
+The components of a *D2* are accessed through the indexing operator, [].
+The input value to the index operator is the @enum@ *Dim2*, which
+defines *X* = 0 and *Y* = 1. This is to encourage using the
+@for(int d=0; i<2; i++)@ idiom when normal operations do not suffice.
+
+h2. Arithmetic Operators
+
+@D2<T>@ implements the *AddableConcept*, *OffsetableConcept*, and
+*ScalableConcept* (if @T@ implements them as well) yielding the
+following operators:
+
+<pre><code>
+AddableConcept: x + y, x - y, x += y, x -= y
+OffsetableConcept: x + p, x - p, x += p, x -= p
+ScalableConcept: x * p, x / p, x *= p, x /= p, -x
+ x * d, x / d, x *= d, x /= d
+</code></pre>
+
+(where @x@ and @y@ are *D2*, d is *Coord*, and @p@ is a *Point* and all
+return @D2<T>@)
+
+These operators all just apply the operation on @T@ to the components.
+So, @a + b@ just returns @D2<T>(a[X] + b[X], a[Y] + b[Y])@, though the
+actual code uses a loop (which is unrolled) in order to avoid
+bugs.
+
+h2. Geometric Operations
+
+<pre><code>
+T dot(D2<T> const &, D2<T> const &);
+T cross(D2<T> const &, D2<T> const &);
+</code></pre>
+
+The *dot*:http://en.wikipedia.org/wiki/Dot@product and
+*cross*:http://en.wikipedia.org/wiki/Cross@product products are defined
+on D2<T> when T implements *AddableConcept* and *MultiplicableConcept.
+The cross function returns the length of the resultant 3d vector
+perpendicular to the 2d plane.
+
+@ D2<T> operator*(D2<T> const &, Matrix const &)@
+
+This operation applies an affine transformation to the 2d object.
+
+h2. Fragment Lifting
+
+*D2<T>* also implements FragmentConcept if T implements it as well,
+allowing *D2* to lift one dimensional functions into two-dimensional
+parametric curves. As a fragment, a *D2* will represent a function
+from a double to a Point.
+
+h3. Fragment Operations
+
+In addition to the normal set of Fragment methods, D2 has the following
+functions:
+
+h4. @ D2<T> compose(D2<T> const &a, T const &b); @
+
+The *compose* function is defined when @T@ is a function representation which
+supports composition. The only forms in 2geom are *SBasis* and *SBasis2d*.
+The *D2* *compose* function composes @b@ on both components of @a@. This
+makes sense, as a D2<SBasis> is double -> D2<double> and the function for
+composition is double -> double. One way to think of composition is that
+the output is equivalent to applying @b@ to the input, and then applying a
+to @b@'s output.
+
+h4. @ D2<T> compose_each(D2<T> const &a, D2<T> &b); @
+
+The *compose_each* function is similar to the *compose* function, except that
+@b@ is also a *D2*, so instead of composing the same function on each component,
+the two functions in @b@ are used.
+
+
+h4. @ Point D2<T>::operator()(double x, double y) const @
+
+*D2* wraps this operator for when @T@ is a function taking a 2 component input.
+The only case of this currently within 2geom is SBasis2d.
+
+(TODO: derivative/integral)
diff --git a/doc/manual2/geometric primitives b/doc/manual2/geometric primitives
new file mode 100644
index 0000000..b78370e
--- /dev/null
+++ b/doc/manual2/geometric primitives
@@ -0,0 +1,65 @@
+h1. Geometric Primitives
+
+What good is a geometry library without geometric primitives? By this
+I mean the very basic stuff, Points/Vectors, Matrices, etc.
+
+2geom's primitives are descendant from libNR's geometric primitives.
+They have been modified quite a bit since that initial import.
+
+h2. Point
+
+!media/point.png!
+
+The mathematical concepts of points and vectors are merged into the
+2geom class called *Point*. See Appendix A for a further
+discussion of this decision.
+
+Point may be interpreted as a D2<double> with some additional operations.
+
+(TODO: document these ops.)
+
+\section{Transformations}
+
+Affine transformations are either represented with a canonical 6
+element matrix, or special forms.
+
+\subsection{Scale}
+
+\includegraphics[height=50mm]{media/scale.png}
+
+A \code{Scale} transformation stores a vector representing a scaling
+transformation.
+
+\subsection{Rotate}
+
+\includegraphics[height=50mm]{media/rotate.png}
+
+A \code{Rotate} transformation uses a vector(\code{Point}) to store
+a rotation about the origin.
+
+In correspondence with mathematical convention (y increasing upwards),
+0 degrees is encoded as a vector pointing along the x axis, and positive
+angles indicate anticlockwise rotation. So, for example, a vector along
+the y axis would encode a 90 degree anticlockwise rotation of 90 degrees.
+
+In the case that the computer convention of y increasing downwards,
+the \verb}Rotate} transformation works essentially the same, except
+that positive angles indicate clockwise rotation.
+
+\subsection{Translate}
+
+\includegraphics[height=70mm]{media/translate.png}
+
+A \code{Translate} transformation is a simple vector(\code{Point})
+which stores an offset.
+
+\subsection{Matrix}
+
+\includegraphics[height=70mm]{media/matrix.png}
+
+A \code{Matrix} is a general affine transform. Code is provided for
+various decompositions, constructions, and manipulations. A
+\code{Matrix} is composed of 6 coordinates, essentially storing the
+x axis, y axis, and offset of the transformation. A detailed
+explanation for matrices is given in Appendix B.
+
diff --git a/doc/manual2/introduction b/doc/manual2/introduction
new file mode 100644
index 0000000..f8c71fc
--- /dev/null
+++ b/doc/manual2/introduction
@@ -0,0 +1,41 @@
+h1. Introduction
+
+This manual focuses on the lib2geom computational geometry framework.
+The main goal of this framework is the eventual replacement of
+Inkscape's multiple and shoddy geometry frameworks. As with any decent
+module or lib, 2geom is designed to achieve the desired functionality
+while maintaining a generality encouraging usage within other
+applications. The focus on robust, accurate algorithms, as well as
+utilization of newer and better representations makes the lib
+very attractive for many applications.
+
+h2. Design Considerations
+
+2Geom is written with a functional programming style in mind.
+Generally data structures are considered immutable and rather than
+assignment we use labeling. However, C++ can become unwieldy if
+this is taken to extreme and so a certain amount of pragmatism is
+used in practice. In particular, usability is not forgotten in the
+mires of functional zeal.
+
+The code relies strongly on the type system and uses some of the more
+'tricky' elements of C++ to make the code more elegant and 'correct'.
+Despite this, the intended use of 2Geom is a serious vector graphics
+application. In such domains, performance is still used as a quality
+metric, and as such we consider inefficiency to be a bug, and have
+traded elegance for efficiency where it matters.
+
+In general the data structures used in 2Geom are relatively 'flat'
+and require little from the memory management. Currently most data
+structures are built on standard STL headers, and new and delete are
+used sparingly. It is intended for 2Geom to be fully compatible with
+Boehm garbage collector though this has not yet been tested.
+
+h2. Toy-Based Development
+
+We have managed to come up with a method of library development
+which is perfect for geometry - the development of toys exemplifying
+a feature while the feature is perfected. This has somewhat subsumed
+the role of tests, and provides immediate motivation/reward for work.
+
+!media/gear.png!
diff --git a/doc/manual2/piecewise b/doc/manual2/piecewise
new file mode 100644
index 0000000..9f1bd98
--- /dev/null
+++ b/doc/manual2/piecewise
@@ -0,0 +1,134 @@
+h1. *Piecewise*
+
+In order to represent functions with a complex shape, it is necessary
+to define functions in a piecewise manner. In the graphics world this
+sort of function, when parametric, is often referred to as a 'spline'.
+Even beyond the representation of paths, it is also often necessary
+for mathematical operations to return piecewise functions, as otherwise
+the single-fragment versions would require an inordinate degree to
+still be accurate. An example of this is the *inverse* function.
+
+In the world of lib2geom, this is implemented as the *Piecewise*
+template class. It manages a sequence of fragment 'segments' and the
+cuts between them. These cuts are the various t-values which separate
+the different segments.
+
+h2. Cuts
+
+The first and last cuts of a piecewise define it's intended range, and
+the intermediary cuts separate the segments. With indices, segment i
+is always bordered on the left with cut i and on the right with cut i+1.
+In general, c = s+1, where c is the number of cuts and s is the number
+of segments. These invariants are checked by the
+@bool Piecewise<T>::invariants();@ method.
+
+The cuts essentially define the position and scale of each segment.
+For example, if the left and right cuts are 0.5 apart, the segment is
+half its regular size; the derivative will be twice as big.
+
+h4. Cut Query Functions
+
+<pre><code>
+unsigned Piecewise<T>::segN(double, int low = 0, int high = -1) const;
+double Piecewise<T>::segT(double, int = -1) const;
+double mapToDomain(double t, unsigned i) const;
+</code></pre>
+
+These functions use the cut information to ascertain which segment a
+t-value lies within ( *segN* ), and what the t-value is for that segment
+at that particular point ( *segT* ). *segN* takes two optional parameters
+which limit the range of the search, and are used internally as it is
+defined as a recursive binary search. These may be used if you are sure
+that the desired segment index lies within the range. *segT* takes an
+optional parameter for the case where you already know the segment number.
+
+mapToDomain is the inverse of segT, as it takes a t-value for a particular
+segment, and returns the global piecewise time for that point.
+
+h4. @ Interval Piecewise<T>::domain() const; @
+
+The *domain* function returns the Interval of the intended domain of the
+function, from the first cut to the last cut.
+
+h4. Cut Modification Functions
+
+<pre><code>
+void Piecewise<T>::offsetDomain(double o)
+void Piecewise<T>::scaleDomain(double s)
+void Piecewise<T>::setDomain(Interval dom)
+</code></pre>
+
+These functions very simply transform the cuts with linear transformations.
+
+h3. Technical Details
+
+As the cuts are simply a public std::vector, they may also be accessed as
+@pw.cuts@.
+
+While the actual segments begin on the first cut and end on the last,
+the function is defined throughout all inputs by extending the first
+and last segments. The exact switching between segments is arbitrarily
+such that beginnings (t=0) have priority over endings (t=1). This only
+really matters if it is discontinuous at that location.
+
+In the context of 2d parametrically defined curves, the usefulness of cuts
+becomes less apparrent, as they make no real difference for the display
+of the curves. Rather, cuts become more of an agreement between various
+functions such that the proper data aligns.
+
+h2. Construction
+
+Most of the time there is no need for raw construction of *Piecewise*
+functions, as they are usually obtained from operations and other sources.
+
+The following constructors defined for *Piecewise*:
+* The blank constructor
+* A constructor which explicitly lifts a fragment to a *Piecewise* on [0,1]
+* A constructor which takes the *output_type*, and creates a constant function
+
+<pre><code>
+void Piecewise<T>::push_seg(T);
+void Piecewise<T>::push_cut(double);
+void Piecewise<T>::push(T, double);
+</code></pre>
+
+The usual method for raw construction is to construct a blank *Piecewise*
+function, and use these push methods to load the content. *push_seg* and
+*push_cut* simply add to the segment and cut lists, although *push_cut*
+also checks that the cut time is larger than the last cut. The current
+recommended method for calling these functions is to have one initial
+*push_cut*, followed by successive calls to *push*, as this will guarantee
+that the cuts and segments properly align.
+
+h2. Operations
+
+h3. Arithmetic
+
+*Piecewise* has many arithmetic operations, and implements
+*OffsetableConcept*, *ScalableConcept*, *AddableConcept*, and
+*MultiplicableConcept*. The operations which operate on two Piecewise
+functions (Addable and Multiplicable) work by interleaving the cuts using
+mutual *partition* calls, and iterating the resulting segments.
+
+h3. Fragment Wrapping
+
+While *Piecewise* is not a fragment (it does not have the [0,1] domain),
+it has many functions reminiscient of *FragmentConcept*, including the
+bounds functions, () and valueAt.
+
+(TODO: reverse function?)
+
+h3. Concatenation
+
+<pre><code>
+void Piecewise<T>::concat(const Piecewise<T> &other);
+void Piecewise<T>::continuousConcat(const Piecewise<T> &other);
+</code></pre>
+
+These functions efficiently append another *Piecewise* to the end of a
+*Piecewise*. They offset the _other_ *Piecewise* in time such that it is
+flush with the end of this *Piecewise*. *continuousConcat* is basically
+the same except that it also offsets in space so the functions also match
+in value.
+
+(TODO: compose/derivative/integral)
diff --git a/doc/manual2/s-basis b/doc/manual2/s-basis
new file mode 100644
index 0000000..5f2ddfb
--- /dev/null
+++ b/doc/manual2/s-basis
@@ -0,0 +1,91 @@
+h1. S-Power-Basis-Forms
+
+2Geom provides a very powerful algebra for modifying paths. Although
+paths are kept in an extended SVG native form where possible, many
+operations require a more mathematical form. Our prefferred form is
+a sequence of s-power basis polynomials, henceforth referred to as
+s-basis. We may convert to this form, perform the required operations
+and convert back, approximating to a requested tolerance as required.
+
+The precise details of the s-basis form are beyond the scope of this
+manual - the interested reader should consult \cite{SanchezReyes1997,SanchezReyes2000,SanchezReyes2001,SanchezReyes2003,SanchezReyes2004}.
+An elementary, functional description is given in Appendix C.
+
+(TODO: work out textile citations, math inclusion)
+
+Geometrically important properties:
+* exact representation of bezier segments
+* low condition number on bezier conversion.
+* strong convergence guarantees
+* $C^0$ continuity guarantee
+
+The following operations are directly implementable and are very efficient:
+* fast conversion from all svg elements
+* basic arithmetic - @+@, @-@, $\times$, $\div$
+* algebraic derivative and integral
+* elementary trigonometric functions: $\sqrt{\cdot}$, $\sin(\cdot)$, $\cos(\cdot)$, $\exp(\cdot)$
+* efficient degree elevation and reduction
+* function inversion
+* exact solutions for many non trivial operations
+* root finding
+* composition
+
+All of these operations are fast. For example, multiplication of two
+beziers by converting to s-basis form, multiplying and converting back
+takes roughly the same time as performing the bezier multiplication
+directly, and furthermore, subdivision and degree reduction are
+straightforward in this form.
+
+h2. Implementation
+
+h3. *Linear*
+
+The *Linear* class represents a linear function, mostly for use as a
+building block for *SBasis*. *Linear* fully implements *AddableConcept*,
+*OffsetableConcept*, and *ScalableConcept* yielding the following operators:
+
+<pre><code>
+ AddableConcept: x + y, x - y, x += y, x -= y
+ OffsetableConcept: x + d, x - d, x += d, x -= d
+ ScalableConcept: x * d, x / d, x *= d, x /= d, -x
+</code></pre>
+
+(where @x@ and @y@ are *Linear*, d is *Coord*, and all return *Linear*)
+
+As *Linear* is a basic function type, it also implements the *FragmentConcept*.
+
+The main *Linear* constructor accepts two *Coord* values, one for the Linear's
+value at 0, and one for its value at 1. These may then later be accessed and
+modified with the indexing operator, @[]@, with a value of 0 or 1.
+
+h3. *SBasis*
+
+The *SBasis* class provides the most basic function form,
+$f(t) \rightarrow y$. *SBasis* are made up of multiple *Linear* elements,
+which store to/from values for each polynomial coefficient.
+
+*SBasis*, like *Linear*, above, fully implements *AddableConcept*,
+*OffsetableConcept*, and *ScalableConcept*.
+
+As *SBasis* is a basic function type, it implements the *FragmentConcept*.
+
+Usually you do not have to directly construct SBasis, as they are obtained
+one way or another, and many of the operations are defined, however, *SBasis*
+may be constructed as an implicit *Linear* cast, as a copy, or as a blank.
+The class is actually an extension of @std::vector<Linear>@. This provides
+the primary method of raw *SBasis* construction -- @push_back(Linear)@, which
+adds another coefficient to the *SBasis*.
+
+*SBasis* also provides the indexing accessor/mutator, and due to its vector
+nature, iteration.
+
+(TODO: wouldn't the indexing be provided by vector any way?)
+
+h3. *SBasis2D*
+
+SBasis2D provides a multivariate form - functions of the form
+$f(u,v) \rightarrow z$. These can be used for arbitrary distortion
+functions (take a path $p(t) \rightarrow (u,v)$ and a pair of surfaces
+$f(u,v),g(u,v)$ and compose: $q(t) = (f(p(t)), g(p(t)))$.
+
+(TODO: flesh out this section)