diff --git a/src/algorithms.hpp b/src/algorithms.hpp
index 39df831c26a8c8a0321128a19396ea6a5d092b30..76ac6856eb8bdb5132789d4110d4c785e6e52ec0 100644
--- a/src/algorithms.hpp
+++ b/src/algorithms.hpp
@@ -171,7 +171,7 @@ namespace algorithms{
         }
 
         auto num_child = child_count(parent_index);
-        std::vector<typename C::value_type> branch_index(
+        std::vector<typename C::value_type> branch_runs(
             parent_index.size(), 0
         );
 
@@ -182,16 +182,16 @@ namespace algorithms{
                 ++num_branches;
             }
 
-            branch_index[i] = num_branches;
+            branch_runs[i] = num_branches;
         }
 
-        return branch_index;
+        return branch_runs;
     }
 
     template<typename C>
     std::vector<typename C::value_type> branches_fast(const C &parent_index)
     {
-        return branches<C, false>(parent_index);
+        return branches<C,false>(parent_index);
     }
 
 } // namespace algorithms
diff --git a/src/swcio.cpp b/src/swcio.cpp
index 796972a60e4f8b4ab5fe3595386c91732481295a..f96676449d9526154d4f7d0cd3531da62bba715e 100644
--- a/src/swcio.cpp
+++ b/src/swcio.cpp
@@ -5,7 +5,9 @@
 #include <unordered_set>
 
 #include <algorithms.hpp>
+#include <point.hpp>
 #include <swcio.hpp>
+#include <util.hpp>
 
 namespace nest {
 namespace mc {
@@ -160,10 +162,10 @@ swc_record swc_parser::parse_record(std::istringstream &is)
 {
     auto id = parse_value_strict<int>(is, *this);
     auto type = parse_value_strict<swc_record::kind>(is, *this);
-    auto x = parse_value_strict<float>(is, *this);
-    auto y = parse_value_strict<float>(is, *this);
-    auto z = parse_value_strict<float>(is, *this);
-    auto r = parse_value_strict<float>(is, *this);
+    auto x = parse_value_strict<swc_record::coord_type>(is, *this);
+    auto y = parse_value_strict<swc_record::coord_type>(is, *this);
+    auto z = parse_value_strict<swc_record::coord_type>(is, *this);
+    auto r = parse_value_strict<swc_record::coord_type>(is, *this);
     auto parent_id = parse_value_strict<swc_record::id_type>(is, *this);
 
     // Convert to zero-based, leaving parent_id as-is if -1
@@ -223,11 +225,98 @@ swc_record_range_clean::swc_record_range_clean(std::istream &is)
         parent_list.push_back(records_[i].parent());
     }
 
-    if (!nest::mc::algorithms::is_contiguously_numbered(parent_list)) {
+    if (!nest::mc::algorithms::has_contiguous_segments(parent_list)) {
         throw swc_parse_error("branches are not contiguously numbered", 0);
     }
 }
 
+//
+// Convenience functions for returning the radii and the coordinates of a series
+// of swc records
+//
+static std::vector<swc_record::coord_type>
+swc_radii(const std::vector<swc_record> &records)
+{
+    std::vector<swc_record::coord_type> radii;
+    for (const auto &r : records) {
+        radii.push_back(r.radius());
+    }
+
+    return radii;
+}
+
+static std::vector<nest::mc::point<swc_record::coord_type> >
+swc_points(const std::vector<swc_record> &records)
+{
+    std::vector<nest::mc::point<swc_record::coord_type> > points;
+    for (const auto &r : records) {
+        points.push_back(r.coord());
+    }
+
+    return points;
+}
+
+static void make_cable(cell &cell,
+                       const std::vector<swc_record::id_type> &branch_index,
+                       const std::vector<swc_record> &branch_run)
+{
+    auto new_parent = branch_index[branch_run.back().id()] - 1;
+    cell.add_cable(new_parent, nest::mc::segmentKind::dendrite,
+                   swc_radii(branch_run), swc_points(branch_run));
+}
+
+cell swc_read_cell(std::istream &is)
+{
+    cell newcell;
+    std::vector<swc_record::id_type> parent_list;
+    std::vector<swc_record> swc_records;
+    for (const auto &r : swc_get_records<swc_io_clean>(is)) {
+        swc_records.push_back(r);
+        parent_list.push_back(r.parent());
+    }
+
+    // The parent of soma must be 0
+    if (!parent_list.empty()) {
+        parent_list[0] = 0;
+    }
+
+    auto branch_index = nest::mc::algorithms::branches(parent_list);
+    std::vector<swc_record> branch_run;
+
+    branch_run.reserve(parent_list.size());
+    auto last_branch_point = branch_index[0];
+    for (auto i = 0u; i < swc_records.size(); ++i) {
+        if (branch_index[i] != last_branch_point) {
+            // New branch encountered; add to cell the current one
+            const auto &p = branch_run.back();
+            if (p.parent() == -1) {
+                // This is a soma
+                newcell.add_soma(p.radius(), p.coord());
+                last_branch_point = i;
+            } else {
+                last_branch_point = i - 1;
+                make_cable(newcell, branch_index, branch_run);
+            }
+
+            // Reset the branch run
+            branch_run.clear();
+            if (p.parent() != -1) {
+                // Add parent of the current cell to the branch,
+                // if not branching from soma
+                branch_run.push_back(swc_records[parent_list[i]]);
+            }
+        }
+
+        branch_run.push_back(swc_records[i]);
+    }
+
+    if (!branch_run.empty()) {
+        make_cable(newcell, branch_index, branch_run);
+    }
+
+    return newcell;
+}
+
 } // namespace io
 } // namespace mc
 } // namespace nest
