void mitk::PlaneGeometryDataMapper2D::CreateVtkCrosshair(mitk::BaseRenderer *renderer)
{
  bool visible = true;
  LocalStorage* ls = m_LSH.GetLocalStorage(renderer);
  ls->m_CrosshairActor->SetVisibility(0);
  ls->m_ArrowActor->SetVisibility(0);
  ls->m_CrosshairHelperLineActor->SetVisibility(0);

  GetDataNode()->GetVisibility(visible, renderer, "visible");

  if(!visible)
  {
    return;
  }

  PlaneGeometryData::Pointer input = const_cast< PlaneGeometryData * >(this->GetInput());
  mitk::DataNode* geometryDataNode = renderer->GetCurrentWorldPlaneGeometryNode();
  const PlaneGeometryData* rendererWorldPlaneGeometryData = dynamic_cast< PlaneGeometryData * >(geometryDataNode->GetData());

  // intersecting with ourself?
  if ( input.IsNull() || input.GetPointer() == rendererWorldPlaneGeometryData)
  {
    return; //nothing to do in this case
  }

  const PlaneGeometry *inputPlaneGeometry = dynamic_cast< const PlaneGeometry * >( input->GetPlaneGeometry() );

  const PlaneGeometry* worldPlaneGeometry = dynamic_cast< const PlaneGeometry* >(
        rendererWorldPlaneGeometryData->GetPlaneGeometry() );

  if ( worldPlaneGeometry && dynamic_cast<const AbstractTransformGeometry*>(worldPlaneGeometry)==NULL
       && inputPlaneGeometry && dynamic_cast<const AbstractTransformGeometry*>(input->GetPlaneGeometry() )==NULL
       && inputPlaneGeometry->GetReferenceGeometry() )
  {
    const BaseGeometry *referenceGeometry = inputPlaneGeometry->GetReferenceGeometry();

    // calculate intersection of the plane data with the border of the
    // world geometry rectangle
    Point3D point1, point2;

    Line3D crossLine;

    // Calculate the intersection line of the input plane with the world plane
    if ( worldPlaneGeometry->IntersectionLine( inputPlaneGeometry, crossLine ) )
    {
      Point3D boundingBoxMin, boundingBoxMax;
      boundingBoxMin = referenceGeometry->GetCornerPoint(0);
      boundingBoxMax = referenceGeometry->GetCornerPoint(7);

      Point3D indexLinePoint;
      Vector3D indexLineDirection;

      referenceGeometry->WorldToIndex(crossLine.GetPoint(),indexLinePoint);
      referenceGeometry->WorldToIndex(crossLine.GetDirection(),indexLineDirection);

      referenceGeometry->WorldToIndex(boundingBoxMin,boundingBoxMin);
      referenceGeometry->WorldToIndex(boundingBoxMax,boundingBoxMax);

      // Then, clip this line with the (transformed) bounding box of the
      // reference geometry.
      Line3D::BoxLineIntersection(
            boundingBoxMin[0], boundingBoxMin[1], boundingBoxMin[2],
          boundingBoxMax[0], boundingBoxMax[1], boundingBoxMax[2],
          indexLinePoint, indexLineDirection,
          point1, point2 );

      referenceGeometry->IndexToWorld(point1,point1);
      referenceGeometry->IndexToWorld(point2,point2);
      crossLine.SetPoints(point1,point2);

      vtkSmartPointer<vtkCellArray> lines = vtkSmartPointer<vtkCellArray>::New();
      vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
      vtkSmartPointer<vtkPolyData> linesPolyData = vtkSmartPointer<vtkPolyData>::New();


      // Now iterate through all other lines displayed in this window and
      // calculate the positions of intersection with the line to be
      // rendered; these positions will be stored in lineParams to form a
      // gap afterwards.
      NodesVectorType::iterator otherPlanesIt = m_OtherPlaneGeometries.begin();
      NodesVectorType::iterator otherPlanesEnd = m_OtherPlaneGeometries.end();

      std::vector<Point3D> intersections;

      intersections.push_back(point1);

      otherPlanesIt = m_OtherPlaneGeometries.begin();
      int gapsize = 32;
      this->GetDataNode()->GetPropertyValue( "Crosshair.Gap Size",gapsize, NULL );


      ScalarType lineLength = point1.EuclideanDistanceTo(point2);
      DisplayGeometry *displayGeometry = renderer->GetDisplayGeometry();

      ScalarType gapinmm = gapsize * displayGeometry->GetScaleFactorMMPerDisplayUnit();

      float gapSizeParam = gapinmm / lineLength;

      while ( otherPlanesIt != otherPlanesEnd )
      {
        PlaneGeometry *otherPlane = static_cast< PlaneGeometry * >(
              static_cast< PlaneGeometryData * >((*otherPlanesIt)->GetData() )->GetPlaneGeometry() );

        if (otherPlane != inputPlaneGeometry && otherPlane != worldPlaneGeometry)
        {
          Point3D planeIntersection;
          otherPlane->IntersectionPoint(crossLine,planeIntersection);
          ScalarType sectionLength = point1.EuclideanDistanceTo(planeIntersection);
          ScalarType lineValue = sectionLength/lineLength;
          if(lineValue-gapSizeParam > 0.0)
            intersections.push_back(crossLine.GetPoint(lineValue-gapSizeParam));
          else intersections.pop_back();
          if(lineValue+gapSizeParam < 1.0)
            intersections.push_back(crossLine.GetPoint(lineValue+gapSizeParam));
        }
        ++otherPlanesIt;
      }
      if(intersections.size()%2 == 1)
        intersections.push_back(point2);

      if(intersections.empty())
      {
        this->DrawLine(point1,point2,lines,points);
      }
      else
        for(unsigned int i = 0 ; i< intersections.size()-1 ; i+=2)
        {
          this->DrawLine(intersections[i],intersections[i+1],lines,points);
        }

      // Add the points to the dataset
      linesPolyData->SetPoints(points);
      // Add the lines to the dataset
      linesPolyData->SetLines(lines);

      Vector3D orthogonalVector;
      orthogonalVector = inputPlaneGeometry->GetNormal();
      worldPlaneGeometry->Project(orthogonalVector,orthogonalVector);
      orthogonalVector.Normalize();

      // Visualize
      ls->m_Mapper->SetInputData(linesPolyData);
      ls->m_CrosshairActor->SetMapper(ls->m_Mapper);

      // Determine if we should draw the area covered by the thick slicing, default is false.
      // This will also show the area of slices that do not have thick slice mode enabled
      bool showAreaOfThickSlicing = false;
      GetDataNode()->GetBoolProperty( "reslice.thickslices.showarea", showAreaOfThickSlicing );

      // determine the pixelSpacing in that direction
      double thickSliceDistance = SlicedGeometry3D::CalculateSpacing( referenceGeometry->GetSpacing(), orthogonalVector );

      IntProperty *intProperty=0;
      if( GetDataNode()->GetProperty( intProperty, "reslice.thickslices.num" ) && intProperty )
        thickSliceDistance *= intProperty->GetValue()+0.5;
      else
        showAreaOfThickSlicing = false;

      // not the nicest place to do it, but we have the width of the visible bloc in MM here
      // so we store it in this fancy property
      GetDataNode()->SetFloatProperty( "reslice.thickslices.sizeinmm", thickSliceDistance*2 );

      ls->m_CrosshairActor->SetVisibility(1);

      vtkSmartPointer<vtkPolyData> arrowPolyData = vtkSmartPointer<vtkPolyData>::New();
      ls->m_Arrowmapper->SetInputData(arrowPolyData);
      if(this->m_RenderOrientationArrows)
      {
        ScalarType triangleSizeMM = 7.0 * displayGeometry->GetScaleFactorMMPerDisplayUnit();

        vtkSmartPointer<vtkCellArray> triangles = vtkSmartPointer<vtkCellArray>::New();
        vtkSmartPointer<vtkPoints> triPoints = vtkSmartPointer<vtkPoints>::New();

        DrawOrientationArrow(triangles,triPoints,triangleSizeMM,orthogonalVector,point1,point2);
        DrawOrientationArrow(triangles,triPoints,triangleSizeMM,orthogonalVector,point2,point1);
        arrowPolyData->SetPoints(triPoints);
        arrowPolyData->SetPolys(triangles);
        ls->m_ArrowActor->SetVisibility(1);
      }

      // Visualize
      vtkSmartPointer<vtkPolyData> helperlinesPolyData = vtkSmartPointer<vtkPolyData>::New();
      ls->m_HelperLinesmapper->SetInputData(helperlinesPolyData);
      if ( showAreaOfThickSlicing )
      {
        vtkSmartPointer<vtkCellArray> helperlines = vtkSmartPointer<vtkCellArray>::New();
        // vectorToHelperLine defines how to reach the helperLine from the mainLine
        // got the right direction, so we multiply the width
        Vector3D vecToHelperLine = orthogonalVector * thickSliceDistance;

        this->DrawLine(point1 - vecToHelperLine, point2 - vecToHelperLine,helperlines,points);
        this->DrawLine(point1 + vecToHelperLine, point2 + vecToHelperLine,helperlines,points);

        // Add the points to the dataset
        helperlinesPolyData->SetPoints(points);

        // Add the lines to the dataset
        helperlinesPolyData->SetLines(helperlines);

        ls->m_CrosshairActor->GetProperty()->SetLineStipplePattern(0xf0f0);
        ls->m_CrosshairActor->GetProperty()->SetLineStippleRepeatFactor(1);
        ls->m_CrosshairHelperLineActor->SetVisibility(1);
      }
    }
  }
}
Пример #2
0
  void PlaneGeometryDataVtkMapper3D::GenerateDataForRenderer(BaseRenderer* renderer)
  {
    SetVtkMapperImmediateModeRendering(m_EdgeMapper);
    SetVtkMapperImmediateModeRendering(m_BackgroundMapper);

    // Remove all actors from the assembly, and re-initialize it with the
    // edge actor
    m_ImageAssembly->GetParts()->RemoveAllItems();

    bool visible = true;
    GetDataNode()->GetVisibility(visible, renderer, "visible");

    if ( !visible )
    {
      // visibility has explicitly to be set in the single actors
      // due to problems when using cell picking:
      // even if the assembly is invisible, the renderer contains
      // references to the assemblies parts. During picking the
      // visibility of each part is checked, and not only for the
      // whole assembly.
      m_ImageAssembly->VisibilityOff();
      m_EdgeActor->VisibilityOff();
      return;
    }

    // visibility has explicitly to be set in the single actors
    // due to problems when using cell picking:
    // even if the assembly is invisible, the renderer contains
    // references to the assemblies parts. During picking the
    // visibility of each part is checked, and not only for the
    // whole assembly.
    m_ImageAssembly->VisibilityOn();
    bool drawEdges = true;
    this->GetDataNode()->GetBoolProperty("draw edges", drawEdges, renderer);
    m_EdgeActor->SetVisibility(drawEdges);

    PlaneGeometryData::Pointer input = const_cast< PlaneGeometryData * >(this->GetInput());

    if (input.IsNotNull() && (input->GetPlaneGeometry() != NULL))
    {
      SmartPointerProperty::Pointer surfacecreatorprop;
      surfacecreatorprop = dynamic_cast< SmartPointerProperty * >(GetDataNode()->GetProperty("surfacegeometry", renderer));

      if ( (surfacecreatorprop.IsNull())
        || (surfacecreatorprop->GetSmartPointer().IsNull())
        || ((m_SurfaceCreator = dynamic_cast<PlaneGeometryDataToSurfaceFilter*>
             (surfacecreatorprop->GetSmartPointer().GetPointer())).IsNull() ) )
        {
        m_SurfaceCreator->PlaceByGeometryOn();
        surfacecreatorprop = SmartPointerProperty::New( m_SurfaceCreator );
        GetDataNode()->SetProperty("surfacegeometry", surfacecreatorprop);
      }

      m_SurfaceCreator->SetInput(input);

      int res;
      if (GetDataNode()->GetIntProperty("xresolution", res, renderer))
      {
        m_SurfaceCreator->SetXResolution(res);
      }
      if (GetDataNode()->GetIntProperty("yresolution", res, renderer))
      {
        m_SurfaceCreator->SetYResolution(res);
      }

      double tubeRadius = 1.0; // Radius of tubular edge surrounding plane

      // Clip the PlaneGeometry with the reference geometry bounds (if available)
      if ( input->GetPlaneGeometry()->HasReferenceGeometry() )
      {
        BaseGeometry *referenceGeometry =
            input->GetPlaneGeometry()->GetReferenceGeometry();

        BoundingBox::PointType boundingBoxMin, boundingBoxMax;
        boundingBoxMin = referenceGeometry->GetBoundingBox()->GetMinimum();
        boundingBoxMax = referenceGeometry->GetBoundingBox()->GetMaximum();

        if ( referenceGeometry->GetImageGeometry() )
        {
          for ( unsigned int i = 0; i < 3; ++i )
          {
            boundingBoxMin[i] -= 0.5;
            boundingBoxMax[i] -= 0.5;
          }
        }

        m_SurfaceCreatorPointsContainer->CreateElementAt( 0 ) = boundingBoxMin;
        m_SurfaceCreatorPointsContainer->CreateElementAt( 1 ) = boundingBoxMax;

        m_SurfaceCreatorBoundingBox->ComputeBoundingBox();

        m_SurfaceCreator->SetBoundingBox( m_SurfaceCreatorBoundingBox );

        tubeRadius = referenceGeometry->GetDiagonalLength() / 450.0;
      }

      // If no reference geometry is available, clip with the current global
      // bounds
      else if (m_DataStorage.IsNotNull())
      {
        m_SurfaceCreator->SetBoundingBox(m_DataStorage->ComputeVisibleBoundingBox(NULL, "includeInBoundingBox"));
        tubeRadius = sqrt( m_SurfaceCreator->GetBoundingBox()->GetDiagonalLength2() ) / 450.0;
      }

      // Calculate the surface of the PlaneGeometry
      m_SurfaceCreator->Update();
      Surface *surface = m_SurfaceCreator->GetOutput();

      // Check if there's something to display, otherwise return
      if ( (surface->GetVtkPolyData() == 0 )
        || (surface->GetVtkPolyData()->GetNumberOfCells() == 0) )
        {
        m_ImageAssembly->VisibilityOff();
        return;
      }

      // add a graphical representation of the surface normals if requested
      DataNode* node = this->GetDataNode();
      bool displayNormals = false;
      bool colorTwoSides = false;
      bool invertNormals = false;
      node->GetBoolProperty("draw normals 3D", displayNormals, renderer);
      node->GetBoolProperty("color two sides", colorTwoSides, renderer);
      node->GetBoolProperty("invert normals", invertNormals, renderer);

      //if we want to draw the display normals or render two sides we have to get the colors
      if( displayNormals || colorTwoSides )
      {
        //get colors
        float frontColor[3] = { 0.0, 0.0, 1.0 };
        node->GetColor( frontColor, renderer, "front color" );
        float backColor[3] = { 1.0, 0.0, 0.0 };
        node->GetColor( backColor, renderer, "back color" );

        if ( displayNormals )
        {
          m_NormalsTransformer->SetInputData( surface->GetVtkPolyData() );
          m_NormalsTransformer->SetTransform(node->GetVtkTransform(this->GetTimestep()) );

          m_FrontHedgeHog->SetInputConnection(m_NormalsTransformer->GetOutputPort() );
          m_FrontHedgeHog->SetVectorModeToUseNormal();
          m_FrontHedgeHog->SetScaleFactor( invertNormals ? 1.0 : -1.0 );
          m_FrontHedgeHog->Update();

          m_FrontNormalsActor->GetProperty()->SetColor( frontColor[0], frontColor[1], frontColor[2] );

          m_BackHedgeHog->SetInputConnection( m_NormalsTransformer->GetOutputPort() );
          m_BackHedgeHog->SetVectorModeToUseNormal();
          m_BackHedgeHog->SetScaleFactor( invertNormals ? -1.0 : 1.0 );
          m_BackHedgeHog->Update();

          m_BackNormalsActor->GetProperty()->SetColor( backColor[0], backColor[1], backColor[2] );

          //if there is no actor added yet, add one
          if ( !m_NormalsActorAdded )
          {
            m_Prop3DAssembly->AddPart( m_FrontNormalsActor );
            m_Prop3DAssembly->AddPart( m_BackNormalsActor );
            m_NormalsActorAdded = true;
          }
        }
        //if we don't want to display normals AND there is an actor added remove the actor
        else if ( m_NormalsActorAdded )
        {
          m_Prop3DAssembly->RemovePart( m_FrontNormalsActor );
          m_Prop3DAssembly->RemovePart( m_BackNormalsActor );
          m_NormalsActorAdded = false;
        }

        if ( colorTwoSides )
        {
          if ( !invertNormals )
          {
            m_BackgroundActor->GetProperty()->SetColor( backColor[0], backColor[1], backColor[2] );
            m_BackgroundActor->GetBackfaceProperty()->SetColor( frontColor[0], frontColor[1], frontColor[2] );
          }
          else
          {
            m_BackgroundActor->GetProperty()->SetColor( frontColor[0], frontColor[1], frontColor[2] );
            m_BackgroundActor->GetBackfaceProperty()->SetColor( backColor[0], backColor[1], backColor[2] );
          }
        }
      }

      // Add black background for all images (which may be transparent)
      m_BackgroundMapper->SetInputData( surface->GetVtkPolyData() );
      m_ImageAssembly->AddPart( m_BackgroundActor );

      LayerSortedActorList layerSortedActors;

      // Traverse the data tree to find nodes resliced by ImageMapperGL2D
      //use a predicate to get all data nodes which are "images" or inherit from mitk::Image
      mitk::TNodePredicateDataType< mitk::Image >::Pointer predicateAllImages = mitk::TNodePredicateDataType< mitk::Image >::New();
      mitk::DataStorage::SetOfObjects::ConstPointer all = m_DataStorage->GetSubset(predicateAllImages);
      //process all found images
      for (mitk::DataStorage::SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it)
      {

        DataNode *node = it->Value();
        if (node != NULL)
          this->ProcessNode(node, renderer, surface, layerSortedActors);
      }

      // Add all image actors to the assembly, sorted according to
      // layer property
      LayerSortedActorList::iterator actorIt;
      for ( actorIt = layerSortedActors.begin(); actorIt != layerSortedActors.end(); ++actorIt )
      {
        m_ImageAssembly->AddPart( actorIt->second );
      }

      // Configurate the tube-shaped frame: size according to the surface
      // bounds, color as specified in the plane's properties
      vtkPolyData *surfacePolyData = surface->GetVtkPolyData();
      m_Cleaner->SetInputData(surfacePolyData);
      m_EdgeTransformer->SetTransform(this->GetDataNode()->GetVtkTransform(this->GetTimestep()) );

      // Adjust the radius according to extent
      m_EdgeTuber->SetRadius( tubeRadius );

      // Get the plane's color and set the tube properties accordingly
      ColorProperty::Pointer colorProperty;
      colorProperty = dynamic_cast<ColorProperty*>(this->GetDataNode()->GetProperty( "color" ));
      if ( colorProperty.IsNotNull() )
      {
        const Color& color = colorProperty->GetColor();
        m_EdgeActor->GetProperty()->SetColor(color.GetRed(), color.GetGreen(), color.GetBlue());
      }
      else
      {
        m_EdgeActor->GetProperty()->SetColor( 1.0, 1.0, 1.0 );
      }

      m_ImageAssembly->SetUserTransform(this->GetDataNode()->GetVtkTransform(this->GetTimestep()) );
    }

    VtkRepresentationProperty* representationProperty;
    this->GetDataNode()->GetProperty(representationProperty, "material.representation", renderer);
    if ( representationProperty != NULL )
      m_BackgroundActor->GetProperty()->SetRepresentation( representationProperty->GetVtkRepresentation() );
  }
