diff --git a/Documentation/Examples/cascade_example.cc b/Documentation/Examples/cascade_example.cc
index 5caff6b799fae41ec263c4646127f86df3233d3f..9b664046b1c4fc51dc1e7ceae7795247cf881120 100644
--- a/Documentation/Examples/cascade_example.cc
+++ b/Documentation/Examples/cascade_example.cc
@@ -23,6 +23,7 @@
 
 #include <corsika/cascade/SibStack.h>
 #include <corsika/cascade/sibyll2.3c.h>
+#include <corsika/geometry/Sphere.h>
 #include <corsika/process/sibyll/ParticleConversion.h>
 
 #include <corsika/units/PhysicalUnits.h>
@@ -39,6 +40,7 @@ using namespace corsika::geometry;
 using namespace corsika::environment;
 
 using namespace std;
+using namespace corsika::units::si;
 
 static int fCount = 0;
 
@@ -47,7 +49,7 @@ public:
   ProcessSplit() {}
 
   template <typename Particle>
-  double MinStepLength(Particle& p, setup::Trajectory&) const {
+  double MinStepLength(Particle& p, corsika::setup::Trajectory&) const {
 
     // beam particles for sibyll : 1, 2, 3 for p, pi, k
     // read from cross section code table
@@ -99,7 +101,7 @@ public:
   }
 
   template <typename Particle, typename Stack>
-  EProcessReturn DoContinuous(Particle&, Trajectory&, Stack&) const {
+  EProcessReturn DoContinuous(Particle&, corsika::setup::Trajectory&, Stack&) const {
     // corsika::utls::ignore(p);
     return EProcessReturn::eOk;
   }
@@ -242,12 +244,14 @@ double s_rndm_(int&) {
   return rmng() / (double)rmng.max();
 }
 
-int main() {  
+int main() {
   Environment env;
-  
-  auto theMedium = env.GetUniverse()::CreateNode<Sphere>({Point{env.GetCS(), 0_m, 0_m, 0_m}, 100_km});
-    
-  tracking_line::TrackingLine<setup::Stack> tracking(environment);
+  auto& universe = env.GetUniverse();
+
+  auto theMedium = Environment::CreateNode<Sphere>(
+      Point{env.GetCoordinateSystem(), 0_m, 0_m, 0_m}, 100_km);
+
+  tracking_line::TrackingLine<setup::Stack> tracking(env);
   stack_inspector::StackInspector<setup::Stack> p0(true);
   ProcessSplit p1;
   const auto sequence = p0 + p1;
@@ -257,7 +261,7 @@ int main() {
 
   stack.Clear();
   auto particle = stack.NewParticle();
-  EnergyType E0 = 100_GeV;
+  EnergyType E0 = 1_EeV;
   particle.SetEnergy(E0);
   particle.SetPID(Code::Proton);
   EAS.Init();
diff --git a/Environment/Environment.h b/Environment/Environment.h
index 3c20ba22a5040c2f3916995fb18a0d01c0a8b435..0bc2fa11273b615edaec5089ee5527ecd2808b47 100644
--- a/Environment/Environment.h
+++ b/Environment/Environment.h
@@ -20,11 +20,26 @@ namespace corsika::environment {
 
   class Environment {
   public:
+    using IEnvironmentModel = corsika::setup::IEnvironmentModel;
+
     auto& GetUniverse() { return universe; }
-    auto const& GetCS() const { return corsika::geometry::RootCoordinateSystem::GetInstance().GetRootCS();}
+    auto const& GetCoordinateSystem() const {
+      return corsika::geometry::RootCoordinateSystem::GetInstance().GetRootCS();
+    }
+
+    // factory method for creation of VolumeTreeNodes
+    template <class VolumeType, typename... Args>
+    static auto CreateNode(Args&&... args) {
+      static_assert(std::is_base_of_v<corsika::geometry::Volume, VolumeType>,
+                    "unusable type provided, needs to be derived from "
+                    "\"corsika::geometry::Volume\"");
+
+      return std::make_unique<VolumeTreeNode<IEnvironmentModel>>(
+          std::make_unique<VolumeType>(std::forward<Args>(args)...));
+    }
 
   private:
-    VolumeTreeNode<corsika::setup::IEnvironmentModel>::VTNUPtr universe;
+    VolumeTreeNode<IEnvironmentModel>::VTNUPtr universe;
   };
 
 } // namespace corsika::environment
diff --git a/Environment/IMediumModel.h b/Environment/IMediumModel.h
index a809508315621b652d502a38bbb04a05cd5ced9e..4a1eedd86562187c310d180a4516ee3425a05674 100644
--- a/Environment/IMediumModel.h
+++ b/Environment/IMediumModel.h
@@ -2,6 +2,7 @@
 #define _include_IMediumModel_h
 
 #include <corsika/environment/NuclearComposition.h>
+#include <corsika/geometry/Line.h>
 #include <corsika/geometry/Point.h>
 #include <corsika/geometry/Trajectory.h>
 #include <corsika/units/PhysicalUnits.h>
diff --git a/Environment/VolumeTreeNode.h b/Environment/VolumeTreeNode.h
index 523aebcd265bc455e32b82e202a03630d3323bfe..470bb8aa0c301fc9494417282d9bb32aad181927 100644
--- a/Environment/VolumeTreeNode.h
+++ b/Environment/VolumeTreeNode.h
@@ -102,17 +102,6 @@ namespace corsika::environment {
       return std::make_shared<MediumType>(std::forward<Args>(args)...);
     }
 
-    // factory method for creation of nodes
-    template <class VolumeType, typename... Args>
-    static auto CreateNode(Args&&... args) {
-      static_assert(std::is_base_of_v<corsika::geometry::Volume, VolumeType>,
-                    "unusable type provided, needs to be derived from "
-                    "\"corsika::geometry::Volume\"");
-
-      return std::make_unique<VolumeTreeNode<IModelProperties>>(
-          std::make_unique<VolumeType>(std::forward<Args>(args)...));
-    }
-
   private:
     std::vector<VTNUPtr> fChildNodes;
     std::vector<VolumeTreeNode<IModelProperties> const*> fExcludedNodes;
diff --git a/Framework/Cascade/Cascade.h b/Framework/Cascade/Cascade.h
index e46960dc9c3d8e8c33254c2751a601ab72843a18..8207a036ff159c2d9d05fb8d9fbb69ea1b8e8d68 100644
--- a/Framework/Cascade/Cascade.h
+++ b/Framework/Cascade/Cascade.h
@@ -19,8 +19,6 @@
 
 #include <corsika/setup/SetupTrajectory.h>
 
-using namespace corsika::units::si;
-
 namespace corsika::cascade {
 
   template <typename Tracking, typename ProcessList, typename Stack>
diff --git a/Framework/Cascade/testCascade.cc b/Framework/Cascade/testCascade.cc
index ad4daa2e4df0a554727f1a0584cc88a3af3cff72..5017d5acf48727e167d7a6cba90d8c446b47e6fe 100644
--- a/Framework/Cascade/testCascade.cc
+++ b/Framework/Cascade/testCascade.cc
@@ -9,6 +9,8 @@
  * the license.
  */
 
+#include <corsika/environment/Environment.h>
+
 #include <corsika/cascade/Cascade.h>
 
 #include <corsika/process/ProcessSequence.h>
@@ -35,6 +37,7 @@ using namespace corsika::geometry;
 
 #include <iostream>
 using namespace std;
+using namespace corsika::units::si;
 
 static int fCount = 0;
 
@@ -73,10 +76,10 @@ public:
 private:
 };
 
-
 TEST_CASE("Cascade", "[Cascade]") {
+  corsika::environment::Environment env; // dummy environment
 
-  tracking_line::TrackingLine<setup::Stack> tracking;
+  tracking_line::TrackingLine<setup::Stack> tracking(env);
 
   stack_inspector::StackInspector<setup::Stack> p0(true);
   ProcessSplit p1;
@@ -92,8 +95,8 @@ TEST_CASE("Cascade", "[Cascade]") {
   EnergyType E0 = 100_GeV;
   particle.SetEnergy(E0);
   particle.SetPosition(Point(rootCS, {0_m, 0_m, 10_km}));
-  particle.SetMomentum(
-		       corsika::stack::super_stupid::MomentumVector(rootCS, {0*newton*second, 0*newton*second, -1*newton*second}));
+  particle.SetMomentum(corsika::stack::super_stupid::MomentumVector(
+      rootCS, {0 * newton * second, 0 * newton * second, -1 * newton * second}));
   EAS.Init();
   EAS.Run();
 
diff --git a/Framework/Geometry/Line.h b/Framework/Geometry/Line.h
index 80f6c16bf83e77cc1fb830612ba5b852f1414ab1..a79ba9ce85167ebdf5cef65622e060e844cc22b4 100644
--- a/Framework/Geometry/Line.h
+++ b/Framework/Geometry/Line.h
@@ -33,7 +33,7 @@ namespace corsika::geometry {
     Point GetPosition(corsika::units::si::TimeType t) const { return r0 + v0 * t; }
 
     LengthType ArcLength(corsika::units::si::TimeType t1,
-                               corsika::units::si::TimeType t2) const {
+                         corsika::units::si::TimeType t2) const {
       return v0.norm() * (t2 - t1);
     }
 
@@ -41,6 +41,9 @@ namespace corsika::geometry {
         corsika::units::si::LengthType t) const {
       return t / v0.norm();
     }
+
+    auto GetR0() const { return r0; }
+    auto GetV0() const { return v0; }
   };
 
 } // namespace corsika::geometry
diff --git a/Framework/Geometry/Sphere.h b/Framework/Geometry/Sphere.h
index 3b6c52860e57d3e4814d4a2f5dadf1380f589e23..3e5458b7e2328d062e61307f4c01589c8ee02f05 100644
--- a/Framework/Geometry/Sphere.h
+++ b/Framework/Geometry/Sphere.h
@@ -31,6 +31,9 @@ namespace corsika::geometry {
     bool Contains(Point const& p) const override {
       return fRadius * fRadius > (fCenter - p).squaredNorm();
     }
+
+    auto& GetCenter() const { return fCenter; }
+    auto GetRadius() const { return fRadius; }
   };
 
 } // namespace corsika::geometry
diff --git a/Framework/Geometry/Vector.h b/Framework/Geometry/Vector.h
index cb4e4900544705c10a37ff16a0fd4ba00b0f9b29..904b7039874ec3dbca83692f9316f93a0932201b 100644
--- a/Framework/Geometry/Vector.h
+++ b/Framework/Geometry/Vector.h
@@ -181,6 +181,17 @@ namespace corsika::geometry {
                                                              bareResult);
       }
     }
+
+    template <typename dim2>
+    auto dot(Vector<dim2> pV) const {
+      auto const c1 = GetComponents().eVector;
+      auto const c2 = pV.GetComponents(*BaseVector<dim>::cs).eVector;
+      auto const bareResult = c1.dot(c2);
+
+      using ProdQuantity = phys::units::detail::Product<dim, dim2, double, double>;
+
+      return ProdQuantity(bareResult);
+    }
   };
 
 } // namespace corsika::geometry
diff --git a/Framework/Geometry/testGeometry.cc b/Framework/Geometry/testGeometry.cc
index 63f119fc04f971e3a50fcc14a2faa6e2950fa92a..8130114aacb6c0bbac07b0f42f3d043d704b6c89 100644
--- a/Framework/Geometry/testGeometry.cc
+++ b/Framework/Geometry/testGeometry.cc
@@ -132,7 +132,15 @@ TEST_CASE("Sphere") {
   Point center(rootCS, {0_m, 3_m, 4_m});
   Sphere sphere(center, 5_m);
 
-  SECTION("isInside") {
+  SECTION("GetCenter") {
+    CHECK((sphere.GetCenter().GetCoordinates(rootCS) -
+           QuantityVector<length_d>(0_m, 3_m, 4_m))
+              .norm()
+              .magnitude() == Approx(0).margin(absMargin));
+    CHECK(sphere.GetRadius() / 5_m == Approx(1));
+  }
+
+  SECTION("Contains") {
     REQUIRE_FALSE(sphere.Contains(Point(rootCS, {100_m, 0_m, 0_m})));
     REQUIRE(sphere.Contains(Point(rootCS, {2_m, 3_m, 4_m})));
   }
@@ -154,8 +162,7 @@ TEST_CASE("Trajectories") {
 
     auto const t = 1_s;
     Trajectory<Line> base(line, t);
-    CHECK(line.GetPosition(t).GetCoordinates() ==
-          base.GetPosition(1.).GetCoordinates());
+    CHECK(line.GetPosition(t).GetCoordinates() == base.GetPosition(1.).GetCoordinates());
 
     CHECK(base.ArcLength(1_s, 2_s) / 1_m == Approx(1));
   }
@@ -183,8 +190,7 @@ TEST_CASE("Trajectories") {
 
     auto const t = 1234_s;
     Trajectory<Helix> const base(helix, t);
-    CHECK(helix.GetPosition(t).GetCoordinates() ==
-          base.GetPosition(1.).GetCoordinates());
+    CHECK(helix.GetPosition(t).GetCoordinates() == base.GetPosition(1.).GetCoordinates());
 
     CHECK(base.ArcLength(1_s, 2_s) / 1_m == Approx(5));
   }
diff --git a/Processes/TrackingLine/CMakeLists.txt b/Processes/TrackingLine/CMakeLists.txt
index 2911c9b787787f43ba837e64fd67c89921c699b0..83ed893c150d6d041182bbe7ab9cd30046edb640 100644
--- a/Processes/TrackingLine/CMakeLists.txt
+++ b/Processes/TrackingLine/CMakeLists.txt
@@ -22,17 +22,16 @@ target_include_directories (
 
 install (FILES ${MODEL_HEADERS} DESTINATION include/${MODEL_NAMESPACE})
 
-
-
-# # --------------------
-# # code unit testing
-# add_executable (testStackInspector testStackInspector.cc)
-
-# target_link_libraries (
-#   testStackInspector
-#   CORSIKAunits
-#   CORSIKAthirdparty # for catch2
-#   )
-
-# add_test (NAME testStackInspector COMMAND testStackInspector)
-
+# #-- -- -- -- -- -- -- -- -- --
+# #code unit testing
+add_executable (testTrackingLine testTrackingLine.cc)
+
+target_link_libraries (
+   testTrackingLine
+   CORSIKAunits
+   CORSIKAenvironment
+   CORSIKAgeometry
+   CORSIKAthirdparty # for catch2
+)
+
+add_test (NAME testTrackingLine COMMAND testTrackingLine)
diff --git a/Processes/TrackingLine/TrackingLine.h b/Processes/TrackingLine/TrackingLine.h
index 602d5473269c8e15561967fe9adc8b16ff4dfa0c..386215801676a144dd28a8ab123e12e15981324e 100644
--- a/Processes/TrackingLine/TrackingLine.h
+++ b/Processes/TrackingLine/TrackingLine.h
@@ -1,14 +1,20 @@
 #ifndef _include_corsika_processes_TrackinLine_h_
 #define _include_corsika_processes_TrackinLine_h_
 
-#include <corsika/geometry/Vector.h>
 #include <corsika/geometry/Point.h>
+#include <corsika/geometry/Sphere.h>
+#include <corsika/geometry/Vector.h>
 
 #include <corsika/units/PhysicalUnits.h>
 
+#include <corsika/environment/Environment.h>
 #include <corsika/setup/SetupStack.h>
 #include <corsika/setup/SetupTrajectory.h>
 
+#include <optional>
+
+#include <iostream>
+
 using namespace corsika;
 
 namespace corsika::process {
@@ -16,19 +22,54 @@ namespace corsika::process {
   namespace tracking_line {
 
     template <typename Stack>
-    class TrackingLine { // Newton-step, naja.. not yet
+    class TrackingLine { //
       typedef typename Stack::ParticleType Particle;
 
+      corsika::environment::Environment const& fEnvironment;
+
     public:
+      std::optional<corsika::units::si::TimeType> TimeOfIntersection(
+          geometry::Trajectory<corsika::geometry::Line> const& traj,
+          geometry::Sphere const& sphere) {
+        using namespace corsika::units::si;
+        auto const& cs = fEnvironment.GetCoordinateSystem();
+        geometry::Point const origin(cs, 0_m, 0_m, 0_m);
+
+        auto const r0 = (traj.GetR0() - origin);
+        auto const v0 = traj.GetV0();
+        auto const c0 = (sphere.GetCenter() - origin);
+
+        auto const alpha = r0.dot(v0) - 2 * v0.dot(c0);
+        auto const beta = c0.squaredNorm() + r0.squaredNorm() + 2 * c0.dot(r0) -
+                          sphere.GetRadius() * sphere.GetRadius();
+
+        auto const discriminant = alpha * alpha - 4 * beta * v0.squaredNorm();
+
+        //~ std::cout << "discriminant: " << discriminant << std::endl;
+        //~ std::cout << "alpha: " << alpha << std::endl;
+        //~ std::cout << "beta: " << beta << std::endl;
+
+        if (discriminant.magnitude() > 0) {
+          auto const t = (-alpha - sqrt(discriminant)) / (2 * v0.squaredNorm());
+          return t;
+        } else {
+          return {};
+        }
+      }
+
+      TrackingLine(corsika::environment::Environment const& pEnv)
+          : fEnvironment(pEnv) {}
       void Init() {}
-      setup::Trajectory GetTrack(Particle& p) {
-        geometry::Vector<SpeedType::dimension_type> v = p.GetDirection();
-        geometry::Line traj(p.GetPosition(), v);
+      auto GetTrack(Particle& p) {
+        using namespace corsika::units::si;
+        geometry::Vector<SpeedType::dimension_type> const velocity =
+            p.GetMomentum() / p.GetEnergy() * corsika::units::si::constants::cSquared;
+        geometry::Line traj(p.GetPosition(), velocity);
         return geometry::Trajectory<corsika::geometry::Line>(traj, 100_ns);
       }
     };
 
-  } // namespace stack_inspector
+  } // namespace tracking_line
 
 } // namespace corsika::process
 
diff --git a/Processes/TrackingLine/testTrackingLine.cc b/Processes/TrackingLine/testTrackingLine.cc
new file mode 100644
index 0000000000000000000000000000000000000000..a07101096e13eda22daec046fb3390df03dc9882
--- /dev/null
+++ b/Processes/TrackingLine/testTrackingLine.cc
@@ -0,0 +1,58 @@
+/**
+ * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+ *
+ * See file AUTHORS for a list of contributors.
+ *
+ * This software is distributed under the terms of the GNU General Public
+ * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
+ * the license.
+ */
+
+#include <corsika/environment/Environment.h>
+
+#include <corsika/process/tracking_line/TrackingLine.h>
+
+#include <corsika/geometry/Point.h>
+#include <corsika/geometry/Vector.h>
+#include <corsika/geometry/Sphere.h>
+
+#include <corsika/setup/SetupTrajectory.h>
+using corsika::setup::Trajectory;
+
+#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one
+                          // cpp file
+#include <catch2/catch.hpp>
+
+using namespace corsika;
+using namespace corsika::process;
+using namespace corsika::units;
+using namespace corsika::geometry;
+
+#include <iostream>
+using namespace std;
+using namespace corsika::units::si;
+
+
+TEST_CASE("TrackingLine") {
+  corsika::environment::Environment env; // dummy environment
+  auto const& cs = env.GetCoordinateSystem();
+  
+  tracking_line::TrackingLine<setup::Stack> tracking(env);
+
+  SECTION("intersection with sphere") {
+    Point const origin(cs, {0_m, 0_m, 0_m});
+    Point const center(cs, {0_m, 0_m, 10_m});
+    Sphere const sphere(center, 1_m);
+    Vector<corsika::units::si::SpeedType::dimension_type> v(cs, 0_m/second, 0_m/second, 1_m/second);
+    Line line(origin, v);
+    
+    geometry::Trajectory<Line> traj(line, 12345_s);
+    
+    auto const opt = tracking.TimeOfIntersection(traj, Sphere(Point(cs, {0_m, 0_m, 10_m}), 1_m));
+    REQUIRE(opt.has_value());
+    REQUIRE(opt.value() / 9_s == Approx(1));
+    
+    auto const optNoIntersection = tracking.TimeOfIntersection(traj, Sphere(Point(cs, {5_m, 0_m, 10_m}), 1_m));
+    REQUIRE_FALSE(optNoIntersection.has_value());
+  }
+}