diff --git a/src/swcio.hpp b/src/swcio.hpp
index 6a4af5f8192354f44f769dc74ee21507a8a3f096..a58bbac9aee9a32c03ae9bb33eb9289782a537b2 100644
--- a/src/swcio.hpp
+++ b/src/swcio.hpp
@@ -6,6 +6,9 @@
 #include <string>
 #include <vector>
 
+#include <cell.hpp>
+#include <point.hpp>
+
 namespace nest {
 namespace mc {
 namespace io {
@@ -14,6 +17,7 @@ class swc_record
 {
 public:
     using id_type = int;
+    using coord_type = double;
 
     // More on SWC files: http://research.mssm.edu/cnic/swc.html
     enum class kind {
@@ -29,7 +33,7 @@ public:
 
     // swc records assume zero-based indexing; root's parent remains -1
     swc_record(swc_record::kind type, int id,
-               float x, float y, float z, float r,
+               coord_type x, coord_type y, coord_type z, coord_type r,
                int parent_id)
         : type_(type)
         , id_(id)
@@ -119,41 +123,46 @@ public:
         return parent_id_;
     }
 
-    float x() const
+    coord_type x() const
     {
         return x_;
     }
 
-    float y() const
+    coord_type y() const
     {
         return y_;
     }
 
-    float z() const
+    coord_type z() const
     {
         return z_;
     }
 
-    float radius() const
+    coord_type radius() const
     {
         return r_;
     }
 
-    float diameter() const
+    coord_type diameter() const
     {
         return 2*r_;
     }
 
+    nest::mc::point<coord_type> coord() const
+    {
+        return nest::mc::point<coord_type>(x_, y_, z_);
+    }
+
     void renumber(id_type new_id, std::map<id_type, id_type> &idmap);
 
 private:
     void check_consistency() const;
 
-    kind type_;         // record type
-    id_type id_;        // record id
-    float x_, y_, z_;   // record coordinates
-    float r_;           // record radius
-    id_type parent_id_; // record parent's id
+    kind type_;             // record type
+    id_type id_;            // record id
+    coord_type x_, y_, z_;  // record coordinates
+    coord_type r_;          // record radius
+    id_type parent_id_;     // record parent's id
 };
 
 
@@ -398,11 +407,13 @@ struct swc_io_clean
 };
 
 template<typename T = swc_io_clean>
- typename T::record_range_type swc_get_records(std::istream &is)
+typename T::record_range_type swc_get_records(std::istream &is)
 {
     return typename T::record_range_type(is);
 }
 
+cell swc_read_cell(std::istream &is);
+
 } // namespace io
 } // namespace mc
 } // namespace nest