Пример #3
0
void mitk::PlaneGeometryDataMapper2D::CreateVtkCrosshair(mitk::BaseRenderer *renderer)
{
  bool visible = true;
  LocalStorage* ls = m_LSH.GetLocalStorage(renderer);
  ls->m_CrosshairActor->SetVisibility(0);
  ls->m_ArrowActor->SetVisibility(0);
  ls->m_CrosshairHelperLineActor->SetVisibility(0);

  GetDataNode()->GetVisibility(visible, renderer, "visible");

  if(!visible)
  {
    return;
  }

  PlaneGeometryData::Pointer input = const_cast< PlaneGeometryData * >(this->GetInput());
  mitk::DataNode* geometryDataNode = renderer->GetCurrentWorldPlaneGeometryNode();
  const PlaneGeometryData* rendererWorldPlaneGeometryData = dynamic_cast< PlaneGeometryData * >(geometryDataNode->GetData());

  // intersecting with ourself?
  if ( input.IsNull() || input.GetPointer() == rendererWorldPlaneGeometryData)
  {
    return; //nothing to do in this case
  }

  const PlaneGeometry *inputPlaneGeometry = dynamic_cast< const PlaneGeometry * >( input->GetPlaneGeometry() );

  const PlaneGeometry* worldPlaneGeometry = dynamic_cast< const PlaneGeometry* >(
        rendererWorldPlaneGeometryData->GetPlaneGeometry() );

  if ( worldPlaneGeometry && dynamic_cast<const AbstractTransformGeometry*>(worldPlaneGeometry)==NULL
       && inputPlaneGeometry && dynamic_cast<const AbstractTransformGeometry*>(input->GetPlaneGeometry() )==NULL)
  {
    const BaseGeometry *referenceGeometry = inputPlaneGeometry->GetReferenceGeometry();

    // calculate intersection of the plane data with the border of the
    // world geometry rectangle
    Point3D point1, point2;

    Line3D crossLine;

    // Calculate the intersection line of the input plane with the world plane
    if ( worldPlaneGeometry->IntersectionLine( inputPlaneGeometry, crossLine ) )
    {
      bool hasIntersection = referenceGeometry ? CutCrossLineWithReferenceGeometry(referenceGeometry, crossLine) :
                                                 CutCrossLineWithPlaneGeometry(inputPlaneGeometry, crossLine);

      if (!hasIntersection)
      {
        return;
      }

      point1 = crossLine.GetPoint1();
      point2 = crossLine.GetPoint2();

      vtkSmartPointer<vtkCellArray> lines = vtkSmartPointer<vtkCellArray>::New();
      vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
      vtkSmartPointer<vtkPolyData> linesPolyData = vtkSmartPointer<vtkPolyData>::New();


      // Now iterate through all other lines displayed in this window and
      // calculate the positions of intersection with the line to be
      // rendered; these positions will be stored in lineParams to form a
      // gap afterwards.
      NodesVectorType::iterator otherPlanesIt = m_OtherPlaneGeometries.begin();
      NodesVectorType::iterator otherPlanesEnd = m_OtherPlaneGeometries.end();

      otherPlanesIt = m_OtherPlaneGeometries.begin();
      int gapSize = 32;
      this->GetDataNode()->GetPropertyValue("Crosshair.Gap Size", gapSize, NULL);


      auto intervals = IntervalSet<double>( SimpleInterval<double>(0, 1));

      ScalarType lineLength = point1.EuclideanDistanceTo(point2);
      ScalarType gapInMM = gapSize * renderer->GetScaleFactorMMPerDisplayUnit();
      float gapSizeParam = gapInMM / lineLength;

      if( gapSize != 0 )
      {
        while ( otherPlanesIt != otherPlanesEnd )
        {
          bool ignorePlane = false;
          (*otherPlanesIt)->GetPropertyValue("Crosshair.Ignore", ignorePlane);
          if (ignorePlane)
          {
              ++otherPlanesIt;
              continue;
          }

          PlaneGeometry *otherPlaneGeometry = static_cast< PlaneGeometry * >(
                static_cast< PlaneGeometryData * >((*otherPlanesIt)->GetData() )->GetPlaneGeometry() );

          if (otherPlaneGeometry != inputPlaneGeometry && otherPlaneGeometry != worldPlaneGeometry)
          {
              double intersectionParam;
              if (otherPlaneGeometry->IntersectionPointParam(crossLine, intersectionParam) && intersectionParam > 0 &&
                  intersectionParam < 1)
              {
                Point3D point = crossLine.GetPoint() + intersectionParam * crossLine.GetDirection();

                bool intersectionPointInsideOtherPlane =
                  otherPlaneGeometry->HasReferenceGeometry() ?
                    TestPointInReferenceGeometry(otherPlaneGeometry->GetReferenceGeometry(), point) :
                    TestPointInPlaneGeometry(otherPlaneGeometry, point);

                if (intersectionPointInsideOtherPlane)
                {
                  intervals -= SimpleInterval<double>(intersectionParam - gapSizeParam, intersectionParam + gapSizeParam);
                }
              }
          }
          ++otherPlanesIt;
        }
      }

      for (const auto& interval : intervals.getIntervals()) {
          this->DrawLine(crossLine.GetPoint(interval.GetLowerBoundary()), crossLine.GetPoint(interval.GetUpperBoundary()), lines, points);
      }

      // Add the points to the dataset
      linesPolyData->SetPoints(points);
      // Add the lines to the dataset
      linesPolyData->SetLines(lines);

      Vector3D orthogonalVector;
      orthogonalVector = inputPlaneGeometry->GetNormal();
      worldPlaneGeometry->Project(orthogonalVector,orthogonalVector);
      orthogonalVector.Normalize();

      // Visualize
      ls->m_Mapper->SetInputData(linesPolyData);
      ls->m_CrosshairActor->SetMapper(ls->m_Mapper);

      // Determine if we should draw the area covered by the thick slicing, default is false.
      // This will also show the area of slices that do not have thick slice mode enabled
      bool showAreaOfThickSlicing = false;
      GetDataNode()->GetBoolProperty( "reslice.thickslices.showarea", showAreaOfThickSlicing );

      // determine the pixelSpacing in that direction
      double thickSliceDistance = SlicedGeometry3D::CalculateSpacing(
        referenceGeometry ? referenceGeometry->GetSpacing() : inputPlaneGeometry->GetSpacing(), orthogonalVector);

      IntProperty *intProperty=0;
      if( GetDataNode()->GetProperty( intProperty, "reslice.thickslices.num" ) && intProperty )
        thickSliceDistance *= intProperty->GetValue()+0.5;
      else
        showAreaOfThickSlicing = false;

      // not the nicest place to do it, but we have the width of the visible bloc in MM here
      // so we store it in this fancy property
      GetDataNode()->SetFloatProperty( "reslice.thickslices.sizeinmm", thickSliceDistance*2 );

      ls->m_CrosshairActor->SetVisibility(1);

      vtkSmartPointer<vtkPolyData> arrowPolyData = vtkSmartPointer<vtkPolyData>::New();
      ls->m_Arrowmapper->SetInputData(arrowPolyData);
      if(this->m_RenderOrientationArrows)
      {
        ScalarType triangleSizeMM = 7.0 * renderer->GetScaleFactorMMPerDisplayUnit();

        vtkSmartPointer<vtkCellArray> triangles = vtkSmartPointer<vtkCellArray>::New();
        vtkSmartPointer<vtkPoints> triPoints = vtkSmartPointer<vtkPoints>::New();

        DrawOrientationArrow(triangles,triPoints,triangleSizeMM,orthogonalVector,point1,point2);
        DrawOrientationArrow(triangles,triPoints,triangleSizeMM,orthogonalVector,point2,point1);
        arrowPolyData->SetPoints(triPoints);
        arrowPolyData->SetPolys(triangles);
        ls->m_ArrowActor->SetVisibility(1);
      }

      // Visualize
      vtkSmartPointer<vtkPolyData> helperlinesPolyData = vtkSmartPointer<vtkPolyData>::New();
      ls->m_HelperLinesmapper->SetInputData(helperlinesPolyData);
      if ( showAreaOfThickSlicing )
      {
        vtkSmartPointer<vtkCellArray> helperlines = vtkSmartPointer<vtkCellArray>::New();
        // vectorToHelperLine defines how to reach the helperLine from the mainLine
        // got the right direction, so we multiply the width
        Vector3D vecToHelperLine = orthogonalVector * thickSliceDistance;

        this->DrawLine(point1 - vecToHelperLine, point2 - vecToHelperLine,helperlines,points);
        this->DrawLine(point1 + vecToHelperLine, point2 + vecToHelperLine,helperlines,points);

        // Add the points to the dataset
        helperlinesPolyData->SetPoints(points);

        // Add the lines to the dataset
        helperlinesPolyData->SetLines(helperlines);

        ls->m_CrosshairActor->GetProperty()->SetLineStipplePattern(0xf0f0);
        ls->m_CrosshairActor->GetProperty()->SetLineStippleRepeatFactor(1);
        ls->m_CrosshairHelperLineActor->SetVisibility(1);
      }
    }
  }
}