void mitk::ConnectomicsNetworkCreator::CreateNetworkFromFibersAndSegmentation()
{

  //empty graph
  m_ConNetwork->clear();
  m_LabelToVertexMap.clear();
  m_LabelToNodePropertyMap.clear();

  vtkSmartPointer<vtkPolyData> fiberPolyData = m_FiberBundle->GetFiberPolyData();
  vtkSmartPointer<vtkCellArray> vLines = fiberPolyData->GetLines();
  vLines->InitTraversal();

  int numFibers = m_FiberBundle->GetNumFibers();
  for( int fiberID( 0 ); fiberID < numFibers; fiberID++ )
  {
    vtkIdType   numPointsInCell(0);
    vtkIdType*  pointsInCell(NULL);
    vLines->GetNextCell ( numPointsInCell, pointsInCell );

    TractType::Pointer singleTract = TractType::New();
    for( int pointInCellID( 0 ); pointInCellID < numPointsInCell ; pointInCellID++)
    {
      // push back point
      PointType point = GetItkPoint( fiberPolyData->GetPoint( pointsInCell[ pointInCellID ] ) );
      singleTract->InsertElement( singleTract->Size(), point );
    }

    //MappingStrategy strategy = EndElementPosition;
    //MappingStrategy strategy = JustEndPointVerticesNoLabel;
    MappingStrategy strategy = EndElementPositionAvoidingWhiteMatter;
    if ( singleTract && ( singleTract->Size() > 0 ) )
    {
      AddConnectionToNetwork( 
        ReturnAssociatedVertexPairForLabelPair( 
        ReturnLabelForFiberTract( singleTract, strategy ) 
        ) 
        );
    }
  }

  // Prune unconnected nodes
  m_ConNetwork->PruneUnconnectedSingleNodes();
  // provide network with geometry
  m_ConNetwork->SetGeometry( m_Segmentation->GetGeometry() );
  m_ConNetwork->UpdateBounds();
  m_ConNetwork->SetIsModified( true );

  MBI_INFO << mitk::ConnectomicsConstantsManager::CONNECTOMICS_WARNING_INFO_NETWORK_CREATED;
}
void mitk::ConnectomicsNetworkCreator::CreateNetworkFromFibersAndSegmentation()
{

  //empty graph
  m_ConNetwork = mitk::ConnectomicsNetwork::New();
  m_LabelToVertexMap.clear();
  m_LabelToNodePropertyMap.clear();
  idCounter = 0;

  vtkSmartPointer<vtkPolyData> fiberPolyData = m_FiberBundle->GetFiberPolyData();

  int numFibers = m_FiberBundle->GetNumFibers();
  for( int fiberID( 0 ); fiberID < numFibers; fiberID++ )
  {
    vtkCell* cell = fiberPolyData->GetCell(fiberID);
    int numPoints = cell->GetNumberOfPoints();
    vtkPoints* points = cell->GetPoints();

    TractType::Pointer singleTract = TractType::New();
    for( int pointInCellID( 0 ); pointInCellID < numPoints ; pointInCellID++)
    {
      // push back point
      PointType point = GetItkPoint( points->GetPoint( pointInCellID ) );
      singleTract->InsertElement( singleTract->Size(), point );
    }

    if ( singleTract && ( singleTract->Size() > 0 ) )
    {
      AddConnectionToNetwork(
        ReturnAssociatedVertexPairForLabelPair(
        ReturnLabelForFiberTract( singleTract, m_MappingStrategy )
        )
        );
      m_AbortConnection = false;
    }
  }

  // Prune unconnected nodes
  //m_ConNetwork->PruneUnconnectedSingleNodes();

  // provide network with geometry
  m_ConNetwork->SetGeometry( dynamic_cast<mitk::BaseGeometry*>(m_Segmentation->GetGeometry()->Clone().GetPointer()) );
  m_ConNetwork->UpdateBounds();
  m_ConNetwork->SetIsModified( true );

  MBI_INFO << mitk::ConnectomicsConstantsManager::CONNECTOMICS_WARNING_INFO_NETWORK_CREATED;
}
void mitk::ConnectomicsNetworkCreator::RetractionUntilBrainMatter( bool retractFront, TractType::Pointer singleTract,
                                                                  int & label, itk::Index<3> & mitkIndex )
{
  int retractionStartIndex( singleTract->Size() - 1 );
  int retractionStepIndexSize( -1 );
  int retractionTerminationIndex( 0 );

  if( retractFront )
  {
    retractionStartIndex = 0;
    retractionStepIndexSize = 1;
    retractionTerminationIndex = singleTract->Size() - 1;
  }

  int currentRetractionIndex = retractionStartIndex;

  bool keepRetracting( true );

  mitk::Point3D currentPoint, nextPoint;
  std::vector< double > differenceVector;
  differenceVector.resize( singleTract->front().Size() );

  while( keepRetracting && ( currentRetractionIndex != retractionTerminationIndex ) )
  {
    // convert to segmentation coords
    mitk::Point3D currentPointFiberCoord, nextPointFiberCoord;
    for( unsigned int index = 0; index < singleTract->front().Size(); index++ )
    {
      currentPointFiberCoord.SetElement( index, singleTract->GetElement( currentRetractionIndex ).GetElement( index ) );
      nextPointFiberCoord.SetElement( index, singleTract->GetElement( currentRetractionIndex + retractionStepIndexSize ).GetElement( index ) );
    }

    FiberToSegmentationCoords( currentPointFiberCoord, currentPoint );
    FiberToSegmentationCoords( nextPointFiberCoord, nextPoint );

    // calculate straight line

    for( unsigned int index = 0; index < singleTract->front().Size(); index++ )
    {
      differenceVector[ index ] = nextPoint.GetElement( index ) - currentPoint.GetElement( index );
    }

    // calculate length of direction vector

    double length( 0.0 );
    double sum( 0.0 );

    for( unsigned int index = 0; index < differenceVector.size() ; index++ )
    {
      sum = sum + differenceVector[ index ] * differenceVector[ index ];
    }

    length = std::sqrt( sum );

    // retract
    itk::Index<3> tempIndex;
    int tempLabel( label );

    for( int parameter( 0 ) ; parameter < length ; parameter++ )
    {

      for( int index( 0 ); index < 3; index++ )
      {
        tempIndex.SetElement( index,
          currentPoint.GetElement( index ) + ( 1.0 + parameter ) / ( 1.0 + length ) * differenceVector[ index ] );
      }

      tempLabel = m_SegmentationItk->GetPixel( tempIndex );

      if( !IsBackgroundLabel( tempLabel ) )
      {
        // check whether result is within the search space
        {
          mitk::Point3D endPoint, foundPointSegmentation, foundPointFiber;
          for( unsigned int index = 0; index < singleTract->front().Size(); index++ )
          {
            // this is in fiber (world) coordinates
            endPoint.SetElement( index, singleTract->GetElement( retractionStartIndex ).GetElement( index ) );
          }

          for( int index( 0 ); index < 3; index++ )
          {
            foundPointSegmentation.SetElement( index,
              currentPoint.GetElement( index ) + ( 1.0 + parameter ) / ( 1.0 + length ) * differenceVector[ index ] );
          }

          SegmentationToFiberCoords( foundPointSegmentation, foundPointFiber );

          std::vector< double > finalDistance;
          finalDistance.resize( singleTract->front().Size() );
          for( unsigned int index = 0; index < singleTract->front().Size(); index++ )
          {
            finalDistance[ index ] = foundPointFiber.GetElement( index ) - endPoint.GetElement( index );
          }

          // calculate length of direction vector

          double finalLength( 0.0 );
          double finalSum( 0.0 );

          for( unsigned int index = 0; index < finalDistance.size() ; index++ )
          {
            finalSum = finalSum + finalDistance[ index ] * finalDistance[ index ];
          }
          finalLength = std::sqrt( finalSum );

          if( finalLength > m_EndPointSearchRadius )
          {
            // the found point was not within the search space
            return;
          }
        }

        label = tempLabel;
        mitkIndex = tempIndex;
        return;
      }
      // hit next point without finding brain matter
      currentRetractionIndex = currentRetractionIndex + retractionStepIndexSize;
      if( ( currentRetractionIndex < 1 ) || ( (unsigned int)currentRetractionIndex > ( singleTract->Size() - 2 ) ) )
      {
        keepRetracting = false;
      }
    }
  }
}
void mitk::ConnectomicsNetworkCreator::LinearExtensionUntilGreyMatter(
  std::vector<int> & indexVectorOfPointsToUse,
  TractType::Pointer singleTract,
  int & label,
  itk::Index<3> & mitkIndex )
{
  if( indexVectorOfPointsToUse.size() > singleTract->Size() )
  {
    MBI_WARN << mitk::ConnectomicsConstantsManager::CONNECTOMICS_WARNING_MORE_POINTS_THAN_PRESENT;
    return;
  }

  if( indexVectorOfPointsToUse.size() < 2 )
  {
    MBI_WARN << mitk::ConnectomicsConstantsManager::CONNECTOMICS_WARNING_ESTIMATING_LESS_THAN_2;
    return;
  }

  for( unsigned int index( 0 ); index < indexVectorOfPointsToUse.size(); index++ )
  {
    if( indexVectorOfPointsToUse[ index ] < 0 )
    {
      MBI_WARN << mitk::ConnectomicsConstantsManager::CONNECTOMICS_WARNING_ESTIMATING_BEYOND_START;
      return;
    }
    if( (unsigned int)indexVectorOfPointsToUse[ index ] > singleTract->Size() )
    {
      MBI_WARN << mitk::ConnectomicsConstantsManager::CONNECTOMICS_WARNING_ESTIMATING_BEYOND_END;
      return;
    }
  }

  mitk::Point3D startPoint, endPoint;
  std::vector< double > differenceVector;
  differenceVector.resize( singleTract->front().Size() );

  {
    // which points to use, currently only last two //TODO correct using all points
    int endPointIndex = indexVectorOfPointsToUse.size() - 1;
    int startPointIndex = indexVectorOfPointsToUse.size() - 2;

    // convert to segmentation coords
    mitk::Point3D startFiber, endFiber;
    for( unsigned int index = 0; index < singleTract->front().Size(); index++ )
    {
      endFiber.SetElement( index, singleTract->GetElement( indexVectorOfPointsToUse[ endPointIndex ] ).GetElement( index ) );
      startFiber.SetElement( index, singleTract->GetElement( indexVectorOfPointsToUse[ startPointIndex ] ).GetElement( index ) );
    }

    FiberToSegmentationCoords( endFiber, endPoint );
    FiberToSegmentationCoords( startFiber, startPoint );

    // calculate straight line

    for( unsigned int index = 0; index < singleTract->front().Size(); index++ )
    {
      differenceVector[ index ] = endPoint.GetElement( index ) - startPoint.GetElement( index );
    }

    // normalizing direction vector

    double length( 0.0 );
    double sum( 0.0 );

    for( unsigned int index = 0; index < differenceVector.size() ; index++ )
    {
      sum = sum + differenceVector[ index ] * differenceVector[ index ];
    }

    length = std::sqrt( sum );

    for( unsigned int index = 0; index < differenceVector.size() ; index++ )
    {
      differenceVector[ index ] = differenceVector[ index ] / length;
    }

    // follow line until first non white matter label
    itk::Index<3> tempIndex;
    int tempLabel( label );

    bool keepOn( true );

    itk::ImageRegion<3> itkRegion = m_SegmentationItk->GetLargestPossibleRegion();

    for( int parameter( 0 ) ; keepOn ; parameter++ )
    {
      if( parameter > 1000 )
      {
        MBI_WARN << mitk::ConnectomicsConstantsManager::CONNECTOMICS_WARNING_DID_NOT_FIND_WHITE;
        break;
      }

      for( int index( 0 ); index < 3; index++ )
      {
        tempIndex.SetElement( index, endPoint.GetElement( index ) + parameter * differenceVector[ index ] );
      }

      if( itkRegion.IsInside( tempIndex ) )
      {
        tempLabel = m_SegmentationItk->GetPixel( tempIndex );
      }
      else
      {
        tempLabel = -1;
      }

      if( IsNonWhiteMatterLabel( tempLabel ) )
      {
        if( tempLabel < 1 )
        {
          keepOn = false;
          //MBI_WARN << mitk::ConnectomicsConstantsManager::CONNECTOMICS_WARNING_NOT_EXTEND_TO_WHITE;
        }
        else
        {
          label = tempLabel;
          mitkIndex = tempIndex;
          keepOn = false;
        }
      }
    }

  }
}
mitk::ConnectomicsNetworkCreator::ImageLabelPairType mitk::ConnectomicsNetworkCreator::EndElementPositionLabelAvoidingWhiteMatter( TractType::Pointer singleTract )
{
  ImageLabelPairType labelpair;

  {// Note: .fib image tracts are safed using index coordinates
    mitk::Point3D firstElementFiberCoord, lastElementFiberCoord;
    mitk::Point3D firstElementSegCoord, lastElementSegCoord;
    itk::Index<3> firstElementSegIndex, lastElementSegIndex;

    if( singleTract->front().Size() != 3 )
    {
      MBI_ERROR << mitk::ConnectomicsConstantsManager::CONNECTOMICS_ERROR_INVALID_DIMENSION_NEED_3;
    }
    for( unsigned int index = 0; index < singleTract->front().Size(); index++ )
    {
      firstElementFiberCoord.SetElement( index, singleTract->front().GetElement( index ) );
      lastElementFiberCoord.SetElement( index, singleTract->back().GetElement( index ) );
    }

    // convert from fiber index coordinates to segmentation index coordinates
    FiberToSegmentationCoords( firstElementFiberCoord, firstElementSegCoord );
    FiberToSegmentationCoords( lastElementFiberCoord, lastElementSegCoord );

    for( int index = 0; index < 3; index++ )
    {
      firstElementSegIndex.SetElement( index, firstElementSegCoord.GetElement( index ) );
      lastElementSegIndex.SetElement( index, lastElementSegCoord.GetElement( index ) );
    }

    int firstLabel = m_SegmentationItk->GetPixel(firstElementSegIndex);
    int lastLabel = m_SegmentationItk->GetPixel(lastElementSegIndex );

    // Check whether the labels belong to the white matter (which means, that the fibers ended early)
    bool extendFront(false), extendEnd(false), retractFront(false), retractEnd(false);
    extendFront = !IsNonWhiteMatterLabel( firstLabel );
    extendEnd = !IsNonWhiteMatterLabel( lastLabel );
    retractFront = IsBackgroundLabel( firstLabel );
    retractEnd = IsBackgroundLabel( lastLabel );

    //if( extendFront || extendEnd )
    //{
    //MBI_INFO << "Before Start: " << firstLabel << " at " << firstElementSegIndex[ 0 ] << " " << firstElementSegIndex[ 1 ] << " " << firstElementSegIndex[ 2 ] << " End: " << lastLabel << " at " << lastElementSegIndex[ 0 ] << " " << lastElementSegIndex[ 1 ] << " " << lastElementSegIndex[ 2 ];
    //}
    if ( extendFront )
    {
      std::vector< int > indexVectorOfPointsToUse;

      //Use first two points for direction
      indexVectorOfPointsToUse.push_back( 1 );
      indexVectorOfPointsToUse.push_back( 0 );

      // label and coordinate temp storage
      int tempLabel( firstLabel );
      itk::Index<3> tempIndex = firstElementSegIndex;

      LinearExtensionUntilGreyMatter( indexVectorOfPointsToUse, singleTract, tempLabel, tempIndex );

      firstLabel = tempLabel;
      firstElementSegIndex = tempIndex;

    }

    if ( extendEnd )
    {
      std::vector< int > indexVectorOfPointsToUse;

      //Use last two points for direction
      indexVectorOfPointsToUse.push_back( singleTract->Size() - 2 );
      indexVectorOfPointsToUse.push_back( singleTract->Size() - 1 );

      // label and coordinate temp storage
      int tempLabel( lastLabel );
      itk::Index<3> tempIndex = lastElementSegIndex;

      LinearExtensionUntilGreyMatter( indexVectorOfPointsToUse, singleTract, tempLabel, tempIndex );

      lastLabel = tempLabel;
      lastElementSegIndex = tempIndex;
    }
        if ( retractFront )
    {
      // label and coordinate temp storage
      int tempLabel( firstLabel );
      itk::Index<3> tempIndex = firstElementSegIndex;

      RetractionUntilBrainMatter( true, singleTract, tempLabel, tempIndex );

      firstLabel = tempLabel;
      firstElementSegIndex = tempIndex;

    }

    if ( retractEnd )
    {
      // label and coordinate temp storage
      int tempLabel( lastLabel );
      itk::Index<3> tempIndex = lastElementSegIndex;

      RetractionUntilBrainMatter( false, singleTract, tempLabel, tempIndex );

      lastLabel = tempLabel;
      lastElementSegIndex = tempIndex;
    }
    //if( extendFront || extendEnd )
    //{
    //    MBI_INFO << "After Start: " << firstLabel << " at " << firstElementSegIndex[ 0 ] << " " << firstElementSegIndex[ 1 ] << " " << firstElementSegIndex[ 2 ] << " End: " << lastLabel << " at " << lastElementSegIndex[ 0 ] << " " << lastElementSegIndex[ 1 ] << " " << lastElementSegIndex[ 2 ];
    //}

    labelpair.first = firstLabel;
    labelpair.second = lastLabel;

    // Add property to property map
    CreateNewNode( firstLabel, firstElementSegIndex, m_UseCoMCoordinates );
    CreateNewNode( lastLabel, lastElementSegIndex, m_UseCoMCoordinates );
  }

  return labelpair;
}
void mitk::ConnectomicsNetworkCreator::RetractionUntilBrainMatter( bool retractFront, TractType::Pointer singleTract, 
                                                                  int & label, mitk::Index3D & mitkIndex )
{
  int retractionStartIndex( singleTract->Size() - 1 );
  int retractionStepIndexSize( -1 );
  int retractionTerminationIndex( 0 );

  if( retractFront )
  {
    retractionStartIndex = 0;
    retractionStepIndexSize = 1;
    retractionTerminationIndex = singleTract->Size() - 1;
  }

  int currentRetractionIndex = retractionStartIndex;

  bool keepRetracting( true );

  mitk::Point3D currentPoint, nextPoint;
  std::vector< double > differenceVector;
  differenceVector.resize( singleTract->front().Size() );

  while( keepRetracting && ( currentRetractionIndex != retractionTerminationIndex ) )
  {
    // convert to segmentation coords
    mitk::Point3D currentPointFiberCoord, nextPointFiberCoord;
    for( int index = 0; index < singleTract->front().Size(); index++ )
    {
      currentPointFiberCoord.SetElement( index, singleTract->GetElement( currentRetractionIndex ).GetElement( index ) );
      nextPointFiberCoord.SetElement( index, singleTract->GetElement( currentRetractionIndex + retractionStepIndexSize ).GetElement( index ) );
    }

    FiberToSegmentationCoords( currentPointFiberCoord, currentPoint );
    FiberToSegmentationCoords( nextPointFiberCoord, nextPoint );

    // calculate straight line

    for( int index = 0; index < singleTract->front().Size(); index++ )
    {
      differenceVector[ index ] = nextPoint.GetElement( index ) - currentPoint.GetElement( index );
    }

    // calculate length of direction vector

    double length( 0.0 );
    double sum( 0.0 );

    for( int index = 0; index < differenceVector.size() ; index++ )
    {
      sum = sum + differenceVector[ index ] * differenceVector[ index ];
    }

    length = std::sqrt( sum );

    // retract
    mitk::Index3D tempIndex;
    int tempLabel( label );

    for( int parameter( 0 ) ; parameter < length ; parameter++ )
    {

      for( int index( 0 ); index < 3; index++ )
      {
        tempIndex.SetElement( index, 
          currentPoint.GetElement( index ) + ( 1.0 + parameter ) / ( 1.0 + length ) * differenceVector[ index ] );
      }

      tempLabel = m_Segmentation->GetPixelValueByIndex( tempIndex );

      if( !IsBackgroundLabel( tempLabel ) )
      {
        label = tempLabel;
        mitkIndex = tempIndex;
        return;
      }
      // hit next point without finding brain matter
      currentRetractionIndex = currentRetractionIndex + retractionStepIndexSize;
      if( ( currentRetractionIndex < 1 ) || ( currentRetractionIndex > ( singleTract->Size() - 2 ) ) )
      {
        keepRetracting = false;
      }
    }
  }
}