diff --git a/Reconstruction/SiliconTracking/src/SpacePointBuilderAlg.cpp b/Reconstruction/SiliconTracking/src/SpacePointBuilderAlg.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d2a9b87c350c0d5f7b9595623c2e1d425430c923
--- /dev/null
+++ b/Reconstruction/SiliconTracking/src/SpacePointBuilderAlg.cpp
@@ -0,0 +1,765 @@
+#include "SpacePointBuilderAlg.h"
+#include "GearSvc/IGearSvc.h"
+#include "TrackSystemSvc/ITrackSystemSvc.h"
+
+#include "UTIL/ILDConf.h"
+//#include "UTIL/LCRelationNavigator.h"
+
+#include "gear/GEAR.h"
+#include "gear/GearParameters.h"
+#include "gear/FTDParameters.h"
+#include "gear/FTDLayerLayout.h"
+#include "gear/ZPlanarParameters.h"
+#include "gear/ZPlanarLayerLayout.h"
+
+#include "gear/gearsurf/MeasurementSurfaceStore.h"
+#include "gear/gearsurf/MeasurementSurface.h"
+#include "gear/gearsurf/ICoordinateSystem.h"
+#include "gear/gearsurf/CartesianCoordinateSystem.h"
+
+#include "CLHEP/Matrix/SymMatrix.h"
+#include "CLHEP/Matrix/Matrix.h"
+
+#include <cmath>
+#include <sstream>
+
+DECLARE_COMPONENT(SpacePointBuilderAlg)
+
+SpacePointBuilderAlg::SpacePointBuilderAlg(const std::string& name, ISvcLocator* svcLoc)
+: GaudiAlgorithm(name, svcLoc) {
+  //declareProperty("HeaderCol", _headerColHdl);
+  declareProperty("MCParticleCollection", _inMCColHdl, "Handle of the Input MCParticle collection");
+  declareProperty("TrackerHitCollection", _inHitColHdl, "Handle of the Input TrackerHits collection");
+  //declareProperty("FTDPixelHitCollection", _inFTDPixelColHdl, "Handle of the Input FTD TrackerHits collection");
+  declareProperty("TrackerHitAssociationCollection", _inHitAssColHdl, "Handle of the Input MCRecoTrackerAssociation collection");
+  //declareProperty("SITHitCollection", _inSITColHdl, "Handle of the Input SIT TrackerHits collection");
+  declareProperty("SpacePointCollection", _outSPColHdl, "Handle of the SpacePoint output collection");
+  declareProperty("SpacePointAssociationCollection", _outSPAssColHdl, "Handle of the SpacePoints association output collection");
+}
+
+StatusCode SpacePointBuilderAlg::initialize() { 
+  debug() << "   init called  " << endmsg;
+  // usually a good idea to
+  _nRun = 0 ;
+  _nEvt = 0 ;
+  
+  _nominal_vertex.set(_nominal_vertex_x, _nominal_vertex_y, _nominal_vertex_z);
+
+  auto gearSvc = service<IGearSvc>("GearSvc");
+  if ( !gearSvc ) {
+    error() << "Failed to find GearSvc ..." << endmsg;
+    return StatusCode::FAILURE;
+  }
+  _GEAR = gearSvc->getGearMgr();
+  
+  //FIXME:SJA: if we want the surface store to be filled we need to create an instance of MarlinTrk implemented with KalTest/KalDet
+  auto _trackSystemSvc = service<ITrackSystemSvc>("TrackSystemSvc");
+  if ( !_trackSystemSvc ) {
+    error() << "Failed to find TrackSystemSvc ..." << endmsg;
+    return StatusCode::FAILURE;
+  }
+
+  MarlinTrk::IMarlinTrkSystem* _trksystem =  _trackSystemSvc->getTrackSystem();
+  _trksystem->init();
+
+  _trackSystemSvc->removeTrackSystem();
+  
+  return GaudiAlgorithm::initialize();
+}
+
+StatusCode SpacePointBuilderAlg::execute(){
+  StatusCode sc;
+  const edm4hep::TrackerHitCollection* hitCol = nullptr;
+  try {
+    hitCol = _inHitColHdl.get();
+  }
+  catch ( GaudiException &e ) {
+    debug() << "Collection " << _inHitColHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg;
+    return sc;
+  }
+
+  const edm4hep::MCRecoTrackerAssociationCollection* hitAssCol = nullptr;
+  try {
+    hitAssCol = _inHitAssColHdl.get();
+  }
+  catch ( GaudiException &e ) {
+    debug() << "Collection " << _inHitAssColHdl.fullKey() << " is unavailable in event " << _nEvt << endmsg;
+    return sc;
+  }
+    
+  if(hitCol!=NULL && hitAssCol!=NULL){
+    unsigned createdSpacePoints = 0;
+    unsigned rawStripHits = 0;
+    unsigned possibleSpacePoints = 0;
+    _nOutOfBoundary = 0;
+    _nStripsTooParallel = 0;
+    _nPlanesNotParallel = 0;
+    
+    edm4hep::TrackerHitCollection* spCol = new edm4hep::TrackerHitCollection();    // output spacepoint collection
+    edm4hep::MCRecoTrackerAssociationCollection* relCol = new edm4hep::MCRecoTrackerAssociationCollection();    // output relation collection
+    
+    // to store the weights
+    //LCFlagImpl lcFlag(0) ;
+    //lcFlag.setBit( LCIO::LCREL_WEIGHTED ) ;
+    //relCol->setFlag( lcFlag.getFlag()  ) ;
+    
+    unsigned nHits = hitCol->size();
+    debug() << "Number of hits: " << nHits << endmsg;
+    
+    //store hits in map according to their CellID0
+    std::map<long long, std::vector<edm4hep::TrackerHit> > map_cellID0_hits;
+    std::map<long long, std::vector<edm4hep::TrackerHit> >::iterator it;
+    for(auto trkHit : *hitCol){
+      debug() << "Add hit with CellID0 = " << trkHit.getCellID() << " " << getCellID0Info( trkHit.getCellID() ) << endmsg;
+      map_cellID0_hits[ trkHit.getCellID() ].push_back( trkHit );
+    }
+    
+    UTIL::BitField64  cellID( UTIL::ILDCellID0::encoder_string );
+    // now loop over all CellID0s
+    for( it= map_cellID0_hits.begin(); it!= map_cellID0_hits.end(); it++ ){
+      rawStripHits += it->second.size();
+      std::vector<edm4hep::TrackerHit>& hitsFront = it->second;
+      unsigned long long cellID0 = it->first;
+      //get the CellID0s at the back of this sensor
+      std::vector<int> cellID0sBack = getCellID0sAtBack( cellID0 );
+      
+      for( unsigned i=0; i< cellID0sBack.size(); i++ ){ 
+        int cellID0Back = cellID0sBack[i];
+        std::vector<edm4hep::TrackerHit>& hitsBack = map_cellID0_hits[ cellID0Back ];
+        debug() << "strips: CellID0 " << cellID0  << " " << getCellID0Info( cellID0 )  << "(" << hitsFront.size()
+		<< " hits) <---> CellID0 " << cellID0Back << getCellID0Info( cellID0Back )
+		<< "(" << hitsBack.size() << " hits)" << endmsg
+		<< "--> " << hitsFront.size() * hitsBack.size() << " possible combinations" << endmsg;
+        
+        possibleSpacePoints += hitsFront.size() * hitsBack.size();
+	// Now iterate over all combinations and store those that make sense
+        for( unsigned ifront=0; ifront<hitsFront.size(); ifront++ ){
+	  edm4hep::TrackerHit& hitFront = hitsFront[ifront];
+	  for( unsigned j=0; j<hitsBack.size(); j++ ){
+	    edm4hep::TrackerHit& hitBack = hitsBack[j];
+
+	    std::vector<edm4hep::ConstSimTrackerHit> simHitsFront;
+	    std::vector<edm4hep::ConstSimTrackerHit> simHitsBack;
+	    for(auto hitAss : *hitAssCol){
+	      if(hitAss.getRec().id()==hitFront.id()) simHitsFront.push_back(hitAss.getSim());
+	      if(hitAss.getRec().id()==hitBack.id()) simHitsBack.push_back(hitAss.getSim());
+	    }
+	    debug() << "attempt to create space point from:" << endmsg;
+            debug() << "   front hit: " << hitFront.id() << " no. of simhit = " << simHitsFront.size() ;
+            if( simHitsFront.size()!=0 ) { 
+	      edm4hep::ConstSimTrackerHit& simhit = simHitsFront[0];
+              debug() << "   first simhit = " << simhit.id() << " mcp = " << simhit.getMCParticle().id() << " (" << simhit.getPosition() << ") " ; 
+            }
+            debug() << endmsg;
+            debug() << "  rear hit: " << hitBack.id() << " no. of simhit = " << simHitsBack.size() ;
+            if( simHitsBack.size()!=0 ) { 
+	      edm4hep::ConstSimTrackerHit& simhit = simHitsBack[0];
+              debug() << "   first simhit = " << simhit.id() << " mcp = "<< simhit.getMCParticle().id() << " (" << simhit.getPosition() << ") " ; 
+            }
+	    debug() << endmsg;
+            
+            bool ghost_hit = true;
+	    if (simHitsFront.size()==1 && simHitsBack.size() == 1) {
+              debug() << "SpacePoint creation from two good hits:" << endmsg;
+	      ghost_hit = simHitsFront[0].getMCParticle().id() != simHitsBack[0].getMCParticle().id();
+	    }
+	    if ( ghost_hit == true ) {
+              debug() << "SpacePoint Ghosthit!" << endmsg;
+            }
+            
+            cellID.setValue( cellID0 );
+	    int subdet = cellID[ UTIL::ILDCellID0::subdet ] ;
+            double strip_length_mm = 0;
+            if (subdet == UTIL::ILDDetID::SIT) {
+	      strip_length_mm = _GEAR->getSITParameters().getDoubleVal("strip_length_mm");
+            }
+	    else if (subdet == UTIL::ILDDetID::SET) {
+              strip_length_mm = _GEAR->getSETParameters().getDoubleVal("strip_length_mm");
+            }
+	    else if (subdet == UTIL::ILDDetID::FTD) {
+              strip_length_mm = _GEAR->getFTDParameters().getDoubleVal("strip_length_mm");
+            }
+	    else {
+	      std::stringstream errorMsg;
+              errorMsg << "SpacePointBuilderAlg::processEvent: unsupported detector ID = " << subdet << ": file " << __FILE__ << " line " << __LINE__ ;
+              throw GaudiException( errorMsg.str(), "CellID not matched", StatusCode::FAILURE );  
+            }
+
+            // add tolerence 
+            strip_length_mm = strip_length_mm * (1.0 + _striplength_tolerance);
+	    try{
+	      edm4hep::TrackerHit spacePoint = createSpacePoint( &hitFront, &hitBack, strip_length_mm);
+
+	      //UTIL::CellIDEncoder<TrackerHitImpl> cellid_encoder( UTIL::ILDCellID0::encoder_string , spCol );
+              //cellid_encoder.setValue( cellID0 ); //give the new hit, the CellID0 of the front hit
+              //cellid_encoder.setCellID( spacePoint ) ;
+	      spacePoint.setCellID(cellID0);
+
+              // store the hits it's composed of:
+              spacePoint.addToRawHits( hitFront.getObjectID() );
+              spacePoint.addToRawHits( hitBack.getObjectID() );
+
+              spacePoint.setType( UTIL::set_bit( spacePoint.getType() ,  UTIL::ILDTrkHitTypeBit::COMPOSITE_SPACEPOINT ) ) ;
+
+              spCol->push_back( spacePoint ); 
+	      //debug() << "push_back space point's id=" << spCol->at(spCol->size()-1).id() << endmsg;
+              createdSpacePoints++;
+              
+              ///////////////////////////////
+              // make the relations
+              if( simHitsFront.size() == 1 ){
+		edm4hep::ConstSimTrackerHit& simHit = simHitsFront[0];
+		edm4hep::MCRecoTrackerAssociation spAss = relCol->create();
+		spAss.setRec(spacePoint);
+		spAss.setSim(simHit);
+		spAss.setWeight( 0.5 );
+              }
+              if( simHitsBack.size() == 1 ){
+		edm4hep::ConstSimTrackerHit& simHit = simHitsBack[0];
+		edm4hep::MCRecoTrackerAssociation spAss = relCol->create();
+                spAss.setRec(spacePoint);
+		spAss.setSim(simHit);
+                spAss.setWeight( 0.5 );
+	      }
+	    }
+	    catch(std::runtime_error& e){
+	      if ( ghost_hit == true ) {
+                debug() << "Ghosthit correctly rejected" << endmsg;
+              }
+	      else {
+                debug() << "True hit rejected!" << endmsg;
+              }
+            }
+          }
+        }
+      }
+    }
+    
+    if(spCol->size()!=0) _outSPColHdl.put(spCol);
+    else                 delete spCol;
+    if(relCol->size()!=0) _outSPAssColHdl.put(relCol);
+    else                  delete relCol;
+    
+    debug() << "\nCreated " << createdSpacePoints << " space points ( raw strip hits: " << rawStripHits << ")\n"
+	    << "  There were " << rawStripHits << " strip hits available, giving " 
+	    << possibleSpacePoints << " possible space points" << endmsg;
+    debug() << "  " << _nStripsTooParallel << " space points couldn't be created, because the strips were too parallel\n"
+	    << "  " << _nPlanesNotParallel << " space points couldn't be created, because the planes of the measurement surfaces where not parallel enough\n"
+	    << "  " << _nOutOfBoundary     << " space points couldn't be created, because the result was outside the sensor boundary\n" << endmsg; 
+  }
+
+  _nEvt ++ ;
+  return sc;
+}
+
+StatusCode SpacePointBuilderAlg::finalize(){
+  info() << "Processed " << _nEvt << " events " << endmsg;
+  return GaudiAlgorithm::finalize();
+}
+
+edm4hep::TrackerHit SpacePointBuilderAlg::createSpacePoint( edm4hep::TrackerHit* a , edm4hep::TrackerHit* b, double stripLength ){
+  
+  const edm4hep::Vector3d& pa = a->getPosition();
+  double xa = pa[0];
+  double ya = pa[1];
+  double za = pa[2];
+  CLHEP::Hep3Vector PA( xa,ya,za );
+  //double du_a = a->getdU();  
+  float du_a = a->getCovMatrix(2);
+  
+  gear::MeasurementSurface const* msA = _GEAR->getMeasurementSurfaceStore().GetMeasurementSurface( a->getCellID() );
+  gear::CartesianCoordinateSystem* ccsA = dynamic_cast< gear::CartesianCoordinateSystem* >( msA->getCoordinateSystem() );
+ 
+  CLHEP::Hep3Vector WA = ccsA->getLocalZAxis(); // the vector W of the local coordinate system the measurement surface has
+  CLHEP::Hep3Vector VA = ccsA->getLocalYAxis(); // the vector V of the local coordinate system the measurement surface has
+  CLHEP::Hep3Vector UA = ccsA->getLocalXAxis(); // the vector U of the local coordinate system the measurement surface has
+  
+  const edm4hep::Vector3d& pb = b->getPosition();
+  double xb = pb[0];
+  double yb = pb[1];
+  double zb = pb[2];
+  CLHEP::Hep3Vector PB( xb,yb,zb );
+  //double du_b = b->getdU();  
+  float du_b = b->getCovMatrix(2);
+
+  gear::MeasurementSurface const* msB = _GEAR->getMeasurementSurfaceStore().GetMeasurementSurface( b->getCellID() );
+  gear::CartesianCoordinateSystem* ccsB = dynamic_cast< gear::CartesianCoordinateSystem* >( msB->getCoordinateSystem() );
+  CLHEP::Hep3Vector WB = ccsB->getLocalZAxis(); // the vector W of the local coordinate system the measurement surface has
+  CLHEP::Hep3Vector VB = ccsB->getLocalYAxis(); // the vector V of the local coordinate system the measurement surface has
+  CLHEP::Hep3Vector UB = ccsB->getLocalXAxis(); // the vector U of the local coordinate system the measurement surface has
+  
+  debug() << "\t ( " << xa << " " << ya << " " << za << " ) <--> ( " << xb << " " << yb << " " << zb << " )" << endmsg;
+  
+  //////////////////////////////////////////////////////////////////////////////////////////////////////
+  // First: check if the two measurement surfaces are parallel (i.e. the w are parallel or antiparallel)
+  double angle = fabs(WB.angle(WA));
+  double angleMax = 1.*M_PI/180.;
+  if(( angle > angleMax )&&( angle < M_PI-angleMax )){
+    _nPlanesNotParallel++;
+    debug() << "\tThe planes of the measurement surfaces are not parallel enough, the angle between the W vectors is " << angle
+	    << " where the angle has to be smaller than " << angleMax << " or bigger than " << M_PI-angleMax << endmsg;
+    throw std::runtime_error(""); //calculate the xing point and if that fails don't create a spacepoint
+  }
+  //////////////////////////////////////////////////////////////////////////////////////////////////////
+ 
+  //////////////////////////////////////////////////////////////////////////////////////////////////////
+  // Next: check if the angle between the strips is not 0
+  angle = fabs(VB.angle(VA));
+  double angleMin= 1.*M_PI/180.;
+  if(( angle < angleMin )||( angle > M_PI-angleMin )){
+    _nStripsTooParallel++;
+    debug() << "\tThe strips (V vectors) of the measurement surfaces are too parallel, the angle between the V vectors is " << angle
+	    << " where the angle has to be between " << angleMax << " or bigger than " << M_PI-angleMin << endmsg;
+    throw std::runtime_error(""); //calculate the xing point and if that fails don't create a spacepoint
+  }
+  //////////////////////////////////////////////////////////////////////////////////////////////////////
+ 
+  //////////////////////////////////////////////////////////////////////////////////////////////////////
+  // Next we want to calculate the crossing point.
+  
+  CLHEP::Hep3Vector point;
+
+//  calculatePointBetweenTwoLines( PA, VA, PB, VB, point );
+//  
+//  // we want to set the space point on the surface of the hit closest to the IP
+//  if (PA.mag2() < PB.mag2()) {
+//    calculatePointBetweenTwoLines( PA, VA, PB, VB, point );
+//  } else {
+//    calculatePointBetweenTwoLines( PB, VB, PA, VA, point );
+//  }
+//  
+//
+//  
+//  streamlog_out( DEBUG2 ) << "\tStandard: Position of space point (global) : ( " << point.x() << " " << point.y() << " " << point.z() << " )\n";
+   
+  CLHEP::Hep3Vector vertex(0.,0.,0.);
+  CLHEP::Hep3Vector L1 = ccsA->getLocalPoint(PA);
+  CLHEP::Hep3Vector L2 = ccsB->getLocalPoint(PB);
+
+  debug() << " L1 = " << L1 << endmsg;
+  debug() << " L2 = " << L2 << endmsg;
+      
+  L1.setY(-stripLength/2.0);
+  CLHEP::Hep3Vector SL1 = L1;
+  L1.setY( stripLength/2.0);
+  CLHEP::Hep3Vector EL1 = L1;
+  
+  
+  L2.setY(-stripLength/2.0);
+  CLHEP::Hep3Vector SL2 = L2;
+  L2.setY( stripLength/2.0);
+  CLHEP::Hep3Vector EL2 = L2;
+  
+  
+  CLHEP::Hep3Vector S1 = ccsA->getGlobalPoint(SL1);
+  CLHEP::Hep3Vector E1 = ccsA->getGlobalPoint(EL1);
+
+  CLHEP::Hep3Vector S2 = ccsB->getGlobalPoint(SL2);
+  CLHEP::Hep3Vector E2 = ccsB->getGlobalPoint(EL2);
+
+  debug() << " stripLength = " << stripLength << endmsg;
+  debug() << " S1 = " << S1 << endmsg;
+  debug() << " E1 = " << E1 << endmsg;
+  debug() << " S2 = " << S2 << endmsg;
+  debug() << " E2 = " << E2 << endmsg;
+
+  point.set(0.0, 0.0, 0.0);
+    
+  int valid_intersection = calculatePointBetweenTwoLines_UsingVertex( S1, E1, S2, E2, vertex, point );
+  
+  if (valid_intersection != 0) {
+    debug() << "\tNo valid intersection for lines" << endmsg;
+    throw std::runtime_error("");
+  }
+  
+  debug() << "\tVertex: Position of space point (global) : ( " << point.x() << " " << point.y() << " " << point.z() << " )" << endmsg;
+  
+  // Check if the new hit is within the boundaries
+  CLHEP::Hep3Vector localPointA = ccsA->getLocalPoint(point);
+  localPointA.setZ(0.);// we set w to 0 so it is in the plane ( we are only interested if u and v are in or out of range, to exclude w from the check it is set to 0)
+  
+  CLHEP::Hep3Vector localPointB = ccsB->getLocalPoint(point);
+  localPointB.setZ(0.);// we set w to 0 so it is in the plane ( we are only interested if u and v are in or out of range, to exclude w from the check it is set to 0)
+  
+  if( !msA->isLocalInBoundary( localPointA ) ){
+    _nOutOfBoundary++;
+    debug() << "\tSpacePoint position lies outside the boundary of the first layer: local coordinates are ( " 
+	    << localPointA.x() << " " << localPointA.y() << " " << localPointA.z() << " )" << endmsg;
+    throw std::runtime_error("");
+  }
+  if( !msB->isLocalInBoundary( localPointB ) ){
+    _nOutOfBoundary++;
+    debug() << "\tSecond hit is out of boundary: local coordinates are ( " 
+	    << localPointB.x() << " " << localPointB.y() << " " << localPointB.z() << " )" << endmsg;
+    throw std::runtime_error("");
+  }
+  
+  //Create the new TrackerHit
+  edm4hep::TrackerHit spacePoint;// = new edm4hep::TrackerHit();
+  
+  edm4hep::Vector3d pos(point.x(), point.y(), point.z());
+  spacePoint.setPosition(pos) ;
+  
+  // set error treating the strips as stereo with equal and opposite rotation -- for reference see Karimaki NIM A 374 p367-370
+
+  // first calculate the covariance matrix in the cartisian coordinate system defined by the sensor 
+  // here we assume that du is the same for both sides
+  
+  if( fabs(du_a - du_b) > 1.0e-06 ){
+    error() << "\tThe measurement errors of the two 1D hits must be equal " << endmsg;    
+    assert( fabs(du_a - du_b) > 1.0e-06 == false );
+    throw std::runtime_error(""); //measurement errors are not equal don't create a spacepoint
+  }
+   
+  double du2 = du_a*du_a;
+  
+  // rotate the strip system back to double-layer wafer system
+  CLHEP::Hep3Vector u_sensor = UA + UB;
+  CLHEP::Hep3Vector v_sensor = VA + VB;
+  CLHEP::Hep3Vector w_sensor = WA + WB;
+  
+  CLHEP::HepRotation rot_sensor( u_sensor, v_sensor, w_sensor );
+  CLHEP::HepMatrix rot_sensor_matrix;
+  rot_sensor_matrix = rot_sensor;
+  
+  double cos2_alpha = VA.cos2Theta(v_sensor) ; // alpha = strip angle   
+  double sin2_alpha = 1 - cos2_alpha ; 
+  
+  CLHEP::HepSymMatrix cov_plane(3,0); // u,v,w
+  
+  cov_plane(1,1) = (0.5 * du2) / cos2_alpha;
+  cov_plane(2,2) = (0.5 * du2) / sin2_alpha;
+  
+  debug() << "\t cov_plane  = " << cov_plane << endmsg;  
+  debug() << "\tstrip_angle = " << VA.angle(VB)/(M_PI/180) / 2.0 << " degrees " << endmsg;
+  
+  CLHEP::HepSymMatrix cov_xyz= cov_plane.similarity(rot_sensor_matrix);
+  
+  debug() << "\t cov_xyz  = " << cov_xyz << endmsg;
+  
+  std::array<float, 6> cov;
+  //EVENT::FloatVec cov( 9 )  ; 
+  int icov = 0 ;
+  for(int irow=0; irow<3; ++irow ){
+    for(int jcol=0; jcol<irow+1; ++jcol){
+      //      std::cout << "row = " << irow << " col = " << jcol << std::endl ;
+      cov[icov] = cov_xyz[irow][jcol] ;
+//      std::cout << "cov["<< icov << "] = " << cov[icov] << std::endl ;
+      ++icov ;
+    }
+  }
+  
+  spacePoint.setCovMatrix(cov);
+  
+  debug() << "\tHit accepted id=" << spacePoint.id() << endmsg;
+  
+  return spacePoint;
+}
+/*
+TrackerHitImpl* SpacePointBuilderAlg::createSpacePointOld( TrackerHitPlane* a , TrackerHitPlane* b ){
+  
+  streamlog_out( DEBUG2 ) << "\t OLD OLD OLD OLD\n";
+  
+  
+  const double* p1 = a->getPosition();
+  double x1 = p1[0];
+  double y1 = p1[1];
+  double z1 = p1[2];
+  const float* v1 = a->getV();
+  float ex1 = cos( v1[1] ) * sin( v1[0] ); 
+  float ey1 = sin( v1[1] ) * sin( v1[0] );
+  
+  const double* p2 = b->getPosition();
+  double x2 = p2[0];
+  double y2 = p2[1];
+  double z2 = p2[2];
+  const float* v2 = b->getV();
+  float ex2 = cos( v2[1] ) * sin( v2[0] ); 
+  float ey2 = sin( v2[1] ) * sin( v2[0] );
+  
+  streamlog_out( DEBUG2 ) << "\t ( " << x1 << " " << y1 << " " << z1 << " ) <--> ( " << x2 << " " << y2 << " " << z2 << " )\n";
+  
+  double x=0.;
+  double y=0.;
+  
+  if ( calculateXingPoint( x1, y1, ex1, ey1, x2, y2, ex2, ey2, x, y ) != 0 ){
+    
+    _nStripsTooParallel++;
+    streamlog_out( DEBUG2 ) << "\tStrips too parallel\n\n";
+    return NULL; //calculate the xing point and if that fails don't create a spacepoint
+  
+  }
+  
+  double z= (z1 + z2)/2.;
+  
+  streamlog_out( DEBUG2 ) << "\tPosition of space point (global) : ( " << x << " " << y << " " << z << " )\n";
+  
+  // Check if the new hit is within the boundary
+  CLHEP::Hep3Vector globalPoint(x,y,z);
+  //  gear::MeasurementSurface* ms = gear::MeasurementSurfaceStore::Instance().GetMeasurementSurface( a->getCellID() );
+  CLHEP::Hep3Vector localPoint = ms->getCoordinateSystem()->getLocalPoint(globalPoint);
+  localPoint.setZ( 0. ); // we set w to 0 so it is in the plane ( we are only interested if u and v are in or out of range, to exclude w from the check it is set to 0)
+  if( !ms->isLocalInBoundary( localPoint ) ){
+    
+    _nOutOfBoundary++;
+    streamlog_out( DEBUG2 ) << "\tHit is out of boundary: local coordinates are ( " 
+      << localPoint.x() << " " << localPoint.y() << " " << localPoint.z() << " )\n\n";
+    
+    return NULL;
+    
+  }
+  
+  
+  //Create the new TrackerHit
+  TrackerHitImpl* spacePoint = new TrackerHitImpl();
+  
+  double pos[3] = {x,y,z};
+  spacePoint->setPosition(  pos  ) ;
+  
+  streamlog_out( DEBUG2 ) << "\tHit accepted\n\n";
+
+  return spacePoint;
+  
+}
+*/
+
+
+
+int SpacePointBuilderAlg::calculatePointBetweenTwoLines_UsingVertex( 
+                                                const CLHEP::Hep3Vector& PA, 
+                                                const CLHEP::Hep3Vector& PB, 
+                                                const CLHEP::Hep3Vector& PC, 
+                                                const CLHEP::Hep3Vector& PD,
+                                                const CLHEP::Hep3Vector& Vertex,
+                                                CLHEP::Hep3Vector& point){
+
+  
+  // A general point on the line joining point PA to point PB is
+  // x, where 2*x=(1+m)*PA + (1-m)*PB. Similarly for 2*y=(1+n)*PC + (1-n)*PD.
+  // Suppose that v is the vertex. Requiring that the two 'general
+  // points' lie on a straight through v means that the vector x-v is a 
+  // multiple of y-v. This condition fixes the parameters m and n.
+  // We then return the 'space-point' x, supposed to be the layer containing PA and PB. 
+  // We require that -1<m<1, otherwise x lies 
+  // outside the segment PA to PB; and similarly for n.
+  
+  bool ok = true;
+  
+//  streamlog_out( DEBUG1 ) << " Vertex = " << Vertex << std::endl; 
+//  
+//  streamlog_out( DEBUG1 ) << " PA = " << PA << std::endl;
+//  streamlog_out( DEBUG1 ) << " PB = " << PB << std::endl;
+//  streamlog_out( DEBUG1 ) << " PC = " << PC << std::endl;
+//  streamlog_out( DEBUG1 ) << " PD = " << PD << std::endl;
+  
+  CLHEP::Hep3Vector VAB(PA-PB);
+  CLHEP::Hep3Vector VCD(PC-PD);
+
+//  streamlog_out( DEBUG1 ) << " VAB = " << VAB << std::endl;
+//  streamlog_out( DEBUG1 ) << " VCD = " << VCD << std::endl;
+  
+  CLHEP::Hep3Vector  s(PA+PB-2*Vertex);   // twice the vector from vertex to midpoint
+  CLHEP::Hep3Vector  t(PC+PD-2*Vertex);   // twice the vector from vertex to midpoint
+
+  CLHEP::Hep3Vector  qs(VAB.cross(s));  
+  CLHEP::Hep3Vector  rt(VCD.cross(t));  
+
+//  streamlog_out( DEBUG1 ) << " s = " << s << std::endl;
+//  streamlog_out( DEBUG1 ) << " t = " << t << std::endl;
+//  streamlog_out( DEBUG1 ) << " qs = " << qs << std::endl;
+//  streamlog_out( DEBUG1 ) << " rt = " << rt << std::endl;
+  
+  
+  double m = (-(s*rt)/(VAB*rt)); // ratio for first line
+    
+  double limit = 1.0;
+  
+  if (m>limit || m<-1.*limit) {
+    debug() << "m' = " << m << endmsg;
+    ok = false;
+  }
+  else {
+    double n = (-(t*qs)/(VCD*qs)); // ratio for second line
+    if (n>limit || n<-1.*limit) {
+      debug() << "n' = " << n << endmsg;
+      ok = false;
+    }
+  }
+  
+  if (ok) {
+    point = 0.5*(PA + PB + m*VAB);
+  }
+  
+  return ok ? 0 : 1;
+}
+
+
+
+int SpacePointBuilderAlg::calculatePointBetweenTwoLines( const CLHEP::Hep3Vector& P1, const CLHEP::Hep3Vector& V1, const CLHEP::Hep3Vector& P2, const CLHEP::Hep3Vector& V2, CLHEP::Hep3Vector& point ){
+  
+  // Richgungsvektor normal auf die anderen beiden:
+  CLHEP::Hep3Vector n = V1.cross( V2 );
+  
+  // Now we want to rotate into a coordinate system, where n is parallel to the z axis
+  // For this: first set phi to 0
+  // then: set theta to 0 (we set phi to 0 first, so we can then rotate arount the y axis)
+  CLHEP::HepRotation rot;
+  rot.rotateZ( -n.phi() );
+  CLHEP::Hep3Vector nPrime = rot * n; //now the phi of nPrime should be 0
+  debug() << "phi of n'' = " << nPrime.phi() << " (it should be 0!!!)\n";
+  rot.rotateY( -n.theta() );
+  nPrime = rot * n;
+  debug() << "phi of n' = " << nPrime.phi() << " (it should be 0!!!)\n";
+  debug() << "theta of n' = " << nPrime.theta() <<  " (it should be 0!!!)" << endmsg;
+  
+  // Now rotate all the vectors and points into this coordinatesystem.
+  CLHEP::Hep3Vector P1prime = rot * P1;
+  CLHEP::Hep3Vector V1prime = rot * V1;
+  CLHEP::Hep3Vector P2prime = rot * P2;
+  CLHEP::Hep3Vector V2prime = rot * V2;
+  
+  // What is the gain of rotating into this system?
+  // A: 
+  double x;
+  double y;
+  int res = calculateXingPoint( P1prime.x(), P1prime.y(), V1prime.x(), V1prime.y(), P2prime.x(), P2prime.y(), V2prime.x(), V2prime.y(), x, y );
+  
+  if ( res != 0 ) return 1;
+  
+  point.setX( x );
+  point.setY( y );
+  point.setZ( (P1prime.z() + P2prime.z())/2. );
+  
+  // Now transform back to the global coordinates
+  point = rot.inverse() * point;
+  
+  return 0;
+}
+
+
+int SpacePointBuilderAlg::calculateXingPoint( double x1, double y1, float ex1, float ey1, double x2, double y2, float ex2, float ey2, double& x, double& y ){
+  float a = (x1*ey1 - y1*ex1) - (x2*ey1 - y2*ex1);
+  float b = ex2*ey1 - ex1*ey2;
+
+  const float epsilon = 0.00001;
+
+  if( fabs(b) < epsilon ) return 1; // if b==0 the two directions e1 and e2 are parallel and there is no crossing!
+
+  float t = a/b;
+
+  x = x2 + t*ex2;
+  y = y2 + t*ey2;
+
+  return 0;
+}
+ 
+ 
+std::vector< int > SpacePointBuilderAlg::getCellID0sAtBack( int cellID0 ){
+  std::vector< int > back;
+  
+  UTIL::BitField64  cellID( UTIL::ILDCellID0::encoder_string );
+  cellID.setValue( cellID0 );
+  
+  int subdet = cellID[ UTIL::ILDCellID0::subdet ] ;
+  
+  if( subdet == UTIL::ILDDetID::FTD ) return getCellID0sAtBackOfFTD( cellID0 );
+  if( subdet == UTIL::ILDDetID::SIT ) return getCellID0sAtBackOfSIT( cellID0 );
+  if( subdet == UTIL::ILDDetID::SET ) return getCellID0sAtBackOfSET( cellID0 );
+  
+  return back;
+}
+
+
+std::vector< int > SpacePointBuilderAlg::getCellID0sAtBackOfFTD( int cellID0 ){
+  std::vector< int > back;
+  
+  const gear::FTDLayerLayout& ftdLayers = _GEAR->getFTDParameters().getFTDLayerLayout();
+  
+  //find out layer, module, sensor
+  UTIL::BitField64  cellID( UTIL::ILDCellID0::encoder_string );
+  cellID.setValue( cellID0 );
+  
+//   int side   = cellID[ UTIL::ILDCellID0::side ];
+//   int module = cellID[ UTIL::ILDCellID0::module ];
+  int sensor = cellID[ UTIL::ILDCellID0::sensor ];
+  int layer  = cellID[ UTIL::ILDCellID0::layer ];
+  
+  //check if sensor is in front
+  if(( ftdLayers.isDoubleSided( layer ) ) && ( sensor <= ftdLayers.getNSensors( layer ) / 2 ) ){
+    cellID[ UTIL::ILDCellID0::sensor ] = sensor + ftdLayers.getNSensors( layer ) / 2; 
+    // it is assumed (according to current gear and mokka), that sensors 1 until n/2 will be on front
+    // and sensor n/2 + 1 until n are at the back
+    // so the sensor x, will have sensor x+n/2 at the back
+    back.push_back( cellID.lowWord() );
+  }
+  return back;
+}
+
+std::vector< int > SpacePointBuilderAlg::getCellID0sAtBackOfSIT( int cellID0 ){
+  std::vector< int > back;
+  
+//   const gear::ZPlanarLayerLayout& sitLayout = _GEAR->getSITParameters().getZPlanarLayerLayout();
+  
+  //find out layer, module, sensor
+  UTIL::BitField64  cellID( UTIL::ILDCellID0::encoder_string );
+  cellID.setValue( cellID0 );
+  
+//   int side   = cellID[ UTIL::ILDCellID0::side ];
+//   int module = cellID[ UTIL::ILDCellID0::module ];
+//   int sensor = cellID[ UTIL::ILDCellID0::sensor ];
+  int layer  = cellID[ UTIL::ILDCellID0::layer ];
+  
+  //check if sensor is in front
+  if( layer%2 == 0 ){ // even layers are front sensors
+    cellID[ UTIL::ILDCellID0::layer ] = layer + 1; 
+    // it is assumed that the even layers are the front layers
+    // and the following odd ones the back layers
+    back.push_back( cellID.lowWord() );
+  }
+  return back;
+}
+
+std::vector< int > SpacePointBuilderAlg::getCellID0sAtBackOfSET( int cellID0 ){
+  std::vector< int > back;
+  
+//   const gear::ZPlanarLayerLayout& setLayout = _GEAR->getSETParameters().getZPlanarLayerLayout();
+  
+  //find out layer, module, sensor
+  UTIL::BitField64  cellID( UTIL::ILDCellID0::encoder_string );
+  cellID.setValue( cellID0 );
+  
+  //   int side   = cellID[ UTIL::ILDCellID0::side ];
+  //   int module = cellID[ UTIL::ILDCellID0::module ];
+  //   int sensor = cellID[ UTIL::ILDCellID0::sensor ];
+  int layer  = cellID[ UTIL::ILDCellID0::layer ];
+  
+  //check if sensor is in front
+  if( layer%2 == 0 ){ // even layers are front sensors
+    cellID[ UTIL::ILDCellID0::layer ] = layer + 1; 
+    // it is assumed that the even layers are the front layers
+    // and the following odd ones the back layers
+    back.push_back( cellID.lowWord() );
+  }
+  return back;
+}
+
+std::string SpacePointBuilderAlg::getCellID0Info( int cellID0 ){
+  std::stringstream s;
+  
+  //find out layer, module, sensor
+  UTIL::BitField64  cellID( UTIL::ILDCellID0::encoder_string );
+  cellID.setValue( cellID0 );
+
+  int subdet = cellID[ UTIL::ILDCellID0::subdet ] ;
+  int side   = cellID[ UTIL::ILDCellID0::side ];
+  int module = cellID[ UTIL::ILDCellID0::module ];
+  int sensor = cellID[ UTIL::ILDCellID0::sensor ];
+  int layer  = cellID[ UTIL::ILDCellID0::layer ];
+  
+  s << "(su" << subdet << ",si" << side << ",la" << layer << ",mo" << module << ",se" << sensor << ")";
+  
+  return s.str();
+}
+
+
+
diff --git a/Reconstruction/SiliconTracking/src/SpacePointBuilderAlg.h b/Reconstruction/SiliconTracking/src/SpacePointBuilderAlg.h
new file mode 100644
index 0000000000000000000000000000000000000000..17cae2394b7e9801ad2cd1a44865da0b28e81ec7
--- /dev/null
+++ b/Reconstruction/SiliconTracking/src/SpacePointBuilderAlg.h
@@ -0,0 +1,185 @@
+#ifndef SpacePointBuilder_h
+#define SpacePointBuilder_h 1
+
+#include "FWCore/DataHandle.h"
+#include "GaudiAlg/GaudiAlgorithm.h"
+//#include "edm4hep/EventHeaderCollection.h"
+#include "edm4hep/MCParticleCollection.h"
+#include "edm4hep/SimTrackerHitCollection.h"
+#include "edm4hep/TrackerHitCollection.h"
+#include "edm4hep/MCRecoTrackerAssociationCollection.h"
+
+#include "CLHEP/Vector/ThreeVector.h"
+
+/** ================= FTD Space Point Builder =================
+ * 
+ * Builds space points for pairs of silicon strip detectors. 
+ * The digitisers create TrackerHitPlanars for the front and the back strips. 
+ * In order to get a spacepoint (as is needed by track reconstruction) those strip measurements need to be combined into one space point.
+ * 
+ * This is done by this processor. 
+ * 
+ *  <h4>Input - Prerequisites</h4>
+ *  
+ * The TrackerHitPlanars as created by the Digitisers of FTD, SET or SIT. 
+ * This could of course be used for other detectors as well, but as information about the detector
+ * is acquired from gear, and as different detectors (at the moment) are stored differently
+ * in gear, used detectors have to be taken care of in the code.
+ *
+ *  <h4>Output</h4> 
+ *  
+ * A collection of TrackerHits containing the constructed space points.
+ * The created hits will store the original strip hits in their rawHits. 
+ * 
+ * @param TrackerHitCollection The name of the input collection of TrackerHits coming from strip detectors on the FTD, SIT or SET <br>
+ * (default name FTDTrackerHits) <br>
+ * 
+ * @param SpacePointsCollection The name of the output collection of the created spacepoints <br>
+ * (default name FTDSpacePoints) <br>
+ * 
+ * @param TrackerHitSimHitRelCollection The name of the input collection of the relations of the TrackerHits to SimHits<br>
+ * (default name FTDTrackerHitRelations)<br>
+ * 
+ * @param SimHitSpacePointRelCollection The name of the SpacePoint SimTrackerHit relation output collection <br>
+ * (default name VTXTrackerHitRelations) <br>
+ * 
+ * @author Robin Glattauer HEPHY, Vienna
+ *
+ */
+
+namespace gear { class GearMgr; }
+
+class SpacePointBuilderAlg : public GaudiAlgorithm {
+ public:
+  
+  SpacePointBuilderAlg(const std::string& name, ISvcLocator* svcLoc);
+  
+  /** Called at the begin of the job before anything is read.
+   * Use to initialize the processor, e.g. book histograms.
+   */
+  virtual StatusCode initialize() ;
+
+  virtual StatusCode execute() ;
+
+  virtual StatusCode finalize() ;
+  
+  //virtual void check( LCEvent * evt ) ; 
+  
+  
+  /** Called after data processing for clean up.
+   */
+  //virtual void end() ;
+  
+ protected:
+  // Input collection
+  DataHandle<edm4hep::MCParticleCollection> _inMCColHdl{"MCParticle", Gaudi::DataHandle::Reader, this};
+  DataHandle<edm4hep::TrackerHitCollection> _inHitColHdl{"FTDStripTrackerHits", Gaudi::DataHandle::Reader, this};
+  DataHandle<edm4hep::MCRecoTrackerAssociationCollection> _inHitAssColHdl{"FTDStripTrackerHitsAssociation", Gaudi::DataHandle::Reader, this};
+  // Output collection
+  DataHandle<edm4hep::TrackerHitCollection> _outSPColHdl{"FTDSpacePoints", Gaudi::DataHandle::Writer, this};
+  DataHandle<edm4hep::MCRecoTrackerAssociationCollection> _outSPAssColHdl{"FTDSpacePointsAssociation", Gaudi::DataHandle::Writer, this};
+  /** Calculates the 2 dimensional crossing point of two lines.
+   * Each line is specified by a point (x,y) and a direction vector (ex,ey).
+   * 
+   * @return 0, if the calculation has been successful, another number if there was a problem.
+   */
+  //static
+    int calculateXingPoint( double x1, double y1, float ex1, float ey1, double x2, double y2, float ex2, float ey2, double& x, double& y );
+ 
+  /** Calculates a point between two lines in a way that it is equidistant from both lines and as close to them as
+   * possible. 
+   * So when you calculate the distance between two lines, and you actually draw this distance as a short connecting 
+   * line, the point in the middle of this line, is what this method finds.
+   * \verbatim
+                  /
+                 /
+                /|___here!!!
+               / |
+     ---------/-------------- (line a)
+             /
+            /(line b)
+    
+     \endverbatim
+   * (If this sketch looks terrible, you probably read this in doxygen and it still needs to be formatted in a
+   * way, that it still looks sensible in doxygen.)
+   * 
+   * @param P1 a point on the first line
+   * @param V1 the direction vector of the first line
+   * 
+   * @param point the reference to a point where the result will be stored
+   */
+  //static
+    int calculatePointBetweenTwoLines( 
+                                           const CLHEP::Hep3Vector& P1, 
+                                           const CLHEP::Hep3Vector& V1, 
+                                           const CLHEP::Hep3Vector& P2, 
+                                           const CLHEP::Hep3Vector& V2, 
+                                           CLHEP::Hep3Vector& point );
+
+  
+  
+  /** Calculates the intersection of a line L and line PAPB ( strip on the first sensor ). 
+   *  L is constrained to pass through the point "Vertex" and bisect both lines PAPB ( strip on the first sensor ) and PCPD ( strip on the second sensor )
+   * @param PA start of the first line
+   * @param PB end of the first line
+   * @param PC start of the second line
+   * @param PD end of the second line
+   * @param Vertex the position 
+   * 
+   * @param point the reference to a point where the result will be stored
+   */
+  //static
+    int calculatePointBetweenTwoLines_UsingVertex( 
+                                                  const CLHEP::Hep3Vector& PA, 
+                                                  const CLHEP::Hep3Vector& PB, 
+                                                  const CLHEP::Hep3Vector& PC, 
+                                                  const CLHEP::Hep3Vector& PD,
+                                                  const CLHEP::Hep3Vector& Vertex,
+                                                  CLHEP::Hep3Vector& point);
+  
+  
+  /** @return a spacepoint (in the form of a TrackerHitImpl* ) created from two TrackerHitPlane* which stand for si-strips */
+  edm4hep::TrackerHit createSpacePoint( edm4hep::TrackerHit* a , edm4hep::TrackerHit* b, double stripLength );
+  
+//   TrackerHitImpl* createSpacePointOld( TrackerHitPlane* a , TrackerHitPlane* b );
+  
+  /** @return the CellID0s of the sensors that are back to back to a given front sensor. If the given sensor
+   * is in the back itself or has no corresponding sensor(s) on the back the vector will be empty.
+   * 
+   * @param cellID0 a CellID0 corresponding to a sensor
+   */
+  std::vector< int > getCellID0sAtBack( int cellID0 );
+  
+  std::vector< int > getCellID0sAtBackOfFTD( int cellID0 );
+  
+  std::vector< int > getCellID0sAtBackOfSET( int cellID0 );
+  
+  std::vector< int > getCellID0sAtBackOfSIT( int cellID0 );
+
+  
+  /** @return information about the contents of the passed CellID0 */ 
+  std::string getCellID0Info( int cellID0 );
+
+  gear::GearMgr* _GEAR;
+
+  int _nRun ;
+  int _nEvt ;
+
+  unsigned _nOutOfBoundary;
+  unsigned _nStripsTooParallel;
+  unsigned _nPlanesNotParallel;
+
+  float _nominal_vertex_x;
+  float _nominal_vertex_y;
+  float _nominal_vertex_z;
+
+  CLHEP::Hep3Vector _nominal_vertex;
+
+  float _striplength_tolerance;
+  
+} ;
+
+#endif
+
+
+