diff --git a/tests/test_algorithms.cpp b/tests/test_algorithms.cpp
index 05da8c0c41f8aeb39c29f35f65c814542cd1355b..7804bb60e77e80f1a318aca46aad12d977bbdd6b 100644
--- a/tests/test_algorithms.cpp
+++ b/tests/test_algorithms.cpp
@@ -195,9 +195,9 @@ TEST(algorithms, has_contiguous_segments)
     //       1
     //       |
     //       2
-    //      /|\
+    //      /|\.
     //     3 6 5
-    //    /     \
+    //    /     \.
     //   4       7
     //
     EXPECT_FALSE(
@@ -212,9 +212,9 @@ TEST(algorithms, has_contiguous_segments)
     //       1
     //       |
     //       2
-    //      /|\
+    //      /|\.
     //     3 7 5
-    //    /     \
+    //    /     \.
     //   4       6
     //
     EXPECT_TRUE(
@@ -227,11 +227,11 @@ TEST(algorithms, has_contiguous_segments)
     //         0
     //         |
     //         1
-    //        / \
+    //        / \.
     //       2   7
-    //      / \
+    //      / \.
     //     3   5
-    //    /     \
+    //    /     \.
     //   4       6
     //
     EXPECT_TRUE(
@@ -260,17 +260,17 @@ TEST(algorithms, child_count)
     {
         //
         //        0
-        //       /|\
+        //       /|\.
         //      1 4 6
-        //     /  |  \
+        //     /  |  \.
         //    2   5   7
-        //   /         \
+        //   /         \.
         //  3           8
-        //             / \
+        //             / \.
         //            9   11
-        //           /     \
+        //           /     \.
         //          10      12
-        //                   \
+        //                   \.
         //                    13
         //
         std::vector<int> parent_index =
@@ -292,17 +292,17 @@ TEST(algorithms, branches)
     {
         //
         //        0
-        //       /|\
+        //       /|\.
         //      1 4 6
-        //     /  |  \
+        //     /  |  \.
         //    2   5   7
-        //   /         \
+        //   /         \.
         //  3           8
-        //             / \
+        //             / \.
         //            9   11
-        //           /     \
+        //           /     \.
         //          10      12
-        //                   \
+        //                   \.
         //                    13
         //
         std::vector<int> parent_index =
@@ -340,9 +340,9 @@ TEST(algorithms, branches)
         //    1
         //    |
         //    2
-        //   / \
+        //   / \.
         //  3   4
-        //       \
+        //       \.
         //        5
         //
         std::vector<int> parent_index =
diff --git a/tests/test_swcio.cpp b/tests/test_swcio.cpp
index 635ccb442666b3662745a1f02e064bdbf81b5168..17a836c2065b0a56954d26fa3e1297cbfc16de45 100644
--- a/tests/test_swcio.cpp
+++ b/tests/test_swcio.cpp
@@ -3,10 +3,12 @@
 #include <iostream>
 #include <fstream>
 #include <numeric>
+#include <type_traits>
 #include <vector>
 
 #include "gtest.h"
 
+#include <cell.hpp>
 #include <swcio.hpp>
 
 // SWC tests
@@ -250,9 +252,9 @@ TEST(swc_parser, input_cleaning)
         // Check duplicates
         std::stringstream is;
         is << "1 1 14.566132 34.873772 7.857000 0.717830 -1\n";
-        is << "2 1 14.566132 34.873772 7.857000 0.717830 1\n";
-        is << "2 1 14.566132 34.873772 7.857000 0.717830 1\n";
-        is << "2 1 14.566132 34.873772 7.857000 0.717830 1\n";
+        is << "2 2 14.566132 34.873772 7.857000 0.717830 1\n";
+        is << "2 2 14.566132 34.873772 7.857000 0.717830 1\n";
+        is << "2 2 14.566132 34.873772 7.857000 0.717830 1\n";
 
         EXPECT_EQ(2u, swc_get_records<swc_io_clean>(is).size());
     }
@@ -261,9 +263,9 @@ TEST(swc_parser, input_cleaning)
         // Check multiple trees
         std::stringstream is;
         is << "1 1 14.566132 34.873772 7.857000 0.717830 -1\n";
-        is << "2 1 14.566132 34.873772 7.857000 0.717830 1\n";
+        is << "2 2 14.566132 34.873772 7.857000 0.717830 1\n";
         is << "3 1 14.566132 34.873772 7.857000 0.717830 -1\n";
-        is << "4 1 14.566132 34.873772 7.857000 0.717830 1\n";
+        is << "4 2 14.566132 34.873772 7.857000 0.717830 1\n";
 
         auto records = swc_get_records<swc_io_clean>(is);
         EXPECT_EQ(2u, records.size());
@@ -272,9 +274,9 @@ TEST(swc_parser, input_cleaning)
     {
         // Check unsorted input
         std::stringstream is;
-        is << "3 1 14.566132 34.873772 7.857000 0.717830 1\n";
-        is << "2 1 14.566132 34.873772 7.857000 0.717830 1\n";
-        is << "4 1 14.566132 34.873772 7.857000 0.717830 1\n";
+        is << "3 2 14.566132 34.873772 7.857000 0.717830 1\n";
+        is << "2 2 14.566132 34.873772 7.857000 0.717830 1\n";
+        is << "4 2 14.566132 34.873772 7.857000 0.717830 1\n";
         is << "1 1 14.566132 34.873772 7.857000 0.717830 -1\n";
 
         std::array<swc_record::id_type, 4> expected_id_list = {{ 0, 1, 2, 3 }};
@@ -293,11 +295,11 @@ TEST(swc_parser, input_cleaning)
         // Check holes in numbering
         std::stringstream is;
         is << "1 1 14.566132 34.873772 7.857000 0.717830 -1\n";
-        is << "21 1 14.566132 34.873772 7.857000 0.717830 1\n";
-        is << "31 1 14.566132 34.873772 7.857000 0.717830 21\n";
-        is << "41 1 14.566132 34.873772 7.857000 0.717830 21\n";
-        is << "51 1 14.566132 34.873772 7.857000 0.717830 1\n";
-        is << "61 1 14.566132 34.873772 7.857000 0.717830 51\n";
+        is << "21 2 14.566132 34.873772 7.857000 0.717830 1\n";
+        is << "31 2 14.566132 34.873772 7.857000 0.717830 21\n";
+        is << "41 2 14.566132 34.873772 7.857000 0.717830 21\n";
+        is << "51 2 14.566132 34.873772 7.857000 0.717830 1\n";
+        is << "61 2 14.566132 34.873772 7.857000 0.717830 51\n";
 
         std::array<swc_record::id_type, 6> expected_id_list =
             {{ 0, 1, 2, 3, 4, 5 }};
@@ -327,9 +329,9 @@ TEST(swc_record_ranges, raw)
         // Check valid usage
         std::stringstream is;
         is << "1 1 14.566132 34.873772 7.857000 0.717830 -1\n";
-        is << "2 1 14.566132 34.873772 7.857000 0.717830 1\n";
-        is << "3 1 14.566132 34.873772 7.857000 0.717830 1\n";
-        is << "4 1 14.566132 34.873772 7.857000 0.717830 1\n";
+        is << "2 2 14.566132 34.873772 7.857000 0.717830 1\n";
+        is << "3 2 14.566132 34.873772 7.857000 0.717830 1\n";
+        is << "4 2 14.566132 34.873772 7.857000 0.717830 1\n";
 
         std::vector<swc_record> records;
         for (auto c : swc_get_records<swc_io_raw>(is)) {
@@ -381,9 +383,9 @@ TEST(swc_record_ranges, raw)
         // Check parse error context
         std::stringstream is;
         is << "1 1 14.566132 34.873772 7.857000 0.717830 -1\n";
-        is << "2 1 14.566132 34.873772 7.857000 0.717830 1\n";
+        is << "2 2 14.566132 34.873772 7.857000 0.717830 1\n";
         is << "3 10 14.566132 34.873772 7.857000 0.717830 1\n";
-        is << "4 1 14.566132 34.873772 7.857000 0.717830 1\n";
+        is << "4 2 14.566132 34.873772 7.857000 0.717830 1\n";
 
         std::vector<swc_record> records;
         try {
@@ -404,3 +406,84 @@ TEST(swc_record_ranges, raw)
         EXPECT_TRUE(swc_get_records<swc_io_clean>(is).empty());
     }
 }
+
+TEST(swc_io, cell_construction)
+{
+    using namespace nest::mc;
+
+    {
+        //
+        //    0
+        //    |
+        //    1
+        //    |
+        //    2
+        //   / \.
+        //  3   4
+        //       \.
+        //        5
+        //
+
+        std::stringstream is;
+        is << "1 1 0 0 0 2.1 -1\n";
+        is << "2 2 0.1 1.2 1.2 1.3 1\n";
+        is << "3 2 1.0 2.0 2.2 1.1 2\n";
+        is << "4 2 1.5 3.3 1.3 2.2 3\n";
+        is << "5 2 2.5 5.3 2.5 0.7 3\n";
+        is << "6 2 3.5 2.3 3.7 3.4 5\n";
+
+        using point_type = point<double>;
+        std::vector<point_type> points = {
+            { 0.0, 0.0, 0.0 },
+            { 0.1, 1.2, 1.2 },
+            { 1.0, 2.0, 2.2 },
+            { 1.5, 3.3, 1.3 },
+            { 2.5, 5.3, 2.5 },
+            { 3.5, 2.3, 3.7 },
+        };
+
+        cell cell = io::swc_read_cell(is);
+        EXPECT_TRUE(cell.has_soma());
+        EXPECT_EQ(4, cell.num_segments());
+
+        EXPECT_EQ(norm(points[1]-points[2]), cell.cable(1)->length());
+        EXPECT_EQ(norm(points[2]-points[3]), cell.cable(2)->length());
+        EXPECT_EQ(norm(points[2]-points[4]) + norm(points[4]-points[5]),
+                  cell.cable(3)->length());
+
+
+        // Check each segment separately
+        EXPECT_TRUE(cell.segment(0)->is_soma());
+        EXPECT_EQ(2.1, cell.soma()->radius());
+        EXPECT_EQ(point_type(0, 0, 0), cell.soma()->center());
+
+        for (auto i = 1; i < cell.num_segments(); ++i) {
+            EXPECT_TRUE(cell.segment(i)->is_dendrite());
+        }
+
+        EXPECT_EQ(1, cell.cable(1)->num_sub_segments());
+        EXPECT_EQ(1, cell.cable(2)->num_sub_segments());
+        EXPECT_EQ(2, cell.cable(3)->num_sub_segments());
+
+
+        // Check the radii
+        EXPECT_EQ(1.3, cell.cable(1)->radius(0));
+        EXPECT_EQ(1.1, cell.cable(1)->radius(1));
+
+        EXPECT_EQ(1.1, cell.cable(2)->radius(0));
+        EXPECT_EQ(2.2, cell.cable(2)->radius(1));
+
+        EXPECT_EQ(1.1, cell.cable(3)->radius(0));
+        EXPECT_EQ(3.4, cell.cable(3)->radius(1));
+
+        auto len_ratio = norm(points[2]-points[4]) / cell.cable(3)->length();
+        EXPECT_NEAR(.7, cell.cable(3)->radius(len_ratio), 1e-15);
+
+        // Double-check radii at joins are equal
+        EXPECT_EQ(cell.cable(1)->radius(1),
+                  cell.cable(2)->radius(0));
+
+        EXPECT_EQ(cell.cable(1)->radius(1),
+                  cell.cable(3)->radius(0));
+    }
+}
diff --git a/tests/test_tree.cpp b/tests/test_tree.cpp
index 9bb320d1e4cf5f1b0e8b1f5e320384f32935d728..a9b923170e14a42edab6a1deb070cb380e8d2378 100644
--- a/tests/test_tree.cpp
+++ b/tests/test_tree.cpp
@@ -30,8 +30,17 @@ TEST(cell_tree, from_parent_index) {
         EXPECT_EQ(tree.num_segments(), 1u);
         EXPECT_EQ(tree.num_children(0), 0u);
     }
-    // tree with two segments off the root node
+
     {
+        //
+        //        0               0
+        //       / \             / \
+        //      1   4      =>   1   2
+        //     /     \
+        //    2       5
+        //   /
+        //  3
+        //
         std::vector<int> parent_index =
             {0, 0, 1, 2, 0, 4};
         cell_tree tree(parent_index);
@@ -43,9 +52,18 @@ TEST(cell_tree, from_parent_index) {
         EXPECT_EQ(tree.num_children(2), 0u);
     }
     {
-        // tree with three segments off the root node
+        //
+        //        0               0
+        //       /|\             /|\
+        //      1 4 6      =>   1 2 3
+        //     /  |  \
+        //    2   5   7
+        //   /         \
+        //  3           8
+        //
         std::vector<int> parent_index =
             {0, 0, 1, 2, 0, 4, 0, 6, 7, 8};
+
         cell_tree tree(parent_index);
         EXPECT_EQ(tree.num_segments(), 4u);
         // the root has 3 children
@@ -54,9 +72,29 @@ TEST(cell_tree, from_parent_index) {
         EXPECT_EQ(tree.num_children(1), 0u);
         EXPECT_EQ(tree.num_children(2), 0u);
         EXPECT_EQ(tree.num_children(3), 0u);
+
+        // Check new structure
+        EXPECT_EQ(-1, tree.parent(0));
+        EXPECT_EQ(0, tree.parent(1));
+        EXPECT_EQ(0, tree.parent(2));
+        EXPECT_EQ(0, tree.parent(3));
     }
     {
-        // tree with three segments off the root node, and another 2 segments off of the third branch from the root node
+        //
+        //        0               0
+        //       /|\             /|\
+        //      1 4 6      =>   1 2 3
+        //     /  |  \             / \
+        //    2   5   7           4   5
+        //   /         \
+        //  3           8
+        //             / \
+        //            9   11
+        //           /     \
+        //          10     12
+        //                   \
+        //                   13
+        //
         std::vector<int> parent_index =
             {0, 0, 1, 2, 0, 4, 0, 6, 7, 8, 9, 8, 11, 12};
         cell_tree tree(parent_index);
@@ -70,6 +108,14 @@ TEST(cell_tree, from_parent_index) {
         EXPECT_EQ(tree.num_children(2), 0u);
         EXPECT_EQ(tree.num_children(4), 0u);
         EXPECT_EQ(tree.num_children(5), 0u);
+
+        // Check new structure
+        EXPECT_EQ(-1, tree.parent(0));
+        EXPECT_EQ(0, tree.parent(1));
+        EXPECT_EQ(0, tree.parent(2));
+        EXPECT_EQ(0, tree.parent(3));
+        EXPECT_EQ(3, tree.parent(4));
+        EXPECT_EQ(3, tree.parent(5));
     }
     {
         //