示例#1
0
文件: mitkCuboid.cpp 项目: 0r/MITK
mitk::ScalarType mitk::Cuboid::GetVolume()
{
  TimeGeometry* geometry = GetTimeGeometry();
  return   geometry->GetExtentInWorld(0)
    * geometry->GetExtentInWorld(1)
    * geometry->GetExtentInWorld(2);
}
示例#2
0
void mitk::SlicedData::SetOrigin(const mitk::Point3D& origin)
{
  TimeGeometry* timeGeometry = GetTimeGeometry();

  assert(timeGeometry!=NULL);

  mitk::SlicedGeometry3D* slicedGeometry;

  unsigned int steps = timeGeometry->CountTimeSteps();

  for(unsigned int timestep = 0; timestep < steps; ++timestep)
  {
    slicedGeometry = GetSlicedGeometry(timestep);
    if(slicedGeometry != NULL)
    {
      slicedGeometry->SetOrigin(origin);
      if(slicedGeometry->GetEvenlySpaced())
      {
        mitk::PlaneGeometry* geometry2D = slicedGeometry->GetPlaneGeometry(0);
        geometry2D->SetOrigin(origin);
        slicedGeometry->InitializeEvenlySpaced(geometry2D, slicedGeometry->GetSlices());
      }
    }
    //ProportionalTimeGeometry* timeGeometry = dynamic_cast<ProportionalTimeGeometry *>(GetTimeGeometry());
    //if(timeGeometry != NULL)
    //{
    //  timeGeometry->Initialize(slicedGeometry, steps);
    //  break;
    //}
  }
}
示例#3
0
void mitk::Surface::CalculateBoundingBox()
{
  TimeGeometry *timeGeometry = this->GetTimeGeometry();

  if (timeGeometry->CountTimeSteps() != m_PolyDatas.size())
    mitkThrow() << "Number of geometry time steps is inconsistent with number of poly data pointers.";

  for (unsigned int i = 0; i < m_PolyDatas.size(); ++i)
  {
    vtkPolyData *polyData = m_PolyDatas[i].GetPointer();
    double bounds[6] = {0};

    if (polyData != nullptr && polyData->GetNumberOfPoints() > 0)
    {
      //      polyData->Update(); //VTK6_TODO vtk pipeline
      polyData->ComputeBounds();
      polyData->GetBounds(bounds);
    }

    BaseGeometry::Pointer geometry = timeGeometry->GetGeometryForTimeStep(i);

    if (geometry.IsNull())
      mitkThrow() << "Time-sliced geometry is invalid (equals nullptr).";

    geometry->SetFloatBounds(bounds);
  }

  timeGeometry->Update();
  m_CalculateBoundingBox = false;
}
示例#4
0
文件: mitkCylinder.cpp 项目: 0r/MITK
mitk::ScalarType mitk::Cylinder::GetVolume()
{
  TimeGeometry* geometry = GetTimeGeometry();
  return   geometry->GetExtentInWorld(0) * 0.5
    * geometry->GetExtentInWorld(2) * 0.5
    * vnl_math::pi
    * geometry->GetExtentInWorld(1);
}
示例#5
0
void mitk::UnstructuredGrid::CalculateBoundingBox()
{
  //
  // first make sure, that the associated time sliced geometry has
  // the same number of geometry 3d's as vtkUnstructuredGrids are present
  //
  TimeGeometry* timeGeometry = GetTimeGeometry();
  if ( timeGeometry->CountTimeSteps() != m_GridSeries.size() )
  {
    itkExceptionMacro(<<"timeGeometry->CountTimeSteps() != m_GridSeries.size() -- use Initialize(timeSteps) with correct number of timeSteps!");
  }
示例#6
0
void mitk::PointSet::UpdateOutputInformation()
{
    if ( this->GetSource( ) )
    {
        this->GetSource( )->UpdateOutputInformation( );
    }

    //
    // first make sure, that the associated time sliced geometry has
    // the same number of geometry 3d's as PointSets are present
    //
    TimeGeometry* timeGeometry = GetTimeGeometry();
    if ( timeGeometry->CountTimeSteps() != m_PointSetSeries.size() )
    {
        itkExceptionMacro(<<"timeGeometry->CountTimeSteps() != m_PointSetSeries.size() -- use Initialize(timeSteps) with correct number of timeSteps!");
    }
示例#7
0
void mitk::SlicedData::SetSpacing(mitk::Vector3D aSpacing)
{
  TimeGeometry *timeGeometry = GetTimeGeometry();

  assert(timeGeometry != nullptr);

  unsigned int steps = timeGeometry->CountTimeSteps();

  for (unsigned int timestep = 0; timestep < steps; ++timestep)
  {
    mitk::SlicedGeometry3D *slicedGeometry = GetSlicedGeometry(timestep);
    if (slicedGeometry != nullptr)
    {
      slicedGeometry->SetSpacing(aSpacing);
    }
  }
  timeGeometry->Update();
}
  void SliceNavigationController::SetGeometryTime(const itk::EventObject &geometryTimeEvent)
  {
    if (m_CreatedWorldGeometry.IsNull())
    {
      return;
    }

    const SliceNavigationController::GeometryTimeEvent *timeEvent =
      dynamic_cast< const SliceNavigationController::GeometryTimeEvent * >(&geometryTimeEvent);
    assert( timeEvent != nullptr );

    TimeGeometry *timeGeometry = timeEvent->GetTimeGeometry();
    assert( timeGeometry != nullptr );

    int timeStep = (int)timeEvent->GetPos();
    ScalarType timeInMS;
    timeInMS = timeGeometry->TimeStepToTimePoint(timeStep);
    timeStep = m_CreatedWorldGeometry->TimePointToTimeStep(timeInMS);
    this->GetTime()->SetPos(timeStep);
  }
示例#9
0
void SlicesRotator::RotateToPoint( SliceNavigationController *rotationPlaneSNC,
                                   SliceNavigationController *rotatedPlaneSNC,
                                   const Point3D &point, bool linked )
{
    MITK_WARN << "Deprecated function! Use SliceNavigationController::ReorientSlices() instead";

    SliceNavigationController *thirdSNC = NULL;

    SNCVector::iterator iter;
    for ( iter = m_RotatableSNCs.begin(); iter != m_RotatableSNCs.end(); ++iter )
    {
        if ( ((*iter) != rotationPlaneSNC)
                && ((*iter) != rotatedPlaneSNC) )
        {
            thirdSNC = *iter;
            break;
        }
    }

    if ( thirdSNC == NULL )
    {
        return;
    }

    const PlaneGeometry *rotationPlane = rotationPlaneSNC->GetCurrentPlaneGeometry();
    const PlaneGeometry *rotatedPlane = rotatedPlaneSNC->GetCurrentPlaneGeometry();
    const PlaneGeometry *thirdPlane = thirdSNC->GetCurrentPlaneGeometry();

    if ( (rotationPlane == NULL) || (rotatedPlane == NULL)
            || (thirdPlane == NULL) )
    {
        return;
    }

    if ( rotatedPlane->DistanceFromPlane( point ) < 0.001 )
    {
        // Skip irrelevant rotations
        return;
    }

    Point3D projectedPoint;
    Line3D intersection;
    Point3D rotationCenter;

    if ( !rotationPlane->Project( point, projectedPoint )
            || !rotationPlane->IntersectionLine( rotatedPlane, intersection )
            || !thirdPlane->IntersectionPoint( intersection, rotationCenter ) )
    {
        return;
    }

    // All pre-requirements are met; execute the rotation

    Point3D referencePoint = intersection.Project( projectedPoint );

    Vector3D toProjected = referencePoint - rotationCenter;
    Vector3D toCursor    = projectedPoint - rotationCenter;

    // cross product: | A x B | = |A| * |B| * sin(angle)
    Vector3D axisOfRotation;
    vnl_vector_fixed< ScalarType, 3 > vnlDirection =
        vnl_cross_3d( toCursor.GetVnlVector(), toProjected.GetVnlVector() );
    axisOfRotation.SetVnlVector( vnlDirection );

    // scalar product: A * B = |A| * |B| * cos(angle)
    // tan = sin / cos
    ScalarType angle = - atan2(
                           (double)(axisOfRotation.GetNorm()),
                           (double)(toCursor * toProjected) );
    angle *= 180.0 / vnl_math::pi;

    // create RotationOperation and apply to all SNCs that should be rotated
    RotationOperation op(OpROTATE, rotationCenter, axisOfRotation, angle);

    if ( !linked )
    {
        BaseRenderer *renderer = rotatedPlaneSNC->GetRenderer();
        if ( renderer == NULL )
        {
            return;
        }

        DisplayGeometry *displayGeometry = renderer->GetDisplayGeometry();

        Point2D point2DWorld, point2DDisplayPre, point2DDisplayPost;
        displayGeometry->Map( rotationCenter, point2DWorld );
        displayGeometry->WorldToDisplay( point2DWorld, point2DDisplayPre );

        TimeGeometry *timeGeometry= rotatedPlaneSNC->GetCreatedWorldGeometry();
        if ( !timeGeometry )
        {
            return;
        }

        timeGeometry->ExecuteOperation( &op );

        displayGeometry->Map( rotationCenter, point2DWorld );
        displayGeometry->WorldToDisplay( point2DWorld, point2DDisplayPost );
        Vector2D vector2DDisplayDiff = point2DDisplayPost - point2DDisplayPre;

        //Vector2D origin = displayGeometry->GetOriginInMM();

        displayGeometry->MoveBy( vector2DDisplayDiff );

        rotatedPlaneSNC->SendCreatedWorldGeometryUpdate();
    }
    else
    {
        SNCVector::iterator iter;
        for ( iter = m_RotatableSNCs.begin(); iter != m_RotatableSNCs.end(); ++iter )
        {
            BaseRenderer *renderer = (*iter)->GetRenderer();
            if ( renderer == NULL )
            {
                continue;
            }

            DisplayGeometry *displayGeometry = renderer->GetDisplayGeometry();

            Point2D point2DWorld, point2DDisplayPre, point2DDisplayPost;
            displayGeometry->Map( rotationCenter, point2DWorld );
            displayGeometry->WorldToDisplay( point2DWorld, point2DDisplayPre );

            TimeGeometry* timeGeometry = (*iter)->GetCreatedWorldGeometry();
            if ( !timeGeometry )
            {
                continue;
            }

            timeGeometry->ExecuteOperation( &op );

            displayGeometry->Map( rotationCenter, point2DWorld );
            displayGeometry->WorldToDisplay( point2DWorld, point2DDisplayPost );
            Vector2D vector2DDisplayDiff = point2DDisplayPost - point2DDisplayPre;

            //Vector2D origin = displayGeometry->GetOriginInMM();

            displayGeometry->MoveBy( vector2DDisplayDiff );

            (*iter)->SendCreatedWorldGeometryUpdate();
        }
    }
} // end RotateToPoint
示例#10
0
bool SlicesRotator::DoRotationStep(Action*, const StateEvent* e)
{
    const DisplayPositionEvent* posEvent = dynamic_cast<const DisplayPositionEvent*>(e->GetEvent());
    if (!posEvent) return false;

    Point3D cursor = posEvent->GetWorldPosition();

    Vector3D toProjected = m_LastCursorPosition - m_CenterOfRotation;
    Vector3D toCursor    = cursor - m_CenterOfRotation;

    // cross product: | A x B | = |A| * |B| * sin(angle)
    Vector3D axisOfRotation;
    vnl_vector_fixed< ScalarType, 3 > vnlDirection = vnl_cross_3d( toCursor.GetVnlVector(), toProjected.GetVnlVector() );
    axisOfRotation.SetVnlVector(vnlDirection);

    // scalar product: A * B = |A| * |B| * cos(angle)
    // tan = sin / cos
    ScalarType angle = - atan2( (double)(axisOfRotation.GetNorm()), (double)(toCursor * toProjected) );
    angle *= 180.0 / vnl_math::pi;
    m_LastCursorPosition = cursor;

    // create RotationOperation and apply to all SNCs that should be rotated
    RotationOperation rotationOperation(OpROTATE, m_CenterOfRotation, axisOfRotation, angle);

    // iterate the OTHER slice navigation controllers: these are filled in DoDecideBetweenRotationAndSliceSelection
    for (SNCVector::iterator iter = m_SNCsToBeRotated.begin(); iter != m_SNCsToBeRotated.end(); ++iter)
    {
        //  - remember the center of rotation on the 2D display BEFORE rotation
        //  - execute rotation
        //  - calculate new center of rotation on 2D display
        //  - move display IF the center of rotation has moved slightly before and after rotation

        // DM 2012-10: this must probably be due to rounding errors only, right?
        //             We don't have documentation on if/why this code is needed
        BaseRenderer *renderer = (*iter)->GetRenderer();
        if ( !renderer ) continue;

        DisplayGeometry *displayGeometry = renderer->GetDisplayGeometry();

        Point2D rotationCenter2DWorld, point2DDisplayPreRotation, point2DDisplayPostRotation;
        displayGeometry->Map( m_CenterOfRotation, rotationCenter2DWorld );
        displayGeometry->WorldToDisplay( rotationCenter2DWorld, point2DDisplayPreRotation );

        TimeGeometry* timeGeometry = (*iter)->GetCreatedWorldGeometry();
        if (!timeGeometry) continue;

        timeGeometry->ExecuteOperation(&rotationOperation);

        displayGeometry->Map( m_CenterOfRotation, rotationCenter2DWorld );
        displayGeometry->WorldToDisplay( rotationCenter2DWorld, point2DDisplayPostRotation );
        Vector2D vector2DDisplayDiff = point2DDisplayPostRotation - point2DDisplayPreRotation;

        displayGeometry->MoveBy( vector2DDisplayDiff );

        (*iter)->SendCreatedWorldGeometryUpdate();
    }

    RenderingManager::GetInstance()->RequestUpdateAll();

    this->InvokeEvent( SliceRotationEvent() ); // notify listeners

    return true;
}
void mitk::Geometry2DDataToSurfaceFilter::GenerateOutputInformation()
{
  mitk::Geometry2DData::ConstPointer input = this->GetInput();
  mitk::Surface::Pointer output = this->GetOutput();

  if ( input.IsNull() || (input->GetGeometry2D() == NULL)
    || (input->GetGeometry2D()->IsValid() == false)
    || (m_UseBoundingBox && (m_BoundingBox.IsNull() || (m_BoundingBox->GetDiagonalLength2() < mitk::eps))) )
  {
    return;
  }

  Point3D origin;
  Point3D right, bottom;

  vtkPolyData *planeSurface = NULL;


  // Does the Geometry2DData contain a PlaneGeometry?
  if ( dynamic_cast< PlaneGeometry * >( input->GetGeometry2D() ) != NULL )
  {
    mitk::PlaneGeometry *planeGeometry =
      dynamic_cast< PlaneGeometry * >( input->GetGeometry2D() );

    if ( m_PlaceByGeometry )
    {
      // Let the output use the input geometry to appropriately transform the
      // coordinate system.
      mitk::Geometry3D::TransformType *affineTransform =
        planeGeometry->GetIndexToWorldTransform();

      TimeGeometry *timeGeometry = output->GetTimeGeometry();
      Geometry3D *geometrie3d = timeGeometry->GetGeometryForTimeStep( 0 );
      geometrie3d->SetIndexToWorldTransform( affineTransform );
    }

    if ( !m_UseBoundingBox)
    {
      // We do not have a bounding box, so no clipping is required.

      if ( m_PlaceByGeometry )
      {
        // Derive coordinate axes and origin from input geometry extent
        origin.Fill( 0.0 );
        FillVector3D( right,  planeGeometry->GetExtent(0), 0.0, 0.0 );
        FillVector3D( bottom, 0.0, planeGeometry->GetExtent(1), 0.0 );
      }
      else
      {
        // Take the coordinate axes and origin directly from the input geometry.
        origin = planeGeometry->GetOrigin();
        right = planeGeometry->GetCornerPoint( false, true );
        bottom = planeGeometry->GetCornerPoint( true, false );
      }

      // Since the plane is planar, there is no need to subdivide the grid
      // (cf. AbstractTransformGeometry case)
      m_PlaneSource->SetXResolution( 1 );
      m_PlaneSource->SetYResolution( 1 );

      m_PlaneSource->SetOrigin( origin[0], origin[1], origin[2] );
      m_PlaneSource->SetPoint1( right[0], right[1], right[2] );
      m_PlaneSource->SetPoint2( bottom[0], bottom[1], bottom[2] );

      m_PlaneSource->Update();
      planeSurface = m_PlaneSource->GetOutput();

    }
    else
    {
      // Set up a cube with the extent and origin of the bounding box. This
      // cube will be clipped by a plane later on. The intersection of the
      // cube and the plane will be the surface we are interested in. Note
      // that the bounding box needs to be explicitly specified by the user
      // of this class, since it is not necessarily clear from the data
      // available herein which bounding box to use. In most cases, this
      // would be the bounding box of the input geometry's reference
      // geometry, but this is not an inevitable requirement.
      mitk::BoundingBox::PointType boundingBoxMin = m_BoundingBox->GetMinimum();
      mitk::BoundingBox::PointType boundingBoxMax = m_BoundingBox->GetMaximum();
      mitk::BoundingBox::PointType boundingBoxCenter = m_BoundingBox->GetCenter();

      m_CubeSource->SetXLength( boundingBoxMax[0] - boundingBoxMin[0] );
      m_CubeSource->SetYLength( boundingBoxMax[1] - boundingBoxMin[1] );
      m_CubeSource->SetZLength( boundingBoxMax[2] - boundingBoxMin[2] );
      m_CubeSource->SetCenter(
        boundingBoxCenter[0],
        boundingBoxCenter[1],
        boundingBoxCenter[2] );


      // Now we have to transform the cube, so that it will cut our plane
      // appropriately. (As can be seen below, the plane corresponds to the
      // z-plane in the coordinate system and is *not* transformed.) Therefore,
      // we get the inverse of the plane geometry's transform and concatenate
      // it with the transform of the reference geometry, if available.
      m_Transform->Identity();
      m_Transform->Concatenate(
        planeGeometry->GetVtkTransform()->GetLinearInverse()
      );

      Geometry3D *referenceGeometry = planeGeometry->GetReferenceGeometry();
      if ( referenceGeometry )
      {
        m_Transform->Concatenate(
          referenceGeometry->GetVtkTransform()
        );
      }

      // Transform the cube accordingly (s.a.)
      m_PolyDataTransformer->SetInputConnection( m_CubeSource->GetOutputPort() );
      m_PolyDataTransformer->SetTransform( m_Transform );

      // Initialize the plane to clip the cube with, as lying on the z-plane
      m_Plane->SetOrigin( 0.0, 0.0, 0.0 );
      m_Plane->SetNormal( 0.0, 0.0, 1.0 );

      // Cut the plane with the cube.
      m_PlaneCutter->SetInputConnection( m_PolyDataTransformer->GetOutputPort() );
      m_PlaneCutter->SetCutFunction( m_Plane );

      // The output of the cutter must be converted into appropriate poly data.
      m_PlaneStripper->SetInputConnection( m_PlaneCutter->GetOutputPort() );
      m_PlaneStripper->Update();

      if ( m_PlaneStripper->GetOutput()->GetNumberOfPoints() < 3 )
      {
        return;
      }

      m_PlanePolyData->SetPoints( m_PlaneStripper->GetOutput()->GetPoints() );
      m_PlanePolyData->SetPolys( m_PlaneStripper->GetOutput()->GetLines() );

      m_PlaneTriangler->SetInputData( m_PlanePolyData );


      // Get bounds of the resulting surface and use it to generate the texture
      // mapping information
      m_PlaneTriangler->Update();
      m_PlaneTriangler->GetOutput()->ComputeBounds();
      double *surfaceBounds =
        m_PlaneTriangler->GetOutput()->GetBounds();

      origin[0] = surfaceBounds[0];
      origin[1] = surfaceBounds[2];
      origin[2] = surfaceBounds[4];

      right[0] = surfaceBounds[1];
      right[1] = surfaceBounds[2];
      right[2] = surfaceBounds[4];

      bottom[0] = surfaceBounds[0];
      bottom[1] = surfaceBounds[3];
      bottom[2] = surfaceBounds[4];

      // Now we tell the data how it shall be textured afterwards;
      // description see above.
      m_TextureMapToPlane->SetInputConnection( m_PlaneTriangler->GetOutputPort() );
      m_TextureMapToPlane->AutomaticPlaneGenerationOn();
      m_TextureMapToPlane->SetOrigin( origin[0], origin[1], origin[2] );
      m_TextureMapToPlane->SetPoint1( right[0], right[1], right[2] );
      m_TextureMapToPlane->SetPoint2( bottom[0], bottom[1], bottom[2] );

      // Need to call update so that output data and bounds are immediately
      // available
      m_TextureMapToPlane->Update();


      // Return the output of this generation process
      planeSurface = dynamic_cast< vtkPolyData * >(
        m_TextureMapToPlane->GetOutput()
      );
    }
  }

  // Does the Geometry2DData contain an AbstractTransformGeometry?
  else if ( mitk::AbstractTransformGeometry *abstractGeometry =
    dynamic_cast< AbstractTransformGeometry * >( input->GetGeometry2D() ) )
  {
    // In the case of an AbstractTransformGeometry (which holds a possibly
    // non-rigid transform), we proceed slightly differently: since the
    // plane can be arbitrarily deformed, we need to transform it by the
    // abstract transform before clipping it. The setup for this is partially
    // done in the constructor.
    origin = abstractGeometry->GetPlane()->GetOrigin();
    right = origin + abstractGeometry->GetPlane()->GetAxisVector( 0 );
    bottom = origin + abstractGeometry->GetPlane()->GetAxisVector( 1 );

    // Define the plane
    m_PlaneSource->SetOrigin( origin[0], origin[1], origin[2] );
    m_PlaneSource->SetPoint1( right[0], right[1], right[2] );
    m_PlaneSource->SetPoint2( bottom[0], bottom[1], bottom[2] );

    // Set the plane's resolution (unlike for non-deformable planes, the plane
    // grid needs to have a certain resolution so that the deformation has the
    // desired effect).
    if ( m_UseGeometryParametricBounds )
    {
      m_PlaneSource->SetXResolution(
        (int)abstractGeometry->GetParametricExtent(0)
      );
      m_PlaneSource->SetYResolution(
        (int)abstractGeometry->GetParametricExtent(1)
      );
    }
    else
    {
      m_PlaneSource->SetXResolution( m_XResolution );
      m_PlaneSource->SetYResolution( m_YResolution );
    }
    if ( m_PlaceByGeometry )
    {
      // Let the output use the input geometry to appropriately transform the
      // coordinate system.
      mitk::Geometry3D::TransformType *affineTransform =
        abstractGeometry->GetIndexToWorldTransform();

      TimeGeometry *timeGeometry = output->GetTimeGeometry();
      Geometry3D *g3d = timeGeometry->GetGeometryForTimeStep( 0 );
      g3d->SetIndexToWorldTransform( affineTransform );

      vtkGeneralTransform *composedResliceTransform = vtkGeneralTransform::New();
      composedResliceTransform->Identity();
      composedResliceTransform->Concatenate(
        abstractGeometry->GetVtkTransform()->GetLinearInverse() );
      composedResliceTransform->Concatenate(
        abstractGeometry->GetVtkAbstractTransform()
        );
      // Use the non-rigid transform for transforming the plane.
      m_VtkTransformPlaneFilter->SetTransform(
        composedResliceTransform
      );
    }
    else
    {
      // Use the non-rigid transform for transforming the plane.
      m_VtkTransformPlaneFilter->SetTransform(
        abstractGeometry->GetVtkAbstractTransform()
      );
    }

    if ( m_UseBoundingBox )
    {
      mitk::BoundingBox::PointType boundingBoxMin = m_BoundingBox->GetMinimum();
      mitk::BoundingBox::PointType boundingBoxMax = m_BoundingBox->GetMaximum();
      //mitk::BoundingBox::PointType boundingBoxCenter = m_BoundingBox->GetCenter();

      m_Box->SetXMin( boundingBoxMin[0], boundingBoxMin[1], boundingBoxMin[2] );
      m_Box->SetXMax( boundingBoxMax[0], boundingBoxMax[1], boundingBoxMax[2] );
    }
    else
    {
      // Plane will not be clipped
      m_Box->SetXMin( -10000.0, -10000.0, -10000.0 );
      m_Box->SetXMax( 10000.0, 10000.0, 10000.0 );
    }

    m_Transform->Identity();
    m_Transform->Concatenate( input->GetGeometry2D()->GetVtkTransform() );
    m_Transform->PreMultiply();

    m_Box->SetTransform( m_Transform );

    m_PlaneClipper->SetInputConnection(m_VtkTransformPlaneFilter->GetOutputPort() );
    m_PlaneClipper->SetClipFunction( m_Box );
    m_PlaneClipper->GenerateClippedOutputOff(); // important to NOT generate normals data for clipped part
    m_PlaneClipper->InsideOutOn();
    m_PlaneClipper->SetValue( 0.0 );
    m_PlaneClipper->Update();

    planeSurface = m_PlaneClipper->GetOutput();
  }

  m_NormalsUpdater->SetInputData( planeSurface );
  m_NormalsUpdater->AutoOrientNormalsOn(); // that's the trick! Brings consistency between
                                          //  normals direction and front/back faces direction (see bug 1440)
  m_NormalsUpdater->ComputePointNormalsOn();
  m_NormalsUpdater->Update();

  output->SetVtkPolyData( m_NormalsUpdater->GetOutput() );
  output->CalculateBoundingBox();
}