diff --git a/Core/Code/Controllers/mitkSliceNavigationController.h b/Core/Code/Controllers/mitkSliceNavigationController.h index 5cf5646a5d..6ff232b0cd 100644 --- a/Core/Code/Controllers/mitkSliceNavigationController.h +++ b/Core/Code/Controllers/mitkSliceNavigationController.h @@ -1,505 +1,505 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef SLICENAVIGATIONCONTROLLER_H_HEADER_INCLUDED_C1C55A2F #define SLICENAVIGATIONCONTROLLER_H_HEADER_INCLUDED_C1C55A2F #include "mitkCommon.h" #include "mitkBaseController.h" #include "mitkRenderingManager.h" #include "mitkTimeSlicedGeometry.h" #include #include #include #include namespace mitk { #define mitkTimeSlicedGeometryEventMacro( classname , super ) \ class MITK_CORE_EXPORT classname : public super { \ public: \ typedef classname Self; \ typedef super Superclass; \ classname(TimeSlicedGeometry* aTimeSlicedGeometry, unsigned int aPos) \ : Superclass(aTimeSlicedGeometry, aPos) {} \ virtual ~classname() {} \ virtual const char * GetEventName() const { return #classname; } \ virtual bool CheckEvent(const ::itk::EventObject* e) const \ { return dynamic_cast(e); } \ virtual ::itk::EventObject* MakeObject() const \ { return new Self(GetTimeSlicedGeometry(), GetPos()); } \ private: \ void operator=(const Self&); \ } class PlaneGeometry; class Geometry3D; class BaseRenderer; /** * \brief Controls the selection of the slice the associated BaseRenderer * will display * * A SliceNavigationController takes a Geometry3D as input world geometry * (TODO what are the exact requirements?) and generates a TimeSlicedGeometry * as output. The TimeSlicedGeometry holds a number of SlicedGeometry3Ds and * these in turn hold a series of Geometry2Ds. One of these Geometry2Ds is * selected as world geometry for the BaseRenderers associated to 2D views. * * The SliceNavigationController holds has Steppers (one for the slice, a * second for the time step), which control the selection of a single * Geometry2D from the TimeSlicedGeometry. SliceNavigationController generates * ITK events to tell observers, like a BaseRenderer, when the selected slice * or timestep changes. * * SliceNavigationControllers are registered as listeners to GlobalInteraction * by the QmitkStdMultiWidget. In ExecuteAction, the controllers react to * PositionEvents by setting the steppers to the slice which is nearest to the * point of the PositionEvent. * * Example: * \code * // Initialization * sliceCtrl = mitk::SliceNavigationController::New(); * * // Tell the navigator the geometry to be sliced (with geometry a * // Geometry3D::ConstPointer) * sliceCtrl->SetInputWorldGeometry(geometry.GetPointer()); * * // Tell the navigator in which direction it shall slice the data * sliceCtrl->SetViewDirection(mitk::SliceNavigationController::Transversal); * * // Connect one or more BaseRenderer to this navigator, i.e.: events sent * // by the navigator when stepping through the slices (e.g. by * // sliceCtrl->GetSlice()->Next()) will be received by the BaseRenderer * // (in this example only slice-changes, see also ConnectGeometryTimeEvent * // and ConnectGeometryEvents.) * sliceCtrl->ConnectGeometrySliceEvent(renderer.GetPointer()); * * //create a world geometry and send the information to the connected renderer(s) * sliceCtrl->Update(); * \endcode * * * You can connect visible navigators to a SliceNavigationController, e.g., a * QmitkSliderNavigator (for Qt): * * \code * // Create the visible navigator (a slider with a spin-box) * QmitkSliderNavigator* navigator = * new QmitkSliderNavigator(parent, "slidernavigator"); * * // Connect the navigator to the slice-stepper of the * // SliceNavigationController. For initialization (position, mininal and * // maximal values) the values of the SliceNavigationController are used. * // Thus, accessing methods of a navigator is normally not necessary, since * // everything can be set via the (Qt-independent) SliceNavigationController. * // The QmitkStepperAdapter converts the Qt-signals to Qt-independent * // itk-events. * new QmitkStepperAdapter(navigator, sliceCtrl->GetSlice(), "navigatoradaptor"); * \endcode * * If you do not want that all renderwindows are updated when a new slice is * selected, you can use a specific RenderingManager, which updates only those * renderwindows that should be updated. This is sometimes useful when a 3D view * does not need to be updated when the slices in some 2D views are changed. * QmitkSliderNavigator (for Qt): * * \code * // create a specific RenderingManager * mitk::RenderingManager::Pointer myManager = mitk::RenderingManager::New(); * * // tell the RenderingManager to update only renderwindow1 and renderwindow2 * myManager->AddRenderWindow(renderwindow1); * myManager->AddRenderWindow(renderwindow2); * * // tell the SliceNavigationController of renderwindow1 and renderwindow2 * // to use the specific RenderingManager instead of the global one * renderwindow1->GetSliceNavigationController()->SetRenderingManager(myManager); * renderwindow2->GetSliceNavigationController()->SetRenderingManager(myManager); * \endcode * * \todo implement for non-evenly-timed geometry! * \ingroup NavigationControl */ class MITK_CORE_EXPORT SliceNavigationController : public BaseController { public: mitkClassMacro(SliceNavigationController,BaseController); itkNewMacro(Self); mitkNewMacro1Param(Self, const char *); /** * \brief Possible view directions, \a Original will uses * the Geometry2D instances in a SlicedGeometry3D provided * as input world geometry (by SetInputWorldGeometry). */ enum ViewDirection{Transversal, Sagittal, Frontal, Original}; /** * \brief Set the input world geometry out of which the * geometries for slicing will be created. */ void SetInputWorldGeometry(const mitk::Geometry3D* geometry); itkGetConstObjectMacro(InputWorldGeometry, mitk::Geometry3D); /** * \brief Access the created geometry */ itkGetConstObjectMacro(CreatedWorldGeometry, mitk::Geometry3D); /** * \brief Set the desired view directions * * \sa ViewDirection * \sa Update(ViewDirection viewDirection, bool top = true, * bool frontside = true, bool rotated = false) */ - itkSetMacro(ViewDirection, ViewDirection); - itkGetMacro(ViewDirection, ViewDirection); + itkSetEnumMacro(ViewDirection, ViewDirection); + itkGetEnumMacro(ViewDirection, ViewDirection); /** * \brief Set the default view direction * * This is used to re-initialize the view direction of the SNC to the * default value with SetViewDirectionToDefault() * * \sa ViewDirection * \sa Update(ViewDirection viewDirection, bool top = true, * bool frontside = true, bool rotated = false) */ - itkSetMacro(DefaultViewDirection, ViewDirection); - itkGetMacro(DefaultViewDirection, ViewDirection); + itkSetEnumMacro(DefaultViewDirection, ViewDirection); + itkGetEnumMacro(DefaultViewDirection, ViewDirection); virtual void SetViewDirectionToDefault(); /** * \brief Do the actual creation and send it to the connected * observers (renderers) * */ virtual void Update(); /** * \brief Extended version of Update, additionally allowing to * specify the direction/orientation of the created geometry. * */ virtual void Update(ViewDirection viewDirection, bool top = true, bool frontside = true, bool rotated = false); /** * \brief Send the created geometry to the connected * observers (renderers) * * Called by Update(). */ virtual void SendCreatedWorldGeometry(); /** * \brief Tell observers to re-read the currently selected 2D geometry * * Called by mitk::SlicesRotator during rotation. */ virtual void SendCreatedWorldGeometryUpdate(); /** * \brief Send the currently selected slice to the connected * observers (renderers) * * Called by Update(). */ virtual void SendSlice(); /** * \brief Send the currently selected time to the connected * observers (renderers) * * Called by Update(). */ virtual void SendTime(); /** * \brief Set the RenderingManager to be used * * If \a NULL, the default RenderingManager will be used. */ itkSetObjectMacro(RenderingManager, RenderingManager); mitk::RenderingManager* GetRenderingManager() const; itkEventMacro( UpdateEvent, itk::AnyEvent ); class MITK_CORE_EXPORT TimeSlicedGeometryEvent : public itk::AnyEvent { public: typedef TimeSlicedGeometryEvent Self; typedef itk::AnyEvent Superclass; TimeSlicedGeometryEvent( TimeSlicedGeometry* aTimeSlicedGeometry, unsigned int aPos) : m_TimeSlicedGeometry(aTimeSlicedGeometry), m_Pos(aPos) {} virtual ~TimeSlicedGeometryEvent() {} virtual const char * GetEventName() const { return "TimeSlicedGeometryEvent"; } virtual bool CheckEvent(const ::itk::EventObject* e) const { return dynamic_cast(e); } virtual ::itk::EventObject* MakeObject() const { return new Self(m_TimeSlicedGeometry, m_Pos); } TimeSlicedGeometry* GetTimeSlicedGeometry() const { return m_TimeSlicedGeometry; } unsigned int GetPos() const { return m_Pos; } private: TimeSlicedGeometry::Pointer m_TimeSlicedGeometry; unsigned int m_Pos; // TimeSlicedGeometryEvent(const Self&); void operator=(const Self&); //just hide }; mitkTimeSlicedGeometryEventMacro( GeometrySendEvent,TimeSlicedGeometryEvent ); mitkTimeSlicedGeometryEventMacro( GeometryUpdateEvent, TimeSlicedGeometryEvent ); mitkTimeSlicedGeometryEventMacro( GeometryTimeEvent, TimeSlicedGeometryEvent ); mitkTimeSlicedGeometryEventMacro( GeometrySliceEvent, TimeSlicedGeometryEvent ); template void ConnectGeometrySendEvent(T* receiver) { typedef typename itk::ReceptorMemberCommand::Pointer ReceptorMemberCommandPointer; ReceptorMemberCommandPointer eventReceptorCommand = itk::ReceptorMemberCommand::New(); eventReceptorCommand->SetCallbackFunction(receiver, &T::SetGeometry); AddObserver(GeometrySendEvent(NULL,0), eventReceptorCommand); } template void ConnectGeometryUpdateEvent(T* receiver) { typedef typename itk::ReceptorMemberCommand::Pointer ReceptorMemberCommandPointer; ReceptorMemberCommandPointer eventReceptorCommand = itk::ReceptorMemberCommand::New(); eventReceptorCommand->SetCallbackFunction(receiver, &T::UpdateGeometry); AddObserver(GeometryUpdateEvent(NULL,0), eventReceptorCommand); } template void ConnectGeometrySliceEvent(T* receiver, bool connectSendEvent=true) { typedef typename itk::ReceptorMemberCommand::Pointer ReceptorMemberCommandPointer; ReceptorMemberCommandPointer eventReceptorCommand = itk::ReceptorMemberCommand::New(); eventReceptorCommand->SetCallbackFunction(receiver, &T::SetGeometrySlice); AddObserver(GeometrySliceEvent(NULL,0), eventReceptorCommand); if(connectSendEvent) ConnectGeometrySendEvent(receiver); } template void ConnectGeometryTimeEvent(T* receiver, bool connectSendEvent=true) { typedef typename itk::ReceptorMemberCommand::Pointer ReceptorMemberCommandPointer; ReceptorMemberCommandPointer eventReceptorCommand = itk::ReceptorMemberCommand::New(); eventReceptorCommand->SetCallbackFunction(receiver, &T::SetGeometryTime); AddObserver(GeometryTimeEvent(NULL,0), eventReceptorCommand); if(connectSendEvent) ConnectGeometrySendEvent(receiver); } template void ConnectGeometryEvents(T* receiver) { //connect sendEvent only once ConnectGeometrySliceEvent(receiver, false); ConnectGeometryTimeEvent(receiver); } /** * \brief To connect multiple SliceNavigationController, we can * act as an observer ourselves: implemented interface * \warning not implemented */ virtual void SetGeometry(const itk::EventObject & geometrySliceEvent); /** * \brief To connect multiple SliceNavigationController, we can * act as an observer ourselves: implemented interface */ virtual void SetGeometrySlice(const itk::EventObject & geometrySliceEvent); /** * \brief To connect multiple SliceNavigationController, we can * act as an observer ourselves: implemented interface */ virtual void SetGeometryTime(const itk::EventObject & geometryTimeEvent); /** \brief Positions the SNC according to the specified point */ void SelectSliceByPoint( const mitk::Point3D &point ); /** \brief Returns the TimeSlicedGeometry created by the SNC. */ const mitk::TimeSlicedGeometry *GetCreatedWorldGeometry(); /** \brief Returns the Geometry3D of the currently selected time step. */ const mitk::Geometry3D *GetCurrentGeometry3D(); /** \brief Returns the currently selected Plane in the current * Geometry3D (if existent). */ const mitk::PlaneGeometry *GetCurrentPlaneGeometry(); /** \brief Sets the BaseRenderer associated with this SNC (if any). While * the BaseRenderer is not directly used by SNC, this is a convenience * method to enable BaseRenderer access via the SNC. */ void SetRenderer( BaseRenderer *renderer ); /** \brief Gets the BaseRenderer associated with this SNC (if any). While * the BaseRenderer is not directly used by SNC, this is a convenience * method to enable BaseRenderer access via the SNC. Returns NULL if no * BaseRenderer has been specified*/ BaseRenderer *GetRenderer() const; /** \brief Re-orients the slice stack to include the plane specified by * the given point an normal vector. */ void ReorientSlices( const mitk::Point3D &point, const mitk::Vector3D &normal ); virtual bool ExecuteAction( Action* action, mitk::StateEvent const* stateEvent); void ExecuteOperation(Operation* operation); /** * \brief Feature option to lock planes during mouse interaction. * This option flag disables the mouse event which causes the center * cross to move near by. */ itkSetMacro(SliceLocked, bool); itkGetMacro(SliceLocked, bool); itkBooleanMacro(SliceLocked); /** * \brief Feature option to lock slice rotation. * * This option flag disables separately the rotation of a slice which is * implemented in mitkSliceRotator. */ itkSetMacro(SliceRotationLocked, bool); itkGetMacro(SliceRotationLocked, bool); itkBooleanMacro(SliceRotationLocked); /** * \brief Adjusts the numerical range of the slice stepper according to * the current geometry orientation of this SNC's SlicedGeometry. */ void AdjustSliceStepperRange(); protected: SliceNavigationController(const char * type = NULL); virtual ~SliceNavigationController(); template static void buildstring( mitkIpPicDescriptor *pic, itk::Point p, std::string &s, T = 0) { std::string value; std::stringstream stream; stream.imbue(std::locale::classic()); stream<=0 && p[1] >=0 && p[2]>=0) && (unsigned int)p[0] < pic->n[0] && (unsigned int)p[1] < pic->n[1] && (unsigned int)p[2] < pic->n[2] ) { if(pic->bpe!=24) { stream<<(((T*) pic->data)[ p[0] + p[1]*pic->n[0] + p[2]*pic->n[0]*pic->n[1] ]); } else { stream<<(((T*) pic->data)[p[0]*3 + 0 + p[1]*pic->n[0]*3 + p[2]*pic->n[0]*pic->n[1]*3 ]); stream<<(((T*) pic->data)[p[0]*3 + 1 + p[1]*pic->n[0]*3 + p[2]*pic->n[0]*pic->n[1]*3 ]); stream<<(((T*) pic->data)[p[0]*3 + 2 + p[1]*pic->n[0]*3 + p[2]*pic->n[0]*pic->n[1]*3 ]); } s = stream.str(); } else { s+= "point out of data"; } }; mitk::Geometry3D::ConstPointer m_InputWorldGeometry; mitk::Geometry3D::Pointer m_ExtendedInputWorldGeometry; mitk::TimeSlicedGeometry::Pointer m_CreatedWorldGeometry; ViewDirection m_ViewDirection; ViewDirection m_DefaultViewDirection; mitk::RenderingManager::Pointer m_RenderingManager; mitk::BaseRenderer *m_Renderer; itkSetMacro(Top, bool); itkGetMacro(Top, bool); itkBooleanMacro(Top); itkSetMacro(FrontSide, bool); itkGetMacro(FrontSide, bool); itkBooleanMacro(FrontSide); itkSetMacro(Rotated, bool); itkGetMacro(Rotated, bool); itkBooleanMacro(Rotated); bool m_Top; bool m_FrontSide; bool m_Rotated; bool m_BlockUpdate; bool m_SliceLocked; bool m_SliceRotationLocked; unsigned int m_OldPos; }; } // namespace mitk #endif /* SLICENAVIGATIONCONTROLLER_H_HEADER_INCLUDED_C1C55A2F */ diff --git a/Core/Code/DataManagement/mitkAbstractTransformGeometry.cpp b/Core/Code/DataManagement/mitkAbstractTransformGeometry.cpp index 8d91e54c66..57b2bb883d 100644 --- a/Core/Code/DataManagement/mitkAbstractTransformGeometry.cpp +++ b/Core/Code/DataManagement/mitkAbstractTransformGeometry.cpp @@ -1,263 +1,263 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "mitkAbstractTransformGeometry.h" #include mitk::AbstractTransformGeometry::AbstractTransformGeometry() : m_Plane(NULL), m_FrameGeometry(NULL) { Initialize(); } +mitk::AbstractTransformGeometry::AbstractTransformGeometry(const AbstractTransformGeometry& other) : Superclass(other) +{ + if(other.m_ParametricBoundingBox.IsNotNull()) + { + this->SetParametricBounds(m_ParametricBoundingBox->GetBounds()); + } + + this->SetPlane(other.m_Plane); + + this->SetFrameGeometry(other.m_FrameGeometry); +} + + mitk::AbstractTransformGeometry::~AbstractTransformGeometry() { } void mitk::AbstractTransformGeometry::Initialize() { Superclass::Initialize(); m_ItkVtkAbstractTransform = itk::VtkAbstractTransform::New(); } vtkAbstractTransform* mitk::AbstractTransformGeometry::GetVtkAbstractTransform() const { return m_ItkVtkAbstractTransform->GetVtkAbstractTransform(); } mitk::ScalarType mitk::AbstractTransformGeometry::GetParametricExtentInMM(int direction) const { if(m_Plane.IsNull()) { itkExceptionMacro(<<"m_Plane is NULL."); } return m_Plane->GetExtentInMM(direction); } const mitk::Transform3D* mitk::AbstractTransformGeometry::GetParametricTransform() const { return m_ItkVtkAbstractTransform; } bool mitk::AbstractTransformGeometry::Project(const mitk::Point3D &pt3d_mm, mitk::Point3D &projectedPt3d_mm) const { assert(m_BoundingBox.IsNotNull()); mitk::Point2D pt2d_mm; bool isInside; isInside = Map(pt3d_mm, pt2d_mm); Map(pt2d_mm, projectedPt3d_mm); return isInside; //Point3D pt3d_units; //pt3d_units = m_ItkVtkAbstractTransform->BackTransform(pt3d_mm); //pt3d_units[2] = 0; //projectedPt3d_mm = m_ItkVtkAbstractTransform->TransformPoint(pt3d_units); //return const_cast(m_BoundingBox.GetPointer())->IsInside(pt3d_units); } bool mitk::AbstractTransformGeometry::Map(const mitk::Point3D &pt3d_mm, mitk::Point2D &pt2d_mm) const { assert((m_ItkVtkAbstractTransform.IsNotNull()) && (m_Plane.IsNotNull())); Point3D pt3d_units; pt3d_units = m_ItkVtkAbstractTransform->BackTransform(pt3d_mm); return m_Plane->Map(pt3d_units, pt2d_mm); } void mitk::AbstractTransformGeometry::Map(const mitk::Point2D &pt2d_mm, mitk::Point3D &pt3d_mm) const { assert((m_ItkVtkAbstractTransform.IsNotNull()) && (m_Plane.IsNotNull())); m_Plane->Map(pt2d_mm, pt3d_mm); pt3d_mm = m_ItkVtkAbstractTransform->TransformPoint(pt3d_mm); } bool mitk::AbstractTransformGeometry::Project(const mitk::Point3D & atPt3d_mm, const mitk::Vector3D &vec3d_mm, mitk::Vector3D &projectedVec3d_mm) const { itkExceptionMacro("not implemented yet - replace GetIndexToWorldTransform by m_ItkVtkAbstractTransform->GetInverseVtkAbstractTransform()"); assert(m_BoundingBox.IsNotNull()); Vector3D vec3d_units; vec3d_units = GetIndexToWorldTransform()->BackTransform(vec3d_mm); vec3d_units[2] = 0; projectedVec3d_mm = GetIndexToWorldTransform()->TransformVector(vec3d_units); Point3D pt3d_units; pt3d_units = GetIndexToWorldTransform()->BackTransformPoint(atPt3d_mm); return const_cast(m_BoundingBox.GetPointer())->IsInside(pt3d_units); } bool mitk::AbstractTransformGeometry::Map(const mitk::Point3D & atPt3d_mm, const mitk::Vector3D &vec3d_mm, mitk::Vector2D &vec2d_mm) const { assert((m_ItkVtkAbstractTransform.IsNotNull()) && (m_Plane.IsNotNull())); float vtkpt[3], vtkvec[3]; itk2vtk(atPt3d_mm, vtkpt); itk2vtk(vec3d_mm, vtkvec); m_ItkVtkAbstractTransform->GetInverseVtkAbstractTransform()->TransformVectorAtPoint(vtkpt, vtkvec, vtkvec); mitk::Vector3D vec3d_units; vtk2itk(vtkvec, vec3d_units); return m_Plane->Map(atPt3d_mm, vec3d_units, vec2d_mm); } void mitk::AbstractTransformGeometry::Map(const mitk::Point2D & atPt2d_mm, const mitk::Vector2D &vec2d_mm, mitk::Vector3D &vec3d_mm) const { m_Plane->Map(atPt2d_mm, vec2d_mm, vec3d_mm); Point3D atPt3d_mm; Map(atPt2d_mm, atPt3d_mm); float vtkpt[3], vtkvec[3]; itk2vtk(atPt3d_mm, vtkpt); itk2vtk(vec3d_mm, vtkvec); m_ItkVtkAbstractTransform->GetVtkAbstractTransform()->TransformVectorAtPoint(vtkpt, vtkvec, vtkvec); vtk2itk(vtkvec, vec3d_mm); } void mitk::AbstractTransformGeometry::IndexToWorld(const mitk::Point2D &pt_units, mitk::Point2D &pt_mm) const { m_Plane->IndexToWorld(pt_units, pt_mm); } void mitk::AbstractTransformGeometry::WorldToIndex(const mitk::Point2D &pt_mm, mitk::Point2D &pt_units) const { m_Plane->WorldToIndex(pt_mm, pt_units); } void mitk::AbstractTransformGeometry::IndexToWorld(const mitk::Point2D &atPt2d_units, const mitk::Vector2D &vec_units, mitk::Vector2D &vec_mm) const { MITK_WARN<<"Warning! Call of the deprecated function AbstractTransformGeometry::IndexToWorld(point, vec, vec). Use AbstractTransformGeometry::IndexToWorld(vec, vec) instead!"; this->IndexToWorld(vec_units, vec_mm); } void mitk::AbstractTransformGeometry::IndexToWorld(const mitk::Vector2D &vec_units, mitk::Vector2D &vec_mm) const { m_Plane->IndexToWorld(vec_units, vec_mm); } void mitk::AbstractTransformGeometry::WorldToIndex(const mitk::Point2D &atPt2d_mm, const mitk::Vector2D &vec_mm, mitk::Vector2D &vec_units) const { MITK_WARN<<"Warning! Call of the deprecated function AbstractTransformGeometry::WorldToIndex(point, vec, vec). Use AbstractTransformGeometry::WorldToIndex(vec, vec) instead!"; this->WorldToIndex(vec_mm, vec_units); } void mitk::AbstractTransformGeometry::WorldToIndex(const mitk::Vector2D &vec_mm, mitk::Vector2D &vec_units) const { m_Plane->WorldToIndex(vec_mm, vec_units); } bool mitk::AbstractTransformGeometry::IsAbove(const mitk::Point3D& pt3d_mm) const { assert((m_ItkVtkAbstractTransform.IsNotNull()) && (m_Plane.IsNotNull())); Point3D pt3d_ParametricWorld; pt3d_ParametricWorld = m_ItkVtkAbstractTransform->BackTransform(pt3d_mm); Point3D pt3d_ParametricUnits; ((Geometry3D*)m_Plane)->WorldToIndex(pt3d_ParametricWorld, pt3d_ParametricUnits); return (pt3d_ParametricUnits[2] > m_ParametricBoundingBox->GetBounds()[4]); } void mitk::AbstractTransformGeometry::SetVtkAbstractTransform(vtkAbstractTransform* aVtkAbstractTransform) { m_ItkVtkAbstractTransform->SetVtkAbstractTransform(aVtkAbstractTransform); } void mitk::AbstractTransformGeometry::SetPlane(const mitk::PlaneGeometry* aPlane) { if(aPlane!=NULL) { m_Plane = static_cast(aPlane->Clone().GetPointer()); BoundingBox::BoundsArrayType b=m_Plane->GetBoundingBox()->GetBounds(); SetParametricBounds(b); CalculateFrameGeometry(); } else { if(m_Plane.IsNull()) return; m_Plane=NULL; } Modified(); } void mitk::AbstractTransformGeometry::CalculateFrameGeometry() { if((m_Plane.IsNull()) || (m_FrameGeometry.IsNotNull())) return; //@warning affine-transforms and bounding-box should be set by specific sub-classes! SetBounds(m_Plane->GetBoundingBox()->GetBounds()); } void mitk::AbstractTransformGeometry::SetFrameGeometry(const mitk::Geometry3D* frameGeometry) { if((frameGeometry != NULL) && (frameGeometry->IsValid())) { m_FrameGeometry = static_cast(frameGeometry->Clone().GetPointer()); SetIndexToWorldTransform(m_FrameGeometry->GetIndexToWorldTransform()); SetBounds(m_FrameGeometry->GetBounds()); } else { m_FrameGeometry = NULL; } } unsigned long mitk::AbstractTransformGeometry::GetMTime() const { if(Superclass::GetMTime()GetMTime()) return m_ItkVtkAbstractTransform->GetMTime(); return Superclass::GetMTime(); } void mitk::AbstractTransformGeometry::SetOversampling(float oversampling) { if(m_Plane.IsNull()) { itkExceptionMacro(<< "m_Plane is not set."); } mitk::BoundingBox::BoundsArrayType bounds = m_Plane->GetBounds(); bounds[1]*=oversampling; bounds[3]*=oversampling; bounds[5]*=oversampling; SetParametricBounds(bounds); } mitk::AffineGeometryFrame3D::Pointer mitk::AbstractTransformGeometry::Clone() const { - Self::Pointer newGeometry = Self::New(); - newGeometry->Initialize(); - InitializeGeometry(newGeometry); + Self::Pointer newGeometry = new AbstractTransformGeometry(*this); + newGeometry->UnRegister(); return newGeometry.GetPointer(); } - -void mitk::AbstractTransformGeometry::InitializeGeometry(Self * newGeometry) const -{ - Superclass::InitializeGeometry(newGeometry); - - if(m_ParametricBoundingBox.IsNotNull()) - newGeometry->SetParametricBounds(m_ParametricBoundingBox->GetBounds()); - - newGeometry->SetPlane(m_Plane); - - newGeometry->SetFrameGeometry(m_FrameGeometry); -} diff --git a/Core/Code/DataManagement/mitkAbstractTransformGeometry.h b/Core/Code/DataManagement/mitkAbstractTransformGeometry.h index 195b80aafe..3a409d5bfb 100644 --- a/Core/Code/DataManagement/mitkAbstractTransformGeometry.h +++ b/Core/Code/DataManagement/mitkAbstractTransformGeometry.h @@ -1,180 +1,180 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef MITKVTKABSTRACTTRANSFORMPLANEGEOMETRY_H_HEADER_INCLUDED_C1C68A2C #define MITKVTKABSTRACTTRANSFORMPLANEGEOMETRY_H_HEADER_INCLUDED_C1C68A2C #include "mitkCommon.h" #include "mitkGeometry2D.h" #include "mitkPlaneGeometry.h" #include "itkVtkAbstractTransform.h" class vtkAbstractTransform; namespace mitk { //##Documentation //## @brief Describes a geometry defined by an vtkAbstractTransform and a plane //## //## vtkAbstractTransform is the most general transform in vtk (superclass for //## all vtk geometric transformations). It defines an arbitrary 3D transformation, //## i.e., a transformation of 3D space into 3D space. In contrast, //## AbstractTransformGeometry (since it is a subclass of Geometry2D) describes a //## 2D manifold in 3D space. The 2D manifold is defined as the manifold that results //## from transforming a rectangle (given in m_Plane as a PlaneGeometry) by the //## vtkAbstractTransform (given in m_VtkAbstractTransform). //## The PlaneGeometry m_Plane is used to define the parameter space. 2D coordinates are //## first mapped by the PlaneGeometry and the resulting 3D coordinates are put into //## the vtkAbstractTransform. //## @note This class is the superclass of concrete geometries. Since there is no //## write access to the vtkAbstractTransform and m_Plane, this class is somehow //## abstract. For full write access from extern, use ExternAbstractTransformGeometry. //## @note The bounds of the PlaneGeometry are used as the parametric bounds. //## @sa ExternAbstractTransformGeometry //## @ingroup Geometry class MITK_CORE_EXPORT AbstractTransformGeometry : public Geometry2D { public: mitkClassMacro(AbstractTransformGeometry, Geometry2D); itkNewMacro(Self); //##Documentation //## @brief Get the vtkAbstractTransform (stored in m_VtkAbstractTransform) virtual vtkAbstractTransform* GetVtkAbstractTransform() const; virtual unsigned long GetMTime() const; //##Documentation //## @brief Get the rectangular area that is used for transformation by //## m_VtkAbstractTransform and therewith defines the 2D manifold described by //## AbstractTransformGeometry itkGetConstObjectMacro(Plane, PlaneGeometry); virtual bool Project(const mitk::Point3D &pt3d_mm, mitk::Point3D &projectedPt3d_mm) const; virtual bool Map(const mitk::Point3D &pt3d_mm, mitk::Point2D &pt2d_mm) const; virtual void Map(const mitk::Point2D &pt2d_mm, mitk::Point3D &pt3d_mm) const; virtual bool Project(const mitk::Point3D & atPt3d_mm, const mitk::Vector3D &vec3d_mm, mitk::Vector3D &projectedVec3d_mm) const; virtual bool Map(const mitk::Point3D & atPt3d_mm, const mitk::Vector3D &vec3d_mm, mitk::Vector2D &vec2d_mm) const; virtual void Map(const mitk::Point2D & atPt2d_mm, const mitk::Vector2D &vec2d_mm, mitk::Vector3D &vec3d_mm) const; virtual void IndexToWorld(const mitk::Point2D &pt_units, mitk::Point2D &pt_mm) const; virtual void WorldToIndex(const mitk::Point2D &pt_mm, mitk::Point2D &pt_units) const; //##Documentation //## @brief Convert (continuous or discrete) index coordinates of a \em vector //## \a vec_units to world coordinates (in mm) //## @deprecated First parameter (Point2D) is not used. If possible, please use void IndexToWorld(const mitk::Vector2D& vec_units, mitk::Vector2D& vec_mm) const. //## For further information about coordinates types, please see the Geometry documentation virtual void IndexToWorld(const mitk::Point2D &atPt2d_units, const mitk::Vector2D &vec_units, mitk::Vector2D &vec_mm) const; //##Documentation //## @brief Convert (continuous or discrete) index coordinates of a \em vector //## \a vec_units to world coordinates (in mm) //## For further information about coordinates types, please see the Geometry documentation virtual void IndexToWorld(const mitk::Vector2D &vec_units, mitk::Vector2D &vec_mm) const; //##Documentation //## @brief Convert world coordinates (in mm) of a \em vector //## \a vec_mm to (continuous!) index coordinates. //## @deprecated First parameter (Point2D) is not used. If possible, please use void WorldToIndex(const mitk::Vector2D& vec_mm, mitk::Vector2D& vec_units) const. //## For further information about coordinates types, please see the Geometry documentation virtual void WorldToIndex(const mitk::Point2D &atPt2d_mm, const mitk::Vector2D &vec_mm, mitk::Vector2D &vec_units) const; //##Documentation //## @brief Convert world coordinates (in mm) of a \em vector //## \a vec_mm to (continuous!) index coordinates. //## For further information about coordinates types, please see the Geometry documentation virtual void WorldToIndex(const mitk::Vector2D &vec_mm, mitk::Vector2D &vec_units) const; virtual bool IsAbove(const Point3D& pt3d_mm) const; virtual mitk::ScalarType GetParametricExtentInMM(int direction) const; virtual const Transform3D* GetParametricTransform() const; //##Documentation //## @brief Change the parametric bounds to @a oversampling times //## the bounds of m_Plane. //## //## The change is done once (immediately). Later changes of the bounds //## of m_Plane will not influence the parametric bounds. (Consequently, //## there is no method to get the oversampling.) virtual void SetOversampling(float oversampling); virtual void Initialize(); //##Documentation //## @brief Calculates the standard part of a Geometry3D //## (IndexToWorldTransform and bounding box) around the //## curved geometry. Has to be implemented in subclasses. //## //## \sa SetFrameGeometry virtual void CalculateFrameGeometry(); //##Documentation //## @brief Set the frame geometry which is used as the standard //## part of an Geometry3D (IndexToWorldTransform and bounding box) //## //## Maybe used as a hint within which the interpolation shall occur //## by concrete sub-classes. //## \sa CalculateFrameGeometry virtual void SetFrameGeometry(const mitk::Geometry3D* frameGeometry); virtual AffineGeometryFrame3D::Pointer Clone() const; protected: AbstractTransformGeometry(); + AbstractTransformGeometry(const AbstractTransformGeometry& other); + virtual ~AbstractTransformGeometry(); - - void InitializeGeometry(Self * newGeometry) const; - + //##Documentation //## @brief Set the vtkAbstractTransform (stored in m_VtkAbstractTransform) //## //## Protected in this class, made public in ExternAbstractTransformGeometry. virtual void SetVtkAbstractTransform(vtkAbstractTransform* aVtkAbstractTransform); //##Documentation //## @brief Set the rectangular area that is used for transformation by //## m_VtkAbstractTransform and therewith defines the 2D manifold described by //## ExternAbstractTransformGeometry //## //## Protected in this class, made public in ExternAbstractTransformGeometry. //## @note The bounds of the PlaneGeometry are used as the parametric bounds. //## @note The PlaneGeometry is cloned, @em not linked/referenced. virtual void SetPlane(const mitk::PlaneGeometry* aPlane); //##Documentation //## @brief The rectangular area that is used for transformation by //## m_VtkAbstractTransform and therewith defines the 2D manifold described by //## AbstractTransformGeometry. mitk::PlaneGeometry::Pointer m_Plane; itk::VtkAbstractTransform::Pointer m_ItkVtkAbstractTransform; mitk::Geometry3D::Pointer m_FrameGeometry; }; } // namespace mitk #endif /* MITKVTKABSTRACTTRANSFORMPLANEGEOMETRY_H_HEADER_INCLUDED_C1C68A2C */ diff --git a/Core/Code/DataManagement/mitkAnnotationProperty.h b/Core/Code/DataManagement/mitkAnnotationProperty.h index 335f812849..d87976acd3 100644 --- a/Core/Code/DataManagement/mitkAnnotationProperty.h +++ b/Core/Code/DataManagement/mitkAnnotationProperty.h @@ -1,78 +1,79 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date: 2008-04-14 19:45:53 +0200 (Mo, 14 Apr 2008) $ Version: $Revision: 14081 $ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef MITKANNOTATIONPROPERTY_H_HEADER_INCLUDED #define MITKANNOTATIONPROPERTY_H_HEADER_INCLUDED #include "mitkCommon.h" #include "mitkBaseProperty.h" #include "mitkVector.h" #include #include namespace mitk { /** * \brief Property for annotations * \ingroup DataManagement */ class MITK_CORE_EXPORT AnnotationProperty : public BaseProperty { public: mitkClassMacro(AnnotationProperty, BaseProperty); typedef std::string ValueType; itkNewMacro( AnnotationProperty ); mitkNewMacro2Param( AnnotationProperty, const char *, const Point3D & ); mitkNewMacro2Param( AnnotationProperty, const std::string &, const Point3D & ); mitkNewMacro4Param( AnnotationProperty, const char *, ScalarType, ScalarType, ScalarType ); mitkNewMacro4Param( AnnotationProperty, const std::string &, ScalarType, ScalarType, ScalarType ); itkGetStringMacro( Label ); itkSetStringMacro( Label ); const Point3D &GetPosition() const; void SetPosition( const Point3D &position ); virtual bool operator==(const BaseProperty& property ) const; virtual std::string GetValueAsString() const; + virtual BaseProperty& operator=(const BaseProperty& other) { return Superclass::operator=(other); } \ protected: std::string m_Label; Point3D m_Position; AnnotationProperty(); AnnotationProperty( const char *label, const Point3D &position ); AnnotationProperty( const std::string &label, const Point3D &position ); AnnotationProperty( const char *label, ScalarType x, ScalarType y, ScalarType z ); AnnotationProperty( const std::string &label, ScalarType x, ScalarType y, ScalarType z ); }; } // namespace mitk #endif /* MITKANNOTATIONPROPERTY_H_HEADER_INCLUDED */ diff --git a/Core/Code/DataManagement/mitkBaseData.cpp b/Core/Code/DataManagement/mitkBaseData.cpp index c4e91ec5b4..97fc10009f 100644 --- a/Core/Code/DataManagement/mitkBaseData.cpp +++ b/Core/Code/DataManagement/mitkBaseData.cpp @@ -1,355 +1,352 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "mitkBaseData.h" #include #include template class MITK_CORE_EXPORT itk::SmartPointerForwardReference; #define MITK_WEAKPOINTER_PROBLEM_WORKAROUND_ENABLED mitk::BaseData::BaseData() : m_RequestedRegionInitialized(false), m_SmartSourcePointer(NULL), m_SourceOutputIndexDuplicate(0), m_Initialized(true), m_Unregistering(false), m_CalculatingExternalReferenceCount(false), m_ExternalReferenceCount(-1) { m_TimeSlicedGeometry = TimeSlicedGeometry::New(); m_PropertyList = PropertyList::New(); } mitk::BaseData::~BaseData() { m_SmartSourcePointer = NULL; } void mitk::BaseData::InitializeTimeSlicedGeometry(unsigned int timeSteps) { mitk::TimeSlicedGeometry::Pointer timeGeometry = this->GetTimeSlicedGeometry(); mitk::Geometry3D::Pointer g3d = mitk::Geometry3D::New(); g3d->Initialize(); if ( timeSteps > 1 ) { mitk::ScalarType timeBounds[] = {0.0, 1.0}; g3d->SetTimeBounds( timeBounds ); } // The geometry is propagated automatically to the other items, // if EvenlyTimed is true... timeGeometry->InitializeEvenlyTimed( g3d.GetPointer(), timeSteps ); } void mitk::BaseData::UpdateOutputInformation() { if ( this->GetSource() ) { this->GetSource()->UpdateOutputInformation(); } if(m_TimeSlicedGeometry.IsNotNull()) m_TimeSlicedGeometry->UpdateInformation(); } const mitk::TimeSlicedGeometry* mitk::BaseData::GetUpdatedTimeSlicedGeometry() { SetRequestedRegionToLargestPossibleRegion(); UpdateOutputInformation(); return GetTimeSlicedGeometry(); } void mitk::BaseData::Expand( unsigned int timeSteps ) { if( m_TimeSlicedGeometry.IsNotNull() ) m_TimeSlicedGeometry->ExpandToNumberOfTimeSteps( timeSteps ); } const mitk::Geometry3D* mitk::BaseData::GetUpdatedGeometry(int t) { SetRequestedRegionToLargestPossibleRegion(); UpdateOutputInformation(); return GetGeometry(t); } void mitk::BaseData::SetGeometry(Geometry3D* aGeometry3D) { if(aGeometry3D!=NULL) { TimeSlicedGeometry::Pointer timeSlicedGeometry = dynamic_cast(aGeometry3D); if ( timeSlicedGeometry.IsNotNull() ) m_TimeSlicedGeometry = timeSlicedGeometry; else { timeSlicedGeometry = TimeSlicedGeometry::New(); m_TimeSlicedGeometry = timeSlicedGeometry; timeSlicedGeometry->InitializeEvenlyTimed(aGeometry3D, 1); } Modified(); } else if( m_TimeSlicedGeometry.IsNotNull() ) { m_TimeSlicedGeometry = NULL; Modified(); } return; } -void mitk::BaseData::SetGeometry(Geometry3D* aGeometry3D, unsigned int time) -{ - if ( m_TimeSlicedGeometry ) - m_TimeSlicedGeometry->SetGeometry3D(aGeometry3D, time); -} - void mitk::BaseData::SetClonedGeometry(const Geometry3D* aGeometry3D) { SetGeometry(static_cast(aGeometry3D->Clone().GetPointer())); } void mitk::BaseData::SetClonedGeometry(const Geometry3D* aGeometry3D, unsigned int time) { - SetGeometry(static_cast(aGeometry3D->Clone().GetPointer()), time); + if (m_TimeSlicedGeometry) + { + m_TimeSlicedGeometry->SetGeometry3D(static_cast(aGeometry3D->Clone().GetPointer()), time); + } } -bool mitk::BaseData::IsEmpty(unsigned int) const +bool mitk::BaseData::IsEmptyTimeStep(unsigned int) const { return IsInitialized() == false; } bool mitk::BaseData::IsEmpty() const { if(IsInitialized() == false) return true; const TimeSlicedGeometry* timeGeometry = const_cast(this)->GetUpdatedTimeSlicedGeometry(); if(timeGeometry == NULL) return true; unsigned int timeSteps = timeGeometry->GetTimeSteps(); for ( unsigned int t = 0 ; t < timeSteps ; ++t ) { - if(IsEmpty(t) == false) + if(IsEmptyTimeStep(t) == false) return false; } return true; } itk::SmartPointerForwardReference mitk::BaseData::GetSource() const { return static_cast(Superclass::GetSource().GetPointer()); } int mitk::BaseData::GetExternalReferenceCount() const { if(m_CalculatingExternalReferenceCount==false) //this is only needed because a smart-pointer to m_Outputs (private!!) must be created by calling GetOutputs. { m_CalculatingExternalReferenceCount = true; m_ExternalReferenceCount = -1; int realReferenceCount = GetReferenceCount(); if(GetSource()==NULL) { m_ExternalReferenceCount = realReferenceCount; m_CalculatingExternalReferenceCount = false; return m_ExternalReferenceCount; } mitk::BaseProcess::DataObjectPointerArray outputs = m_SmartSourcePointer->GetOutputs(); unsigned int idx; for (idx = 0; idx < outputs.size(); ++idx) { //references of outputs that are not referenced from someone else (reference additional to the reference from this BaseProcess object) are interpreted as non-existent if(outputs[idx]==this) --realReferenceCount; } m_ExternalReferenceCount = realReferenceCount; if(m_ExternalReferenceCount<0) m_ExternalReferenceCount=0; m_CalculatingExternalReferenceCount = false; } else return -1; return m_ExternalReferenceCount; } void mitk::BaseData::UnRegister() const { #ifdef MITK_WEAKPOINTER_PROBLEM_WORKAROUND_ENABLED if(GetReferenceCount()>1) { Superclass::UnRegister(); if((m_Unregistering==false) && (m_SmartSourcePointer.IsNotNull())) { m_Unregistering=true; // the order of the following boolean statement is important: // this->GetSource() returns a SmartPointerForwardReference, // which increases and afterwards decreases the reference count, // which may result in an ExternalReferenceCount of 0, causing // BaseProcess::UnRegister() to destroy us (also we already // about to do that). if((this->m_SmartSourcePointer->GetExternalReferenceCount()==0) || (this->GetSource()==NULL)) m_SmartSourcePointer=NULL; // now the reference count is zero and this object has been destroyed; thus nothing may be done after this line!! else m_Unregistering=false; } } else #endif Superclass::UnRegister(); // now the reference count is zero and this object has been destroyed; thus nothing may be done after this line!! } void mitk::BaseData::ConnectSource(itk::ProcessObject *arg, unsigned int idx) const { #ifdef MITK_WEAKPOINTER_PROBLEM_WORKAROUND_ENABLED itkDebugMacro( "connecting source " << arg << ", source output index " << idx); if ( GetSource() != arg || m_SourceOutputIndexDuplicate != idx) { m_SmartSourcePointer = dynamic_cast(arg); m_SourceOutputIndexDuplicate = idx; Modified(); } #endif } mitk::PropertyList::Pointer mitk::BaseData::GetPropertyList() const { return m_PropertyList; } mitk::BaseProperty::Pointer mitk::BaseData::GetProperty(const char *propertyKey) const { return m_PropertyList->GetProperty(propertyKey); } void mitk::BaseData::SetProperty(const char *propertyKey, BaseProperty* propertyValue) { m_PropertyList->SetProperty(propertyKey, propertyValue); } void mitk::BaseData::SetPropertyList(PropertyList *pList) { m_PropertyList = pList; } void mitk::BaseData::SetOrigin(const mitk::Point3D& origin) { mitk::TimeSlicedGeometry* timeSlicedGeometry = GetTimeSlicedGeometry(); assert(timeSlicedGeometry!=NULL); mitk::Geometry3D* geometry; unsigned int steps = timeSlicedGeometry->GetTimeSteps(); for(unsigned int timestep = 0; timestep < steps; ++timestep) { geometry = GetGeometry(timestep); if(geometry != NULL) { geometry->SetOrigin(origin); } if(GetTimeSlicedGeometry()->GetEvenlyTimed()) { GetTimeSlicedGeometry()->InitializeEvenlyTimed(geometry, steps); break; } } } unsigned long mitk::BaseData::GetMTime() const { unsigned long time = Superclass::GetMTime(); if(m_TimeSlicedGeometry.IsNotNull()) { if((time < m_TimeSlicedGeometry->GetMTime())) { Modified(); return Superclass::GetMTime(); } //unsigned long geometryTime = m_TimeSlicedGeometry->GetMTime(); //if(time < geometryTime) //{ // return geometryTime; //} } return time; } void mitk::BaseData::CopyInformation( const itk::DataObject* data ) { const Self* bd = dynamic_cast(data); if (bd != NULL) { m_TimeSlicedGeometry = dynamic_cast(bd->GetTimeSlicedGeometry()->Clone().GetPointer()); m_PropertyList = bd->GetPropertyList()->Clone(); } else { // pointer could not be cast back down; this can be the case if your filters input // and output objects differ in type; then you have to write your own GenerateOutputInformation method itkExceptionMacro(<< "mitk::BaseData::CopyInformation() cannot cast " << typeid(data).name() << " to " << typeid(Self*).name() ); } } bool mitk::BaseData::IsInitialized() const { return m_Initialized; } void mitk::BaseData::Clear() { this->ClearData(); this->InitializeEmpty(); } void mitk::BaseData::ClearData() { if(m_Initialized) { ReleaseData(); m_Initialized = false; } } void mitk::BaseData::ExecuteOperation(mitk::Operation* /*operation*/) { //empty by default. override if needed! } void mitk::BaseData::PrintSelf(std::ostream& os, itk::Indent indent) const { os << std::endl; os << indent << " TimeSlicedGeometry: "; if(GetTimeSlicedGeometry() == NULL) os << "NULL" << std::endl; else GetTimeSlicedGeometry()->Print(os, indent); } diff --git a/Core/Code/DataManagement/mitkBaseData.h b/Core/Code/DataManagement/mitkBaseData.h index 75693e884e..bb3dc0eb18 100644 --- a/Core/Code/DataManagement/mitkBaseData.h +++ b/Core/Code/DataManagement/mitkBaseData.h @@ -1,395 +1,387 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef BASEDATA_H_HEADER_INCLUDED_C1EBB6FA #define BASEDATA_H_HEADER_INCLUDED_C1EBB6FA #include #include "mitkBaseProcess.h" #include "mitkTimeSlicedGeometry.h" #include "mitkCommon.h" #include "mitkOperationActor.h" #include "mitkPropertyList.h" namespace mitk { class BaseProcess; //##Documentation //## @brief Base of all data objects //## //## Base of all data objects, e.g., images, contours, surfaces etc. Inherits //## from itk::DataObject and thus can be included in a pipeline. //## Inherits also from OperationActor and can be used as a destination for Undo //## @ingroup Data class MITK_CORE_EXPORT BaseData : public itk::DataObject, public OperationActor { public: mitkClassMacro(BaseData,itk::DataObject) //##Documentation //## @brief Return the TimeSlicedGeometry of the data as const pointer. //## //## \warning No update will be called. Use GetUpdatedGeometry() if you cannot //## be sure that the geometry is up-to-date. //## //## Normally used in GenerateOutputInformation of subclasses of BaseProcess. const mitk::TimeSlicedGeometry* GetTimeSlicedGeometry() const { return m_TimeSlicedGeometry.GetPointer(); } //##Documentation //## @brief Return the TimeSlicedGeometry of the data as pointer. //## //## \warning No update will be called. Use GetUpdatedGeometry() if you cannot //## be sure that the geometry is up-to-date. //## //## Normally used in GenerateOutputInformation of subclasses of BaseProcess. mitk::TimeSlicedGeometry* GetTimeSlicedGeometry() { return m_TimeSlicedGeometry.GetPointer(); } //##Documentation //## @brief Return the Geometry3D of the data. //## //## The method does not simply return the value of the m_TimeSlicedGeometry //## member. Before doing this, it makes sure that the TimeSlicedGeometry //## is up-to-date (by setting the update extent to largest possible and //## calling UpdateOutputInformation). const mitk::TimeSlicedGeometry* GetUpdatedTimeSlicedGeometry(); //##Documentation //## @brief Expands the TimeSlicedGeometry to a number of TimeSteps. //## //## The method expands the TimeSlicedGeometry to the given number of TimeSteps, //## filling newly created elements with empty geometries. Sub-classes should override //## this method to handle the elongation of their data vectors, too. //## Note that a shrinking is neither possible nor intended. virtual void Expand( unsigned int timeSteps ); //##Documentation //## @brief Return the Geometry3D of the data at time \a t. //## //## The method does not simply return //## m_TimeSlicedGeometry->GetGeometry(t). //## Before doing this, it makes sure that the Geometry3D is up-to-date //## (by setting the update extent appropriately and calling //## UpdateOutputInformation). //## //## @todo Appropriate setting of the update extent is missing. const mitk::Geometry3D* GetUpdatedGeometry(int t=0); //##Documentation //## @brief Return the geometry, which is a TimeSlicedGeometry, of the data //## as non-const pointer. //## //## \warning No update will be called. Use GetUpdatedGeometry() if you cannot //## be sure that the geometry is up-to-date. //## //## Normally used in GenerateOutputInformation of subclasses of BaseProcess. mitk::Geometry3D* GetGeometry(int t=0) const { if(m_TimeSlicedGeometry.IsNull()) return NULL; return m_TimeSlicedGeometry->GetGeometry3D(t); } //##Documentation //## @brief Helps to deal with the weak-pointer-problem. virtual void UnRegister() const; //##Documentation //## @brief for internal use only. Helps to deal with the //## weak-pointer-problem. virtual int GetExternalReferenceCount() const; //##Documentation //## @brief Update the information for this BaseData (the geometry in particular) //## so that it can be used as an output of a BaseProcess. //## //## This method is used in the pipeline mechanism to propagate information and //## initialize the meta data associated with a BaseData. Any implementation //## of this method in a derived class is assumed to call its source's //## BaseProcess::UpdateOutputInformation() which determines modified //## times, LargestPossibleRegions, and any extra meta data like spacing, //## origin, etc. Default implementation simply call's it's source's //## UpdateOutputInformation(). //## \note Implementations of this methods in derived classes must take care //## that the geometry is updated by calling //## GetTimeSlicedGeometry()->UpdateInformation() //## \em after calling its source's BaseProcess::UpdateOutputInformation(). void UpdateOutputInformation(); //##Documentation //## @brief Set the RequestedRegion to the LargestPossibleRegion. //## //## This forces a filter to produce all of the output in one execution //## (i.e. not streaming) on the next call to Update(). void SetRequestedRegionToLargestPossibleRegion()=0; //##Documentation //## @brief Determine whether the RequestedRegion is outside of the BufferedRegion. //## //## This method returns true if the RequestedRegion //## is outside the BufferedRegion (true if at least one pixel is //## outside). This is used by the pipeline mechanism to determine //## whether a filter needs to re-execute in order to satisfy the //## current request. If the current RequestedRegion is already //## inside the BufferedRegion from the previous execution (and the //## current filter is up to date), then a given filter does not need //## to re-execute bool RequestedRegionIsOutsideOfTheBufferedRegion()=0; //##Documentation //## @brief Verify that the RequestedRegion is within the LargestPossibleRegion. //## //## If the RequestedRegion is not within the LargestPossibleRegion, //## then the filter cannot possibly satisfy the request. This method //## returns true if the request can be satisfied (even if it will be //## necessary to process the entire LargestPossibleRegion) and //## returns false otherwise. This method is used by //## PropagateRequestedRegion(). PropagateRequestedRegion() throws a //## InvalidRequestedRegionError exception if the requested region is //## not within the LargestPossibleRegion. virtual bool VerifyRequestedRegion() = 0; //##Documentation //## @brief Copy information from the specified data set. //## //## This method is part of the pipeline execution model. By default, a //## BaseProcess will copy meta-data from the first input to all of its //## outputs. See ProcessObject::GenerateOutputInformation(). Each //## subclass of DataObject is responsible for being able to copy //## whatever meta-data it needs from another DataObject. //## The default implementation of this method copies the time sliced geometry //## and the property list of an object. If a subclass overrides this //## method, it should always call its superclass' version. void CopyInformation(const itk::DataObject* data); //##Documentation //## @brief Check whether the data has been initialized, i.e., //## at least the Geometry and other header data has been set //## //## \warning Set to \a true by default for compatibility reasons. //## Set m_Initialized=false in constructors of sub-classes that //## support distinction between initialized and uninitialized state. virtual bool IsInitialized() const; //##Documentation //## @brief Calls ClearData() and InitializeEmpty(); //## \warning Only use in subclasses that reimplemented these methods. //## Just calling Clear from BaseData will reset an object to a not initialized, //## invalid state. virtual void Clear(); //##Documentation //## @brief Check whether object contains data (at //## a specified time), e.g., a set of points may be empty //## //## \warning Returns IsInitialized()==false by default for //## compatibility reasons. Override in sub-classes that //## support distinction between empty/non-empty state. - virtual bool IsEmpty(unsigned int t) const; + virtual bool IsEmptyTimeStep(unsigned int t) const; //##Documentation //## @brief Check whether object contains data (at //## least at one point in time), e.g., a set of points //## may be empty //## //## \warning Returns IsInitialized()==false by default for //## compatibility reasons. Override in sub-classes that //## support distinction between empty/non-empty state. virtual bool IsEmpty() const; //##Documentation //## @brief Set the requested region from this data object to match the requested //## region of the data object passed in as a parameter. //## //## This method is implemented in the concrete subclasses of BaseData. void SetRequestedRegion(itk::DataObject *data)=0; //##Documentation //##@brief overwrite if the Data can be called by an Interactor (StateMachine). //## //## Empty by default. Overwrite and implement all the necessary operations here //## and get the necessary information from the parameter operation. void ExecuteOperation(Operation* operation); //##Documentation //## @brief Set the Geometry3D of the data, which will be referenced (not copied!). //## Assumes the data object has only 1 time step ( is a 3D object ). //## //## For convenience (and historic) reasons, it is also possible to set a complete //## mitk::TimeSlicedGeometry*, which will be referenced (not copied!). //## //## @warning This method will normally be called internally by the sub-class of BaseData //## during initialization. //## \sa SetClonedGeometry virtual void SetGeometry(Geometry3D* aGeometry3D); - //##Documentation - //## @brief Set the Geometry3D of a given time step, which will be referenced (not copied!). - //## - //## @warning This method will normally be called internally by the sub-class of BaseData - //## during initialization. - //## \sa SetClonedGeometry - virtual void SetGeometry(Geometry3D* aGeometry3D, unsigned int time); - //##Documentation //## @brief Set a clone of the provided geometry as Geometry3D of the data. //## Assumes the data object has only 1 time step ( is a 3D object ) //## //## \sa SetGeometry virtual void SetClonedGeometry(const Geometry3D* aGeometry3D); //##Documentation //## @brief Set a clone of the provided geometry as Geometry3D of a given time step. //## //## \sa SetGeometry virtual void SetClonedGeometry(const Geometry3D* aGeometry3D, unsigned int time); //##Documentation //## @brief Get the data's property list //## @sa GetProperty //## @sa m_PropertyList mitk::PropertyList::Pointer GetPropertyList() const; //##Documentation //## @brief Set the data's property list //## @sa SetProperty //## @sa m_PropertyList void SetPropertyList(PropertyList* propertyList); //##Documentation //## @brief Get the property (instance of BaseProperty) with key @a propertyKey from the PropertyList, //## and set it to this, respectively; //## @sa GetPropertyList //## @sa m_PropertyList //## @sa m_MapOfPropertyLists mitk::BaseProperty::Pointer GetProperty(const char *propertyKey) const; void SetProperty(const char *propertyKey, BaseProperty* property); //##Documentation //## @brief Convenience method for setting the origin of //## the Geometry3D instances of all time steps //## //## \warning Geometries contained in the Geometry3D will //## \em not be changed, e.g. in case the Geometry3D is a //## SlicedGeometry3D the origin will \em not be propagated //## to the contained slices. The sub-class SlicedData //## does this for the case that the SlicedGeometry3D is //## evenly spaced. virtual void SetOrigin(const Point3D& origin); /** \brief Get the process object that generated this data object. * * If there is no process object, then the data object has * been disconnected from the pipeline, or the data object * was created manually. (Note: we cannot use the GetObjectMacro() * defined in itkMacro because the mutual dependency of * DataObject and ProcessObject causes compile problems. Also, * a forward reference smart pointer is returned, not a smart pointer, * because of the circular dependency between the process and data object.) * * GetSource() returns a SmartPointerForwardReference and not a WeakPointer * because it is assumed the code calling GetSource() wants to hold a * long term reference to the source. */ itk::SmartPointerForwardReference GetSource() const; //##Documentation //## @brief Get the number of time steps from the Timeslicedgeometry //## As the base data has not a data vector given by itself, the number //## of time steps is defined over the time sliced geometry. In sub classes, //## a better implementation could be over the length of the data vector. unsigned int GetTimeSteps() const { return m_TimeSlicedGeometry->GetTimeSteps(); }; //##Documentation //## @brief Get the modified time of the last change of the contents //## this data object or its geometry. virtual unsigned long GetMTime() const; protected: BaseData(); ~BaseData(); //##Documentation //## @brief Initialize the TimeSlicedGeometry for a number of time steps. //## The TimeSlicedGeometry is initialized empty and evenly timed. //## In many cases it will be necessary to overwrite this in sub-classes. virtual void InitializeTimeSlicedGeometry( unsigned int timeSteps = 1 ); //##Documentation //## @brief reset to non-initialized state, release memory virtual void ClearData(); //##Documentation //## @brief Pure virtual; Must be used in subclasses to get a data object to a //## valid state. Should at least create one empty object and call //## Superclass::InitializeTimeSlicedGeometry() to ensure an existing valid geometry virtual void InitializeEmpty(){}; virtual void PrintSelf(std::ostream& os, itk::Indent indent) const; bool m_RequestedRegionInitialized; bool m_LastRequestedRegionWasOutsideOfTheBufferedRegion; mutable itk::SmartPointer m_SmartSourcePointer; mutable unsigned int m_SourceOutputIndexDuplicate; //##Documentation //## @brief for internal use only. Helps to deal with the //## weak-pointer-problem. virtual void ConnectSource(itk::ProcessObject *arg, unsigned int idx) const; bool m_Initialized; private: //##Documentation //## @brief Helps to deal with the weak-pointer-problem. mutable bool m_Unregistering; //##Documentation //## @brief Helps to deal with the weak-pointer-problem. mutable bool m_CalculatingExternalReferenceCount; //##Documentation //## @brief Helps to deal with the weak-pointer-problem. mutable int m_ExternalReferenceCount; //##Documentation //## @brief PropertyList, f.e. to hold pic-tags, tracking-data,.. //## PropertyList::Pointer m_PropertyList; TimeSlicedGeometry::Pointer m_TimeSlicedGeometry; //##Documentation //## @brief Helps to deal with the weak-pointer-problem. friend class mitk::BaseProcess; }; } // namespace mitk #endif /* BASEDATA_H_HEADER_INCLUDED_C1EBB6FA */ diff --git a/Core/Code/DataManagement/mitkClippingProperty.h b/Core/Code/DataManagement/mitkClippingProperty.h index 0c0e3d7e68..1f656c6183 100644 --- a/Core/Code/DataManagement/mitkClippingProperty.h +++ b/Core/Code/DataManagement/mitkClippingProperty.h @@ -1,75 +1,77 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date: 2008-04-14 19:45:53 +0200 (Mo, 14 Apr 2008) $ Version: $Revision: 14081 $ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef MITKCLIPPINGPROPERTY_H_HEADER_INCLUDED #define MITKCLIPPINGPROPERTY_H_HEADER_INCLUDED #include "mitkCommon.h" #include "mitkBaseProperty.h" #include "mitkVector.h" #include #include namespace mitk { /** * \brief Property for clipping datasets; currently only * clipping planes are possible * \ingroup DataManagement */ class MITK_CORE_EXPORT ClippingProperty : public BaseProperty { public: mitkClassMacro(ClippingProperty, BaseProperty); + + virtual BaseProperty& operator=(const BaseProperty& other) { return Superclass::operator=(other); } typedef std::string ValueType; itkNewMacro( ClippingProperty ); mitkNewMacro2Param( ClippingProperty, const Point3D &, const Vector3D & ); bool GetClippingEnabled() const; void SetClippingEnabled( bool enabled ); const Point3D &GetOrigin() const; void SetOrigin( const Point3D &origin ); const Vector3D &GetNormal() const; void SetNormal( const Vector3D &normal ); virtual bool operator==(const BaseProperty& property ) const; virtual std::string GetValueAsString() const; protected: bool m_ClippingEnabled; Point3D m_Origin; Vector3D m_Normal; ClippingProperty(); ClippingProperty( const Point3D &origin, const Vector3D &normal ); }; } // namespace mitk #endif /* MITKCLIPPINGPROPERTY_H_HEADER_INCLUDED */ diff --git a/Core/Code/DataManagement/mitkEnumerationProperty.h b/Core/Code/DataManagement/mitkEnumerationProperty.h index 602392e34a..550965a713 100644 --- a/Core/Code/DataManagement/mitkEnumerationProperty.h +++ b/Core/Code/DataManagement/mitkEnumerationProperty.h @@ -1,215 +1,215 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef _MITK_ENUMERATION_PROPERTY__H_ #define _MITK_ENUMERATION_PROPERTY__H_ #include "mitkBaseProperty.h" #include #include namespace mitk { /** * This class may be used to store properties similar to enumeration values. * Each enumeration value is identified via a string representation and a * id. Note, that both string representation and id MUST be unique. This is checked * when inserting a new enumeration value. Please note that you have to add valid * enumeration values before you may use the Get/SetValue methods. * * To use the class enumeration property you have 2 choices: * * 1. Directly use the class and add your possible enumeration values via * AddEnum(name, id). NOte that the ids do not have to be in any order, they * just have to be unique. The current value is set via SetValue(...) and * retrieved via GetValueAsId() or GetValueAsString(). * 2. Create a subclass, which adds the possible enumeration values in its * constructor and maybe adds some additional convenience functions to * set/get the value. NOte that you should override AddEnum(...) as protected * so that the user may not add additional invalid enumeration values. * As example see mitk::VtkRepresentationProperty or mitk::VtkInterpolationProperty * * @ingroup DataManagement */ class MITK_CORE_EXPORT EnumerationProperty : public BaseProperty { public: mitkClassMacro( EnumerationProperty, BaseProperty ); itkNewMacro(EnumerationProperty); /** * Represents the unique id which is asigned to each enumeration value */ typedef unsigned int IdType; /** * Type used to store a mapping from enumeration id to enumeration string/ * description */ typedef std::map EnumIdsContainerType; /** * Type used to store a mapping from enumeration string/description to * enumeration id */ typedef std::map EnumStringsContainerType; /** * Type used for iterators over all defined enumeration values. */ typedef EnumIdsContainerType::const_iterator EnumConstIterator; /** * Adds an enumeration value into the enumeration. The name and id provided * must be unique. This is checked while adding the new enumeration value. * If it is not unique, false is returned. If addition was successful, true * is returned. * @param name the unique string representation of the enumeration value * @param id the unique integer representation of the enumeration value * @returns true, if the name/id combination was successfully added to the * enumeration values or true otherwise */ virtual bool AddEnum( const std::string& name, const IdType& id ); /** * Sets the current value of the enumeration * @param name the string representation of the enumeration value to set * @returns true if the value was successfully set (i.e. it was valid), or * false, if the name provided is incalid. */ virtual bool SetValue( const std::string& name ); /** * Sets the current value of the enumeration * @param id the integer representation of the enumeration value to set * @returns true if the value was successfully set (i.e. it was valid), or * false, if the id provided is invalid. */ virtual bool SetValue( const IdType& id ); /** * Returns the id of the current enumeration value. If it was not yet set, * the return value is unspecified */ virtual IdType GetValueAsId() const; /** * Returns the string representation of the current enumeration value. If it * was not yet set, the return value is unspecified */ virtual std::string GetValueAsString() const; /** * Clears all possible enumeration values and the current enumeration value. */ virtual void Clear(); /** * Determines the number of enumeration values which have been added via * AddEnum(...). * @returns the number of enumeration values associated with this Enumeration * Property */ virtual EnumIdsContainerType::size_type Size() const; /** * Provides access to the set of known enumeration values. The string representation * may be accessed via iterator->second, the id may be access via iterator->first * @returns an iterator over all enumeration values. */ virtual EnumConstIterator Begin() const; /** * Specifies the end of the range of the known enumeration values. * @returns an iterator pointing past the last known element of the possible * enumeration values. */ virtual EnumConstIterator End() const; /** * Returns the string representation for the given id. * @param id the id for which the string representation should be determined * if id is invalid, the return value is unspecified. * @returns the string representation of the given enumeration value */ virtual std::string GetEnumString( const IdType& id ) const; /** * Returns the integer representation for the given string. * @param name the enumeration name for which the integer representation should be determined * if the name is invalid, the return value is unspecified. * @returns the integer representation of the given enumeration value */ virtual IdType GetEnumId( const std::string& name ) const; /** * Determines if a given integer representation of an enumeration value * is valid or not * @param val the integer value to check * @returns true if the given value is valid or false otherwise */ virtual bool IsValidEnumerationValue( const IdType& val ) const; /** * Determines if a given string representation of an enumeration value * is valid or not * @param val the string to check * @returns true if the given value is valid or false otherwise */ virtual bool IsValidEnumerationValue( const std::string& val ) const; virtual bool operator==( const BaseProperty& property ) const; - + virtual BaseProperty& operator=(const BaseProperty& other) { return Superclass::operator=(other); } const EnumIdsContainerType& GetEnumIds() const; const EnumStringsContainerType& GetEnumStrings() const; EnumIdsContainerType& GetEnumIds(); EnumStringsContainerType& GetEnumStrings(); protected: /** * Default constructor. The current value of the enumeration is undefined. */ EnumerationProperty(); private: IdType m_CurrentValue; EnumIdsContainerType m_EnumIds; EnumStringsContainerType m_EnumStrings; typedef std::map IdMapForClassNameContainerType; typedef std::map StringMapForClassNameContainerType; static IdMapForClassNameContainerType s_IdMapForClassName; static StringMapForClassNameContainerType s_StringMapForClassName; }; } // namespace #endif diff --git a/Core/Code/DataManagement/mitkGenericLookupTable.h b/Core/Code/DataManagement/mitkGenericLookupTable.h index 6e1fe42a1e..5ef973dc1a 100644 --- a/Core/Code/DataManagement/mitkGenericLookupTable.h +++ b/Core/Code/DataManagement/mitkGenericLookupTable.h @@ -1,149 +1,150 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date: 2008-06-24 19:37:48 +0200 (Di, 24 Jun 2008) $ Version: $Revision: 14641 $ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef MITKGENERICLOOKUPTABLE_H_HEADER_INCLUDED_C1061CEE #define MITKGENERICLOOKUPTABLE_H_HEADER_INCLUDED_C1061CEE #include #include #include #include #include #include "mitkVector.h" #include "mitkCommon.h" namespace mitk { /** * @brief Template class for generating lookup-tables * * This class template can be instantiated for all classes/internal types that fulfills * these requirements: * - an operator<< so that the properties value can be put into a std::stringstream * - an operator== so that two properties can be checked for equality * * The main purpose of this class is to be used in conjunction with * GenericLookupTableProperty. This enables passing of arbitrary lookup * tables to mappers to configure the rendering process. */ template class GenericLookupTable { public: typedef unsigned int IdentifierType; typedef T ValueType; typedef std::map< IdentifierType, ValueType > LookupTableType; typedef GenericLookupTable Self; GenericLookupTable() {} virtual ~GenericLookupTable() { } virtual const char *GetNameOfClass() const { return "GenericLookupTable"; } void SetTableValue( IdentifierType id, ValueType value ) { m_LookupTable[id] = value; } bool ValueExists(IdentifierType id) const { typename LookupTableType::const_iterator it = m_LookupTable.find(id); return (it != m_LookupTable.end()); } ValueType GetTableValue( IdentifierType id ) const { typename LookupTableType::const_iterator it = m_LookupTable.find(id); if (it != m_LookupTable.end()) return it->second; else throw std::range_error("id does not exist in the lookup table"); } const LookupTableType& GetLookupTable() const { return m_LookupTable; } bool operator==( const Self& lookupTable ) const { return (m_LookupTable == lookupTable.m_LookupTable); } bool operator!=( const Self& lookupTable ) const { return !(m_LookupTable == lookupTable.m_LookupTable); } virtual Self& operator=(const Self& other) // \TODO: this needs to be unit tested! { if ( this == &other ) { return *this; } else { m_LookupTable.clear(); m_LookupTable = other.m_LookupTable; return *this; } } protected: LookupTableType m_LookupTable; }; } // namespace mitk /** * Generates a specialized subclass of mitk::GenericLookupTable. * This way, GetNameOfClass() returns the value provided by LookupTableName. * Please see mitkProperties.h for examples. * @param LookupTableName the name of the instantiation of GenericLookupTable * @param Type the value type of the GenericLookupTable */ #define mitkSpecializeGenericLookupTable(LookupTableName,Type) \ class MITK_CORE_EXPORT LookupTableName: public GenericLookupTable< Type > \ { \ public: \ typedef LookupTableName Self; \ typedef GenericLookupTable< Type > Superclass; \ virtual const char *GetNameOfClass() const \ {return #LookupTableName;} \ LookupTableName() {} \ + virtual Superclass& operator=(const Superclass& other) { return Superclass::operator=(other); } \ virtual ~LookupTableName() {} \ }; \ std::ostream& operator<<(std::ostream& stream, const LookupTableName& /*l*/); /** * Generates the ostream << operator for the lookuptable. This definition * of a global function must be in a cpp file, therefore it is split from the * class declaration macro mitkSpecializeGenericLookupTable. */ #define mitkSpecializeGenericLookupTableOperator(LookupTableName) \ std::ostream& mitk::operator<<(std::ostream& stream, const LookupTableName& /*l*/) \ { \ return stream; \ }; #endif diff --git a/Core/Code/DataManagement/mitkGenericProperty.h b/Core/Code/DataManagement/mitkGenericProperty.h index b31b9956a2..fd3e0201fb 100644 --- a/Core/Code/DataManagement/mitkGenericProperty.h +++ b/Core/Code/DataManagement/mitkGenericProperty.h @@ -1,149 +1,150 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef MITKGENERICPROPERTY_H_HEADER_INCLUDED_C1061CEE #define MITKGENERICPROPERTY_H_HEADER_INCLUDED_C1061CEE #include #include #include #include "mitkVector.h" #include "mitkCommon.h" #include "mitkBaseProperty.h" namespace mitk { /*! @ brief Template class for generating properties for int, float, bool, etc. This class template can be instantiated for all classes/internal types that fulfills these requirements: - an operator<< so that the properties value can be put into a std::stringstream - an operator== so that two properties can be checked for equality Note: you must use the macro mitkSpecializeGenericProperty to provide specializations for concrete types (e.g. BoolProperty). Please see mitkProperties.h for examples. If you don't use the mitkSpecializeGenericProperty Macro, GetNameOfClass() returns a wrong name. */ template class GenericProperty : public BaseProperty { public: mitkClassMacro(GenericProperty, BaseProperty); mitkNewMacro1Param(GenericProperty, T); typedef T ValueType; virtual ~GenericProperty() { } itkSetMacro(Value,T); itkGetConstMacro(Value,T); virtual bool operator==(const BaseProperty& other) const { try { const Self *otherProp = dynamic_cast(&other); if(otherProp==NULL) return false; if (this->m_Value == otherProp->m_Value) return true; } catch (std::bad_cast) { // nothing to do now - just return false } return false; } virtual std::string GetValueAsString() const { std::stringstream myStr; myStr << GetValue() ; return myStr.str(); } virtual bool Assignable(const BaseProperty& other) const { try { dynamic_cast(other); // dear compiler, please don't optimize this away! return true; } catch (std::bad_cast) { } return false; } virtual BaseProperty& operator=(const BaseProperty& other) { try { const Self& otherProp( dynamic_cast(other) ); if (this->m_Value != otherProp.m_Value) { this->m_Value = otherProp.m_Value; this->Modified(); } } catch (std::bad_cast) { // nothing to do then } return *this; } protected: GenericProperty() {} GenericProperty(T x) : m_Value(x) {} T m_Value; }; } // namespace mitk /** * Generates a specialized subclass of mitk::GenericProperty. * This way, GetNameOfClass() returns the value provided by PropertyName. * Please see mitkProperties.h for examples. * @param PropertyName the name of the instantiation of GenericProperty * @param Type the value type of the GenericProperty */ #define mitkSpecializeGenericProperty(PropertyName,Type,DefaultValue) \ class MITK_CORE_EXPORT PropertyName: public GenericProperty< Type > \ { \ public: \ mitkClassMacro(PropertyName, GenericProperty< Type >); \ itkNewMacro(PropertyName); \ mitkNewMacro1Param(PropertyName, Type); \ virtual ~PropertyName() {} \ + virtual BaseProperty& operator=(const BaseProperty& other) { return Superclass::operator=(other); } \ protected: \ PropertyName() { m_Value = DefaultValue; } \ PropertyName(Type x) : GenericProperty(x) {} \ }; #endif /* MITKGENERICPROPERTY_H_HEADER_INCLUDED_C1061CEE */ diff --git a/Core/Code/DataManagement/mitkGeometry2D.cpp b/Core/Code/DataManagement/mitkGeometry2D.cpp index 29fe5e370e..3dfdb48c34 100644 --- a/Core/Code/DataManagement/mitkGeometry2D.cpp +++ b/Core/Code/DataManagement/mitkGeometry2D.cpp @@ -1,275 +1,273 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "mitkGeometry2D.h" #include mitk::Geometry2D::Geometry2D() : m_ScaleFactorMMPerUnitX( 1.0 ), m_ScaleFactorMMPerUnitY( 1.0 ), m_ReferenceGeometry( NULL ) { } +mitk::Geometry2D::Geometry2D(const Geometry2D& other) + : Geometry3D(other), m_ScaleFactorMMPerUnitX( other.m_ScaleFactorMMPerUnitX), + m_ScaleFactorMMPerUnitY( other.m_ScaleFactorMMPerUnitY), + m_ReferenceGeometry( other.m_ReferenceGeometry ) +{ +} + + mitk::Geometry2D::~Geometry2D() { } void mitk::Geometry2D::SetIndexToWorldTransform( mitk::AffineTransform3D* transform) { Superclass::SetIndexToWorldTransform(transform); m_ScaleFactorMMPerUnitX=GetExtentInMM(0)/GetExtent(0); m_ScaleFactorMMPerUnitY=GetExtentInMM(1)/GetExtent(1); assert(m_ScaleFactorMMPerUnitX(m_BoundingBox.GetPointer())->IsInside(pt3d_units); } void mitk::Geometry2D::Map(const mitk::Point2D &pt2d_mm, mitk::Point3D &pt3d_mm) const { Point3D pt3d_units; pt3d_units[0]=pt2d_mm[0]/m_ScaleFactorMMPerUnitX; pt3d_units[1]=pt2d_mm[1]/m_ScaleFactorMMPerUnitY; pt3d_units[2]=0; pt3d_mm = GetParametricTransform()->TransformPoint(pt3d_units); } void mitk::Geometry2D::IndexToWorld( const mitk::Point2D &/*pt_units*/, mitk::Point2D &/*pt_mm*/) const { itkExceptionMacro(<< "No general transform possible (only affine) ==> no general" \ " IndexToWorld(const mitk::Point2D &pt_mm, mitk::Point2D &pt_units)" \ " possible. Has to be implemented in sub-class."); } void mitk::Geometry2D::WorldToIndex( const mitk::Point2D &/*pt_mm*/, mitk::Point2D &/*pt_units*/) const { itkExceptionMacro(<< "No general back transform possible (only affine) ==> no general" \ " WorldToIndex(const mitk::Point2D &pt_mm, mitk::Point2D &pt_units)" \ " possible. Has to be implemented in sub-class."); } void mitk::Geometry2D::IndexToWorld(const mitk::Point2D &/*atPt2d_units*/, const mitk::Vector2D &/*vec_units*/, mitk::Vector2D &/*vec_mm*/) const { itkExceptionMacro(<< "No general transform possible (only affine) ==> no general" \ " IndexToWorld(const mitk::Vector2D &vec_mm, mitk::Vector2D &vec_units)" \ " possible. Has to be implemented in sub-class."); } void mitk::Geometry2D::WorldToIndex(const mitk::Point2D &/*atPt2d_mm*/, const mitk::Vector2D &/*vec_mm*/, mitk::Vector2D &/*vec_units*/) const { itkExceptionMacro(<< "No general back transform possible (only affine) ==> no general" \ " WorldToIndex(const mitk::Vector2D &vec_mm, mitk::Vector2D &vec_units)" \ " possible. Has to be implemented in sub-class."); } void mitk::Geometry2D::SetSizeInUnits(mitk::ScalarType width, mitk::ScalarType height) { ScalarType bounds[6]={0, width, 0, height, 0, 1}; ScalarType extent, newextentInMM; if(GetExtent(0)>0) { extent = GetExtent(0); if(width>extent) newextentInMM = GetExtentInMM(0)/width*extent; else newextentInMM = GetExtentInMM(0)*extent/width; SetExtentInMM(0, newextentInMM); } if(GetExtent(1)>0) { extent = GetExtent(1); if(width>extent) newextentInMM = GetExtentInMM(1)/height*extent; else newextentInMM = GetExtentInMM(1)*extent/height; SetExtentInMM(1, newextentInMM); } SetBounds(bounds); } bool mitk::Geometry2D::Project( const mitk::Point3D &pt3d_mm, mitk::Point3D &projectedPt3d_mm) const { assert(m_BoundingBox.IsNotNull()); Point3D pt3d_units; BackTransform(pt3d_mm, pt3d_units); pt3d_units[2] = 0; projectedPt3d_mm = GetParametricTransform()->TransformPoint(pt3d_units); return const_cast(m_BoundingBox.GetPointer())->IsInside(pt3d_units); } bool mitk::Geometry2D::Map(const mitk::Point3D & atPt3d_mm, const mitk::Vector3D &vec3d_mm, mitk::Vector2D &vec2d_mm) const { Point2D pt2d_mm_start, pt2d_mm_end; Point3D pt3d_mm_end; bool inside=Map(atPt3d_mm, pt2d_mm_start); pt3d_mm_end = atPt3d_mm+vec3d_mm; inside&=Map(pt3d_mm_end, pt2d_mm_end); vec2d_mm=pt2d_mm_end-pt2d_mm_start; return inside; } void mitk::Geometry2D::Map(const mitk::Point2D &/*atPt2d_mm*/, const mitk::Vector2D &/*vec2d_mm*/, mitk::Vector3D &/*vec3d_mm*/) const { //@todo implement parallel to the other Map method! assert(false); } bool mitk::Geometry2D::Project(const mitk::Point3D & atPt3d_mm, const mitk::Vector3D &vec3d_mm, mitk::Vector3D &projectedVec3d_mm) const { assert(m_BoundingBox.IsNotNull()); Vector3D vec3d_units; BackTransform(atPt3d_mm, vec3d_mm, vec3d_units); vec3d_units[2] = 0; projectedVec3d_mm = GetParametricTransform()->TransformVector(vec3d_units); Point3D pt3d_units; BackTransform(atPt3d_mm, pt3d_units); return const_cast(m_BoundingBox.GetPointer())->IsInside(pt3d_units); } mitk::ScalarType mitk::Geometry2D::SignedDistance(const mitk::Point3D& pt3d_mm) const { Point3D projectedPoint; Project(pt3d_mm, projectedPoint); Vector3D direction = pt3d_mm-projectedPoint; ScalarType distance = direction.GetNorm(); if(IsAbove(pt3d_mm) == false) distance*=-1.0; return distance; } bool mitk::Geometry2D::IsAbove(const mitk::Point3D& pt3d_mm) const { Point3D pt3d_units; Geometry3D::WorldToIndex(pt3d_mm, pt3d_units); return (pt3d_units[2] > m_BoundingBox->GetBounds()[4]); } -mitk::AffineGeometryFrame3D::Pointer +mitk::AffineGeometryFrame3D::Pointer mitk::Geometry2D::Clone() const { - Self::Pointer newGeometry = Self::New(); - newGeometry->Initialize(); - InitializeGeometry(newGeometry); + Self::Pointer newGeometry = new Geometry2D(*this); + newGeometry->UnRegister(); return newGeometry.GetPointer(); } - -void -mitk::Geometry2D::InitializeGeometry(Self * newGeometry) const -{ - Superclass::InitializeGeometry(newGeometry); - - newGeometry->SetReferenceGeometry( m_ReferenceGeometry ); -} - void mitk::Geometry2D::PrintSelf(std::ostream& os, itk::Indent indent) const { Superclass::PrintSelf(os,indent); os << indent << " ScaleFactorMMPerUnitX: " << m_ScaleFactorMMPerUnitX << std::endl; os << indent << " ScaleFactorMMPerUnitY: " << m_ScaleFactorMMPerUnitY << std::endl; } void mitk::Geometry2D::SetReferenceGeometry( mitk::Geometry3D *geometry ) { m_ReferenceGeometry = geometry; } mitk::Geometry3D * mitk::Geometry2D::GetReferenceGeometry() const { return m_ReferenceGeometry; } bool mitk::Geometry2D::HasReferenceGeometry() const { return ( m_ReferenceGeometry != NULL ); } diff --git a/Core/Code/DataManagement/mitkGeometry2D.h b/Core/Code/DataManagement/mitkGeometry2D.h index 2074f58443..be4e082542 100644 --- a/Core/Code/DataManagement/mitkGeometry2D.h +++ b/Core/Code/DataManagement/mitkGeometry2D.h @@ -1,264 +1,264 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef GEOMETRY2D_H_HEADER_INCLUDED_C1F4D8E0 #define GEOMETRY2D_H_HEADER_INCLUDED_C1F4D8E0 #include "mitkCommon.h" #include "mitkGeometry3D.h" namespace mitk { /** * \brief Describes the geometry of a two-dimensional object * * Describes a two-dimensional manifold, i.e., to put it simply, * an object that can be described using a 2D coordinate-system. * * Geometry2D can map points between 3D world coordinates * (in mm) and the described 2D coordinate-system (in mm) by first projecting * the 3D point onto the 2D manifold and then calculating the 2D-coordinates * (in mm). These 2D-mm-coordinates can be further converted into * 2D-unit-coordinates (e.g., pixels), giving a parameter representation of * the object with parameter values inside a rectangle * (e.g., [0,0]..[width, height]), which is the bounding box (bounding range * in z-direction always [0]..[1]). * * A Geometry2D describes the 2D representation within a 3D object and is * therefore itself a Geometry3D (derived from Geometry3D). For example, * a single CT-image (slice) is 2D in the sense that you can access the * pixels using 2D-coordinates, but is also 3D, as the pixels are really * voxels, thus have an extension (thickness) in the 3rd dimension. * * Most often, instances of Geometry2D will be used to descibe a plane, * which is represented by the sub-class PlaneGeometry, but curved * surfaces are also possible. * * Optionally, a reference Geometry3D can be specified, which usually would * be the geometry associated with the underlying dataset. This is currently * used for calculating the intersection of inclined / rotated planes * (represented as Geometry2D) with the bounding box of the associated * Geometry3D. * * \warning The Geometry2Ds are not necessarily up-to-date and not even * initialized. As described in the previous paragraph, one of the * Generate-/Copy-/UpdateOutputInformation methods have to initialize it. * mitk::BaseData::GetGeometry2D() makes sure, that the Geometry2D is * up-to-date before returning it (by setting the update extent appropriately * and calling UpdateOutputInformation). * * Rule: everything is in mm (or ms for temporal information) if not * stated otherwise. * \ingroup Geometry */ class MITK_CORE_EXPORT Geometry2D : public mitk::Geometry3D { public: mitkClassMacro(Geometry2D, mitk::Geometry3D); itkNewMacro(Self); /** * \brief Project a 3D point given in mm (\a pt3d_mm) onto the 2D * geometry. The result is a 2D point in mm (\a pt2d_mm). * * The result is a 2D point in mm (\a pt2d_mm) relative to the upper-left * corner of the geometry. To convert this point into units (e.g., pixels * in case of an image), use WorldToIndex. * \return true projection was possible * \sa Project(const mitk::Point3D &pt3d_mm, mitk::Point3D * &projectedPt3d_mm) */ virtual bool Map(const mitk::Point3D &pt3d_mm, mitk::Point2D &pt2d_mm) const; /** * \brief Converts a 2D point given in mm (\a pt2d_mm) relative to the * upper-left corner of the geometry into the corresponding * world-coordinate (a 3D point in mm, \a pt3d_mm). * * To convert a 2D point given in units (e.g., pixels in case of an * image) into a 2D point given in mm (as required by this method), use * IndexToWorld. */ virtual void Map(const mitk::Point2D &pt2d_mm, mitk::Point3D &pt3d_mm) const; /** * \brief Convert a 2D point given in units (e.g., pixels in case of an * image) into a 2D point given in mm */ virtual void IndexToWorld( const mitk::Point2D &pt_units, mitk::Point2D &pt_mm) const; /** * \brief Convert a 2D point given in mm into a 2D point given in mm * (e.g., pixels in case of an image) */ virtual void WorldToIndex( const mitk::Point2D &pt_mm, mitk::Point2D &pt_units) const; /** * \brief Convert a 2D vector given in units (e.g., pixels in case of an * image) into a 2D vector given in mm * \warning strange: in contrast to vtkTransform the class itk::Transform * does not have the parameter, \em where the vector that is to be * transformed is located. This method here should also need this * information for general transforms. */ virtual void IndexToWorld( const mitk::Point2D &atPt2d_units, const mitk::Vector2D &vec_units, mitk::Vector2D &vec_mm) const; /** * \brief Convert a 2D vector given in mm into a 2D point vector in mm * (e.g., pixels in case of an image) * \warning strange: in contrast to vtkTransform the class itk::Transform * does not have the parameter, \em where the vector that is to be * transformed is located. This method here should also need this * information for general transforms. */ virtual void WorldToIndex( const mitk::Point2D &atPt2d_mm, const mitk::Vector2D &vec_mm, mitk::Vector2D &vec_units) const; /** * \brief Set the width and height of this 2D-geometry in units by calling * SetBounds. This does \a not change the extent in mm! * * For an image, this is the number of pixels in x-/y-direction. * \note In contrast to calling SetBounds directly, this does \a not change * the extent in mm! */ virtual void SetSizeInUnits(mitk::ScalarType width, mitk::ScalarType height); /** * \brief Project a 3D point given in mm (\a pt3d_mm) onto the 2D * geometry. The result is a 3D point in mm (\a projectedPt3d_mm). * * \return true projection was possible */ virtual bool Project(const mitk::Point3D &pt3d_mm, mitk::Point3D &projectedPt3d_mm) const; /** * \brief Project a 3D vector given in mm (\a vec3d_mm) onto the 2D * geometry. The result is a 2D vector in mm (\a vec2d_mm). * * The result is a 2D vector in mm (\a vec2d_mm) relative to the * upper-left * corner of the geometry. To convert this point into units (e.g., pixels * in case of an image), use WorldToIndex. * \return true projection was possible * \sa Project(const mitk::Vector3D &vec3d_mm, mitk::Vector3D * &projectedVec3d_mm) */ virtual bool Map(const mitk::Point3D & atPt3d_mm, const mitk::Vector3D &vec3d_mm, mitk::Vector2D &vec2d_mm) const; /** * \brief Converts a 2D vector given in mm (\a vec2d_mm) relative to the * upper-left corner of the geometry into the corresponding * world-coordinate (a 3D vector in mm, \a vec3d_mm). * * To convert a 2D vector given in units (e.g., pixels in case of an * image) into a 2D vector given in mm (as required by this method), use * IndexToWorld. */ virtual void Map(const mitk::Point2D & atPt2d_mm, const mitk::Vector2D &vec2d_mm, mitk::Vector3D &vec3d_mm) const; /** * \brief Project a 3D vector given in mm (\a vec3d_mm) onto the 2D * geometry. The result is a 3D vector in mm (\a projectedVec3d_mm). * * \return true projection was possible */ virtual bool Project(const mitk::Point3D & atPt3d_mm, const mitk::Vector3D &vec3d_mm, mitk::Vector3D &projectedVec3d_mm) const; /** * \brief Distance of the point from the geometry * (bounding-box \em not considered) * */ inline ScalarType Distance(const Point3D& pt3d_mm) const { return fabs(SignedDistance(pt3d_mm)); } /** * \brief Signed distance of the point from the geometry * (bounding-box \em not considered) * */ virtual ScalarType SignedDistance(const Point3D& pt3d_mm) const; /** * \brief Test if the point is above the geometry * (bounding-box \em not considered) * */ virtual bool IsAbove(const Point3D& pt3d_mm) const; virtual void SetIndexToWorldTransform(mitk::AffineTransform3D* transform); virtual void SetExtentInMM(int direction, ScalarType extentInMM); virtual AffineGeometryFrame3D::Pointer Clone() const; /** * \brief Set the geometrical frame of reference in which this Geometry2D * is placed. * * This would usually be the Geometry3D of the underlying dataset, but * setting it is optional. */ void SetReferenceGeometry( mitk::Geometry3D *geometry ); /** * \brief Get the geometrical frame of reference for this Geometry2D. */ Geometry3D *GetReferenceGeometry() const; bool HasReferenceGeometry() const; protected: Geometry2D(); + + Geometry2D(const Geometry2D& other); virtual ~Geometry2D(); - virtual void InitializeGeometry(Self * newGeometry) const; - virtual void PrintSelf(std::ostream& os, itk::Indent indent) const; /** * \brief factor to convert x-coordinates from mm to units and vice versa * */ mutable mitk::ScalarType m_ScaleFactorMMPerUnitX; /** * \brief factor to convert y-coordinates from mm to units and vice versa * */ mutable mitk::ScalarType m_ScaleFactorMMPerUnitY; mitk::Geometry3D *m_ReferenceGeometry; }; } // namespace mitk #endif /* GEOMETRY2D_H_HEADER_INCLUDED_C1F4D8E0 */ diff --git a/Core/Code/DataManagement/mitkGeometry3D.cpp b/Core/Code/DataManagement/mitkGeometry3D.cpp index de755a370c..009be4fdcf 100644 --- a/Core/Code/DataManagement/mitkGeometry3D.cpp +++ b/Core/Code/DataManagement/mitkGeometry3D.cpp @@ -1,717 +1,731 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "mitkGeometry3D.h" #include "mitkMatrixConvert.h" #include "mitkRotationOperation.h" #include "mitkPointOperation.h" #include "mitkInteractionConst.h" //#include "mitkStatusBar.h" #include #include // Standard constructor for the New() macro. Sets the geometry to 3 dimensions mitk::Geometry3D::Geometry3D() : m_ParametricBoundingBox(NULL), m_ImageGeometry(false), m_Valid(true), m_FrameOfReferenceID(0), m_IndexToWorldTransformLastModified(0) { FillVector3D(m_FloatSpacing, 1,1,1); m_VtkMatrix = vtkMatrix4x4::New(); m_VtkIndexToWorldTransform = vtkMatrixToLinearTransform::New(); m_VtkIndexToWorldTransform->SetInput(m_VtkMatrix); Initialize(); } +mitk::Geometry3D::Geometry3D(const Geometry3D& other) : Superclass(), m_ParametricBoundingBox(other.m_ParametricBoundingBox),m_TimeBounds(other.m_TimeBounds), + m_ImageGeometry(other.m_ImageGeometry), m_Valid(other.m_Valid), m_FrameOfReferenceID(other.m_FrameOfReferenceID), m_IndexToWorldTransformLastModified(other.m_IndexToWorldTransformLastModified), m_RotationQuaternion( other.m_RotationQuaternion ) , m_Origin(other.m_Origin) +{ + // AffineGeometryFrame + SetBounds(other.GetBounds()); + //SetIndexToObjectTransform(other.GetIndexToObjectTransform()); + //SetObjectToNodeTransform(other.GetObjectToNodeTransform()); + //SetIndexToWorldTransform(other.GetIndexToWorldTransform()); + // this is not used in AffineGeometryFrame of ITK, thus there are not Get and Set methods + // m_IndexToNodeTransform = other.m_IndexToNodeTransform; + // m_InvertedTransform = TransformType::New(); + // m_InvertedTransform = TransformType::New(); + // m_InvertedTransform->DeepCopy(other.m_InvertedTransform); + m_VtkMatrix = vtkMatrix4x4::New(); + m_VtkMatrix->DeepCopy(other.m_VtkMatrix); + if (other.m_ParametricBoundingBox.IsNotNull()) + { + m_ParametricBoundingBox = other.m_ParametricBoundingBox->DeepCopy(); + } + FillVector3D(m_FloatSpacing,other.m_FloatSpacing[0],other.m_FloatSpacing[1],other.m_FloatSpacing[2]); + m_VtkIndexToWorldTransform = vtkMatrixToLinearTransform::New(); + m_VtkIndexToWorldTransform->DeepCopy(other.m_VtkIndexToWorldTransform); + other.InitializeGeometry(this); +} mitk::Geometry3D::~Geometry3D() { m_VtkMatrix->Delete(); m_VtkIndexToWorldTransform->Delete(); } static void CopySpacingFromTransform(mitk::AffineTransform3D* transform, mitk::Vector3D& spacing, float floatSpacing[3]) { mitk::AffineTransform3D::MatrixType::InternalMatrixType vnlmatrix; vnlmatrix = transform->GetMatrix().GetVnlMatrix(); spacing[0]=vnlmatrix.get_column(0).magnitude(); spacing[1]=vnlmatrix.get_column(1).magnitude(); spacing[2]=vnlmatrix.get_column(2).magnitude(); floatSpacing[0]=spacing[0]; floatSpacing[1]=spacing[1]; floatSpacing[2]=spacing[2]; } void mitk::Geometry3D::Initialize() { float b[6] = {0,1,0,1,0,1}; SetFloatBounds(b); m_IndexToObjectTransform = TransformType::New(); m_ObjectToNodeTransform = TransformType::New(); if(m_IndexToWorldTransform.IsNull()) m_IndexToWorldTransform = TransformType::New(); else m_IndexToWorldTransform->SetIdentity(); CopySpacingFromTransform(m_IndexToWorldTransform, m_Spacing, m_FloatSpacing); vtk2itk(m_IndexToWorldTransform->GetOffset(), m_Origin); m_VtkMatrix->Identity(); m_TimeBounds[0]=ScalarTypeNumericTraits::NonpositiveMin(); m_TimeBounds[1]=ScalarTypeNumericTraits::max(); m_FrameOfReferenceID = 0; m_ImageGeometry = false; } void mitk::Geometry3D::TransferItkToVtkTransform() { // copy m_IndexToWorldTransform into m_VtkIndexToWorldTransform TransferItkTransformToVtkMatrix(m_IndexToWorldTransform.GetPointer(), m_VtkMatrix); m_VtkIndexToWorldTransform->Modified(); } void mitk::Geometry3D::TransferVtkToItkTransform() { TransferVtkMatrixToItkTransform(m_VtkMatrix, m_IndexToWorldTransform.GetPointer()); CopySpacingFromTransform(m_IndexToWorldTransform, m_Spacing, m_FloatSpacing); vtk2itk(m_IndexToWorldTransform->GetOffset(), m_Origin); } void mitk::Geometry3D::SetIndexToWorldTransformByVtkMatrix(vtkMatrix4x4* vtkmatrix) { m_VtkMatrix->DeepCopy(vtkmatrix); TransferVtkToItkTransform(); } void mitk::Geometry3D::SetTimeBounds(const TimeBounds& timebounds) { if(m_TimeBounds != timebounds) { m_TimeBounds = timebounds; Modified(); } } void mitk::Geometry3D::SetFloatBounds(const float bounds[6]) { mitk::BoundingBox::BoundsArrayType b; const float *input = bounds; int i=0; for(mitk::BoundingBox::BoundsArrayType::Iterator it = b.Begin(); i < 6 ;++i) *it++ = (mitk::ScalarType)*input++; SetBoundsArray(b, m_BoundingBox); } void mitk::Geometry3D::SetFloatBounds(const double bounds[6]) { mitk::BoundingBox::BoundsArrayType b; const double *input = bounds; int i=0; for(mitk::BoundingBox::BoundsArrayType::Iterator it = b.Begin(); i < 6 ;++i) *it++ = (mitk::ScalarType)*input++; SetBoundsArray(b, m_BoundingBox); } void mitk::Geometry3D::SetParametricBounds(const BoundingBox::BoundsArrayType& bounds) { SetBoundsArray(bounds, m_ParametricBoundingBox); } void mitk::Geometry3D::WorldToIndex(const mitk::Point3D &pt_mm, mitk::Point3D &pt_units) const { BackTransform(pt_mm, pt_units); } void mitk::Geometry3D::IndexToWorld(const mitk::Point3D &pt_units, mitk::Point3D &pt_mm) const { pt_mm = m_IndexToWorldTransform->TransformPoint(pt_units); } void mitk::Geometry3D::WorldToIndex(const mitk::Point3D &atPt3d_mm, const mitk::Vector3D &vec_mm, mitk::Vector3D &vec_units) const { MITK_WARN<<"Warning! Call of the deprecated function Geometry3D::WorldToIndex(point, vec, vec). Use Geometry3D::WorldToIndex(vec, vec) instead!"; //BackTransform(atPt3d_mm, vec_mm, vec_units); this->WorldToIndex(vec_mm, vec_units); } void mitk::Geometry3D::WorldToIndex( const mitk::Vector3D &vec_mm, mitk::Vector3D &vec_units) const { BackTransform( vec_mm, vec_units); } void mitk::Geometry3D::IndexToWorld(const mitk::Point3D &/*atPt3d_units*/, const mitk::Vector3D &vec_units, mitk::Vector3D &vec_mm) const { MITK_WARN<<"Warning! Call of the deprecated function Geometry3D::IndexToWorld(point, vec, vec). Use Geometry3D::IndexToWorld(vec, vec) instead!"; //vec_mm = m_IndexToWorldTransform->TransformVector(vec_units); this->IndexToWorld(vec_units, vec_mm); } void mitk::Geometry3D::IndexToWorld(const mitk::Vector3D &vec_units, mitk::Vector3D &vec_mm) const { vec_mm = m_IndexToWorldTransform->TransformVector(vec_units); } void mitk::Geometry3D::SetIndexToWorldTransform(mitk::AffineTransform3D* transform) { if(m_IndexToWorldTransform.GetPointer() != transform) { Superclass::SetIndexToWorldTransform(transform); CopySpacingFromTransform(m_IndexToWorldTransform, m_Spacing, m_FloatSpacing); vtk2itk(m_IndexToWorldTransform->GetOffset(), m_Origin); TransferItkToVtkTransform(); Modified(); } } mitk::AffineGeometryFrame3D::Pointer mitk::Geometry3D::Clone() const { - Self::Pointer newGeometry = Self::New(); - newGeometry->Initialize(); - InitializeGeometry(newGeometry); + Self::Pointer newGeometry = new Self(*this); + newGeometry->UnRegister(); return newGeometry.GetPointer(); } - +/* void mitk::Geometry3D::InitializeGeometry(Geometry3D * newGeometry) const { Superclass::InitializeGeometry(newGeometry); newGeometry->SetTimeBounds(m_TimeBounds); //newGeometry->GetVtkTransform()->SetMatrix(m_VtkIndexToWorldTransform->GetMatrix()); IW //newGeometry->TransferVtkToItkTransform(); //MH newGeometry->SetFrameOfReferenceID(GetFrameOfReferenceID()); newGeometry->m_ImageGeometry = m_ImageGeometry; } - +*/ void mitk::Geometry3D::SetExtentInMM(int direction, ScalarType extentInMM) { ScalarType len = GetExtentInMM(direction); if(fabs(len - extentInMM)>=mitk::eps) { AffineTransform3D::MatrixType::InternalMatrixType vnlmatrix; vnlmatrix = m_IndexToWorldTransform->GetMatrix().GetVnlMatrix(); if(len>extentInMM) vnlmatrix.set_column(direction, vnlmatrix.get_column(direction)/len*extentInMM); else vnlmatrix.set_column(direction, vnlmatrix.get_column(direction)*extentInMM/len); Matrix3D matrix; matrix = vnlmatrix; m_IndexToWorldTransform->SetMatrix(matrix); Modified(); } } mitk::BoundingBox::Pointer mitk::Geometry3D::CalculateBoundingBoxRelativeToTransform(const mitk::AffineTransform3D* transform) const { mitk::BoundingBox::PointsContainer::Pointer pointscontainer=mitk::BoundingBox::PointsContainer::New(); mitk::BoundingBox::PointIdentifier pointid=0; unsigned char i; if(transform!=NULL) { mitk::AffineTransform3D::Pointer inverse = mitk::AffineTransform3D::New(); transform->GetInverse(inverse); for(i=0; i<8; ++i) pointscontainer->InsertElement( pointid++, inverse->TransformPoint( GetCornerPoint(i) )); } else { for(i=0; i<8; ++i) pointscontainer->InsertElement( pointid++, GetCornerPoint(i) ); } mitk::BoundingBox::Pointer result = mitk::BoundingBox::New(); result->SetPoints(pointscontainer); result->ComputeBoundingBox(); return result; } #include void mitk::Geometry3D::ExecuteOperation(Operation* operation) { vtkTransform *vtktransform = vtkTransform::New(); vtktransform->SetMatrix(m_VtkMatrix); switch (operation->GetOperationType()) { case OpNOTHING: break; case OpMOVE: { mitk::PointOperation *pointOp = dynamic_cast(operation); if (pointOp == NULL) { //mitk::StatusBar::GetInstance()->DisplayText("received wrong type of operation!See mitkAffineInteractor.cpp", 10000); return; } mitk::Point3D newPos = pointOp->GetPoint(); ScalarType data[3]; vtktransform->GetPosition(data); vtktransform->PostMultiply(); vtktransform->Translate(newPos[0], newPos[1], newPos[2]); vtktransform->PreMultiply(); break; } case OpSCALE: { mitk::PointOperation *pointOp = dynamic_cast(operation); if (pointOp == NULL) { //mitk::StatusBar::GetInstance()->DisplayText("received wrong type of operation!See mitkAffineInteractor.cpp", 10000); return; } mitk::Point3D newScale = pointOp->GetPoint(); ScalarType data[3]; /* calculate new scale: newscale = oldscale * (oldscale + scaletoadd)/oldscale */ data[0] = 1 + (newScale[0] / GetMatrixColumn(0).magnitude()); data[1] = 1 + (newScale[1] / GetMatrixColumn(1).magnitude()); data[2] = 1 + (newScale[2] / GetMatrixColumn(2).magnitude()); mitk::Point3D center = const_cast(m_BoundingBox.GetPointer())->GetCenter(); ScalarType pos[3]; vtktransform->GetPosition(pos); vtktransform->PostMultiply(); vtktransform->Translate(-pos[0], -pos[1], -pos[2]); vtktransform->Translate(-center[0], -center[1], -center[2]); vtktransform->PreMultiply(); vtktransform->Scale(data[0], data[1], data[2]); vtktransform->PostMultiply(); vtktransform->Translate(+center[0], +center[1], +center[2]); vtktransform->Translate(pos[0], pos[1], pos[2]); vtktransform->PreMultiply(); break; } case OpROTATE: { mitk::RotationOperation *rotateOp = dynamic_cast(operation); if (rotateOp == NULL) { //mitk::StatusBar::GetInstance()->DisplayText("received wrong type of operation!See mitkAffineInteractor.cpp", 10000); return; } Vector3D rotationVector = rotateOp->GetVectorOfRotation(); Point3D center = rotateOp->GetCenterOfRotation(); ScalarType angle = rotateOp->GetAngleOfRotation(); vtktransform->PostMultiply(); vtktransform->Translate(-center[0], -center[1], -center[2]); vtktransform->RotateWXYZ(angle, rotationVector[0], rotationVector[1], rotationVector[2]); vtktransform->Translate(center[0], center[1], center[2]); vtktransform->PreMultiply(); break; } default: vtktransform->Delete(); return; } m_VtkMatrix->DeepCopy(vtktransform->GetMatrix()); TransferVtkToItkTransform(); Modified(); vtktransform->Delete(); } void mitk::Geometry3D::BackTransform(const mitk::Point3D &in, mitk::Point3D& out) const { ScalarType temp[3]; unsigned int i, j; const TransformType::OffsetType& offset = m_IndexToWorldTransform->GetOffset(); // Remove offset for (j = 0; j < 3; j++) { temp[j] = in[j] - offset[j]; } // Get WorldToIndex transform if (m_IndexToWorldTransformLastModified != m_IndexToWorldTransform->GetMTime()) { m_InvertedTransform = TransformType::New(); if (!m_IndexToWorldTransform->GetInverse( m_InvertedTransform.GetPointer() )) { itkExceptionMacro( "Internal ITK matrix inversion error, cannot proceed." ); } m_IndexToWorldTransformLastModified = m_IndexToWorldTransform->GetMTime(); } // Check for valid matrix inversion const TransformType::MatrixType& inverse = m_InvertedTransform->GetMatrix(); if(inverse.GetVnlMatrix().has_nans()) { itkExceptionMacro( "Internal ITK matrix inversion error, cannot proceed. Matrix was: " << std::endl << m_IndexToWorldTransform->GetMatrix() << "Suggested inverted matrix is:" << std::endl << inverse ); } // Transform point for (i = 0; i < 3; i++) { out[i] = 0.0; for (j = 0; j < 3; j++) { out[i] += inverse[i][j]*temp[j]; } } } void mitk::Geometry3D::BackTransform(const mitk::Point3D &/*at*/, const mitk::Vector3D &in, mitk::Vector3D& out) const { MITK_INFO<<"Warning! Call of the deprecated function Geometry3D::BackTransform(point, vec, vec). Use Geometry3D::BackTransform(vec, vec) instead!"; //// Get WorldToIndex transform //if (m_IndexToWorldTransformLastModified != m_IndexToWorldTransform->GetMTime()) //{ // m_InvertedTransform = TransformType::New(); // if (!m_IndexToWorldTransform->GetInverse( m_InvertedTransform.GetPointer() )) // { // itkExceptionMacro( "Internal ITK matrix inversion error, cannot proceed." ); // } // m_IndexToWorldTransformLastModified = m_IndexToWorldTransform->GetMTime(); //} //// Check for valid matrix inversion //const TransformType::MatrixType& inverse = m_InvertedTransform->GetMatrix(); //if(inverse.GetVnlMatrix().has_nans()) //{ // itkExceptionMacro( "Internal ITK matrix inversion error, cannot proceed. Matrix was: " << std::endl // << m_IndexToWorldTransform->GetMatrix() << "Suggested inverted matrix is:" << std::endl // << inverse ); //} //// Transform vector //for (unsigned int i = 0; i < 3; i++) //{ // out[i] = 0.0; // for (unsigned int j = 0; j < 3; j++) // { // out[i] += inverse[i][j]*in[j]; // } //} this->BackTransform(in, out); } void mitk::Geometry3D::BackTransform(const mitk::Vector3D& in, mitk::Vector3D& out) const { // Get WorldToIndex transform if (m_IndexToWorldTransformLastModified != m_IndexToWorldTransform->GetMTime()) { m_InvertedTransform = TransformType::New(); if (!m_IndexToWorldTransform->GetInverse( m_InvertedTransform.GetPointer() )) { itkExceptionMacro( "Internal ITK matrix inversion error, cannot proceed." ); } m_IndexToWorldTransformLastModified = m_IndexToWorldTransform->GetMTime(); } // Check for valid matrix inversion const TransformType::MatrixType& inverse = m_InvertedTransform->GetMatrix(); if(inverse.GetVnlMatrix().has_nans()) { itkExceptionMacro( "Internal ITK matrix inversion error, cannot proceed. Matrix was: " << std::endl << m_IndexToWorldTransform->GetMatrix() << "Suggested inverted matrix is:" << std::endl << inverse ); } // Transform vector for (unsigned int i = 0; i < 3; i++) { out[i] = 0.0; for (unsigned int j = 0; j < 3; j++) { out[i] += inverse[i][j]*in[j]; } } } const float* mitk::Geometry3D::GetFloatSpacing() const { return m_FloatSpacing; } -void mitk::Geometry3D::SetSpacing(const float aSpacing[3]) -{ - mitk::Vector3D tmp; - tmp[0]= aSpacing[0]; - tmp[1]= aSpacing[1]; - tmp[2]= aSpacing[2]; - SetSpacing(tmp); -} - void mitk::Geometry3D::SetSpacing(const mitk::Vector3D& aSpacing) { if(mitk::Equal(m_Spacing, aSpacing) == false) { assert(aSpacing[0]>0 && aSpacing[1]>0 && aSpacing[2]>0); m_Spacing = aSpacing; AffineTransform3D::MatrixType::InternalMatrixType vnlmatrix; vnlmatrix = m_IndexToWorldTransform->GetMatrix().GetVnlMatrix(); mitk::VnlVector col; col = vnlmatrix.get_column(0); col.normalize(); col*=aSpacing[0]; vnlmatrix.set_column(0, col); col = vnlmatrix.get_column(1); col.normalize(); col*=aSpacing[1]; vnlmatrix.set_column(1, col); col = vnlmatrix.get_column(2); col.normalize(); col*=aSpacing[2]; vnlmatrix.set_column(2, col); Matrix3D matrix; matrix = vnlmatrix; AffineTransform3D::Pointer transform = AffineTransform3D::New(); transform->SetMatrix(matrix); transform->SetOffset(m_IndexToWorldTransform->GetOffset()); SetIndexToWorldTransform(transform.GetPointer()); itk2vtk(m_Spacing, m_FloatSpacing); } } void mitk::Geometry3D::SetOrigin(const Point3D & origin) { if(origin!=GetOrigin()) { m_Origin = origin; m_IndexToWorldTransform->SetOffset(m_Origin.GetVectorFromOrigin()); Modified(); TransferItkToVtkTransform(); } } void mitk::Geometry3D::Translate(const Vector3D & vector) { if((vector[0] != 0) || (vector[1] != 0) || (vector[2] != 0)) { m_IndexToWorldTransform->SetOffset(m_IndexToWorldTransform->GetOffset()+vector); TransferItkToVtkTransform(); Modified(); } } void mitk::Geometry3D::SetIdentity() { m_IndexToWorldTransform->SetIdentity(); m_Origin.Fill(0); Modified(); TransferItkToVtkTransform(); } void mitk::Geometry3D::Compose( const mitk::AffineGeometryFrame3D::TransformType * other, bool pre ) { m_IndexToWorldTransform->Compose(other, pre); CopySpacingFromTransform(m_IndexToWorldTransform, m_Spacing, m_FloatSpacing); vtk2itk(m_IndexToWorldTransform->GetOffset(), m_Origin); Modified(); TransferItkToVtkTransform(); } void mitk::Geometry3D::Compose( const vtkMatrix4x4 * vtkmatrix, bool pre ) { mitk::AffineGeometryFrame3D::TransformType::Pointer itkTransform = mitk::AffineGeometryFrame3D::TransformType::New(); TransferVtkMatrixToItkTransform(vtkmatrix, itkTransform.GetPointer()); Compose(itkTransform, pre); } const char* mitk::Geometry3D::GetTransformAsString( TransformType* transformType ) { static char buffer[255]; for ( int j=0; j<255; j++) buffer[j] = '\0'; ostrstream out( buffer, 255 ); out << '['; for( int i=0; i<3; ++i ) { out << '['; for( int j=0; j<3; ++j ) out << transformType->GetMatrix().GetVnlMatrix().get(i, j) << ' '; out << ']'; } out << "]["; for( int i=0; i<3; ++i ) out << transformType->GetOffset()[i] << ' '; out << "]\0"; return buffer; } void mitk::Geometry3D::PrintSelf(std::ostream& os, itk::Indent indent) const { os << indent << " IndexToWorldTransform: "; if(m_IndexToWorldTransform.IsNull()) os << "NULL" << std::endl; else { // from itk::MatrixOffsetTransformBase unsigned int i, j; os << std::endl; os << indent << "Matrix: " << std::endl; for (i = 0; i < 3; i++) { os << indent.GetNextIndent(); for (j = 0; j < 3; j++) { os << m_IndexToWorldTransform->GetMatrix()[i][j] << " "; } os << std::endl; } os << indent << "Offset: " << m_IndexToWorldTransform->GetOffset() << std::endl; os << indent << "Center: " << m_IndexToWorldTransform->GetCenter() << std::endl; os << indent << "Translation: " << m_IndexToWorldTransform->GetTranslation() << std::endl; os << indent << "Inverse: " << std::endl; for (i = 0; i < 3; i++) { os << indent.GetNextIndent(); for (j = 0; j < 3; j++) { os << m_IndexToWorldTransform->GetInverseMatrix()[i][j] << " "; } os << std::endl; } // from itk::ScalableAffineTransform os << indent << "Scale : "; for (i = 0; i < 3; i++) { os << m_IndexToWorldTransform->GetScale()[i] << " "; } os << std::endl; } os << indent << " BoundingBox: "; if(m_BoundingBox.IsNull()) os << "NULL" << std::endl; else { os << indent << "( "; for (unsigned int i=0; i<3; i++) { os << m_BoundingBox->GetBounds()[2*i] << "," << m_BoundingBox->GetBounds()[2*i+1] << " "; } os << " )" << std::endl; } os << indent << " Origin: " << m_Origin << std::endl; os << indent << " ImageGeometry: " << m_ImageGeometry << std::endl; os << indent << " Spacing: " << m_Spacing << std::endl; os << indent << " TimeBounds: " << m_TimeBounds << std::endl; } mitk::Point3D mitk::Geometry3D::GetCornerPoint(int id) const { assert(id >= 0); assert(m_BoundingBox.IsNotNull()); BoundingBox::BoundsArrayType bounds = m_BoundingBox->GetBounds(); Point3D cornerpoint; switch(id) { case 0: FillVector3D(cornerpoint, bounds[0],bounds[2],bounds[4]); break; case 1: FillVector3D(cornerpoint, bounds[0],bounds[2],bounds[5]); break; case 2: FillVector3D(cornerpoint, bounds[0],bounds[3],bounds[4]); break; case 3: FillVector3D(cornerpoint, bounds[0],bounds[3],bounds[5]); break; case 4: FillVector3D(cornerpoint, bounds[1],bounds[2],bounds[4]); break; case 5: FillVector3D(cornerpoint, bounds[1],bounds[2],bounds[5]); break; case 6: FillVector3D(cornerpoint, bounds[1],bounds[3],bounds[4]); break; case 7: FillVector3D(cornerpoint, bounds[1],bounds[3],bounds[5]); break; default: { itkExceptionMacro(<<"A cube only has 8 corners. These are labeled 0-7."); return NULL; } } if(m_ImageGeometry) { // Here i have to adjust the 0.5 offset manually, because the cornerpoint is the corner of the // bounding box. The bounding box itself is no image, so it is corner-based FillVector3D(cornerpoint, cornerpoint[0]-0.5, cornerpoint[1]-0.5, cornerpoint[2]-0.5); } return m_IndexToWorldTransform->TransformPoint(cornerpoint); } mitk::Point3D mitk::Geometry3D::GetCornerPoint(bool xFront, bool yFront, bool zFront) const { assert(m_BoundingBox.IsNotNull()); BoundingBox::BoundsArrayType bounds = m_BoundingBox->GetBounds(); Point3D cornerpoint; cornerpoint[0] = (xFront ? bounds[0] : bounds[1]); cornerpoint[1] = (yFront ? bounds[2] : bounds[3]); cornerpoint[2] = (zFront ? bounds[4] : bounds[5]); if(m_ImageGeometry) { // Here i have to adjust the 0.5 offset manually, because the cornerpoint is the corner of the // bounding box. The bounding box itself is no image, so it is corner-based FillVector3D(cornerpoint, cornerpoint[0]-0.5, cornerpoint[1]-0.5, cornerpoint[2]-0.5); } return m_IndexToWorldTransform->TransformPoint(cornerpoint); } void mitk::Geometry3D::ResetSubTransforms() { } void mitk::Geometry3D::ChangeImageGeometryConsideringOriginOffset( const bool isAnImageGeometry ) { // If Geometry is switched to ImageGeometry, you have to put an offset to the origin, because // imageGeometries origins are pixel-center-based // ... and remove the offset, if you switch an imageGeometry back to a normal geometry // For more information please see the Geometry documentation page if(m_ImageGeometry == isAnImageGeometry) return; const BoundingBox::BoundsArrayType& boundsarray = this->GetBoundingBox()->GetBounds(); Point3D originIndex; FillVector3D(originIndex, boundsarray[0], boundsarray[2], boundsarray[4]); if(isAnImageGeometry == true) FillVector3D( originIndex, originIndex[0] + 0.5, originIndex[1] + 0.5, originIndex[2] + 0.5 ); else FillVector3D( originIndex, originIndex[0] - 0.5, originIndex[1] - 0.5, originIndex[2] - 0.5 ); Point3D originWorld; originWorld = GetIndexToWorldTransform() ->TransformPoint( originIndex ); // instead could as well call IndexToWorld(originIndex,originWorld); SetOrigin(originWorld); this->SetImageGeometry(isAnImageGeometry); -} \ No newline at end of file +} diff --git a/Core/Code/DataManagement/mitkGeometry3D.h b/Core/Code/DataManagement/mitkGeometry3D.h index 76aed22e3d..6782431d58 100644 --- a/Core/Code/DataManagement/mitkGeometry3D.h +++ b/Core/Code/DataManagement/mitkGeometry3D.h @@ -1,693 +1,680 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef GEOMETRY3D_H_HEADER_INCLUDED_C1EBD0AD #define GEOMETRY3D_H_HEADER_INCLUDED_C1EBD0AD #include "mitkCommon.h" #include "mitkVector.h" #include "mitkOperationActor.h" #include #include #include #include class vtkLinearTransform; class vtkMatrixToLinearTransform; class vtkMatrix4x4; namespace mitk { //##Documentation //## @brief Standard 3D-BoundingBox typedef //## //## Standard 3D-BoundingBox typedef to get rid of template arguments (3D, type). typedef itk::BoundingBox BoundingBox; //##Documentation //## @brief Standard typedef for time-bounds typedef itk::FixedArray TimeBounds; typedef itk::FixedArray FixedArrayType; typedef itk::AffineGeometryFrame AffineGeometryFrame3D; //##Documentation //## @brief Describes the geometry of a data object //## //## At least, it can return the bounding box of the data object. //## //## The class holds //## \li a bounding box which is axes-parallel in intrinsic coordinates //## (often integer indices of pixels), to be accessed by //## GetBoundingBox() //## \li a transform to convert intrinsic coordinates into a //## world-coordinate system with coordinates in millimeters //## and milliseconds (all are floating point values), to //## be accessed by GetIndexToWorldTransform() //## \li a life span, i.e. a bounding box in time in ms (with //## start and end time), to be accessed by GetTimeBounds(). //## The default is minus infinity to plus infinity. //## //## Geometry3D and its sub-classes allow converting between //## intrinsic coordinates (called index or unit coordinates) //## and world-coordinates (called world or mm coordinates), //## e.g. WorldToIndex. //## In case you need integer index coordinates, provide an //## mitk::Index3D (or itk::Index) as target variable to //## WorldToIndex, otherwise you will get a continuous index //## (floating point values). //## //## An important sub-class is SlicedGeometry3D, which descibes //## data objects consisting of slices, e.g., objects of type Image. //## Conversions between world coordinates (in mm) and unit coordinates //## (e.g., pixels in the case of an Image) can be performed. //## //## For more information on related classes, see \ref Geometry. //## //## Geometry3D instances referring to an Image need a slightly //## different definition of corners, see SetImageGeometry. This //## is usualy automatically called by Image. //## //## Geometry3D have to be initialized in the method GenerateOutputInformation() //## of BaseProcess (or CopyInformation/ UpdateOutputInformation of BaseData, //## if possible, e.g., by analyzing pic tags in Image) subclasses. See also //## itk::ProcessObject::GenerateOutputInformation(), //## itk::DataObject::CopyInformation() and //## itk::DataObject::UpdateOutputInformation(). //## //## Rule: everything is in mm (ms) if not stated otherwise. //## @ingroup Geometry class MITK_CORE_EXPORT Geometry3D : public AffineGeometryFrame3D, public OperationActor { public: mitkClassMacro(Geometry3D, AffineGeometryFrame3D); typedef itk::QuaternionRigidTransform< ScalarType > QuaternionTransformType; typedef QuaternionTransformType::VnlQuaternionType VnlQuaternionType; /** Method for creation through the object factory. */ itkNewMacro(Self); // a bit of a misuse, but we want only doxygen to see the following: #ifdef DOXYGEN_SKIP //##Documentation //## @brief Get the transformation used to convert from index //## to world coordinates itkGetObjectMacro(IndexToWorldTransform, AffineTransform3D); #endif //## @brief Set the transformation used to convert from index //## to world coordinates virtual void SetIndexToWorldTransform(mitk::AffineTransform3D* transform); //##Documentation //## @brief Convenience method for setting the ITK transform //## (m_IndexToWorldTransform) via an vtkMatrix4x4 //## \sa SetIndexToWorldTransform virtual void SetIndexToWorldTransformByVtkMatrix(vtkMatrix4x4* vtkmatrix); #ifdef DOXYGEN_SKIP //##Documentation //## @brief Get bounding box (in index/unit coordinates) itkGetConstObjectMacro(BoundingBox, BoundingBoxType); //##Documentation //## @brief Get bounding box (in index/unit coordinates) as a BoundsArrayType const BoundsArrayType GetBounds() const { assert(m_BoundingBox.IsNotNull()); return m_BoundingBox->GetBounds(); } //##Documentation //## \brief Set the bounding box (in index/unit coordinates) //## //## Only possible via the BoundsArray to make clear that a //## copy of the bounding-box is stored, not a reference to it. virtual void SetBounds(const BoundsArrayType& bounds); #endif //##Documentation //## @brief Set the bounding box (in index/unit coordinates) via a float array virtual void SetFloatBounds(const float bounds[6]); //##Documentation //## @brief Set the bounding box (in index/unit coordinates) via a double array virtual void SetFloatBounds(const double bounds[6]); //##Documentation //## @brief When switching from an Image Geometry to a normal Geometry (and the other way around), you have to change the origin as well (See Geometry Documentation)! This function will change the "isImageGeometry" bool flag and changes the origin respectively. virtual void ChangeImageGeometryConsideringOriginOffset( const bool isAnImageGeometry ); //##Documentation //## @brief Get the time bounds (in ms) itkGetConstReferenceMacro(TimeBounds, TimeBounds); //##Documentation //## @brief Set the time bounds (in ms) virtual void SetTimeBounds(const TimeBounds& timebounds); //##Documentation //## @brief Get the position of the corner number \a id (in world coordinates) //## //## See SetImageGeometry for how a corner is defined on images. Point3D GetCornerPoint(int id) const; //##Documentation //## @brief Get the position of a corner (in world coordinates) //## //## See SetImageGeometry for how a corner is defined on images. Point3D GetCornerPoint(bool xFront=true, bool yFront=true, bool zFront=true) const; //##Documentation //## @brief Get vector along bounding-box in the specified @a direction in mm //## //## The length of the vector is the size of the bounding-box in the //## specified @a direction in mm //## \sa GetMatrixColumn Vector3D GetAxisVector(unsigned int direction) const { Vector3D frontToBack; frontToBack.Set_vnl_vector(m_IndexToWorldTransform->GetMatrix().GetVnlMatrix().get_column(direction)); frontToBack *= GetExtent(direction); return frontToBack; } //##Documentation //## @brief Get the center of the bounding-box in mm //## Point3D GetCenter() const { assert(m_BoundingBox.IsNotNull()); return m_IndexToWorldTransform->TransformPoint(m_BoundingBox->GetCenter()); } //##Documentation //## @brief Get the squared length of the diagonal of the bounding-box in mm //## double GetDiagonalLength2() const { Vector3D diagonalvector = GetCornerPoint()-GetCornerPoint(false, false, false); return diagonalvector.GetSquaredNorm(); } //##Documentation //## @brief Get the length of the diagonal of the bounding-box in mm //## double GetDiagonalLength() const { return sqrt(GetDiagonalLength2()); } //##Documentation //## @brief Get a VnlVector along bounding-box in the specified //## @a direction, length is spacing //## //## \sa GetAxisVector VnlVector GetMatrixColumn(unsigned int direction) const { return m_IndexToWorldTransform->GetMatrix().GetVnlMatrix().get_column(direction); } #ifdef DOXYGEN_SKIP //##Documentation //## @brief Get the extent of the bounding box (in index/unit coordinates) //## //## To access the extent in mm use GetExtentInMM ScalarType GetExtent(unsigned int direction) const; #endif //##Documentation //## @brief Get the extent of the bounding-box in the specified @a direction in mm //## //## Equals length of GetAxisVector(direction). ScalarType GetExtentInMM(int direction) const { return m_IndexToWorldTransform->GetMatrix().GetVnlMatrix().get_column(direction).magnitude()*GetExtent(direction); } //##Documentation //## @brief Set the extent of the bounding-box in the specified @a direction in mm //## //## @note This changes the matrix in the transform, @a not the bounds, which are given in units! virtual void SetExtentInMM(int direction, ScalarType extentInMM); //##Documentation //## @brief Get the m_IndexToWorldTransform as a vtkLinearTransform vtkLinearTransform* GetVtkTransform() const { return (vtkLinearTransform*)m_VtkIndexToWorldTransform; } //##Documentation //## @brief Set the origin, i.e. the upper-left corner of the plane //## virtual void SetOrigin(const Point3D& origin); //##Documentation //## @brief Translate the origin by a vector //## virtual void Translate(const Vector3D& vector); //##Documentation //## @brief Set the transform to identity //## virtual void SetIdentity(); //##Documentation //## @brief Compose new IndexToWorldTransform with a given transform. //## //## This method composes m_IndexToWorldTransform with another transform, //## modifying self to be the composition of self and other. //## If the argument pre is true, then other is precomposed with self; //## that is, the resulting transformation consists of first applying //## other to the source, followed by self. If pre is false or omitted, //## then other is post-composed with self; that is the resulting //## transformation consists of first applying self to the source, //## followed by other. virtual void Compose( const AffineGeometryFrame3D::TransformType * other, bool pre = 0 ); //##Documentation //## @brief Compose new IndexToWorldTransform with a given vtkMatrix4x4. //## //## Converts the vtkMatrix4x4 into a itk-transform and calls the previous method. virtual void Compose( const vtkMatrix4x4 * vtkmatrix, bool pre = 0 ); //##Documentation //## @brief Get the origin, e.g. the upper-left corner of the plane const Point3D& GetOrigin() const { return m_Origin; } //##Documentation //## @brief Get the origin as VnlVector //## //## \sa GetOrigin VnlVector GetOriginVnl() const { return const_cast(this)->m_Origin.Get_vnl_vector(); } //##Documentation //## @brief Convert world coordinates (in mm) of a \em point to (continuous!) index coordinates //## \warning If you need (discrete) integer index coordinates (e.g., for iterating easily over an image), //## use WorldToIndex(const mitk::Point3D& pt_mm, itk::Index &index). //## For further information about coordinates types, please see the Geometry documentation void WorldToIndex(const mitk::Point3D& pt_mm, mitk::Point3D& pt_units) const; //##Documentation //## @brief Convert (continuous or discrete) index coordinates of a \em point to world coordinates (in mm) //## For further information about coordinates types, please see the Geometry documentation void IndexToWorld(const mitk::Point3D& pt_units, mitk::Point3D& pt_mm) const; //##Documentation //## @brief Convert world coordinates (in mm) of a \em vector //## \a vec_mm to (continuous!) index coordinates. //## @deprecated First parameter (Point3D) is not used. If possible, please use void WorldToIndex(const mitk::Vector3D& vec_mm, mitk::Vector3D& vec_units) const. //## For further information about coordinates types, please see the Geometry documentation void WorldToIndex(const mitk::Point3D& atPt3d_mm, const mitk::Vector3D& vec_mm, mitk::Vector3D& vec_units) const; //##Documentation //## @brief Convert world coordinates (in mm) of a \em vector //## \a vec_mm to (continuous!) index coordinates. //## For further information about coordinates types, please see the Geometry documentation void WorldToIndex(const mitk::Vector3D& vec_mm, mitk::Vector3D& vec_units) const; //##Documentation //## @brief Convert (continuous or discrete) index coordinates of a \em vector //## \a vec_units to world coordinates (in mm) //## @deprecated First parameter (Point3D) is not used. If possible, please use void IndexToWorld(const mitk::Vector3D& vec_units, mitk::Vector3D& vec_mm) const. //## For further information about coordinates types, please see the Geometry documentation void IndexToWorld(const mitk::Point3D& atPt3d_units, const mitk::Vector3D& vec_units, mitk::Vector3D& vec_mm) const; //##Documentation //## @brief Convert (continuous or discrete) index coordinates of a \em vector //## \a vec_units to world coordinates (in mm) //## For further information about coordinates types, please see the Geometry documentation void IndexToWorld(const mitk::Vector3D& vec_units, mitk::Vector3D& vec_mm) const; //##Documentation //## @brief Convert world coordinates (in mm) of a \em point to (discrete!) index coordinates. //## This method rounds to integer indices! //## For further information about coordinates types, please see the Geometry documentation template void WorldToIndex(const mitk::Point3D& pt_mm, itk::Index &index) const { typedef itk::Index IndexType; mitk::Point3D pt_units; this->WorldToIndex(pt_mm, pt_units); int i, dim=index.GetIndexDimension(); if(dim>3) { index.Fill(0); dim=3; } for(i=0;i( pt_units[i] ); index[i]=itk::Math::RoundHalfIntegerUp( pt_units[i] ); } } //##Documentation //## @brief Deprecated for use with ITK version 3.10 or newer. //## Convert world coordinates (in mm) of a \em point to //## ITK physical coordinates (in mm, but without a possible rotation) //## //## This method is useful if you have want to access an mitk::Image //## via an itk::Image. ITK v3.8 and older did not support rotated (tilted) //## images, i.e., ITK images are always parallel to the coordinate axes. //## When accessing a (possibly rotated) mitk::Image via an itk::Image //## the rotational part of the transformation in the Geometry3D is //## simply discarded; in other word: only the origin and spacing is //## used by ITK, not the complete matrix available in MITK. //## With WorldToItkPhysicalPoint you can convert an MITK world //## coordinate (including the rotation) into a coordinate that //## can be used with the ITK image as a ITK physical coordinate //## (excluding the rotation). template void WorldToItkPhysicalPoint(const mitk::Point3D& pt_mm, itk::Point& itkPhysicalPoint) const { #if ((ITK_VERSION_MAJOR > 3) || (ITK_VERSION_MAJOR == 3 && ITK_VERSION_MINOR > 8)) mitk::vtk2itk(pt_mm, itkPhysicalPoint); #else mitk::Point3D index; WorldToIndex(pt_mm, index); for (unsigned int i = 0 ; i < 3 ; i++) { itkPhysicalPoint[i] = static_cast( this->m_Spacing[i] * index[i] + this->m_Origin[i] ); } #endif } //##Documentation //## @brief Deprecated for use with ITK version 3.10 or newer. //## Convert ITK physical coordinates of a \em point (in mm, //## but without a rotation) into MITK world coordinates (in mm) //## //## For more information, see WorldToItkPhysicalPoint. template void ItkPhysicalPointToWorld(const itk::Point& itkPhysicalPoint, mitk::Point3D& pt_mm) const { #if ((ITK_VERSION_MAJOR > 3) || (ITK_VERSION_MAJOR == 3 && ITK_VERSION_MINOR > 8)) mitk::vtk2itk(itkPhysicalPoint, pt_mm); #else mitk::Point3D index; for (unsigned int i = 0 ; i < 3 ; i++) { index[i] = static_cast( (itkPhysicalPoint[i]- this->m_Origin[i]) / this->m_Spacing[i] ); } IndexToWorld(index, pt_mm); #endif } //##Documentation //## @brief Initialize the Geometry3D virtual void Initialize(); //##Documentation //## @brief Is this an ImageGeometry? //## //## For more information, see SetImageGeometry itkGetConstMacro(ImageGeometry, bool); //##Documentation //## @brief Define that this Geometry3D is refering to an Image //## //## A geometry referring to an Image needs a slightly different //## definition of the position of the corners (see GetCornerPoint). //## The position of a voxel is defined by the position of its center. //## If we would use the origin (position of the (center of) the first //## voxel) as a corner and display this point, it would seem to be //## \em not at the corner but a bit within the image. Even worse for //## the opposite corner of the image: here the corner would appear //## outside the image (by half of the voxel diameter). Thus, we have //## to correct for this and to be able to do that, we need to know //## that the Geometry3D is referring to an Image. itkSetMacro(ImageGeometry, bool); itkBooleanMacro(ImageGeometry); //##Documentation //## @brief Is this Geometry3D in a state that is valid? virtual bool IsValid() const { return m_Valid; } //##Documentation //## @brief Test whether the point \a p (world coordinates in mm) is //## inside the bounding box bool IsInside(const mitk::Point3D& p) const { mitk::Point3D index; WorldToIndex(p, index); return IsIndexInside(index); } //##Documentation //## @brief Test whether the point \a p ((continous!)index coordinates in units) is //## inside the bounding box bool IsIndexInside(const mitk::Point3D& index) const { bool inside = false; //if it is an image geometry, we need to convert the index to discrete values //this is done by applying the rounding function also used in WorldToIndex (see line 323) if (m_ImageGeometry) { mitk::Point3D discretIndex; discretIndex[0]=itk::Math::RoundHalfIntegerUp( index[0] ); discretIndex[1]=itk::Math::RoundHalfIntegerUp( index[1] ); discretIndex[2]=itk::Math::RoundHalfIntegerUp( index[2] ); inside = m_BoundingBox->IsInside(discretIndex); //we have to check if the index is at the upper border of each dimension, // because the boundingbox is not centerbased if (inside) { const BoundingBox::BoundsArrayType& bounds = m_BoundingBox->GetBounds(); if((discretIndex[0] == bounds[1]) || (discretIndex[1] == bounds[3]) || (discretIndex[2] == bounds[5])) inside = false; } } else inside = m_BoundingBox->IsInside(index); return inside; } //##Documentation //## @brief Convenience method for working with ITK indices template bool IsIndexInside(const itk::Index &index) const { int i, dim=index.GetIndexDimension(); Point3D pt_index; pt_index.Fill(0); for ( i = 0; i < dim; ++i ) { pt_index[i] = index[i]; } return IsIndexInside(pt_index); } //##Documentation //## @brief Get the spacing (size of a pixel). //## itkGetConstReferenceMacro(Spacing, mitk::Vector3D); //##Documentation //## @brief Get the spacing as a float[3] array. const float* GetFloatSpacing() const; //##Documentation //## @brief Set the spacing (m_Spacing) virtual void SetSpacing(const mitk::Vector3D& aSpacing); - //##Documentation - //## @brief Set the spacing (m_Spacing) via a float array - virtual void SetSpacing(const float aSpacing[3]); //##Documentation //## @brief Get the DICOM FrameOfReferenceID referring to the //## used world coordinate system itkGetConstMacro(FrameOfReferenceID, unsigned int); //##Documentation //## @brief Set the DICOM FrameOfReferenceID referring to the //## used world coordinate system itkSetMacro(FrameOfReferenceID, unsigned int); //##Documentation //## @brief Copy the ITK transform //## (m_IndexToWorldTransform) to the VTK transform //## \sa SetIndexToWorldTransform void TransferItkToVtkTransform(); //##Documentation //## @brief Copy the VTK transform //## to the ITK transform (m_IndexToWorldTransform) //## \sa SetIndexToWorldTransform void TransferVtkToItkTransform(); //##Documentation //## @brief Get the parametric bounding-box //## //## See AbstractTransformGeometry for an example usage of this. itkGetConstObjectMacro(ParametricBoundingBox, BoundingBox); //##Documentation //## @brief Get the parametric bounds //## //## See AbstractTransformGeometry for an example usage of this. const BoundingBox::BoundsArrayType& GetParametricBounds() const { assert(m_ParametricBoundingBox.IsNotNull()); return m_ParametricBoundingBox->GetBounds(); } //##Documentation //## @brief Get the parametric extent //## //## See AbstractTransformGeometry for an example usage of this. mitk::ScalarType GetParametricExtent(int direction) const { assert(direction>=0 && direction<3); assert(m_ParametricBoundingBox.IsNotNull()); BoundingBoxType::BoundsArrayType bounds = m_ParametricBoundingBox->GetBounds(); return bounds[direction*2+1]-bounds[direction*2]; } //##Documentation //## @brief Get the parametric extent in mm //## //## See AbstractTransformGeometry for an example usage of this. virtual mitk::ScalarType GetParametricExtentInMM(int direction) const { return GetExtentInMM(direction); } //##Documentation //## @brief Get the parametric transform //## //## See AbstractTransformGeometry for an example usage of this. virtual const Transform3D* GetParametricTransform() const { return m_IndexToWorldTransform; } //##Documentation //## @brief Calculates a bounding-box around the geometry relative //## to a coordinate system defined by a transform //## mitk::BoundingBox::Pointer CalculateBoundingBoxRelativeToTransform(const mitk::AffineTransform3D* transform) const; //##Documentation //## @brief clones the geometry //## //## Overwrite in all sub-classes. //## Normally looks like: //## \code - //## Self::Pointer newGeometry = Self::New(); - //## newGeometry->Initialize(); - //## InitializeGeometry(newGeometry); + //## Self::Pointer newGeometry = new Self(*this); + //## newGeometry->UnRegister(); //## return newGeometry.GetPointer(); //## \endcode - //## \sa InitializeGeometry virtual AffineGeometryFrame3D::Pointer Clone() const; //##Documentation //##@brief executes affine operations (translate, rotate, scale) virtual void ExecuteOperation(Operation* operation); protected: Geometry3D(); + Geometry3D(const Geometry3D& other); + static const char* GetTransformAsString( TransformType* transformType ); virtual ~Geometry3D(); - //##Documentation - //## @brief used in clone to initialize the newly created geometry - //## - //## Has to be overwritten in sub-classes, if they add members. - //## Do the following: - //## \li call Superclass::InitializeGeometry(newGeometry) - //## \li transfer all additional members of Self compared to Superclass - virtual void InitializeGeometry(Self * newGeometry) const; - virtual void PrintSelf(std::ostream& os, itk::Indent indent) const; virtual void BackTransform(const mitk::Point3D& in, mitk::Point3D& out) const; //##Documentation //## @brief Deprecated virtual void BackTransform(const mitk::Point3D& at, const mitk::Vector3D& in, mitk::Vector3D& out) const; //Without redundant parameter Point3D virtual void BackTransform(const mitk::Vector3D& in, mitk::Vector3D& out) const; //##Documentation //## @brief Set the parametric bounds //## //## Protected in this class, made public in some sub-classes, e.g., //## ExternAbstractTransformGeometry. virtual void SetParametricBounds(const BoundingBox::BoundsArrayType& bounds); /** Resets sub-transforms that compose m_IndexToWorldTransform, by using * the current value of m_IndexToWorldTransform and setting the rotation * component to zero. */ virtual void ResetSubTransforms(); mutable mitk::BoundingBox::Pointer m_ParametricBoundingBox; mutable mitk::TimeBounds m_TimeBounds; vtkMatrix4x4* m_VtkMatrix; bool m_ImageGeometry; //##Documentation //## @brief Spacing of the data. Only significant if the geometry describes //## an Image (m_ImageGeometry==true). mitk::Vector3D m_Spacing; bool m_Valid; unsigned int m_FrameOfReferenceID; static const std::string INDEX_TO_OBJECT_TRANSFORM; static const std::string OBJECT_TO_NODE_TRANSFORM; static const std::string INDEX_TO_NODE_TRANSFORM; static const std::string INDEX_TO_WORLD_TRANSFORM; private: mutable TransformType::Pointer m_InvertedTransform; mutable unsigned long m_IndexToWorldTransformLastModified; - QuaternionTransformType::Pointer m_IndexToWorldRotationTransform; VnlQuaternionType m_RotationQuaternion; float m_FloatSpacing[3]; vtkMatrixToLinearTransform* m_VtkIndexToWorldTransform; //##Documentation //## @brief Origin, i.e. upper-left corner of the plane //## Point3D m_Origin; }; } // namespace mitk #endif /* GEOMETRY3D_H_HEADER_INCLUDED_C1EBD0AD */ diff --git a/Core/Code/DataManagement/mitkImage.cpp b/Core/Code/DataManagement/mitkImage.cpp index b1f2121bce..54344b60ed 100644 --- a/Core/Code/DataManagement/mitkImage.cpp +++ b/Core/Code/DataManagement/mitkImage.cpp @@ -1,1435 +1,1439 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "mitkImage.h" #include "mitkHistogramGenerator.h" #include "mitkPicHelper.h" #include "mitkImageTimeSelector.h" #include "ipFunc/mitkIpFunc.h" #include "mitkIpPicTypeMultiplex.h" #include #include template class MITK_CORE_EXPORT itk::SmartPointerForwardReference; mitk::Image::Image() : m_Dimension(0), m_Dimensions(NULL), m_OffsetTable(NULL), m_CompleteData(NULL), m_PixelType(NULL), m_TimeSelectorForExtremaObject(NULL) { m_CountOfMinValuedVoxels.resize(1, 0); m_CountOfMaxValuedVoxels.resize(1, 0); m_ScalarMin.resize(1, itk::NumericTraits::max()); m_ScalarMax.resize(1, itk::NumericTraits::NonpositiveMin()); m_Scalar2ndMin.resize(1, itk::NumericTraits::max()); m_Scalar2ndMax.resize(1, itk::NumericTraits::NonpositiveMin()); m_Initialized = false; mitk::HistogramGenerator::Pointer generator = mitk::HistogramGenerator::New(); m_HistogramGeneratorObject = generator; } mitk::Image::~Image() { Clear(); m_ReferenceCountLock.Lock(); m_ReferenceCount = 3; m_ReferenceCountLock.Unlock(); m_HistogramGeneratorObject = NULL; m_TimeSelectorForExtremaObject = NULL; m_ReferenceCountLock.Lock(); m_ReferenceCount = 0; m_ReferenceCountLock.Unlock(); delete [] m_OffsetTable; } const mitk::PixelType& mitk::Image::GetPixelType(int /*n*/) const { return m_PixelType; } unsigned int mitk::Image::GetDimension() const { return m_Dimension; } unsigned int mitk::Image::GetDimension(int i) const { if((i>=0) && (i<(int)m_Dimension)) return m_Dimensions[i]; return 1; } void* mitk::Image::GetData() { if(m_Initialized==false) { if(GetSource()==NULL) return NULL; if(GetSource()->Updating()==false) GetSource()->UpdateOutputInformation(); } m_CompleteData=GetChannelData(); return m_CompleteData->GetData(); } template void AccessPixel(mitkIpPicDescriptor* pic, const mitk::Index3D& p, double& value, int timestep) { if ( (p[0]>=0 && p[1] >=0 && p[2]>=0 && timestep>=0) && (unsigned int)p[0] < pic->n[0] && (unsigned int)p[1] < pic->n[1] && (unsigned int)p[2] < pic->n[2] && (unsigned int)timestep < pic->n[3] ) { if(pic->bpe!=24) { value = (double) (((T*) pic->data)[ p[0] + p[1]*pic->n[0] + p[2]*pic->n[0]*pic->n[1] + timestep*pic->n[0]*pic->n[1]*pic->n[2] ]); } else { double returnvalue = (((T*) pic->data)[p[0]*3 + 0 + p[1]*pic->n[0]*3 + p[2]*pic->n[0]*pic->n[1]*3 + timestep*pic->n[0]*pic->n[1]*pic->n[2]*3 ]); returnvalue += (((T*) pic->data)[p[0]*3 + 1 + p[1]*pic->n[0]*3 + p[2]*pic->n[0]*pic->n[1]*3 + timestep*pic->n[0]*pic->n[1]*pic->n[2]*3]); returnvalue += (((T*) pic->data)[p[0]*3 + 2 + p[1]*pic->n[0]*3 + p[2]*pic->n[0]*pic->n[1]*3 + timestep*pic->n[0]*pic->n[1]*pic->n[2]*3]); value = returnvalue; } } else { value = 0; } }; double mitk::Image::GetPixelValueByIndex(const mitk::Index3D &position, unsigned int timestep) { mitkIpPicDescriptor* pic = this->GetPic(); double value = 0; if (this->GetTimeSteps() < timestep) { timestep = this->GetTimeSteps(); } mitkIpPicTypeMultiplex3(AccessPixel, pic, position, value, timestep); return value; } double mitk::Image::GetPixelValueByWorldCoordinate(const mitk::Point3D& position, unsigned int timestep) { mitkIpPicDescriptor* pic = this->GetPic(); double value = 0; if (this->GetTimeSteps() < timestep) { timestep = this->GetTimeSteps(); } Index3D itkIndex; this->GetGeometry()->WorldToIndex(position,itkIndex); mitkIpPicTypeMultiplex3(AccessPixel, pic, itkIndex, value, timestep); return value; } vtkImageData* mitk::Image::GetVtkImageData(int t, int n) { if(m_Initialized==false) { if(GetSource()==NULL) return NULL; if(GetSource()->Updating()==false) GetSource()->UpdateOutputInformation(); } ImageDataItemPointer volume=GetVolumeData(t, n); if(volume.GetPointer()==NULL || volume->GetVtkImageData() == NULL) return NULL; #if ((VTK_MAJOR_VERSION > 4) || ((VTK_MAJOR_VERSION==4) && (VTK_MINOR_VERSION>=4) )) float *fspacing = const_cast(GetSlicedGeometry(t)->GetFloatSpacing()); double dspacing[3] = {fspacing[0],fspacing[1],fspacing[2]}; volume->GetVtkImageData()->SetSpacing( dspacing ); #else volume->GetVtkImageData()->SetSpacing(const_cast(GetSlicedGeometry(t)->GetFloatSpacing())); #endif return volume->GetVtkImageData(); } mitkIpPicDescriptor* mitk::Image::GetPic() { if(m_Initialized==false) { if(GetSource()==NULL) return NULL; if(GetSource()->Updating()==false) GetSource()->UpdateOutputInformation(); } m_CompleteData=GetChannelData(); if(m_CompleteData.GetPointer()==NULL) return NULL; return m_CompleteData->GetPicDescriptor(); } mitk::Image::ImageDataItemPointer mitk::Image::GetSliceData(int s, int t, int n, void *data, ImportMemoryManagementType importMemoryManagement) { if(IsValidSlice(s,t,n)==false) return NULL; // slice directly available? int pos=GetSliceIndex(s,t,n); if(m_Slices[pos].GetPointer()!=NULL) return m_Slices[pos]; // is slice available as part of a volume that is available? ImageDataItemPointer sl, ch, vol; vol=m_Volumes[GetVolumeIndex(t,n)]; if((vol.GetPointer()!=NULL) && (vol->IsComplete())) { sl=new ImageDataItem(*vol, 2, data, importMemoryManagement == ManageMemory, ((size_t) s)*m_OffsetTable[2]*(m_PixelType.GetBpe()/8)); sl->SetComplete(true); return m_Slices[pos]=sl; } // is slice available as part of a channel that is available? ch=m_Channels[n]; if((ch.GetPointer()!=NULL) && (ch->IsComplete())) { sl=new ImageDataItem(*ch, 2, data, importMemoryManagement == ManageMemory, (((size_t) s)*m_OffsetTable[2]+((size_t) t)*m_OffsetTable[3])*(m_PixelType.GetBpe()/8)); sl->SetComplete(true); return m_Slices[pos]=sl; } // slice is unavailable. Can we calculate it? if((GetSource()!=NULL) && (GetSource()->Updating()==false)) { // ... wir mussen rechnen!!! .... m_RequestedRegion.SetIndex(0, 0); m_RequestedRegion.SetIndex(1, 0); m_RequestedRegion.SetIndex(2, s); m_RequestedRegion.SetIndex(3, t); m_RequestedRegion.SetIndex(4, n); m_RequestedRegion.SetSize(0, m_Dimensions[0]); m_RequestedRegion.SetSize(1, m_Dimensions[1]); m_RequestedRegion.SetSize(2, 1); m_RequestedRegion.SetSize(3, 1); m_RequestedRegion.SetSize(4, 1); m_RequestedRegionInitialized=true; GetSource()->Update(); if(IsSliceSet(s,t,n)) //yes: now we can call ourselves without the risk of a endless loop (see "if" above) return GetSliceData(s,t,n,data,importMemoryManagement); else return NULL; } else { ImageDataItemPointer item = AllocateSliceData(s,t,n,data,importMemoryManagement); item->SetComplete(true); return item; } } mitk::Image::ImageDataItemPointer mitk::Image::GetVolumeData(int t, int n, void *data, ImportMemoryManagementType importMemoryManagement) { if(IsValidVolume(t,n)==false) return NULL; ImageDataItemPointer ch, vol; // volume directly available? int pos=GetVolumeIndex(t,n); vol=m_Volumes[pos]; if((vol.GetPointer()!=NULL) && (vol->IsComplete())) return vol; // is volume available as part of a channel that is available? ch=m_Channels[n]; if((ch.GetPointer()!=NULL) && (ch->IsComplete())) { vol=new ImageDataItem(*ch, 3, data, importMemoryManagement == ManageMemory, (((size_t) t)*m_OffsetTable[3])*(m_PixelType.GetBpe()/8)); vol->SetComplete(true); return m_Volumes[pos]=vol; } // let's see if all slices of the volume are set, so that we can (could) combine them to a volume bool complete=true; unsigned int s; for(s=0;sSetComplete(true); } else { vol=m_Volumes[pos]; // ok, let's combine the slices! if(vol.GetPointer()==NULL) vol=new ImageDataItem(m_PixelType, 3, m_Dimensions, NULL, true); vol->SetComplete(true); size_t size=m_OffsetTable[2]*(m_PixelType.GetBpe()/8); for(s=0;sGetParent()!=vol) { // copy data of slices in volume size_t offset = ((size_t) s)*size; std::memcpy(static_cast(vol->GetData())+offset, sl->GetData(), size); mitkIpPicDescriptor * pic = sl->GetPicDescriptor(); // replace old slice with reference to volume sl=new ImageDataItem(*vol, 2, data, importMemoryManagement == ManageMemory, ((size_t) s)*size); sl->SetComplete(true); mitkIpFuncCopyTags(sl->GetPicDescriptor(), pic); m_Slices[posSl]=sl; } } if(vol->GetPicDescriptor()->info->tags_head==NULL) mitkIpFuncCopyTags(vol->GetPicDescriptor(), m_Slices[GetSliceIndex(0,t,n)]->GetPicDescriptor()); } return m_Volumes[pos]=vol; } // volume is unavailable. Can we calculate it? if((GetSource()!=NULL) && (GetSource()->Updating()==false)) { // ... wir muessen rechnen!!! .... m_RequestedRegion.SetIndex(0, 0); m_RequestedRegion.SetIndex(1, 0); m_RequestedRegion.SetIndex(2, 0); m_RequestedRegion.SetIndex(3, t); m_RequestedRegion.SetIndex(4, n); m_RequestedRegion.SetSize(0, m_Dimensions[0]); m_RequestedRegion.SetSize(1, m_Dimensions[1]); m_RequestedRegion.SetSize(2, m_Dimensions[2]); m_RequestedRegion.SetSize(3, 1); m_RequestedRegion.SetSize(4, 1); m_RequestedRegionInitialized=true; GetSource()->Update(); if(IsVolumeSet(t,n)) //yes: now we can call ourselves without the risk of a endless loop (see "if" above) return GetVolumeData(t,n,data,importMemoryManagement); else return NULL; } else { ImageDataItemPointer item = AllocateVolumeData(t,n,data,importMemoryManagement); item->SetComplete(true); return item; } } mitk::Image::ImageDataItemPointer mitk::Image::GetChannelData(int n, void *data, ImportMemoryManagementType importMemoryManagement) { if(IsValidChannel(n)==false) return NULL; ImageDataItemPointer ch, vol; ch=m_Channels[n]; if((ch.GetPointer()!=NULL) && (ch->IsComplete())) return ch; // let's see if all volumes are set, so that we can (could) combine them to a channel if(IsChannelSet(n)) { // if there is only one time frame we do not need to combine anything if(m_Dimensions[3]<=1) { vol=GetVolumeData(0,n,data,importMemoryManagement); ch=new ImageDataItem(*vol, 3, data, importMemoryManagement == ManageMemory); ch->SetComplete(true); } else { ch=m_Channels[n]; // ok, let's combine the volumes! if(ch.GetPointer()==NULL) ch=new ImageDataItem(m_PixelType, m_Dimension, m_Dimensions, NULL, true); ch->SetComplete(true); size_t size=m_OffsetTable[m_Dimension-1]*(m_PixelType.GetBpe()/8); unsigned int t; ImageDataItemPointerArray::iterator slicesIt = m_Slices.begin()+n*m_Dimensions[2]*m_Dimensions[3]; for(t=0;tGetParent()!=ch) { // copy data of volume in channel size_t offset = ((size_t) t)*m_OffsetTable[3]*(m_PixelType.GetBpe()/8); std::memcpy(static_cast(ch->GetData())+offset, vol->GetData(), size); mitkIpPicDescriptor * pic = vol->GetPicDescriptor(); // replace old volume with reference to channel vol=new ImageDataItem(*ch, 3, data, importMemoryManagement == ManageMemory, offset); vol->SetComplete(true); mitkIpFuncCopyTags(vol->GetPicDescriptor(), pic); m_Volumes[posVol]=vol; // get rid of slices - they may point to old volume ImageDataItemPointer dnull=NULL; for(unsigned int i = 0; i < m_Dimensions[2]; ++i, ++slicesIt) { assert(slicesIt != m_Slices.end()); *slicesIt = dnull; } } } if(ch->GetPicDescriptor()->info->tags_head==NULL) mitkIpFuncCopyTags(ch->GetPicDescriptor(), m_Volumes[GetVolumeIndex(0,n)]->GetPicDescriptor()); } return m_Channels[n]=ch; } // channel is unavailable. Can we calculate it? if((GetSource()!=NULL) && (GetSource()->Updating()==false)) { // ... wir muessen rechnen!!! .... m_RequestedRegion.SetIndex(0, 0); m_RequestedRegion.SetIndex(1, 0); m_RequestedRegion.SetIndex(2, 0); m_RequestedRegion.SetIndex(3, 0); m_RequestedRegion.SetIndex(4, n); m_RequestedRegion.SetSize(0, m_Dimensions[0]); m_RequestedRegion.SetSize(1, m_Dimensions[1]); m_RequestedRegion.SetSize(2, m_Dimensions[2]); m_RequestedRegion.SetSize(3, m_Dimensions[3]); m_RequestedRegion.SetSize(4, 1); m_RequestedRegionInitialized=true; GetSource()->Update(); // did it work? if(IsChannelSet(n)) //yes: now we can call ourselves without the risk of a endless loop (see "if" above) return GetChannelData(n,data,importMemoryManagement); else return NULL; } else { ImageDataItemPointer item = AllocateChannelData(n,data,importMemoryManagement); item->SetComplete(true); return item; } } bool mitk::Image::IsSliceSet(int s, int t, int n) const { if(IsValidSlice(s,t,n)==false) return false; if(m_Slices[GetSliceIndex(s,t,n)].GetPointer()!=NULL) return true; ImageDataItemPointer ch, vol; vol=m_Volumes[GetVolumeIndex(t,n)]; if((vol.GetPointer()!=NULL) && (vol->IsComplete())) return true; ch=m_Channels[n]; if((ch.GetPointer()!=NULL) && (ch->IsComplete())) return true; return false; } bool mitk::Image::IsVolumeSet(int t, int n) const { if(IsValidVolume(t,n)==false) return false; ImageDataItemPointer ch, vol; // volume directly available? vol=m_Volumes[GetVolumeIndex(t,n)]; if((vol.GetPointer()!=NULL) && (vol->IsComplete())) return true; // is volume available as part of a channel that is available? ch=m_Channels[n]; if((ch.GetPointer()!=NULL) && (ch->IsComplete())) return true; // let's see if all slices of the volume are set, so that we can (could) combine them to a volume unsigned int s; for(s=0;sIsComplete())) return true; // let's see if all volumes are set, so that we can (could) combine them to a channel unsigned int t; for(t=0;t(data), s, t, n, CopyMemory); } bool mitk::Image::SetVolume(const void *data, int t, int n) { // const_cast is no risk for ImportMemoryManagementType == CopyMemory return SetImportVolume(const_cast(data), t, n, CopyMemory); } bool mitk::Image::SetChannel(const void *data, int n) { // const_cast is no risk for ImportMemoryManagementType == CopyMemory return SetImportChannel(const_cast(data), n, CopyMemory); } bool mitk::Image::SetImportSlice(void *data, int s, int t, int n, ImportMemoryManagementType importMemoryManagement) { if(IsValidSlice(s,t,n)==false) return false; ImageDataItemPointer sl; if(IsSliceSet(s,t,n)) { sl=GetSliceData(s,t,n,data,importMemoryManagement); if(sl->GetManageMemory()==false) { sl=AllocateSliceData(s,t,n,data,importMemoryManagement); if(sl.GetPointer()==NULL) return false; } if ( sl->GetData() != data ) std::memcpy(sl->GetData(), data, m_OffsetTable[2]*(m_PixelType.GetBpe()/8)); sl->Modified(); //we have changed the data: call Modified()! Modified(); } else { sl=AllocateSliceData(s,t,n,data,importMemoryManagement); if(sl.GetPointer()==NULL) return false; if ( sl->GetData() != data ) std::memcpy(sl->GetData(), data, m_OffsetTable[2]*(m_PixelType.GetBpe()/8)); //we just added a missing slice, which is not regarded as modification. //Therefore, we do not call Modified()! } return true; } bool mitk::Image::SetImportVolume(void *data, int t, int n, ImportMemoryManagementType importMemoryManagement) { if(IsValidVolume(t,n)==false) return false; ImageDataItemPointer vol; if(IsVolumeSet(t,n)) { vol=GetVolumeData(t,n,data,importMemoryManagement); if(vol->GetManageMemory()==false) { vol=AllocateVolumeData(t,n,data,importMemoryManagement); if(vol.GetPointer()==NULL) return false; } if ( vol->GetData() != data ) std::memcpy(vol->GetData(), data, m_OffsetTable[3]*(m_PixelType.GetBpe()/8)); vol->Modified(); vol->SetComplete(true); //we have changed the data: call Modified()! Modified(); } else { vol=AllocateVolumeData(t,n,data,importMemoryManagement); if(vol.GetPointer()==NULL) return false; if ( vol->GetData() != data ) { std::memcpy(vol->GetData(), data, m_OffsetTable[3]*(m_PixelType.GetBpe()/8)); } vol->SetComplete(true); //we just added a missing Volume, which is not regarded as modification. //Therefore, we do not call Modified()! } return true; } bool mitk::Image::SetImportChannel(void *data, int n, ImportMemoryManagementType importMemoryManagement) { if(IsValidChannel(n)==false) return false; ImageDataItemPointer ch; if(IsChannelSet(n)) { ch=GetChannelData(n,data,importMemoryManagement); if(ch->GetManageMemory()==false) { ch=AllocateChannelData(n,data,importMemoryManagement); if(ch.GetPointer()==NULL) return false; } if ( ch->GetData() != data ) std::memcpy(ch->GetData(), data, m_OffsetTable[4]*(m_PixelType.GetBpe()/8)); ch->Modified(); ch->SetComplete(true); //we have changed the data: call Modified()! Modified(); } else { ch=AllocateChannelData(n,data,importMemoryManagement); if(ch.GetPointer()==NULL) return false; if ( ch->GetData() != data ) std::memcpy(ch->GetData(), data, m_OffsetTable[4]*(m_PixelType.GetBpe()/8)); ch->SetComplete(true); //we just added a missing Channel, which is not regarded as modification. //Therefore, we do not call Modified()! } return true; } bool mitk::Image::SetPicSlice(const mitkIpPicDescriptor *pic, int s, int t, int n, ImportMemoryManagementType /*importMemoryManagement*/) { if(pic==NULL) return false; if(pic->dim!=2) return false; if((pic->n[0]!=m_Dimensions[0]) || (pic->n[1]!=m_Dimensions[1])) return false; if(SetSlice(pic->data,s,t,n)) //@todo: add geometry! { ImageDataItemPointer sl; sl=GetSliceData(s,t,n,NULL,CopyMemory); mitkIpFuncCopyTags(sl->GetPicDescriptor(), const_cast(pic)); return true; } else return false; } bool mitk::Image::SetPicVolume(const mitkIpPicDescriptor *pic, int t, int n, ImportMemoryManagementType /*importMemoryManagement*/) { if(pic==NULL) return false; if((pic->dim==2) && ((m_Dimension==2) || ((m_Dimension>2) && (m_Dimensions[2]==1)))) return SetPicSlice(pic, 0, t, n); if(pic->dim!=3) return false; if((pic->n[0]!=m_Dimensions[0]) || (pic->n[1]!=m_Dimensions[1]) || (pic->n[2]!=m_Dimensions[2])) return false; if(SetVolume(pic->data,t,n)) //@todo: add geometry! { ImageDataItemPointer vol; vol=GetVolumeData(t,n,NULL,CopyMemory); mitkIpFuncCopyTags(vol->GetPicDescriptor(), const_cast(pic)); return true; } else return false; } bool mitk::Image::SetPicChannel(const mitkIpPicDescriptor *pic, int n, ImportMemoryManagementType /*importMemoryManagement*/) { if(pic==NULL) return false; if(pic->dim<=3) return SetPicVolume(pic, 0, n); if(pic->dim!=m_Dimension) return false; unsigned int i; for(i=0;in[i]!=m_Dimensions[i]) return false; } if(SetChannel(pic->data,n)) //@todo: add geometry! { ImageDataItemPointer ch; ch=GetChannelData(n,NULL,CopyMemory); // commented the next line, because // it crashes when called from mitkDICOMFileReader for the Live3D data // mitkIpFuncCopyTags(ch->GetPicDescriptor(), pic); return true; } else return false; } void mitk::Image::Initialize() { ImageDataItemPointerArray::iterator it, end; for( it=m_Slices.begin(), end=m_Slices.end(); it!=end; ++it ) { (*it)=NULL; } for( it=m_Volumes.begin(), end=m_Volumes.end(); it!=end; ++it ) { (*it)=NULL; } for( it=m_Channels.begin(), end=m_Channels.end(); it!=end; ++it ) { (*it)=NULL; } m_CompleteData = NULL; this->GetTimeSelector(); // just to create m_TimeSelectorForExtremaObject SetRequestedRegionToLargestPossibleRegion(); } mitk::ImageTimeSelector* mitk::Image::GetTimeSelector() const { if(m_TimeSelectorForExtremaObject.IsNull()) { m_TimeSelectorForExtremaObject = ImageTimeSelector::New(); ImageTimeSelector* timeSelector = static_cast( m_TimeSelectorForExtremaObject.GetPointer() ); timeSelector->SetInput(this); this->UnRegister(); } return static_cast( m_TimeSelectorForExtremaObject.GetPointer() ); } void mitk::Image::Initialize(const mitk::PixelType& type, unsigned int dimension, unsigned int *dimensions, unsigned int channels) { Clear(); m_Dimension=dimension; if(!dimensions) itkExceptionMacro(<< "invalid zero dimension image"); unsigned int i; for(i=0;i4?m_Dimension:4]; std::memcpy(m_Dimensions, dimensions, sizeof(unsigned int)*m_Dimension); if(m_Dimension<4) { unsigned int *p; for(i=0,p=m_Dimensions+m_Dimension;i<4-m_Dimension;++i, ++p) *p=1; } for(i=0;i<4;++i) { m_LargestPossibleRegion.SetIndex(i, 0); m_LargestPossibleRegion.SetSize (i, m_Dimensions[i]); } m_LargestPossibleRegion.SetIndex(i, 0); m_LargestPossibleRegion.SetSize(i, channels); if(m_LargestPossibleRegion.GetNumberOfPixels()==0) { delete [] m_Dimensions; m_Dimensions = NULL; return; } m_PixelType=type; PlaneGeometry::Pointer planegeometry = PlaneGeometry::New(); planegeometry->InitializeStandardPlane(m_Dimensions[0], m_Dimensions[1]); SlicedGeometry3D::Pointer slicedGeometry = SlicedGeometry3D::New(); slicedGeometry->InitializeEvenlySpaced(planegeometry, m_Dimensions[2]); if(dimension>=4) { TimeBounds timebounds; timebounds[0] = 0.0; timebounds[1] = 1.0; slicedGeometry->SetTimeBounds(timebounds); } TimeSlicedGeometry::Pointer timeSliceGeometry = TimeSlicedGeometry::New(); timeSliceGeometry->InitializeEvenlyTimed(slicedGeometry, m_Dimensions[3]); timeSliceGeometry->ImageGeometryOn(); SetGeometry(timeSliceGeometry); ImageDataItemPointer dnull=NULL; m_Channels.assign(GetNumberOfChannels(), dnull); m_Volumes.assign(GetNumberOfChannels()*m_Dimensions[3], dnull); m_Slices.assign(GetNumberOfChannels()*m_Dimensions[3]*m_Dimensions[2], dnull); ComputeOffsetTable(); Initialize(); m_Initialized = true; } void mitk::Image::Initialize(const mitk::PixelType& type, const mitk::Geometry3D& geometry, unsigned int channels, int tDim ) { unsigned int dimensions[5]; dimensions[0] = (unsigned int)(geometry.GetExtent(0)+0.5); dimensions[1] = (unsigned int)(geometry.GetExtent(1)+0.5); dimensions[2] = (unsigned int)(geometry.GetExtent(2)+0.5); dimensions[3] = 0; dimensions[4] = 0; unsigned int dimension = 2; if ( dimensions[2] > 1 ) dimension = 3; if ( tDim > 0) { dimensions[3] = tDim; } else { const mitk::TimeSlicedGeometry* timeGeometry = dynamic_cast(&geometry); if ( timeGeometry != NULL ) { dimensions[3] = timeGeometry->GetTimeSteps(); } } if ( dimensions[3] > 1 ) dimension = 4; Initialize( type, dimension, dimensions, channels ); SetGeometry(static_cast(geometry.Clone().GetPointer())); mitk::BoundingBox::BoundsArrayType bounds = geometry.GetBoundingBox()->GetBounds(); if( (bounds[0] != 0.0) || (bounds[2] != 0.0) || (bounds[4] != 0.0) ) { SlicedGeometry3D* slicedGeometry = GetSlicedGeometry(0); mitk::Point3D origin; origin.Fill(0.0); slicedGeometry->IndexToWorld(origin, origin); bounds[1]-=bounds[0]; bounds[3]-=bounds[2]; bounds[5]-=bounds[4]; bounds[0] = 0.0; bounds[2] = 0.0; bounds[4] = 0.0; slicedGeometry->SetBounds(bounds); slicedGeometry->GetIndexToWorldTransform()->SetOffset(origin.Get_vnl_vector().data_block()); GetTimeSlicedGeometry()->InitializeEvenlyTimed(slicedGeometry, m_Dimensions[3]); } } void mitk::Image::Initialize(const mitk::PixelType& type, int sDim, const mitk::Geometry2D& geometry2d, bool flipped, unsigned int channels, int tDim ) { SlicedGeometry3D::Pointer slicedGeometry = SlicedGeometry3D::New(); slicedGeometry->InitializeEvenlySpaced(static_cast(geometry2d.Clone().GetPointer()), sDim, flipped); Initialize(type, *slicedGeometry, channels, tDim); } void mitk::Image::Initialize(const mitk::Image* image) { Initialize(*image->GetPixelType().GetTypeId(), *image->GetTimeSlicedGeometry()); } void mitk::Image::Initialize(vtkImageData* vtkimagedata, int channels, int tDim, int sDim) { if(vtkimagedata==NULL) return; m_Dimension=vtkimagedata->GetDataDimension(); unsigned int i, *tmpDimensions=new unsigned int[m_Dimension>4?m_Dimension:4]; for(i=0;iGetDimensions()[i]; if(m_Dimension<4) { unsigned int *p; for(i=0,p=tmpDimensions+m_Dimension;i<4-m_Dimension;++i, ++p) *p=1; } if(sDim>=0) { tmpDimensions[2]=sDim; if(m_Dimension < 3) m_Dimension = 3; } if(tDim>=0) { tmpDimensions[3]=tDim; if(m_Dimension < 4) m_Dimension = 4; } mitk::PixelType pixelType; switch ( vtkimagedata->GetScalarType() ) { case VTK_BIT: case VTK_CHAR: pixelType.Initialize(typeid(char), vtkimagedata->GetNumberOfScalarComponents()); break; case VTK_UNSIGNED_CHAR: pixelType.Initialize(typeid(unsigned char), vtkimagedata->GetNumberOfScalarComponents()); break; case VTK_SHORT: pixelType.Initialize(typeid(short), vtkimagedata->GetNumberOfScalarComponents()); break; case VTK_UNSIGNED_SHORT: pixelType.Initialize(typeid(unsigned short), vtkimagedata->GetNumberOfScalarComponents()); break; case VTK_INT: pixelType.Initialize(typeid(int), vtkimagedata->GetNumberOfScalarComponents()); break; case VTK_UNSIGNED_INT: pixelType.Initialize(typeid(unsigned int), vtkimagedata->GetNumberOfScalarComponents()); break; case VTK_LONG: pixelType.Initialize(typeid(long), vtkimagedata->GetNumberOfScalarComponents()); break; case VTK_UNSIGNED_LONG: pixelType.Initialize(typeid(unsigned long), vtkimagedata->GetNumberOfScalarComponents()); break; case VTK_FLOAT: pixelType.Initialize(typeid(float), vtkimagedata->GetNumberOfScalarComponents()); break; case VTK_DOUBLE: pixelType.Initialize(typeid(double), vtkimagedata->GetNumberOfScalarComponents()); break; default: break; } Initialize(pixelType, m_Dimension, tmpDimensions, channels); #if ((VTK_MAJOR_VERSION > 4) || ((VTK_MAJOR_VERSION==4) && (VTK_MINOR_VERSION>=4) )) const double *spacinglist = vtkimagedata->GetSpacing(); #else const float *spacinglist = vtkimagedata->GetSpacing(); #endif Vector3D spacing; FillVector3D(spacing, spacinglist[0], 1.0, 1.0); if(m_Dimension>=2) spacing[1]=spacinglist[1]; if(m_Dimension>=3) spacing[2]=spacinglist[2]; // access origin of vtkImage Point3D origin; vtkFloatingPointType vtkorigin[3]; vtkimagedata->GetOrigin(vtkorigin); FillVector3D(origin, vtkorigin[0], 0.0, 0.0); if(m_Dimension>=2) origin[1]=vtkorigin[1]; if(m_Dimension>=3) origin[2]=vtkorigin[2]; SlicedGeometry3D* slicedGeometry = GetSlicedGeometry(0); // re-initialize PlaneGeometry with origin and direction PlaneGeometry* planeGeometry = static_cast(slicedGeometry->GetGeometry2D(0)); planeGeometry->SetOrigin(origin); // re-initialize SlicedGeometry3D slicedGeometry->SetOrigin(origin); slicedGeometry->SetSpacing(spacing); GetTimeSlicedGeometry()->InitializeEvenlyTimed(slicedGeometry, m_Dimensions[3]); delete [] tmpDimensions; } void mitk::Image::Initialize(const mitkIpPicDescriptor* pic, int channels, int tDim, int sDim) { if(pic==NULL) return; Clear(); m_Dimension=pic->dim; m_Dimensions=new unsigned int[m_Dimension>4?m_Dimension:4]; std::memcpy(m_Dimensions, pic->n, sizeof(unsigned int)*m_Dimension); if(m_Dimension<4) { unsigned int i, *p; for(i=0,p=m_Dimensions+m_Dimension;i<4-m_Dimension;++i, ++p) *p=1; } if(sDim>=0) { m_Dimensions[2]=sDim; if(m_Dimension < 3) m_Dimension = 3; } if(tDim>=0) { m_Dimensions[3]=tDim; if(m_Dimension < 4) m_Dimension = 4; } unsigned int i; for(i=0;i<4;++i) { m_LargestPossibleRegion.SetIndex(i, 0); m_LargestPossibleRegion.SetSize (i, m_Dimensions[i]); } m_LargestPossibleRegion.SetIndex(i, 0); m_LargestPossibleRegion.SetSize(i, channels); m_PixelType=PixelType(pic); SlicedGeometry3D::Pointer slicedGeometry = SlicedGeometry3D::New(); PicHelper::InitializeEvenlySpaced(pic, m_Dimensions[2], slicedGeometry); TimeSlicedGeometry::Pointer timeSliceGeometry = TimeSlicedGeometry::New(); timeSliceGeometry->InitializeEvenlyTimed(slicedGeometry, m_Dimensions[3]); timeSliceGeometry->ImageGeometryOn(); SetGeometry(timeSliceGeometry); ImageDataItemPointer dnull=NULL; m_Channels.assign(GetNumberOfChannels(), dnull); m_Volumes.assign(GetNumberOfChannels()*m_Dimensions[3], dnull); m_Slices.assign(GetNumberOfChannels()*m_Dimensions[3]*m_Dimensions[2], dnull); ComputeOffsetTable(); Initialize(); m_Initialized = true; } bool mitk::Image::IsValidSlice(int s, int t, int n) const { if(m_Initialized) return ((s>=0) && (s<(int)m_Dimensions[2]) && (t>=0) && (t< (int) m_Dimensions[3]) && (n>=0) && (n< (int)GetNumberOfChannels())); else return false; } bool mitk::Image::IsValidVolume(int t, int n) const { if(m_Initialized) return IsValidSlice(0, t, n); else return false; } bool mitk::Image::IsValidChannel(int n) const { if(m_Initialized) return IsValidSlice(0, 0, n); else return false; } void mitk::Image::ComputeOffsetTable() { if(m_OffsetTable!=NULL) delete [] m_OffsetTable; m_OffsetTable=new size_t[m_Dimension>4 ? m_Dimension+1 : 4+1]; unsigned int i; size_t num=1; m_OffsetTable[0] = 1; for (i=0; i < m_Dimension; ++i) { num *= m_Dimensions[i]; m_OffsetTable[i+1] = num; } for (;i < 4; ++i) m_OffsetTable[i+1] = num; } int mitk::Image::GetSliceIndex(int s, int t, int n) const { if(IsValidSlice(s,t,n)==false) return false; return ((size_t)s)+((size_t) t)*m_Dimensions[2]+((size_t) n)*m_Dimensions[3]*m_Dimensions[2]; //?? } int mitk::Image::GetVolumeIndex(int t, int n) const { if(IsValidVolume(t,n)==false) return false; return ((size_t)t)+((size_t) n)*m_Dimensions[3]; //?? } mitk::Image::ImageDataItemPointer mitk::Image::AllocateSliceData(int s, int t, int n, void *data, ImportMemoryManagementType importMemoryManagement) { int pos; pos=GetSliceIndex(s,t,n); // is slice available as part of a volume that is available? ImageDataItemPointer sl, ch, vol; vol=m_Volumes[GetVolumeIndex(t,n)]; if(vol.GetPointer()!=NULL) { sl=new ImageDataItem(*vol, 2, data, importMemoryManagement == ManageMemory, ((size_t) s)*m_OffsetTable[2]*(m_PixelType.GetBpe()/8)); sl->SetComplete(true); return m_Slices[pos]=sl; } // is slice available as part of a channel that is available? ch=m_Channels[n]; if(ch.GetPointer()!=NULL) { sl=new ImageDataItem(*ch, 2, data, importMemoryManagement == ManageMemory, (((size_t) s)*m_OffsetTable[2]+((size_t) t)*m_OffsetTable[3])*(m_PixelType.GetBpe()/8)); sl->SetComplete(true); return m_Slices[pos]=sl; } // allocate new volume (instead of a single slice to keep data together!) m_Volumes[GetVolumeIndex(t,n)]=vol=AllocateVolumeData(t,n,NULL,importMemoryManagement); sl=new ImageDataItem(*vol, 2, data, importMemoryManagement == ManageMemory, ((size_t) s)*m_OffsetTable[2]*(m_PixelType.GetBpe()/8)); sl->SetComplete(true); return m_Slices[pos]=sl; ////ALTERNATIVE: //// allocate new slice //sl=new ImageDataItem(m_PixelType, 2, m_Dimensions); //m_Slices[pos]=sl; //return vol; } mitk::Image::ImageDataItemPointer mitk::Image::AllocateVolumeData(int t, int n, void *data, ImportMemoryManagementType importMemoryManagement) { int pos; pos=GetVolumeIndex(t,n); // is volume available as part of a channel that is available? ImageDataItemPointer ch, vol; ch=m_Channels[n]; if(ch.GetPointer()!=NULL) { vol=new ImageDataItem(*ch, 3, data, importMemoryManagement == ManageMemory, (((size_t) t)*m_OffsetTable[3])*(m_PixelType.GetBpe()/8)); return m_Volumes[pos]=vol; } // allocate new volume if(importMemoryManagement == CopyMemory) { vol=new ImageDataItem(m_PixelType, 3, m_Dimensions, NULL, true); if(data != NULL) std::memcpy(vol->GetData(), data, m_OffsetTable[3]*(m_PixelType.GetBpe()/8)); } else { vol=new ImageDataItem(m_PixelType, 3, m_Dimensions, data, importMemoryManagement == ManageMemory); } m_Volumes[pos]=vol; return vol; } mitk::Image::ImageDataItemPointer mitk::Image::AllocateChannelData(int n, void *data, ImportMemoryManagementType importMemoryManagement) { ImageDataItemPointer ch; // allocate new channel if(importMemoryManagement == CopyMemory) { ch=new ImageDataItem(m_PixelType, m_Dimension, m_Dimensions, NULL, true); if(data != NULL) std::memcpy(ch->GetData(), data, m_OffsetTable[4]*(m_PixelType.GetBpe()/8)); } else { ch=new ImageDataItem(m_PixelType, m_Dimension, m_Dimensions, data, importMemoryManagement == ManageMemory); } m_Channels[n]=ch; return ch; } unsigned int* mitk::Image::GetDimensions() const { return m_Dimensions; } void mitk::Image::Clear() { Superclass::Clear(); delete [] m_Dimensions; m_Dimensions = NULL; } void mitk::Image::SetGeometry(Geometry3D* aGeometry3D) { // Please be aware of the 0.5 offset/pixel-center issue! See Geometry documentation for further information if(aGeometry3D->GetImageGeometry()==false) { MITK_INFO << "WARNING: Applied a non-image geometry onto an image. Please be SURE that this geometry is pixel-center-based! If it is not, you need to call Geometry3D->ChangeImageGeometryConsideringOriginOffset(true) before calling image->setGeometry(..)\n"; } Superclass::SetGeometry(aGeometry3D); GetTimeSlicedGeometry()->ImageGeometryOn(); } const mitk::Image::HistogramType* mitk::Image::GetScalarHistogram(int t) const { mitk::ImageTimeSelector* timeSelector = this->GetTimeSelector(); if(timeSelector!=NULL) { timeSelector->SetTimeNr(t); timeSelector->UpdateLargestPossibleRegion(); mitk::HistogramGenerator* generator = static_cast(m_HistogramGeneratorObject.GetPointer()); generator->SetImage(timeSelector->GetOutput()); generator->ComputeHistogram(); return static_cast(generator->GetHistogram()); } return NULL; } #include "mitkImageAccessByItk.h" //#define BOUNDINGOBJECT_IGNORE template < typename ItkImageType > void mitk::_ComputeExtremaInItkImage(ItkImageType* itkImage, mitk::Image* mitkImage, int t) { typename ItkImageType::RegionType region; region = itkImage->GetBufferedRegion(); if(region.Crop(itkImage->GetRequestedRegion()) == false) return; if(region != itkImage->GetRequestedRegion()) return; itk::ImageRegionConstIterator it(itkImage, region); typedef typename ItkImageType::PixelType TPixel; TPixel value = 0; if ( !mitkImage || !mitkImage->IsValidTimeStep( t ) ) return; mitkImage->Expand(t+1); // make sure we have initialized all arrays mitkImage->m_CountOfMinValuedVoxels[t] = 0; mitkImage->m_CountOfMaxValuedVoxels[t] = 0; mitkImage->m_Scalar2ndMin[t]= mitkImage->m_ScalarMin[t] = itk::NumericTraits::max(); mitkImage->m_Scalar2ndMax[t]= mitkImage->m_ScalarMax[t] = itk::NumericTraits::NonpositiveMin(); while( !it.IsAtEnd() ) { value = it.Get(); // if ( (value > mitkImage->m_ScalarMin) && (value < mitkImage->m_Scalar2ndMin) ) mitkImage->m_Scalar2ndMin = value; // else if ( (value < mitkImage->m_ScalarMax) && (value > mitkImage->m_Scalar2ndMax) ) mitkImage->m_Scalar2ndMax = value; // else if (value > mitkImage->m_ScalarMax) mitkImage->m_ScalarMax = value; // else if (value < mitkImage->m_ScalarMin) mitkImage->m_ScalarMin = value; // if numbers start with 2ndMin or 2ndMax and never have that value again, the previous above logic failed #ifdef BOUNDINGOBJECT_IGNORE if( value > -32765) { #endif // update min if ( value < mitkImage->m_ScalarMin[t] ) { mitkImage->m_Scalar2ndMin[t] = mitkImage->m_ScalarMin[t]; mitkImage->m_ScalarMin[t] = value; mitkImage->m_CountOfMinValuedVoxels[t] = 1; } else if ( value == mitkImage->m_ScalarMin[t] ) { ++mitkImage->m_CountOfMinValuedVoxels[t]; } else if ( value < mitkImage->m_Scalar2ndMin[t] ) { mitkImage->m_Scalar2ndMin[t] = value; } // update max if ( value > mitkImage->m_ScalarMax[t] ) { mitkImage->m_Scalar2ndMax[t] = mitkImage->m_ScalarMax[t]; mitkImage->m_ScalarMax[t] = value; mitkImage->m_CountOfMaxValuedVoxels[t] = 1; } else if ( value == mitkImage->m_ScalarMax[t] ) { ++mitkImage->m_CountOfMaxValuedVoxels[t]; } else if ( value > mitkImage->m_Scalar2ndMax[t] ) { mitkImage->m_Scalar2ndMax[t] = value; } #ifdef BOUNDINGOBJECT_IGNORE } #endif ++it; } //// guard for wrong 2dMin/Max on single constant value images if (mitkImage->m_ScalarMax[t] == mitkImage->m_ScalarMin[t]) { mitkImage->m_Scalar2ndMax[t] = mitkImage->m_Scalar2ndMin[t] = mitkImage->m_ScalarMax[t]; } mitkImage->m_LastRecomputeTimeStamp.Modified(); //MITK_DEBUG <<"extrema "<::NonpositiveMin()<<" "<m_ScalarMin<<" "<m_Scalar2ndMin<<" "<m_Scalar2ndMax<<" "<m_ScalarMax<<" "<::max(); } bool mitk::Image::IsValidTimeStep(int t) const { return ( ( m_Dimension >= 4 && t <= (int)m_Dimensions[3] && t > 0 ) || (t == 0) ); } -void mitk::Image::Expand( int timeSteps ) const +void mitk::Image::Expand( unsigned int timeSteps ) { if(timeSteps < 1) itkExceptionMacro(<< "Invalid timestep in Image!"); if(! IsValidTimeStep( timeSteps-1 ) ) return; - if(timeSteps > (int)m_ScalarMin.size() ) + Superclass::Expand(timeSteps); + if(timeSteps > m_ScalarMin.size() ) { m_ScalarMin.resize(timeSteps, itk::NumericTraits::max()); m_ScalarMax.resize(timeSteps, itk::NumericTraits::NonpositiveMin()); m_Scalar2ndMin.resize(timeSteps, itk::NumericTraits::max()); m_Scalar2ndMax.resize(timeSteps, itk::NumericTraits::NonpositiveMin()); m_CountOfMinValuedVoxels.resize(timeSteps, 0); m_CountOfMaxValuedVoxels.resize(timeSteps, 0); } } void mitk::Image::ResetImageStatistics() const { m_ScalarMin.assign(1, itk::NumericTraits::max()); m_ScalarMax.assign(1, itk::NumericTraits::NonpositiveMin()); m_Scalar2ndMin.assign(1, itk::NumericTraits::max()); m_Scalar2ndMax.assign(1, itk::NumericTraits::NonpositiveMin()); m_CountOfMinValuedVoxels.assign(1, 0); m_CountOfMaxValuedVoxels.assign(1, 0); } void mitk::Image::ComputeImageStatistics(int t) const { // timestep valid? if (!IsValidTimeStep(t)) return; // image modified? if (this->GetMTime() > m_LastRecomputeTimeStamp.GetMTime()) this->ResetImageStatistics(); // adapt vector length - this->Expand(t+1); + // the const_cast is necessary since the whole statistics are provided + // with const-methods but are actually stored inside the object with mutable + // members. This should be resolved in a redesign of the image class. + const_cast(this)->Expand(t+1); // do we have valid information already? if( m_ScalarMin[t] != itk::NumericTraits::max() || m_Scalar2ndMin[t] != itk::NumericTraits::max() ) return; // Values already calculated before... if(this->m_PixelType.GetNumberOfComponents() == 1) { // recompute mitk::ImageTimeSelector* timeSelector = this->GetTimeSelector(); if(timeSelector!=NULL) { timeSelector->SetTimeNr(t); timeSelector->UpdateLargestPossibleRegion(); mitk::Image* image = timeSelector->GetOutput(); mitk::Image* thisImage = const_cast(this); AccessByItk_2( image, _ComputeExtremaInItkImage, thisImage, t ); } } else if(this->m_PixelType.GetNumberOfComponents() > 1) { m_ScalarMin[t] = 0; m_ScalarMax[t] = 255; } } mitk::ScalarType mitk::Image::GetScalarValueMin(int t) const { ComputeImageStatistics(t); return m_ScalarMin[t]; } mitk::ScalarType mitk::Image::GetScalarValueMax(int t) const { ComputeImageStatistics(t); return m_ScalarMax[t]; } mitk::ScalarType mitk::Image::GetScalarValue2ndMin(int t) const { ComputeImageStatistics(t); return m_Scalar2ndMin[t]; } mitk::ScalarType mitk::Image::GetScalarValue2ndMax(int t) const { ComputeImageStatistics(t); return m_Scalar2ndMax[t]; } mitk::ScalarType mitk::Image::GetCountOfMinValuedVoxels(int t) const { ComputeImageStatistics(t); return m_CountOfMinValuedVoxels[t]; } mitk::ScalarType mitk::Image::GetCountOfMaxValuedVoxels(int t) const { ComputeImageStatistics(t); return m_CountOfMaxValuedVoxels[t]; } void mitk::Image::PrintSelf(std::ostream& os, itk::Indent indent) const { unsigned char i; if(m_Initialized) { os << indent << " PixelType: " << m_PixelType.GetTypeId()->name() << std::endl; os << indent << " BitsPerElement: " << m_PixelType.GetBpe() << std::endl; os << indent << " NumberOfComponents: " << m_PixelType.GetNumberOfComponents() << std::endl; os << indent << " BitsPerComponent: " << m_PixelType.GetBitsPerComponent() << std::endl; os << indent << " Dimension: " << m_Dimension << std::endl; os << indent << " Dimensions: "; for(i=0; i < m_Dimension; ++i) os << GetDimension(i) << " "; os << std::endl; } else { os << indent << " Image not initialized: m_Initialized: false" << std::endl; } Superclass::PrintSelf(os,indent); } bool mitk::Image::IsRotated() const { const mitk::Geometry3D* geo = this->GetGeometry(); bool ret = false; if(geo) { const vnl_matrix_fixed & mx = geo->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix(); float ref = 0; for(short k = 0; k < 3; ++k) ref += mx[k][k]; ref/=1000; // Arbitrary value; if a non-diagonal (nd) element is bigger then this, matrix is considered nd. for(short i = 0; i < 3; ++i) { for(short j = 0; j < 3; ++j) { if(i != j) { if(abs(mx[i][j]) > ref) // matrix is nd ret = true; } } } } return ret; } diff --git a/Core/Code/DataManagement/mitkImage.h b/Core/Code/DataManagement/mitkImage.h index 74f9337cdb..3c2dc23d4d 100644 --- a/Core/Code/DataManagement/mitkImage.h +++ b/Core/Code/DataManagement/mitkImage.h @@ -1,658 +1,658 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef MITKIMAGE_H_HEADER_INCLUDED_C1C2FCD2 #define MITKIMAGE_H_HEADER_INCLUDED_C1C2FCD2 #include "mitkCommon.h" #include "mitkSlicedData.h" #include "mitkPixelType.h" #include "mitkBaseData.h" #include "mitkLevelWindow.h" #include "mitkPlaneGeometry.h" #ifndef __itkHistogram_h #include #endif class vtkImageData; namespace mitk { class SubImageSelector; class ImageDataItem; class ImageTimeSelector; //##Documentation //## @brief Image class for storing images //## //## Can be asked for header information, the data vector, //## the mitkIpPicDescriptor struct or vtkImageData objects. If not the complete //## data is required, the appropriate SubImageSelector class should be used //## for access. //## Image organizes sets of slices (s x 2D), volumes (t x 3D) and channels (n //## x ND). Channels are for different kind of data, e.g., morphology in //## channel 0, velocities in channel 1. All channels must have the same Geometry! In //## particular, the dimensions of all channels are the same, only the pixel-type //## may differ between channels. //## //## For importing ITK images use of mitk::ITKImageImport is recommended, see //## \ref Adaptor. //## //## For ITK v3.8 and older: Converting coordinates from the ITK physical //## coordinate system (which does not support rotated images) to the MITK world //## coordinate system should be performed via the Geometry3D of the Image, see //## Geometry3D::WorldToItkPhysicalPoint. //## @ingroup Data class MITK_CORE_EXPORT Image : public SlicedData { friend class SubImageSelector; public: mitkClassMacro(Image, SlicedData); itkNewMacro(Self); /** Smart Pointer type to a ImageDataItem. */ typedef itk::SmartPointerForwardReference ImageDataItemPointer; //## @param ImportMemoryManagementType This parameter is evaluated when setting new data to an image. //## The different options are: //## CopyMemory: Data to be set is copied and assigned to a new memory block. Data memory block will be freed on deletion of mitk::Image. //## MamageMemory: Data to be set will be referenced, and Data memory block will be freed on deletion of mitk::Image. //## Reference Memory: Data to be set will be referenced, but Data memory block will not be freed on deletion of mitk::Image. //## DontManageMemory = ReferenceMemory. enum ImportMemoryManagementType { CopyMemory, ManageMemory, ReferenceMemory, DontManageMemory = ReferenceMemory }; //##Documentation //## @brief Vector container of SmartPointers to ImageDataItems; //## Class is only for internal usage to allow convenient access to all slices over iterators; //## See documentation of ImageDataItem for details. typedef std::vector ImageDataItemPointerArray; typedef itk::Statistics::Histogram HistogramType; public: //##Documentation //## @brief Returns the PixelType of channel @a n. const mitk::PixelType& GetPixelType(int n = 0) const; //##Documentation //## @brief Get dimension of the image //## unsigned int GetDimension() const; //##Documentation //## @brief Get the size of dimension @a i (e.g., i=0 results in the number of pixels in x-direction). //## //## @sa GetDimensions() unsigned int GetDimension(int i) const; //## @brief Get the data vector of the complete image, i.e., of all channels linked together. //## //## If you only want to access a slice, volume at a specific time or single channel //## use one of the SubImageSelector classes. virtual void* GetData(); //## @brief Get the pixel value at one specific index position. //## @brief Get the pixel value at one specific position. //## //## The pixel type is always being converted to double. double GetPixelValueByIndex(const mitk::Index3D& position, unsigned int timestep = 0); //## @brief Get the pixel value at one specific world position. //## //## The pixel type is always being converted to double. double GetPixelValueByWorldCoordinate(const mitk::Point3D& position, unsigned int timestep = 0); //##Documentation //## @brief Get a volume at a specific time @a t of channel @a n as a vtkImageData. virtual vtkImageData* GetVtkImageData(int t = 0, int n = 0); //##Documentation //## @brief Get the complete image, i.e., all channels linked together, as a @a mitkIpPicDescriptor. //## //## If you only want to access a slice, volume at a specific time or single channel //## use one of the SubImageSelector classes. virtual mitkIpPicDescriptor* GetPic(); //##Documentation //## @brief Check whether slice @a s at time @a t in channel @a n is set virtual bool IsSliceSet(int s = 0, int t = 0, int n = 0) const; //##Documentation //## @brief Check whether volume at time @a t in channel @a n is set virtual bool IsVolumeSet(int t = 0, int n = 0) const; //##Documentation //## @brief Check whether the channel @a n is set virtual bool IsChannelSet(int n = 0) const; //##Documentation //## @brief Set @a data as slice @a s at time @a t in channel @a n. It is in //## the responsibility of the caller to ensure that the data vector @a data //## is really a slice (at least is not smaller than a slice), since there is //## no chance to check this. //## //## The data is copied to an array managed by the image. If the image shall //## reference the data, use SetImportSlice with ImportMemoryManagementType //## set to ReferenceMemory. For importing ITK images use of mitk:: //## ITKImageImport is recommended. //## @sa SetPicSlice, SetImportSlice, SetImportVolume virtual bool SetSlice(const void *data, int s = 0, int t = 0, int n = 0); //##Documentation //## @brief Set @a data as volume at time @a t in channel @a n. It is in //## the responsibility of the caller to ensure that the data vector @a data //## is really a volume (at least is not smaller than a volume), since there is //## no chance to check this. //## //## The data is copied to an array managed by the image. If the image shall //## reference the data, use SetImportVolume with ImportMemoryManagementType //## set to ReferenceMemory. For importing ITK images use of mitk:: //## ITKImageImport is recommended. //## @sa SetPicVolume, SetImportVolume virtual bool SetVolume(const void *data, int t = 0, int n = 0); //##Documentation //## @brief Set @a data in channel @a n. It is in //## the responsibility of the caller to ensure that the data vector @a data //## is really a channel (at least is not smaller than a channel), since there is //## no chance to check this. //## //## The data is copied to an array managed by the image. If the image shall //## reference the data, use SetImportChannel with ImportMemoryManagementType //## set to ReferenceMemory. For importing ITK images use of mitk:: //## ITKImageImport is recommended. //## @sa SetPicChannel, SetImportChannel virtual bool SetChannel(const void *data, int n = 0); //##Documentation //## @brief Set @a data as slice @a s at time @a t in channel @a n. It is in //## the responsibility of the caller to ensure that the data vector @a data //## is really a slice (at least is not smaller than a slice), since there is //## no chance to check this. //## //## The data is managed according to the parameter \a importMemoryManagement. //## @sa SetPicSlice virtual bool SetImportSlice(void *data, int s = 0, int t = 0, int n = 0, ImportMemoryManagementType importMemoryManagement = CopyMemory ); //##Documentation //## @brief Set @a data as volume at time @a t in channel @a n. It is in //## the responsibility of the caller to ensure that the data vector @a data //## is really a volume (at least is not smaller than a volume), since there is //## no chance to check this. //## //## The data is managed according to the parameter \a importMemoryManagement. //## @sa SetPicVolume virtual bool SetImportVolume(void *data, int t = 0, int n = 0, ImportMemoryManagementType importMemoryManagement = CopyMemory ); //##Documentation //## @brief Set @a data in channel @a n. It is in //## the responsibility of the caller to ensure that the data vector @a data //## is really a channel (at least is not smaller than a channel), since there is //## no chance to check this. //## //## The data is managed according to the parameter \a importMemoryManagement. //## @sa SetPicChannel virtual bool SetImportChannel(void *data, int n = 0, ImportMemoryManagementType importMemoryManagement = CopyMemory ); //##Documentation //## @brief Set @a pic as slice @a s at time @a t in channel @a n. //## //## The data is copied to an array managed by the image. //## @todo The corresponding @a Geomety3D and depending @a Geometry2D entries //## are updated according to the information provided in the tags of @a pic. //## @return @a false : dimensions and/or data-type of @a pic does not //## comply with image //## @a true success virtual bool SetPicSlice(const mitkIpPicDescriptor *pic, int s = 0, int t = 0, int n = 0, ImportMemoryManagementType importMemoryManagement = CopyMemory ); //##Documentation //## @brief Set @a pic as volume at time @a t in channel @a n. //## //## The data is copied to an array managed by the image. //## @todo The corresponding @a Geomety3D and depending @a Geometry2D entries //## are updated according to the information provided in the tags of @a pic. //## @return @a false : dimensions and/or data-type of @a pic does not //## comply with image //## @a true success virtual bool SetPicVolume(const mitkIpPicDescriptor *pic, int t = 0, int n = 0, ImportMemoryManagementType importMemoryManagement = CopyMemory ); //##Documentation //## @brief Set @a pic in channel @a n. //## //## The data is copied to an array managed by the image. //## @todo The corresponding @a Geomety3D and depending @a Geometry2D entries //## are updated according to the information provided in the tags of @a pic. //## @return @a false : dimensions and/or data-type of @a pic does not //## comply with image //## @a true success virtual bool SetPicChannel(const mitkIpPicDescriptor *pic, int n = 0, ImportMemoryManagementType importMemoryManagement = CopyMemory ); //##Documentation //## initialize new (or re-initialize) image information //## @warning Initialize() by pic assumes a plane, evenly spaced geometry starting at (0,0,0). virtual void Initialize(const mitk::PixelType& type, unsigned int dimension, unsigned int *dimensions, unsigned int channels = 1); //##Documentation //## initialize new (or re-initialize) image information by a Geometry3D //## //## @param tDim override time dimension (@a n[3]) if @a geometry is a TimeSlicedGeometry (if >0) virtual void Initialize(const mitk::PixelType& type, const mitk::Geometry3D& geometry, unsigned int channels = 1, int tDim=-1); //##Documentation //## initialize new (or re-initialize) image information by a Geometry2D and number of slices //## //## Initializes the bounding box according to the width/height of the //## Geometry2D and @a sDim via SlicedGeometry3D::InitializeEvenlySpaced. //## The spacing is calculated from the Geometry2D. //## @param tDim override time dimension (@a n[3]) if @a geometry is a TimeSlicedGeometry (if >0) //## \sa SlicedGeometry3D::InitializeEvenlySpaced virtual void Initialize(const mitk::PixelType& type, int sDim, const mitk::Geometry2D& geometry2d, bool flipped = false, unsigned int channels = 1, int tDim=-1); //##Documentation //## initialize new (or re-initialize) image information by another //## mitk-image. //## Only the header is used, not the data vector! //## virtual void Initialize(const mitk::Image* image); //##Documentation //## initialize new (or re-initialize) image information by @a pic. //## Dimensions and @a Geometry3D /@a Geometry2D are set according //## to the tags in @a pic. //## Only the header is used, not the data vector! Use SetPicVolume(pic) //## to set the data vector. //## //## @param tDim override time dimension (@a n[3]) in @a pic (if >0) //## @param sDim override z-space dimension (@a n[2]) in @a pic (if >0) //## @warning Initialize() by pic assumes a plane, evenly spaced geometry starting at (0,0,0). virtual void Initialize(const mitkIpPicDescriptor* pic, int channels = 1, int tDim = -1, int sDim = -1); //##Documentation //## initialize new (or re-initialize) image information by @a vtkimagedata, //## a vtk-image. //## Only the header is used, not the data vector! Use //## SetVolume(vtkimage->GetScalarPointer()) to set the data vector. //## //## @param tDim override time dimension in @a vtkimagedata (if >0 and <) //## @param sDim override z-space dimension in @a vtkimagedata (if >0 and <) virtual void Initialize(vtkImageData* vtkimagedata, int channels = 1, int tDim = -1, int sDim = -1); //##Documentation //## initialize new (or re-initialize) image information by @a itkimage, //## a templated itk-image. //## Only the header is used, not the data vector! Use //## SetVolume(itkimage->GetBufferPointer()) to set the data vector. //## //## @param tDim override time dimension in @a itkimage (if >0 and <) //## @param sDim override z-space dimension in @a itkimage (if >0 and <) template void InitializeByItk(const itkImageType* itkimage, int channels = 1, int tDim = -1, int sDim=-1) { if(itkimage==NULL) return; MITK_DEBUG << "Initializing MITK image from ITK image."; // build array with dimensions in each direction with at least 4 entries m_Dimension=itkimage->GetImageDimension(); unsigned int i, *tmpDimensions=new unsigned int[m_Dimension>4?m_Dimension:4]; for(i=0;iGetLargestPossibleRegion().GetSize().GetSize()[i]; if(m_Dimension<4) { unsigned int *p; for(i=0,p=tmpDimensions+m_Dimension;i<4-m_Dimension;++i, ++p) *p=1; } // overwrite number of slices if sDim is set if((m_Dimension>2) && (sDim>=0)) tmpDimensions[2]=sDim; // overwrite number of time points if tDim is set if((m_Dimension>3) && (tDim>=0)) tmpDimensions[3]=tDim; // rough initialization of Image Initialize(mitk::PixelType(typeid(typename itkImageType::PixelType)), m_Dimension, tmpDimensions, channels); const typename itkImageType::SpacingType & itkspacing = itkimage->GetSpacing(); MITK_DEBUG << "ITK spacing " << itkspacing; // access spacing of itk::Image Vector3D spacing; FillVector3D(spacing, itkspacing[0], 1.0, 1.0); if(m_Dimension >= 2) spacing[1]=itkspacing[1]; if(m_Dimension >= 3) spacing[2]=itkspacing[2]; // access origin of itk::Image Point3D origin; const typename itkImageType::PointType & itkorigin = itkimage->GetOrigin(); MITK_DEBUG << "ITK origin " << itkorigin; FillVector3D(origin, itkorigin[0], 0.0, 0.0); if(m_Dimension>=2) origin[1]=itkorigin[1]; if(m_Dimension>=3) origin[2]=itkorigin[2]; // access direction of itk::Image and include spacing const typename itkImageType::DirectionType & itkdirection = itkimage->GetDirection(); MITK_DEBUG << "ITK direction " << itkdirection; mitk::Matrix3D matrix; matrix.SetIdentity(); unsigned int j, itkDimMax3 = (m_Dimension >= 3? 3 : m_Dimension); // check if spacing has no zero entry and itkdirection has no zero columns bool itkdirectionOk = true; mitk::ScalarType columnSum; for( j=0; j < itkDimMax3; ++j ) { columnSum = 0.0; for ( i=0; i < itkDimMax3; ++i) { columnSum += fabs(itkdirection[i][j]); } if(columnSum < mitk::eps) { itkdirectionOk = false; } if ( (spacing[j] < - mitk::eps) // (normally sized) negative value && (j==2) && (m_Dimensions[2] == 1) ) { // Negative spacings can occur when reading single DICOM slices with ITK via GDCMIO // In these cases spacing is not determind by ITK correctly (because it distinguishes correctly // between slice thickness and inter slice distance -- slice distance is meaningless for // single slices). // I experienced that ITK produced something meaningful nonetheless because is is // evaluating the tag "(0018,0088) Spacing between slices" as a fallback. This tag is not // reliable (http://www.itk.org/pipermail/insight-users/2005-September/014711.html) // but gives at least a hint. // In real world cases I experienced that this tag contained the correct inter slice distance // with a negative sign, so we just invert such negative spacings. MITK_WARN << "Illegal value of itk::Image::GetSpacing()[" << j <<"]=" << spacing[j] << ". Using inverted value " << -spacing[j]; spacing[j] = -spacing[j]; } else if (spacing[j] < mitk::eps) // value near zero { MITK_ERROR << "Illegal value of itk::Image::GetSpacing()[" << j <<"]=" << spacing[j] << ". Using 1.0 instead."; spacing[j] = 1.0; } } if(itkdirectionOk == false) { MITK_ERROR << "Illegal matrix returned by itk::Image::GetDirection():" << itkdirection << " Using identity instead."; for ( i=0; i < itkDimMax3; ++i) for( j=0; j < itkDimMax3; ++j ) if ( i == j ) matrix[i][j] = spacing[j]; else matrix[i][j] = 0.0; } else { for ( i=0; i < itkDimMax3; ++i) for( j=0; j < itkDimMax3; ++j ) matrix[i][j] = itkdirection[i][j]*spacing[j]; } // re-initialize PlaneGeometry with origin and direction PlaneGeometry* planeGeometry = static_cast(GetSlicedGeometry(0)->GetGeometry2D(0)); planeGeometry->SetOrigin(origin); planeGeometry->GetIndexToWorldTransform()->SetMatrix(matrix); // re-initialize SlicedGeometry3D SlicedGeometry3D* slicedGeometry = GetSlicedGeometry(0); slicedGeometry->InitializeEvenlySpaced(planeGeometry, m_Dimensions[2]); slicedGeometry->SetSpacing(spacing); // re-initialize TimeSlicedGeometry GetTimeSlicedGeometry()->InitializeEvenlyTimed(slicedGeometry, m_Dimensions[3]); // clean-up delete [] tmpDimensions; this->Initialize(); }; //##Documentation //## @brief Check whether slice @a s at time @a t in channel @a n is valid, i.e., //## is (or can be) inside of the image virtual bool IsValidSlice(int s = 0, int t = 0, int n = 0) const; //##Documentation //## @brief Check whether volume at time @a t in channel @a n is valid, i.e., //## is (or can be) inside of the image virtual bool IsValidVolume(int t = 0, int n = 0) const; //##Documentation //## @brief Check whether the channel @a n is valid, i.e., //## is (or can be) inside of the image virtual bool IsValidChannel(int n = 0) const; //##Documentation //## @brief Returns true if an image is rotated, i.e. its geometry's //## transformation matrix has nonzero elements besides the diagonal. //## Non-diagonal elements are checked if larger then 1/1000 of the matrix' trace. bool IsRotated() const; //##Documentation //## @brief Get the sizes of all dimensions as an integer-array. //## //## @sa GetDimension(int i); unsigned int* GetDimensions() const; //##Documentation //## @brief Sets a geometry to an image. virtual void SetGeometry(Geometry3D* aGeometry3D); virtual const HistogramType* GetScalarHistogram(int t=0) const; //##Documentation //## \brief Get the minimum for scalar images virtual ScalarType GetScalarValueMin(int t=0) const; //##Documentation //## \brief Get the maximum for scalar images virtual ScalarType GetScalarValueMax(int t=0) const; //##Documentation //## \brief Get the second smallest value for scalar images virtual ScalarType GetScalarValue2ndMin(int t=0) const; //##Documentation //## \brief Get the smallest value for scalar images, but do not recompute it first virtual mitk::ScalarType GetScalarValueMinNoRecompute( unsigned int t = 0 ) const { if ( t < m_ScalarMin.size() ) return m_ScalarMin[t]; else return itk::NumericTraits::max(); } //##Documentation //## \brief Get the second smallest value for scalar images, but do not recompute it first virtual mitk::ScalarType GetScalarValue2ndMinNoRecompute( unsigned int t = 0 ) const { if ( t < m_Scalar2ndMin.size() ) return m_Scalar2ndMin[t]; else return itk::NumericTraits::max(); } //##Documentation //## \brief Get the second largest value for scalar images virtual ScalarType GetScalarValue2ndMax(int t=0) const; //##Documentation //## \brief Get the largest value for scalar images, but do not recompute it first virtual mitk::ScalarType GetScalarValueMaxNoRecompute( unsigned int t = 0 ) const { if ( t < m_ScalarMax.size() ) return m_ScalarMax[t]; else return itk::NumericTraits::NonpositiveMin(); } //##Documentation //## \brief Get the second largest value for scalar images, but do not recompute it first virtual mitk::ScalarType GetScalarValue2ndMaxNoRecompute( unsigned int t = 0 ) const { if ( t < m_Scalar2ndMax.size() ) return m_Scalar2ndMax[t]; else return itk::NumericTraits::NonpositiveMin(); } //##Documentation //## \brief Get the count of voxels with the smallest scalar value in the dataset mitk::ScalarType GetCountOfMinValuedVoxels(int t = 0) const; //##Documentation //## \brief Get the count of voxels with the largest scalar value in the dataset mitk::ScalarType GetCountOfMaxValuedVoxels(int t = 0) const; //##Documentation //## \brief Get the count of voxels with the largest scalar value in the dataset virtual unsigned int GetCountOfMaxValuedVoxelsNoRecompute( unsigned int t = 0 ) const { if ( t < m_CountOfMaxValuedVoxels.size() ) return m_CountOfMaxValuedVoxels[t]; else return 0; } //##Documentation //## \brief Get the count of voxels with the smallest scalar value in the dataset virtual unsigned int GetCountOfMinValuedVoxelsNoRecompute( unsigned int t = 0 ) const { if ( t < m_CountOfMinValuedVoxels.size() ) return m_CountOfMinValuedVoxels[t]; else return 0; } //##Documentation //## @warning for internal use only virtual ImageDataItemPointer GetSliceData(int s = 0, int t = 0, int n = 0, void *data = NULL, ImportMemoryManagementType importMemoryManagement = CopyMemory); //##Documentation //## @warning for internal use only virtual ImageDataItemPointer GetVolumeData(int t = 0, int n = 0, void *data = NULL, ImportMemoryManagementType importMemoryManagement = CopyMemory); //##Documentation //## @warning for internal use only virtual ImageDataItemPointer GetChannelData(int n = 0, void *data = NULL, ImportMemoryManagementType importMemoryManagement = CopyMemory); template < typename ItkImageType > friend void _ComputeExtremaInItkImage(ItkImageType* itkImage, mitk::Image * mitkImage, int t); protected: int GetSliceIndex(int s = 0, int t = 0, int n = 0) const; int GetVolumeIndex(int t = 0, int n = 0) const; void ComputeOffsetTable(); - virtual void Expand( int timeSteps ) const; + virtual void Expand( unsigned int timeSteps ); virtual bool IsValidTimeStep(int t) const; virtual void ResetImageStatistics() const; virtual void ComputeImageStatistics(int t=0) const; virtual ImageDataItemPointer AllocateSliceData(int s = 0, int t = 0, int n = 0, void *data = NULL, ImportMemoryManagementType importMemoryManagement = CopyMemory); virtual ImageDataItemPointer AllocateVolumeData(int t = 0, int n = 0, void *data = NULL, ImportMemoryManagementType importMemoryManagement = CopyMemory); virtual ImageDataItemPointer AllocateChannelData(int n = 0, void *data = NULL, ImportMemoryManagementType importMemoryManagement = CopyMemory); Image(); virtual ~Image(); virtual void Clear(); //## @warning Has to be called by every Initialize method! virtual void Initialize(); ImageTimeSelector* GetTimeSelector() const; virtual void PrintSelf(std::ostream& os, itk::Indent indent) const; mutable ImageDataItemPointerArray m_Channels; mutable ImageDataItemPointerArray m_Volumes; mutable ImageDataItemPointerArray m_Slices; unsigned int m_Dimension; unsigned int *m_Dimensions; size_t *m_OffsetTable; ImageDataItemPointer m_CompleteData; PixelType m_PixelType; mutable itk::Object::Pointer m_HistogramGeneratorObject; mutable itk::Object::Pointer m_TimeSelectorForExtremaObject; mutable std::vector m_CountOfMinValuedVoxels; mutable std::vector m_CountOfMaxValuedVoxels; mutable std::vector m_ScalarMin; mutable std::vector m_ScalarMax; mutable std::vector m_Scalar2ndMin; mutable std::vector m_Scalar2ndMax; itk::TimeStamp m_LastRecomputeTimeStamp; }; //##Documentation //## @brief Cast an itk::Image (with a specific type) to an mitk::Image. //## //## CastToMitkImage does not cast pixel types etc., just image data //## Needs "mitkImage.h" header included. //## If you get a compile error, try image.GetPointer(); //## @ingroup Adaptor //## \sa mitkITKImageImport template void CastToMitkImage(const itk::SmartPointer& itkimage, itk::SmartPointer& mitkoutputimage) { if(mitkoutputimage.IsNull()) { mitkoutputimage = mitk::Image::New(); } mitkoutputimage->InitializeByItk(itkimage.GetPointer()); mitkoutputimage->SetChannel(itkimage->GetBufferPointer()); } //##Documentation //## @brief Cast an itk::Image (with a specific type) to an mitk::Image. //## //## CastToMitkImage does not cast pixel types etc., just image data //## Needs "mitkImage.h" header included. //## If you get a compile error, try image.GetPointer(); //## @ingroup Adaptor //## \sa mitkITKImageImport template void CastToMitkImage(const ItkOutputImageType* itkimage, itk::SmartPointer& mitkoutputimage) { if(mitkoutputimage.IsNull()) { mitkoutputimage = mitk::Image::New(); } mitkoutputimage->InitializeByItk(itkimage); mitkoutputimage->SetChannel(itkimage->GetBufferPointer()); } } // namespace mitk #endif /* MITKIMAGE_H_HEADER_INCLUDED_C1C2FCD2 */ diff --git a/Core/Code/DataManagement/mitkLandmarkBasedCurvedGeometry.cpp b/Core/Code/DataManagement/mitkLandmarkBasedCurvedGeometry.cpp index 3a785dc677..61a36914e4 100644 --- a/Core/Code/DataManagement/mitkLandmarkBasedCurvedGeometry.cpp +++ b/Core/Code/DataManagement/mitkLandmarkBasedCurvedGeometry.cpp @@ -1,36 +1,36 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "mitkLandmarkBasedCurvedGeometry.h" #include mitk::LandmarkBasedCurvedGeometry::LandmarkBasedCurvedGeometry() : m_TargetLandmarks(NULL) { } -mitk::LandmarkBasedCurvedGeometry::~LandmarkBasedCurvedGeometry() +mitk::LandmarkBasedCurvedGeometry::LandmarkBasedCurvedGeometry(const LandmarkBasedCurvedGeometry& other) + : Superclass(other) { - + SetTargetLandmarks(other.m_TargetLandmarks); } -void mitk::LandmarkBasedCurvedGeometry::InitializeGeometry(Self * newGeometry) const +mitk::LandmarkBasedCurvedGeometry::~LandmarkBasedCurvedGeometry() { - Superclass::InitializeGeometry(newGeometry); - newGeometry->SetTargetLandmarks(m_TargetLandmarks); + } diff --git a/Core/Code/DataManagement/mitkLandmarkBasedCurvedGeometry.h b/Core/Code/DataManagement/mitkLandmarkBasedCurvedGeometry.h index 8cc2e588d4..584a4a4aae 100644 --- a/Core/Code/DataManagement/mitkLandmarkBasedCurvedGeometry.h +++ b/Core/Code/DataManagement/mitkLandmarkBasedCurvedGeometry.h @@ -1,59 +1,61 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef MITKLANDMARKBASEDCURVEDGEOMETRY_H_HEADER_INCLUDED_C1C68A2C #define MITKLANDMARKBASEDCURVEDGEOMETRY_H_HEADER_INCLUDED_C1C68A2C #include "mitkAbstractTransformGeometry.h" #include "mitkPointSet.h" namespace mitk { //##Documentation //## @brief Superclass of AbstractTransformGeometry sub-classes defined //## by a set of landmarks. //## //## @ingroup Geometry class MITK_CORE_EXPORT LandmarkBasedCurvedGeometry : public AbstractTransformGeometry { public: mitkClassMacro(LandmarkBasedCurvedGeometry, AbstractTransformGeometry); //##Documentation //## @brief Set the landmarks through which the geometry shall pass itkSetConstObjectMacro(TargetLandmarks, mitk::PointSet::DataType::PointsContainer); //##Documentation //## @brief Get the landmarks through which the geometry shall pass itkGetConstObjectMacro(TargetLandmarks, mitk::PointSet::DataType::PointsContainer); virtual void ComputeGeometry() = 0; + virtual AffineGeometryFrame3D::Pointer Clone() const = 0; + protected: LandmarkBasedCurvedGeometry(); + LandmarkBasedCurvedGeometry(const LandmarkBasedCurvedGeometry& other); + virtual ~LandmarkBasedCurvedGeometry(); - - void InitializeGeometry(Self * newGeometry) const; mitk::PointSet::DataType::PointsContainer::ConstPointer m_TargetLandmarks; }; } // namespace mitk #endif /* MITKLANDMARKBASEDCURVEDGEOMETRY_H_HEADER_INCLUDED_C1C68A2C */ diff --git a/Core/Code/DataManagement/mitkLandmarkProjectorBasedCurvedGeometry.cpp b/Core/Code/DataManagement/mitkLandmarkProjectorBasedCurvedGeometry.cpp index e327470ab3..6511906f82 100644 --- a/Core/Code/DataManagement/mitkLandmarkProjectorBasedCurvedGeometry.cpp +++ b/Core/Code/DataManagement/mitkLandmarkProjectorBasedCurvedGeometry.cpp @@ -1,78 +1,83 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "mitkLandmarkProjectorBasedCurvedGeometry.h" #include mitk::LandmarkProjectorBasedCurvedGeometry::LandmarkProjectorBasedCurvedGeometry() : m_LandmarkProjector(NULL), m_InterpolatingAbstractTransform(NULL) { } +mitk::LandmarkProjectorBasedCurvedGeometry::LandmarkProjectorBasedCurvedGeometry(const mitk::LandmarkProjectorBasedCurvedGeometry& other) : Superclass(other) +{ + this->SetLandmarkProjector(other.m_LandmarkProjector); + this->ComputeGeometry(); +} + mitk::LandmarkProjectorBasedCurvedGeometry::~LandmarkProjectorBasedCurvedGeometry() { if(m_InterpolatingAbstractTransform!=NULL) m_InterpolatingAbstractTransform->Delete(); } void mitk::LandmarkProjectorBasedCurvedGeometry::SetLandmarkProjector(mitk::LandmarkProjector* aLandmarkProjector) { itkDebugMacro("setting LandmarkProjector to " << aLandmarkProjector ); if(m_LandmarkProjector != aLandmarkProjector) { m_LandmarkProjector = aLandmarkProjector; if(m_LandmarkProjector.IsNotNull()) { if(m_FrameGeometry.IsNotNull()) m_LandmarkProjector->SetFrameGeometry(m_FrameGeometry); if(m_InterpolatingAbstractTransform == NULL) { itkWarningMacro(<<"m_InterpolatingAbstractTransform not set."); } m_LandmarkProjector->SetInterpolatingAbstractTransform(GetInterpolatingAbstractTransform()); SetVtkAbstractTransform(m_LandmarkProjector->GetCompleteAbstractTransform()); } Modified(); } } void mitk::LandmarkProjectorBasedCurvedGeometry::SetFrameGeometry(const mitk::Geometry3D* frameGeometry) { Superclass::SetFrameGeometry(frameGeometry); if(m_LandmarkProjector.IsNotNull()) m_LandmarkProjector->SetFrameGeometry(frameGeometry); } void mitk::LandmarkProjectorBasedCurvedGeometry::ComputeGeometry() { if(m_LandmarkProjector.IsNull()) { itkExceptionMacro(<< "m_LandmarkProjector is not set."); } m_LandmarkProjector->ProjectLandmarks(m_TargetLandmarks); SetPlane(m_LandmarkProjector->GetParameterPlane()); } - -void mitk::LandmarkProjectorBasedCurvedGeometry::InitializeGeometry(Self * newGeometry) const +mitk::AffineGeometryFrame3D::Pointer mitk::LandmarkProjectorBasedCurvedGeometry::Clone() const { - Superclass::InitializeGeometry(newGeometry); - newGeometry->SetLandmarkProjector(m_LandmarkProjector); - newGeometry->ComputeGeometry(); + mitk::AffineGeometryFrame3D::Pointer newGeometry = new LandmarkProjectorBasedCurvedGeometry(*this); + newGeometry->UnRegister(); + return newGeometry.GetPointer(); } diff --git a/Core/Code/DataManagement/mitkLandmarkProjectorBasedCurvedGeometry.h b/Core/Code/DataManagement/mitkLandmarkProjectorBasedCurvedGeometry.h index 0d42cb1337..9381f90d0b 100644 --- a/Core/Code/DataManagement/mitkLandmarkProjectorBasedCurvedGeometry.h +++ b/Core/Code/DataManagement/mitkLandmarkProjectorBasedCurvedGeometry.h @@ -1,59 +1,62 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef MITKLANDMARKPROJECTORBASEDCURVEDGEOMETRY_H_HEADER_INCLUDED_C1C68A2C #define MITKLANDMARKPROJECTORBASEDCURVEDGEOMETRY_H_HEADER_INCLUDED_C1C68A2C #include "mitkLandmarkBasedCurvedGeometry.h" #include "mitkLandmarkProjector.h" namespace mitk { //##Documentation //## @brief Superclass of AbstractTransformGeometry sub-classes defined //## by a set of landmarks. //## //## @ingroup Geometry class MITK_CORE_EXPORT LandmarkProjectorBasedCurvedGeometry : public LandmarkBasedCurvedGeometry { public: mitkClassMacro(LandmarkProjectorBasedCurvedGeometry, LandmarkBasedCurvedGeometry); void SetLandmarkProjector(mitk::LandmarkProjector* aLandmarkProjector); itkGetConstObjectMacro(LandmarkProjector, mitk::LandmarkProjector); virtual void SetFrameGeometry(const mitk::Geometry3D* frameGeometry); virtual void ComputeGeometry(); itkGetConstMacro(InterpolatingAbstractTransform, vtkAbstractTransform*); + + mitk::AffineGeometryFrame3D::Pointer Clone() const; + protected: LandmarkProjectorBasedCurvedGeometry(); + LandmarkProjectorBasedCurvedGeometry(const LandmarkProjectorBasedCurvedGeometry& other); + virtual ~LandmarkProjectorBasedCurvedGeometry(); - void InitializeGeometry(Self * newGeometry) const; - mitk::LandmarkProjector::Pointer m_LandmarkProjector; vtkAbstractTransform* m_InterpolatingAbstractTransform; }; } // namespace mitk #endif /* MITKLANDMARKPROJECTORBASEDCURVEDGEOMETRY_H_HEADER_INCLUDED_C1C68A2C */ diff --git a/Core/Code/DataManagement/mitkLevelWindowProperty.h b/Core/Code/DataManagement/mitkLevelWindowProperty.h index d979cb169f..f5080b2568 100755 --- a/Core/Code/DataManagement/mitkLevelWindowProperty.h +++ b/Core/Code/DataManagement/mitkLevelWindowProperty.h @@ -1,63 +1,65 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef MITKLEVELWINDOWPROPERTY_H_HEADER_INCLUDED_C10EEAA8 #define MITKLEVELWINDOWPROPERTY_H_HEADER_INCLUDED_C10EEAA8 #include "mitkBaseProperty.h" #include "mitkLevelWindow.h" namespace mitk { //##Documentation //## @brief Property for level/window data //## //## @ingroup DataManagement class MITK_CORE_EXPORT LevelWindowProperty : public BaseProperty { protected: LevelWindow m_LevWin; LevelWindowProperty(); LevelWindowProperty(const mitk::LevelWindow &levWin); public: mitkClassMacro(LevelWindowProperty, BaseProperty); itkNewMacro(LevelWindowProperty); mitkNewMacro1Param(LevelWindowProperty, const mitk::LevelWindow&); virtual ~LevelWindowProperty(); + virtual BaseProperty& operator=(const BaseProperty& other) { return Superclass::operator=(other); } + virtual bool operator==(const BaseProperty& property) const; const mitk::LevelWindow & GetLevelWindow() const; void SetLevelWindow(const LevelWindow &levWin); virtual std::string GetValueAsString() const; }; } // namespace mitk #endif /* MITKLEVELWINDOWPROPERTY_H_HEADER_INCLUDED_C10EEAA8 */ diff --git a/Core/Code/DataManagement/mitkModalityProperty.h b/Core/Code/DataManagement/mitkModalityProperty.h index 5d31b4665c..7b5bec4af1 100644 --- a/Core/Code/DataManagement/mitkModalityProperty.h +++ b/Core/Code/DataManagement/mitkModalityProperty.h @@ -1,55 +1,57 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date: 2009-05-15 10:46:54 +0200 (Fr, 15 Mai 2009) $ Version: $Revision: 17272 $ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef mitkModalityProperty_h_Included #define mitkModalityProperty_h_Included #include "mitkCommon.h" #include "mitkEnumerationProperty.h" #include namespace mitk { /** \brief Enumerates all known modalities \ingroup DataManagement */ class MITK_CORE_EXPORT ModalityProperty : public EnumerationProperty { public: mitkClassMacro(ModalityProperty, EnumerationProperty); itkNewMacro(ModalityProperty); mitkNewMacro1Param(ModalityProperty, const IdType&); mitkNewMacro1Param(ModalityProperty, const std::string&); + virtual BaseProperty& operator=(const BaseProperty& other) { return Superclass::operator=(other); } + protected: ModalityProperty(); ModalityProperty( const IdType& value ); ModalityProperty( const std::string& value ); virtual ~ModalityProperty(); virtual void AddEnumerationTypes(); }; } // namespace #endif diff --git a/Core/Code/DataManagement/mitkPlaneGeometry.cpp b/Core/Code/DataManagement/mitkPlaneGeometry.cpp index a0ce9f80a6..abef65059d 100644 --- a/Core/Code/DataManagement/mitkPlaneGeometry.cpp +++ b/Core/Code/DataManagement/mitkPlaneGeometry.cpp @@ -1,764 +1,755 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "mitkPlaneGeometry.h" #include "mitkPlaneOperation.h" #include "mitkInteractionConst.h" #include "mitkLine.h" #include #include namespace mitk { mitk::PlaneGeometry::PlaneGeometry() { Initialize(); } mitk::PlaneGeometry::~PlaneGeometry() { } void PlaneGeometry::Initialize() { Superclass::Initialize(); } void PlaneGeometry::EnsurePerpendicularNormal(mitk::AffineTransform3D *transform) { //ensure row(2) of transform to be perpendicular to plane, keep length. VnlVector normal = vnl_cross_3d( transform->GetMatrix().GetVnlMatrix().get_column(0), transform->GetMatrix().GetVnlMatrix().get_column(1) ); normal.normalize(); ScalarType len = transform->GetMatrix() .GetVnlMatrix().get_column(2).two_norm(); if (len==0) len = 1; normal*=len; Matrix3D matrix = transform->GetMatrix(); matrix.GetVnlMatrix().set_column(2, normal); transform->SetMatrix(matrix); } void PlaneGeometry::SetIndexToWorldTransform(mitk::AffineTransform3D *transform) { EnsurePerpendicularNormal(transform); Superclass::SetIndexToWorldTransform(transform); } void PlaneGeometry::SetBounds(const BoundingBox::BoundsArrayType &bounds) { //currently the unit rectangle must be starting at the origin [0,0] assert(bounds[0]==0); assert(bounds[2]==0); //the unit rectangle must be two-dimensional assert(bounds[1]>0); assert(bounds[3]>0); Superclass::SetBounds(bounds); } void PlaneGeometry::IndexToWorld( const Point2D &pt_units, Point2D &pt_mm ) const { pt_mm[0]=m_ScaleFactorMMPerUnitX*pt_units[0]; pt_mm[1]=m_ScaleFactorMMPerUnitY*pt_units[1]; } void PlaneGeometry::WorldToIndex( const Point2D &pt_mm, Point2D &pt_units ) const { pt_units[0]=pt_mm[0]*(1.0/m_ScaleFactorMMPerUnitX); pt_units[1]=pt_mm[1]*(1.0/m_ScaleFactorMMPerUnitY); } void PlaneGeometry::IndexToWorld( const Point2D &atPt2d_units, const Vector2D &vec_units, Vector2D &vec_mm) const { MITK_WARN<<"Warning! Call of the deprecated function PlaneGeometry::IndexToWorld(point, vec, vec). Use PlaneGeometry::IndexToWorld(vec, vec) instead!"; this->IndexToWorld(vec_units, vec_mm); } void PlaneGeometry::IndexToWorld(const Vector2D &vec_units, Vector2D &vec_mm) const { vec_mm[0] = m_ScaleFactorMMPerUnitX * vec_units[0]; vec_mm[1] = m_ScaleFactorMMPerUnitY * vec_units[1]; } void PlaneGeometry::WorldToIndex( const Point2D &atPt2d_mm, const Vector2D &vec_mm, Vector2D &vec_units) const { MITK_WARN<<"Warning! Call of the deprecated function PlaneGeometry::WorldToIndex(point, vec, vec). Use PlaneGeometry::WorldToIndex(vec, vec) instead!"; this->WorldToIndex(vec_mm, vec_units); } void PlaneGeometry::WorldToIndex( const Vector2D &vec_mm, Vector2D &vec_units) const { vec_units[0] = vec_mm[0] * ( 1.0 / m_ScaleFactorMMPerUnitX ); vec_units[1] = vec_mm[1] * ( 1.0 / m_ScaleFactorMMPerUnitY ); } void PlaneGeometry::InitializeStandardPlane( mitk::ScalarType width, ScalarType height, const Vector3D & spacing, PlaneGeometry::PlaneOrientation planeorientation, ScalarType zPosition, bool frontside, bool rotated ) { AffineTransform3D::Pointer transform; transform = AffineTransform3D::New(); AffineTransform3D::MatrixType matrix; AffineTransform3D::MatrixType::InternalMatrixType &vnlmatrix = matrix.GetVnlMatrix(); vnlmatrix.set_identity(); vnlmatrix(0,0) = spacing[0]; vnlmatrix(1,1) = spacing[1]; vnlmatrix(2,2) = spacing[2]; transform->SetIdentity(); transform->SetMatrix(matrix); InitializeStandardPlane(width, height, transform.GetPointer(), planeorientation, zPosition, frontside, rotated); } void PlaneGeometry::InitializeStandardPlane( mitk::ScalarType width, ScalarType height, const AffineTransform3D* transform, PlaneGeometry::PlaneOrientation planeorientation, ScalarType zPosition, bool frontside, bool rotated ) { Superclass::Initialize(); //construct standard view Point3D origin; VnlVector rightDV(3), bottomDV(3); origin.Fill(0); int normalDirection; switch(planeorientation) { case Transversal: if(frontside) { if(rotated==false) { FillVector3D(origin, 0, 0, zPosition); FillVector3D(rightDV, 1, 0, 0); FillVector3D(bottomDV, 0, 1, 0); } else { FillVector3D(origin, width, height, zPosition); FillVector3D(rightDV, -1, 0, 0); FillVector3D(bottomDV, 0, -1, 0); } } else { if(rotated==false) { FillVector3D(origin, width, 0, zPosition); FillVector3D(rightDV, -1, 0, 0); FillVector3D(bottomDV, 0, 1, 0); } else { FillVector3D(origin, 0, height, zPosition); FillVector3D(rightDV, 1, 0, 0); FillVector3D(bottomDV, 0, -1, 0); } } normalDirection = 2; break; case Frontal: if(frontside) { if(rotated==false) { FillVector3D(origin, 0, zPosition, 0); FillVector3D(rightDV, 1, 0, 0); FillVector3D(bottomDV, 0, 0, 1); } else { FillVector3D(origin, width, zPosition, height); FillVector3D(rightDV, -1, 0, 0); FillVector3D(bottomDV, 0, 0, -1); } } else { if(rotated==false) { FillVector3D(origin, width, zPosition, 0); FillVector3D(rightDV, -1, 0, 0); FillVector3D(bottomDV, 0, 0, 1); } else { FillVector3D(origin, 0, zPosition, height); FillVector3D(rightDV, 1, 0, 0); FillVector3D(bottomDV, 0, 0, -1); } } normalDirection = 1; break; case Sagittal: if(frontside) { if(rotated==false) { FillVector3D(origin, zPosition, 0, 0); FillVector3D(rightDV, 0, 1, 0); FillVector3D(bottomDV, 0, 0, 1); } else { FillVector3D(origin, zPosition, width, height); FillVector3D(rightDV, 0, -1, 0); FillVector3D(bottomDV, 0, 0, -1); } } else { if(rotated==false) { FillVector3D(origin, zPosition, width, 0); FillVector3D(rightDV, 0, -1, 0); FillVector3D(bottomDV, 0, 0, 1); } else { FillVector3D(origin, zPosition, 0, height); FillVector3D(rightDV, 0, 1, 0); FillVector3D(bottomDV, 0, 0, -1); } } normalDirection = 0; break; default: itkExceptionMacro("unknown PlaneOrientation"); } if ( transform != NULL ) { origin = transform->TransformPoint( origin ); rightDV = transform->TransformVector( rightDV ); bottomDV = transform->TransformVector( bottomDV ); } ScalarType bounds[6]= { 0, width, 0, height, 0, 1 }; this->SetBounds( bounds ); if ( transform == NULL ) { this->SetMatrixByVectors( rightDV, bottomDV ); } else { this->SetMatrixByVectors( rightDV, bottomDV, transform->GetMatrix().GetVnlMatrix() .get_column(normalDirection).magnitude() ); } this->SetOrigin(origin); } void PlaneGeometry::InitializeStandardPlane( const Geometry3D *geometry3D, PlaneOrientation planeorientation, ScalarType zPosition, bool frontside, bool rotated ) { this->SetReferenceGeometry( const_cast< Geometry3D * >( geometry3D ) ); ScalarType width, height; const BoundingBox::BoundsArrayType& boundsarray = geometry3D->GetBoundingBox()->GetBounds(); Vector3D originVector; FillVector3D(originVector, boundsarray[0], boundsarray[2], boundsarray[4]); if(geometry3D->GetImageGeometry()) { FillVector3D( originVector, originVector[0] - 0.5, originVector[1] - 0.5, originVector[2] - 0.5 ); } switch(planeorientation) { case Transversal: width = geometry3D->GetExtent(0); height = geometry3D->GetExtent(1); break; case Frontal: width = geometry3D->GetExtent(0); height = geometry3D->GetExtent(2); break; case Sagittal: width = geometry3D->GetExtent(1); height = geometry3D->GetExtent(2); break; default: itkExceptionMacro("unknown PlaneOrientation"); } InitializeStandardPlane( width, height, geometry3D->GetIndexToWorldTransform(), planeorientation, zPosition, frontside, rotated ); ScalarType bounds[6]= { 0, width, 0, height, 0, 1 }; this->SetBounds( bounds ); Point3D origin; originVector = geometry3D->GetIndexToWorldTransform() ->TransformVector( originVector ); origin = GetOrigin() + originVector; SetOrigin(origin); } void PlaneGeometry::InitializeStandardPlane( const Geometry3D *geometry3D, bool top, PlaneOrientation planeorientation, bool frontside, bool rotated ) { ScalarType zPosition; switch(planeorientation) { case Transversal: zPosition = (top ? 0.5 : geometry3D->GetExtent(2)-1+0.5); break; case Frontal: zPosition = (top ? 0.5 : geometry3D->GetExtent(1)-1+0.5); break; case Sagittal: zPosition = (top ? 0.5 : geometry3D->GetExtent(0)-1+0.5); break; default: itkExceptionMacro("unknown PlaneOrientation"); } InitializeStandardPlane( geometry3D, planeorientation, zPosition, frontside, rotated ); } void PlaneGeometry::InitializeStandardPlane( const Vector3D &rightVector, const Vector3D &downVector, const Vector3D *spacing ) { InitializeStandardPlane( rightVector.Get_vnl_vector(), downVector.Get_vnl_vector(), spacing ); } void PlaneGeometry::InitializeStandardPlane( const VnlVector& rightVector, const VnlVector &downVector, const Vector3D *spacing ) { ScalarType width = rightVector.magnitude(); ScalarType height = downVector.magnitude(); InitializeStandardPlane( width, height, rightVector, downVector, spacing ); } void PlaneGeometry::InitializeStandardPlane( mitk::ScalarType width, ScalarType height, const Vector3D &rightVector, const Vector3D &downVector, const Vector3D *spacing ) { InitializeStandardPlane( width, height, rightVector.Get_vnl_vector(), downVector.Get_vnl_vector(), spacing ); } void PlaneGeometry::InitializeStandardPlane( mitk::ScalarType width, ScalarType height, const VnlVector &rightVector, const VnlVector &downVector, const Vector3D *spacing ) { assert(width > 0); assert(height > 0); VnlVector rightDV = rightVector; rightDV.normalize(); VnlVector downDV = downVector; downDV.normalize(); VnlVector normal = vnl_cross_3d(rightVector, downVector); normal.normalize(); if(spacing!=NULL) { rightDV *= (*spacing)[0]; downDV *= (*spacing)[1]; normal *= (*spacing)[2]; } AffineTransform3D::Pointer transform = AffineTransform3D::New(); Matrix3D matrix; matrix.GetVnlMatrix().set_column(0, rightDV); matrix.GetVnlMatrix().set_column(1, downDV); matrix.GetVnlMatrix().set_column(2, normal); transform->SetMatrix(matrix); transform->SetOffset(m_IndexToWorldTransform->GetOffset()); ScalarType bounds[6] = { 0, width, 0, height, 0, 1 }; this->SetBounds( bounds ); this->SetIndexToWorldTransform( transform ); } void PlaneGeometry::InitializePlane( const Point3D &origin, const Vector3D &normal ) { VnlVector rightVectorVnl(3), downVectorVnl; if( Equal( normal[1], 0.0f ) == false ) { FillVector3D( rightVectorVnl, 1.0f, -normal[0]/normal[1], 0.0f ); rightVectorVnl.normalize(); } else { FillVector3D( rightVectorVnl, 0.0f, 1.0f, 0.0f ); } downVectorVnl = vnl_cross_3d( normal.Get_vnl_vector(), rightVectorVnl ); downVectorVnl.normalize(); InitializeStandardPlane( rightVectorVnl, downVectorVnl ); SetOrigin(origin); } void PlaneGeometry::SetMatrixByVectors( const VnlVector &rightVector, const VnlVector &downVector, ScalarType thickness ) { VnlVector normal = vnl_cross_3d(rightVector, downVector); normal.normalize(); normal *= thickness; AffineTransform3D::Pointer transform = AffineTransform3D::New(); Matrix3D matrix; matrix.GetVnlMatrix().set_column(0, rightVector); matrix.GetVnlMatrix().set_column(1, downVector); matrix.GetVnlMatrix().set_column(2, normal); transform->SetMatrix(matrix); transform->SetOffset(m_IndexToWorldTransform->GetOffset()); SetIndexToWorldTransform(transform); } Vector3D PlaneGeometry::GetNormal() const { Vector3D frontToBack; frontToBack.Set_vnl_vector( m_IndexToWorldTransform ->GetMatrix().GetVnlMatrix().get_column(2) ); return frontToBack; } VnlVector PlaneGeometry::GetNormalVnl() const { return m_IndexToWorldTransform ->GetMatrix().GetVnlMatrix().get_column(2); } ScalarType PlaneGeometry::DistanceFromPlane( const Point3D &pt3d_mm ) const { return fabs(SignedDistance( pt3d_mm )); } ScalarType PlaneGeometry::SignedDistance( const Point3D &pt3d_mm ) const { return SignedDistanceFromPlane(pt3d_mm); } bool PlaneGeometry::IsAbove( const Point3D &pt3d_mm ) const { return SignedDistanceFromPlane(pt3d_mm) > 0; } bool PlaneGeometry::IntersectionLine( const PlaneGeometry* plane, Line3D& crossline ) const { Vector3D normal = this->GetNormal(); normal.Normalize(); Vector3D planeNormal = plane->GetNormal(); planeNormal.Normalize(); Vector3D direction = itk::CrossProduct( normal, planeNormal ); if ( direction.GetSquaredNorm() < eps ) return false; crossline.SetDirection( direction ); double N1dN2 = normal * planeNormal; double determinant = 1.0 - N1dN2 * N1dN2; Vector3D origin = this->GetOrigin().GetVectorFromOrigin(); Vector3D planeOrigin = plane->GetOrigin().GetVectorFromOrigin(); double d1 = normal * origin; double d2 = planeNormal * planeOrigin; double c1 = ( d1 - d2 * N1dN2 ) / determinant; double c2 = ( d2 - d1 * N1dN2 ) / determinant; Vector3D p = normal * c1 + planeNormal * c2; crossline.GetPoint().Get_vnl_vector() = p.Get_vnl_vector(); return true; } unsigned int PlaneGeometry::IntersectWithPlane2D( const PlaneGeometry* plane, Point2D& lineFrom, Point2D &lineTo ) const { Line3D crossline; if ( this->IntersectionLine( plane, crossline ) == false ) return 0; Point2D point2; Vector2D direction2; this->Map( crossline.GetPoint(), point2 ); this->Map( crossline.GetPoint(), crossline.GetDirection(), direction2 ); return Line3D::RectangleLineIntersection( 0, 0, GetExtentInMM(0), GetExtentInMM(1), point2, direction2, lineFrom, lineTo ); } double PlaneGeometry::Angle( const PlaneGeometry *plane ) const { return angle(plane->GetMatrixColumn(2), GetMatrixColumn(2)); } double PlaneGeometry::Angle( const Line3D &line ) const { return vnl_math::pi_over_2 - angle( line.GetDirection().Get_vnl_vector(), GetMatrixColumn(2) ); } bool PlaneGeometry::IntersectionPoint( const Line3D &line, Point3D &intersectionPoint ) const { Vector3D planeNormal = this->GetNormal(); planeNormal.Normalize(); Vector3D lineDirection = line.GetDirection(); lineDirection.Normalize(); double t = planeNormal * lineDirection; if ( fabs( t ) < eps ) { return false; } Vector3D diff; diff = this->GetOrigin() - line.GetPoint(); t = ( planeNormal * diff ) / t; intersectionPoint = line.GetPoint() + lineDirection * t; return true; } bool PlaneGeometry::IntersectionPointParam( const Line3D &line, double &t ) const { Vector3D planeNormal = this->GetNormal(); planeNormal.Normalize(); Vector3D lineDirection = line.GetDirection(); lineDirection.Normalize(); t = planeNormal * lineDirection; if ( fabs( t ) < eps ) { return false; } Vector3D diff; diff = this->GetOrigin() - line.GetPoint(); t = ( planeNormal * diff ) / t; return true; } bool PlaneGeometry::IsParallel( const PlaneGeometry *plane ) const { return ( (Angle(plane) < 10.0 * mitk::sqrteps ) || ( Angle(plane) > ( vnl_math::pi - 10.0 * sqrteps ) ) ) ; } bool PlaneGeometry::IsOnPlane( const Point3D &point ) const { return Distance(point) < eps; } bool PlaneGeometry::IsOnPlane( const Line3D &line ) const { return ( (Distance( line.GetPoint() ) < eps) && (Distance( line.GetPoint2() ) < eps) ); } bool PlaneGeometry::IsOnPlane( const PlaneGeometry *plane ) const { return ( IsParallel( plane ) && (Distance( plane->GetOrigin() ) < eps) ); } Point3D PlaneGeometry::ProjectPointOntoPlane( const Point3D& pt ) const { ScalarType len = this->GetNormalVnl().two_norm(); return pt - this->GetNormal() * this->SignedDistanceFromPlane( pt ) / len; } AffineGeometryFrame3D::Pointer PlaneGeometry::Clone() const { - Self::Pointer newGeometry = Self::New(); - newGeometry->Initialize(); - InitializeGeometry(newGeometry); + Self::Pointer newGeometry = new PlaneGeometry(*this); + newGeometry->UnRegister(); return newGeometry.GetPointer(); } - void PlaneGeometry::ExecuteOperation( Operation *operation ) { vtkTransform *transform = vtkTransform::New(); transform->SetMatrix( m_VtkMatrix ); switch ( operation->GetOperationType() ) { case OpORIENT: { mitk::PlaneOperation *planeOp = dynamic_cast< mitk::PlaneOperation * >( operation ); if ( planeOp == NULL ) { return; } Point3D center = planeOp->GetPoint(); Vector3D orientationVector = planeOp->GetNormal(); Vector3D defaultVector; FillVector3D( defaultVector, 0.0, 0.0, 1.0 ); Vector3D rotationAxis = itk::CrossProduct( orientationVector, defaultVector ); //vtkFloatingPointType rotationAngle = acos( orientationVector[2] / orientationVector.GetNorm() ); vtkFloatingPointType rotationAngle = atan2( (double) rotationAxis.GetNorm(), (double) (orientationVector * defaultVector) ); rotationAngle *= 180.0 / vnl_math::pi; transform->PostMultiply(); transform->Identity(); transform->Translate( center[0], center[1], center[2] ); transform->RotateWXYZ( rotationAngle, rotationAxis[0], rotationAxis[1], rotationAxis[2] ); transform->Translate( -center[0], -center[1], -center[2] ); break; } default: Superclass::ExecuteOperation( operation ); transform->Delete(); return; } m_VtkMatrix->DeepCopy(transform->GetMatrix()); this->TransferVtkToItkTransform(); this->Modified(); transform->Delete(); } - -void PlaneGeometry::InitializeGeometry( Self *newGeometry ) const -{ - Superclass::InitializeGeometry(newGeometry); -} - - void PlaneGeometry::PrintSelf( std::ostream& os, itk::Indent indent ) const { Superclass::PrintSelf(os,indent); os << indent << " Normal: " << GetNormal() << std::endl; } } // namespace diff --git a/Core/Code/DataManagement/mitkPlaneGeometry.h b/Core/Code/DataManagement/mitkPlaneGeometry.h index 8705674338..ba64a4d029 100644 --- a/Core/Code/DataManagement/mitkPlaneGeometry.h +++ b/Core/Code/DataManagement/mitkPlaneGeometry.h @@ -1,424 +1,422 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef PLANEGEOMETRY_H_HEADER_INCLUDED_C1C68A2C #define PLANEGEOMETRY_H_HEADER_INCLUDED_C1C68A2C #include "mitkCommon.h" #include "mitkGeometry2D.h" #include namespace mitk { template < class TCoordRep, unsigned int NPointDimension > class Line; typedef Line Line3D; /** * \brief Describes a two-dimensional, rectangular plane * * \ingroup Geometry */ class MITK_CORE_EXPORT PlaneGeometry : public Geometry2D { public: mitkClassMacro(PlaneGeometry,Geometry2D); /** Method for creation through the object factory. */ itkNewMacro(Self); enum PlaneOrientation { Transversal, Sagittal, Frontal }; virtual void IndexToWorld(const Point2D &pt_units, Point2D &pt_mm) const; virtual void WorldToIndex(const Point2D &pt_mm, Point2D &pt_units) const; //##Documentation //## @brief Convert (continuous or discrete) index coordinates of a \em vector //## \a vec_units to world coordinates (in mm) //## @deprecated First parameter (Point2D) is not used. If possible, please use void IndexToWorld(const mitk::Vector2D& vec_units, mitk::Vector2D& vec_mm) const. //## For further information about coordinates types, please see the Geometry documentation virtual void IndexToWorld(const mitk::Point2D &atPt2d_untis, const mitk::Vector2D &vec_units, mitk::Vector2D &vec_mm) const; //##Documentation //## @brief Convert (continuous or discrete) index coordinates of a \em vector //## \a vec_units to world coordinates (in mm) //## For further information about coordinates types, please see the Geometry documentation virtual void IndexToWorld(const mitk::Vector2D &vec_units, mitk::Vector2D &vec_mm) const; //##Documentation //## @brief Convert world coordinates (in mm) of a \em vector //## \a vec_mm to (continuous!) index coordinates. //## @deprecated First parameter (Point2D) is not used. If possible, please use void WorldToIndex(const mitk::Vector2D& vec_mm, mitk::Vector2D& vec_units) const. //## For further information about coordinates types, please see the Geometry documentation virtual void WorldToIndex(const mitk::Point2D &atPt2d_mm, const mitk::Vector2D &vec_mm, mitk::Vector2D &vec_units) const; //##Documentation //## @brief Convert world coordinates (in mm) of a \em vector //## \a vec_mm to (continuous!) index coordinates. //## For further information about coordinates types, please see the Geometry documentation virtual void WorldToIndex(const mitk::Vector2D &vec_mm, mitk::Vector2D &vec_units) const; virtual void Initialize(); /** * \brief Initialize a plane with orientation \a planeorientation * (default: transversal) with respect to \a geometry3D (default: identity). * Spacing also taken from \a geometry3D. * * \warning A former version of this method created a geometry with unit * spacing. For unit spacing use * * \code * // for in-plane unit spacing: * thisgeometry->SetSizeInUnits(thisgeometry->GetExtentInMM(0), * thisgeometry->GetExtentInMM(1)); * // additionally, for unit spacing in normal direction (former version * // did not do this): * thisgeometry->SetExtentInMM(2, 1.0); * \endcode */ virtual void InitializeStandardPlane( const Geometry3D* geometry3D, PlaneOrientation planeorientation = Transversal, ScalarType zPosition = 0, bool frontside=true, bool rotated=false ); /** * \brief Initialize a plane with orientation \a planeorientation * (default: transversal) with respect to \a geometry3D (default: identity). * Spacing also taken from \a geometry3D. * * \param top if \a true, create plane at top, otherwise at bottom * (for PlaneOrientation Transversal, for other plane locations respectively) */ virtual void InitializeStandardPlane( const Geometry3D* geometry3D, bool top, PlaneOrientation planeorientation = Transversal, bool frontside=true, bool rotated=false ); /** * \brief Initialize a plane with orientation \a planeorientation * (default: transversal) with respect to \a transform (default: identity) * given width and height in units. * */ virtual void InitializeStandardPlane( ScalarType width, ScalarType height, const AffineTransform3D* transform = NULL, PlaneOrientation planeorientation = Transversal, ScalarType zPosition = 0, bool frontside=true, bool rotated=false ); /** * \brief Initialize plane with orientation \a planeorientation * (default: transversal) given width, height and spacing. * */ virtual void InitializeStandardPlane( ScalarType width, ScalarType height, const Vector3D & spacing, PlaneOrientation planeorientation = Transversal, ScalarType zPosition = 0, bool frontside = true, bool rotated = false ); /** * \brief Initialize plane by width and height in pixels, right-/down-vector * (itk) to describe orientation in world-space (vectors will be normalized) * and spacing (default: 1.0 mm in all directions). * * The vectors are normalized and multiplied by the respective spacing before * they are set in the matrix. */ virtual void InitializeStandardPlane( ScalarType width, ScalarType height, const Vector3D& rightVector, const Vector3D& downVector, const Vector3D *spacing = NULL ); /** * \brief Initialize plane by width and height in pixels, * right-/down-vector (vnl) to describe orientation in world-space (vectors * will be normalized) and spacing (default: 1.0 mm in all directions). * * The vectors are normalized and multiplied by the respective spacing * before they are set in the matrix. */ virtual void InitializeStandardPlane( ScalarType width, ScalarType height, const VnlVector& rightVector, const VnlVector& downVector, const Vector3D * spacing = NULL ); /** * \brief Initialize plane by right-/down-vector (itk) and spacing * (default: 1.0 mm in all directions). * * The length of the right-/-down-vector is used as width/height in units, * respectively. Then, the vectors are normalized and multiplied by the * respective spacing before they are set in the matrix. */ virtual void InitializeStandardPlane( const Vector3D& rightVector, const Vector3D& downVector, const Vector3D * spacing = NULL ); /** * \brief Initialize plane by right-/down-vector (vnl) and spacing * (default: 1.0 mm in all directions). * * The length of the right-/-down-vector is used as width/height in units, * respectively. Then, the vectors are normalized and multiplied by the * respective spacing before they are set in the matrix. */ virtual void InitializeStandardPlane( const VnlVector& rightVector, const VnlVector& downVector, const Vector3D * spacing = NULL ); /** * \brief Initialize plane by origin and normal (size is 1.0 mm in * all directions, direction of right-/down-vector valid but * undefined). * */ virtual void InitializePlane( const Point3D& origin, const Vector3D& normal); /** * \brief Initialize plane by right-/down-vector. * * \warning The vectors are set into the matrix as they are, * \em without normalization! */ void SetMatrixByVectors( const VnlVector& rightVector, const VnlVector& downVector, ScalarType thickness=1.0 ); /** * \brief Change \a transform so that the third column of the * transform-martix is perpendicular to the first two columns * */ static void EnsurePerpendicularNormal( AffineTransform3D* transform ); /** * \brief Normal of the plane * */ Vector3D GetNormal() const; /** * \brief Normal of the plane as VnlVector * */ VnlVector GetNormalVnl() const; virtual ScalarType SignedDistance( const Point3D& pt3d_mm ) const; virtual bool IsAbove( const Point3D& pt3d_mm ) const; /** * \brief Distance of the point from the plane * (bounding-box \em not considered) * */ ScalarType DistanceFromPlane( const Point3D& pt3d_mm ) const ; /** * \brief Signed distance of the point from the plane * (bounding-box \em not considered) * * > 0 : point is in the direction of the direction vector. */ inline ScalarType SignedDistanceFromPlane( const Point3D& pt3d_mm ) const { ScalarType len = GetNormalVnl().two_norm(); if( len == 0 ) return 0; return (pt3d_mm-GetOrigin())*GetNormal() / len; } /** * \brief Distance of the plane from another plane * (bounding-box \em not considered) * * Result is 0 if planes are not parallel. */ ScalarType DistanceFromPlane(const PlaneGeometry* plane) const { return fabs(SignedDistanceFromPlane(plane)); } /** * \brief Signed distance of the plane from another plane * (bounding-box \em not considered) * * Result is 0 if planes are not parallel. */ inline ScalarType SignedDistanceFromPlane( const PlaneGeometry *plane ) const { if(IsParallel(plane)) { return SignedDistance(plane->GetOrigin()); } return 0; } /** * \brief Calculate the intersecting line of two planes * * \return \a true planes are intersecting * \return \a false planes do not intersect */ bool IntersectionLine( const PlaneGeometry *plane, Line3D &crossline ) const; /** * \brief Calculate two points where another plane intersects the border of this plane * * \return number of intersection points (0..2). First interection point (if existing) * is returned in \a lineFrom, second in \a lineTo. */ unsigned int IntersectWithPlane2D(const PlaneGeometry *plane, Point2D &lineFrom, Point2D &lineTo ) const ; /** * \brief Calculate the angle between two planes * * \return angle in radiants */ double Angle( const PlaneGeometry *plane ) const; /** * \brief Calculate the angle between the plane and a line * * \return angle in radiants */ double Angle( const Line3D &line ) const; /** * \brief Calculate intersection point between the plane and a line * * \param intersectionPoint intersection point * \return \a true if \em unique intersection exists, i.e., if line * is \em not on or parallel to the plane */ bool IntersectionPoint( const Line3D &line, Point3D &intersectionPoint ) const; /** * \brief Calculate line parameter of intersection point between the * plane and a line * * \param t parameter of line: intersection point is * line.GetPoint()+t*line.GetDirection() * \return \a true if \em unique intersection exists, i.e., if line * is \em not on or parallel to the plane */ bool IntersectionPointParam( const Line3D &line, double &t ) const; /** * \brief Returns whether the plane is parallel to another plane * * @return true iff the normal vectors both point to the same or exactly oposit direction */ bool IsParallel( const PlaneGeometry *plane ) const; /** * \brief Returns whether the point is on the plane * (bounding-box \em not considered) */ bool IsOnPlane( const Point3D &point ) const; /** * \brief Returns whether the line is on the plane * (bounding-box \em not considered) */ bool IsOnPlane( const Line3D &line ) const; /** * \brief Returns whether the plane is on the plane * (bounding-box \em not considered) * * @return true iff the normal vector of the planes point to the same or the exactly oposit direction and * the distance of the planes is < eps * */ bool IsOnPlane( const PlaneGeometry *plane ) const; /** * \brief Returns the lot from the point to the plane */ Point3D ProjectPointOntoPlane( const Point3D &pt ) const; virtual void SetIndexToWorldTransform( AffineTransform3D *transform); virtual void SetBounds( const BoundingBox::BoundsArrayType &bounds ); AffineGeometryFrame3D::Pointer Clone() const; /** Implements operation to re-orient the plane */ virtual void ExecuteOperation( Operation *operation ); protected: PlaneGeometry(); virtual ~PlaneGeometry(); - virtual void InitializeGeometry( Self *newGeometry ) const; - virtual void PrintSelf( std::ostream &os, itk::Indent indent ) const; private: /** * \brief Compares plane with another plane: \a true if IsOnPlane * (bounding-box \em not considered) */ virtual bool operator==( const PlaneGeometry * ) const { return false; }; /** * \brief Compares plane with another plane: \a false if IsOnPlane * (bounding-box \em not considered) */ virtual bool operator!=( const PlaneGeometry * ) const { return false; }; }; } // namespace mitk #endif /* PLANEGEOMETRY_H_HEADER_INCLUDED_C1C68A2C */ diff --git a/Core/Code/DataManagement/mitkPlaneOrientationProperty.h b/Core/Code/DataManagement/mitkPlaneOrientationProperty.h index a268d2bd69..b8d88db95c 100644 --- a/Core/Code/DataManagement/mitkPlaneOrientationProperty.h +++ b/Core/Code/DataManagement/mitkPlaneOrientationProperty.h @@ -1,113 +1,115 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date: 2008-04-14 19:45:53 +0200 (Mo, 14 Apr 2008) $ Version: $Revision: 14081 $ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef MITK_PLANE_DECORATION_PROPERTY__H #define MITK_PLANE_DECORATION_PROPERTY__H #include "mitkEnumerationProperty.h" namespace mitk { /** * Property which controls whether 2D line representation of a PlaneGeometry * should have small arrows at both ends to indicate the orientation of * the plane, and whether the arrows should be oriented in the direction of * the plane's normal or against it. * * Valid values of the enumeration property are * - PLANE_DECORATION_NONE (no arrows) * - PLANE_DECORATION_POSITIVE_ORIENTATION (arrows pointing upwards) * - PLANE_DECORATION_NEGATIVE_ORIENTATION (arrows pointing downwards) * * See also mitk::Geometry2DDataMapper2D::DrawOrientationArrow() */ class MITK_CORE_EXPORT PlaneOrientationProperty : public EnumerationProperty { public: mitkClassMacro( PlaneOrientationProperty, EnumerationProperty ); itkNewMacro(PlaneOrientationProperty); mitkNewMacro1Param(PlaneOrientationProperty, const IdType&); mitkNewMacro1Param(PlaneOrientationProperty, const std::string&); + virtual BaseProperty& operator=(const BaseProperty& other) { return Superclass::operator=(other); } + enum { PLANE_DECORATION_NONE, PLANE_DECORATION_POSITIVE_ORIENTATION, PLANE_DECORATION_NEGATIVE_ORIENTATION }; /** * Returns the state of plane decoration. */ virtual int GetPlaneDecoration(); /** * Sets the decoration type to no decoration. */ virtual void SetPlaneDecorationToNone(); /** * Sets the decoration type to arrows in positive plane direction. */ virtual void SetPlaneDecorationToPositiveOrientation(); /** * Sets the decoration type to arrows in negative plane direction. */ virtual void SetPlaneDecorationToNegativeOrientation(); protected: /** * Constructor. Sets the decoration type to none. */ PlaneOrientationProperty( ); /** * Constructor. Sets the decoration type to the given value. If it is not * valid, the interpolation is set to none */ PlaneOrientationProperty( const IdType &value ); /** * Constructor. Sets the decoration type to the given value. If it is not * valid, the representation is set to none */ PlaneOrientationProperty( const std::string &value ); /** * this function is overridden as protected, so that the user may not add * additional invalid types. */ virtual bool AddEnum( const std::string &name, const IdType &id ); /** * Adds the standard enumeration types with corresponding strings. */ virtual void AddDecorationTypes(); }; } // end of namespace mitk #endif diff --git a/Core/Code/DataManagement/mitkPointSet.cpp b/Core/Code/DataManagement/mitkPointSet.cpp index bc3db0ef93..1e74465ea7 100755 --- a/Core/Code/DataManagement/mitkPointSet.cpp +++ b/Core/Code/DataManagement/mitkPointSet.cpp @@ -1,776 +1,776 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "mitkPointSet.h" #include "mitkPointOperation.h" #include "mitkInteractionConst.h" #include mitk::PointSet::PointSet() { this->InitializeEmpty(); } mitk::PointSet::~PointSet() { this->ClearData(); } void mitk::PointSet::ClearData() { m_PointSetSeries.clear(); Superclass::ClearData(); } void mitk::PointSet::InitializeEmpty() { m_PointSetSeries.resize( 1 ); m_PointSetSeries[0] = DataType::New(); PointDataContainer::Pointer pointData = PointDataContainer::New(); m_PointSetSeries[0]->SetPointData( pointData ); m_CalculateBoundingBox = false; Superclass::InitializeTimeSlicedGeometry(1); m_Initialized = true; } -bool mitk::PointSet::IsEmpty(unsigned int t) const +bool mitk::PointSet::IsEmptyTimeStep(unsigned int t) const { return IsInitialized() && (GetSize(t) == 0); } void mitk::PointSet::Expand( unsigned int timeSteps ) { // Check if the vector is long enough to contain the new element // at the given position. If not, expand it with sufficient pre-initialized // elements. // // NOTE: This method will never REDUCE the vector size; it should only // be used to make sure that the vector has enough elements to include the // specified time step. unsigned int oldSize = m_PointSetSeries.size(); if ( timeSteps > oldSize ) { Superclass::Expand( timeSteps ); m_PointSetSeries.resize( timeSteps ); for ( unsigned int i = oldSize; i < timeSteps; ++i ) { m_PointSetSeries[i] = DataType::New(); PointDataContainer::Pointer pointData = PointDataContainer::New(); m_PointSetSeries[i]->SetPointData( pointData ); } //if the size changes, then compute the bounding box m_CalculateBoundingBox = true; this->InvokeEvent( PointSetExtendTimeRangeEvent() ); } } unsigned int mitk::PointSet::GetPointSetSeriesSize() const { return m_PointSetSeries.size(); } int mitk::PointSet::GetSize( unsigned int t ) const { if ( t < m_PointSetSeries.size() ) { return m_PointSetSeries[t]->GetNumberOfPoints(); } else { return 0; } } mitk::PointSet::DataType::Pointer mitk::PointSet::GetPointSet( int t ) const { if ( t < (int)m_PointSetSeries.size() ) { return m_PointSetSeries[t]; } else { return NULL; } } int mitk::PointSet::SearchPoint( Point3D point, float distance, int t ) const { if ( t >= (int)m_PointSetSeries.size() ) { return -1; } // Out is the point which is checked to be the searched point PointType out; out.Fill( 0 ); PointType indexPoint; this->GetGeometry( t )->WorldToIndex(point, indexPoint); // Searching the first point in the Set, that is +- distance far away fro // the given point unsigned int i; PointsContainer::Iterator it, end; end = m_PointSetSeries[t]->GetPoints()->End(); int bestIndex = -1; distance = distance * distance; // To correct errors from converting index to world and world to index if (distance == 0.0) { distance = 0.000001; } ScalarType bestDist = distance; ScalarType dist, tmp; for ( it = m_PointSetSeries[t]->GetPoints()->Begin(), i = 0; it != end; ++it, ++i ) { bool ok = m_PointSetSeries[t]->GetPoints() ->GetElementIfIndexExists( it->Index(), &out ); if ( !ok ) { return -1; } else if ( indexPoint == out ) //if totally equal { return it->Index(); } //distance calculation tmp = out[0] - indexPoint[0]; dist = tmp * tmp; tmp = out[1] - indexPoint[1]; dist += tmp * tmp; tmp = out[2] - indexPoint[2]; dist += tmp * tmp; if ( dist < bestDist ) { bestIndex = it->Index(); bestDist = dist; } } return bestIndex; } mitk::PointSet::PointType mitk::PointSet::GetPoint( PointIdentifier id, int t ) const { PointType out; out.Fill(0); if ( (unsigned int) t >= m_PointSetSeries.size() ) { return out; } if ( m_PointSetSeries[t]->GetPoints()->IndexExists(id) ) { m_PointSetSeries[t]->GetPoint( id, &out ); this->GetGeometry(t)->IndexToWorld( out, out ); return out; } else { return out; } } bool mitk::PointSet ::GetPointIfExists( PointIdentifier id, PointType* point, int t ) const { if ( (unsigned int) t >= m_PointSetSeries.size() ) { return false; } if ( m_PointSetSeries[t]->GetPoints()->GetElementIfIndexExists(id, point) ) { this->GetGeometry( t )->IndexToWorld( *point, *point ); return true; } else { return false; } } void mitk::PointSet::SetPoint( PointIdentifier id, PointType point, int t ) { // Adapt the size of the data vector if necessary this->Expand( t+1 ); mitk::Point3D indexPoint; this->GetGeometry( t )->WorldToIndex( point, indexPoint ); m_PointSetSeries[t]->SetPoint( id, indexPoint ); PointDataType defaultPointData; defaultPointData.id = id; defaultPointData.selected = false; defaultPointData.pointSpec = mitk::PTUNDEFINED; m_PointSetSeries[t]->SetPointData( id, defaultPointData ); //boundingbox has to be computed anyway m_CalculateBoundingBox = true; this->Modified(); } void mitk::PointSet::SetPoint( PointIdentifier id, PointType point, PointSpecificationType spec, int t ) { // Adapt the size of the data vector if necessary this->Expand( t+1 ); mitk::Point3D indexPoint; this->GetGeometry( t )->WorldToIndex( point, indexPoint ); m_PointSetSeries[t]->SetPoint( id, indexPoint ); PointDataType defaultPointData; defaultPointData.id = id; defaultPointData.selected = false; defaultPointData.pointSpec = spec; m_PointSetSeries[t]->SetPointData( id, defaultPointData ); //boundingbox has to be computed anyway m_CalculateBoundingBox = true; this->Modified(); } void mitk::PointSet::InsertPoint( PointIdentifier id, PointType point, int t ) { if ( (unsigned int) t < m_PointSetSeries.size() ) { mitk::Point3D indexPoint; mitk::Geometry3D* tempGeometry = this->GetGeometry( t ); if (tempGeometry == NULL) { MITK_INFO<< __FILE__ << ", l." << __LINE__ << ": GetGeometry of "<< t <<" returned NULL!" << std::endl; return; } tempGeometry->WorldToIndex( point, indexPoint ); m_PointSetSeries[t]->GetPoints()->InsertElement( id, indexPoint ); PointDataType defaultPointData; defaultPointData.id = id; defaultPointData.selected = false; defaultPointData.pointSpec = mitk::PTUNDEFINED; m_PointSetSeries[t]->GetPointData()->InsertElement(id, defaultPointData); //boundingbox has to be computed anyway m_CalculateBoundingBox = true; this->Modified(); } } void mitk::PointSet::InsertPoint( PointIdentifier id, PointType point, PointSpecificationType spec, int t ) { if ( (unsigned int) t < m_PointSetSeries.size() ) { mitk::Point3D indexPoint; mitk::Geometry3D* tempGeometry = this->GetGeometry( t ); if (tempGeometry == NULL) { MITK_INFO<< __FILE__ << ", l." << __LINE__ << ": GetGeometry of "<< t <<" returned NULL!" << std::endl; return; } tempGeometry->WorldToIndex( point, indexPoint ); m_PointSetSeries[t]->GetPoints()->InsertElement( id, indexPoint ); PointDataType defaultPointData; defaultPointData.id = id; defaultPointData.selected = false; defaultPointData.pointSpec = spec; m_PointSetSeries[t]->GetPointData()->InsertElement(id, defaultPointData); //boundingbox has to be computed anyway m_CalculateBoundingBox = true; this->Modified(); } } bool mitk::PointSet::SwapPointPosition( PointIdentifier id, bool moveUpwards, int t ) { if(IndexExists(id, t) ) { PointType point = GetPoint(id,t); if(moveUpwards) {//up if(IndexExists(id-1,t)) { InsertPoint(id, GetPoint(id - 1, t), t); InsertPoint(id-1,point,t); this->Modified(); return true; } } else {//down if(IndexExists(id+1,t)) { InsertPoint(id, GetPoint(id + 1, t), t); InsertPoint(id+1,point,t); this->Modified(); return true; } } } return false; } bool mitk::PointSet::IndexExists( int position, int t ) const { if ( (unsigned int) t < m_PointSetSeries.size() ) { return m_PointSetSeries[t]->GetPoints()->IndexExists( position ); } else { return false; } } bool mitk::PointSet::GetSelectInfo( int position, int t ) const { if ( this->IndexExists( position, t ) ) { PointDataType pointData = { 0, false, PTUNDEFINED }; m_PointSetSeries[t]->GetPointData( position, &pointData ); return pointData.selected; } else { return false; } } void mitk::PointSet::SetSelectInfo( int position, bool selected, int t ) { if ( this->IndexExists( position, t ) ) { // timeStep to ms ScalarType timeInMS = this->GetTimeSlicedGeometry()->TimeStepToMS( t ); // point Point3D point = this->GetPoint( position, t ); PointOperation* op; if (selected) { op = new mitk::PointOperation(OpSELECTPOINT, timeInMS, point, position ); } else { op = new mitk::PointOperation(OpDESELECTPOINT, timeInMS, point, position ); } this->ExecuteOperation( op ); } } mitk::PointSpecificationType mitk::PointSet::GetSpecificationTypeInfo( int position, int t ) const { if ( this->IndexExists( position, t ) ) { PointDataType pointData = { 0, false, PTUNDEFINED }; m_PointSetSeries[t]->GetPointData( position, &pointData ); return pointData.pointSpec; } else { return PTUNDEFINED; } } int mitk::PointSet::GetNumberOfSelected( int t ) const { if ( (unsigned int) t >= m_PointSetSeries.size() ) { return 0; } int numberOfSelected = 0; PointDataIterator it; for ( it = m_PointSetSeries[t]->GetPointData()->Begin(); it != m_PointSetSeries[t]->GetPointData()->End(); it++ ) { if (it->Value().selected == true) { ++numberOfSelected; } } return numberOfSelected; } int mitk::PointSet::SearchSelectedPoint( int t ) const { if ( (unsigned int) t >= m_PointSetSeries.size() ) { return -1; } PointDataIterator it; for ( it = m_PointSetSeries[t]->GetPointData()->Begin(); it != m_PointSetSeries[t]->GetPointData()->End(); it++ ) { if ( it->Value().selected == true ) { return it->Index(); } } return -1; } void mitk::PointSet::ExecuteOperation( Operation* operation ) { int timeStep = -1; mitkCheckOperationTypeMacro(PointOperation, operation, pointOp); if ( pointOp ) { timeStep = this->GetTimeSlicedGeometry() ->MSToTimeStep( pointOp->GetTimeInMS() ); } if ( timeStep < 0 ) { MITK_ERROR << "Time step (" << timeStep << ") outside of PointSet time bounds" << std::endl; return; } switch (operation->GetOperationType()) { case OpNOTHING: break; case OpINSERT://inserts the point at the given position and selects it. { int position = pointOp->GetIndex(); PointType pt; pt.CastFrom(pointOp->GetPoint()); //transfer from world to index coordinates mitk::Geometry3D* geometry = this->GetGeometry( timeStep ); if (geometry == NULL) { MITK_INFO<<"GetGeometry returned NULL!\n"; return; } geometry->WorldToIndex(pt, pt); m_PointSetSeries[timeStep]->GetPoints()->InsertElement(position, pt); PointDataType pointData = { pointOp->GetIndex(), pointOp->GetSelected(), pointOp->GetPointType() }; m_PointSetSeries[timeStep]->GetPointData() ->InsertElement(position, pointData); this->Modified(); //boundingbox has to be computed m_CalculateBoundingBox = true; this->InvokeEvent( PointSetAddEvent() ); this->OnPointSetChange(); } break; case OpMOVE://moves the point given by index { PointType pt; pt.CastFrom(pointOp->GetPoint()); //transfer from world to index coordinates this->GetGeometry( timeStep )->WorldToIndex(pt, pt); // Copy new point into container m_PointSetSeries[timeStep]->SetPoint(pointOp->GetIndex(), pt); // Insert a default point data object to keep the containers in sync // (if no point data object exists yet) PointDataType pointData; if ( !m_PointSetSeries[timeStep]->GetPointData( pointOp->GetIndex(), &pointData ) ) { m_PointSetSeries[timeStep]->SetPointData( pointOp->GetIndex(), pointData ); } this->OnPointSetChange(); this->Modified(); //boundingbox has to be computed anyway m_CalculateBoundingBox = true; this->InvokeEvent( PointSetMoveEvent() ); } break; case OpREMOVE://removes the point at given by position { m_PointSetSeries[timeStep]->GetPoints()->DeleteIndex((unsigned)pointOp->GetIndex()); m_PointSetSeries[timeStep]->GetPointData()->DeleteIndex((unsigned)pointOp->GetIndex()); this->OnPointSetChange(); this->Modified(); //boundingbox has to be computed anyway m_CalculateBoundingBox = true; this->InvokeEvent( PointSetRemoveEvent() ); } break; case OpSELECTPOINT://select the given point { PointDataType pointData = {0, false, PTUNDEFINED}; m_PointSetSeries[timeStep]->GetPointData(pointOp->GetIndex(), &pointData); pointData.selected = true; m_PointSetSeries[timeStep]->SetPointData(pointOp->GetIndex(), pointData); this->Modified(); } break; case OpDESELECTPOINT://unselect the given point { PointDataType pointData = {0, false, PTUNDEFINED}; m_PointSetSeries[timeStep]->GetPointData(pointOp->GetIndex(), &pointData); pointData.selected = false; m_PointSetSeries[timeStep]->SetPointData(pointOp->GetIndex(), pointData); this->Modified(); } break; case OpSETPOINTTYPE: { PointDataType pointData = {0, false, PTUNDEFINED}; m_PointSetSeries[timeStep]->GetPointData(pointOp->GetIndex(), &pointData); pointData.pointSpec = pointOp->GetPointType(); m_PointSetSeries[timeStep]->SetPointData(pointOp->GetIndex(), pointData); this->Modified(); } break; case OpMOVEPOINTUP: // swap content of point with ID pointOp->GetIndex() with the point preceding it in the container // move point position within the pointset { PointIdentifier currentID = pointOp->GetIndex(); /* search for point with this id and point that precedes this one in the data container */ PointsContainer::STLContainerType points = m_PointSetSeries[timeStep]->GetPoints()->CastToSTLContainer(); PointsContainer::STLContainerType::iterator it = points.find(currentID); if (it == points.end()) // ID not found break; if (it == points.begin()) // we are at the first element, there is no previous element break; /* get and cache current point & pointdata and previous point & pointdata */ --it; PointIdentifier prevID = it->first; if (this->SwapPointContents(prevID, currentID, timeStep) == true) this->Modified(); } break; case OpMOVEPOINTDOWN: // move point position within the pointset { PointIdentifier currentID = pointOp->GetIndex(); /* search for point with this id and point that succeeds this one in the data container */ PointsContainer::STLContainerType points = m_PointSetSeries[timeStep]->GetPoints()->CastToSTLContainer(); PointsContainer::STLContainerType::iterator it = points.find(currentID); if (it == points.end()) // ID not found break; ++it; if (it == points.end()) // ID is already the last element, there is no succeeding element break; /* get and cache current point & pointdata and previous point & pointdata */ PointIdentifier nextID = it->first; if (this->SwapPointContents(nextID, currentID, timeStep) == true) this->Modified(); } break; default: itkWarningMacro("mitkPointSet could not understrand the operation. Please check!"); break; } //to tell the mappers, that the data is modified and has to be updated //only call modified if anything is done, so call in cases //this->Modified(); mitk::OperationEndEvent endevent(operation); ((const itk::Object*)this)->InvokeEvent(endevent); //*todo has to be done here, cause of update-pipeline not working yet // As discussed lately, don't mess with the rendering from inside data structures //mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } 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 // mitk::TimeSlicedGeometry* timeGeometry = GetTimeSlicedGeometry(); if ( timeGeometry->GetTimeSteps() != m_PointSetSeries.size() ) { itkExceptionMacro(<<"timeGeometry->GetTimeSteps() != m_PointSetSeries.size() -- use Initialize(timeSteps) with correct number of timeSteps!"); } // This is needed to detect zero objects mitk::ScalarType nullpoint[]={0,0,0,0,0,0}; BoundingBox::BoundsArrayType itkBoundsNull(nullpoint); // // Iterate over the PointSets and update the Geometry // information of each of the items. // if (m_CalculateBoundingBox) { for ( unsigned int i = 0 ; i < m_PointSetSeries.size() ; ++i ) { const DataType::BoundingBoxType *bb = m_PointSetSeries[i]->GetBoundingBox(); BoundingBox::BoundsArrayType itkBounds = bb->GetBounds(); if ( m_PointSetSeries[i].IsNull() || (m_PointSetSeries[i]->GetNumberOfPoints() == 0) || (itkBounds == itkBoundsNull) ) { itkBounds = itkBoundsNull; continue; } // Ensure minimal bounds of 1.0 in each dimension for ( unsigned int j = 0; j < 3; ++j ) { if ( itkBounds[j*2+1] - itkBounds[j*2] < 1.0 ) { BoundingBox::CoordRepType center = (itkBounds[j*2] + itkBounds[j*2+1]) / 2.0; itkBounds[j*2] = center - 0.5; itkBounds[j*2+1] = center + 0.5; } } this->GetGeometry(i)->SetBounds(itkBounds); } m_CalculateBoundingBox = false; } this->GetTimeSlicedGeometry()->UpdateInformation(); } void mitk::PointSet::SetRequestedRegionToLargestPossibleRegion() { } bool mitk::PointSet::RequestedRegionIsOutsideOfTheBufferedRegion() { return false; } bool mitk::PointSet::VerifyRequestedRegion() { return true; } void mitk::PointSet::SetRequestedRegion( itk::DataObject * ) { } void mitk::PointSet::PrintSelf( std::ostream& os, itk::Indent indent ) const { Superclass::PrintSelf(os, indent); os << indent << "Number timesteps: " << m_PointSetSeries.size() << "\n"; unsigned int i = 0; for (PointSetSeries::const_iterator it = m_PointSetSeries.begin(); it != m_PointSetSeries.end(); ++it) { os << indent << "Timestep " << i++ << ": \n"; MeshType::Pointer ps = *it; itk::Indent nextIndent = indent.GetNextIndent(); ps->Print(os, nextIndent); MeshType::PointsContainer* points = ps->GetPoints(); MeshType::PointDataContainer* datas = ps->GetPointData(); MeshType::PointDataContainer::Iterator dataIterator = datas->Begin(); for (MeshType::PointsContainer::Iterator pointIterator = points->Begin(); pointIterator != points->End(); ++pointIterator, ++dataIterator) { os << nextIndent << "Point " << pointIterator->Index() << ": ["; os << pointIterator->Value().GetElement(0); for (unsigned int i = 1; i < PointType::GetPointDimension(); ++i) { os << ", " << pointIterator->Value().GetElement(i); } os << "]"; os << ", selected: " << dataIterator->Value().selected << ", point spec: " << dataIterator->Value().pointSpec << "\n"; } } } bool mitk::PointSet::SwapPointContents(PointIdentifier id1, PointIdentifier id2, int timeStep) { /* search and cache contents */ PointType p1; if (m_PointSetSeries[timeStep]->GetPoint(id1, &p1) == false) return false; PointDataType data1; if (m_PointSetSeries[timeStep]->GetPointData(id1, &data1) == false) return false; PointType p2; if (m_PointSetSeries[timeStep]->GetPoint(id2, &p2) == false) return false; PointDataType data2; if (m_PointSetSeries[timeStep]->GetPointData(id2, &data2) == false) return false; /* now swap contents */ m_PointSetSeries[timeStep]->SetPoint(id1, p2); m_PointSetSeries[timeStep]->SetPointData(id1, data2); m_PointSetSeries[timeStep]->SetPoint(id2, p1); m_PointSetSeries[timeStep]->SetPointData(id2, data1); return true; -} \ No newline at end of file +} diff --git a/Core/Code/DataManagement/mitkPointSet.h b/Core/Code/DataManagement/mitkPointSet.h index 38e13bc8e6..2b701dce27 100755 --- a/Core/Code/DataManagement/mitkPointSet.h +++ b/Core/Code/DataManagement/mitkPointSet.h @@ -1,273 +1,273 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef MITKPointSet_H_HEADER_INCLUDED #define MITKPointSet_H_HEADER_INCLUDED #include "mitkBaseData.h" #include #include namespace mitk { /** * \brief Data structure which stores a set of points. Superclass of * mitk::Mesh. * * 3D points are grouped within a point set; for time resolved usage, one point * set is created and maintained per time step. A point entry consists of the * point coordinates and point data. * * The point data includes a point ID (unique identifier to address this point * within the point set), the selection state of the point and the type of * the point. * * For further information about different point types see * mitk::PointSpecificationType in mitkVector.h. * * Inserting a point is accompanied by an event, containing an index. The new * point is inserted into the list at the specified position. At the same time * an internal ID is generated and stored for the point. Points at specific time * steps are accessed by specifying the time step number (which defaults to 0). * * The points of itk::PointSet stores the points in a pointContainer * (MapContainer). The points are best accessed by using a ConstIterator (as * defined in MapContainer); avoid access via index. * * The class internally uses an itk::Mesh for each time step, because * mitk::Mesh is derived from mitk::PointSet and needs the itk::Mesh structure * which is also derived from itk::PointSet. Thus several typedefs which seem * to be in wrong place, are declared here (for example SelectedLinesType). * * \section mitkPointSetDisplayOptions * * The default mappers for this data structure are mitk::PointSetGLMapper2D and * mitk::PointSetVtkMapper3D. See these classes for display options which can * can be set via properties. * * \section Events * * PointSet issues the following events, for which observers can register * (the below events are grouped into a class hierarchy as indicated by * identation level; e.g. PointSetSizeChangeEvent comprises PointSetAddEvent * and PointSetRemoveEvent): * * * PointSetEvent subsumes all PointSet events * PointSetMoveEvent issued when a point of the PointSet is moved * PointSetSizeChangeEvent subsumes add and remove events * PointSetAddEvent issued when a point is added to the PointSet * PointSetRemoveEvent issued when a point is removed from the PointSet * * \ingroup PSIO * \ingroup Data */ class MITK_CORE_EXPORT PointSet : public BaseData { public: mitkClassMacro(PointSet, BaseData); itkNewMacro(Self); typedef mitk::ScalarType CoordinateType; typedef mitk::ScalarType InterpolationWeightType; static const unsigned int PointDimension = 3; static const unsigned int MaxTopologicalDimension = 3; /** * \brief struct for data of a point */ struct PointDataType { unsigned int id; //to give the point a special ID bool selected; //information about if the point is selected mitk::PointSpecificationType pointSpec; //specifies the type of the point }; /** * \brief cellDataType, that stores all indexes of the lines, that are * selected e.g.: points A,B and C.Between A and B there is a line with * index 0. If vector of cellData contains 1 and 2, then the lines between * B and C and C and A is selected. */ typedef std::vector SelectedLinesType; typedef SelectedLinesType::iterator SelectedLinesIter; struct CellDataType { //used to set the whole cell on selected bool selected; //indexes of selected lines. 0 is between pointId 0 and 1 SelectedLinesType selectedLines; //is the polygon already finished and closed bool closed; }; typedef itk::DefaultDynamicMeshTraits< PointDataType, PointDimension, MaxTopologicalDimension, CoordinateType, InterpolationWeightType, CellDataType > MeshTraits; typedef itk::Mesh MeshType; typedef MeshType DataType; typedef DataType::PointType PointType; typedef DataType::PointIdentifier PointIdentifier; typedef DataType::PointsContainer PointsContainer; typedef DataType::PointsContainerIterator PointsIterator; typedef DataType::PointsContainer::ConstIterator PointsConstIterator; typedef DataType::PointDataContainer PointDataContainer; typedef DataType::PointDataContainerIterator PointDataIterator; virtual void Expand( unsigned int timeSteps ); /** \brief executes the given Operation */ virtual void ExecuteOperation(Operation* operation); /** \brief returns the current size of the point-list */ virtual int GetSize( unsigned int t = 0 ) const; virtual unsigned int GetPointSetSeriesSize() const; /** \brief returns the pointset */ virtual DataType::Pointer GetPointSet( int t = 0 ) const; /** * \brief Get the point with ID id in world coordinates * * check if the ID exists. If it doesn't exist, then return 0,0,0 */ PointType GetPoint( PointIdentifier id, int t = 0 ) const; /** * \brief Get the point with ID id in world coordinates * * If a point exists for the ID id, the point is returned in the parameter point * and the method returns true. If the ID does not exist, the method returns false */ bool GetPointIfExists( PointIdentifier id, PointType* point, int t = 0 ) const; /** * \brief Set the given point in world coordinate system into the itkPointSet. */ void SetPoint( PointIdentifier id, PointType point, int t = 0 ); /** * \brief Set the given point in world coordinate system with the given PointSpecificationType */ void SetPoint( PointIdentifier id, PointType point, PointSpecificationType spec, int t = 0 ); /** * \brief Set the given point in world coordinate system into the itkPointSet. */ void InsertPoint( PointIdentifier id, PointType point, int t = 0 ); /** * \brief Set the given point in world coordinate system with given PointSpecificationType */ void InsertPoint( PointIdentifier id, PointType point, PointSpecificationType spec, int t ); /** * \brief Swap a point at the given position (id) with the upper point (moveUpwards=true) or with the lower point (moveUpwards=false). * If upper or lower index does not exist false is returned, if swap was successful true. */ bool SwapPointPosition( PointIdentifier id, bool moveUpwards, int t = 0 ); /** * \brief searches a selected point and returns the id of that point. * If no point is found, then -1 is returned */ virtual int SearchSelectedPoint( int t = 0 ) const; /** \brief returns true if a point exists at this position */ virtual bool IndexExists( int position, int t = 0 ) const; /** \brief to get the state selected/unselected of the point on the * position */ virtual bool GetSelectInfo( int position, int t = 0 ) const; virtual void SetSelectInfo( int position, bool selected, int t = 0 ); /** \brief to get the type of the point at the position and the moment */ virtual PointSpecificationType GetSpecificationTypeInfo( int position, int t ) const; /** \brief returns the number of selected points */ virtual int GetNumberOfSelected( int t = 0 ) const; /** * \brief searches a point in the list == point +/- distance * * \param point is in world coordinates. * \param distance is in mm. * returns -1 if no point is found * or the position in the list of the first match */ int SearchPoint( Point3D point, float distance, int t = 0 ) const; - virtual bool IsEmpty(unsigned int t) const; + virtual bool IsEmptyTimeStep(unsigned int t) const; //virtual methods, that need to be implemented virtual void UpdateOutputInformation(); virtual void SetRequestedRegionToLargestPossibleRegion(); virtual bool RequestedRegionIsOutsideOfTheBufferedRegion(); virtual bool VerifyRequestedRegion(); virtual void SetRequestedRegion(itk::DataObject *data); //Method for subclasses virtual void OnPointSetChange(){}; protected: PointSet(); virtual ~PointSet(); virtual void PrintSelf(std::ostream& os, itk::Indent indent) const; ///< print content of the object to os virtual void ClearData(); virtual void InitializeEmpty(); /** \brief swaps point coordinates and point data of the points with identifiers id1 and id2 */ bool SwapPointContents(PointIdentifier id1, PointIdentifier id2, int t = 0 ); typedef std::vector< DataType::Pointer > PointSetSeries; PointSetSeries m_PointSetSeries; /** * @brief flag to indicate the right time to call SetBounds **/ bool m_CalculateBoundingBox; }; itkEventMacro( PointSetEvent, itk::AnyEvent ); itkEventMacro( PointSetMoveEvent, PointSetEvent ); itkEventMacro( PointSetSizeChangeEvent, PointSetEvent ); itkEventMacro( PointSetAddEvent, PointSetSizeChangeEvent ); itkEventMacro( PointSetRemoveEvent, PointSetSizeChangeEvent ); itkEventMacro( PointSetExtendTimeRangeEvent, PointSetEvent ); } // namespace mitk #endif /* MITKPointSet_H_HEADER_INCLUDED */ diff --git a/Core/Code/DataManagement/mitkResliceMethodProperty.h b/Core/Code/DataManagement/mitkResliceMethodProperty.h index c94060c749..e858ec8b22 100644 --- a/Core/Code/DataManagement/mitkResliceMethodProperty.h +++ b/Core/Code/DataManagement/mitkResliceMethodProperty.h @@ -1,51 +1,53 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date: 2008-04-14 19:45:53 +0200 (Mo, 14 Apr 2008) $ Version: $Revision: 14081 $ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef __MITKRESLICEMETHODENUMPROPERTY_H #define __MITKRESLICEMETHODENUMPROPERTY_H #include "mitkEnumerationProperty.h" namespace mitk { /** * Encapsulates the thick slices method enumeration */ class MITK_CORE_EXPORT ResliceMethodProperty : public EnumerationProperty { public: mitkClassMacro( ResliceMethodProperty, EnumerationProperty ); itkNewMacro(ResliceMethodProperty); mitkNewMacro1Param(ResliceMethodProperty, const IdType&); mitkNewMacro1Param(ResliceMethodProperty, const std::string&); + + virtual BaseProperty& operator=(const BaseProperty& other) { return Superclass::operator=(other); } protected: ResliceMethodProperty( ); ResliceMethodProperty( const IdType& value ); ResliceMethodProperty( const std::string& value ); void AddThickSlicesTypes(); }; } // end of namespace mitk #endif //_MITK_VTK_SCALARMODE_PROPERTY__H_ diff --git a/Core/Code/DataManagement/mitkShaderProperty.h b/Core/Code/DataManagement/mitkShaderProperty.h index 6d84923d79..a7b795357d 100644 --- a/Core/Code/DataManagement/mitkShaderProperty.h +++ b/Core/Code/DataManagement/mitkShaderProperty.h @@ -1,96 +1,98 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date: 2008-04-14 19:45:53 +0200 (Mo, 14 Apr 2008) $ Version: $Revision: 14081 $ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef __MITKSHADERENUMPROPERTY_H #define __MITKSHADERENUMPROPERTY_H #include "mitkEnumerationProperty.h" namespace mitk { /** * Encapsulates the shader enumeration */ class MITK_CORE_EXPORT ShaderProperty : public EnumerationProperty { public: class Element { public: std::string name; }; mitkClassMacro( ShaderProperty, EnumerationProperty ); itkNewMacro(ShaderProperty); + + virtual BaseProperty& operator=(const BaseProperty& other) { return Superclass::operator=(other); } mitkNewMacro1Param(ShaderProperty, const IdType&); mitkNewMacro1Param(ShaderProperty, const std::string&); /** * Returns the current scalar mode value as defined by VTK constants. * @returns the current scalar mode as VTK constant. */ IdType GetShaderId(); std::string GetShaderName(); void SetShader(const IdType& i); void SetShader(const std::string& i); protected: std::list shaderList; /** * Constructor. Sets the representation to a default value of surface(2) */ ShaderProperty( ); /** * \brief Sets the scalar mode to the given value. If it is not * valid, the scalar mode is set to default (0). * @param value the integer representation of the scalar mode */ ShaderProperty( const IdType& value ); /** * \brief Sets the scalar mode to the given value. If it is not * valid, the representation is set to default (0). * @param value the string representation of the scalar mode */ ShaderProperty( const std::string& value ); /** * this function is overridden as protected, so that the user may not add * additional invalid scalar mode types. */ bool AddEnum( const std::string& name ); /** * Adds the enumeration types as defined by vtk to the list of known * enumeration values. */ void AddShaderTypes(); }; } // end of namespace mitk #endif //_MITK_VTK_SCALARMODE_PROPERTY__H_ diff --git a/Core/Code/DataManagement/mitkSlicedGeometry3D.cpp b/Core/Code/DataManagement/mitkSlicedGeometry3D.cpp index 3a6c5b0200..14324eb55e 100644 --- a/Core/Code/DataManagement/mitkSlicedGeometry3D.cpp +++ b/Core/Code/DataManagement/mitkSlicedGeometry3D.cpp @@ -1,840 +1,836 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "mitkSlicedGeometry3D.h" #include "mitkPlaneGeometry.h" #include "mitkRotationOperation.h" #include "mitkPlaneOperation.h" #include "mitkInteractionConst.h" #include "mitkSliceNavigationController.h" mitk::SlicedGeometry3D::SlicedGeometry3D() : m_EvenlySpaced( true ), m_Slices( 0 ), m_ReferenceGeometry( NULL ), m_SliceNavigationController( NULL ) { - this->Initialize( m_Slices ); + this->InitializeSlicedGeometry( m_Slices ); } +mitk::SlicedGeometry3D::SlicedGeometry3D(const SlicedGeometry3D& other) +: Superclass(other), + m_EvenlySpaced( other.m_EvenlySpaced ), + m_Slices( other.m_Slices ), + m_ReferenceGeometry( other.m_ReferenceGeometry ), + m_SliceNavigationController( other.m_SliceNavigationController ) +{ + + SetSpacing( other.GetSpacing() ); + SetDirectionVector( other.GetDirectionVector() ); + + if ( m_EvenlySpaced ) + { + AffineGeometryFrame3D::Pointer geometry = other.m_Geometry2Ds[0]->Clone(); + Geometry2D* geometry2D = dynamic_cast(geometry.GetPointer()); + assert(geometry2D!=NULL); + SetGeometry2D(geometry2D, 0); + } + else + { + unsigned int s; + for ( s = 0; s < other.m_Slices; ++s ) + { + if ( other.m_Geometry2Ds[s].IsNull() ) + { + assert(other.m_EvenlySpaced); + m_Geometry2Ds[s] = NULL; + } + else + { + AffineGeometryFrame3D::Pointer geometry = other.m_Geometry2Ds[s]->Clone(); + Geometry2D* geometry2D = dynamic_cast(geometry.GetPointer()); + assert(geometry2D!=NULL); + SetGeometry2D(geometry2D, s); + } + } + } +} mitk::SlicedGeometry3D::~SlicedGeometry3D() { } mitk::Geometry2D * mitk::SlicedGeometry3D::GetGeometry2D( int s ) const { mitk::Geometry2D::Pointer geometry2D = NULL; if ( this->IsValidSlice(s) ) { geometry2D = m_Geometry2Ds[s]; // If (a) m_EvenlySpaced==true, (b) we don't have a Geometry2D stored // for the requested slice, and (c) the first slice (s=0) // is a PlaneGeometry instance, then we calculate the geometry of the // requested as the plane of the first slice shifted by m_Spacing[2]*s // in the direction of m_DirectionVector. if ( (m_EvenlySpaced) && (geometry2D.IsNull()) ) { PlaneGeometry *firstSlice = dynamic_cast< PlaneGeometry * > ( m_Geometry2Ds[0].GetPointer() ); if ( firstSlice != NULL ) { if ( (m_DirectionVector[0] == 0.0) && (m_DirectionVector[1] == 0.0) && (m_DirectionVector[2] == 0.0) ) { m_DirectionVector = firstSlice->GetNormal(); m_DirectionVector.Normalize(); } Vector3D direction; direction = m_DirectionVector * m_Spacing[2]; mitk::PlaneGeometry::Pointer requestedslice; requestedslice = static_cast< mitk::PlaneGeometry * >( firstSlice->Clone().GetPointer() ); requestedslice->SetOrigin( requestedslice->GetOrigin() + direction * s ); geometry2D = requestedslice; m_Geometry2Ds[s] = geometry2D; } } return geometry2D; } else { return NULL; } } const mitk::BoundingBox * mitk::SlicedGeometry3D::GetBoundingBox() const { assert(m_BoundingBox.IsNotNull()); return m_BoundingBox.GetPointer(); } bool mitk::SlicedGeometry3D::SetGeometry2D( mitk::Geometry2D *geometry2D, int s ) { if ( this->IsValidSlice(s) ) { m_Geometry2Ds[s] = geometry2D; m_Geometry2Ds[s]->SetReferenceGeometry( m_ReferenceGeometry ); return true; } return false; } void -mitk::SlicedGeometry3D::Initialize( unsigned int slices ) +mitk::SlicedGeometry3D::InitializeSlicedGeometry( unsigned int slices ) { Superclass::Initialize(); m_Slices = slices; Geometry2D::Pointer gnull = NULL; m_Geometry2Ds.assign( m_Slices, gnull ); Vector3D spacing; spacing.Fill( 1.0 ); this->SetSpacing( spacing ); m_DirectionVector.Fill( 0 ); } void mitk::SlicedGeometry3D::InitializeEvenlySpaced( mitk::Geometry2D* geometry2D, unsigned int slices, bool flipped ) { assert( geometry2D != NULL ); this->InitializeEvenlySpaced( geometry2D, geometry2D->GetExtentInMM(2)/geometry2D->GetExtent(2), slices, flipped ); } void mitk::SlicedGeometry3D::InitializeEvenlySpaced( mitk::Geometry2D* geometry2D, mitk::ScalarType zSpacing, unsigned int slices, bool flipped ) { assert( geometry2D != NULL ); assert( geometry2D->GetExtent(0) > 0 ); assert( geometry2D->GetExtent(1) > 0 ); geometry2D->Register(); Superclass::Initialize(); m_Slices = slices; BoundingBox::BoundsArrayType bounds = geometry2D->GetBounds(); bounds[4] = 0; bounds[5] = slices; // clear and reserve Geometry2D::Pointer gnull = NULL; m_Geometry2Ds.assign( m_Slices, gnull ); Vector3D directionVector = geometry2D->GetAxisVector(2); directionVector.Normalize(); directionVector *= zSpacing; if ( flipped == false ) { // Normally we should use the following four lines to create a copy of // the transform contrained in geometry2D, because it may not be changed // by us. But we know that SetSpacing creates a new transform without // changing the old (coming from geometry2D), so we can use the fifth // line instead. We check this at (**). // // AffineTransform3D::Pointer transform = AffineTransform3D::New(); // transform->SetMatrix(geometry2D->GetIndexToWorldTransform()->GetMatrix()); // transform->SetOffset(geometry2D->GetIndexToWorldTransform()->GetOffset()); // SetIndexToWorldTransform(transform); m_IndexToWorldTransform = const_cast< AffineTransform3D * >( geometry2D->GetIndexToWorldTransform() ); } else { directionVector *= -1.0; m_IndexToWorldTransform = AffineTransform3D::New(); m_IndexToWorldTransform->SetMatrix( geometry2D->GetIndexToWorldTransform()->GetMatrix() ); AffineTransform3D::OutputVectorType scaleVector; FillVector3D(scaleVector, 1.0, 1.0, -1.0); m_IndexToWorldTransform->Scale(scaleVector, true); m_IndexToWorldTransform->SetOffset( geometry2D->GetIndexToWorldTransform()->GetOffset() ); } mitk::Vector3D spacing; FillVector3D( spacing, geometry2D->GetExtentInMM(0) / bounds[1], geometry2D->GetExtentInMM(1) / bounds[3], zSpacing ); // Ensure that spacing differs from m_Spacing to make SetSpacing change the // matrix. m_Spacing[2] = zSpacing - 1; this->SetDirectionVector( directionVector ); this->SetBounds( bounds ); this->SetGeometry2D( geometry2D, 0 ); this->SetSpacing( spacing ); this->SetEvenlySpaced(); this->SetTimeBounds( geometry2D->GetTimeBounds() ); assert(m_IndexToWorldTransform.GetPointer() != geometry2D->GetIndexToWorldTransform()); // (**) see above. this->SetFrameOfReferenceID( geometry2D->GetFrameOfReferenceID() ); this->SetImageGeometry( geometry2D->GetImageGeometry() ); geometry2D->UnRegister(); } void mitk::SlicedGeometry3D::InitializePlanes( const mitk::Geometry3D *geometry3D, mitk::PlaneGeometry::PlaneOrientation planeorientation, bool top, bool frontside, bool rotated ) { m_ReferenceGeometry = const_cast< Geometry3D * >( geometry3D ); PlaneGeometry::Pointer planeGeometry = mitk::PlaneGeometry::New(); planeGeometry->InitializeStandardPlane( geometry3D, top, planeorientation, frontside, rotated ); ScalarType viewSpacing = 1; unsigned int slices = 1; switch ( planeorientation ) { case PlaneGeometry::Transversal: viewSpacing = geometry3D->GetSpacing()[2]; slices = (unsigned int) geometry3D->GetExtent( 2 ); break; case PlaneGeometry::Frontal: viewSpacing = geometry3D->GetSpacing()[1]; slices = (unsigned int) geometry3D->GetExtent( 1 ); break; case PlaneGeometry::Sagittal: viewSpacing = geometry3D->GetSpacing()[0]; slices = (unsigned int) geometry3D->GetExtent( 0 ); break; default: itkExceptionMacro("unknown PlaneOrientation"); } mitk::Vector3D normal = this->AdjustNormal( planeGeometry->GetNormal() ); ScalarType directedExtent = fabs( m_ReferenceGeometry->GetExtentInMM( 0 ) * normal[0] ) + fabs( m_ReferenceGeometry->GetExtentInMM( 1 ) * normal[1] ) + fabs( m_ReferenceGeometry->GetExtentInMM( 2 ) * normal[2] ); if ( directedExtent >= viewSpacing ) { slices = static_cast< int >(directedExtent / viewSpacing + 0.5); } else { slices = 1; } bool flipped = (top == false); if ( frontside == false ) { flipped = !flipped; } if ( planeorientation == PlaneGeometry::Frontal ) { flipped = !flipped; } this->InitializeEvenlySpaced( planeGeometry, viewSpacing, slices, flipped ); } void mitk::SlicedGeometry3D ::ReinitializePlanes( const Point3D ¢er, const Point3D &referencePoint ) { // Need a reference frame to align the rotated planes if ( !m_ReferenceGeometry ) { return; } // Get first plane of plane stack PlaneGeometry *firstPlane = dynamic_cast< PlaneGeometry * >( m_Geometry2Ds[0].GetPointer() ); // If plane stack is empty, exit if ( firstPlane == NULL ) { return; } // Calculate the "directed" spacing when taking the plane (defined by its axes // vectors and normal) as the reference coordinate frame. // // This is done by calculating the radius of the ellipsoid defined by the // original volume spacing axes, in the direction of the respective axis of the // reference frame. mitk::Vector3D axis0 = firstPlane->GetAxisVector(0); mitk::Vector3D axis1 = firstPlane->GetAxisVector(1); mitk::Vector3D normal = firstPlane->GetNormal(); normal.Normalize(); Vector3D spacing; spacing[0] = this->CalculateSpacing( axis0 ); spacing[1] = this->CalculateSpacing( axis1 ); spacing[2] = this->CalculateSpacing( normal ); Superclass::SetSpacing( spacing ); // Now we need to calculate the number of slices in the plane's normal // direction, so that the entire volume is covered. This is done by first // calculating the dot product between the volume diagonal (the maximum // distance inside the volume) and the normal, and dividing this value by // the directed spacing calculated above. ScalarType directedExtent = fabs( m_ReferenceGeometry->GetExtentInMM( 0 ) * normal[0] ) + fabs( m_ReferenceGeometry->GetExtentInMM( 1 ) * normal[1] ) + fabs( m_ReferenceGeometry->GetExtentInMM( 2 ) * normal[2] ); if ( directedExtent >= spacing[2] ) { m_Slices = static_cast< unsigned int >(directedExtent / spacing[2] + 0.5); } else { m_Slices = 1; } // The origin of our "first plane" needs to be adapted to this new extent. // To achieve this, we first calculate the current distance to the volume's // center, and then shift the origin in the direction of the normal by the // difference between this distance and half of the new extent. double centerOfRotationDistance = firstPlane->SignedDistanceFromPlane( center ); if ( centerOfRotationDistance > 0 ) { firstPlane->SetOrigin( firstPlane->GetOrigin() + normal * (centerOfRotationDistance - directedExtent / 2.0) ); m_DirectionVector = normal; } else { firstPlane->SetOrigin( firstPlane->GetOrigin() + normal * (directedExtent / 2.0 + centerOfRotationDistance) ); m_DirectionVector = -normal; } // Now we adjust this distance according with respect to the given reference // point: we need to make sure that the point is touched by one slice of the // new slice stack. double referencePointDistance = firstPlane->SignedDistanceFromPlane( referencePoint ); int referencePointSlice = static_cast< int >( referencePointDistance / spacing[2]); double alignmentValue = referencePointDistance / spacing[2] - referencePointSlice; firstPlane->SetOrigin( firstPlane->GetOrigin() + normal * alignmentValue * spacing[2] ); // Finally, we can clear the previous geometry stack and initialize it with // our re-initialized "first plane". m_Geometry2Ds.assign( m_Slices, Geometry2D::Pointer( NULL ) ); if ( m_Slices > 0 ) { m_Geometry2Ds[0] = firstPlane; } // Reinitialize SNC with new number of slices m_SliceNavigationController->GetSlice()->SetSteps( m_Slices ); this->Modified(); } double mitk::SlicedGeometry3D::CalculateSpacing( const mitk::Vector3D &d ) const { // Need the spacing of the underlying dataset / geometry if ( !m_ReferenceGeometry ) { return 1.0; } // The following can be derived from the ellipsoid equation // // 1 = x^2/a^2 + y^2/b^2 + z^2/c^2 // // where (a,b,c) = spacing of original volume (ellipsoid radii) // and (x,y,z) = scaled coordinates of vector d (according to ellipsoid) // const mitk::Vector3D &spacing = m_ReferenceGeometry->GetSpacing(); double scaling = d[0]*d[0] / (spacing[0] * spacing[0]) + d[1]*d[1] / (spacing[1] * spacing[1]) + d[2]*d[2] / (spacing[2] * spacing[2]); scaling = sqrt( scaling ); return ( sqrt( d[0]*d[0] + d[1]*d[1] + d[2]*d[2] ) / scaling ); } mitk::Vector3D mitk::SlicedGeometry3D::AdjustNormal( const mitk::Vector3D &normal ) const { Geometry3D::TransformType::Pointer inverse = Geometry3D::TransformType::New(); m_ReferenceGeometry->GetIndexToWorldTransform()->GetInverse( inverse ); Vector3D transformedNormal = inverse->TransformVector( normal ); transformedNormal.Normalize(); return transformedNormal; } void mitk::SlicedGeometry3D::SetImageGeometry( const bool isAnImageGeometry ) { Superclass::SetImageGeometry( isAnImageGeometry ); mitk::Geometry3D* geometry; unsigned int s; for ( s = 0; s < m_Slices; ++s ) { geometry = m_Geometry2Ds[s]; if ( geometry!=NULL ) { geometry->SetImageGeometry( isAnImageGeometry ); } } } void mitk::SlicedGeometry3D::ChangeImageGeometryConsideringOriginOffset( const bool isAnImageGeometry ) { mitk::Geometry3D* geometry; unsigned int s; for ( s = 0; s < m_Slices; ++s ) { geometry = m_Geometry2Ds[s]; if ( geometry!=NULL ) { geometry->ChangeImageGeometryConsideringOriginOffset( isAnImageGeometry ); } } Superclass::ChangeImageGeometryConsideringOriginOffset( isAnImageGeometry ); } bool mitk::SlicedGeometry3D::IsValidSlice( int s ) const { return ((s >= 0) && (s < (int)m_Slices)); } void mitk::SlicedGeometry3D::SetReferenceGeometry( Geometry3D *referenceGeometry ) { m_ReferenceGeometry = referenceGeometry; std::vector::iterator it; for ( it = m_Geometry2Ds.begin(); it != m_Geometry2Ds.end(); ++it ) { (*it)->SetReferenceGeometry( referenceGeometry ); } } void mitk::SlicedGeometry3D::SetSpacing( const mitk::Vector3D &aSpacing ) { bool hasEvenlySpacedPlaneGeometry = false; mitk::Point3D origin; mitk::Vector3D rightDV, bottomDV; BoundingBox::BoundsArrayType bounds; assert(aSpacing[0]>0 && aSpacing[1]>0 && aSpacing[2]>0); // In case of evenly-spaced data: re-initialize instances of Geometry2D, // since the spacing influences them if ((m_EvenlySpaced) && (m_Geometry2Ds.size() > 0)) { mitk::Geometry2D::ConstPointer firstGeometry = m_Geometry2Ds[0].GetPointer(); const PlaneGeometry *planeGeometry = dynamic_cast< const PlaneGeometry * >( firstGeometry.GetPointer() ); if (planeGeometry != NULL ) { this->WorldToIndex( planeGeometry->GetOrigin(), origin ); this->WorldToIndex( planeGeometry->GetAxisVector(0), rightDV ); this->WorldToIndex( planeGeometry->GetAxisVector(1), bottomDV ); bounds = planeGeometry->GetBounds(); hasEvenlySpacedPlaneGeometry = true; } } Superclass::SetSpacing(aSpacing); mitk::Geometry2D::Pointer firstGeometry; // In case of evenly-spaced data: re-initialize instances of Geometry2D, // since the spacing influences them if ( hasEvenlySpacedPlaneGeometry ) { //create planeGeometry according to new spacing this->IndexToWorld( origin, origin ); this->IndexToWorld( rightDV, rightDV ); this->IndexToWorld( bottomDV, bottomDV ); mitk::PlaneGeometry::Pointer planeGeometry = mitk::PlaneGeometry::New(); planeGeometry->SetImageGeometry( this->GetImageGeometry() ); planeGeometry->SetReferenceGeometry( m_ReferenceGeometry ); planeGeometry->InitializeStandardPlane( rightDV.Get_vnl_vector(), bottomDV.Get_vnl_vector(), &m_Spacing ); planeGeometry->SetOrigin(origin); planeGeometry->SetBounds(bounds); firstGeometry = planeGeometry; } else if ( (m_EvenlySpaced) && (m_Geometry2Ds.size() > 0) ) { firstGeometry = m_Geometry2Ds[0].GetPointer(); } //clear and reserve Geometry2D::Pointer gnull=NULL; m_Geometry2Ds.assign(m_Slices, gnull); if ( m_Slices > 0 ) { m_Geometry2Ds[0] = firstGeometry; } this->Modified(); } void mitk::SlicedGeometry3D ::SetSliceNavigationController( SliceNavigationController *snc ) { m_SliceNavigationController = snc; } mitk::SliceNavigationController * mitk::SlicedGeometry3D::GetSliceNavigationController() { return m_SliceNavigationController; } void mitk::SlicedGeometry3D::SetEvenlySpaced(bool on) { if(m_EvenlySpaced!=on) { m_EvenlySpaced=on; this->Modified(); } } void mitk::SlicedGeometry3D ::SetDirectionVector( const mitk::Vector3D& directionVector ) { Vector3D diff = m_DirectionVector - directionVector; if ( (m_DirectionVector.GetSquaredNorm() == 0.0) || (diff.GetNorm() >= vnl_math::float_eps) ) { m_DirectionVector = directionVector; m_DirectionVector.Normalize(); this->Modified(); } } void mitk::SlicedGeometry3D::SetTimeBounds( const mitk::TimeBounds& timebounds ) { Superclass::SetTimeBounds( timebounds ); unsigned int s; for ( s = 0; s < m_Slices; ++s ) { if(m_Geometry2Ds[s].IsNotNull()) { m_Geometry2Ds[s]->SetTimeBounds( timebounds ); } } m_TimeBounds = timebounds; } mitk::AffineGeometryFrame3D::Pointer mitk::SlicedGeometry3D::Clone() const { - Self::Pointer newGeometry = Self::New(); - newGeometry->Initialize(m_Slices); - InitializeGeometry(newGeometry); + Self::Pointer newGeometry = new SlicedGeometry3D(*this); + newGeometry->UnRegister(); return newGeometry.GetPointer(); } - -void -mitk::SlicedGeometry3D::InitializeGeometry( Self *newGeometry ) const -{ - Superclass::InitializeGeometry( newGeometry ); - - newGeometry->SetEvenlySpaced( m_EvenlySpaced ); - newGeometry->SetSpacing( this->GetSpacing() ); - newGeometry->SetDirectionVector( this->GetDirectionVector() ); - - newGeometry->SetSliceNavigationController( m_SliceNavigationController ); - newGeometry->m_ReferenceGeometry = m_ReferenceGeometry; - - if ( m_EvenlySpaced ) - { - AffineGeometryFrame3D::Pointer geometry = m_Geometry2Ds[0]->Clone(); - Geometry2D* geometry2D = dynamic_cast(geometry.GetPointer()); - assert(geometry2D!=NULL); - newGeometry->SetGeometry2D(geometry2D, 0); - } - else - { - unsigned int s; - for ( s = 0; s < m_Slices; ++s ) - { - if ( m_Geometry2Ds[s].IsNull() ) - { - assert(m_EvenlySpaced); - } - else - { - AffineGeometryFrame3D::Pointer geometry = m_Geometry2Ds[s]->Clone(); - Geometry2D* geometry2D = dynamic_cast(geometry.GetPointer()); - assert(geometry2D!=NULL); - newGeometry->SetGeometry2D(geometry2D, s); - } - } - } -} - - void mitk::SlicedGeometry3D::PrintSelf( std::ostream& os, itk::Indent indent ) const { Superclass::PrintSelf(os,indent); os << indent << " EvenlySpaced: " << m_EvenlySpaced << std::endl; if ( m_EvenlySpaced ) { os << indent << " DirectionVector: " << m_DirectionVector << std::endl; } os << indent << " Slices: " << m_Slices << std::endl; os << std::endl; os << indent << " GetGeometry2D(0): "; if ( this->GetGeometry2D(0) == NULL ) { os << "NULL" << std::endl; } else { this->GetGeometry2D(0)->Print(os, indent); } } void mitk::SlicedGeometry3D::ExecuteOperation(Operation* operation) { switch ( operation->GetOperationType() ) { case OpNOTHING: break; case OpROTATE: if ( m_EvenlySpaced ) { // Need a reference frame to align the rotation if ( m_ReferenceGeometry ) { // Clear all generated geometries and then rotate only the first slice. // The other slices will be re-generated on demand // Save first slice Geometry2D::Pointer geometry2D = m_Geometry2Ds[0]; RotationOperation *rotOp = dynamic_cast< RotationOperation * >( operation ); // Generate a RotationOperation using the dataset center instead of // the supplied rotation center. This is necessary so that the rotated // zero-plane does not shift away. The supplied center is instead used // to adjust the slice stack afterwards. Point3D center = m_ReferenceGeometry->GetCenter(); RotationOperation centeredRotation( rotOp->GetOperationType(), center, rotOp->GetVectorOfRotation(), rotOp->GetAngleOfRotation() ); // Rotate first slice geometry2D->ExecuteOperation( ¢eredRotation ); // Clear the slice stack and adjust it according to the center of // the dataset and the supplied rotation center (see documentation of // ReinitializePlanes) this->ReinitializePlanes( center, rotOp->GetCenterOfRotation() ); if ( m_SliceNavigationController ) { m_SliceNavigationController->SelectSliceByPoint( rotOp->GetCenterOfRotation() ); m_SliceNavigationController->AdjustSliceStepperRange(); } Geometry3D::ExecuteOperation( ¢eredRotation ); } } else { // Reach through to all slices for (std::vector::iterator iter = m_Geometry2Ds.begin(); iter != m_Geometry2Ds.end(); ++iter) { (*iter)->ExecuteOperation(operation); } } break; case OpORIENT: if ( m_EvenlySpaced ) { // Save first slice Geometry2D::Pointer geometry2D = m_Geometry2Ds[0]; PlaneGeometry *planeGeometry = dynamic_cast< PlaneGeometry * >( geometry2D.GetPointer() ); PlaneOperation *planeOp = dynamic_cast< PlaneOperation * >( operation ); // Need a PlaneGeometry, a PlaneOperation and a reference frame to // carry out the re-orientation if ( m_ReferenceGeometry && planeGeometry && planeOp ) { // Clear all generated geometries and then rotate only the first slice. // The other slices will be re-generated on demand // Generate a RotationOperation by calculating the angle between // the current and the requested slice orientation Point3D center = m_ReferenceGeometry->GetCenter(); const mitk::Vector3D ¤tNormal = planeGeometry->GetNormal(); const mitk::Vector3D &newNormal = planeOp->GetNormal(); Vector3D rotationAxis = itk::CrossProduct( newNormal, currentNormal ); vtkFloatingPointType rotationAngle = - atan2( (double) rotationAxis.GetNorm(), (double) (newNormal * currentNormal) ); rotationAngle *= 180.0 / vnl_math::pi; RotationOperation centeredRotation( mitk::OpROTATE, center, rotationAxis, rotationAngle ); // Rotate first slice geometry2D->ExecuteOperation( ¢eredRotation ); // Clear the slice stack and adjust it according to the center of // rotation and plane position (see documentation of ReinitializePlanes) this->ReinitializePlanes( center, planeOp->GetPoint() ); if ( m_SliceNavigationController ) { m_SliceNavigationController->SelectSliceByPoint( planeOp->GetPoint() ); m_SliceNavigationController->AdjustSliceStepperRange(); } Geometry3D::ExecuteOperation( ¢eredRotation ); } } else { // Reach through to all slices for (std::vector::iterator iter = m_Geometry2Ds.begin(); iter != m_Geometry2Ds.end(); ++iter) { (*iter)->ExecuteOperation(operation); } } break; } this->Modified(); } diff --git a/Core/Code/DataManagement/mitkSlicedGeometry3D.h b/Core/Code/DataManagement/mitkSlicedGeometry3D.h index 16f347797e..d3c5ae5580 100644 --- a/Core/Code/DataManagement/mitkSlicedGeometry3D.h +++ b/Core/Code/DataManagement/mitkSlicedGeometry3D.h @@ -1,324 +1,323 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef MITKSLICEDGEOMETRY3D_H_HEADER_INCLUDED_C1EBD0AD #define MITKSLICEDGEOMETRY3D_H_HEADER_INCLUDED_C1EBD0AD #include "mitkGeometry3D.h" #include "mitkPlaneGeometry.h" namespace mitk { class SliceNavigationController; class NavigationController; /** \brief Describes the geometry of a data object consisting of slices. * * A Geometry2D can be requested for each slice. In the case of * \em evenly-spaced, \em plane geometries (m_EvenlySpaced==true), * only the 2D-geometry of the first slice has to be set (to an instance of * PlaneGeometry). The 2D geometries of the other slices are calculated * by shifting the first slice in the direction m_DirectionVector by * m_Spacing.z * sliceNumber. The m_Spacing member (which is only * relevant in the case m_EvenlySpaced==true) descibes the size of a voxel * (in mm), i.e., m_Spacing.x is the voxel width in the x-direction of the * plane. It is derived from the reference geometry of this SlicedGeometry3D, * which usually would be the global geometry describing how datasets are to * be resliced. * * By default, slices are oriented in the direction of one of the main axes * (x, y, z). However, by means of rotation, it is possible to realign the * slices in any possible direction. In case of an inclined plane, the spacing * is derived as a product of the (regular) geometry spacing and the direction * vector of the plane. * * SlicedGeometry3D and the associated Geometry2Ds have to be initialized in * the method GenerateOutputInformation() of BaseProcess (or CopyInformation / * UpdateOutputInformation of BaseData, if possible, e.g., by analyzing pic * tags in Image) subclasses. See also * * \sa itk::ProcessObject::GenerateOutputInformation(), * \sa itk::DataObject::CopyInformation() and * \a itk::DataObject::UpdateOutputInformation(). * * Rule: everything is in mm (or ms for temporal information) if not * stated otherwise. * * \warning The hull (i.e., transform, bounding-box and * time-bounds) is only guaranteed to be up-to-date after calling * UpdateInformation(). * * \ingroup Geometry */ class MITK_CORE_EXPORT SlicedGeometry3D : public mitk::Geometry3D { public: mitkClassMacro(SlicedGeometry3D, Geometry3D); /** Method for creation through the object factory. */ itkNewMacro(Self); /** * \brief Returns the Geometry2D of the slice (\a s). * * If (a) m_EvenlySpaced==true, (b) we don't have a Geometry2D stored * for the requested slice, and (c) the first slice (s=0) * is a PlaneGeometry instance, then we calculate the geometry of the * requested as the plane of the first slice shifted by m_Spacing[3]*s * in the direction of m_DirectionVector. * * \warning The Geometry2Ds are not necessarily up-to-date and not even * initialized. * * The Geometry2Ds have to be initialized in the method * GenerateOutputInformation() of BaseProcess (or CopyInformation / * UpdateOutputInformation of BaseData, if possible, e.g., by analyzing * pic tags in Image) subclasses. See also * * \sa itk::ProcessObject::GenerateOutputInformation(), * \sa itk::DataObject::CopyInformation() and * \sa itk::DataObject::UpdateOutputInformation(). */ virtual mitk::Geometry2D* GetGeometry2D( int s ) const; /** * \brief Set Geometry2D of slice \a s. */ virtual bool SetGeometry2D( mitk::Geometry2D *geometry2D, int s ); //##Documentation //## @brief When switching from an Image Geometry to a normal Geometry (and the other way around), you have to change the origin as well (See Geometry Documentation)! This function will change the "isImageGeometry" bool flag and changes the origin respectively. virtual void ChangeImageGeometryConsideringOriginOffset( const bool isAnImageGeometry ); virtual void SetTimeBounds( const mitk::TimeBounds& timebounds ); virtual const mitk::BoundingBox* GetBoundingBox() const; /** * \brief Get the number of slices */ itkGetConstMacro( Slices, unsigned int ); /** * \brief Check whether a slice exists */ virtual bool IsValidSlice( int s = 0 ) const; virtual void SetReferenceGeometry( Geometry3D *referenceGeometry ); /** * \brief Set the spacing (m_Spacing), in direction of the plane normal. * * INTERNAL METHOD. */ virtual void SetSpacing( const mitk::Vector3D &aSpacing ); /** * \brief Set the SliceNavigationController corresponding to this sliced * geometry. * * The SNC needs to be informed when the number of slices in the geometry * changes, which can occur whenthe slices are re-oriented by rotation. */ virtual void SetSliceNavigationController( mitk::SliceNavigationController *snc ); mitk::SliceNavigationController *GetSliceNavigationController(); /** * \brief Set/Get whether the SlicedGeometry3D is evenly-spaced * (m_EvenlySpaced) * * If (a) m_EvenlySpaced==true, (b) we don't have a Geometry2D stored for * the requested slice, and (c) the first slice (s=0) is a PlaneGeometry * instance, then we calculate the geometry of the requested as the plane * of the first slice shifted by m_Spacing.z * s in the direction of * m_DirectionVector. * * \sa GetGeometry2D */ itkGetConstMacro(EvenlySpaced, bool); virtual void SetEvenlySpaced(bool on = true); /** * \brief Set/Get the vector between slices for the evenly-spaced case * (m_EvenlySpaced==true). * * If the direction-vector is (0,0,0) (the default) and the first * 2D geometry is a PlaneGeometry, then the direction-vector will be * calculated from the plane normal. * * \sa m_DirectionVector */ virtual void SetDirectionVector(const mitk::Vector3D& directionVector); itkGetConstMacro(DirectionVector, const mitk::Vector3D&); virtual AffineGeometryFrame3D::Pointer Clone() const; static const std::string SLICES; const static std::string DIRECTION_VECTOR; const static std::string EVENLY_SPACED; /** * \brief Tell this instance how many Geometry2Ds it shall manage. Bounding * box and the Geometry2Ds must be set additionally by calling the respective * methods! * * \warning Bounding box and the 2D-geometries must be set additionally: use * SetBounds(), SetGeometry(). */ - virtual void Initialize( unsigned int slices ); + virtual void InitializeSlicedGeometry( unsigned int slices ); /** * \brief Completely initialize this instance as evenly-spaced with slices * parallel to the provided Geometry2D that is used as the first slice and * for spacing calculation. * * Initializes the bounding box according to the width/height of the * Geometry2D and \a slices. The spacing is calculated from the Geometry2D. */ virtual void InitializeEvenlySpaced( mitk::Geometry2D *geometry2D, unsigned int slices, bool flipped=false ); /** * \brief Completely initialize this instance as evenly-spaced with slices * parallel to the provided Geometry2D that is used as the first slice and * for spacing calculation (except z-spacing). * * Initializes the bounding box according to the width/height of the * Geometry2D and \a slices. The x-/y-spacing is calculated from the * Geometry2D. */ virtual void InitializeEvenlySpaced( mitk::Geometry2D *geometry2D, mitk::ScalarType zSpacing, unsigned int slices, bool flipped=false ); /** * \brief Completely initialize this instance as evenly-spaced plane slices * parallel to a side of the provided Geometry3D and using its spacing * information. * * Initializes the bounding box according to the width/height of the * Geometry3D and the number of slices according to * Geometry3D::GetExtent(2). * * \param planeorientation side parallel to which the slices will be oriented * \param top if \a true, create plane at top, otherwise at bottom * (for PlaneOrientation Transversal, for other plane locations respectively) * \param frontside defines the side of the plane (the definition of * front/back is somewhat arbitrary) * * \param rotate rotates the plane by 180 degree around its normal (the * definition of rotated vs not rotated is somewhat arbitrary) */ virtual void InitializePlanes( const mitk::Geometry3D *geometry3D, mitk::PlaneGeometry::PlaneOrientation planeorientation, bool top=true, bool frontside=true, bool rotated=false ); virtual void SetImageGeometry(const bool isAnImageGeometry); virtual void ExecuteOperation(Operation* operation); protected: SlicedGeometry3D(); + SlicedGeometry3D(const SlicedGeometry3D& other); + virtual ~SlicedGeometry3D(); /** * Reinitialize plane stack after rotation. More precisely, the first plane * of the stack needs to spatially aligned, in two respects: * * 1. Re-alignment with respect to the dataset center; this is necessary * since the distance from the first palne to the center could otherwise * continuously decrease or increase. * 2. Re-alignment with respect to a given reference point; the reference * point is a location which the user wants to be exactly touched by one * plane of the plane stack. The first plane is minimally shifted to * ensure this touching. Usually, the reference point would be the * point around which the geometry is rotated. */ virtual void ReinitializePlanes( const Point3D ¢er, const Point3D &referencePoint ); ScalarType GetLargestExtent( const Geometry3D *geometry ); - - virtual void InitializeGeometry(Self * newGeometry) const; - void PrintSelf(std::ostream& os, itk::Indent indent) const; /** Calculate "directed spacing", i.e. the spacing in directions * non-orthogonal to the coordinate axes. This is done via the * ellipsoid equation. */ double CalculateSpacing( const mitk::Vector3D &direction ) const; /** The extent of the slice stack, i.e. the number of slices, depends on the * plane normal. For rotated geometries, the geometry's transform needs to * be accounted in this calculation. */ mitk::Vector3D AdjustNormal( const mitk::Vector3D &normal ) const; /** * Container for the 2D-geometries contained within this SliceGeometry3D. */ mutable std::vector m_Geometry2Ds; /** * If (a) m_EvenlySpaced==true, (b) we don't have a Geometry2D stored * for the requested slice, and (c) the first slice (s=0) * is a PlaneGeometry instance, then we calculate the geometry of the * requested as the plane of the first slice shifted by m_Spacing.z*s * in the direction of m_DirectionVector. * * \sa GetGeometry2D */ bool m_EvenlySpaced; /** * Vector between slices for the evenly-spaced case (m_EvenlySpaced==true). * If the direction-vector is (0,0,0) (the default) and the first * 2D geometry is a PlaneGeometry, then the direction-vector will be * calculated from the plane normal. */ mutable mitk::Vector3D m_DirectionVector; /** Number of slices this SliceGeometry3D is descibing. */ unsigned int m_Slices; /** Underlying Geometry3D for this SlicedGeometry */ mitk::Geometry3D *m_ReferenceGeometry; /** SNC correcsponding to this geometry; used to reflect changes in the * number of slices due to rotation. */ //mitk::NavigationController *m_NavigationController; mitk::SliceNavigationController *m_SliceNavigationController; }; } // namespace mitk #endif /* MITKSLICEDGEOMETRY3D_H_HEADER_INCLUDED_C1EBD0AD */ diff --git a/Core/Code/DataManagement/mitkSurface.cpp b/Core/Code/DataManagement/mitkSurface.cpp index 1af88fc837..7553de5c43 100644 --- a/Core/Code/DataManagement/mitkSurface.cpp +++ b/Core/Code/DataManagement/mitkSurface.cpp @@ -1,362 +1,362 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "mitkSurface.h" #include "mitkInteractionConst.h" #include "mitkSurfaceOperation.h" #include #include mitk::Surface::Surface() : m_CalculateBoundingBox( false ) { this->InitializeEmpty(); } mitk::Surface::~Surface() { this->ClearData(); } void mitk::Surface::ClearData() { for ( VTKPolyDataSeries::iterator it = m_PolyDataSeries.begin(); it != m_PolyDataSeries.end(); ++it ) { if ( ( *it ) != NULL ) ( *it )->Delete(); } m_PolyDataSeries.clear(); Superclass::ClearData(); } void mitk::Surface::InitializeEmpty() { vtkPolyData* pdnull = NULL; m_PolyDataSeries.resize( 1, pdnull ); Superclass::InitializeTimeSlicedGeometry(1); m_Initialized = true; } void mitk::Surface::SetVtkPolyData( vtkPolyData* polydata, unsigned int t ) { // Adapt the size of the data vector if necessary this->Expand( t+1 ); if(m_PolyDataSeries[ t ] != NULL) { if ( m_PolyDataSeries[ t ] == polydata ) return; // we do not need the reference on the object any longer m_PolyDataSeries[ t ]->Delete(); } m_PolyDataSeries[ t ] = polydata; // call m_VtkPolyData->Register(NULL) to tell // the reference counting that we want to keep a // reference on the object if(m_PolyDataSeries[ t ] != NULL) { m_PolyDataSeries[ t ]->Register( NULL ); } this->Modified(); m_CalculateBoundingBox = true; } -bool mitk::Surface::IsEmpty(unsigned int t) const +bool mitk::Surface::IsEmptyTimeStep(unsigned int t) const { if(!IsInitialized()) return false; vtkPolyData* polydata = const_cast(this)->GetVtkPolyData(t); return (polydata == NULL) || ( (polydata->GetNumberOfVerts() <= 0) && (polydata->GetNumberOfPolys() <= 0) && (polydata->GetNumberOfStrips() <= 0) && (polydata->GetNumberOfLines() <= 0) ); } vtkPolyData* mitk::Surface::GetVtkPolyData( unsigned int t ) { if ( t < m_PolyDataSeries.size() ) { vtkPolyData* polydata = m_PolyDataSeries[ t ]; if((polydata==NULL) && (GetSource().GetPointer()!=NULL)) { RegionType requestedregion; requestedregion.SetIndex(3, t); requestedregion.SetSize(3, 1); SetRequestedRegion(&requestedregion); GetSource()->Update(); } polydata = m_PolyDataSeries[ t ]; return polydata; } else return NULL; } void mitk::Surface::UpdateOutputInformation() { if ( this->GetSource() ) { this->GetSource()->UpdateOutputInformation(); } if ( ( m_CalculateBoundingBox ) && ( m_PolyDataSeries.size() > 0 ) ) CalculateBoundingBox(); else GetTimeSlicedGeometry()->UpdateInformation(); } void mitk::Surface::CalculateBoundingBox() { // // first make sure, that the associated time sliced geometry has // the same number of geometry 3d's as vtkPolyDatas are present // mitk::TimeSlicedGeometry* timeGeometry = GetTimeSlicedGeometry(); if ( timeGeometry->GetTimeSteps() != m_PolyDataSeries.size() ) { itkExceptionMacro(<<"timeGeometry->GetTimeSteps() != m_PolyDataSeries.size() -- use Initialize(timeSteps) with correct number of timeSteps!"); } // // Iterate over the vtkPolyDatas and update the Geometry // information of each of the items. // for ( unsigned int i = 0 ; i < m_PolyDataSeries.size() ; ++i ) { vtkPolyData* polyData = m_PolyDataSeries[ i ]; vtkFloatingPointType bounds[ ] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; if ( ( polyData != NULL ) && ( polyData->GetNumberOfPoints() > 0 ) ) { polyData->Update(); polyData->ComputeBounds(); polyData->GetBounds( bounds ); } mitk::Geometry3D::Pointer g3d = timeGeometry->GetGeometry3D( i ); assert( g3d.IsNotNull() ); g3d->SetFloatBounds( bounds ); } timeGeometry->UpdateInformation(); mitk::BoundingBox::Pointer bb = const_cast( timeGeometry->GetBoundingBox() ); itkDebugMacro( << "boundingbox min: "<< bb->GetMinimum()); itkDebugMacro( << "boundingbox max: "<< bb->GetMaximum()); m_CalculateBoundingBox = false; } void mitk::Surface::SetRequestedRegionToLargestPossibleRegion() { m_RequestedRegion = GetLargestPossibleRegion(); } bool mitk::Surface::RequestedRegionIsOutsideOfTheBufferedRegion() { RegionType::IndexValueType end = m_RequestedRegion.GetIndex(3)+m_RequestedRegion.GetSize(3); if(((RegionType::IndexValueType)m_PolyDataSeries.size())=0) && (m_RequestedRegion.GetIndex(3)+m_RequestedRegion.GetSize(3)<=m_PolyDataSeries.size()) ) return true; return false; } void mitk::Surface::SetRequestedRegion( itk::DataObject *data ) { mitk::Surface *surfaceData; surfaceData = dynamic_cast(data); if (surfaceData) { m_RequestedRegion = surfaceData->GetRequestedRegion(); } else { // pointer could not be cast back down itkExceptionMacro( << "mitk::Surface::SetRequestedRegion(DataObject*) cannot cast " << typeid(data).name() << " to " << typeid(Surface*).name() ); } } void mitk::Surface::SetRequestedRegion(Surface::RegionType *region) //by arin { if(region!=NULL) { m_RequestedRegion = *region; } else { // pointer could not be cast back down itkExceptionMacro( << "mitk::Surface::SetRequestedRegion(Surface::RegionType*) cannot cast " << typeid(region).name() << " to " << typeid(Surface*).name() ); } } void mitk::Surface::CopyInformation( const itk::DataObject * data) { Superclass::CopyInformation( data ); const mitk::Surface* surfaceData; surfaceData = dynamic_cast( data ); if ( surfaceData ) { m_LargestPossibleRegion = surfaceData->GetLargestPossibleRegion(); } else { // pointer could not be cast back down itkExceptionMacro( << "mitk::Surface::CopyInformation(const DataObject *data) cannot cast " << typeid(data).name() << " to " << typeid(surfaceData).name() ); } } void mitk::Surface::Update() { if ( GetSource() == NULL ) { for ( VTKPolyDataSeries::iterator it = m_PolyDataSeries.begin() ; it != m_PolyDataSeries.end() ; ++it ) { if ( ( *it ) != NULL ) ( *it )->Update(); } } Superclass::Update(); } void mitk::Surface::Expand( unsigned int timeSteps ) { // check if the vector is long enough to contain the new element // at the given position. If not, expand it with sufficient zero-filled elements. if ( timeSteps > m_PolyDataSeries.size() ) { Superclass::Expand( timeSteps ); vtkPolyData* pdnull = NULL; m_PolyDataSeries.resize( timeSteps, pdnull ); m_CalculateBoundingBox = true; } } void mitk::Surface::ExecuteOperation(Operation *operation) { switch ( operation->GetOperationType() ) { case OpSURFACECHANGED: mitk::SurfaceOperation* surfOp = dynamic_cast(operation); if( ! surfOp ) break; unsigned int time = surfOp->GetTimeStep(); if(m_PolyDataSeries[ time ] != NULL) { vtkPolyData* updatePoly = surfOp->GetVtkPolyData(); if( updatePoly ){ this->SetVtkPolyData( updatePoly, time ); this->CalculateBoundingBox(); } } break; } this->Modified(); } unsigned int mitk::Surface::GetSizeOfPolyDataSeries() const { return m_PolyDataSeries.size(); } void mitk::Surface::Graft( const DataObject* data ) { const Self* surface; try { surface = dynamic_cast( data ); } catch(...) { itkExceptionMacro( << "mitk::Surface::Graft cannot cast " << typeid(data).name() << " to " << typeid(const Self *).name() ); return; } if(!surface) { // pointer could not be cast back down itkExceptionMacro( << "mitk::Surface::Graft cannot cast " << typeid(data).name() << " to " << typeid(const Self *).name() ); return; } this->CopyInformation( data ); //clear list of PolyData's m_PolyDataSeries.clear(); // do copy for (unsigned int i=0; iGetSizeOfPolyDataSeries(); i++) { m_PolyDataSeries.push_back(vtkPolyData::New()); m_PolyDataSeries.back()->DeepCopy( const_cast(surface)->GetVtkPolyData( i ) ); //CopyStructure( const_cast(surface)->GetVtkPolyData( i ) ); } } void mitk::Surface::PrintSelf( std::ostream& os, itk::Indent indent ) const { Superclass::PrintSelf(os, indent); os << indent << "\nNumber PolyDatas: " << m_PolyDataSeries.size() << "\n"; unsigned int count = 0; for (VTKPolyDataSeries::const_iterator it = m_PolyDataSeries.begin(); it != m_PolyDataSeries.end(); ++it) { vtkPolyData* pd = *it; if(pd != NULL) { os << "\n"; os << indent << "PolyData at time step " << count << ". \n"; os << indent << "Number of cells " << pd->GetNumberOfCells() << ": \n"; os << indent << "Number of points " << pd->GetNumberOfPoints() << ": \n\n"; os << indent << "VTKPolyData : \n"; pd->Print(os); } else os << indent << "\nEmpty PolyData at time step " << count << ".\n"; count++; } -} \ No newline at end of file +} diff --git a/Core/Code/DataManagement/mitkSurface.h b/Core/Code/DataManagement/mitkSurface.h index 0982423176..0608b10e22 100644 --- a/Core/Code/DataManagement/mitkSurface.h +++ b/Core/Code/DataManagement/mitkSurface.h @@ -1,117 +1,117 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef MITKSURFACEDATA_H_HEADER_INCLUDED #define MITKSURFACEDATA_H_HEADER_INCLUDED #include "mitkBaseData.h" #include "itkImageRegion.h" class vtkPolyData; namespace mitk { //##Documentation //## @brief Class for storing surfaces (vtkPolyData) //## @ingroup Data class MITK_CORE_EXPORT Surface : public BaseData { protected: public: // not yet the best chioce of a region-type for surfaces, but it works for the time being typedef itk::ImageRegion< 5 > RegionType; mitkClassMacro(Surface, BaseData); itkNewMacro(Self); virtual void SetVtkPolyData(vtkPolyData* polydata, unsigned int t = 0); virtual vtkPolyData* GetVtkPolyData(unsigned int t = 0); virtual void UpdateOutputInformation(); virtual void SetRequestedRegionToLargestPossibleRegion(); virtual bool RequestedRegionIsOutsideOfTheBufferedRegion(); virtual bool VerifyRequestedRegion(); virtual void SetRequestedRegion(itk::DataObject *data); virtual void SetRequestedRegion(Surface::RegionType *region); virtual void CopyInformation(const itk::DataObject *data); - virtual bool IsEmpty(unsigned int t) const; + virtual bool IsEmptyTimeStep(unsigned int t) const; unsigned int GetSizeOfPolyDataSeries() const; virtual void Update(); virtual void Expand( unsigned int timeSteps = 1 ); virtual void Graft( const DataObject* data ); const RegionType& GetLargestPossibleRegion() const { m_LargestPossibleRegion.SetIndex(3, 0); m_LargestPossibleRegion.SetSize(3, GetTimeSlicedGeometry()->GetTimeSteps()); return m_LargestPossibleRegion; } //##Documentation //## Get the region object that defines the size and starting index //## for the region of the image requested (i.e., the region of the //## image to be operated on by a filter). virtual const RegionType& GetRequestedRegion() const { return m_RequestedRegion; } void CalculateBoundingBox(); virtual void PrintSelf( std::ostream& os, itk::Indent indent ) const; virtual void ExecuteOperation(Operation *operation); protected: typedef std::vector< vtkPolyData* > VTKPolyDataSeries; Surface(); virtual ~Surface(); virtual void ClearData(); virtual void InitializeEmpty(); VTKPolyDataSeries m_PolyDataSeries; mutable RegionType m_LargestPossibleRegion; RegionType m_RequestedRegion; bool m_CalculateBoundingBox; }; } // namespace mitk #endif /* MITKSURFACEDATA_H_HEADER_INCLUDED */ diff --git a/Core/Code/DataManagement/mitkThinPlateSplineCurvedGeometry.cpp b/Core/Code/DataManagement/mitkThinPlateSplineCurvedGeometry.cpp index a13b3d8699..d7f9d60d49 100644 --- a/Core/Code/DataManagement/mitkThinPlateSplineCurvedGeometry.cpp +++ b/Core/Code/DataManagement/mitkThinPlateSplineCurvedGeometry.cpp @@ -1,105 +1,103 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "mitkThinPlateSplineCurvedGeometry.h" #include #include mitk::ThinPlateSplineCurvedGeometry::ThinPlateSplineCurvedGeometry() { m_InterpolatingAbstractTransform = m_ThinPlateSplineTransform = vtkThinPlateSplineTransform::New(); m_VtkTargetLandmarks = vtkPoints::New(); m_VtkProjectedLandmarks = vtkPoints::New(); m_ThinPlateSplineTransform->SetInverseIterations(5000); } +mitk::ThinPlateSplineCurvedGeometry::ThinPlateSplineCurvedGeometry(const ThinPlateSplineCurvedGeometry& other ) : Superclass(other) +{ + this->SetSigma(other.GetSigma()); +} + mitk::ThinPlateSplineCurvedGeometry::~ThinPlateSplineCurvedGeometry() { // don't need to delete m_ThinPlateSplineTransform, because it is // the same as m_InterpolatingAbstractTransform, which will be deleted // by the superclass. if(m_VtkTargetLandmarks!=NULL) m_VtkTargetLandmarks->Delete(); if(m_VtkProjectedLandmarks!=NULL) m_VtkProjectedLandmarks->Delete(); } bool mitk::ThinPlateSplineCurvedGeometry::IsValid() const { return m_TargetLandmarks.IsNotNull() && (m_TargetLandmarks->Size() >= 3) && m_LandmarkProjector.IsNotNull(); } void mitk::ThinPlateSplineCurvedGeometry::SetSigma(float sigma) { m_ThinPlateSplineTransform->SetSigma(sigma); } float mitk::ThinPlateSplineCurvedGeometry::GetSigma() const { return m_ThinPlateSplineTransform->GetSigma(); } void mitk::ThinPlateSplineCurvedGeometry::ComputeGeometry() { Superclass::ComputeGeometry(); const mitk::PointSet::DataType::PointsContainer *finalTargetLandmarks, *projectedTargetLandmarks; finalTargetLandmarks = m_LandmarkProjector->GetFinalTargetLandmarks(); projectedTargetLandmarks = m_LandmarkProjector->GetProjectedLandmarks(); mitk::PointSet::DataType::PointsContainer::ConstIterator targetIt, projectedIt; targetIt = finalTargetLandmarks->Begin(); projectedIt = projectedTargetLandmarks->Begin(); //initialize Thin-Plate-Spline m_VtkTargetLandmarks->Reset(); m_VtkProjectedLandmarks->Reset(); vtkIdType id; int size=finalTargetLandmarks->Size(); for(id=0; id < size; ++id, ++targetIt, ++projectedIt) { const mitk::PointSet::PointType& target = targetIt->Value(); m_VtkTargetLandmarks->InsertPoint(id, target[0], target[1], target[2]); const mitk::PointSet::PointType& projected = projectedIt->Value(); m_VtkProjectedLandmarks->InsertPoint(id, projected[0], projected[1], projected[2]); } m_VtkTargetLandmarks->Modified(); m_VtkProjectedLandmarks->Modified(); m_ThinPlateSplineTransform->SetSourceLandmarks(m_VtkProjectedLandmarks); m_ThinPlateSplineTransform->SetTargetLandmarks(m_VtkTargetLandmarks); } mitk::AffineGeometryFrame3D::Pointer mitk::ThinPlateSplineCurvedGeometry::Clone() const { - Self::Pointer newGeometry = Self::New(); - newGeometry->Initialize(); - InitializeGeometry(newGeometry); - return newGeometry.GetPointer(); -} - -void mitk::ThinPlateSplineCurvedGeometry::InitializeGeometry(Self * newGeometry) const -{ - newGeometry->SetSigma(GetSigma()); - Superclass::InitializeGeometry(newGeometry); + mitk::AffineGeometryFrame3D::Pointer newGeometry = new Self(*this); + newGeometry->UnRegister(); + return newGeometry.GetPointer(); } diff --git a/Core/Code/DataManagement/mitkThinPlateSplineCurvedGeometry.h b/Core/Code/DataManagement/mitkThinPlateSplineCurvedGeometry.h index 33cbad9374..ecf988245b 100644 --- a/Core/Code/DataManagement/mitkThinPlateSplineCurvedGeometry.h +++ b/Core/Code/DataManagement/mitkThinPlateSplineCurvedGeometry.h @@ -1,68 +1,69 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef MITKTHINPLATESPLINECURVEDGEOMETRY_H_HEADER_INCLUDED_C1C68A2C #define MITKTHINPLATESPLINECURVEDGEOMETRY_H_HEADER_INCLUDED_C1C68A2C #include "mitkLandmarkProjectorBasedCurvedGeometry.h" class vtkPoints; class vtkThinPlateSplineTransform; namespace mitk { //##Documentation //## @brief Thin-plate-spline-based landmark-based curved geometry //## //## @ingroup Geometry class MITK_CORE_EXPORT ThinPlateSplineCurvedGeometry : public LandmarkProjectorBasedCurvedGeometry { public: mitkClassMacro(ThinPlateSplineCurvedGeometry, LandmarkProjectorBasedCurvedGeometry); itkNewMacro(Self); virtual void ComputeGeometry(); virtual AffineGeometryFrame3D::Pointer Clone() const; vtkThinPlateSplineTransform* GetThinPlateSplineTransform() const { return m_ThinPlateSplineTransform; } virtual void SetSigma(float sigma); virtual float GetSigma() const; virtual bool IsValid() const; protected: ThinPlateSplineCurvedGeometry(); + ThinPlateSplineCurvedGeometry(const ThinPlateSplineCurvedGeometry& other ); + virtual ~ThinPlateSplineCurvedGeometry(); vtkThinPlateSplineTransform* m_ThinPlateSplineTransform; vtkPoints* m_VtkTargetLandmarks; vtkPoints* m_VtkProjectedLandmarks; - void InitializeGeometry(Self * newGeometry) const; }; } // namespace mitk #endif /* MITKTHINPLATESPLINECURVEDGEOMETRY_H_HEADER_INCLUDED_C1C68A2C */ diff --git a/Core/Code/DataManagement/mitkTimeSlicedGeometry.cpp b/Core/Code/DataManagement/mitkTimeSlicedGeometry.cpp index cc53a4c0c1..a80a942880 100644 --- a/Core/Code/DataManagement/mitkTimeSlicedGeometry.cpp +++ b/Core/Code/DataManagement/mitkTimeSlicedGeometry.cpp @@ -1,418 +1,417 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "mitkTimeSlicedGeometry.h" void mitk::TimeSlicedGeometry::UpdateInformation() { if(m_TimeSteps==0) return; unsigned long maxModifiedTime = 0, curModifiedTime; mitk::ScalarType stmin, stmax; stmin= ScalarTypeNumericTraits::NonpositiveMin(); stmax= ScalarTypeNumericTraits::max(); TimeBounds timeBounds; timeBounds[0]=stmax; timeBounds[1]=stmin; mitk::BoundingBox::Pointer boundingBox=mitk::BoundingBox::New(); mitk::BoundingBox::PointsContainer::Pointer pointscontainer=mitk::BoundingBox::PointsContainer::New(); unsigned int t; mitk::Geometry3D* geometry3d; mitk::BoundingBox::ConstPointer nextBoundingBox; mitk::BoundingBox::PointIdentifier pointid=0; // Need to check for zero bounding boxes mitk::ScalarType zeropoint[]={0,0,0,0,0,0}; BoundingBox::BoundsArrayType itkBoundsZero(zeropoint); for(t=0; t < m_TimeSteps; ++t) { geometry3d = GetGeometry3D(t); assert(geometry3d!=NULL); curModifiedTime = geometry3d->GetMTime(); if(maxModifiedTime < curModifiedTime) maxModifiedTime = curModifiedTime; const TimeBounds & curTimeBounds = geometry3d->GetTimeBounds(); if((curTimeBounds[0] > stmin) && (curTimeBounds[0] < timeBounds[0])) timeBounds[0] = curTimeBounds[0]; if((curTimeBounds[1] < stmax) && (curTimeBounds[1] > timeBounds[1])) timeBounds[1] = curTimeBounds[1]; nextBoundingBox = geometry3d->GetBoundingBox(); assert(nextBoundingBox.IsNotNull()); // Only respect non-zero BBes if (nextBoundingBox->GetBounds() == itkBoundsZero) { continue; } const mitk::BoundingBox::PointsContainer * nextPoints = nextBoundingBox->GetPoints(); if(nextPoints!=NULL) { mitk::BoundingBox::PointsContainer::ConstIterator pointsIt = nextPoints->Begin(); while (pointsIt != nextPoints->End() ) { pointscontainer->InsertElement( pointid++, pointsIt->Value()); ++pointsIt; } } } if(!(timeBounds[0] < stmax)) { timeBounds[0] = stmin; timeBounds[1] = stmax; } m_TimeBounds = timeBounds; assert(timeBounds[0]<=timeBounds[1]); boundingBox->SetPoints(pointscontainer); boundingBox->ComputeBoundingBox(); m_BoundingBox = boundingBox; SetIndexToWorldTransform(GetGeometry3D(0)->GetIndexToWorldTransform()); if(this->GetMTime() < maxModifiedTime) Modified(); } mitk::Geometry3D* mitk::TimeSlicedGeometry::GetGeometry3D(int t) const { mitk::Geometry3D::Pointer geometry3d = NULL; if(IsValidTime(t)) { geometry3d = m_Geometry3Ds[t]; //if (a) we don't have a Geometry3D stored for the requested time, //(b) m_EvenlyTimed is activated and (c) the first geometry (t=0) //is set, then we clone the geometry and set the m_TimeBounds accordingly. if((m_EvenlyTimed) && (geometry3d.IsNull())) { const Geometry3D* firstgeometry=m_Geometry3Ds[0].GetPointer(); assert(firstgeometry != NULL); mitk::Geometry3D::Pointer requestedgeometry; requestedgeometry = dynamic_cast(firstgeometry->Clone().GetPointer()); if ( requestedgeometry.IsNull() ) itkExceptionMacro("Geometry is NULL!"); TimeBounds timebounds = requestedgeometry->GetTimeBounds(); if(timebounds[1]SetTimeBounds(timebounds); } geometry3d = requestedgeometry; m_Geometry3Ds[t] = geometry3d; } } else return NULL; return geometry3d; } bool mitk::TimeSlicedGeometry::SetGeometry3D(mitk::Geometry3D* geometry3D, int t) { if(IsValidTime(t)) { m_Geometry3Ds[t]=geometry3D; return true; } return false; } int mitk::TimeSlicedGeometry::MSToTimeStep(mitk::ScalarType time_in_ms) const { if(time_in_ms < m_TimeBounds[0]) return -1; if(time_in_ms >= m_TimeBounds[1]) return m_TimeSteps; if(m_EvenlyTimed) { if(m_TimeBounds[0] == m_TimeBounds[1]) return 0; if((m_TimeBounds[0]>ScalarTypeNumericTraits::NonpositiveMin()) && (m_TimeBounds[1]GetTimeBounds(); if( (timeBounds[0] <= time_in_ms) && (time_in_ms <= timeBounds[1]) ) { return t; } } } return 0; } mitk::ScalarType mitk::TimeSlicedGeometry::TimeStepToMS(int timestep) const { if(IsValidTime(timestep)==false) return ScalarTypeNumericTraits::max(); if(m_EvenlyTimed) { if ( timestep == 0 ) return m_TimeBounds[0]; else { assert( ! (m_TimeBounds[0] == ScalarTypeNumericTraits::NonpositiveMin() && m_TimeBounds[1] == ScalarTypeNumericTraits::max() ) ); return ((mitk::ScalarType)timestep)/m_TimeSteps*(m_TimeBounds[1]-m_TimeBounds[0])+m_TimeBounds[0]; } } else { return GetGeometry3D(timestep)->GetTimeBounds()[0]; } } int mitk::TimeSlicedGeometry::TimeStepToTimeStep( const mitk::TimeSlicedGeometry *referenceGeometry, int t) const { int timeStep; if ( referenceGeometry->GetTimeSteps() > 1 ) { // referenceGeometry is nD+t timeStep = this->MSToTimeStep( referenceGeometry->TimeStepToMS( t ) ); } else { // referenceGEometry is nD (only one time step) timeStep = 0; } return timeStep; } -void mitk::TimeSlicedGeometry::Initialize(unsigned int timeSteps) +void mitk::TimeSlicedGeometry::InitializeEvenlyTimed(unsigned int timeSteps) { Geometry3D::Pointer geometry3D = Geometry3D::New(); geometry3D->Initialize(); InitializeEvenlyTimed(geometry3D, timeSteps); } void mitk::TimeSlicedGeometry::InitializeEvenlyTimed(mitk::Geometry3D* geometry3D, unsigned int timeSteps) { assert(geometry3D!=NULL); geometry3D->Register(); InitializeEmpty(timeSteps); AffineTransform3D::Pointer transform = AffineTransform3D::New(); transform->SetMatrix(geometry3D->GetIndexToWorldTransform()->GetMatrix()); transform->SetOffset(geometry3D->GetIndexToWorldTransform()->GetOffset()); SetIndexToWorldTransform(transform); SetBounds(geometry3D->GetBounds()); SetGeometry3D(geometry3D, 0); SetEvenlyTimed(); UpdateInformation(); SetFrameOfReferenceID(geometry3D->GetFrameOfReferenceID()); SetImageGeometry(geometry3D->GetImageGeometry()); geometry3D->UnRegister(); } void mitk::TimeSlicedGeometry::InitializeEmpty(unsigned int timeSteps) { m_IndexToWorldTransform = NULL; Superclass::Initialize(); m_TimeSteps = timeSteps; // initialize with empty geometries Geometry3D::Pointer gnull=NULL; m_Geometry3Ds.assign(m_TimeSteps, gnull); } void mitk::TimeSlicedGeometry::ExpandToNumberOfTimeSteps( unsigned int timeSteps ) { if( timeSteps <= m_TimeSteps ) return; if(m_TimeSteps == 1) { Geometry3D* g3d = m_Geometry3Ds[0]; const TimeBounds & timeBounds = g3d->GetTimeBounds(); if( (timeBounds[0] == ScalarTypeNumericTraits::NonpositiveMin()) || (timeBounds[1]==ScalarTypeNumericTraits::max()) ) { mitk::ScalarType timeBounds[] = {0.0, 1.0}; m_Geometry3Ds[0]->SetTimeBounds( timeBounds ); } } // Expand to Number of time steps; initialize with empty geometries Geometry3D::Pointer gnull=NULL; m_Geometry3Ds.resize(timeSteps, gnull); m_TimeSteps = timeSteps; UpdateInformation(); } mitk::TimeSlicedGeometry::TimeSlicedGeometry() : m_TimeSteps(0), m_EvenlyTimed(false) { } +mitk::TimeSlicedGeometry::TimeSlicedGeometry(const TimeSlicedGeometry& other) : Geometry3D(other), m_TimeSteps(other.m_TimeSteps), m_EvenlyTimed(other.m_EvenlyTimed) +{ + m_Geometry3Ds.resize(m_TimeSteps); + unsigned int t; + for(t=0; t(other.m_Geometry3Ds[t]->Clone().GetPointer()), t); + } + } +} + mitk::TimeSlicedGeometry::~TimeSlicedGeometry() { } void mitk::TimeSlicedGeometry::SetImageGeometry(const bool isAnImageGeometry) { Superclass::SetImageGeometry(isAnImageGeometry); mitk::Geometry3D* geometry3d; unsigned int t; for(t=0; tSetImageGeometry(isAnImageGeometry); } } void mitk::TimeSlicedGeometry::ChangeImageGeometryConsideringOriginOffset(const bool isAnImageGeometry) { mitk::Geometry3D* geometry3d; unsigned int t; for(t=0; tChangeImageGeometryConsideringOriginOffset(isAnImageGeometry); } Superclass::ChangeImageGeometryConsideringOriginOffset(isAnImageGeometry); } void mitk::TimeSlicedGeometry::SetEvenlyTimed(bool on) { m_EvenlyTimed = on; Modified(); } bool mitk::TimeSlicedGeometry::IsValidTime(int t) const { return (t>=0) && (t< (int)m_TimeSteps); } void mitk::TimeSlicedGeometry::CopyTimes(const mitk::TimeSlicedGeometry* timeslicedgeometry, unsigned int t, unsigned int endtimeindex) { if(endtimeindex >= timeslicedgeometry->GetTimeSteps()) endtimeindex = timeslicedgeometry->GetTimeSteps()-1; if(endtimeindex >= this->GetTimeSteps()) endtimeindex = this->GetTimeSteps()-1; for(; t <= endtimeindex; ++t) { mitk::Geometry3D* geometry3d = GetGeometry3D(t); mitk::Geometry3D* othergeometry3d = timeslicedgeometry->GetGeometry3D(t); assert((geometry3d!=NULL) && (othergeometry3d!=NULL)); geometry3d->SetTimeBounds(othergeometry3d->GetTimeBounds()); } UpdateInformation(); } mitk::AffineGeometryFrame3D::Pointer mitk::TimeSlicedGeometry::Clone() const { - Self::Pointer newGeometry = Self::New(); - newGeometry->Initialize(m_TimeSteps); - InitializeGeometry(newGeometry); + Self::Pointer newGeometry = new TimeSlicedGeometry(*this); + newGeometry->UnRegister(); return newGeometry.GetPointer(); } -void mitk::TimeSlicedGeometry::InitializeGeometry(Self * newGeometry) const -{ - Superclass::InitializeGeometry(newGeometry); - - newGeometry->SetEvenlyTimed(m_EvenlyTimed); - unsigned int t; - for(t=0; tSetGeometry3D(dynamic_cast(m_Geometry3Ds[t]->Clone().GetPointer()), t); - } - } -} void mitk::TimeSlicedGeometry::PrintSelf(std::ostream& os, itk::Indent indent) const { //Superclass::PrintSelf(os,indent); os << indent << " EvenlyTimed: " << m_EvenlyTimed << std::endl; os << indent << " TimeSteps: " << m_TimeSteps << std::endl; os << std::endl; os << indent << " GetGeometry3D(0): "; if(GetGeometry3D(0)==NULL) os << "NULL" << std::endl; else GetGeometry3D(0)->Print(os, indent); } void mitk::TimeSlicedGeometry::ExecuteOperation(Operation* operation) { // reach through to all time steps for (std::vector::iterator iter = m_Geometry3Ds.begin(); iter != m_Geometry3Ds.end(); ++iter) { (*iter)->ExecuteOperation(operation); } Geometry3D::ExecuteOperation(operation); this->Modified(); } diff --git a/Core/Code/DataManagement/mitkTimeSlicedGeometry.h b/Core/Code/DataManagement/mitkTimeSlicedGeometry.h index 68e273fa55..6f2e098320 100644 --- a/Core/Code/DataManagement/mitkTimeSlicedGeometry.h +++ b/Core/Code/DataManagement/mitkTimeSlicedGeometry.h @@ -1,179 +1,178 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef TIMESLICEDGEOMETRY_H_HEADER_INCLUDED_C1EBD0AD #define TIMESLICEDGEOMETRY_H_HEADER_INCLUDED_C1EBD0AD #include "mitkGeometry3D.h" namespace mitk { //##Documentation //## @brief Describes a geometry consisting of several geometries which //## exist at different times. //## //## The geometry contains m_TimeSteps geometries, which can be accessed //## using GetGeometry3D(int t). To convert between world-time in //## milliseconds and the integer timestep-number use MSToTimeStep. //## The hull (in space and time) of the TimeSlicedGeometry contains all //## contained geometries. //## @warning The hull (i.e., transform, bounding-box and //## time-bounds) is only guaranteed to be up-to-date after calling //## UpdateInformation(). //## //## TimeSlicedGeometry and the associated Geometry3Ds have to be //## initialized in the method GenerateOutputInformation() of BaseProcess (or //## CopyInformation/ UpdateOutputInformation of BaseData, if possible, e.g., //## by analyzing pic tags in Image) subclasses. See also //## itk::ProcessObject::GenerateOutputInformation(), //## itk::DataObject::CopyInformation() and //## itk::DataObject::UpdateOutputInformation(). //## //## @ingroup Geometry class MITK_CORE_EXPORT TimeSlicedGeometry : public Geometry3D { public: mitkClassMacro(TimeSlicedGeometry, Geometry3D); itkNewMacro(Self); //##Documentation //## @brief Re-calculate the hull of the contained geometries. //## //## The transforms, bounding-box and time-bounds of this //## geometry (stored in members of the super-class Geometry3D) //## are re-calculated from the contained geometries. void UpdateInformation(); //##Documentation //## @brief Get the number of time-steps itkGetConstMacro(TimeSteps, unsigned int); //##Documentation //## @brief Set/Get whether the TimeSlicedGeometry is evenly-timed (m_EvenlyTimed) //## //## If (a) we don't have a Geometry3D stored for the requested time, //## (b) m_EvenlyTimed is activated and (c) the first geometry (t=0) //## is set, then we clone the geometry and set the m_TimeBounds accordingly. //## \sa GetGeometry3D itkGetConstMacro(EvenlyTimed, bool); virtual void SetEvenlyTimed(bool on = true); //##Documentation //## @brief Set the Geometry3D for time @a t virtual bool SetGeometry3D(mitk::Geometry3D* geometry3D, int t); //##Documentation //## @brief When switching from an Image Geometry to a normal Geometry (and the other way around), you have to change the origin as well (See Geometry Documentation)! This function will change the "isImageGeometry" bool flag and changes the origin respectively. virtual void ChangeImageGeometryConsideringOriginOffset( const bool isAnImageGeometry ); //##Documentation //## @brief Get the Geometry3D at time @a t virtual mitk::Geometry3D* GetGeometry3D(int t) const; //##Documentation //## @brief Test whether @a t is a valid time step virtual bool IsValidTime(int t) const; //##Documentation //## @brief Convert time in ms to a time step virtual int MSToTimeStep(mitk::ScalarType time_in_ms) const; //##Documentation //## @brief Convert time step to time in ms virtual mitk::ScalarType TimeStepToMS(int timestep) const; //##Documentation //## @brief Convert time step in the reference TimeSlicedGeometry to time step //## in this TimeSlicedGeometry. virtual int TimeStepToTimeStep(const mitk::TimeSlicedGeometry *referenceGeometry, int t) const; //##Documentation //## @brief Completely initialize this instance as evenly-timed with //## \a timeSteps geometries of type Geometry3D, each initialized by //## Geometry3D::Initialize(). - virtual void Initialize(unsigned int timeSteps); + virtual void InitializeEvenlyTimed(unsigned int timeSteps); //##Documentation //## @brief Completely initialize this instance as evenly-timed with //## \a timeSteps geometries identical to the provided Geometry3D //## except for the time bounds virtual void InitializeEvenlyTimed(mitk::Geometry3D* geometry3D, unsigned int timeSteps); //##Documentation //## @brief Initialize this instance to contain \a timeSteps //## geometries, but without setting them yet virtual void InitializeEmpty(unsigned int timeSteps); //##Documentation //## @brief Expand the number of time steps contained //## to \a timeSteps. //## //## New, additional time steps will be initialized empty. //## Only enlargement of the time steps vector is intended and possible. virtual void ExpandToNumberOfTimeSteps( unsigned int timeSteps ); virtual void SetImageGeometry(const bool isAnImageGeometry); //##Documentation //## @brief Copy the m_TimeBounds of the geometries contained //## in timeslicedgeometry into the geometries contained in this //## TimeSlicedGeometry object. //## //## Useful for initialization of the TimeSlicedGeometry of the //## output in GenerateOutputInformation() methods of process objects, //## see for example BoundingObjectCutter::GenerateOutputInformation(). //## @param t start time index //## @param endtimeindex (endtimeindex) is the time index of //## the last geometry whose time-bounds are copied. If //## timeslicedgeometry or this TimeSlicedGeometry object does //## not contain enough geometries, endtimeindex is reduced //## appropriately. void CopyTimes(const mitk::TimeSlicedGeometry* timeslicedgeometry, unsigned int t=0, unsigned int endtimeindex = itk::NumericTraits::max()); //##Documentation //## @brief duplicates the geometry virtual AffineGeometryFrame3D::Pointer Clone() const; virtual void ExecuteOperation(Operation* operation); protected: TimeSlicedGeometry(); + TimeSlicedGeometry(const TimeSlicedGeometry& other); virtual ~TimeSlicedGeometry(); - void InitializeGeometry(Self * newGeometry) const; - virtual void PrintSelf(std::ostream& os, itk::Indent indent) const; mutable std::vector m_Geometry3Ds; //##Documentation //## @brief Number of time steps unsigned int m_TimeSteps; //##Documentation //## @brief \a true in case the time steps have equal length bool m_EvenlyTimed; static const std::string EVENLY_TIMED; static const std::string TIME_STEPS; }; } // namespace mitk #endif /* TIMESLICEDGEOMETRY_H_HEADER_INCLUDED_C1EBD0AD */ diff --git a/Core/Code/DataManagement/mitkTransferFunctionProperty.h b/Core/Code/DataManagement/mitkTransferFunctionProperty.h index 129f2dacaa..e17af7b605 100644 --- a/Core/Code/DataManagement/mitkTransferFunctionProperty.h +++ b/Core/Code/DataManagement/mitkTransferFunctionProperty.h @@ -1,81 +1,81 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef MITKTRANFERFUNCTIONPROPERTY_H_HEADER_INCLUDED #define MITKTRANFERFUNCTIONPROPERTY_H_HEADER_INCLUDED #include "mitkBaseProperty.h" #include "mitkTransferFunction.h" namespace mitk { class MITK_CORE_EXPORT TransferFunctionProperty : public BaseProperty { public: mitkClassMacro(TransferFunctionProperty, BaseProperty); itkNewMacro(TransferFunctionProperty); mitkNewMacro1Param(TransferFunctionProperty, mitk::TransferFunction::Pointer); itkSetMacro(Value, mitk::TransferFunction::Pointer ); itkGetConstMacro(Value, mitk::TransferFunction::Pointer ); /** * */ virtual bool operator==(const BaseProperty& property) const { const Self *other = dynamic_cast(&property); if(other==NULL) return false; else return *(m_Value.GetPointer()) == *(other->m_Value.GetPointer()); } - + virtual BaseProperty& operator=(const BaseProperty& other) { return Superclass::operator=(other); } /** * */ std::string GetValueAsString() const { std::stringstream myStr; myStr << GetValue() ; return myStr.str(); } protected: mitk::TransferFunction::Pointer m_Value; TransferFunctionProperty() : BaseProperty() {}; virtual ~TransferFunctionProperty() { }; TransferFunctionProperty( mitk::TransferFunction::Pointer value ) : BaseProperty(), m_Value( value ) {}; }; // typedef GenericProperty TransferFunctionProperty; } // namespace mitk #endif /* MITKTRANFERFUNCTIONPROPERTY_H_HEADER_INCLUDED */ diff --git a/Core/Code/DataManagement/mitkVtkInterpolationProperty.h b/Core/Code/DataManagement/mitkVtkInterpolationProperty.h index 46120c2f1d..60e8b5757c 100644 --- a/Core/Code/DataManagement/mitkVtkInterpolationProperty.h +++ b/Core/Code/DataManagement/mitkVtkInterpolationProperty.h @@ -1,103 +1,105 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef _MITK_VTK_INTERPOLATION_PROPERTY__H_ #define _MITK_VTK_INTERPOLATION_PROPERTY__H_ #include "mitkEnumerationProperty.h" namespace mitk { /** * Encapsulates the enumeration vtkInterpolation. Valid values are * (VTK constant/Id/string representation): * VTK_FLAT/0/Flat, VTK_GOURAUD/1/Gouraud, VTK_PHONG/2/Phong * Default is the Gouraud interpolation */ class MITK_CORE_EXPORT VtkInterpolationProperty : public EnumerationProperty { public: mitkClassMacro( VtkInterpolationProperty, EnumerationProperty ); itkNewMacro(VtkInterpolationProperty); mitkNewMacro1Param(VtkInterpolationProperty, const IdType&); mitkNewMacro1Param(VtkInterpolationProperty, const std::string&); + + virtual BaseProperty& operator=(const BaseProperty& other) { return Superclass::operator=(other); } /** * Returns the current interpolation value as defined by VTK constants. * @returns the current interpolation as VTK constant. */ virtual int GetVtkInterpolation(); /** * Sets the interpolation type to VTK_FLAT. */ virtual void SetInterpolationToFlat(); /** * Sets the interpolation type to VTK_WIREFRAME. */ virtual void SetInterpolationToGouraud(); /** * Sets the interpolation type to VTK_SURFACE. */ virtual void SetInterpolationToPhong(); protected: /** * Constructor. Sets the representation to a default value of surface(2) */ VtkInterpolationProperty( ); /** * Constructor. Sets the interpolation to the given value. If it is not * valid, the interpolation is set to gouraud(1) * @param value the integer representation of the interpolation */ VtkInterpolationProperty( const IdType& value ); /** * Constructor. Sets the interpolation to the given value. If it is not * valid, the representation is set to gouraud(1) * @param value the string representation of the interpolation */ VtkInterpolationProperty( const std::string& value ); /** * this function is overridden as protected, so that the user may not add * additional invalid interpolation types. */ virtual bool AddEnum( const std::string& name, const IdType& id ); /** * Adds the enumeration types as defined by vtk to the list of known * enumeration values. */ virtual void AddInterpolationTypes(); }; } // end of namespace mitk #endif diff --git a/Core/Code/DataManagement/mitkVtkRepresentationProperty.h b/Core/Code/DataManagement/mitkVtkRepresentationProperty.h index 98ded81c08..eacc4a8e96 100644 --- a/Core/Code/DataManagement/mitkVtkRepresentationProperty.h +++ b/Core/Code/DataManagement/mitkVtkRepresentationProperty.h @@ -1,101 +1,103 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef _MITK_VTK_REPRESENTATION_PROPERTY__H_ #define _MITK_VTK_REPRESENTATION_PROPERTY__H_ #include "mitkEnumerationProperty.h" namespace mitk { /** * Encapsulates the enumeration vtkRepresentation. Valid values are * (VTK constant/Id/string representation): * VTK_POINTS/0/Points, VTK_WIREFRAME/1/Wireframe, VTK_SURFACE/2/Surface * Default is the Surface representation */ class MITK_CORE_EXPORT VtkRepresentationProperty : public EnumerationProperty { public: mitkClassMacro( VtkRepresentationProperty, EnumerationProperty ); itkNewMacro(VtkRepresentationProperty); mitkNewMacro1Param(VtkRepresentationProperty, const IdType&); mitkNewMacro1Param(VtkRepresentationProperty, const std::string&); /** * Returns the current representation value as defined by VTK constants. * @returns the current representation as VTK constant. */ virtual int GetVtkRepresentation(); /** * Sets the representation type to VTK_POINTS. */ virtual void SetRepresentationToPoints(); /** * Sets the representation type to VTK_WIREFRAME. */ virtual void SetRepresentationToWireframe(); /** * Sets the representation type to VTK_SURFACE. */ virtual void SetRepresentationToSurface(); + + virtual BaseProperty& operator=(const BaseProperty& other) { return Superclass::operator=(other); } protected: /** * Constructor. Sets the representation to a default value of Surface(2) */ VtkRepresentationProperty( ); /** * Constructor. Sets the representation to the given value. If it is not * valid, the representation is set to Surface(2) * @param value the integer representation of the representation */ VtkRepresentationProperty( const IdType& value ); /** * Constructor. Sets the representation to the given value. If it is not * valid, the representation is set to Surface(2) * @param value the string representation of the representation */ VtkRepresentationProperty( const std::string& value ); /** * this function is overridden as protected, so that the user may not add * additional invalid representation types. */ virtual bool AddEnum( const std::string& name, const IdType& id ); /** * Adds the enumeration types as defined by vtk to the list of known * enumeration values. */ virtual void AddRepresentationTypes(); }; } // end of namespace mitk #endif diff --git a/Core/Code/DataManagement/mitkVtkResliceInterpolationProperty.h b/Core/Code/DataManagement/mitkVtkResliceInterpolationProperty.h index dbf4c9944b..4ee164c299 100644 --- a/Core/Code/DataManagement/mitkVtkResliceInterpolationProperty.h +++ b/Core/Code/DataManagement/mitkVtkResliceInterpolationProperty.h @@ -1,99 +1,101 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision: $ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef _MITK_VTK_RESLICE_INTERPOLATION_PROPERTY__H_ #define _MITK_VTK_RESLICE_INTERPOLATION_PROPERTY__H_ #include "mitkEnumerationProperty.h" #include namespace mitk { /** * Encapsulates the enumeration for reslice interpolation. Valid values are * (VTK constant/Id/string representation): * VTK_RESLICE_NEAREST, VTK_RESLICE_LINEAR, VTK_RESLICE_CUBIC * Default is VTK_RESLICE_NEAREST */ class MITK_CORE_EXPORT VtkResliceInterpolationProperty : public EnumerationProperty { public: mitkClassMacro( VtkResliceInterpolationProperty, EnumerationProperty ); itkNewMacro(VtkResliceInterpolationProperty); mitkNewMacro1Param(VtkResliceInterpolationProperty, const IdType&); mitkNewMacro1Param(VtkResliceInterpolationProperty, const std::string&); + + virtual BaseProperty& operator=(const BaseProperty& other) { return Superclass::operator=(other); } /** * Returns the current interpolation value as defined by VTK constants. */ virtual int GetInterpolation(); /** * Sets the interpolation type to VTK_RESLICE_NEAREST. */ virtual void SetInterpolationToNearest(); /** * Sets the interpolation type to VTK_RESLICE_LINEAR. */ virtual void SetInterpolationToLinear(); /** * Sets the interpolation type to VTK_RESLICE_CUBIC. */ virtual void SetInterpolationToCubic(); protected: /** Sets reslice interpolation mode to default (VTK_RESLICE_NEAREST). */ VtkResliceInterpolationProperty( ); /** * Constructor. Sets reslice interpolation to the given value. */ VtkResliceInterpolationProperty( const IdType& value ); /** * Constructor. Sets reslice interpolation to the given value. */ VtkResliceInterpolationProperty( const std::string& value ); /** * this function is overridden as protected, so that the user may not add * additional invalid interpolation types. */ virtual bool AddEnum( const std::string& name, const IdType& id ); /** * Adds the enumeration types as defined by vtk to the list of known * enumeration values. */ virtual void AddInterpolationTypes(); }; } // end of namespace mitk #endif diff --git a/Core/Code/DataManagement/mitkVtkScalarModeProperty.h b/Core/Code/DataManagement/mitkVtkScalarModeProperty.h index a161a5a58d..9daac9822f 100644 --- a/Core/Code/DataManagement/mitkVtkScalarModeProperty.h +++ b/Core/Code/DataManagement/mitkVtkScalarModeProperty.h @@ -1,101 +1,103 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef _MITK_VTK_SCALARMODE_PROPERTY__H_ #define _MITK_VTK_SCALARMODE_PROPERTY__H_ #include "mitkEnumerationProperty.h" namespace mitk { /** * Encapsulates the enumeration vtkInterpolation. Valid values are * (VTK constant/Id/string representation): * \li VTK_SCALAR_MODE_DEFAULT/0/Default, * \li VTK_SCALAR_MODE_USE_POINT_DATA/1/PointData, * \li VTK_SCALAR_MODE_USE_CELL_DATA/2/CellData * \li VTK_SCALAR_MODE_USE_POINT_FIELD_DATA/3/PointFieldData * \li VTK_SCALAR_MODE_USE_CELL_FIELD_DATA/4/CellFieldData */ class MITK_CORE_EXPORT VtkScalarModeProperty : public EnumerationProperty { public: mitkClassMacro( VtkScalarModeProperty, EnumerationProperty ); itkNewMacro(VtkScalarModeProperty); mitkNewMacro1Param(VtkScalarModeProperty, const IdType&); mitkNewMacro1Param(VtkScalarModeProperty, const std::string&); - + + virtual BaseProperty& operator=(const BaseProperty& other) { return Superclass::operator=(other); } + /** * Returns the current scalar mode value as defined by VTK constants. * @returns the current scalar mode as VTK constant. */ virtual int GetVtkScalarMode(); virtual void SetScalarModeToDefault(); virtual void SetScalarModeToPointData(); virtual void SetScalarModeToCellData(); virtual void SetScalarModeToPointFieldData(); virtual void SetScalarModeToCellFieldData(); protected: /** * Constructor. Sets the representation to a default value of surface(2) */ VtkScalarModeProperty( ); /** * \brief Sets the scalar mode to the given value. If it is not * valid, the scalar mode is set to default (0). * @param value the integer representation of the scalar mode */ VtkScalarModeProperty( const IdType& value ); /** * \brief Sets the scalar mode to the given value. If it is not * valid, the representation is set to default (0). * @param value the string representation of the scalar mode */ VtkScalarModeProperty( const std::string& value ); /** * this function is overridden as protected, so that the user may not add * additional invalid scalar mode types. */ virtual bool AddEnum( const std::string& name, const IdType& id ); /** * Adds the enumeration types as defined by vtk to the list of known * enumeration values. */ virtual void AddInterpolationTypes(); }; } // end of namespace mitk #endif //_MITK_VTK_SCALARMODE_PROPERTY__H_ diff --git a/Core/Code/DataManagement/mitkVtkVolumeRenderingProperty.h b/Core/Code/DataManagement/mitkVtkVolumeRenderingProperty.h index c9fbdf4712..b7838cfc89 100644 --- a/Core/Code/DataManagement/mitkVtkVolumeRenderingProperty.h +++ b/Core/Code/DataManagement/mitkVtkVolumeRenderingProperty.h @@ -1,95 +1,97 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision: $ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef _MITK_VTK_VOLUME_RENDERING_PROPERTY__H_ #define _MITK_VTK_VOLUME_RENDERING_PROPERTY__H_ #include "mitkEnumerationProperty.h" #define VTK_RAY_CAST_COMPOSITE_FUNCTION 1 #define VTK_VOLUME_RAY_CAST_MIP_FUNCTION 2 namespace mitk { /** * Encapsulates the enumeration for volume rendering. Valid values are * (VTK constant/Id/string representation): * VTK_VOLUME_RAY_CAST_MIP_FUNCTION * VTK_RAY_CAST_COMPOSITE_FUNCTION * Default is NULL */ class MITK_CORE_EXPORT VtkVolumeRenderingProperty : public EnumerationProperty { public: mitkClassMacro( VtkVolumeRenderingProperty, EnumerationProperty ); itkNewMacro(VtkVolumeRenderingProperty); mitkNewMacro1Param(VtkVolumeRenderingProperty, const IdType&); mitkNewMacro1Param(VtkVolumeRenderingProperty, const std::string&); + virtual BaseProperty& operator=(const BaseProperty& other) { return Superclass::operator=(other); } + /** * Returns the current volume rendering type */ virtual int GetRenderingType(); /** * Sets the rendering type to VTK_VOLUME_RAY_CAST_MIP_FUNCTION */ virtual void SetRenderingTypeToMIP(); /** * Sets the rendering type to VTK_RAY_CAST_COMPOSITE_FUNCTION */ virtual void SetRenderingTypeToComposite(); protected: /** Sets rendering type to default (VTK_RAY_CAST_COMPOSITE_FUNCTION). */ VtkVolumeRenderingProperty( ); /** * Constructor. Sets rendering type to the given value. */ VtkVolumeRenderingProperty( const IdType& value ); /** * Constructor. Sets rendering type to the given value. */ VtkVolumeRenderingProperty( const std::string& value ); /** * this function is overridden as protected, so that the user may not add * additional invalid rendering types. */ virtual bool AddEnum( const std::string& name, const IdType& id ); /** * Adds the enumeration types as defined by vtk to the list of known * enumeration values. */ virtual void AddRenderingTypes(); }; } // end of namespace mitk #endif diff --git a/Core/Code/DataManagement/mitkWeakPointerProperty.h b/Core/Code/DataManagement/mitkWeakPointerProperty.h index dd71bfb88d..bea8d5de23 100644 --- a/Core/Code/DataManagement/mitkWeakPointerProperty.h +++ b/Core/Code/DataManagement/mitkWeakPointerProperty.h @@ -1,56 +1,58 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef MITKWEAKPOINTERPROPERTY_H_HEADER_INCLUDED_C126B791 #define MITKWEAKPOINTERPROPERTY_H_HEADER_INCLUDED_C126B791 #include "mitkCommon.h" #include "mitkBaseProperty.h" #include "itkWeakPointer.h" namespace mitk { //##Documentation //## @brief Property containing a smart-pointer //## //## @ingroup DataManagement class MITK_CORE_EXPORT WeakPointerProperty : public BaseProperty { public: mitkClassMacro(WeakPointerProperty, BaseProperty); mitkNewMacro1Param(WeakPointerProperty, itk::Object*); virtual bool operator==(const BaseProperty& property) const; + virtual BaseProperty& operator=(const BaseProperty& other) { return Superclass::operator=(other); } + virtual ~WeakPointerProperty(); itk::Object::Pointer GetWeakPointer() const; void SetWeakPointer(itk::Object* pointer); protected: itk::WeakPointer m_WeakPointer; WeakPointerProperty(itk::Object* pointer); }; } // namespace mitk #endif /* MITKWEAKPOINTERPROPERTY_H_HEADER_INCLUDED_C126B791 */ diff --git a/Core/Code/IO/mitkLookupTableProperty.h b/Core/Code/IO/mitkLookupTableProperty.h index 2592838c26..89744d02ac 100755 --- a/Core/Code/IO/mitkLookupTableProperty.h +++ b/Core/Code/IO/mitkLookupTableProperty.h @@ -1,64 +1,66 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef MITKLookupTablePROPERTY_H_HEADER_INCLUDED_C10EEAA8 #define MITKLookupTablePROPERTY_H_HEADER_INCLUDED_C10EEAA8 #include "mitkCommon.h" #include "mitkBaseProperty.h" #include "mitkLookupTable.h" namespace mitk { //##Documentation //## @brief Property for LookupTable data //## //## @ingroup DataManagement class MITK_CORE_EXPORT LookupTableProperty : public BaseProperty { protected: LookupTable::Pointer m_LookupTable; LookupTableProperty(); LookupTableProperty(const mitk::LookupTable::Pointer lut); // LookupTableProperty(const mitk::LookupTable& aLookupTable); public: mitkClassMacro(LookupTableProperty, BaseProperty); itkNewMacro(LookupTableProperty); mitkNewMacro1Param(LookupTableProperty, const mitk::LookupTable::Pointer); + virtual BaseProperty& operator=(const BaseProperty& other) { return Superclass::operator=(other); } + virtual ~LookupTableProperty(); virtual bool operator==(const BaseProperty& property) const; itkGetObjectMacro(LookupTable, LookupTable ); void SetLookupTable(const mitk::LookupTable::Pointer aLookupTable); }; } // namespace mitk #endif /* MITKLookupTablePROPERTY_H_HEADER_INCLUDED_C10EEAA8 */ diff --git a/Core/Code/Rendering/mitkGeometry2DDataVtkMapper3D.cpp b/Core/Code/Rendering/mitkGeometry2DDataVtkMapper3D.cpp index 5d42144101..310e33db68 100644 --- a/Core/Code/Rendering/mitkGeometry2DDataVtkMapper3D.cpp +++ b/Core/Code/Rendering/mitkGeometry2DDataVtkMapper3D.cpp @@ -1,713 +1,713 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "mitkGeometry2DDataVtkMapper3D.h" #include "mitkImageMapperGL2D.h" #include "mitkLookupTableProperty.h" #include "mitkSmartPointerProperty.h" #include "mitkSurface.h" #include "mitkVtkRepresentationProperty.h" #include "mitkWeakPointerProperty.h" #include "mitkNodePredicateDataType.h" #include "mitkNodePredicateOr.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace mitk { Geometry2DDataVtkMapper3D::Geometry2DDataVtkMapper3D() : m_NormalsActorAdded(false), m_DataStorage(NULL) { m_EdgeTuber = vtkTubeFilter::New(); m_EdgeMapper = vtkPolyDataMapper::New(); m_SurfaceCreator = Geometry2DDataToSurfaceFilter::New(); m_SurfaceCreatorBoundingBox = BoundingBox::New(); m_SurfaceCreatorPointsContainer = BoundingBox::PointsContainer::New(); m_Edges = vtkFeatureEdges::New(); m_Edges->BoundaryEdgesOn(); m_Edges->FeatureEdgesOff(); m_Edges->NonManifoldEdgesOff(); m_Edges->ManifoldEdgesOff(); m_EdgeTransformer = vtkTransformPolyDataFilter::New(); m_NormalsTransformer = vtkTransformPolyDataFilter::New(); m_EdgeActor = vtkActor::New(); m_BackgroundMapper = vtkPolyDataMapper::New(); m_BackgroundActor = vtkActor::New(); m_Prop3DAssembly = vtkAssembly::New(); m_ImageAssembly = vtkAssembly::New(); m_SurfaceCreatorBoundingBox->SetPoints( m_SurfaceCreatorPointsContainer ); m_Cleaner = vtkCleanPolyData::New(); m_Cleaner->PieceInvariantOn(); m_Cleaner->ConvertLinesToPointsOn(); m_Cleaner->ConvertPolysToLinesOn(); m_Cleaner->ConvertStripsToPolysOn(); m_Cleaner->PointMergingOn(); // Make sure that the FeatureEdge algorithm is initialized with a "valid" // (though empty) input vtkPolyData *emptyPolyData = vtkPolyData::New(); m_Cleaner->SetInput( emptyPolyData ); emptyPolyData->Delete(); m_Edges->SetInput(m_Cleaner->GetOutput()); m_EdgeTransformer->SetInput( m_Edges->GetOutput() ); m_EdgeTuber->SetInput( m_EdgeTransformer->GetOutput() ); m_EdgeTuber->SetVaryRadiusToVaryRadiusOff(); m_EdgeTuber->SetNumberOfSides( 12 ); m_EdgeTuber->CappingOn(); m_EdgeMapper->SetInput( m_EdgeTuber->GetOutput() ); m_EdgeMapper->ScalarVisibilityOff(); m_BackgroundMapper->SetInput(emptyPolyData); m_EdgeActor->SetMapper( m_EdgeMapper ); m_BackgroundActor->GetProperty()->SetAmbient( 0.5 ); m_BackgroundActor->GetProperty()->SetColor( 0.0, 0.0, 0.0 ); m_BackgroundActor->GetProperty()->SetOpacity( 1.0 ); m_BackgroundActor->SetMapper( m_BackgroundMapper ); vtkProperty * backfaceProperty = m_BackgroundActor->MakeProperty(); backfaceProperty->SetColor( 0.0, 0.0, 0.0 ); m_BackgroundActor->SetBackfaceProperty( backfaceProperty ); backfaceProperty->Delete(); m_FrontHedgeHog = vtkHedgeHog::New(); m_BackHedgeHog = vtkHedgeHog::New(); m_FrontNormalsMapper = vtkPolyDataMapper::New(); m_FrontNormalsMapper->SetInput( m_FrontHedgeHog->GetOutput() ); m_BackNormalsMapper = vtkPolyDataMapper::New(); m_Prop3DAssembly->AddPart( m_EdgeActor ); m_Prop3DAssembly->AddPart( m_ImageAssembly ); m_FrontNormalsActor = vtkActor::New(); m_FrontNormalsActor->SetMapper(m_FrontNormalsMapper); m_BackNormalsActor = vtkActor::New(); m_BackNormalsActor->SetMapper(m_BackNormalsMapper); m_DefaultLookupTable = vtkLookupTable::New(); m_DefaultLookupTable->SetTableRange( -1024.0, 4096.0 ); m_DefaultLookupTable->SetSaturationRange( 0.0, 0.0 ); m_DefaultLookupTable->SetHueRange( 0.0, 0.0 ); m_DefaultLookupTable->SetValueRange( 0.0, 1.0 ); m_DefaultLookupTable->Build(); m_DefaultLookupTable->SetTableValue( 0, 0.0, 0.0, 0.0, 0.0 ); m_ImageMapperDeletedCommand = MemberCommandType::New(); m_ImageMapperDeletedCommand->SetCallbackFunction( this, &Geometry2DDataVtkMapper3D::ImageMapperDeletedCallback ); } Geometry2DDataVtkMapper3D::~Geometry2DDataVtkMapper3D() { m_ImageAssembly->Delete(); m_Prop3DAssembly->Delete(); m_EdgeTuber->Delete(); m_EdgeMapper->Delete(); m_EdgeTransformer->Delete(); m_Cleaner->Delete(); m_Edges->Delete(); m_NormalsTransformer->Delete(); m_EdgeActor->Delete(); m_BackgroundMapper->Delete(); m_BackgroundActor->Delete(); m_DefaultLookupTable->Delete(); m_FrontNormalsMapper->Delete(); m_FrontNormalsActor->Delete(); m_FrontHedgeHog->Delete(); m_BackNormalsMapper->Delete(); m_BackNormalsActor->Delete(); m_BackHedgeHog->Delete(); // Delete entries in m_ImageActors list one by one m_ImageActors.clear(); LookupTablePropertiesList::iterator it; for(it = m_LookupTableProperties.begin(); it != m_LookupTableProperties.end();++it) { if ( it->second.LookupTableSource != NULL ) { it->second.LookupTableSource->Delete(); it->second.LookupTableSource = NULL; } } m_DataStorage = NULL; } vtkProp* Geometry2DDataVtkMapper3D::GetVtkProp(mitk::BaseRenderer * /*renderer*/) { if ( (this->GetDataNode() != NULL ) && (m_ImageAssembly != NULL) ) { // Do not transform the entire Prop3D assembly, but only the image part // here. The colored frame is transformed elsewhere (via m_EdgeTransformer), // since only vertices should be transformed there, not the poly data // itself, to avoid distortion for anisotropic datasets. m_ImageAssembly->SetUserTransform( this->GetDataNode()->GetVtkTransform() ); } return m_Prop3DAssembly; } void Geometry2DDataVtkMapper3D::UpdateVtkTransform(mitk::BaseRenderer * /*renderer*/) { m_ImageAssembly->SetUserTransform( this->GetDataNode()->GetVtkTransform(this->GetTimestep()) ); } const Geometry2DData* Geometry2DDataVtkMapper3D::GetInput() { return static_cast ( GetData() ); } void Geometry2DDataVtkMapper3D::SetDataStorageForTexture(mitk::DataStorage* storage) { if(storage != NULL && m_DataStorage != storage ) { m_DataStorage = storage; this->Modified(); } } void Geometry2DDataVtkMapper3D::ImageMapperDeletedCallback( itk::Object *caller, const itk::EventObject& /*event*/ ) { ImageMapperGL2D *imageMapper = dynamic_cast< ImageMapperGL2D * >( caller ); if ( (imageMapper != NULL) ) { if ( m_ImageActors.count( imageMapper ) > 0) { m_ImageActors[imageMapper].m_Sender = NULL; // sender is already destroying itself m_ImageActors.erase( imageMapper ); } if ( m_LookupTableProperties.count( imageMapper ) > 0 ) { m_LookupTableProperties[imageMapper].LookupTableSource->Delete(); m_LookupTableProperties.erase( imageMapper ); } } } - void Geometry2DDataVtkMapper3D::GenerateData(BaseRenderer* renderer) + void Geometry2DDataVtkMapper3D::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(); if ( !this->IsVisible(renderer) ) { // 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(); m_EdgeActor->VisibilityOn(); Geometry2DData::Pointer input = const_cast< Geometry2DData * >(this->GetInput()); if (input.IsNotNull() && (input->GetGeometry2D() != NULL)) { SmartPointerProperty::Pointer surfacecreatorprop; surfacecreatorprop = dynamic_cast< SmartPointerProperty * >(GetDataNode()->GetProperty("surfacegeometry", renderer)); if ( (surfacecreatorprop.IsNull()) || (surfacecreatorprop->GetSmartPointer().IsNull()) || ((m_SurfaceCreator = dynamic_cast (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 Geometry2D with the reference geometry bounds (if available) if ( input->GetGeometry2D()->HasReferenceGeometry() ) { Geometry3D *referenceGeometry = input->GetGeometry2D()->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 Geometry2D 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->SetInput( surface->GetVtkPolyData() ); m_NormalsTransformer->SetTransform(node->GetVtkTransform(this->GetTimestep()) ); m_FrontHedgeHog->SetInput( m_NormalsTransformer->GetOutput() ); m_FrontHedgeHog->SetVectorModeToUseNormal(); m_FrontHedgeHog->SetScaleFactor( invertNormals ? 1.0 : -1.0 ); m_FrontNormalsActor->GetProperty()->SetColor( frontColor[0], frontColor[1], frontColor[2] ); m_BackHedgeHog->SetInput( m_NormalsTransformer->GetOutput() ); m_BackHedgeHog->SetVectorModeToUseNormal(); m_BackHedgeHog->SetScaleFactor( invertNormals ? -1.0 : 1.0 ); 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->SetInput( surface->GetVtkPolyData() ); m_ImageAssembly->AddPart( m_BackgroundActor ); LayerSortedActorList layerSortedActors; // Traverse the data tree to find nodes resliced by ImageMapperGL2D mitk::NodePredicateOr::Pointer p = mitk::NodePredicateOr::New(); //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->SetInput(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(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() ); } void Geometry2DDataVtkMapper3D::ProcessNode( DataNode * node, BaseRenderer* renderer, Surface * surface, LayerSortedActorList &layerSortedActors ) { if ( node != NULL ) { //we need to get the information from the 2D mapper to render the texture on the 3D plane ImageMapperGL2D *imageMapper = dynamic_cast< ImageMapperGL2D * >( node->GetMapper(1) ); //GetMapper(1) provides the 2D mapper for the data node //if there is a 2D mapper, which is not the standard image mapper... if(!imageMapper && node->GetMapper(1)) { //... check if it is the composite mapper std::string cname(node->GetMapper(1)->GetNameOfClass()); if(!cname.compare("CompositeMapper")) //string.compare returns 0 if the two strings are equal. { //get the standard image mapper. //This is a special case in MITK and does only work for the CompositeMapper. imageMapper = dynamic_cast( node->GetMapper(3) ); } } if ( (node->IsVisible(renderer)) && imageMapper ) { WeakPointerProperty::Pointer rendererProp = dynamic_cast< WeakPointerProperty * >(GetDataNode()->GetPropertyList()->GetProperty("renderer")); if ( rendererProp.IsNotNull() ) { BaseRenderer::Pointer planeRenderer = dynamic_cast< BaseRenderer * >(rendererProp->GetWeakPointer().GetPointer()); if ( planeRenderer.IsNotNull() ) { // If it has not been initialized already in a previous pass, // generate an actor, a lookup table and a texture object to // render the image associated with the ImageMapperGL2D. vtkActor *imageActor; vtkDataSetMapper *dataSetMapper = NULL; vtkLookupTable *lookupTable; vtkTexture *texture; if ( m_ImageActors.count( imageMapper ) == 0 ) { dataSetMapper = vtkDataSetMapper::New(); //Enable rendering without copying the image. dataSetMapper->ImmediateModeRenderingOn(); lookupTable = vtkLookupTable::New(); lookupTable->DeepCopy( m_DefaultLookupTable ); texture = vtkTexture::New(); texture->SetLookupTable( lookupTable ); texture->RepeatOff(); imageActor = vtkActor::New(); imageActor->GetProperty()->SetAmbient( 0.5 ); imageActor->SetMapper( dataSetMapper ); imageActor->SetTexture( texture ); // Make imageActor the sole owner of the mapper and texture // objects lookupTable->UnRegister( NULL ); dataSetMapper->UnRegister( NULL ); texture->UnRegister( NULL ); // Store the actor so that it may be accessed in following // passes. m_ImageActors[imageMapper].Initialize(imageActor, imageMapper, m_ImageMapperDeletedCommand); } else { // Else, retrieve the actor and associated objects from the // previous pass. imageActor = m_ImageActors[imageMapper].m_Actor; dataSetMapper = (vtkDataSetMapper *)imageActor->GetMapper(); texture = imageActor->GetTexture(); //BUG (#1551) added dynamic cast for VTK5.2 support #if ( ( VTK_MAJOR_VERSION >= 5 ) && ( VTK_MINOR_VERSION>=2) ) lookupTable = dynamic_cast(texture->GetLookupTable()); #else lookupTable = texture->GetLookupTable(); #endif } // Set poly data new each time its object changes (e.g. when // switching between planar and curved geometries) if ( (dataSetMapper != NULL) && (dataSetMapper->GetInput() != surface->GetVtkPolyData()) ) { dataSetMapper->SetInput( surface->GetVtkPolyData() ); } imageActor->GetMapper()->GetInput()->Update(); imageActor->GetMapper()->Update(); // We have to do this before GenerateAllData() is called // since there may be no RendererInfo for renderer yet, // thus GenerateAllData won't update the (non-existing) // RendererInfo for renderer. By calling GetRendererInfo // a RendererInfo will be created for renderer (if it does not // exist yet). imageMapper->GetRendererInfo( planeRenderer ); imageMapper->GenerateAllData(); // ensure the right openGL context, as 3D widgets may render and take their plane texture from 2D image mappers renderer->GetRenderWindow()->MakeCurrent(); // Retrieve and update image to be mapped const ImageMapperGL2D::RendererInfo *rit = imageMapper->GetRendererInfo( planeRenderer ); if(rit->m_Image != NULL) { rit->m_Image->Update(); //set the 2D image as texture for the 3D plane texture->SetInput( rit->m_Image ); //default level window ScalarType windowMin = 0.0; ScalarType windowMax = 255.0; LevelWindow levelWindow; bool binary = false; node->GetBoolProperty( "binary", binary, renderer ); // check for "use color" bool useColor = false; node->GetBoolProperty( "use color", useColor, planeRenderer ); // VTK (mis-)interprets unsigned char (binary) images as color images; // So, we must manually turn on their mapping through a (gray scale) lookup table; texture->SetMapColorScalarsThroughLookupTable(binary); //if we have a binary image, the range is just 0 to 1 if( binary ) { windowMin = 0; windowMax = 1; useColor = true; } // check for level-window-prop and use it if it exists if( !binary && ( node->GetLevelWindow( levelWindow, planeRenderer, "levelWindow" ) || node->GetLevelWindow( levelWindow, planeRenderer ) ) ) { windowMin = levelWindow.GetLowerWindowBound(); windowMax = levelWindow.GetUpperWindowBound(); } vtkLookupTable *lookupTableSource; // check for LookupTable LookupTableProperty::Pointer lookupTableProp; lookupTableProp = dynamic_cast< LookupTableProperty * >(node->GetPropertyList()->GetProperty( "LookupTable" )); // If there is a lookup table supplied and we don't // want to use the color property, use it; //otherwise, use the default grayscale table if ( lookupTableProp.IsNotNull() && !useColor ) { lookupTableSource = lookupTableProp->GetLookupTable()->GetVtkLookupTable(); } else { lookupTableSource = m_DefaultLookupTable; } LookupTableProperties &lutProperties = m_LookupTableProperties[imageMapper]; // If there has been some change since the last pass which // makes it necessary to re-build the lookup table, do it. if ( (lutProperties.LookupTableSource != lookupTableSource) || (lutProperties.windowMin != windowMin) || (lutProperties.windowMax != windowMax) ) { // Note the values for the next pass (lutProperties is a // reference to the list entry!) if ( lutProperties.LookupTableSource != NULL ) { lutProperties.LookupTableSource->Delete(); } lutProperties.LookupTableSource = lookupTableSource; lutProperties.LookupTableSource->Register( NULL ); lutProperties.windowMin = windowMin; lutProperties.windowMax = windowMax; lookupTable->DeepCopy( lookupTableSource ); lookupTable->SetRange( windowMin, windowMax ); } //get the color float rgb[3] = { 1.0, 1.0, 1.0 }; node->GetColor( rgb, renderer ); // Apply color property (of the node, not of the plane) // if we want to use the color if(useColor) { imageActor->GetProperty()->SetColor( rgb[0], rgb[1], rgb[2] ); } else //else default color = white to avoid site effects from the lookuptable { imageActor->GetProperty()->SetColor( 1, 1, 1 ); } // Apply opacity property (of the node, not of the plane) float opacity = 0.999; node->GetOpacity( opacity, renderer ); imageActor->GetProperty()->SetOpacity( opacity ); // Set texture interpolation on/off bool textureInterpolation = node->IsOn( "texture interpolation", renderer ); texture->SetInterpolate( textureInterpolation ); // Store this actor to be added to the actor assembly, sort // by layer int layer = 1; node->GetIntProperty( "layer", layer ); layerSortedActors.insert(std::pair< int, vtkActor * >( layer, imageActor ) ); } } } } } } void Geometry2DDataVtkMapper3D::ActorInfo::Initialize(vtkActor* actor, itk::Object* sender, itk::Command* command) { m_Actor = actor; m_Sender = sender; // Get informed when ImageMapper object is deleted, so that // the data structures built here can be deleted as well m_ObserverID = sender->AddObserver( itk::DeleteEvent(), command ); } Geometry2DDataVtkMapper3D::ActorInfo::ActorInfo() : m_Actor(NULL), m_Sender(NULL), m_ObserverID(0) { } Geometry2DDataVtkMapper3D::ActorInfo::~ActorInfo() { if(m_Sender != NULL) { m_Sender->RemoveObserver(m_ObserverID); } if(m_Actor != NULL) { m_Actor->Delete(); } } } // namespace mitk diff --git a/Core/Code/Rendering/mitkGeometry2DDataVtkMapper3D.h b/Core/Code/Rendering/mitkGeometry2DDataVtkMapper3D.h index a19efee794..fd05eb282a 100644 --- a/Core/Code/Rendering/mitkGeometry2DDataVtkMapper3D.h +++ b/Core/Code/Rendering/mitkGeometry2DDataVtkMapper3D.h @@ -1,234 +1,234 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef MITKGEOMETRY2DDATAVTKMAPPER3D_H_HEADER_INCLUDED_C196C71F #define MITKGEOMETRY2DDATAVTKMAPPER3D_H_HEADER_INCLUDED_C196C71F #include "mitkCommon.h" #include "mitkVtkMapper3D.h" #include "mitkDataStorage.h" #include "mitkGeometry2DDataToSurfaceFilter.h" #include "mitkWeakPointer.h" #include #include class vtkActor; class vtkPolyDataMapper; class vtkDataSetMapper; class vtkLookupTable; class vtkAssembly; class vtkFeatureEdges; class vtkTubeFilter; class vtkTransformPolyDataFilter; class vtkHedgeHog; namespace mitk { class Geometry2DData; class BaseRenderer; class ImageMapperGL2D; class DataStorage; /** * \brief Vtk-based mapper to display a Geometry2D in a 3D window * \ingroup Mapper * * Uses a Geometry2DDataToSurfaceFilter object to create a vtkPolyData representation of a given Geometry2D instance. * Geometry2D may either contain a common flat plane or a curved plane (ThinPlateSplineCurvedGeometry). * * The vtkPolyData object is then decorated by a colored tube on the edges and by image textures if possible * (currently this requires that there is a 2D render window rendering the same geometry as this mapper). * * Properties that influence rendering are: * * - \b "color": (ColorProperty) Color of the tubed frame. * - \b "xresolution": (FloatProperty) Resolution (=number of tiles) in x direction. Only relevant for ThinPlateSplineCurvedGeometry * - \b "yresolution": (FloatProperty) Resolution (=number of tiles) in y direction. Only relevant for ThinPlateSplineCurvedGeometry * - \b "draw normals 3D": (BoolProperty) If true, a vtkHedgeHog is used to display normals for the generated surface object. Useful to distinguish front and back of a plane. Hedgehogs are colored according to "front color" and "back color" * - \b "color two sides": (BoolProperty) If true, front and back side of the plane are colored differently ("front color" and "back color") * - \b "invert normals": (BoolProperty) Inverts front/back for display. * - \b "front color": (ColorProperty) Color for front side of the plane * - \b "back color": (ColorProperty) Color for back side of the plane * - \b "material.representation": (BoolProperty) Choose the representation to draw the mesh in (Surface, Wireframe, Point Cloud) * - \b "surfacegeometry": TODO: Add documentation * - \b "LookupTable": (LookupTableProperty) Set the lookuptable to render with. * * Note: The following properties are set for each image individually, and thus, also influence the rendering of this mapper: * * - \b "texture interpolation": (BoolProperty) Turn on/off the texture interpolation of each image * - \b "use color": (BoolProperty) Decide whether we want to use the color property or a lookuptable. * - \b "binary": (BoolProperty) Binary image handling: Color the value=1.0 with the color property and make the background (value=0.0) of the image translucent. * - \b "layer": (IntProperty) Controls what image is considered "on top" of another. In the case that two should inhabit the same space, higher layer occludes lower layer. * - \b "opacity": (FloatProperty) Set the opacity for each rendered image. * - \b "color": (FloatProperty) Set the color for each rendered image. * * The internal filter pipeline which combines a (sometimes deformed) 2D surface * with a nice frame and image textures is illustrated in the following sketch: * * \image html mitkGeometry2DDataVtkMapper3D.png "Internal filter pipeline" * */ class MITK_CORE_EXPORT Geometry2DDataVtkMapper3D : public VtkMapper3D { public: mitkClassMacro(Geometry2DDataVtkMapper3D, VtkMapper3D); itkNewMacro(Geometry2DDataVtkMapper3D); /** * Overloaded since the displayed color-frame of the image mustn't be * transformed after generation of poly data, but before (vertex coordinates * only) */ virtual vtkProp *GetVtkProp(mitk::BaseRenderer *renderer); virtual void UpdateVtkTransform(mitk::BaseRenderer *renderer); /** * \brief Get the Geometry2DData to map */ virtual const Geometry2DData *GetInput(); /** * \brief All images found when traversing the (sub-) tree starting at * \a iterator which are resliced by an ImageMapperGL2D will be mapped. * This method is used to set the data storage to traverse. This offers * the possibility to use this mapper for other data storages (not only * the default data storage). */ virtual void SetDataStorageForTexture(mitk::DataStorage* storage); protected: typedef std::multimap< int, vtkActor * > LayerSortedActorList; Geometry2DDataVtkMapper3D(); virtual ~Geometry2DDataVtkMapper3D(); - virtual void GenerateData(BaseRenderer* renderer); + virtual void GenerateDataForRenderer(BaseRenderer* renderer); void ProcessNode( DataNode * node, BaseRenderer* renderer, Surface * surface, LayerSortedActorList &layerSortedActors ); void ImageMapperDeletedCallback( itk::Object *caller, const itk::EventObject &event ); /** \brief general PropAssembly to hold the entire scene */ vtkAssembly *m_Prop3DAssembly; /** \brief PropAssembly to hold the planes */ vtkAssembly *m_ImageAssembly; Geometry2DDataToSurfaceFilter::Pointer m_SurfaceCreator; BoundingBox::Pointer m_SurfaceCreatorBoundingBox; BoundingBox::PointsContainer::Pointer m_SurfaceCreatorPointsContainer; /** \brief Edge extractor for tube-shaped frame */ vtkFeatureEdges *m_Edges; /** \brief Filter to apply object transform to the extracted edges */ vtkTransformPolyDataFilter *m_EdgeTransformer; /** \brief Source to create the tube-shaped frame */ vtkTubeFilter *m_EdgeTuber; /** \brief Mapper for the tube-shaped frame */ vtkPolyDataMapper *m_EdgeMapper; /** \brief Actor for the tube-shaped frame */ vtkActor *m_EdgeActor; /** \brief Mapper for black plane background */ vtkPolyDataMapper *m_BackgroundMapper; /** \brief Actor for black plane background */ vtkActor *m_BackgroundActor; /** \brief Transforms the suface before applying the glyph filter */ vtkTransformPolyDataFilter* m_NormalsTransformer; /** \brief Mapper for normals representation (thin lines) */ vtkPolyDataMapper* m_FrontNormalsMapper; vtkPolyDataMapper* m_BackNormalsMapper; /** \brief Generates lines for surface normals */ vtkHedgeHog* m_FrontHedgeHog; vtkHedgeHog* m_BackHedgeHog; /** \brief Actor to hold the normals arrows */ vtkActor* m_FrontNormalsActor; vtkActor* m_BackNormalsActor; /** Cleans the polyline in order to avoid phantom boundaries */ vtkCleanPolyData *m_Cleaner; /** Internal flag, if actors for normals are already added to m_Prop3DAssembly*/ bool m_NormalsActorAdded; /** \brief The DataStorage defines which part of the data tree is traversed for renderering. */ mitk::WeakPointer m_DataStorage; /** A default grayscale lookup-table, used for reference */ vtkLookupTable *m_DefaultLookupTable; class MITK_CORE_EXPORT ActorInfo { public: vtkActor * m_Actor; // we do not need a smart-pointer, because we delete our // connection, when the referenced mapper is destroyed itk::Object* m_Sender; unsigned long m_ObserverID; void Initialize(vtkActor* actor, itk::Object* sender, itk::Command* command); ActorInfo(); ~ActorInfo(); }; /** \brief List holding the vtkActor to map the image into 3D for each * ImageMapper */ typedef std::map< ImageMapperGL2D *, ActorInfo > ActorList; ActorList m_ImageActors; struct LookupTableProperties { LookupTableProperties() : LookupTableSource( NULL ), windowMin( 0.0 ), windowMax( 4096.0 ) {} vtkLookupTable *LookupTableSource; vtkFloatingPointType windowMin; vtkFloatingPointType windowMax; }; typedef std::map< ImageMapperGL2D *, LookupTableProperties > LookupTablePropertiesList; /** \brief List holding some lookup table properties of the previous pass */ LookupTablePropertiesList m_LookupTableProperties; // responsiblity to remove the observer upon its destruction typedef itk::MemberCommand< Geometry2DDataVtkMapper3D > MemberCommandType; MemberCommandType::Pointer m_ImageMapperDeletedCommand; }; } // namespace mitk #endif /* MITKGEOMETRY2DDATAVTKMAPPER3D_H_HEADER_INCLUDED_C196C71F */ diff --git a/Core/Code/Rendering/mitkImageMapperGL2D.cpp b/Core/Code/Rendering/mitkImageMapperGL2D.cpp index 8bc256e8c6..0425dae128 100644 --- a/Core/Code/Rendering/mitkImageMapperGL2D.cpp +++ b/Core/Code/Rendering/mitkImageMapperGL2D.cpp @@ -1,1392 +1,1392 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "mitkImageMapperGL2D.h" #include "widget.h" #include "picimage.h" #include "pic2vtk.h" #include "mitkTimeSlicedGeometry.h" #include "mitkPlaneGeometry.h" #include "mitkDataNode.h" #include "mitkVtkPropRenderer.h" #include "mitkLookupTableProperty.h" #include "mitkProperties.h" #include "mitkLevelWindowProperty.h" #include "mitkVtkResliceInterpolationProperty.h" #include "mitkVolumeCalculator.h" #include "mitkImageSliceSelector.h" #include "mitkAbstractTransformGeometry.h" #include "mitkDataNodeFactory.h" #include "mitkResliceMethodProperty.h" #include #include #include #include #include #include #include #include #include #include #include "vtkMitkThickSlicesFilter.h" #include "itkRGBAPixel.h" int mitk::ImageMapperGL2D::numRenderer = 0; mitk::ImageMapperGL2D::ImageMapperGL2D() { } mitk::ImageMapperGL2D::~ImageMapperGL2D() { this->Clear(); this->InvokeEvent( itk::DeleteEvent() ); } void mitk::ImageMapperGL2D::Paint( mitk::BaseRenderer *renderer ) { if ( !this->IsVisible( renderer ) ) { return; } this->Update( renderer ); RendererInfo &rendererInfo = this->AccessRendererInfo( renderer ); iil4mitkPicImage *image = rendererInfo.Get_iil4mitkImage(); if ( ( image == NULL ) || ( image->image() == NULL ) ) { return; } const mitk::DisplayGeometry *displayGeometry = renderer->GetDisplayGeometry(); Vector2D topLeft = displayGeometry->GetOriginInMM(); Vector2D bottomRight = topLeft + displayGeometry->GetSizeInMM(); topLeft[0] *= rendererInfo.m_PixelsPerMM[0]; topLeft[1] *= rendererInfo.m_PixelsPerMM[1]; bottomRight[0] *= rendererInfo.m_PixelsPerMM[0]; bottomRight[1] *= rendererInfo.m_PixelsPerMM[1]; topLeft += rendererInfo.m_Overlap; bottomRight += rendererInfo.m_Overlap; Vector2D diag = ( topLeft - bottomRight ); //float size = diag.GetNorm(); glMatrixMode( GL_PROJECTION ); glLoadIdentity(); glOrtho( topLeft[0], bottomRight[0], topLeft[1], bottomRight[1], 0.0, 1.0 ); glMatrixMode( GL_MODELVIEW ); glDepthMask(GL_FALSE); // Define clipping planes to clip the image according to the bounds // correlating to the current world geometry. The "extent" of the bounds // needs to be enlarged by an "overlap" factor, in order to make the // remaining area are large enough to cover rotated planes also. // // Note that this can be improved on, by not merely using a large enough // rectangle for clipping, but using the side surfaces of the transformed // 3D bounds as clipping planes instead. This would clip even rotates // planes at their exact intersection lines with the 3D bounding box. //GLdouble eqn0[4] = { 1.0, 0.0, 0.0, 0.0 }; //GLdouble eqn1[4] = { -1.0, 0.0, 0.0, rendererInfo.m_Extent[0] // + 2.0 * rendererInfo.m_Overlap[0]/* - rendererInfo.m_PixelsPerMM[0]*/ }; //MITK_INFO << "X: " << rendererInfo.m_Extent[0] // + 2.0 * rendererInfo.m_Overlap[0] - rendererInfo.m_PixelsPerMM[0] << std::endl; //GLdouble eqn2[4] = { 0.0, 1.0, 0.0, 0.0 }; //GLdouble eqn3[4] = { 0.0, -1.0, 0.0, rendererInfo.m_Extent[1] // + 2.0 * rendererInfo.m_Overlap[1]/* - rendererInfo.m_PixelsPerMM[1]*/ }; //MITK_INFO << "Y:" << rendererInfo.m_Extent[1] // + 2.0 * rendererInfo.m_Overlap[1] - rendererInfo.m_PixelsPerMM[1] << std::endl; // IW commented out the previous lines and reverted to rev. 9358 // (version before rev. 9443) See bug #625 GLdouble eqn0[4] = {0.0, 1.0, 0.0, 0.0}; GLdouble eqn1[4] = {1.0, 0.0, 0.0, 0.0}; GLdouble eqn2[4] = {-1.0, 0.0 , 0.0, image->width()}; GLdouble eqn3[4] = {0, -1.0, 0.0, image->height() }; glClipPlane( GL_CLIP_PLANE0, eqn0 ); glEnable( GL_CLIP_PLANE0 ); glClipPlane( GL_CLIP_PLANE1, eqn1 ); glEnable( GL_CLIP_PLANE1 ); glClipPlane( GL_CLIP_PLANE2, eqn2 ); glEnable( GL_CLIP_PLANE2 ); glClipPlane( GL_CLIP_PLANE3, eqn3 ); glEnable( GL_CLIP_PLANE3 ); // Render the image image->setInterpolation( rendererInfo.m_TextureInterpolation ); image->display( renderer->GetRenderWindow() ); // Disable the utilized clipping planes glDisable( GL_CLIP_PLANE0 ); glDisable( GL_CLIP_PLANE1 ); glDisable( GL_CLIP_PLANE2 ); glDisable( GL_CLIP_PLANE3 ); // display volume property, if it exists and should be displayed bool shouldShowVolume = false, binary = false; float segmentationVolume = -1.0; mitk::DataNode *node = this->GetDataNode(); mitk::Image* mitkimage = dynamic_cast(node->GetData()); // Check if a volume in ml can be drawn in the image. // This is the case if: // 1. The property "showVolume" is true AND [ // 2.1 The image has a volume stored as property (3D case) OR // 2.2 The image is 3D or 4D and binary, so the volume can be calculated ] if ( (node->GetBoolProperty("showVolume", shouldShowVolume)) && (shouldShowVolume) && ( (node->GetFloatProperty("volume", segmentationVolume) ) || (mitkimage != NULL && mitkimage->GetDimension() >= 3 && node->GetBoolProperty("binary", binary) && binary) ) ) { // calculate screen position for text by searching for the object border mitkIpPicDescriptor* pic = image->image(); // search object border in current slice unsigned int s_x = 0; unsigned int s_y = 0; unsigned int s_n = 0; for(unsigned int y=0;yn[1];y++) for(unsigned int x=0;xn[0];x++) { bool set=false; switch ( pic->bpe ) { case 8: { mitkIpInt1_t *current = static_cast< mitkIpInt1_t *>( pic->data ); current += y*pic->n[0] + x; if(current[0]) set=true; break; } case 16: { mitkIpInt2_t *current = static_cast< mitkIpInt2_t *>( pic->data ); current += y*pic->n[0] + x; if(current[0]) set=true; break; } case 24: { mitkIpInt1_t *current = static_cast< mitkIpInt1_t *>( pic->data ); current += ( y*pic->n[0] + x )*3; if(current[0]||current[1]||current[2]) set=true; break; } } if(set) { if ( x > s_x ) s_x = x; if ( y > s_y ) s_y = y; s_n++; } } // if an object has been found, draw annotation if ( s_n>0 ) { // make sure a segmentation volume is present if( segmentationVolume <= 0 ) { // if not, check if the image is truly binary if( mitkimage->GetScalarValueMax( renderer->GetTimeStep() ) == 1 ) { // if yes, get the volume from image statistics segmentationVolume = mitk::VolumeCalculator::ComputeVolume( mitkimage->GetSlicedGeometry()->GetSpacing(), mitkimage->GetCountOfMaxValuedVoxelsNoRecompute(renderer->GetTimeStep())); } } // create text std::stringstream volumeString; volumeString << std::fixed << std::setprecision(1) << segmentationVolume; std::string unit; if (node->GetStringProperty("volume annotation unit", unit)) { volumeString << " " << unit; } else { volumeString << " ml"; } // draw text mitk::VtkPropRenderer* OpenGLrenderer = dynamic_cast( renderer ); //calc index pos Point2D pt2D; pt2D[0] = s_x; pt2D[1] = s_y; //calc index pos with spacing const Geometry2D *worldGeometry = renderer->GetCurrentWorldGeometry2D(); //calc display coord worldGeometry->IndexToWorld( pt2D, pt2D ); displayGeometry->WorldToDisplay( pt2D, pt2D ); mitk::ColorProperty::Pointer annotationColorProp; mitk::Color annotationColor; annotationColor.Set(0,1,0); if (node->GetProperty(annotationColorProp, "volume annotation color")) { annotationColor = annotationColorProp->GetColor(); } bool hover = false; bool selected = false; GetDataNode()->GetBoolProperty("binaryimage.ishovering", hover, renderer); GetDataNode()->GetBoolProperty("selected", selected, renderer); if(hover) { mitk::ColorProperty::Pointer colorprop = dynamic_cast(GetDataNode()->GetProperty ("binaryimage.hoveringcolor", renderer)); if(colorprop.IsNotNull()) annotationColor = colorprop->GetColor(); } if(selected) { mitk::ColorProperty::Pointer colorprop = dynamic_cast(GetDataNode()->GetProperty ("binaryimage.selectedcolor", renderer)); if(colorprop.IsNotNull()) annotationColor = colorprop->GetColor(); } OpenGLrenderer->WriteSimpleText(volumeString.str(), pt2D[0]+1, pt2D[1]-1,0,0,0); //this is a shadow OpenGLrenderer->WriteSimpleText(volumeString.str(), pt2D[0] , pt2D[1] ,annotationColor.GetRed() ,annotationColor.GetGreen() ,annotationColor.GetBlue()); } } //glPushMatrix(); glMatrixMode( GL_PROJECTION ); glLoadIdentity(); glOrtho( 0.0, displayGeometry->GetDisplayWidth(), 0.0, displayGeometry->GetDisplayHeight(), 0.0, 1.0 ); glDepthMask(GL_TRUE); //glMatrixMode( GL_MODELVIEW ); //glPopMatrix(); } const mitk::ImageMapperGL2D::InputImageType * mitk::ImageMapperGL2D::GetInput( void ) { return static_cast< const mitk::ImageMapperGL2D::InputImageType * >( this->GetData() ); } int mitk::ImageMapperGL2D::GetAssociatedChannelNr( mitk::BaseRenderer *renderer ) { RendererInfo &rendererInfo = this->AccessRendererInfo( renderer ); return rendererInfo.GetRendererID(); } void -mitk::ImageMapperGL2D::GenerateData( mitk::BaseRenderer *renderer ) +mitk::ImageMapperGL2D::GenerateDataForRenderer( mitk::BaseRenderer *renderer ) { mitk::Image *input = const_cast< mitk::ImageMapperGL2D::InputImageType * >( this->GetInput() ); input->Update(); if ( input == NULL ) { return; } RendererInfo &rendererInfo = this->AccessRendererInfo( renderer ); rendererInfo.Squeeze(); iil4mitkPicImage *image = new iil4mitkPicImage( 512 ); rendererInfo.Set_iil4mitkImage( image ); this->ApplyProperties( renderer ); const Geometry2D *worldGeometry = renderer->GetCurrentWorldGeometry2D(); if( ( worldGeometry == NULL ) || ( !worldGeometry->IsValid() ) || ( !worldGeometry->GetReferenceGeometry() )) { return; } // check if there is something to display. if ( ! input->IsVolumeSet( this->GetTimestep() ) ) return; Image::RegionType requestedRegion = input->GetLargestPossibleRegion(); requestedRegion.SetIndex( 3, this->GetTimestep() ); requestedRegion.SetSize( 3, 1 ); requestedRegion.SetSize( 4, 1 ); input->SetRequestedRegion( &requestedRegion ); input->Update(); vtkImageData* inputData = input->GetVtkImageData( this->GetTimestep() ); if ( inputData == NULL ) { return; } vtkFloatingPointType spacing[3]; inputData->GetSpacing( spacing ); // how big the area is in physical coordinates: widthInMM x heightInMM pixels mitk::ScalarType widthInMM, heightInMM; // where we want to sample Point3D origin; Vector3D right, bottom, normal; Vector3D rightInIndex, bottomInIndex; // take transform of input image into account const TimeSlicedGeometry *inputTimeGeometry = input->GetTimeSlicedGeometry(); const Geometry3D* inputGeometry = inputTimeGeometry->GetGeometry3D( this->GetTimestep() ); ScalarType mmPerPixel[2]; // Bounds information for reslicing (only reuqired if reference geometry // is present) vtkFloatingPointType bounds[6]; bool boundsInitialized = false; for ( int i = 0; i < 6; ++i ) { bounds[i] = 0.0; } // Do we have a simple PlaneGeometry? if ( dynamic_cast< const PlaneGeometry * >( worldGeometry ) != NULL ) { const PlaneGeometry *planeGeometry = static_cast< const PlaneGeometry * >( worldGeometry ); origin = planeGeometry->GetOrigin(); right = planeGeometry->GetAxisVector( 0 ); bottom = planeGeometry->GetAxisVector( 1 ); normal = planeGeometry->GetNormal(); bool inPlaneResampleExtentByGeometry = false; GetDataNode()->GetBoolProperty( "in plane resample extent by geometry", inPlaneResampleExtentByGeometry, renderer ); if ( inPlaneResampleExtentByGeometry ) { // Resampling grid corresponds to the current world geometry. This // means that the spacing of the output 2D image depends on the // currently selected world geometry, and *not* on the image itself. rendererInfo.m_Extent[0] = worldGeometry->GetExtent( 0 ); rendererInfo.m_Extent[1] = worldGeometry->GetExtent( 1 ); } else { // Resampling grid corresponds to the input geometry. This means that // the spacing of the output 2D image is directly derived from the // associated input image, regardless of the currently selected world // geometry. inputGeometry->WorldToIndex( right, rightInIndex ); inputGeometry->WorldToIndex( bottom, bottomInIndex ); rendererInfo.m_Extent[0] = rightInIndex.GetNorm(); rendererInfo.m_Extent[1] = bottomInIndex.GetNorm(); } // Get the extent of the current world geometry and calculate resampling // spacing therefrom. widthInMM = worldGeometry->GetExtentInMM( 0 ); heightInMM = worldGeometry->GetExtentInMM( 1 ); mmPerPixel[0] = widthInMM / rendererInfo.m_Extent[0]; mmPerPixel[1] = heightInMM / rendererInfo.m_Extent[1]; right.Normalize(); bottom.Normalize(); normal.Normalize(); origin += right * ( mmPerPixel[0] * 0.5 ); origin += bottom * ( mmPerPixel[1] * 0.5 ); widthInMM -= mmPerPixel[0]; heightInMM -= mmPerPixel[1]; // Use inverse transform of the input geometry for reslicing the 3D image rendererInfo.m_Reslicer->SetResliceTransform( inputGeometry->GetVtkTransform()->GetLinearInverse() ); // Set background level to TRANSLUCENT (see Geometry2DDataVtkMapper3D) rendererInfo.m_Reslicer->SetBackgroundLevel( -32768 ); // If a reference geometry does exist (as would usually be the case for // PlaneGeometry), store it in rendererInfo so that we have access to it // in Paint. // // Note: this is currently not strictly required, but could facilitate // correct plane clipping. if ( worldGeometry->GetReferenceGeometry() ) { rendererInfo.m_ReferenceGeometry = worldGeometry->GetReferenceGeometry(); // Calculate the actual bounds of the transformed plane clipped by the // dataset bounding box; this is required for drawing the texture at the // correct position during 3D mapping. boundsInitialized = this->CalculateClippedPlaneBounds( rendererInfo.m_ReferenceGeometry, planeGeometry, bounds ); } } // Do we have an AbstractTransformGeometry? else if ( dynamic_cast< const AbstractTransformGeometry * >( worldGeometry ) ) { const mitk::AbstractTransformGeometry* abstractGeometry = dynamic_cast< const AbstractTransformGeometry * >(worldGeometry); rendererInfo.m_Extent[0] = abstractGeometry->GetParametricExtent(0); rendererInfo.m_Extent[1] = abstractGeometry->GetParametricExtent(1); widthInMM = abstractGeometry->GetParametricExtentInMM(0); heightInMM = abstractGeometry->GetParametricExtentInMM(1); mmPerPixel[0] = widthInMM / rendererInfo.m_Extent[0]; mmPerPixel[1] = heightInMM / rendererInfo.m_Extent[1]; origin = abstractGeometry->GetPlane()->GetOrigin(); right = abstractGeometry->GetPlane()->GetAxisVector(0); right.Normalize(); bottom = abstractGeometry->GetPlane()->GetAxisVector(1); bottom.Normalize(); normal = abstractGeometry->GetPlane()->GetNormal(); normal.Normalize(); // Use a combination of the InputGeometry *and* the possible non-rigid // AbstractTransformGeometry for reslicing the 3D Image vtkGeneralTransform *composedResliceTransform = vtkGeneralTransform::New(); composedResliceTransform->Identity(); composedResliceTransform->Concatenate( inputGeometry->GetVtkTransform()->GetLinearInverse() ); composedResliceTransform->Concatenate( abstractGeometry->GetVtkAbstractTransform() ); rendererInfo.m_Reslicer->SetResliceTransform( composedResliceTransform ); composedResliceTransform->UnRegister( NULL ); // decrease RC // Set background level to BLACK instead of translucent, to avoid // boundary artifacts (see Geometry2DDataVtkMapper3D) rendererInfo.m_Reslicer->SetBackgroundLevel( -1023 ); } else { return; } // Make sure that the image to display has a certain minimum size. if ( (rendererInfo.m_Extent[0] <= 2) && (rendererInfo.m_Extent[1] <= 2) ) { return; } // Initialize the interpolation mode for resampling; switch to nearest // neighbor if the input image is too small. if ( (input->GetDimension() >= 3) && (input->GetDimension(2) > 1) ) { VtkResliceInterpolationProperty *resliceInterpolationProperty; this->GetDataNode()->GetProperty( resliceInterpolationProperty, "reslice interpolation" ); int interpolationMode = VTK_RESLICE_NEAREST; if ( resliceInterpolationProperty != NULL ) { interpolationMode = resliceInterpolationProperty->GetInterpolation(); } switch ( interpolationMode ) { case VTK_RESLICE_NEAREST: rendererInfo.m_Reslicer->SetInterpolationModeToNearestNeighbor(); break; case VTK_RESLICE_LINEAR: rendererInfo.m_Reslicer->SetInterpolationModeToLinear(); break; case VTK_RESLICE_CUBIC: rendererInfo.m_Reslicer->SetInterpolationModeToCubic(); break; } } else { rendererInfo.m_Reslicer->SetInterpolationModeToNearestNeighbor(); } int thickSlicesMode = 0; int thickSlicesNum = 1; // Thick slices parameters if( inputData->GetNumberOfScalarComponents() == 1 ) // for now only single component are allowed { DataNode *dn=renderer->GetCurrentWorldGeometry2DNode(); if(dn) { ResliceMethodProperty *resliceMethodEnumProperty=0; if( dn->GetProperty( resliceMethodEnumProperty, "reslice.thickslices" ) && resliceMethodEnumProperty ) thickSlicesMode = resliceMethodEnumProperty->GetValueAsId(); IntProperty *intProperty=0; if( dn->GetProperty( intProperty, "reslice.thickslices.num" ) && intProperty ) { thickSlicesNum = intProperty->GetValue(); if(thickSlicesNum < 1) thickSlicesNum=1; if(thickSlicesNum > 100) thickSlicesNum=100; } } else { MITK_WARN << "no associated widget plane data tree node found"; } } rendererInfo.m_UnitSpacingImageFilter->SetInput( inputData ); rendererInfo.m_Reslicer->SetInput( rendererInfo.m_UnitSpacingImageFilter->GetOutput() ); //rendererInfo.m_Reslicer->SetOutputOrigin( 0.0, 0.0, 0.0 ); //rendererInfo.m_Reslicer->SetOutputDimensionality( 3 ); rendererInfo.m_PixelsPerMM[0] = 1.0 / mmPerPixel[0]; rendererInfo.m_PixelsPerMM[1] = 1.0 / mmPerPixel[1]; //calulate the originArray and the orientations for the reslice-filter double originArray[3]; itk2vtk( origin, originArray ); rendererInfo.m_Reslicer->SetResliceAxesOrigin( originArray ); double cosines[9]; // direction of the X-axis of the sampled result vnl2vtk( right.Get_vnl_vector(), cosines ); // direction of the Y-axis of the sampled result vnl2vtk( bottom.Get_vnl_vector(), cosines + 3 ); // normal of the plane vnl2vtk( normal.Get_vnl_vector(), cosines + 6 ); rendererInfo.m_Reslicer->SetResliceAxesDirectionCosines( cosines ); int xMin, xMax, yMin, yMax; if ( boundsInitialized ) { // Calculate output extent (integer values) xMin = static_cast< int >( bounds[0] / mmPerPixel[0] + 0.5 ); xMax = static_cast< int >( bounds[1] / mmPerPixel[0] + 0.5 ); yMin = static_cast< int >( bounds[2] / mmPerPixel[1] + 0.5 ); yMax = static_cast< int >( bounds[3] / mmPerPixel[1] + 0.5 ); // Calculate the extent by which the maximal plane (due to plane rotation) // overlaps the regular plane size. rendererInfo.m_Overlap[0] = -xMin; rendererInfo.m_Overlap[1] = -yMin; } else { // If no reference geometry is available, we also don't know about the // maximum plane size; so the overlap is just ignored rendererInfo.m_Overlap.Fill( 0.0 ); xMin = yMin = 0; xMax = static_cast< int >( rendererInfo.m_Extent[0] - rendererInfo.m_PixelsPerMM[0] + 0.5 ); yMax = static_cast< int >( rendererInfo.m_Extent[1] - rendererInfo.m_PixelsPerMM[1] + 0.5 ); } // Disallow huge dimensions if ( (xMax-xMin) * (yMax-yMin) > 4096*4096 ) { return; } // Calculate dataset spacing in plane z direction (NOT spacing of current // world geometry) double dataZSpacing = 1.0; normal.Normalize(); Vector3D normInIndex; inputGeometry->WorldToIndex( normal, normInIndex ); if(thickSlicesMode > 0) { dataZSpacing = 1.0 / normInIndex.GetNorm(); rendererInfo.m_Reslicer->SetOutputDimensionality( 3 ); rendererInfo.m_Reslicer->SetOutputExtent( xMin, xMax-1, yMin, yMax-1, -thickSlicesNum, 0+thickSlicesNum ); } else { rendererInfo.m_Reslicer->SetOutputDimensionality( 2 ); rendererInfo.m_Reslicer->SetOutputExtent( xMin, xMax-1, yMin, yMax-1, 0, 0 ); } rendererInfo.m_Reslicer->SetOutputOrigin( 0.0, 0.0, 0.0 ); rendererInfo.m_Reslicer->SetOutputSpacing( mmPerPixel[0], mmPerPixel[1], dataZSpacing ); // xMax and yMax are meant exclusive until now, whereas // SetOutputExtent wants an inclusive bound. Thus, we need // to subtract 1. // Do the reslicing. Modified() is called to make sure that the reslicer is // executed even though the input geometry information did not change; this // is necessary when the input /em data, but not the /em geometry changes. // The reslicing result is used both for 2D and for 3D mapping. 2D mapping // currently uses PIC data structures, while 3D mapping uses VTK data. Thus, // the reslicing result needs to be stored twice. // 1. Check the result vtkImageData* reslicedImage = 0; if(thickSlicesMode>0) { rendererInfo.m_TSFilter->SetThickSliceMode( thickSlicesMode-1 ); rendererInfo.m_TSFilter->SetInput( rendererInfo.m_Reslicer->GetOutput() ); rendererInfo.m_TSFilter->Modified(); rendererInfo.m_TSFilter->Update(); reslicedImage = rendererInfo.m_TSFilter->GetOutput(); } else { rendererInfo.m_Reslicer->Modified(); rendererInfo.m_Reslicer->Update(); reslicedImage = rendererInfo.m_Reslicer->GetOutput(); } if((reslicedImage == NULL) || (reslicedImage->GetDataDimension() < 1)) { MITK_WARN << "reslicer returned empty image"; return; } // 2. Convert the resampling result to PIC image format mitkIpPicDescriptor *pic = Pic2vtk::convert( reslicedImage ); if (pic == NULL) { return; } bool imageIs2D = true; if ( pic->dim == 1 ) { pic->dim = 2; pic->n[1] = 1; imageIs2D = false; } assert( pic->dim == 2 ); rendererInfo.m_Pic = pic; if ( pic->bpe == 24 && reslicedImage->GetScalarType()==VTK_UNSIGNED_CHAR ) // RGB image m_iil4mitkMode = iil4mitkImage::RGB; else if ( pic->bpe == 32 && reslicedImage->GetScalarType()==VTK_UNSIGNED_CHAR ) // RGBA image m_iil4mitkMode = iil4mitkImage::RGBA; image->setImage( pic, m_iil4mitkMode ); image->setInterpolation( false ); image->setRegion( 0, 0, pic->n[0], pic->n[1] ); // 3. Store the result in a VTK image if ( imageIs2D ) { if ( rendererInfo.m_Image == NULL ) { rendererInfo.m_Image = vtkImageData::New();//reslicedImage; } rendererInfo.m_Image->DeepCopy( reslicedImage ); rendererInfo.m_Image->Update(); } else { if ( rendererInfo.m_Image != NULL ) { rendererInfo.m_Image->Delete(); } rendererInfo.m_Image = NULL; } // We have been modified rendererInfo.m_LastUpdateTime.Modified(); } double mitk::ImageMapperGL2D::CalculateSpacing( const mitk::Geometry3D *geometry, const mitk::Vector3D &d ) const { // The following can be derived from the ellipsoid equation // // 1 = x^2/a^2 + y^2/b^2 + z^2/c^2 // // where (a,b,c) = spacing of original volume (ellipsoid radii) // and (x,y,z) = scaled coordinates of vector d (according to ellipsoid) // const mitk::Vector3D &spacing = geometry->GetSpacing(); double scaling = d[0]*d[0] / (spacing[0] * spacing[0]) + d[1]*d[1] / (spacing[1] * spacing[1]) + d[2]*d[2] / (spacing[2] * spacing[2]); scaling = sqrt( scaling ); return ( sqrt( d[0]*d[0] + d[1]*d[1] + d[2]*d[2] ) / scaling ); } bool mitk::ImageMapperGL2D ::LineIntersectZero( vtkPoints *points, int p1, int p2, vtkFloatingPointType *bounds ) { vtkFloatingPointType point1[3]; vtkFloatingPointType point2[3]; points->GetPoint( p1, point1 ); points->GetPoint( p2, point2 ); if ( (point1[2] * point2[2] <= 0.0) && (point1[2] != point2[2]) ) { double x, y; x = ( point1[0] * point2[2] - point1[2] * point2[0] ) / ( point2[2] - point1[2] ); y = ( point1[1] * point2[2] - point1[2] * point2[1] ) / ( point2[2] - point1[2] ); if ( x < bounds[0] ) { bounds[0] = x; } if ( x > bounds[1] ) { bounds[1] = x; } if ( y < bounds[2] ) { bounds[2] = y; } if ( y > bounds[3] ) { bounds[3] = y; } bounds[4] = bounds[5] = 0.0; return true; } return false; } bool mitk::ImageMapperGL2D ::CalculateClippedPlaneBounds( const Geometry3D *boundingGeometry, const PlaneGeometry *planeGeometry, vtkFloatingPointType *bounds ) { // Clip the plane with the bounding geometry. To do so, the corner points // of the bounding box are transformed by the inverse transformation // matrix, and the transformed bounding box edges derived therefrom are // clipped with the plane z=0. The resulting min/max values are taken as // bounds for the image reslicer. const mitk::BoundingBox *boundingBox = boundingGeometry->GetBoundingBox(); mitk::BoundingBox::PointType bbMin = boundingBox->GetMinimum(); mitk::BoundingBox::PointType bbMax = boundingBox->GetMaximum(); mitk::BoundingBox::PointType bbCenter = boundingBox->GetCenter(); vtkPoints *points = vtkPoints::New(); if(boundingGeometry->GetImageGeometry()) { points->InsertPoint( 0, bbMin[0]-0.5, bbMin[1]-0.5, bbMin[2]-0.5 ); points->InsertPoint( 1, bbMin[0]-0.5, bbMin[1]-0.5, bbMax[2]-0.5 ); points->InsertPoint( 2, bbMin[0]-0.5, bbMax[1]-0.5, bbMax[2]-0.5 ); points->InsertPoint( 3, bbMin[0]-0.5, bbMax[1]-0.5, bbMin[2]-0.5 ); points->InsertPoint( 4, bbMax[0]-0.5, bbMin[1]-0.5, bbMin[2]-0.5 ); points->InsertPoint( 5, bbMax[0]-0.5, bbMin[1]-0.5, bbMax[2]-0.5 ); points->InsertPoint( 6, bbMax[0]-0.5, bbMax[1]-0.5, bbMax[2]-0.5 ); points->InsertPoint( 7, bbMax[0]-0.5, bbMax[1]-0.5, bbMin[2]-0.5 ); } else { points->InsertPoint( 0, bbMin[0], bbMin[1], bbMin[2] ); points->InsertPoint( 1, bbMin[0], bbMin[1], bbMax[2] ); points->InsertPoint( 2, bbMin[0], bbMax[1], bbMax[2] ); points->InsertPoint( 3, bbMin[0], bbMax[1], bbMin[2] ); points->InsertPoint( 4, bbMax[0], bbMin[1], bbMin[2] ); points->InsertPoint( 5, bbMax[0], bbMin[1], bbMax[2] ); points->InsertPoint( 6, bbMax[0], bbMax[1], bbMax[2] ); points->InsertPoint( 7, bbMax[0], bbMax[1], bbMin[2] ); } vtkPoints *newPoints = vtkPoints::New(); vtkTransform *transform = vtkTransform::New(); transform->Identity(); transform->Concatenate( planeGeometry->GetVtkTransform()->GetLinearInverse() ); transform->Concatenate( boundingGeometry->GetVtkTransform() ); transform->TransformPoints( points, newPoints ); bounds[0] = bounds[2] = 10000000.0; bounds[1] = bounds[3] = -10000000.0; bounds[4] = bounds[5] = 0.0; this->LineIntersectZero( newPoints, 0, 1, bounds ); this->LineIntersectZero( newPoints, 1, 2, bounds ); this->LineIntersectZero( newPoints, 2, 3, bounds ); this->LineIntersectZero( newPoints, 3, 0, bounds ); this->LineIntersectZero( newPoints, 0, 4, bounds ); this->LineIntersectZero( newPoints, 1, 5, bounds ); this->LineIntersectZero( newPoints, 2, 6, bounds ); this->LineIntersectZero( newPoints, 3, 7, bounds ); this->LineIntersectZero( newPoints, 4, 5, bounds ); this->LineIntersectZero( newPoints, 5, 6, bounds ); this->LineIntersectZero( newPoints, 6, 7, bounds ); this->LineIntersectZero( newPoints, 7, 4, bounds ); // clean up vtk data points->Delete(); newPoints->Delete(); transform->Delete(); if ( (bounds[0] > 9999999.0) || (bounds[2] > 9999999.0) || (bounds[1] < -9999999.0) || (bounds[3] < -9999999.0) ) { return false; } else { // The resulting bounds must be adjusted by the plane spacing, since we // we have so far dealt with index coordinates const float *planeSpacing = planeGeometry->GetFloatSpacing(); bounds[0] *= planeSpacing[0]; bounds[1] *= planeSpacing[0]; bounds[2] *= planeSpacing[1]; bounds[3] *= planeSpacing[1]; bounds[4] *= planeSpacing[2]; bounds[5] *= planeSpacing[2]; return true; } } void mitk::ImageMapperGL2D::GenerateAllData() { RendererInfoMap::iterator it, end = m_RendererInfo.end(); for ( it = m_RendererInfo.begin(); it != end; ++it) { this->Update( it->first ); } } void mitk::ImageMapperGL2D::Clear() { RendererInfoMap::iterator it, end = m_RendererInfo.end(); for ( it = m_RendererInfo.begin(); it != end; ++it ) { it->second.RemoveObserver(); it->second.Squeeze(); } m_RendererInfo.clear(); } void mitk::ImageMapperGL2D::ApplyProperties(mitk::BaseRenderer* renderer) { RendererInfo &rendererInfo = this->AccessRendererInfo( renderer ); iil4mitkPicImage *image = rendererInfo.Get_iil4mitkImage(); assert( image != NULL ); float rgba[4]= { 1.0f, 1.0f, 1.0f, 1.0f }; float opacity = 1.0f; // check for color prop and use it for rendering if it exists // binary image hovering & binary image selection bool hover = false; bool selected = false; GetDataNode()->GetBoolProperty("binaryimage.ishovering", hover, renderer); GetDataNode()->GetBoolProperty("selected", selected, renderer); if(hover && !selected) { mitk::ColorProperty::Pointer colorprop = dynamic_cast(GetDataNode()->GetProperty ("binaryimage.hoveringcolor", renderer)); if(colorprop.IsNotNull()) memcpy(rgba, colorprop->GetColor().GetDataPointer(), 3*sizeof(float)); else GetColor( rgba, renderer ); } if(selected) { mitk::ColorProperty::Pointer colorprop = dynamic_cast(GetDataNode()->GetProperty ("binaryimage.selectedcolor", renderer)); if(colorprop.IsNotNull()) memcpy(rgba, colorprop->GetColor().GetDataPointer(), 3*sizeof(float)); else GetColor( rgba, renderer ); } if(!hover && !selected) { GetColor( rgba, renderer ); } // check for opacity prop and use it for rendering if it exists GetOpacity( opacity, renderer ); rgba[3] = opacity; // check for interpolation properties bool textureInterpolation = false; GetDataNode()->GetBoolProperty( "texture interpolation", textureInterpolation, renderer ); rendererInfo.m_TextureInterpolation = textureInterpolation; mitk::LevelWindow levelWindow; mitk::LevelWindow opacLevelWindow; bool binary = false; this->GetDataNode()->GetBoolProperty( "binary", binary, renderer ); if ( binary ) { image->setExtrema(0, 1); image->setOpacityExtrema( 0.0, 255.0 ); image->setBinary(true); bool binaryOutline = false; if ( this->GetInput()->GetPixelType().GetBpe() <= 8 ) { if (this->GetDataNode()->GetBoolProperty( "outline binary", binaryOutline, renderer )) { image->setOutline(binaryOutline); float binaryOutlineWidth(1.0); if (this->GetDataNode()->GetFloatProperty( "outline width", binaryOutlineWidth, renderer )) { image->setOutlineWidth(binaryOutlineWidth); } } } else { //this->GetDataNode()->SetBoolProperty( "outline binary", false, renderer ); //this->GetDataNode()->SetFloatProperty( "opacity", 0.3, renderer ); //set opacity //rgba[3] = 0.3; MITK_WARN << "Type of all binary images should be (un)signed char. Outline does not work on other pixel types!"; } } else { if( !this->GetLevelWindow( levelWindow, renderer, "levelWindow" ) ) { this->GetLevelWindow( levelWindow, renderer ); } image->setExtrema( levelWindow.GetLowerWindowBound(), levelWindow.GetUpperWindowBound() ); // obtain opacity level window if( this->GetLevelWindow( opacLevelWindow, renderer, "opaclevelwindow" ) ) { image->setOpacityExtrema( opacLevelWindow.GetLowerWindowBound(), opacLevelWindow.GetUpperWindowBound() ); } else { image->setOpacityExtrema( 0.0, 255.0 ); } } bool useColor = false; GetDataNode()->GetBoolProperty( "use color", useColor, renderer ); mitk::LookupTableProperty::Pointer LookupTableProp; if ( !useColor ) { LookupTableProp = dynamic_cast( this->GetDataNode()->GetProperty("LookupTable")); if ( LookupTableProp.IsNull() ) { useColor = true; } } if ( useColor || binary ) { // If lookup table use is NOT requested (or we have a binary image...): m_iil4mitkMode = iil4mitkImage::INTENSITY_ALPHA; image->setColor( rgba[0], rgba[1], rgba[2], rgba[3] ); } else { // If lookup table use is requested: m_iil4mitkMode = iil4mitkImage::COLOR_ALPHA; // only update the lut, when the properties have changed... if ( LookupTableProp->GetLookupTable()->GetMTime() <= this->GetDataNode()->GetPropertyList()->GetMTime() ) { LookupTableProp->GetLookupTable()->ChangeOpacityForAll( opacity ); LookupTableProp->GetLookupTable()->ChangeOpacity(0, 0.0); } image->setColors(LookupTableProp->GetLookupTable()->GetRawLookupTable()); } } void mitk::ImageMapperGL2D::Update(mitk::BaseRenderer* renderer) { mitk::Image* data = const_cast( this->GetInput() ); if ( data == NULL ) { return; } if ( !IsVisible(renderer) ) { return; } // Calculate time step of the input data for the specified renderer (integer value) this->CalculateTimeStep( renderer ); // Check if time step is valid const TimeSlicedGeometry *dataTimeGeometry = data->GetTimeSlicedGeometry(); if ( ( dataTimeGeometry == NULL ) || ( dataTimeGeometry->GetTimeSteps() == 0 ) || ( !dataTimeGeometry->IsValidTime( this->GetTimestep() ) ) ) { return; } const DataNode *node = this->GetDataNode(); RendererInfo& rendererInfo = AccessRendererInfo( renderer ); iil4mitkPicImage* image = rendererInfo.Get_iil4mitkImage(); data->UpdateOutputInformation(); if ( (image == NULL) || (rendererInfo.m_LastUpdateTime < node->GetMTime()) || (rendererInfo.m_LastUpdateTime < data->GetPipelineMTime()) || (rendererInfo.m_LastUpdateTime < renderer->GetCurrentWorldGeometry2DUpdateTime()) || (rendererInfo.m_LastUpdateTime < renderer->GetDisplayGeometryUpdateTime()) ) { - this->GenerateData( renderer ); + this->GenerateDataForRenderer( renderer ); } else if ( rendererInfo.m_LastUpdateTime < renderer->GetCurrentWorldGeometry2D()->GetMTime() ) { - this->GenerateData( renderer ); + this->GenerateDataForRenderer( renderer ); } else if ( (rendererInfo.m_LastUpdateTime < node->GetPropertyList()->GetMTime()) || (rendererInfo.m_LastUpdateTime < node->GetPropertyList(renderer)->GetMTime()) ) { - this->GenerateData( renderer ); + this->GenerateDataForRenderer( renderer ); // since we have checked that nothing important has changed, we can set // m_LastUpdateTime to the current time rendererInfo.m_LastUpdateTime.Modified(); } } void mitk::ImageMapperGL2D ::DeleteRendererCallback( itk::Object *object, const itk::EventObject & ) { mitk::BaseRenderer *renderer = dynamic_cast< mitk::BaseRenderer* >( object ); if ( renderer ) { m_RendererInfo.erase( renderer ); } } mitk::ImageMapperGL2D::RendererInfo ::RendererInfo() : m_RendererID(-1), m_iil4mitkImage(NULL), m_Renderer(NULL), m_Pic(NULL), m_UnitSpacingImageFilter( NULL ), m_Reslicer( NULL ), m_TSFilter( NULL ), m_Image(NULL), m_ReferenceGeometry(NULL), m_TextureInterpolation(true), m_ObserverID( 0 ) { m_PixelsPerMM.Fill(0); }; mitk::ImageMapperGL2D::RendererInfo ::~RendererInfo() { this->Squeeze(); if ( m_UnitSpacingImageFilter != NULL ) { m_UnitSpacingImageFilter->Delete(); } if ( m_Reslicer != NULL ) { m_Reslicer->Delete(); } if ( m_TSFilter != NULL ) { m_TSFilter->Delete(); } if ( m_Image != NULL ) { m_Image->Delete(); } } void mitk::ImageMapperGL2D::RendererInfo ::Set_iil4mitkImage( iil4mitkPicImage *iil4mitkImage ) { assert( iil4mitkImage != NULL ); delete m_iil4mitkImage; m_iil4mitkImage = iil4mitkImage; } void mitk::ImageMapperGL2D::RendererInfo::Squeeze() { delete m_iil4mitkImage; m_iil4mitkImage = NULL; if ( m_Pic != NULL ) { mitkIpPicFree(m_Pic); m_Pic = NULL; } if ( m_Image != NULL ) { m_Image->Delete(); m_Image = NULL; } } void mitk::ImageMapperGL2D::RendererInfo::RemoveObserver() { if ( m_ObserverID != 0 ) { // m_ObserverID has to be decreased by one. Was incremented by one after creation to make the test m_ObserverID != 0 possible. m_Renderer->RemoveObserver( m_ObserverID-1 ); } } void mitk::ImageMapperGL2D::RendererInfo::Initialize( int rendererID, mitk::BaseRenderer *renderer, unsigned long observerID ) { // increase ID by one to avoid 0 ID, has to be decreased before remove of the observer m_ObserverID = observerID+1; assert(rendererID>=0); assert(m_RendererID<0); m_RendererID = rendererID; m_Renderer = renderer; m_Image = vtkImageData::New(); m_Reslicer = vtkImageReslice::New(); m_TSFilter = vtkMitkThickSlicesFilter::New(); m_Reslicer->ReleaseDataFlagOn(); m_TSFilter->ReleaseDataFlagOn(); m_UnitSpacingImageFilter = vtkImageChangeInformation::New(); m_UnitSpacingImageFilter->SetOutputSpacing( 1.0, 1.0, 1.0 ); } void mitk::ImageMapperGL2D::SetDefaultProperties(mitk::DataNode* node, mitk::BaseRenderer* renderer, bool overwrite) { mitk::Image::Pointer image = dynamic_cast(node->GetData()); // Properties common for both images and segmentations node->AddProperty( "use color", mitk::BoolProperty::New( true ), renderer, overwrite ); node->AddProperty( "outline binary", mitk::BoolProperty::New( false ), renderer, overwrite ); node->AddProperty( "outline width", mitk::FloatProperty::New( 1.0 ), renderer, overwrite ); if(image->IsRotated()) node->AddProperty( "reslice interpolation", mitk::VtkResliceInterpolationProperty::New(VTK_RESLICE_CUBIC) ); else node->AddProperty( "reslice interpolation", mitk::VtkResliceInterpolationProperty::New() ); node->AddProperty( "texture interpolation", mitk::BoolProperty::New( mitk::DataNodeFactory::m_TextureInterpolationActive ) ); // set to user configurable default value (see global options) node->AddProperty( "in plane resample extent by geometry", mitk::BoolProperty::New( false ) ); node->AddProperty( "bounding box", mitk::BoolProperty::New( false ) ); bool isBinaryImage(false); if ( ! node->GetBoolProperty("binary", isBinaryImage) ) { // ok, property is not set, use heuristic to determine if this // is a binary image mitk::Image::Pointer centralSliceImage; ScalarType minValue = 0.0; ScalarType maxValue = 0.0; ScalarType min2ndValue = 0.0; ScalarType max2ndValue = 0.0; mitk::ImageSliceSelector::Pointer sliceSelector = mitk::ImageSliceSelector::New(); sliceSelector->SetInput(image); sliceSelector->SetSliceNr(image->GetDimension(2)/2); sliceSelector->SetTimeNr(image->GetDimension(3)/2); sliceSelector->SetChannelNr(image->GetDimension(4)/2); sliceSelector->Update(); centralSliceImage = sliceSelector->GetOutput(); if ( centralSliceImage.IsNotNull() && centralSliceImage->IsInitialized() ) { minValue = centralSliceImage->GetScalarValueMin(); maxValue = centralSliceImage->GetScalarValueMax(); min2ndValue = centralSliceImage->GetScalarValue2ndMin(); max2ndValue = centralSliceImage->GetScalarValue2ndMax(); } if ( minValue == maxValue ) { // centralSlice is strange, lets look at all data minValue = image->GetScalarValueMin(); maxValue = image->GetScalarValueMaxNoRecompute(); min2ndValue = image->GetScalarValue2ndMinNoRecompute(); max2ndValue = image->GetScalarValue2ndMaxNoRecompute(); } isBinaryImage = ( maxValue == min2ndValue && minValue == max2ndValue ); } // some more properties specific for a binary... if (isBinaryImage) { node->AddProperty( "opacity", mitk::FloatProperty::New(0.3f), renderer, overwrite ); node->AddProperty( "color", ColorProperty::New(1.0,0.0,0.0), renderer, overwrite ); node->AddProperty( "binaryimage.selectedcolor", ColorProperty::New(1.0,0.0,0.0), renderer, overwrite ); node->AddProperty( "binaryimage.selectedannotationcolor", ColorProperty::New(1.0,0.0,0.0), renderer, overwrite ); node->AddProperty( "binaryimage.hoveringcolor", ColorProperty::New(1.0,0.0,0.0), renderer, overwrite ); node->AddProperty( "binaryimage.hoveringannotationcolor", ColorProperty::New(1.0,0.0,0.0), renderer, overwrite ); node->AddProperty( "binary", mitk::BoolProperty::New( true ), renderer, overwrite ); node->AddProperty("layer", mitk::IntProperty::New(10), renderer, overwrite); } else //...or image type object { node->AddProperty( "opacity", mitk::FloatProperty::New(1.0f), renderer, overwrite ); node->AddProperty( "color", ColorProperty::New(1.0,1.0,1.0), renderer, overwrite ); node->AddProperty( "binary", mitk::BoolProperty::New( false ), renderer, overwrite ); node->AddProperty("layer", mitk::IntProperty::New(0), renderer, overwrite); } if(image.IsNotNull() && image->IsInitialized()) { if((overwrite) || (node->GetProperty("levelwindow", renderer)==NULL)) { mitk::LevelWindowProperty::Pointer levWinProp = mitk::LevelWindowProperty::New(); mitk::LevelWindow levelwindow; levelwindow.SetAuto( image, true, true ); levWinProp->SetLevelWindow( levelwindow ); node->SetProperty( "levelwindow", levWinProp, renderer ); } if(((overwrite) || (node->GetProperty("opaclevelwindow", renderer)==NULL)) && (image->GetPixelType().GetItkTypeId() && *(image->GetPixelType().GetItkTypeId()) == typeid(itk::RGBAPixel))) { mitk::LevelWindow opaclevwin; opaclevwin.SetRangeMinMax(0,255); opaclevwin.SetWindowBounds(0,255); mitk::LevelWindowProperty::Pointer prop = mitk::LevelWindowProperty::New(opaclevwin); node->SetProperty( "opaclevelwindow", prop, renderer ); } if((overwrite) || (node->GetProperty("LookupTable", renderer)==NULL)) { // add a default rainbow lookup table for color mapping mitk::LookupTable::Pointer mitkLut = mitk::LookupTable::New(); vtkLookupTable* vtkLut = mitkLut->GetVtkLookupTable(); vtkLut->SetHueRange(0.6667, 0.0); vtkLut->SetTableRange(0.0, 20.0); vtkLut->Build(); mitk::LookupTableProperty::Pointer mitkLutProp = mitk::LookupTableProperty::New(); mitkLutProp->SetLookupTable(mitkLut); node->SetProperty( "LookupTable", mitkLutProp ); } } Superclass::SetDefaultProperties(node, renderer, overwrite); } diff --git a/Core/Code/Rendering/mitkImageMapperGL2D.h b/Core/Code/Rendering/mitkImageMapperGL2D.h index f628ed3341..d7aea797f8 100644 --- a/Core/Code/Rendering/mitkImageMapperGL2D.h +++ b/Core/Code/Rendering/mitkImageMapperGL2D.h @@ -1,298 +1,298 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef MITKIMAGEMAPPER2D_H_HEADER_INCLUDED_C10E906E #define MITKIMAGEMAPPER2D_H_HEADER_INCLUDED_C10E906E #include "mitkCommon.h" #include "mitkGLMapper2D.h" #include "mitkBaseRenderer.h" #include #include #include #include #include class iil4mitkPicImage; class Vtk2itk; class vtkImageReslice; class vtkLookupTable; class vtkGeneralTransform; class vtkImageChangeInformation; class vtkPoints; class vtkMitkThickSlicesFilter; namespace mitk { /** \brief Mapper to resample and display 2D slices of a 3D image. * * Currently implemented for mapping on PlaneGeometry and * AbstractTransformGeometry. The resulting 2D image (by reslicing the * underlying 3D input image appropriately) can either be directly rendered * in a 2D view or just be calculated to be used later on by another * rendering entity, e.g. in texture mapping in a 3D view. * * This results in a flipped version when used for texture mapping. Furthermore, * not the complete rectangular area described by the Geometry2D from the renderer * is resampled, @em if the Geometry2D is larger than the image dimension in the * requested direction. This results in a stretched version when used for texture * mapping. * * Properties that can be set for images and influence the imageMapper2D are: * * - \b "modality": (mitkModalityProperty) Modality of the image * - \b "opacity": (FloatProperty) Opacity of the image * - \b "color": (ColorProperty) Color of the image * - \b "use color": (BoolProperty) Use the color of the image or not * - \b "binary": (BoolProperty) is the image a binary image or not * - \b "outline binary": (BoolProperty) show outline of the image or not * - \b "texture interpolation": (BoolProperty) texture interpolation of the image * - \b "reslice interpolation": (VtkResliceInterpolationProperty) reslice interpolation of the image * - \b "in plane resample extent by geometry": (BoolProperty) Do it or not * - \b "bounding box": (BoolProperty) Is the Bounding Box of the image shown or not * - \b "layer": (IntProperty) Layer of the image * - \b "volume annotation color": (ColorProperty) color of the volume annotation * - \b "volume annotation unit": (StringProperty) annotation unit as string (does not implicit convert the unit!) unit is ml/cm3 * The default properties are: * - \b "opacity", mitk::FloatProperty::New(0.3f), renderer, overwrite ) * - \b "color", ColorProperty::New(1.0,0.0,0.0), renderer, overwrite ) * - \b "use color", mitk::BoolProperty::New( true ), renderer, overwrite ) * - \b "binary", mitk::BoolProperty::New( true ), renderer, overwrite ) * - \b "outline binary", mitk::BoolProperty::New( false ), renderer, overwrite ) * - \b "texture interpolation", mitk::BoolProperty::New( mitk::DataNodeFactory::m_TextureInterpolationActive ) ) * - \b "reslice interpolation", mitk::VtkResliceInterpolationProperty::New() ) * - \b "in plane resample extent by geometry", mitk::BoolProperty::New( false ) ) * - \b "bounding box", mitk::BoolProperty::New( false ) ) * - \b "layer", mitk::IntProperty::New(10), renderer, overwrite) * If the modality-property is set for an image, the mapper uses modality-specific default properties, * e.g. color maps, if they are defined. * \ingroup Mapper */ class MITK_CORE_EXPORT ImageMapperGL2D : public GLMapper2D { public: /** Standard class typedefs. */ mitkClassMacro( ImageMapperGL2D,GLMapper2D ); /** Method for creation through the object factory. */ itkNewMacro(Self); /** Some convenient typedefs. */ typedef mitk::Image InputImageType; typedef InputImageType::Pointer InputImagePointer; typedef InputImageType::ConstPointer InputImageConstPointer; typedef SlicedData::RegionType InputImageRegionType; /** \brief Get the Image to map */ const InputImageType *GetInput(void); /** \brief Calls Update() for all associated renderers. */ virtual void GenerateAllData(); /** \brief Renders the (priorly) resampled image onto the screen. */ virtual void Paint( mitk::BaseRenderer *renderer ); /** \brief Checks whether this mapper needs to update itself and generate * data. */ virtual void Update(mitk::BaseRenderer * renderer); virtual void ApplyProperties(mitk::BaseRenderer* renderer); /** \brief Internal storage class for data needed for rendering into a * renderer */ class MITK_CORE_EXPORT RendererInfo { /** \brief internal id of the renderer the data is stored for */ int m_RendererID; /** \brief stored iil4mitkPicImage containing the texture to display for * 2D rendering (cf. m_Image) */ iil4mitkPicImage* m_iil4mitkImage; mitk::BaseRenderer* m_Renderer; public: /** \brief timestamp of last update of stored data */ itk::TimeStamp m_LastUpdateTime; /** \brief stored data as a mitkIpPicDescriptor */ mitkIpPicDescriptor *m_Pic; /** \brief number of pixels per mm in x- and y-direction of the resampled */ Vector2D m_PixelsPerMM; /** \brief Extent (in pixels) of the image */ Vector2D m_Extent; /** \brief Overlap (in pixels) to ensure coverage of rotated images also */ Vector2D m_Overlap; /** \brief Using unit spacing for resampling makes life easier */ vtkImageChangeInformation *m_UnitSpacingImageFilter; /** \brief The actual reslicer (one per renderer) */ vtkImageReslice *m_Reslicer; /** \brief Thickslices post filtering */ vtkMitkThickSlicesFilter *m_TSFilter; /** \brief Extracted image for 3D rendering (cf. m_iil4mitkImage) */ vtkImageData *m_Image; /** \brief Reference geometry associated with the world geometry */ const Geometry3D *m_ReferenceGeometry; bool m_TextureInterpolation; /** \brief stores the id of the observer for delete event of renderer */ unsigned long m_ObserverID; RendererInfo(); ~RendererInfo(); inline bool IsInitialized() const { return m_RendererID >= 0; } void Initialize( int rendererID, mitk::BaseRenderer *renderer, unsigned long observerID ); void Set_iil4mitkImage(iil4mitkPicImage* iil4mitkImage); inline iil4mitkPicImage* Get_iil4mitkImage() const { return m_iil4mitkImage; } inline int GetRendererID() const { return m_RendererID; } void RemoveObserver(); void Squeeze(); }; // RendererInfo /** \brief Get the internal id of the renderer * \sa RendererInfo */ virtual int GetAssociatedChannelNr( mitk::BaseRenderer *renderer ); /** \brief Get the RendererInfo for \a renderer */ const RendererInfo *GetRendererInfo( mitk::BaseRenderer *renderer ) { return &this->AccessRendererInfo(renderer); } /** \brief Release memory allocated for buffering */ virtual void Clear(); static void SetDefaultProperties(mitk::DataNode* node, mitk::BaseRenderer* renderer = NULL, bool overwrite = false); protected: ImageMapperGL2D(); virtual ~ImageMapperGL2D(); /** Does the actual resampling, without rendering the image yet. */ - virtual void GenerateData(mitk::BaseRenderer *renderer); + virtual void GenerateDataForRenderer(mitk::BaseRenderer *renderer); /** \brief Get the RendererInfo for @a renderer */ inline RendererInfo & AccessRendererInfo( mitk::BaseRenderer* renderer ) { RendererInfo& rendererInfo = m_RendererInfo[renderer]; if(rendererInfo.IsInitialized()==false) { // Add observer for renderer reset events (RendererInfo will // automatically be removed from list when a Renderer is deleted) // // Note: observer ID is passed to rendererInfo, which will take // responsiblity to remove the observer upon its destruction typedef itk::MemberCommand< ImageMapperGL2D > MemberCommandType; MemberCommandType::Pointer deleteRendererCommand = MemberCommandType::New(); deleteRendererCommand->SetCallbackFunction( this, &ImageMapperGL2D::DeleteRendererCallback ); unsigned long observerID = renderer->AddObserver( BaseRenderer::RendererResetEvent(), deleteRendererCommand ); // Initialize RendererInfo rendererInfo.Initialize( ImageMapperGL2D::numRenderer++, renderer, observerID ); } return rendererInfo; } void DeleteRendererCallback( itk::Object *object, const itk::EventObject & ); double CalculateSpacing( const mitk::Geometry3D *geometry, const mitk::Vector3D &d ) const; bool LineIntersectZero( vtkPoints *points, int p1, int p2, vtkFloatingPointType *bounds ); bool CalculateClippedPlaneBounds( const Geometry3D *boundingGeometry, const PlaneGeometry *planeGeometry, vtkFloatingPointType *bounds ); /** \brief Number of renderers data is stored for * \todo General concept for keeping data for rendering required * \todo static? */ static int numRenderer; protected: typedef std::map RendererInfoMap; /** \brief Map of instances of RendererInfo * \sa RendererInfo */ RendererInfoMap m_RendererInfo; vtkGeneralTransform *m_ComposedResliceTransform; private: int m_iil4mitkMode; }; } // namespace mitk #endif /* MITKIMAGEMAPPER2D_H_HEADER_INCLUDED_C10E906E */ diff --git a/Core/Code/Rendering/mitkMapper.cpp b/Core/Code/Rendering/mitkMapper.cpp index 42e293d42d..69df73e073 100644 --- a/Core/Code/Rendering/mitkMapper.cpp +++ b/Core/Code/Rendering/mitkMapper.cpp @@ -1,158 +1,158 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "mitkMapper.h" #include "mitkDataNode.h" #include "mitkBaseRenderer.h" #include "mitkProperties.h" mitk::Mapper::Mapper() : m_VtkBased( true ), m_TimeStep( 0 ) { } mitk::Mapper::~Mapper() { } mitk::BaseData* mitk::Mapper::GetData() const { return m_DataNode->GetData(); } mitk::DataNode* mitk::Mapper::GetDataNode() const { itkDebugMacro("returning DataNode address " << this->m_DataNode ); return this->m_DataNode.GetPointer(); } bool mitk::Mapper::GetColor(float rgb[3], mitk::BaseRenderer* renderer, const char* name) const { const mitk::DataNode* node=GetDataNode(); if(node==NULL) return false; return node->GetColor(rgb, renderer, name); } bool mitk::Mapper::GetVisibility(bool &visible, mitk::BaseRenderer* renderer, const char* name) const { const mitk::DataNode* node=GetDataNode(); if(node==NULL) return false; return node->GetVisibility(visible, renderer, name); } bool mitk::Mapper::GetOpacity(float &opacity, mitk::BaseRenderer* renderer, const char* name) const { const mitk::DataNode* node=GetDataNode(); if(node==NULL) return false; return node->GetOpacity(opacity, renderer, name); } bool mitk::Mapper::GetLevelWindow(mitk::LevelWindow& levelWindow, mitk::BaseRenderer* renderer, const char* name) const { const mitk::DataNode* node=GetDataNode(); if(node==NULL) return false; return node->GetLevelWindow(levelWindow, renderer, name); } bool mitk::Mapper::IsVisible(mitk::BaseRenderer* renderer, const char* name) const { bool visible=true; GetVisibility(visible, renderer, name); return visible; } void mitk::Mapper::GenerateData() { } -void mitk::Mapper::GenerateData(mitk::BaseRenderer* /*renderer*/) +void mitk::Mapper::GenerateDataForRenderer(mitk::BaseRenderer* /*renderer*/) { } void mitk::Mapper::CalculateTimeStep( mitk::BaseRenderer *renderer ) { if ( ( renderer != NULL ) && ( m_DataNode.GetPointer() != NULL ) ) { m_TimeStep = renderer->GetTimeStep(m_DataNode->GetData()); } else { m_TimeStep = 0; } } void mitk::Mapper::Update(mitk::BaseRenderer *renderer) { const DataNode* node = GetDataNode(); assert(node!=NULL); //safety cause there are datatreenodes that have no defined data (video-nodes and root) unsigned int dataMTime = 0; mitk::BaseData::Pointer data = static_cast(node->GetData()); if (data.IsNotNull()) { dataMTime = data->GetMTime(); } // Calculate time step of the input data for the specified renderer (integer value) this->CalculateTimeStep( renderer ); // Check if time step is valid const TimeSlicedGeometry *dataTimeGeometry = data->GetTimeSlicedGeometry(); if ( ( dataTimeGeometry == NULL ) || ( dataTimeGeometry->GetTimeSteps() == 0 ) || ( !dataTimeGeometry->IsValidTime( m_TimeStep ) ) ) { // TimeSlicedGeometry or time step is not valid for this data: // reset mapper so that nothing is displayed this->ResetMapper( renderer ); return; } if( (m_LastUpdateTime < GetMTime()) || (m_LastUpdateTime < node->GetDataReferenceChangedTime()) || (m_LastUpdateTime < dataMTime) || (renderer && (m_LastUpdateTime < renderer->GetTimeStepUpdateTime())) ) { this->GenerateData(); m_LastUpdateTime.Modified(); } - this->GenerateData(renderer); + this->GenerateDataForRenderer(renderer); } void mitk::Mapper::SetDefaultProperties(mitk::DataNode* node, mitk::BaseRenderer* renderer, bool overwrite) { node->AddProperty( "visible", mitk::BoolProperty::New(true), renderer, overwrite ); node->AddProperty( "layer", mitk::IntProperty::New(0), renderer, overwrite); node->AddProperty( "name", mitk::StringProperty::New("No Name!"), renderer, overwrite ); } diff --git a/Core/Code/Rendering/mitkMapper.h b/Core/Code/Rendering/mitkMapper.h index 92f81284ad..a91e35d73d 100644 --- a/Core/Code/Rendering/mitkMapper.h +++ b/Core/Code/Rendering/mitkMapper.h @@ -1,287 +1,287 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef MAPPER_H_HEADER_INCLUDED_C1E6EA08 #define MAPPER_H_HEADER_INCLUDED_C1E6EA08 #include "mitkCommon.h" #include "mitkBaseRenderer.h" #include "mitkLevelWindow.h" #include #include //Just included to get VTK version #include class vtkWindow; class vtkProp; namespace mitk { class BaseRenderer; class BaseData; class DataNode; /** \brief Interface for accessing (templated) LocalStorageHandler instances. */ class BaseLocalStorageHandler { public: virtual ~BaseLocalStorageHandler() {} virtual void ClearLocalStorage(mitk::BaseRenderer *renderer,bool unregisterFromBaseRenderer=true )=0; }; //##Documentation //## @brief Base class of all mappers, 2D as well as 3D //## //## Base class of all Mappers, 2D as well as 3D. //## Subclasses of mitk::Mapper control the creation of rendering primitives //## that interface to the graphics library (e.g., OpenGL, vtk). //## @todo Should Mapper be a subclass of ImageSource? //## @ingroup Mapper class MITK_CORE_EXPORT Mapper : public itk::Object { public: mitkClassMacro(Mapper, itk::Object); //##Documentation //## @brief Set the DataNode containing the data to map itkSetObjectMacro(DataNode, DataNode); //##Documentation //## @brief Get the data to map //## //## Returns the mitk::BaseData object associated with this mapper. //## @returns the mitk::BaseData associated with this mapper. BaseData* GetData() const; //##Documentation //## @brief Get the DataNode containing the data to map virtual DataNode* GetDataNode() const; //##Documentation //## @brief Convenience access method for color properties (instances of //## ColorProperty) //## @return @a true property was found virtual bool GetColor(float rgb[3], BaseRenderer* renderer, const char* name = "color") const; //##Documentation //## @brief Convenience access method for visibility properties (instances //## of BoolProperty) //## @return @a true property was found //## @sa IsVisible virtual bool GetVisibility(bool &visible, BaseRenderer* renderer, const char* name = "visible") const; //##Documentation //## @brief Convenience access method for opacity properties (instances of //## FloatProperty) //## @return @a true property was found virtual bool GetOpacity(float &opacity, BaseRenderer* renderer, const char* name = "opacity") const; //##Documentation //## @brief Convenience access method for color properties (instances of //## LevelWindoProperty) //## @return @a true property was found virtual bool GetLevelWindow(LevelWindow &levelWindow, BaseRenderer* renderer, const char* name = "levelwindow") const; //##Documentation //## @brief Convenience access method for visibility properties (instances //## of BoolProperty). Return value is the visibility. Default is //## visible==true, i.e., true is returned even if the property (@a //## propertyKey) is not found. //## //## Thus, the return value has a different meaning than in the //## GetVisibility method! //## @sa GetVisibility virtual bool IsVisible(BaseRenderer* renderer, const char* name = "visible") const; virtual void Update(BaseRenderer* renderer); virtual void MitkRenderOverlay(BaseRenderer* renderer) = 0; virtual void MitkRenderOpaqueGeometry(BaseRenderer* renderer) = 0; virtual void MitkRenderTranslucentGeometry(BaseRenderer* renderer) = 0; #if ( ( VTK_MAJOR_VERSION >= 5 ) && ( VTK_MINOR_VERSION>=2) ) virtual void MitkRenderVolumetricGeometry(BaseRenderer* renderer) = 0; #endif /** * \brief Returns whether this is an vtk-based mapper */ bool IsVtkBased() const { return m_VtkBased; } /** \brief Returns true if this mapper owns the specified vtkProp for * the given BaseRenderer. * * Note: returns false by default; should be implemented for VTK-based * Mapper subclasses. */ virtual bool HasVtkProp( const vtkProp* /*prop*/, BaseRenderer* /*renderer*/ ) { return false; } /** * \brief Release vtk-based graphics resources. Must be overwritten in * subclasses if vtkProps are used. */ virtual void ReleaseGraphicsResources(vtkWindow*) { }; /** \brief Set default values of properties used by this mapper * to \a node * * \param node The node for which the properties are set * \param overwrite overwrite existing properties (default: \a false) * \param renderer defines which property list of node is used * (default: \a NULL, i.e. default property list) */ static void SetDefaultProperties(DataNode* node, BaseRenderer* renderer = NULL, bool overwrite = false); /** \brief Returns the current time step as calculated from the renderer */ int GetTimestep() const {return m_TimeStep;}; /** Returns true if this Mapper currently allows for Level-of-Detail rendering. * This reflects whether this Mapper currently invokes StartEvent, EndEvent, and * ProgressEvent on BaseRenderer. */ virtual bool IsLODEnabled( BaseRenderer * /*renderer*/ ) const { return false; } protected: Mapper(); virtual ~Mapper(); //##Documentation //## @brief Generate the data needed for rendering (independent of a specific renderer) virtual void GenerateData(); //##Documentation //## @brief Generate the data needed for rendering into @a renderer - virtual void GenerateData(BaseRenderer* renderer); + virtual void GenerateDataForRenderer(BaseRenderer* renderer); //## Updates the time step, which is sometimes needed in subclasses virtual void CalculateTimeStep( BaseRenderer* renderer ); //## Reset the mapper (i.e., make sure that nothing is displayed) if no //## valid data is present. //## //## To be implemented in sub-classes. virtual void ResetMapper( BaseRenderer* /*renderer*/ ) { }; bool m_VtkBased; itk::WeakPointer m_DataNode; //##Documentation //## @brief timestamp of last update of stored data itk::TimeStamp m_LastUpdateTime; private: //## The current time step of the dataset to be rendered, for use in subclasses //## The momentary timestep can be accessed via the GetTimestep() method. int m_TimeStep; public: /** \brief Base class for mapper specific rendering ressources. */ class BaseLocalStorage { }; /** \brief Templated class for management of LocalStorage implementations in Mappers. * * The LocalStorageHandler is responsible for providing a LocalStorage to a * concrete mitk::Mapper subclass. Each RenderWindow / mitk::BaseRenderer is * assigned its own LocalStorage instance so that all contained ressources * (actors, shaders, textures, ...) are provided individually per window. * */ template class LocalStorageHandler : public mitk::BaseLocalStorageHandler { protected: std::map m_BaseRenderer2LS; public: /** \brief deallocates a local storage for a specifc BaseRenderer (if the * BaseRenderer is itself deallocating it in its destructor, it has to set * unregisterFromBaseRenderer=false) */ virtual void ClearLocalStorage(mitk::BaseRenderer *renderer,bool unregisterFromBaseRenderer=true ) { //MITK_INFO << "deleting a localstorage on a mapper request"; if(unregisterFromBaseRenderer) renderer->UnregisterLocalStorageHandler( this ); L *l = m_BaseRenderer2LS[renderer]; m_BaseRenderer2LS.erase( renderer ); delete l; } /** \brief Retrieves a LocalStorage for a specific BaseRenderer. * * Should be used by mappers in GenerateData() and ApplyProperties() */ L *GetLocalStorage(mitk::BaseRenderer *forRenderer) { L *l = m_BaseRenderer2LS[ forRenderer ]; if(!l) { //MITK_INFO << "creating new localstorage"; l = new L; m_BaseRenderer2LS[ forRenderer ] = l; forRenderer->RegisterLocalStorageHandler( this ); } return l; } ~LocalStorageHandler() { typename std::map::iterator it; for ( it=m_BaseRenderer2LS.begin() ; it != m_BaseRenderer2LS.end(); it++ ) { (*it).first->UnregisterLocalStorageHandler(this); delete (*it).second; } m_BaseRenderer2LS.clear(); } }; }; } // namespace mitk #endif /* MAPPER_H_HEADER_INCLUDED_C1E6EA08 */ diff --git a/Core/Code/Rendering/mitkPointSetVtkMapper3D.cpp b/Core/Code/Rendering/mitkPointSetVtkMapper3D.cpp index e315d83c12..5d348124f9 100755 --- a/Core/Code/Rendering/mitkPointSetVtkMapper3D.cpp +++ b/Core/Code/Rendering/mitkPointSetVtkMapper3D.cpp @@ -1,675 +1,673 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "mitkPointSetVtkMapper3D.h" #include "mitkDataNode.h" #include "mitkProperties.h" #include "mitkColorProperty.h" #include "mitkVtkPropRenderer.h" #include "mitkPointSet.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if (VTK_MAJOR_VERSION >= 5) #include #else #include #endif #include const mitk::PointSet* mitk::PointSetVtkMapper3D::GetInput() { return static_cast ( GetData() ); } mitk::PointSetVtkMapper3D::PointSetVtkMapper3D() : m_vtkSelectedPointList(NULL), m_vtkUnselectedPointList(NULL), //m_vtkContourPolyData(NULL), m_VtkSelectedPolyDataMapper(NULL), m_VtkUnselectedPolyDataMapper(NULL), //m_vtkContourPolyDataMapper(NULL), m_vtkTextList(NULL), //m_Contour(NULL), //m_TubeFilter(NULL), m_NumberOfSelectedAdded(0), m_NumberOfUnselectedAdded(0), m_PointSize(1.0), m_ContourRadius(0.5) { //propassembly m_PointsAssembly = vtkPropAssembly::New(); //creating actors to be able to set transform m_SelectedActor = vtkActor::New(); m_UnselectedActor = vtkActor::New(); m_ContourActor = vtkActor::New(); } mitk::PointSetVtkMapper3D::~PointSetVtkMapper3D() { m_PointsAssembly->Delete(); m_SelectedActor->Delete(); m_UnselectedActor->Delete(); m_ContourActor->Delete(); } void mitk::PointSetVtkMapper3D::ReleaseGraphicsResources(vtkWindow *renWin) { m_PointsAssembly->ReleaseGraphicsResources(renWin); m_SelectedActor->ReleaseGraphicsResources(renWin); m_UnselectedActor->ReleaseGraphicsResources(renWin); m_ContourActor->ReleaseGraphicsResources(renWin); } void mitk::PointSetVtkMapper3D::CreateVTKRenderObjects() { m_vtkSelectedPointList = vtkAppendPolyData::New(); m_vtkUnselectedPointList = vtkAppendPolyData::New(); m_PointsAssembly->VisibilityOn(); if(m_PointsAssembly->GetParts()->IsItemPresent(m_SelectedActor)) m_PointsAssembly->RemovePart(m_SelectedActor); if(m_PointsAssembly->GetParts()->IsItemPresent(m_UnselectedActor)) m_PointsAssembly->RemovePart(m_UnselectedActor); if(m_PointsAssembly->GetParts()->IsItemPresent(m_ContourActor)) m_PointsAssembly->RemovePart(m_ContourActor); // exceptional displaying for PositionTracker -> MouseOrientationTool int mapperID; bool isInputDevice=false; if( this->GetDataNode()->GetBoolProperty("inputdevice",isInputDevice) && isInputDevice ) { if( this->GetDataNode()->GetIntProperty("BaseRendererMapperID",mapperID) && mapperID == 2) return; //The event for the PositionTracker came from the 3d widget and not needs to be displayed } // get and update the PointSet mitk::PointSet::Pointer input = const_cast(this->GetInput()); /* only update the input data, if the property tells us to */ bool update = true; this->GetDataNode()->GetBoolProperty("updateDataOnRender", update); if (update == true) input->Update(); int timestep = this->GetTimestep(); mitk::PointSet::DataType::Pointer itkPointSet = input->GetPointSet( timestep ); if ( itkPointSet.GetPointer() == NULL) { m_PointsAssembly->VisibilityOff(); return; } mitk::PointSet::PointsContainer::Iterator pointsIter; mitk::PointSet::PointDataContainer::Iterator pointDataIter; int j; m_NumberOfSelectedAdded = 0; m_NumberOfUnselectedAdded = 0; //create contour bool makeContour = false; this->GetDataNode()->GetBoolProperty("show contour", makeContour); if (makeContour) { this->CreateContour(NULL); } //now fill selected and unselected pointList //get size of Points in Property m_PointSize = 2; mitk::FloatProperty::Pointer pointSizeProp = dynamic_cast(this->GetDataNode()->GetProperty("pointsize")); if ( pointSizeProp.IsNotNull() ) m_PointSize = pointSizeProp->GetValue(); //get the property for creating a label onto every point only once bool showLabel = true; this->GetDataNode()->GetBoolProperty("show label", showLabel); const char * pointLabel=NULL; if(showLabel) { if(dynamic_cast(this->GetDataNode()->GetPropertyList()->GetProperty("label")) != NULL) pointLabel =dynamic_cast(this->GetDataNode()->GetPropertyList()->GetProperty("label"))->GetValue(); else showLabel = false; } //check if the list for the PointDataContainer is the same size as the PointsContainer. Is not, then the points were inserted manually and can not be visualized according to the PointData (selected/unselected) bool pointDataBroken = (itkPointSet->GetPointData()->Size() != itkPointSet->GetPoints()->Size()); //now add an object for each point in data pointDataIter = itkPointSet->GetPointData()->Begin(); for (j=0, pointsIter=itkPointSet->GetPoints()->Begin(); pointsIter!=itkPointSet->GetPoints()->End(); pointsIter++, j++) { //check for the pointtype in data and decide which geom-object to take and then add to the selected or unselected list int pointType; if(itkPointSet->GetPointData()->size() == 0 || pointDataBroken) pointType = mitk::PTUNDEFINED; else pointType = pointDataIter.Value().pointSpec; #if (VTK_MAJOR_VERSION >= 5) vtkPolyDataAlgorithm *source; #else vtkPolyDataSource *source; #endif switch (pointType) { case mitk::PTUNDEFINED: { vtkSphereSource *sphere = vtkSphereSource::New(); sphere->SetRadius(m_PointSize); itk::Point point1 = pointsIter->Value(); sphere->SetCenter(point1[0],point1[1],point1[2]); //sphere->SetCenter(pointsIter.Value()[0],pointsIter.Value()[1],pointsIter.Value()[2]); //MouseOrientation Tool (PositionTracker) if(isInputDevice) { sphere->SetThetaResolution(10); sphere->SetPhiResolution(10); } else { sphere->SetThetaResolution(20); sphere->SetPhiResolution(20); } source = sphere; } break; case mitk::PTSTART: { vtkCubeSource *cube = vtkCubeSource::New(); cube->SetXLength(m_PointSize/2); cube->SetYLength(m_PointSize/2); cube->SetZLength(m_PointSize/2); itk::Point point1 = pointsIter->Value(); cube->SetCenter(point1[0],point1[1],point1[2]); source = cube; } break; case mitk::PTCORNER: { vtkConeSource *cone = vtkConeSource::New(); cone->SetRadius(m_PointSize); itk::Point point1 = pointsIter->Value(); cone->SetCenter(point1[0],point1[1],point1[2]); cone->SetResolution(20); source = cone; } break; case mitk::PTEDGE: { vtkCylinderSource *cylinder = vtkCylinderSource::New(); cylinder->SetRadius(m_PointSize); itk::Point point1 = pointsIter->Value(); cylinder->SetCenter(point1[0],point1[1],point1[2]); cylinder->SetResolution(20); source = cylinder; } break; case mitk::PTEND: { vtkSphereSource *sphere = vtkSphereSource::New(); sphere->SetRadius(m_PointSize); itk::Point point1 = pointsIter->Value(); sphere->SetThetaResolution(20); sphere->SetPhiResolution(20); source = sphere; } break; default: { vtkSphereSource *sphere = vtkSphereSource::New(); sphere->SetRadius(m_PointSize); itk::Point point1 = pointsIter->Value(); sphere->SetCenter(point1[0],point1[1],point1[2]); sphere->SetThetaResolution(20); sphere->SetPhiResolution(20); source = sphere; } break; } if (!pointDataBroken) { if (pointDataIter.Value().selected) { m_vtkSelectedPointList->AddInput(source->GetOutput()); ++m_NumberOfSelectedAdded; } else { m_vtkUnselectedPointList->AddInput(source->GetOutput()); ++m_NumberOfUnselectedAdded; } } else { m_vtkUnselectedPointList->AddInput(source->GetOutput()); ++m_NumberOfUnselectedAdded; } source->Delete(); if (showLabel) { char buffer[20]; std::string l = pointLabel; if ( input->GetSize()>1 ) { sprintf(buffer,"%d",j+1); l.append(buffer); } // Define the text for the label vtkVectorText *label = vtkVectorText::New(); label->SetText(l.c_str()); //# Set up a transform to move the label to a new position. vtkTransform *aLabelTransform =vtkTransform::New(); aLabelTransform->Identity(); itk::Point point1 = pointsIter->Value(); aLabelTransform->Translate(point1[0]+2,point1[1]+2,point1[2]); aLabelTransform->Scale(5.7,5.7,5.7); //# Move the label to a new position. vtkTransformPolyDataFilter *labelTransform = vtkTransformPolyDataFilter::New(); labelTransform->SetTransform(aLabelTransform); aLabelTransform->Delete(); labelTransform->SetInput(label->GetOutput()); label->Delete(); //add it to the wright PointList if (pointType) { m_vtkSelectedPointList->AddInput(labelTransform->GetOutput()); ++m_NumberOfSelectedAdded; } else { m_vtkUnselectedPointList->AddInput(labelTransform->GetOutput()); ++m_NumberOfUnselectedAdded; } labelTransform->Delete(); } if(pointDataIter != itkPointSet->GetPointData()->End()) pointDataIter++; } // end FOR //now according to number of elements added to selected or unselected, build up the rendering pipeline if (m_NumberOfSelectedAdded > 0) { m_VtkSelectedPolyDataMapper = vtkPolyDataMapper::New(); m_VtkSelectedPolyDataMapper->SetInput(m_vtkSelectedPointList->GetOutput()); //create a new instance of the actor m_SelectedActor->Delete(); m_SelectedActor = vtkActor::New(); m_SelectedActor->SetMapper(m_VtkSelectedPolyDataMapper); m_VtkSelectedPolyDataMapper->Delete(); m_PointsAssembly->AddPart(m_SelectedActor); } m_vtkSelectedPointList->Delete(); if (m_NumberOfUnselectedAdded > 0) { m_VtkUnselectedPolyDataMapper = vtkPolyDataMapper::New(); m_VtkUnselectedPolyDataMapper->SetInput(m_vtkUnselectedPointList->GetOutput()); //create a new instance of the actor m_UnselectedActor->Delete(); m_UnselectedActor = vtkActor::New(); m_UnselectedActor->SetMapper(m_VtkUnselectedPolyDataMapper); m_VtkUnselectedPolyDataMapper->Delete(); m_PointsAssembly->AddPart(m_UnselectedActor); } m_vtkUnselectedPointList->Delete(); } void mitk::PointSetVtkMapper3D::GenerateData() { //create new vtk render objects (e.g. sphere for a point) this->CreateVTKRenderObjects(); //apply props - Superclass::ApplyProperties( m_ContourActor, NULL ); - this->ApplyProperties(NULL); + this->ApplyProperties(m_ContourActor,NULL); } void mitk::PointSetVtkMapper3D::GenerateData( mitk::BaseRenderer *renderer ) { SetVtkMapperImmediateModeRendering(m_VtkSelectedPolyDataMapper); SetVtkMapperImmediateModeRendering(m_VtkUnselectedPolyDataMapper); mitk::FloatProperty::Pointer pointSizeProp = dynamic_cast(this->GetDataNode()->GetProperty("pointsize")); mitk::FloatProperty::Pointer contourSizeProp = dynamic_cast(this->GetDataNode()->GetProperty("contoursize")); // only create new vtk render objects if property values were changed if ( pointSizeProp.IsNotNull() && contourSizeProp.IsNotNull() ) { if (m_PointSize!=pointSizeProp->GetValue() || m_ContourRadius!= contourSizeProp->GetValue()) { this->CreateVTKRenderObjects(); } } - - Superclass::ApplyProperties( m_ContourActor, renderer ); - this->ApplyProperties(renderer); + this->ApplyProperties(m_ContourActor,renderer); if(IsVisible(renderer)==false) { m_UnselectedActor->VisibilityOff(); m_SelectedActor->VisibilityOff(); m_ContourActor->VisibilityOff(); return; } bool showPoints = true; this->GetDataNode()->GetBoolProperty("show points", showPoints); if(showPoints) { m_UnselectedActor->VisibilityOn(); m_SelectedActor->VisibilityOn(); } else { m_UnselectedActor->VisibilityOff(); m_SelectedActor->VisibilityOff(); } if(dynamic_cast(this->GetDataNode()->GetProperty("opacity")) != NULL) { mitk::FloatProperty::Pointer pointOpacity =dynamic_cast(this->GetDataNode()->GetProperty("opacity")); float opacity = pointOpacity->GetValue(); m_ContourActor->GetProperty()->SetOpacity(opacity); m_UnselectedActor->GetProperty()->SetOpacity(opacity); m_SelectedActor->GetProperty()->SetOpacity(opacity); } bool makeContour = false; this->GetDataNode()->GetBoolProperty("show contour", makeContour); if (makeContour) { m_ContourActor->VisibilityOn(); } else { m_ContourActor->VisibilityOff(); } } void mitk::PointSetVtkMapper3D::ResetMapper( BaseRenderer* /*renderer*/ ) { m_PointsAssembly->VisibilityOff(); } vtkProp* mitk::PointSetVtkMapper3D::GetVtkProp(mitk::BaseRenderer * /*renderer*/) { return m_PointsAssembly; } void mitk::PointSetVtkMapper3D::UpdateVtkTransform(mitk::BaseRenderer * /*renderer*/) { vtkLinearTransform * vtktransform = this->GetDataNode()->GetVtkTransform(this->GetTimestep()); m_SelectedActor->SetUserTransform(vtktransform); m_UnselectedActor->SetUserTransform(vtktransform); m_ContourActor->SetUserTransform(vtktransform); } -void mitk::PointSetVtkMapper3D::ApplyProperties(mitk::BaseRenderer* renderer) +void mitk::PointSetVtkMapper3D::ApplyProperties(vtkActor* actor, mitk::BaseRenderer* renderer) { + Superclass::ApplyProperties(actor,renderer); //check for color props and use it for rendering of selected/unselected points and contour //due to different params in VTK (double/float) we have to convert! //vars to convert to vtkFloatingPointType unselectedColor[4]={1.0f,1.0f,0.0f,1.0f};//yellow vtkFloatingPointType selectedColor[4]={1.0f,0.0f,0.0f,1.0f};//red vtkFloatingPointType contourColor[4]={1.0f,0.0f,0.0f,1.0f};//red //different types for color!!! mitk::Color tmpColor; double opacity = 1.0; //check if there is an unselected property if (dynamic_cast(this->GetDataNode()->GetPropertyList(renderer)->GetProperty("unselectedcolor")) != NULL) { tmpColor = dynamic_cast(this->GetDataNode()->GetPropertyList(renderer)->GetProperty("unselectedcolor"))->GetValue(); unselectedColor[0] = tmpColor[0]; unselectedColor[1] = tmpColor[1]; unselectedColor[2] = tmpColor[2]; unselectedColor[3] = 1.0f; //!!define a new ColorProp to be able to pass alpha value } else if (dynamic_cast(this->GetDataNode()->GetPropertyList(NULL)->GetProperty("unselectedcolor")) != NULL) { tmpColor = dynamic_cast(this->GetDataNode()->GetPropertyList(NULL)->GetProperty("unselectedcolor"))->GetValue(); unselectedColor[0] = tmpColor[0]; unselectedColor[1] = tmpColor[1]; unselectedColor[2] = tmpColor[2]; unselectedColor[3] = 1.0f; //!!define a new ColorProp to be able to pass alpha value } else { //check if the node has a color float unselectedColorTMP[4]={1.0f,1.0f,0.0f,1.0f};//yellow m_DataNode->GetColor(unselectedColorTMP, NULL); unselectedColor[0] = unselectedColorTMP[0]; unselectedColor[1] = unselectedColorTMP[1]; unselectedColor[2] = unselectedColorTMP[2]; //unselectedColor[3] stays 1.0f } //get selected property if (dynamic_cast(this->GetDataNode()->GetPropertyList(renderer)->GetProperty("selectedcolor")) != NULL) { tmpColor = dynamic_cast(this->GetDataNode()->GetPropertyList(renderer)->GetProperty("selectedcolor"))->GetValue(); selectedColor[0] = tmpColor[0]; selectedColor[1] = tmpColor[1]; selectedColor[2] = tmpColor[2]; selectedColor[3] = 1.0f; } else if (dynamic_cast(this->GetDataNode()->GetPropertyList(NULL)->GetProperty("selectedcolor")) != NULL) { tmpColor = dynamic_cast(this->GetDataNode()->GetPropertyList(NULL)->GetProperty("selectedcolor"))->GetValue(); selectedColor[0] = tmpColor[0]; selectedColor[1] = tmpColor[1]; selectedColor[2] = tmpColor[2]; selectedColor[3] = 1.0f; } //get contour property if (dynamic_cast(this->GetDataNode()->GetPropertyList(renderer)->GetProperty("contourcolor")) != NULL) { tmpColor = dynamic_cast(this->GetDataNode()->GetPropertyList(renderer)->GetProperty("contourcolor"))->GetValue(); contourColor[0] = tmpColor[0]; contourColor[1] = tmpColor[1]; contourColor[2] = tmpColor[2]; contourColor[3] = 1.0f; } else if (dynamic_cast(this->GetDataNode()->GetPropertyList(NULL)->GetProperty("contourcolor")) != NULL) { tmpColor = dynamic_cast(this->GetDataNode()->GetPropertyList(NULL)->GetProperty("contourcolor"))->GetValue(); contourColor[0] = tmpColor[0]; contourColor[1] = tmpColor[1]; contourColor[2] = tmpColor[2]; contourColor[3] = 1.0f; } if(dynamic_cast(this->GetDataNode()->GetPropertyList(renderer)->GetProperty("opacity")) != NULL) { mitk::FloatProperty::Pointer pointOpacity =dynamic_cast(this->GetDataNode()->GetPropertyList(renderer)->GetProperty("opacity")); opacity = pointOpacity->GetValue(); } else if(dynamic_cast(this->GetDataNode()->GetPropertyList(NULL)->GetProperty("opacity")) != NULL) { mitk::FloatProperty::Pointer pointOpacity =dynamic_cast(this->GetDataNode()->GetPropertyList(NULL)->GetProperty("opacity")); opacity = pointOpacity->GetValue(); } //finished color / opacity fishing! //check if a contour shall be drawn bool makeContour = false; this->GetDataNode()->GetBoolProperty("show contour", makeContour, renderer); int visibleBefore = m_ContourActor->GetVisibility(); if(makeContour && (m_ContourActor != NULL) ) { if ( visibleBefore == 0)//was not visible before, so create it. this->CreateContour(renderer); m_ContourActor->GetProperty()->SetColor(contourColor); m_ContourActor->GetProperty()->SetOpacity(opacity); } m_SelectedActor->GetProperty()->SetColor(selectedColor); m_SelectedActor->GetProperty()->SetOpacity(opacity); m_UnselectedActor->GetProperty()->SetColor(unselectedColor); m_UnselectedActor->GetProperty()->SetOpacity(opacity); } void mitk::PointSetVtkMapper3D::CreateContour(mitk::BaseRenderer* renderer) { vtkAppendPolyData* vtkContourPolyData = vtkAppendPolyData::New(); vtkPolyDataMapper* vtkContourPolyDataMapper = vtkPolyDataMapper::New(); vtkPoints *points = vtkPoints::New(); vtkCellArray *polys = vtkCellArray::New(); mitk::PointSet::PointsContainer::Iterator pointsIter; mitk::PointSet::PointDataContainer::Iterator pointDataIter; int j; // get and update the PointSet mitk::PointSet::Pointer input = const_cast(this->GetInput()); //input->Update(); int timestep = this->GetTimestep(); mitk::PointSet::DataType::Pointer itkPointSet = input->GetPointSet( timestep ); if ( itkPointSet.GetPointer() == NULL) { return; } for (j=0, pointsIter=itkPointSet->GetPoints()->Begin(); pointsIter!=itkPointSet->GetPoints()->End() ; pointsIter++,j++) { vtkIdType cell[2] = {j-1,j}; itk::Point point1 = pointsIter->Value(); points->InsertPoint(j,point1[0],point1[1],point1[2]); if (j>0) polys->InsertNextCell(2,cell); } bool close; if (dynamic_cast(this->GetDataNode()->GetPropertyList()->GetProperty("close contour"), renderer) == NULL) close = false; else close = dynamic_cast(this->GetDataNode()->GetPropertyList()->GetProperty("close contour"), renderer)->GetValue(); if (close) { vtkIdType cell[2] = {j-1,0}; polys->InsertNextCell(2,cell); } vtkPolyData* contour = vtkPolyData::New(); contour->SetPoints(points); points->Delete(); contour->SetLines(polys); polys->Delete(); contour->Update(); vtkTubeFilter* tubeFilter = vtkTubeFilter::New(); tubeFilter->SetNumberOfSides( 12 ); tubeFilter->SetInput(contour); contour->Delete(); //check for property contoursize. m_ContourRadius = 0.5; mitk::FloatProperty::Pointer contourSizeProp = dynamic_cast(this->GetDataNode()->GetProperty("contoursize") ); if (contourSizeProp.IsNotNull()) m_ContourRadius = contourSizeProp->GetValue(); tubeFilter->SetRadius( m_ContourRadius ); tubeFilter->Update(); //add to pipeline vtkContourPolyData->AddInput(tubeFilter->GetOutput()); tubeFilter->Delete(); vtkContourPolyDataMapper->SetInput(vtkContourPolyData->GetOutput()); vtkContourPolyData->Delete(); //create a new instance of the actor m_ContourActor->Delete(); m_ContourActor = vtkActor::New(); m_ContourActor->SetMapper(vtkContourPolyDataMapper); vtkContourPolyDataMapper->Delete(); m_PointsAssembly->AddPart(m_ContourActor); } void mitk::PointSetVtkMapper3D::SetDefaultProperties(mitk::DataNode* node, mitk::BaseRenderer* renderer, bool overwrite) { node->AddProperty( "line width", mitk::IntProperty::New(2), renderer, overwrite ); node->AddProperty( "pointsize", mitk::FloatProperty::New(1.0), renderer, overwrite); node->AddProperty( "selectedcolor", mitk::ColorProperty::New(1.0f, 0.0f, 0.0f), renderer, overwrite); //red node->AddProperty( "color", mitk::ColorProperty::New(1.0f, 1.0f, 0.0f), renderer, overwrite); //yellow node->AddProperty( "show contour", mitk::BoolProperty::New(false), renderer, overwrite ); node->AddProperty( "contourcolor", mitk::ColorProperty::New(1.0f, 0.0f, 0.0f), renderer, overwrite); node->AddProperty( "contoursize", mitk::FloatProperty::New(0.5), renderer, overwrite ); node->AddProperty( "show points", mitk::BoolProperty::New(true), renderer, overwrite ); node->AddProperty( "updateDataOnRender", mitk::BoolProperty::New(true), renderer, overwrite ); Superclass::SetDefaultProperties(node, renderer, overwrite); } diff --git a/Core/Code/Rendering/mitkPointSetVtkMapper3D.h b/Core/Code/Rendering/mitkPointSetVtkMapper3D.h index cd5ecd542a..ad4e5886b1 100755 --- a/Core/Code/Rendering/mitkPointSetVtkMapper3D.h +++ b/Core/Code/Rendering/mitkPointSetVtkMapper3D.h @@ -1,158 +1,158 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef MITKPointSetVtkMAPPER3D_H_HEADER_INCLUDED_C1907273 #define MITKPointSetVtkMAPPER3D_H_HEADER_INCLUDED_C1907273 #include "mitkCommon.h" #include "mitkVtkMapper3D.h" #include "mitkBaseRenderer.h" class vtkActor; class vtkPropAssembly; class vtkAppendPolyData; class vtkPolyData; class vtkTubeFilter; class vtkPolyDataMapper; namespace mitk { class PointSet; /** * @brief Vtk-based mapper for PointSet * * Due to the need of different colors for selected * and unselected points and the facts, that we also have a contour and * labels for the points, the vtk structure is build up the following way: * * We have two AppendPolyData, one selected, and one unselected and one * for a contour between the points. Each one is connected to an own * PolyDaraMapper and an Actor. The different color for the unselected and * selected state and for the contour is read from properties. * * "unselectedcolor", "selectedcolor" and "contourcolor" are the strings, * that are looked for. Pointlabels are added besides the selected or the * deselected points. * * Then the three Actors are combined inside a vtkPropAssembly and this * object is returned in GetProp() and so hooked up into the rendering * pipeline. * Properties that can be set for point sets and influence the PointSetVTKMapper3D are: * * - \b "color": (ColorProperty*) Color of the point set * - \b "Opacity": (FloatProperty) Opacity of the point set * - \b "show contour": (BoolProperty) If the contour of the points are visible * - \b "contourSizeProp":(FloatProperty) Contour size of the points The default properties are: * - \b "line width": (IntProperty::New(2), renderer, overwrite ) * - \b "pointsize": (FloatProperty::New(1.0), renderer, overwrite) * - \b "selectedcolor": (ColorProperty::New(1.0f, 0.0f, 0.0f), renderer, overwrite) //red * - \b "color": (ColorProperty::New(1.0f, 1.0f, 0.0f), renderer, overwrite) //yellow * - \b "show contour": (BoolProperty::New(false), renderer, overwrite ) * - \b "contourcolor": (ColorProperty::New(1.0f, 0.0f, 0.0f), renderer, overwrite) * - \b "contoursize": (FloatProperty::New(0.5), renderer, overwrite ) * - \b "close contour": (BoolProperty::New(false), renderer, overwrite ) * - \b "show points": (BoolProperty::New(true), renderer, overwrite ) * - \b "updateDataOnRender": (BoolProperty::New(true), renderer, overwrite ) *Other properties looked for are: * * - \b "show contour": if set to on, lines between the points are shown * - \b "close contour": if set to on, the open strip is closed (first point * connected with last point) * - \b "pointsize": size of the points mapped * - \b "label": text of the Points to show besides points * - \b "contoursize": size of the contour drawn between the points * (if not set, the pointsize is taken) * * @ingroup Mapper */ class MITK_CORE_EXPORT PointSetVtkMapper3D : public VtkMapper3D { public: mitkClassMacro(PointSetVtkMapper3D, VtkMapper3D); itkNewMacro(Self); virtual const mitk::PointSet* GetInput(); //overwritten from VtkMapper3D to be able to return a //m_PointsAssembly which is much faster than a vtkAssembly virtual vtkProp* GetVtkProp(mitk::BaseRenderer* renderer); virtual void UpdateVtkTransform(mitk::BaseRenderer* renderer); static void SetDefaultProperties(mitk::DataNode* node, mitk::BaseRenderer* renderer = NULL, bool overwrite = false); void ReleaseGraphicsResources(vtkWindow *renWin); protected: PointSetVtkMapper3D(); virtual ~PointSetVtkMapper3D(); virtual void GenerateData(); virtual void GenerateData(mitk::BaseRenderer* renderer); virtual void ResetMapper( BaseRenderer* renderer ); - virtual void ApplyProperties(mitk::BaseRenderer* renderer); + virtual void ApplyProperties(vtkActor* actor, mitk::BaseRenderer* renderer); virtual void CreateContour(mitk::BaseRenderer* renderer); virtual void CreateVTKRenderObjects(); vtkAppendPolyData *m_vtkSelectedPointList; vtkAppendPolyData *m_vtkUnselectedPointList; // vtkAppendPolyData *m_vtkContourPolyData; vtkPolyDataMapper *m_VtkSelectedPolyDataMapper; vtkPolyDataMapper *m_VtkUnselectedPolyDataMapper; // vtkPolyDataMapper *m_vtkContourPolyDataMapper; vtkActor *m_SelectedActor; vtkActor *m_UnselectedActor; vtkActor *m_ContourActor; vtkPropAssembly *m_PointsAssembly; //help for contour between points vtkAppendPolyData *m_vtkTextList; //vtkPolyData *m_Contour; //vtkTubeFilter *m_TubeFilter; //variables to be able to log, how many inputs have been added to PolyDatas unsigned int m_NumberOfSelectedAdded; unsigned int m_NumberOfUnselectedAdded; //variables to check if an update of the vtk objects is needed ScalarType m_PointSize; ScalarType m_ContourRadius; }; } // namespace mitk #endif /* MITKPointSetVtkMAPPER3D_H_HEADER_INCLUDED_C1907273 */ diff --git a/Core/Code/Rendering/mitkSurfaceGLMapper2D.cpp b/Core/Code/Rendering/mitkSurfaceGLMapper2D.cpp index f4ed1d65e0..d0e2343b99 100644 --- a/Core/Code/Rendering/mitkSurfaceGLMapper2D.cpp +++ b/Core/Code/Rendering/mitkSurfaceGLMapper2D.cpp @@ -1,543 +1,543 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include #include "mitkSurfaceGLMapper2D.h" #include "mitkBaseRenderer.h" #include "mitkPlaneGeometry.h" #include "mitkSurface.h" #include "mitkColorProperty.h" #include "mitkProperties.h" #include "mitkVtkScalarModeProperty.h" #include "mitkAbstractTransformGeometry.h" #include "mitkLookupTableProperty.h" #include #include #include #include #include #include #include #include #include #include #include #include #include mitk::SurfaceGLMapper2D::SurfaceGLMapper2D() : m_Plane( vtkPlane::New() ), m_Cutter( vtkCutter::New() ), m_LUT( vtkLookupTable::New() ), m_PointLocator( vtkPKdTree::New() ), m_Stripper( vtkStripper::New() ), m_DrawNormals(false), m_FrontNormalLengthInPixels(10.0), m_BackNormalLengthInPixels(10.0) { // default for normals on front side = green m_FrontSideColor[0] = 0.0; m_FrontSideColor[1] = 1.0; m_FrontSideColor[2] = 0.0; m_FrontSideColor[3] = 1.0; // default for normals on back side = red m_BackSideColor[0] = 1.0; m_BackSideColor[1] = 0.0; m_BackSideColor[2] = 0.0; m_BackSideColor[3] = 1.0; // default for line color = yellow m_LineColor[0] = 1.0; m_LineColor[1] = 1.0; m_LineColor[2] = 0.0; m_LineColor[3] = 1.0; m_Cutter->SetCutFunction(m_Plane); m_Cutter->GenerateValues(1,0,1); m_LUT->SetTableRange(0,255); m_LUT->SetNumberOfColors(255); m_LUT->SetRampToLinear(); m_LUT->Build(); } mitk::SurfaceGLMapper2D::~SurfaceGLMapper2D() { m_Plane->Delete(); m_Cutter->Delete(); m_LUT->Delete(); m_PointLocator->Delete(); m_Stripper->Delete(); } const mitk::Surface *mitk::SurfaceGLMapper2D::GetInput(void) { if(m_Surface.IsNotNull()) return m_Surface; return static_cast ( GetData() ); } -void mitk::SurfaceGLMapper2D::SetDataNode( mitk::DataNode::Pointer node ) +void mitk::SurfaceGLMapper2D::SetDataNode( mitk::DataNode* node ) { Superclass::SetDataNode( node ); bool useCellData; if (dynamic_cast(node->GetProperty("deprecated useCellDataForColouring")) == NULL) useCellData = false; else useCellData = dynamic_cast(node->GetProperty("deprecated useCellDataForColouring"))->GetValue(); if (!useCellData) { // search min/max point scalars over all time steps vtkFloatingPointType dataRange[2] = {0,0}; vtkFloatingPointType range[2]; Surface::Pointer input = const_cast< Surface* >(dynamic_cast( this->GetDataNode()->GetData() )); if(input.IsNull()) return; const TimeSlicedGeometry::Pointer inputTimeGeometry = input->GetTimeSlicedGeometry(); if(( inputTimeGeometry.IsNull() ) || ( inputTimeGeometry->GetTimeSteps() == 0 ) ) return; for (unsigned int timestep=0; timestepGetTimeSteps(); timestep++) { vtkPolyData * vtkpolydata = input->GetVtkPolyData( timestep ); if((vtkpolydata==NULL) || (vtkpolydata->GetNumberOfPoints() < 1 )) continue; vtkDataArray *vpointscalars = vtkpolydata->GetPointData()->GetScalars(); if (vpointscalars) { vpointscalars->GetRange( range, 0 ); if (dataRange[0]==0 && dataRange[1]==0) { dataRange[0] = range[0]; dataRange[1] = range[1]; } else { if (range[0] < dataRange[0]) dataRange[0] = range[0]; if (range[1] > dataRange[1]) dataRange[1] = range[1]; } } } if (dataRange[1] - dataRange[0] > 0) { m_LUT->SetTableRange( dataRange ); m_LUT->Build(); } } } void mitk::SurfaceGLMapper2D::Paint(mitk::BaseRenderer * renderer) { if(IsVisible(renderer)==false) return; Surface::Pointer input = const_cast(this->GetInput()); if(input.IsNull()) return; // // get the TimeSlicedGeometry of the input object // const TimeSlicedGeometry* inputTimeGeometry = input->GetTimeSlicedGeometry(); if(( inputTimeGeometry == NULL ) || ( inputTimeGeometry->GetTimeSteps() == 0 ) ) return; if (dynamic_cast(this->GetDataNode()->GetProperty("line width")) == NULL) m_LineWidth = 1; else m_LineWidth = dynamic_cast(this->GetDataNode()->GetProperty("line width"))->GetValue(); // // get the world time // Geometry2D::ConstPointer worldGeometry = renderer->GetCurrentWorldGeometry2D(); assert( worldGeometry.IsNotNull() ); ScalarType time = worldGeometry->GetTimeBounds()[ 0 ]; int timestep=0; if( time > ScalarTypeNumericTraits::NonpositiveMin() ) timestep = inputTimeGeometry->MSToTimeStep( time ); // int timestep = this->GetTimestep(); if( inputTimeGeometry->IsValidTime( timestep ) == false ) return; vtkPolyData * vtkpolydata = input->GetVtkPolyData( timestep ); if((vtkpolydata==NULL) || (vtkpolydata->GetNumberOfPoints() < 1 )) return; PlaneGeometry::ConstPointer worldPlaneGeometry = dynamic_cast(worldGeometry.GetPointer()); //apply color and opacity read from the PropertyList ApplyProperties(renderer); if (m_DrawNormals) { m_PointLocator->SetDataSet( vtkpolydata ); m_PointLocator->BuildLocatorFromPoints( vtkpolydata->GetPoints() ); } if(vtkpolydata!=NULL) { Point3D point; Vector3D normal; //Check if Lookup-Table is already given, else use standard one. vtkFloatingPointType* scalarLimits = m_LUT->GetTableRange(); vtkFloatingPointType scalarsMin = scalarLimits[0], scalarsMax = scalarLimits[1]; vtkLookupTable *lut;// = vtkLookupTable::New(); LookupTableProperty::Pointer lookupTableProp; this->GetDataNode()->GetProperty(lookupTableProp, "LookupTable", renderer); if (lookupTableProp.IsNotNull() ) { lut = lookupTableProp->GetLookupTable()->GetVtkLookupTable(); if (dynamic_cast(this->GetDataNode()->GetProperty("ScalarsRangeMinimum")) != NULL) scalarsMin = dynamic_cast(this->GetDataNode()->GetProperty("ScalarsRangeMinimum"))->GetValue(); if (dynamic_cast(this->GetDataNode()->GetProperty("ScalarsRangeMaximum")) != NULL) scalarsMax = dynamic_cast(this->GetDataNode()->GetProperty("ScalarsRangeMaximum"))->GetValue(); // check if the scalar range has been changed, e.g. manually, for the data tree node, and rebuild the LUT if necessary. double* oldRange = lut->GetTableRange(); if( oldRange[0] != scalarsMin || oldRange[1] != scalarsMax ) { lut->SetTableRange(scalarsMin, scalarsMax); lut->Build(); } } else { lut = m_LUT; } vtkLinearTransform * vtktransform = GetDataNode()->GetVtkTransform(timestep); if(worldPlaneGeometry.IsNotNull()) { // set up vtkPlane according to worldGeometry point=worldPlaneGeometry->GetOrigin(); normal=worldPlaneGeometry->GetNormal(); normal.Normalize(); m_Plane->SetTransform((vtkAbstractTransform*)NULL); } else { AbstractTransformGeometry::ConstPointer worldAbstractGeometry = dynamic_cast(renderer->GetCurrentWorldGeometry2D()); if(worldAbstractGeometry.IsNotNull()) { AbstractTransformGeometry::ConstPointer surfaceAbstractGeometry = dynamic_cast(input->GetTimeSlicedGeometry()->GetGeometry3D(0)); if(surfaceAbstractGeometry.IsNotNull()) //@todo substitude by operator== after implementation, see bug id 28 { PaintCells(renderer, vtkpolydata, worldGeometry, renderer->GetDisplayGeometry(), vtktransform, lut); return; } else { //@FIXME: does not work correctly. Does m_Plane->SetTransform really transforms a "flat plane" into a "curved plane"? return; // set up vtkPlane according to worldGeometry point=const_cast(worldAbstractGeometry->GetParametricBoundingBox())->GetMinimum(); FillVector3D(normal, 0, 0, 1); m_Plane->SetTransform(worldAbstractGeometry->GetVtkAbstractTransform()->GetInverse()); } } else return; } vtkFloatingPointType vp[3], vnormal[3]; vnl2vtk(point.Get_vnl_vector(), vp); vnl2vtk(normal.Get_vnl_vector(), vnormal); //normally, we would need to transform the surface and cut the transformed surface with the cutter. //This might be quite slow. Thus, the idea is, to perform an inverse transform of the plane instead. //@todo It probably does not work for scaling operations yet:scaling operations have to be //dealed with after the cut is performed by scaling the contour. vtkLinearTransform * inversetransform = vtktransform->GetLinearInverse(); inversetransform->TransformPoint(vp, vp); inversetransform->TransformNormalAtPoint(vp, vnormal, vnormal); m_Plane->SetOrigin(vp); m_Plane->SetNormal(vnormal); //set data into cutter m_Cutter->SetInput(vtkpolydata); m_Cutter->Update(); // m_Cutter->GenerateCutScalarsOff(); // m_Cutter->SetSortByToSortByCell(); if (m_DrawNormals) { m_Stripper->SetInput( m_Cutter->GetOutput() ); // calculate the cut m_Stripper->Update(); PaintCells(renderer, m_Stripper->GetOutput(), worldGeometry, renderer->GetDisplayGeometry(), vtktransform, lut, vtkpolydata); } else { PaintCells(renderer, m_Cutter->GetOutput(), worldGeometry, renderer->GetDisplayGeometry(), vtktransform, lut, vtkpolydata); } } } void mitk::SurfaceGLMapper2D::PaintCells(mitk::BaseRenderer* renderer, vtkPolyData* contour, const Geometry2D* worldGeometry, const DisplayGeometry* displayGeometry, vtkLinearTransform * vtktransform, vtkLookupTable *lut, vtkPolyData* original3DObject) { // deprecated settings bool usePointData = false; bool useCellData = false; this->GetDataNode()->GetBoolProperty("deprecated useCellDataForColouring", useCellData); bool scalarVisibility = false; this->GetDataNode()->GetBoolProperty("scalar visibility", scalarVisibility); if(scalarVisibility) { VtkScalarModeProperty* scalarMode; if(this->GetDataNode()->GetProperty(scalarMode, "scalar mode", renderer)) { if( (scalarMode->GetVtkScalarMode() == VTK_SCALAR_MODE_USE_POINT_DATA) || (scalarMode->GetVtkScalarMode() == VTK_SCALAR_MODE_DEFAULT) ) { usePointData = true; } if(scalarMode->GetVtkScalarMode() == VTK_SCALAR_MODE_USE_CELL_DATA) { useCellData = true; } } else { usePointData = true; } } vtkPoints *vpoints = contour->GetPoints(); vtkDataArray *vpointscalars = contour->GetPointData()->GetScalars(); vtkCellArray *vlines = contour->GetLines(); vtkDataArray* vcellscalars = contour->GetCellData()->GetScalars(); Point3D p; Point2D p2d, last; int i, j; int numberOfLines = vlines->GetNumberOfCells(); glLineWidth( m_LineWidth ); glBegin (GL_LINES); glColor4fv(m_LineColor); double distanceSinceLastNormal(0.0); vlines->InitTraversal(); for(i=0;iGetNextCell(cellSize, cell); vpoints->GetPoint(cell[0], vp); //take transformation via vtktransform into account vtktransform->TransformPoint(vp, vp); vtk2itk(vp, p); //convert 3D point (in mm) to 2D point on slice (also in mm) worldGeometry->Map(p, p2d); //convert point (until now mm and in world coordinates) to display coordinates (units ) displayGeometry->WorldToDisplay(p2d, p2d); last=p2d; for(j=1; jGetPoint(cell[j], vp); Point3D originalPoint; vtk2itk(vp, originalPoint); //take transformation via vtktransform into account vtktransform->TransformPoint(vp, vp); vtk2itk(vp, p); //convert 3D point (in mm) to 2D point on slice (also in mm) worldGeometry->Map(p, p2d); //convert point (until now mm and in world coordinates) to display coordinates (units ) displayGeometry->WorldToDisplay(p2d, p2d); vtkFloatingPointType color[3]; if (useCellData && vcellscalars != NULL ) { // color each cell according to cell data lut->GetColor( vcellscalars->GetComponent(i,0),color); glColor3f(color[0],color[1],color[2]); glVertex2f(last[0], last[1]); glVertex2f(p2d[0], p2d[1]); } else if (usePointData && vpointscalars != NULL ) { lut->GetColor( vpointscalars->GetComponent(cell[j-1],0),color); glColor3f(color[0],color[1],color[2]); glVertex2f(last[0], last[1]); lut->GetColor( vpointscalars->GetComponent(cell[j],0),color); glColor3f(color[0],color[1],color[2]); glVertex2f(p2d[0], p2d[1]); } else { glVertex2f(last[0], last[1]); glVertex2f(p2d[0], p2d[1]); // draw normals ? if (m_DrawNormals && original3DObject) { distanceSinceLastNormal += sqrt((p2d[0]-last[0])*(p2d[0]-last[0]) + (p2d[1]-last[1])*(p2d[1]-last[1])); if (distanceSinceLastNormal >= 5.0) { distanceSinceLastNormal = 0.0; vtkPointData* pointData = original3DObject->GetPointData(); if (!pointData) break; vtkDataArray* normalsArray = pointData->GetNormals(); if (!normalsArray) break; // find 3D point closest to the currently drawn point double distance(0.0); vtkIdType closestPointId = m_PointLocator->FindClosestPoint(originalPoint[0], originalPoint[1], originalPoint[2], distance); if (closestPointId >= 0) { // find normal of 3D object at this 3D point double* normal = normalsArray->GetTuple3(closestPointId); double transformedNormal[3]; vtktransform->TransformNormal(normal, transformedNormal); Vector3D normalITK; vtk2itk(transformedNormal, normalITK); normalITK.Normalize(); // calculate a point (point from the cut 3D object) + (normal vector of closest point) Point3D tip3D = p + normalITK; // map this point into our 2D coordinate system Point2D tip2D; worldGeometry->Map(tip3D, tip2D); displayGeometry->WorldToDisplay(tip2D, tip2D); // calculate 2D vector from point to point+normal, normalize it to standard length Vector2D tipVectorGLFront = tip2D - p2d; tipVectorGLFront.Normalize(); tipVectorGLFront *= m_FrontNormalLengthInPixels; Vector2D tipVectorGLBack = p2d - tip2D; tipVectorGLBack.Normalize(); tipVectorGLBack *= m_BackNormalLengthInPixels; Point2D tipPoint2D = p2d + tipVectorGLFront; Point2D backTipPoint2D = p2d + tipVectorGLBack; // draw normalized mapped normal vector glColor4f(m_BackSideColor[0], m_BackSideColor[1], m_BackSideColor[2], m_BackSideColor[3]); // red backside glVertex2f(p2d[0], p2d[1]); glVertex2f(tipPoint2D[0], tipPoint2D[1]); glColor4f(m_FrontSideColor[0], m_FrontSideColor[1], m_FrontSideColor[2], m_FrontSideColor[3]); // green backside glVertex2f(p2d[0], p2d[1]); glVertex2f(backTipPoint2D[0], backTipPoint2D[1]); glColor4fv(m_LineColor); // back to line color } } } } last=p2d; } } glEnd(); glLineWidth(1.0); } void mitk::SurfaceGLMapper2D::SetDefaultProperties(mitk::DataNode* node, mitk::BaseRenderer* renderer, bool overwrite) { node->AddProperty( "line width", IntProperty::New(2), renderer, overwrite ); node->AddProperty( "scalar mode", VtkScalarModeProperty::New(), renderer, overwrite ); node->AddProperty( "draw normals 2D", BoolProperty::New(false), renderer, overwrite ); node->AddProperty( "invert normals", BoolProperty::New(false), renderer, overwrite ); node->AddProperty( "front color", ColorProperty::New(0.0, 1.0, 0.0), renderer, overwrite ); node->AddProperty( "back color", ColorProperty::New(1.0, 0.0, 0.0), renderer, overwrite ); node->AddProperty( "front normal lenth (px)", FloatProperty::New(10.0), renderer, overwrite ); node->AddProperty( "back normal lenth (px)", FloatProperty::New(10.0), renderer, overwrite ); node->AddProperty( "layer", mitk::IntProperty::New(100), renderer, overwrite); Superclass::SetDefaultProperties(node, renderer, overwrite); } void mitk::SurfaceGLMapper2D::ApplyProperties(mitk::BaseRenderer* renderer) { Superclass::ApplyProperties(renderer); GetDataNode()->GetBoolProperty("draw normals 2D", m_DrawNormals, renderer); // check for color and opacity properties, use it for rendering if they exists GetColor(m_LineColor, renderer /*, "color" */); GetOpacity(m_LineColor[3], renderer /*, "color" */); bool invertNormals(false); if (DataNode* node = GetDataNode()) { node->GetBoolProperty("invert normals", invertNormals, renderer); } if (!invertNormals) { GetColor(m_FrontSideColor, renderer, "front color"); GetOpacity(m_FrontSideColor[3], renderer); GetColor(m_BackSideColor, renderer, "back color"); GetOpacity(m_BackSideColor[3], renderer); if (DataNode* node = GetDataNode()) { node->GetFloatProperty( "front normal lenth (px)", m_FrontNormalLengthInPixels, renderer ); node->GetFloatProperty( "back normal lenth (px)", m_BackNormalLengthInPixels, renderer ); } } else { GetColor(m_FrontSideColor, renderer, "back color"); GetOpacity(m_FrontSideColor[3], renderer); GetColor(m_BackSideColor, renderer, "front color"); GetOpacity(m_BackSideColor[3], renderer); if (DataNode* node = GetDataNode()) { node->GetFloatProperty( "back normal lenth (px)", m_FrontNormalLengthInPixels, renderer ); node->GetFloatProperty( "front normal lenth (px)", m_BackNormalLengthInPixels, renderer ); } } } diff --git a/Core/Code/Rendering/mitkSurfaceGLMapper2D.h b/Core/Code/Rendering/mitkSurfaceGLMapper2D.h index 6553fc1723..435c92b807 100644 --- a/Core/Code/Rendering/mitkSurfaceGLMapper2D.h +++ b/Core/Code/Rendering/mitkSurfaceGLMapper2D.h @@ -1,156 +1,156 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef MITKSURFACEDATAMAPPER2D_H_HEADER_INCLUDED_C10EB2E8 #define MITKSURFACEDATAMAPPER2D_H_HEADER_INCLUDED_C10EB2E8 #include "mitkCommon.h" #include "mitkGLMapper2D.h" #include "mitkSurface.h" class vtkCutter; class vtkPlane; class vtkLookupTable; class vtkLinearTransform; class vtkPKdTree; class vtkStripper; namespace mitk { class BaseRenderer; class Geometry2D; class DisplayGeometry; /** * @brief OpenGL-based mapper to display a Surface in a 2D window. * * Displays a 2D cut through a Surface object (vtkPolyData). This * is basically done in two steps: * * 1. Cut a slice out of a (input) vtkPolyData object. The slice may be a flat plane (PlaneGeometry) * or a curved plane (ThinPlateSplineCurvedGeometry). The actual cutting is done by a vtkCutter. * The result of cutting is a (3D) vtkPolyData object, which contains only points and lines * describing the cut. * * 2. Paint the cut out slice by means of OpenGL. To do this, all lines of the cut object are traversed. * For each line segment, both end points are transformed from 3D into the 2D system of the associated * renderer and then drawn by OpenGL. * * There is a mode to display normals of the input surface object (see properties below). If this mode * is on, then the drawing of the 2D cut is slightly more complicated. For each line segment of the cut, * we take the end point (p2d) of this line and search the input vtkPolyData object for the closest point to p2d (p3D-input). * We then read out the surface normal for p3D-input. We map this normal into our 2D coordinate system and * then draw a line from p2d to (p2d+mapped normal). This drawing of surface normals will only work if the * input vtkPolyData actually HAS normals. If you have a vtkPolyData without normals, use the vtkPolyDataNormals * filter to generate normals. * * Properties that influence rendering are: * * - \b "color": (ColorProperty) Color of surface object * - \b "line width": (IntProperty) Width in pixels of the lines drawn. * - \b "scalar visibility": (BoolProperty) Whether point/cell data values (from vtkPolyData) should be used to influence colors * - \b "scalar mode": (BoolProperty) If "scalar visibility" is on, whether to use point data or cell data for coloring. * - \b "LookupTable": (LookupTableProperty) A lookup table to translate point/cell data values (from vtkPolyData) to colors * - \b "ScalarsRangeMinimum": (FloatProperty) Range of the lookup table * - \b "ScalarsRangeMaximum": (FloatProperty) Range of the lookup table * - \b "draw normals 2D": (BoolProperty) If true, normals are drawn (if present in vtkPolyData) * - \b "invert normals": (BoolProperty) Inverts front/back for display. * - \b "front color": (ColorProperty) Color for normals display on front side of the plane * - \b "front normal length (px)": (FloatProperty) Length of the front side normals in pixels. * - \b "back color": (ColorProperty) Color for normals display on back side of the plane * - \b "back normal length (px)": (FloatProperty) Length of the back side normals in pixels. * */ class MITK_CORE_EXPORT SurfaceGLMapper2D : public GLMapper2D { public: mitkClassMacro(SurfaceGLMapper2D, GLMapper2D); itkNewMacro(Self); const Surface* GetInput(void); virtual void Paint(BaseRenderer* renderer); /** * @brief The Surface to map can be explicitly set by this method. * * If it is set, it is used instead of the data stored in the DataNode. * This enables to use the mapper also internally from other mappers. */ itkSetConstObjectMacro(Surface, Surface); /** * @brief Get the Surface set explicitly. * * @return NULL is returned if no Surface is set to be used instead of DataNode::GetData(). * @sa SetSurface */ itkGetConstObjectMacro(Surface, Surface); /** *\brief Overwritten to initialize lookup table for point scalar data */ - void SetDataNode( DataNode::Pointer node ); + void SetDataNode( DataNode* node ); /** * \brief Generate OpenGL primitives for the VTK contour held in contour. */ void PaintCells(BaseRenderer* renderer, vtkPolyData* contour, const Geometry2D* worldGeometry, const DisplayGeometry* displayGeometry, vtkLinearTransform* vtktransform, vtkLookupTable* lut = NULL, vtkPolyData* original3DObject = NULL); static void SetDefaultProperties(DataNode* node, BaseRenderer* renderer = NULL, bool overwrite = false); virtual void ApplyProperties(BaseRenderer* renderer); protected: SurfaceGLMapper2D(); virtual ~SurfaceGLMapper2D(); vtkPlane* m_Plane; vtkCutter* m_Cutter; Surface::ConstPointer m_Surface; vtkLookupTable* m_LUT; int m_LineWidth; vtkPKdTree* m_PointLocator; vtkStripper* m_Stripper; bool m_DrawNormals; float m_FrontSideColor[4]; float m_BackSideColor[4]; float m_LineColor[4]; float m_FrontNormalLengthInPixels; float m_BackNormalLengthInPixels; }; } // namespace mitk #endif /* MITKSURFACEDATAMAPPER2D_H_HEADER_INCLUDED_C10EB2E8 */ diff --git a/Core/Code/Rendering/mitkSurfaceVtkMapper3D.cpp b/Core/Code/Rendering/mitkSurfaceVtkMapper3D.cpp index 5486b9344d..9d652e843c 100644 --- a/Core/Code/Rendering/mitkSurfaceVtkMapper3D.cpp +++ b/Core/Code/Rendering/mitkSurfaceVtkMapper3D.cpp @@ -1,456 +1,456 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "mitkSurfaceVtkMapper3D.h" #include "mitkDataNode.h" #include "mitkProperties.h" #include "mitkColorProperty.h" #include "mitkLookupTableProperty.h" #include "mitkVtkRepresentationProperty.h" #include "mitkVtkInterpolationProperty.h" #include "mitkVtkScalarModeProperty.h" #include "mitkClippingProperty.h" #include "mitkShaderProperty.h" #include "mitkShaderRepository.h" #include #include #include #include #include #include #include const mitk::Surface* mitk::SurfaceVtkMapper3D::GetInput() { return static_cast ( GetData() ); } mitk::SurfaceVtkMapper3D::SurfaceVtkMapper3D() { // m_Prop3D = vtkActor::New(); m_GenerateNormals = false; } mitk::SurfaceVtkMapper3D::~SurfaceVtkMapper3D() { // m_Prop3D->Delete(); } -void mitk::SurfaceVtkMapper3D::GenerateData(mitk::BaseRenderer* renderer) +void mitk::SurfaceVtkMapper3D::GenerateDataForRenderer(mitk::BaseRenderer* renderer) { LocalStorage *ls = m_LSH.GetLocalStorage(renderer); bool visible = IsVisible(renderer); if(visible==false) { ls->m_Actor->VisibilityOff(); return; } // // set the input-object at time t for the mapper // mitk::Surface::Pointer input = const_cast< mitk::Surface* >( this->GetInput() ); vtkPolyData * polydata = input->GetVtkPolyData( this->GetTimestep() ); if(polydata == NULL) { ls->m_Actor->VisibilityOff(); return; } if ( m_GenerateNormals ) { ls->m_VtkPolyDataNormals->SetInput( polydata ); ls->m_VtkPolyDataMapper->SetInput( ls->m_VtkPolyDataNormals->GetOutput() ); } else { ls->m_VtkPolyDataMapper->SetInput( polydata ); } // // apply properties read from the PropertyList // ApplyProperties(ls->m_Actor, renderer); if(visible) ls->m_Actor->VisibilityOn(); } void mitk::SurfaceVtkMapper3D::ResetMapper( BaseRenderer* renderer ) { LocalStorage *ls = m_LSH.GetLocalStorage(renderer); ls->m_Actor->VisibilityOff(); } void mitk::SurfaceVtkMapper3D::ApplyMitkPropertiesToVtkProperty(mitk::DataNode *node, vtkProperty* property, mitk::BaseRenderer* renderer) { // Colors { double ambient [3] = { 0.5,0.5,0.0 }; double diffuse [3] = { 0.5,0.5,0.0 }; double specular[3] = { 1.0,1.0,1.0 }; float coeff_ambient = 0.5f; float coeff_diffuse = 0.5f; float coeff_specular= 0.5f; float power_specular=10.0f; // Color { mitk::ColorProperty::Pointer p; node->GetProperty(p, "color", renderer); if(p.IsNotNull()) { mitk::Color c = p->GetColor(); ambient[0]=c.GetRed(); ambient[1]=c.GetGreen(); ambient[2]=c.GetBlue(); diffuse[0]=c.GetRed(); diffuse[1]=c.GetGreen(); diffuse[2]=c.GetBlue(); // Setting specular color to the same, make physically no real sense, however vtk rendering slows down, if these colors are different. specular[0]=c.GetRed(); specular[1]=c.GetGreen(); specular[2]=c.GetBlue(); } } // Ambient { mitk::ColorProperty::Pointer p; node->GetProperty(p, "material.ambientColor", renderer); if(p.IsNotNull()) { mitk::Color c = p->GetColor(); ambient[0]=c.GetRed(); ambient[1]=c.GetGreen(); ambient[2]=c.GetBlue(); } } // Diffuse { mitk::ColorProperty::Pointer p; node->GetProperty(p, "material.diffuseColor", renderer); if(p.IsNotNull()) { mitk::Color c = p->GetColor(); diffuse[0]=c.GetRed(); diffuse[1]=c.GetGreen(); diffuse[2]=c.GetBlue(); } } // Specular { mitk::ColorProperty::Pointer p; node->GetProperty(p, "material.specularColor", renderer); if(p.IsNotNull()) { mitk::Color c = p->GetColor(); specular[0]=c.GetRed(); specular[1]=c.GetGreen(); specular[2]=c.GetBlue(); } } // Ambient coeff { node->GetFloatProperty("material.ambientCoefficient", coeff_ambient, renderer); } // Diffuse coeff { node->GetFloatProperty("material.diffuseCoefficient", coeff_diffuse, renderer); } // Specular coeff { node->GetFloatProperty("material.specularCoefficient", coeff_specular, renderer); } // Specular power { node->GetFloatProperty("material.specularPower", power_specular, renderer); } property->SetAmbient( coeff_ambient ); property->SetDiffuse( coeff_diffuse ); property->SetSpecular( coeff_specular ); property->SetSpecularPower( power_specular ); property->SetAmbientColor( ambient ); property->SetDiffuseColor( diffuse ); property->SetSpecularColor( specular ); } // Render mode { // Opacity { float opacity = 1.0f; if( node->GetOpacity(opacity,renderer) ) property->SetOpacity( opacity ); } // Wireframe line width { float lineWidth = 1; node->GetFloatProperty("material.wireframeLineWidth", lineWidth, renderer); property->SetLineWidth( lineWidth ); } // Representation { mitk::VtkRepresentationProperty::Pointer p; node->GetProperty(p, "material.representation", renderer); if(p.IsNotNull()) property->SetRepresentation( p->GetVtkRepresentation() ); } // Interpolation { mitk::VtkInterpolationProperty::Pointer p; node->GetProperty(p, "material.interpolation", renderer); if(p.IsNotNull()) property->SetInterpolation( p->GetVtkInterpolation() ); } } } void mitk::SurfaceVtkMapper3D::ApplyProperties(vtkActor* /*actor*/, mitk::BaseRenderer* renderer) { LocalStorage *ls = m_LSH.GetLocalStorage(renderer); // Applying shading properties { Superclass::ApplyProperties( ls->m_Actor, renderer ) ; // VTK Properties ApplyMitkPropertiesToVtkProperty( this->GetDataNode(), ls->m_Actor->GetProperty(), renderer ); // Shaders mitk::ShaderRepository::GetGlobalShaderRepository()->ApplyProperties(this->GetDataNode(),ls->m_Actor,renderer,ls->m_ShaderTimestampUpdate); } mitk::LookupTableProperty::Pointer lookupTableProp; this->GetDataNode()->GetProperty(lookupTableProp, "LookupTable", renderer); if (lookupTableProp.IsNotNull() ) { ls->m_VtkPolyDataMapper->SetLookupTable(lookupTableProp->GetLookupTable()->GetVtkLookupTable()); } mitk::LevelWindow levelWindow; if(this->GetDataNode()->GetLevelWindow(levelWindow, renderer, "levelWindow")) { ls->m_VtkPolyDataMapper->SetScalarRange(levelWindow.GetLowerWindowBound(),levelWindow.GetUpperWindowBound()); } else if(this->GetDataNode()->GetLevelWindow(levelWindow, renderer)) { ls->m_VtkPolyDataMapper->SetScalarRange(levelWindow.GetLowerWindowBound(),levelWindow.GetUpperWindowBound()); } bool scalarVisibility = false; this->GetDataNode()->GetBoolProperty("scalar visibility", scalarVisibility); ls->m_VtkPolyDataMapper->SetScalarVisibility( (scalarVisibility ? 1 : 0) ); if(scalarVisibility) { mitk::VtkScalarModeProperty* scalarMode; if(this->GetDataNode()->GetProperty(scalarMode, "scalar mode", renderer)) { ls->m_VtkPolyDataMapper->SetScalarMode(scalarMode->GetVtkScalarMode()); } else ls->m_VtkPolyDataMapper->SetScalarModeToDefault(); bool colorMode = false; this->GetDataNode()->GetBoolProperty("color mode", colorMode); ls->m_VtkPolyDataMapper->SetColorMode( (colorMode ? 1 : 0) ); float scalarsMin = 0; if (dynamic_cast(this->GetDataNode()->GetProperty("ScalarsRangeMinimum")) != NULL) scalarsMin = dynamic_cast(this->GetDataNode()->GetProperty("ScalarsRangeMinimum"))->GetValue(); float scalarsMax = 1.0; if (dynamic_cast(this->GetDataNode()->GetProperty("ScalarsRangeMaximum")) != NULL) scalarsMax = dynamic_cast(this->GetDataNode()->GetProperty("ScalarsRangeMaximum"))->GetValue(); ls->m_VtkPolyDataMapper->SetScalarRange(scalarsMin,scalarsMax); } // deprecated settings bool deprecatedUseCellData = false; this->GetDataNode()->GetBoolProperty("deprecated useCellDataForColouring", deprecatedUseCellData); bool deprecatedUsePointData = false; this->GetDataNode()->GetBoolProperty("deprecated usePointDataForColouring", deprecatedUsePointData); if (deprecatedUseCellData) { ls->m_VtkPolyDataMapper->SetColorModeToDefault(); ls->m_VtkPolyDataMapper->SetScalarRange(0,255); ls->m_VtkPolyDataMapper->ScalarVisibilityOn(); ls->m_VtkPolyDataMapper->SetScalarModeToUseCellData(); ls->m_Actor->GetProperty()->SetSpecular (1); ls->m_Actor->GetProperty()->SetSpecularPower (50); ls->m_Actor->GetProperty()->SetInterpolationToPhong(); } else if (deprecatedUsePointData) { float scalarsMin = 0; if (dynamic_cast(this->GetDataNode()->GetProperty("ScalarsRangeMinimum")) != NULL) scalarsMin = dynamic_cast(this->GetDataNode()->GetProperty("ScalarsRangeMinimum"))->GetValue(); float scalarsMax = 0.1; if (dynamic_cast(this->GetDataNode()->GetProperty("ScalarsRangeMaximum")) != NULL) scalarsMax = dynamic_cast(this->GetDataNode()->GetProperty("ScalarsRangeMaximum"))->GetValue(); ls->m_VtkPolyDataMapper->SetScalarRange(scalarsMin,scalarsMax); ls->m_VtkPolyDataMapper->SetColorModeToMapScalars(); ls->m_VtkPolyDataMapper->ScalarVisibilityOn(); ls->m_Actor->GetProperty()->SetSpecular (1); ls->m_Actor->GetProperty()->SetSpecularPower (50); ls->m_Actor->GetProperty()->SetInterpolationToPhong(); } int deprecatedScalarMode = VTK_COLOR_MODE_DEFAULT; if(this->GetDataNode()->GetIntProperty("deprecated scalar mode", deprecatedScalarMode, renderer)) { ls->m_VtkPolyDataMapper->SetScalarMode(deprecatedScalarMode); ls->m_VtkPolyDataMapper->ScalarVisibilityOn(); ls->m_Actor->GetProperty()->SetSpecular (1); ls->m_Actor->GetProperty()->SetSpecularPower (50); //m_Actor->GetProperty()->SetInterpolationToPhong(); } // Check whether one or more ClippingProperty objects have been defined for // this node. Check both renderer specific and global property lists, since // properties in both should be considered. const PropertyList::PropertyMap *rendererProperties = this->GetDataNode()->GetPropertyList( renderer )->GetMap(); const PropertyList::PropertyMap *globalProperties = this->GetDataNode()->GetPropertyList( NULL )->GetMap(); // Add clipping planes (if any) ls->m_ClippingPlaneCollection->RemoveAllItems(); PropertyList::PropertyMap::const_iterator it; for ( it = rendererProperties->begin(); it != rendererProperties->end(); ++it ) { this->CheckForClippingProperty( renderer,(*it).second.GetPointer() ); } for ( it = globalProperties->begin(); it != globalProperties->end(); ++it ) { this->CheckForClippingProperty( renderer,(*it).second.GetPointer() ); } if ( ls->m_ClippingPlaneCollection->GetNumberOfItems() > 0 ) { ls->m_VtkPolyDataMapper->SetClippingPlanes( ls->m_ClippingPlaneCollection ); } else { ls->m_VtkPolyDataMapper->RemoveAllClippingPlanes(); } } vtkProp *mitk::SurfaceVtkMapper3D::GetVtkProp(mitk::BaseRenderer *renderer) { LocalStorage *ls = m_LSH.GetLocalStorage(renderer); return ls->m_Actor; } void mitk::SurfaceVtkMapper3D::CheckForClippingProperty( mitk::BaseRenderer* renderer, mitk::BaseProperty *property ) { LocalStorage *ls = m_LSH.GetLocalStorage(renderer); // m_Prop3D = ls->m_Actor; ClippingProperty *clippingProperty = dynamic_cast< ClippingProperty * >( property ); if ( (clippingProperty != NULL) && (clippingProperty->GetClippingEnabled()) ) { const Point3D &origin = clippingProperty->GetOrigin(); const Vector3D &normal = clippingProperty->GetNormal(); vtkPlane *clippingPlane = vtkPlane::New(); clippingPlane->SetOrigin( origin[0], origin[1], origin[2] ); clippingPlane->SetNormal( normal[0], normal[1], normal[2] ); ls->m_ClippingPlaneCollection->AddItem( clippingPlane ); clippingPlane->UnRegister( NULL ); } } void mitk::SurfaceVtkMapper3D::SetDefaultPropertiesForVtkProperty(mitk::DataNode* node, mitk::BaseRenderer* renderer, bool overwrite) { // Shading { node->AddProperty( "material.wireframeLineWidth", mitk::FloatProperty::New(1.0f) , renderer, overwrite ); node->AddProperty( "material.ambientCoefficient" , mitk::FloatProperty::New(0.05f) , renderer, overwrite ); node->AddProperty( "material.diffuseCoefficient" , mitk::FloatProperty::New(0.9f) , renderer, overwrite ); node->AddProperty( "material.specularCoefficient", mitk::FloatProperty::New(1.0f) , renderer, overwrite ); node->AddProperty( "material.specularPower" , mitk::FloatProperty::New(16.0f) , renderer, overwrite ); //node->AddProperty( "material.ambientColor" , mitk::ColorProperty::New(1.0f,1.0f,1.0f), renderer, overwrite ); //node->AddProperty( "material.diffuseColor" , mitk::ColorProperty::New(1.0f,1.0f,1.0f), renderer, overwrite ); //node->AddProperty( "material.specularColor" , mitk::ColorProperty::New(1.0f,1.0f,1.0f), renderer, overwrite ); node->AddProperty( "material.representation" , mitk::VtkRepresentationProperty::New() , renderer, overwrite ); node->AddProperty( "material.interpolation" , mitk::VtkInterpolationProperty::New() , renderer, overwrite ); } // Shaders { mitk::ShaderRepository::GetGlobalShaderRepository()->AddDefaultProperties(node,renderer,overwrite); } } void mitk::SurfaceVtkMapper3D::SetDefaultProperties(mitk::DataNode* node, mitk::BaseRenderer* renderer, bool overwrite) { node->AddProperty( "color", mitk::ColorProperty::New(1.0f,1.0f,1.0f), renderer, overwrite ); node->AddProperty( "opacity", mitk::FloatProperty::New(1.0), renderer, overwrite ); mitk::SurfaceVtkMapper3D::SetDefaultPropertiesForVtkProperty(node,renderer,overwrite); // Shading node->AddProperty( "scalar visibility", mitk::BoolProperty::New(false), renderer, overwrite ); node->AddProperty( "color mode", mitk::BoolProperty::New(false), renderer, overwrite ); node->AddProperty( "scalar mode", mitk::VtkScalarModeProperty::New(), renderer, overwrite ); mitk::Surface::Pointer surface = dynamic_cast(node->GetData()); if(surface.IsNotNull()) { if((surface->GetVtkPolyData() != 0) && (surface->GetVtkPolyData()->GetPointData() != NULL) && (surface->GetVtkPolyData()->GetPointData()->GetScalars() != 0)) { node->AddProperty( "scalar visibility", mitk::BoolProperty::New(true), renderer, overwrite ); node->AddProperty( "color mode", mitk::BoolProperty::New(true), renderer, overwrite ); } } Superclass::SetDefaultProperties(node, renderer, overwrite); } void mitk::SurfaceVtkMapper3D::SetImmediateModeRenderingOn(int /*on*/) { /* if (m_VtkPolyDataMapper != NULL) m_VtkPolyDataMapper->SetImmediateModeRendering(on); */ } diff --git a/Core/Code/Rendering/mitkSurfaceVtkMapper3D.h b/Core/Code/Rendering/mitkSurfaceVtkMapper3D.h index 70c7f57fea..6cc22e20f7 100644 --- a/Core/Code/Rendering/mitkSurfaceVtkMapper3D.h +++ b/Core/Code/Rendering/mitkSurfaceVtkMapper3D.h @@ -1,162 +1,162 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef MITKSURFACEDATAVTKMAPPER3D_H_HEADER_INCLUDED_C1907273 #define MITKSURFACEDATAVTKMAPPER3D_H_HEADER_INCLUDED_C1907273 #include "mitkCommon.h" #include "mitkVtkMapper3D.h" #include "mitkSurface.h" #include "mitkBaseRenderer.h" #include #include #include #include #include #include namespace mitk { //##Documentation //## @brief Vtk-based mapper for Surface //## //## @ingroup Mapper /** * @brief Vtk-based mapper for Surface * * Properties that can be set for surfaces and influence the surfaceVTKMapper3D are: * * - \b "color": (ColorProperty) Diffuse color of the surface object (this property will be read when material.diffuseColor is not defined) * - \b "Opacity": (FloatProperty) Opacity of the surface object * - \b "material.ambientColor": (ColorProperty) Ambient color of the surface object * - \b "material.ambientCoefficient": ( FloatProperty) Ambient coefficient of the surface object * - \b "material.diffuseColor": ( ColorProperty) Diffuse color of the surface object * - \b "material.diffuseCoefficient": (FloatProperty) Diffuse coefficient of the surface object * - \b "material.specularColor": (ColorProperty) Specular Color of the surface object * - \b "material.specularCoefficient": (FloatProperty) Specular coefficient of the surface object * - \b "material.specularPower": (FloatProperty) Specular power of the surface object * - \b "material.interpolation": (VtkInterpolationProperty) Interpolation * - \b "material.representation": (VtkRepresentationProperty*) Representation * - \b "material.wireframeLineWidth": (FloatProperty) Width in pixels of the lines drawn. * - \b "scalar visibility": (BoolProperty) If the scarlars of the surface are visible * Properties to look for are: * * - \b "scalar visibility": if set to on, scalars assigned to the data are shown * Turn this on if using a lookup table. * - \b "ScalarsRangeMinimum": Optional. Can be used to store the scalar min, e.g. * for the level window settings. * - \b "ScalarsRangeMaximum": Optional. See above. * * There might be still some other, deprecated properties. These will not be documented anymore. * Please check the source if you really need them. * * @ingroup Mapper */ class MITK_CORE_EXPORT SurfaceVtkMapper3D : public VtkMapper3D { public: mitkClassMacro(SurfaceVtkMapper3D, VtkMapper3D); itkNewMacro(Self); itkSetMacro(GenerateNormals, bool); itkGetMacro(GenerateNormals, bool); //enable ImmediateModeRendering for vtkMapping //yet to solve bug 1398 void SetImmediateModeRenderingOn(int on = 1); itkGetMacro(ImmediateModeRenderingOn, int); virtual const mitk::Surface* GetInput(); virtual vtkProp *GetVtkProp(mitk::BaseRenderer *renderer); virtual void ApplyProperties(vtkActor* actor, mitk::BaseRenderer* renderer); static void SetDefaultProperties(mitk::DataNode* node, mitk::BaseRenderer* renderer = NULL, bool overwrite = false); protected: SurfaceVtkMapper3D(); virtual ~SurfaceVtkMapper3D(); - virtual void GenerateData(mitk::BaseRenderer* renderer); + virtual void GenerateDataForRenderer(mitk::BaseRenderer* renderer); virtual void ResetMapper( mitk::BaseRenderer* renderer ); /** Checks whether the specified property is a ClippingProperty and if yes, * adds it to m_ClippingPlaneCollection (internal method). */ virtual void CheckForClippingProperty( mitk::BaseRenderer* renderer, mitk::BaseProperty *property ); bool m_GenerateNormals; //enable ImmediateModeRendering for the vtkMapper int m_ImmediateModeRenderingOn; public: class LocalStorage : public mitk::Mapper::BaseLocalStorage { public: vtkActor* m_Actor; vtkPolyDataMapper *m_VtkPolyDataMapper; vtkPolyDataNormals *m_VtkPolyDataNormals; vtkPlaneCollection *m_ClippingPlaneCollection; itk::TimeStamp m_ShaderTimestampUpdate; LocalStorage() { m_VtkPolyDataMapper = vtkOpenGLPolyDataMapper::New(); m_VtkPolyDataNormals = vtkPolyDataNormals::New(); m_Actor = vtkActor::New(); m_ClippingPlaneCollection = vtkPlaneCollection::New(); m_Actor->SetMapper(m_VtkPolyDataMapper); } ~LocalStorage() { m_VtkPolyDataMapper->Delete(); m_VtkPolyDataNormals->Delete(); m_Actor->Delete(); m_ClippingPlaneCollection->Delete(); } }; mitk::Mapper::LocalStorageHandler m_LSH; static void ApplyMitkPropertiesToVtkProperty(mitk::DataNode *node, vtkProperty* property, mitk::BaseRenderer* renderer); static void SetDefaultPropertiesForVtkProperty(mitk::DataNode* node, mitk::BaseRenderer* renderer, bool overwrite); }; } // namespace mitk #endif /* MITKSURFACEDATAVTKMAPPER3D_H_HEADER_INCLUDED_C1907273 */ diff --git a/Core/Code/Rendering/mitkVolumeDataVtkMapper3D.cpp b/Core/Code/Rendering/mitkVolumeDataVtkMapper3D.cpp index 2e6ddb937f..b1fce0c004 100644 --- a/Core/Code/Rendering/mitkVolumeDataVtkMapper3D.cpp +++ b/Core/Code/Rendering/mitkVolumeDataVtkMapper3D.cpp @@ -1,706 +1,706 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "mitkVolumeDataVtkMapper3D.h" #include "mitkDataNode.h" #include "mitkProperties.h" #include "mitkLevelWindow.h" #include "mitkColorProperty.h" #include "mitkLevelWindowProperty.h" #include "mitkLookupTableProperty.h" #include "mitkTransferFunctionProperty.h" #include "mitkTransferFunctionInitializer.h" #include "mitkColorProperty.h" #include "mitkVtkPropRenderer.h" #include "mitkRenderingManager.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mitkVtkVolumeRenderingProperty.h" #include const mitk::Image* mitk::VolumeDataVtkMapper3D::GetInput() { return static_cast ( GetData() ); } mitk::VolumeDataVtkMapper3D::VolumeDataVtkMapper3D() : m_Mask( NULL ) { m_PlaneSet = false; m_ClippingPlane = vtkPlane::New(); m_PlaneWidget = vtkImplicitPlaneWidget::New(); /* m_T2DMapper = vtkVolumeTextureMapper2D::New(); m_T2DMapper->SetMaximumNumberOfPlanes( 100 ); */ m_HiResMapper = vtkVolumeRayCastMapper::New(); m_HiResMapper->SetSampleDistance(1.0); // 4 rays for every pixel m_HiResMapper->IntermixIntersectingGeometryOn(); m_HiResMapper->SetNumberOfThreads( itk::MultiThreader::GetGlobalDefaultNumberOfThreads() ); /* vtkVolumeRayCastCompositeFunction* compositeFunction = vtkVolumeRayCastCompositeFunction::New(); compositeFunction->SetCompositeMethodToClassifyFirst(); m_HiResMapper->SetVolumeRayCastFunction(compositeFunction); compositeFunction->Delete(); vtkVolumeRayCastMIPFunction* mipFunction = vtkVolumeRayCastMIPFunction::New(); m_HiResMapper->SetVolumeRayCastFunction(mipFunction); mipFunction->Delete(); */ vtkFiniteDifferenceGradientEstimator* gradientEstimator = vtkFiniteDifferenceGradientEstimator::New(); m_HiResMapper->SetGradientEstimator(gradientEstimator); gradientEstimator->Delete(); m_VolumePropertyLow = vtkVolumeProperty::New(); m_VolumePropertyMed = vtkVolumeProperty::New(); m_VolumePropertyHigh = vtkVolumeProperty::New(); m_VolumeLOD = vtkLODProp3D::New(); m_VolumeLOD->VisibilityOff(); m_HiResID = m_VolumeLOD->AddLOD(m_HiResMapper,m_VolumePropertyHigh,0.0); // RayCast // m_LowResID = m_VolumeLOD->AddLOD(m_T2DMapper,m_VolumePropertyLow,0.0); // TextureMapper2D m_MedResID = m_VolumeLOD->AddLOD(m_HiResMapper,m_VolumePropertyMed,0.0); // RayCast m_Resampler = vtkImageResample::New(); m_Resampler->SetAxisMagnificationFactor(0,0.25); m_Resampler->SetAxisMagnificationFactor(1,0.25); m_Resampler->SetAxisMagnificationFactor(2,0.25); // For abort rendering mechanism m_VolumeLOD->AutomaticLODSelectionOff(); m_BoundingBox = vtkCubeSource::New(); m_BoundingBox->SetXLength( 0.0 ); m_BoundingBox->SetYLength( 0.0 ); m_BoundingBox->SetZLength( 0.0 ); m_BoundingBoxMapper = vtkPolyDataMapper::New(); m_BoundingBoxMapper->SetInput( m_BoundingBox->GetOutput() ); m_BoundingBoxActor = vtkActor::New(); m_BoundingBoxActor->SetMapper( m_BoundingBoxMapper ); m_BoundingBoxActor->GetProperty()->SetColor( 1.0, 1.0, 1.0 ); m_BoundingBoxActor->GetProperty()->SetRepresentationToWireframe(); // BoundingBox rendering is not working due to problem with assembly // transformation; see bug #454 // If commenting in the following, do not forget to comment in the // m_Prop3DAssembly->Delete() line in the destructor. //m_Prop3DAssembly = vtkAssembly::New(); //m_Prop3DAssembly->AddPart( m_VolumeLOD ); //m_Prop3DAssembly->AddPart( m_BoundingBoxActor ); //m_Prop3D = m_Prop3DAssembly; m_ImageCast = vtkImageShiftScale::New(); m_ImageCast->SetOutputScalarTypeToUnsignedShort(); m_ImageCast->ClampOverflowOn(); m_UnitSpacingImageFilter = vtkImageChangeInformation::New(); m_UnitSpacingImageFilter->SetInput(m_ImageCast->GetOutput()); m_UnitSpacingImageFilter->SetOutputSpacing( 1.0, 1.0, 1.0 ); m_ImageMaskFilter = vtkImageMask::New(); m_ImageMaskFilter->SetMaskedOutputValue(0xffff); this->m_Resampler->SetInput( this->m_UnitSpacingImageFilter->GetOutput() ); this->m_HiResMapper->SetInput( this->m_UnitSpacingImageFilter->GetOutput() ); // m_T2DMapper->SetInput(m_Resampler->GetOutput()); this->CreateDefaultTransferFunctions(); } vtkProp *mitk::VolumeDataVtkMapper3D::GetVtkProp(mitk::BaseRenderer * /*renderer*/) { return m_VolumeLOD; } mitk::VolumeDataVtkMapper3D::~VolumeDataVtkMapper3D() { m_UnitSpacingImageFilter->Delete(); m_ImageCast->Delete(); // m_T2DMapper->Delete(); m_HiResMapper->Delete(); m_Resampler->Delete(); m_VolumePropertyLow->Delete(); m_VolumePropertyMed->Delete(); m_VolumePropertyHigh->Delete(); m_VolumeLOD->Delete(); m_ClippingPlane->Delete(); m_PlaneWidget->Delete(); // m_Prop3DAssembly->Delete(); m_BoundingBox->Delete(); m_BoundingBoxMapper->Delete(); m_BoundingBoxActor->Delete(); m_ImageMaskFilter->Delete(); m_DefaultColorTransferFunction->Delete(); m_DefaultOpacityTransferFunction->Delete(); m_DefaultGradientTransferFunction->Delete(); if (m_Mask) { m_Mask->Delete(); } } -void mitk::VolumeDataVtkMapper3D::GenerateData( mitk::BaseRenderer *renderer ) +void mitk::VolumeDataVtkMapper3D::GenerateDataForRenderer( mitk::BaseRenderer *renderer ) { SetVtkMapperImmediateModeRendering(m_BoundingBoxMapper); mitk::Image *input = const_cast< mitk::Image * >( this->GetInput() ); if ( !input || !input->IsInitialized() ) return; vtkRenderWindow* renderWindow = renderer->GetRenderWindow(); bool volumeRenderingEnabled = true; if (this->IsVisible(renderer)==false || this->GetDataNode() == NULL || dynamic_cast(GetDataNode()->GetProperty("volumerendering",renderer))==NULL || dynamic_cast(GetDataNode()->GetProperty("volumerendering",renderer))->GetValue() == false ) { volumeRenderingEnabled = false; // Check if a bounding box should be displayed around the dataset // (even if volume rendering is disabled) bool hasBoundingBox = false; this->GetDataNode()->GetBoolProperty( "bounding box", hasBoundingBox ); if ( !hasBoundingBox ) { m_BoundingBoxActor->VisibilityOff(); } else { m_BoundingBoxActor->VisibilityOn(); const BoundingBox::BoundsArrayType &bounds = input->GetTimeSlicedGeometry()->GetBounds(); m_BoundingBox->SetBounds( bounds[0], bounds[1], bounds[2], bounds[3], bounds[4], bounds[5] ); ColorProperty *colorProperty; if ( this->GetDataNode()->GetProperty( colorProperty, "color" ) ) { const mitk::Color &color = colorProperty->GetColor(); m_BoundingBoxActor->GetProperty()->SetColor( color[0], color[1], color[2] ); } else { m_BoundingBoxActor->GetProperty()->SetColor( 1.0, 1.0, 1.0 ); } } } // Don't do anything if VR is disabled if ( !volumeRenderingEnabled ) { m_VolumeLOD->VisibilityOff(); return; } else { mitk::VtkVolumeRenderingProperty* vrp=dynamic_cast(GetDataNode()->GetProperty("volumerendering configuration",renderer)); if(vrp) { int renderingValue = vrp->GetValueAsId(); switch(renderingValue) { case VTK_VOLUME_RAY_CAST_MIP_FUNCTION: { vtkVolumeRayCastMIPFunction* mipFunction = vtkVolumeRayCastMIPFunction::New(); m_HiResMapper->SetVolumeRayCastFunction(mipFunction); mipFunction->Delete(); MITK_INFO <<"in switch" <SetCompositeMethodToClassifyFirst(); m_HiResMapper->SetVolumeRayCastFunction(compositeFunction); compositeFunction->Delete(); break; } default: MITK_ERROR <<"Warning: invalid volume rendering option. " << std::endl; } } m_VolumeLOD->VisibilityOn(); } this->SetPreferences(); /* switch ( mitk::RenderingManager::GetInstance()->GetNextLOD( renderer ) ) { case 0: m_VolumeLOD->SetSelectedLODID(m_MedResID); m_LowResID ); break; default: case 1: m_VolumeLOD->SetSelectedLODID( m_HiResID ); break; } */ m_VolumeLOD->SetSelectedLODID( m_HiResID ); assert(input->GetTimeSlicedGeometry()); const Geometry3D* worldgeometry = renderer->GetCurrentWorldGeometry(); if(worldgeometry==NULL) { GetDataNode()->SetProperty("volumerendering",mitk::BoolProperty::New(false)); return; } vtkImageData *inputData = input->GetVtkImageData( this->GetTimestep() ); if(inputData==NULL) return; m_ImageCast->SetInput( inputData ); //If mask exists, process mask before resampling. if (this->m_Mask) { this->m_ImageMaskFilter->SetImageInput(this->m_UnitSpacingImageFilter->GetOutput()); this->m_Resampler->SetInput(this->m_ImageMaskFilter->GetOutput()); this->m_HiResMapper->SetInput(this->m_ImageMaskFilter->GetOutput()); } else { this->m_Resampler->SetInput(this->m_UnitSpacingImageFilter->GetOutput()); this->m_HiResMapper->SetInput(this->m_UnitSpacingImageFilter->GetOutput()); } this->UpdateTransferFunctions( renderer ); vtkRenderWindowInteractor *interactor = renderWindow->GetInteractor(); float frameRate; if( this->GetDataNode()->GetFloatProperty( "framerate", frameRate ) && frameRate > 0 && frameRate <= 60) { interactor->SetDesiredUpdateRate( frameRate ); interactor->SetStillUpdateRate( frameRate ); } else if( frameRate > 60 ) { this->GetDataNode()->SetProperty( "framerate",mitk::FloatProperty::New(60)); interactor->SetDesiredUpdateRate( 60 ); interactor->SetStillUpdateRate( 60 ); } else { this->GetDataNode()->SetProperty( "framerate",mitk::FloatProperty::New(0.00001)); interactor->SetDesiredUpdateRate( 0.00001 ); interactor->SetStillUpdateRate( 0.00001 ); } if ( m_RenderWindowInitialized.find( renderWindow ) == m_RenderWindowInitialized.end() ) { m_RenderWindowInitialized.insert( renderWindow ); // mitk::RenderingManager::GetInstance()->SetNextLOD( 0, renderer ); mitk::RenderingManager::GetInstance()->SetShading( true, 0 ); mitk::RenderingManager::GetInstance()->SetShading( true, 1 ); //mitk::RenderingManager::GetInstance()->SetShading( true, 2 ); mitk::RenderingManager::GetInstance()->SetShadingValues( m_VolumePropertyHigh->GetAmbient(), m_VolumePropertyHigh->GetDiffuse(), m_VolumePropertyHigh->GetSpecular(), m_VolumePropertyHigh->GetSpecularPower()); mitk::RenderingManager::GetInstance()->SetClippingPlaneStatus(false); } this->SetClippingPlane( interactor ); } void mitk::VolumeDataVtkMapper3D::CreateDefaultTransferFunctions() { m_DefaultOpacityTransferFunction = vtkPiecewiseFunction::New(); m_DefaultOpacityTransferFunction->AddPoint( 0.0, 0.0 ); m_DefaultOpacityTransferFunction->AddPoint( 255.0, 0.8 ); m_DefaultOpacityTransferFunction->ClampingOn(); m_DefaultGradientTransferFunction = vtkPiecewiseFunction::New(); m_DefaultGradientTransferFunction->AddPoint( 0.0, 0.0 ); m_DefaultGradientTransferFunction->AddPoint( 255.0, 0.8 ); m_DefaultGradientTransferFunction->ClampingOn(); m_DefaultColorTransferFunction = vtkColorTransferFunction::New(); m_DefaultColorTransferFunction->AddRGBPoint( 0.0, 0.0, 0.0, 0.0 ); m_DefaultColorTransferFunction->AddRGBPoint( 127.5, 1, 1, 0.0 ); m_DefaultColorTransferFunction->AddRGBPoint( 255.0, 0.8, 0.2, 0 ); m_DefaultColorTransferFunction->ClampingOn(); } void mitk::VolumeDataVtkMapper3D::UpdateTransferFunctions( mitk::BaseRenderer *renderer ) { vtkPiecewiseFunction *opacityTransferFunction = NULL; vtkPiecewiseFunction *gradientTransferFunction = NULL; vtkColorTransferFunction *colorTransferFunction = NULL; mitk::LookupTableProperty::Pointer lookupTableProp; lookupTableProp = dynamic_cast(this->GetDataNode()->GetProperty("LookupTable")); mitk::TransferFunctionProperty::Pointer transferFunctionProp = dynamic_cast(this->GetDataNode()->GetProperty("TransferFunction")); if ( transferFunctionProp.IsNotNull() ) { opacityTransferFunction = transferFunctionProp->GetValue()->GetScalarOpacityFunction(); gradientTransferFunction = transferFunctionProp->GetValue()->GetGradientOpacityFunction(); colorTransferFunction = transferFunctionProp->GetValue()->GetColorTransferFunction(); } else if (lookupTableProp.IsNotNull() ) { lookupTableProp->GetLookupTable()->CreateOpacityTransferFunction(opacityTransferFunction); opacityTransferFunction->ClampingOn(); lookupTableProp->GetLookupTable()->CreateGradientTransferFunction(gradientTransferFunction); gradientTransferFunction->ClampingOn(); lookupTableProp->GetLookupTable()->CreateColorTransferFunction(colorTransferFunction); colorTransferFunction->ClampingOn(); } else { opacityTransferFunction = m_DefaultOpacityTransferFunction; gradientTransferFunction = m_DefaultGradientTransferFunction; colorTransferFunction = m_DefaultColorTransferFunction; float rgb[3]={1.0f,1.0f,1.0f}; // check for color prop and use it for rendering if it exists if(GetColor(rgb, renderer)) { colorTransferFunction->AddRGBPoint( 0.0, 0.0, 0.0, 0.0 ); colorTransferFunction->AddRGBPoint( 127.5, rgb[0], rgb[1], rgb[2] ); colorTransferFunction->AddRGBPoint( 255.0, rgb[0], rgb[1], rgb[2] ); } } if (this->m_Mask) { opacityTransferFunction->AddPoint(0xffff, 0.0); } m_VolumePropertyLow->SetColor( colorTransferFunction ); m_VolumePropertyLow->SetScalarOpacity( opacityTransferFunction ); m_VolumePropertyLow->SetGradientOpacity( gradientTransferFunction ); m_VolumePropertyLow->SetInterpolationTypeToNearest(); m_VolumePropertyMed->SetColor( colorTransferFunction ); m_VolumePropertyMed->SetScalarOpacity( opacityTransferFunction ); m_VolumePropertyMed->SetGradientOpacity( gradientTransferFunction ); m_VolumePropertyMed->SetInterpolationTypeToNearest(); m_VolumePropertyHigh->SetColor( colorTransferFunction ); m_VolumePropertyHigh->SetScalarOpacity( opacityTransferFunction ); m_VolumePropertyHigh->SetGradientOpacity( gradientTransferFunction ); m_VolumePropertyHigh->SetInterpolationTypeToLinear(); } /* Shading enabled / disabled */ void mitk::VolumeDataVtkMapper3D::SetPreferences() { //LOD 0 /*if(mitk::RenderingManager::GetInstance()->GetShading(0)) { m_VolumePropertyLow->ShadeOn(); m_VolumePropertyLow->SetAmbient(mitk::RenderingManager::GetInstance()->GetShadingValues()[0]); m_VolumePropertyLow->SetDiffuse(mitk::RenderingManager::GetInstance()->GetShadingValues()[1]); m_VolumePropertyLow->SetSpecular(mitk::RenderingManager::GetInstance()->GetShadingValues()[2]); m_VolumePropertyLow->SetSpecularPower(mitk::RenderingManager::GetInstance()->GetShadingValues()[3]); } else*/ { m_VolumePropertyLow->ShadeOff(); } //LOD 1 /*if(mitk::RenderingManager::GetInstance()->GetShading(1)) { m_VolumePropertyMed->ShadeOn(); m_VolumePropertyMed->SetAmbient(mitk::RenderingManager::GetInstance()->GetShadingValues()[0]); m_VolumePropertyMed->SetDiffuse(mitk::RenderingManager::GetInstance()->GetShadingValues()[1]); m_VolumePropertyMed->SetSpecular(mitk::RenderingManager::GetInstance()->GetShadingValues()[2]); m_VolumePropertyMed->SetSpecularPower(mitk::RenderingManager::GetInstance()->GetShadingValues()[3]); } else*/ { m_VolumePropertyMed->ShadeOff(); } //LOD 2 /* if(mitk::RenderingManager::GetInstance()->GetShading(2)) { m_VolumePropertyHigh->ShadeOn(); //Shading Properties m_VolumePropertyHigh->SetAmbient(mitk::RenderingManager::GetInstance()->GetShadingValues()[0]); m_VolumePropertyHigh->SetDiffuse(mitk::RenderingManager::GetInstance()->GetShadingValues()[1]); m_VolumePropertyHigh->SetSpecular(mitk::RenderingManager::GetInstance()->GetShadingValues()[2]); m_VolumePropertyHigh->SetSpecularPower(mitk::RenderingManager::GetInstance()->GetShadingValues()[3]); } else { m_VolumePropertyHigh->ShadeOff(); } */ } /* Adds A Clipping Plane to the Mapper */ void mitk::VolumeDataVtkMapper3D::SetClippingPlane(vtkRenderWindowInteractor* interactor) { if(mitk::RenderingManager::GetInstance()->GetClippingPlaneStatus()) //if clipping plane is enabled { if(!m_PlaneSet) { m_PlaneWidget->SetInteractor(interactor); m_PlaneWidget->SetPlaceFactor(1.0); m_PlaneWidget->SetInput(m_UnitSpacingImageFilter->GetOutput()); m_PlaneWidget->OutlineTranslationOff(); //disables scaling of the bounding box #if (VTK_MAJOR_VERSION >= 5) m_PlaneWidget->ScaleEnabledOff(); //disables scaling of the bounding box #endif m_PlaneWidget->DrawPlaneOff(); //clipping plane is transparent mitk::Image* input = const_cast(this->GetInput()); /*places the widget within the specified bounds*/ m_PlaneWidget->PlaceWidget( input->GetGeometry()->GetOrigin()[0],(input->GetGeometry()->GetOrigin()[0])+(input->GetDimension(0))*(input->GetVtkImageData()->GetSpacing()[0]), input->GetGeometry()->GetOrigin()[1],(input->GetGeometry()->GetOrigin()[1])+(input->GetDimension(1))*(input->GetVtkImageData()->GetSpacing()[1]), input->GetGeometry()->GetOrigin()[2],(input->GetGeometry()->GetOrigin()[2])+(input->GetDimension(2))*(input->GetVtkImageData()->GetSpacing()[2])); // m_T2DMapper->AddClippingPlane(m_ClippingPlane); m_HiResMapper->AddClippingPlane(m_ClippingPlane); } m_PlaneWidget->GetPlane(m_ClippingPlane); m_PlaneSet = true; } else //if clippingplane is disabled { if(m_PlaneSet) //if plane exists { DelClippingPlane(); } } } /* Removes the clipping plane */ void mitk::VolumeDataVtkMapper3D::DelClippingPlane() { // m_T2DMapper->RemoveAllClippingPlanes(); m_HiResMapper->RemoveAllClippingPlanes(); m_PlaneSet = false; } void mitk::VolumeDataVtkMapper3D::ApplyProperties(vtkActor* /*actor*/, mitk::BaseRenderer* /*renderer*/) { } void mitk::VolumeDataVtkMapper3D::SetDefaultProperties(mitk::DataNode* node, mitk::BaseRenderer* renderer, bool overwrite) { node->AddProperty( "volumerendering", mitk::BoolProperty::New( false ), renderer, overwrite ); node->AddProperty( "volumerendering configuration", mitk::VtkVolumeRenderingProperty::New( 1 ), renderer, overwrite ); node->AddProperty( "binary", mitk::BoolProperty::New( false ), renderer, overwrite ); mitk::Image::Pointer image = dynamic_cast(node->GetData()); if(image.IsNotNull() && image->IsInitialized()) { if((overwrite) || (node->GetProperty("levelwindow", renderer)==NULL)) { mitk::LevelWindowProperty::Pointer levWinProp = mitk::LevelWindowProperty::New(); mitk::LevelWindow levelwindow; levelwindow.SetAuto( image ); levWinProp->SetLevelWindow( levelwindow ); node->SetProperty( "levelwindow", levWinProp, renderer ); } if((overwrite) || (node->GetProperty("LookupTable", renderer)==NULL)) { // add a default rainbow lookup table for color mapping mitk::LookupTable::Pointer mitkLut = mitk::LookupTable::New(); vtkLookupTable* vtkLut = mitkLut->GetVtkLookupTable(); vtkLut->SetHueRange(0.6667, 0.0); vtkLut->SetTableRange(0.0, 20.0); vtkLut->Build(); mitk::LookupTableProperty::Pointer mitkLutProp = mitk::LookupTableProperty::New(); mitkLutProp->SetLookupTable(mitkLut); node->SetProperty( "LookupTable", mitkLutProp ); } if((overwrite) || (node->GetProperty("TransferFunction", renderer)==NULL)) { // add a default transfer function mitk::TransferFunction::Pointer tf = mitk::TransferFunction::New(); mitk::TransferFunctionInitializer::Pointer tfInit = mitk::TransferFunctionInitializer::New(tf); tfInit->SetTransferFunctionMode(0); node->SetProperty ( "TransferFunction", mitk::TransferFunctionProperty::New ( tf.GetPointer() ) ); } } Superclass::SetDefaultProperties(node, renderer, overwrite); } bool mitk::VolumeDataVtkMapper3D::IsLODEnabled( mitk::BaseRenderer * /*renderer*/ ) const { return false; // Volume mapper is LOD enabled if volumerendering is enabled /* return dynamic_cast(GetDataNode()->GetProperty("volumerendering",renderer)) != NULL && dynamic_cast(GetDataNode()->GetProperty("volumerendering",renderer))->GetValue() == true; */ } void mitk::VolumeDataVtkMapper3D::EnableMask() { if (!this->m_Mask) { const Image *orig_image = this->GetInput(); unsigned int *dimensions = orig_image->GetDimensions(); this->m_Mask = vtkImageData::New(); this->m_Mask->SetDimensions(dimensions[0], dimensions[1], dimensions[2]); this->m_Mask->SetScalarTypeToUnsignedChar(); this->m_Mask->SetNumberOfScalarComponents(1); this->m_Mask->AllocateScalars(); unsigned char *mask_data = static_cast(this->m_Mask->GetScalarPointer()); unsigned int size = dimensions[0] * dimensions[1] * dimensions[2]; for (unsigned int i = 0u; i < size; ++i) { *mask_data++ = 1u; } this->m_ImageMaskFilter->SetMaskInput(this->m_Mask); this->m_ImageMaskFilter->Modified(); } } void mitk::VolumeDataVtkMapper3D::DisableMask() { if (this->m_Mask) { this->m_Mask->Delete(); this->m_Mask = 0; } } mitk::Image::Pointer mitk::VolumeDataVtkMapper3D::GetMask() { if (this->m_Mask) { Image::Pointer mask = Image::New(); mask->Initialize(this->m_Mask); mask->SetImportVolume(this->m_Mask->GetScalarPointer(), 0, 0, Image::ReferenceMemory); mask->SetGeometry(this->GetInput()->GetGeometry()); return mask; } return 0; } void mitk::VolumeDataVtkMapper3D::UpdateMask() { if (this->m_Mask) { this->m_ImageMaskFilter->Modified(); } } bool mitk::VolumeDataVtkMapper3D::SetMask(const mitk::Image* mask) { if (this->m_Mask) { if (mask->GetPixelType() == PixelType(typeid(unsigned char))) { Image *img = const_cast(mask); this->m_Mask->DeepCopy(img->GetVtkImageData()); this->m_ImageMaskFilter->Modified(); return true; } } return false; } diff --git a/Core/Code/Rendering/mitkVolumeDataVtkMapper3D.h b/Core/Code/Rendering/mitkVolumeDataVtkMapper3D.h index 0e66a89524..bd3351d229 100644 --- a/Core/Code/Rendering/mitkVolumeDataVtkMapper3D.h +++ b/Core/Code/Rendering/mitkVolumeDataVtkMapper3D.h @@ -1,151 +1,151 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef MITKVOLUMEDATAVTKMAPPER3D_H_HEADER_INCLUDED #define MITKVOLUMEDATAVTKMAPPER3D_H_HEADER_INCLUDED #include "mitkCommon.h" #include "mitkVtkMapper3D.h" #include "mitkBaseRenderer.h" #include "mitkImage.h" #include #include #include #include #include #include #include class vtkAssembly; class vtkVolumeRayCastMapper; class vtkFixedPointVolumeRayCastMapper; class vtkVolumeTextureMapper2D; class vtkVolumeMapper; class vtkVolume; class vtkObject; class vtkImageShiftScale; class vtkImageChangeInformation; class vtkLODProp3D; class vtkImageResample; class vtkCubeSource; class vtkPolyDataMapper; class vtkActor; namespace mitk { /************************************************************************/ /* Properties that influence the mapper are: * * - \b "level window": for the level window of the volume data * - \b "LookupTable" : for the lookup table of the volume data * - \b "TransferFunction" (mitk::TransferFunctionProperty): for the used transfer function of the volume data ************************************************************************/ //##Documentation //## @brief Vtk-based mapper for VolumeData //## //## @ingroup Mapper class MITK_CORE_EXPORT VolumeDataVtkMapper3D : public VtkMapper3D { public: mitkClassMacro(VolumeDataVtkMapper3D, VtkMapper3D); itkNewMacro(Self); virtual const mitk::Image* GetInput(); virtual void ApplyProperties(vtkActor* actor, mitk::BaseRenderer* renderer); virtual void EnableMask(); virtual void DisableMask(); Image::Pointer GetMask(); bool SetMask(const Image* mask); virtual void UpdateMask(); static void SetDefaultProperties(mitk::DataNode* node, mitk::BaseRenderer* renderer = NULL, bool overwrite = false); /** Returns true if this Mapper currently allows for Level-of-Detail rendering. * This reflects whether this Mapper currently invokes StartEvent, EndEvent, and * ProgressEvent on BaseRenderer. */ virtual bool IsLODEnabled( BaseRenderer *renderer = NULL ) const; virtual vtkProp *GetVtkProp(mitk::BaseRenderer *renderer); protected: VolumeDataVtkMapper3D(); virtual ~VolumeDataVtkMapper3D(); - virtual void GenerateData(mitk::BaseRenderer* renderer); + virtual void GenerateDataForRenderer(mitk::BaseRenderer* renderer); void CreateDefaultTransferFunctions(); void UpdateTransferFunctions( mitk::BaseRenderer *renderer ); void SetPreferences(); void SetClippingPlane(vtkRenderWindowInteractor* interactor); void DelClippingPlane(); vtkImageShiftScale* m_ImageCast; vtkImageChangeInformation* m_UnitSpacingImageFilter; vtkVolumeProperty* m_VolumePropertyLow; vtkVolumeProperty* m_VolumePropertyMed; vtkVolumeProperty* m_VolumePropertyHigh; vtkVolumeTextureMapper2D* m_T2DMapper; vtkVolumeRayCastMapper* m_HiResMapper; vtkImageResample* m_Resampler; vtkLODProp3D* m_VolumeLOD; vtkCubeSource *m_BoundingBox; vtkPolyDataMapper *m_BoundingBoxMapper; vtkActor *m_BoundingBoxActor; vtkAssembly *m_Prop3DAssembly; vtkPlane* m_ClippingPlane; vtkImplicitPlaneWidget* m_PlaneWidget; vtkImageData *m_Mask; vtkImageMask *m_ImageMaskFilter; vtkPiecewiseFunction *m_DefaultOpacityTransferFunction; vtkPiecewiseFunction *m_DefaultGradientTransferFunction; vtkColorTransferFunction *m_DefaultColorTransferFunction; int m_LowResID; int m_MedResID; int m_HiResID; bool m_PlaneSet; double m_PlaneNormalA; double m_PlaneNormalB; double m_PlaneNormalC; std::set< vtkRenderWindow * > m_RenderWindowInitialized; }; } // namespace mitk #endif /* MITKVOLUMEDATAVTKMAPPER3D_H_HEADER_INCLUDED */ diff --git a/Core/Code/Rendering/mitkVtkPropRenderer.h b/Core/Code/Rendering/mitkVtkPropRenderer.h index 295a6b99a3..eeb4bbea6c 100644 --- a/Core/Code/Rendering/mitkVtkPropRenderer.h +++ b/Core/Code/Rendering/mitkVtkPropRenderer.h @@ -1,193 +1,193 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date: 2007-09-22 12:01:41 +0200 (Sa, 22 Sep 2007) $ Version: $Revision: 12241 $ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef MITKVtkPropRenderer_H_HEADER_INCLUDED_C1C29F6D #define MITKVtkPropRenderer_H_HEADER_INCLUDED_C1C29F6D #include "mitkCommon.h" #include "mitkBaseRenderer.h" #include "mitkDataStorage.h" #include "mitkRenderingManager.h" #include #include #include class vtkRenderWindow; class vtkLight; class vtkLightKit; class vtkWorldPointPicker; class vtkPointPicker; class vtkCellPicker; class vtkTextActor; class vtkTextProperty; class vtkAssemblyPath; namespace mitk { class Mapper; /*! \brief VtkPropRenderer VtkPropRenderer organizes the MITK rendering process. The MITK rendering process is completely integrated into the VTK rendering pipeline. The vtkMitkRenderProp is a custom vtkProp derived class, which implements the rendering interface between MITK and VTK. It redirects render() calls to the VtkPropRenderer, which is responsible for rendering of the datatreenodes. VtkPropRenderer replaces the old OpenGLRenderer. \sa rendering \ingroup rendering */ class MITK_CORE_EXPORT VtkPropRenderer : public BaseRenderer { // Workaround for Displaylistbug private: bool didCount; void checkState(); // Workaround END public: mitkClassMacro(VtkPropRenderer,BaseRenderer); mitkNewMacro3Param(VtkPropRenderer, const char*, vtkRenderWindow *, mitk::RenderingManager* ); typedef std::map MappersMapType; // Render - called by vtkMitkRenderProp, returns the number of props rendered #if ( ( VTK_MAJOR_VERSION >= 5 ) && ( VTK_MINOR_VERSION>=2) ) enum RenderType{Opaque,Translucent,Overlay,Volumetric}; #else enum RenderType{Opaque,Translucent,Overlay}; #endif int Render(RenderType type); // Active current renderwindow virtual void MakeCurrent(); virtual void SetDataStorage( mitk::DataStorage* storage ); ///< set the datastorage that will be used for rendering virtual void InitRenderer(vtkRenderWindow* renderwindow); virtual void Update(mitk::DataNode* datatreenode); virtual void SetMapperID(const MapperSlotId mapperId); // Size virtual void InitSize(int w, int h); virtual void Resize(int w, int h); // Picking enum PickingMode{ WorldPointPicking, PointPicking }; - itkSetMacro( PickingMode, PickingMode ); - itkGetMacro( PickingMode, PickingMode ); + itkSetEnumMacro( PickingMode, PickingMode ); + itkGetEnumMacro( PickingMode, PickingMode ); virtual void PickWorldPoint(const Point2D& displayPoint, Point3D& worldPoint) const; virtual mitk::DataNode *PickObject( const Point2D &displayPosition, Point3D &worldPosition ) const; // Simple text rendering method int WriteSimpleText(std::string text, double posX, double posY, double color1 = 0.0, double color2 = 1.0, double color3 = 0.0); vtkTextProperty * GetTextLabelProperty(int text_id); // Initialization / geometry handling /** This method calculates the bounds of the DataStorage (if it contains any * valid data), creates a geometry from these bounds and sets it as world * geometry of the renderer. * * Call this method to re-initialize the renderer to the current DataStorage * (e.g. after loading an additional dataset), to ensure that the view is * aligned correctly. */ virtual bool SetWorldGeometryToDataStorageBounds(); /** * \brief Used by vtkPointPicker/vtkPicker. * This will query a list of all objects in MITK and provide every vtk based mapper to the picker. */ void InitPathTraversal(); /** * \brief Used by vtkPointPicker/vtkPicker. * This will query a list of all objects in MITK and provide every vtk based mapper to the picker. */ vtkAssemblyPath* GetNextPath(); const vtkWorldPointPicker *GetWorldPointPicker() const; const vtkPointPicker *GetPointPicker() const; const vtkCellPicker *GetCellPicker() const; /** * \brief Release vtk-based graphics resources. Called by * vtkMitkRenderProp::ReleaseGraphicsResources. */ virtual void ReleaseGraphicsResources(vtkWindow *renWin); #if ( ( VTK_MAJOR_VERSION >= 5 ) && ( VTK_MINOR_VERSION>=2) ) MappersMapType GetMappersMap() const; #endif static bool useImmediateModeRendering(); protected: VtkPropRenderer( const char* name = "VtkPropRenderer", vtkRenderWindow * renWin = NULL, mitk::RenderingManager* rm = NULL ); virtual ~VtkPropRenderer(); virtual void Update(); private: // switch between orthogonal opengl projection (2D rendering via mitk::GLMapper2D) and perspective projection (3D rendering) void Enable2DOpenGL(); void Disable2DOpenGL(); // prepare all mitk::mappers for rendering void PrepareMapperQueue(); bool m_InitNeeded; bool m_ResizeNeeded; bool m_VtkMapperPresent; bool m_NewRenderer; // Picking vtkWorldPointPicker * m_WorldPointPicker; vtkPointPicker * m_PointPicker; vtkCellPicker * m_CellPicker; PickingMode m_PickingMode; // Explicit use of SmartPointer to avoid circular #includes itk::SmartPointer< mitk::Mapper > m_CurrentWorldGeometry2DMapper; vtkLightKit* m_LightKit; // sorted list of mappers MappersMapType m_MappersMap; // rendering of text vtkRenderer * m_TextRenderer; typedef std::map TextMapType; TextMapType m_TextCollection; DataStorage::SetOfObjects::ConstPointer m_PickingObjects; DataStorage::SetOfObjects::const_iterator m_PickingObjectsIterator; }; } // namespace mitk #endif /* MITKVtkPropRenderer_H_HEADER_INCLUDED_C1C29F6D */ diff --git a/Core/Code/Testing/mitkBaseDataTest.cpp b/Core/Code/Testing/mitkBaseDataTest.cpp index 88e85ef39d..e8994ee97d 100644 --- a/Core/Code/Testing/mitkBaseDataTest.cpp +++ b/Core/Code/Testing/mitkBaseDataTest.cpp @@ -1,108 +1,112 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision: 17495 $ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "mitkBaseDataTestImplementation.h" #include "mitkStringProperty.h" #include "mitkTestingMacros.h" #include "itkImage.h" int mitkBaseDataTest(int /*argc*/, char* /*argv*/[]) { MITK_TEST_BEGIN("BaseData") //Create a BaseData implementation std::cout << "Creating a base data instance..." << std::endl; mitk::BaseDataTestImplementation::Pointer baseDataImpl = mitk::BaseDataTestImplementation::New(); MITK_TEST_CONDITION_REQUIRED(baseDataImpl.IsNotNull(),"Testing instantiation"); MITK_TEST_CONDITION(baseDataImpl->IsInitialized(), "BaseDataTestImplementation is initialized"); MITK_TEST_CONDITION(baseDataImpl->IsEmpty(), "BaseDataTestImplementation is initialized and empty"); MITK_TEST_CONDITION(baseDataImpl->GetExternalReferenceCount()== baseDataImpl->GetReferenceCount(), "Checks external reference count!"); std::cout << "Testing setter and getter for geometries..." << std::endl; //test method GetTimeSlicedGeometry() MITK_TEST_CONDITION(baseDataImpl->GetTimeSlicedGeometry(), "Testing creation of TimeSlicedGeometry"); mitk::TimeSlicedGeometry* geo = NULL; baseDataImpl->SetGeometry(geo); MITK_TEST_CONDITION(baseDataImpl->GetTimeSlicedGeometry() == NULL, "Reset Geometry"); mitk::TimeSlicedGeometry::Pointer geo2 = mitk::TimeSlicedGeometry::New(); baseDataImpl->SetGeometry(geo2); baseDataImpl->InitializeTimeSlicedGeometry(2); MITK_TEST_CONDITION(baseDataImpl->GetTimeSlicedGeometry() == geo2, "Correct Reinit of TimeslicedGeometry"); //test method GetGeometry(int timeStep) MITK_TEST_CONDITION(baseDataImpl->GetGeometry(1) != NULL, "... and single Geometries"); //test method Expand(unsigned int timeSteps) baseDataImpl->Expand(5); MITK_TEST_CONDITION(baseDataImpl->GetTimeSteps() == 5, "Expand the geometry to further time slices!"); //test method GetUpdatedGeometry(int timeStep); mitk::Geometry3D::Pointer geo3 = mitk::Geometry3D::New(); - baseDataImpl->SetGeometry(geo3, 1); + mitk::TimeSlicedGeometry::Pointer timeSlicedGeometry = baseDataImpl->GetTimeSlicedGeometry(); + if (timeSlicedGeometry.IsNotNull() ) + { + timeSlicedGeometry->SetGeometry3D(geo3, 1); + } MITK_TEST_CONDITION(baseDataImpl->GetUpdatedGeometry(1) == geo3, "Set Geometry for time step 1"); MITK_TEST_CONDITION(baseDataImpl->GetMTime()!= 0, "Check if modified time is set"); baseDataImpl->SetClonedGeometry(geo3, 1); float x[3]; x[0] = 2; x[1] = 4; x[2] = 6; mitk::Point3D p3d(x); baseDataImpl->SetOrigin(p3d); geo3->SetOrigin(p3d); MITK_TEST_CONDITION(baseDataImpl->GetGeometry(1)->GetOrigin() == geo3->GetOrigin(), "Testing Origin set"); - MITK_TEST_CONDITION(!baseDataImpl->IsEmpty(1), "Is not empty before clear()!"); + MITK_TEST_CONDITION(!baseDataImpl->IsEmptyTimeStep(1), "Is not empty before clear()!"); baseDataImpl->Clear(); - MITK_TEST_CONDITION(baseDataImpl->IsEmpty(1), "...but afterwards!"); + MITK_TEST_CONDITION(baseDataImpl->IsEmptyTimeStep(1), "...but afterwards!"); //test method Set-/GetProperty() baseDataImpl->SetProperty("property38", mitk::StringProperty::New("testproperty")); //baseDataImpl->SetProperty("visibility", mitk::BoolProperty::New()); MITK_TEST_CONDITION(baseDataImpl->GetProperty("property38")->GetValueAsString() == "testproperty","Check if base property is set correctly!"); //test method Set-/GetPropertyList mitk::PropertyList::Pointer propertyList = mitk::PropertyList::New(); propertyList->SetFloatProperty("floatProperty1", 123.45); propertyList->SetBoolProperty("visibility",true); propertyList->SetStringProperty("nameXY","propertyName"); baseDataImpl->SetPropertyList(propertyList); bool value = false; MITK_TEST_CONDITION(baseDataImpl->GetPropertyList() == propertyList, "Check if base property list is set correctly!"); MITK_TEST_CONDITION(baseDataImpl->GetPropertyList()->GetBoolProperty("visibility", value) == true, "Check if base property is set correctly in the property list!"); //test method UpdateOutputInformation() baseDataImpl->UpdateOutputInformation(); MITK_TEST_CONDITION(baseDataImpl->GetUpdatedTimeSlicedGeometry() == geo2, "TimeSlicedGeometry update!"); //Test method CopyInformation() mitk::BaseDataTestImplementation::Pointer newBaseData = mitk::BaseDataTestImplementation::New(); newBaseData->CopyInformation(baseDataImpl); MITK_TEST_CONDITION( newBaseData->GetTimeSlicedGeometry()->GetTimeSteps() == 5, "Check copying of of Basedata Data Object!"); MITK_TEST_END() } diff --git a/Core/Code/Testing/mitkPointSetTest.cpp b/Core/Code/Testing/mitkPointSetTest.cpp index 8bee4e149e..a14bc28d02 100644 --- a/Core/Code/Testing/mitkPointSetTest.cpp +++ b/Core/Code/Testing/mitkPointSetTest.cpp @@ -1,604 +1,604 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "mitkTestingMacros.h" #include #include #include #include #include class mitkPointSetTestClass { public: static void TestGetITKPointSet(mitk::PointSet *pointSet) { //try to get the itkPointSet mitk::PointSet::DataType::Pointer itkdata = NULL; itkdata = pointSet->GetPointSet(); MITK_TEST_CONDITION( itkdata.IsNotNull(), "try to get the itkPointSet from a newly created PointSet" ) } static void TestGetSizeIsZero(mitk::PointSet *pointSet) { //fresh PointSet has to be empty! MITK_TEST_CONDITION( pointSet->GetSize() == 0, "check if the PointSet size is 0 " ) } static void TestIsEmpty(mitk::PointSet *pointSet) { - MITK_TEST_CONDITION(pointSet->IsEmpty(0), "check if the PointSet is empty" ) + MITK_TEST_CONDITION(pointSet->IsEmptyTimeStep(0), "check if the PointSet is empty" ) } static void TestCreateOperationAndAddPoint(mitk::PointSet *pointSet) { int id = 0; mitk::Point3D point; point.Fill(1); mitk::PointOperation* doOp = new mitk::PointOperation(mitk::OpINSERT, point, id); pointSet->ExecuteOperation(doOp); MITK_TEST_CONDITION( pointSet->GetSize()==1 && pointSet->IndexExists(id), "check if added points exists" ) delete doOp; mitk::Point3D tempPoint; tempPoint.Fill(0); tempPoint = pointSet->GetPoint(id); MITK_TEST_CONDITION( point == tempPoint, "check if added point contains real value" ) } static void TestAddSecondPoint(mitk::PointSet *pointSet) { //add a point directly int id=0; mitk::Point3D point; mitk::FillVector3D(point, 1.0, 2.0, 3.0); ++id; pointSet->GetPointSet()->GetPoints()->InsertElement(id, point); MITK_TEST_CONDITION( pointSet->GetSize()==2 ||pointSet->IndexExists(id), "check if added points exists" ) mitk::Point3D tempPoint; tempPoint.Fill(0); tempPoint = pointSet->GetPoint(id); MITK_TEST_CONDITION( point == tempPoint, "check if added point contains real value" ) } static void TestIsNotEmpty(mitk::PointSet *pointSet) { //PointSet can not be empty! - MITK_TEST_CONDITION( !pointSet->IsEmpty(0), "check if the PointSet is not empty " ) + MITK_TEST_CONDITION( !pointSet->IsEmptyTimeStep(0), "check if the PointSet is not empty " ) /* std::cout << "check if the PointSet is not empty "; if (pointSet->IsEmpty(0)) { std::cout<<"[FAILED]"<GetPoint(1); pointSet->SwapPointPosition(1, true); tempPoint = pointSet->GetPoint(0); MITK_TEST_CONDITION( point == tempPoint, "check SwapPointPosition upwards" ) /* if(point != tempPoint) { std::cout<<"[FAILED]"<SwapPointPosition(0, true)==false, "check SwapPointPosition upwards not possible" ) /* if(pointSet->SwapPointPosition(0, true)) { std::cout<<"[FAILED]"<GetPoint(0); pointSet->SwapPointPosition(0, false); tempPoint = pointSet->GetPoint(1); MITK_TEST_CONDITION( point == tempPoint, "check SwapPointPosition down" ) /* if(point != tempPoint) { std::cout<<"[FAILED]"<SetPoint(id, point); //Check SwapPointPosition downwards not possible MITK_TEST_CONDITION(!pointSet2->SwapPointPosition(id, false), "check SwapPointPosition downwards not possible" ) /* if(pointSet->SwapPointPosition(1, false)) { std::cout<<"[FAILED]"<ExecuteOperation(doOp); tempPoint = pointSet->GetPoint(id); MITK_TEST_CONDITION(tempPoint == point1 , "check PointOperation OpMove " ) delete doOp; /* if (tempPoint != point1) { std::cout<<"[FAILED]"<GetPoint(id); mitk::PointOperation* doOp = new mitk::PointOperation(mitk::OpREMOVE, point, id); pointSet->ExecuteOperation(doOp); tempPoint = pointSet->GetPoint(id); MITK_TEST_CONDITION(!pointSet->IndexExists(id) , "check PointOperation OpREMOVE " ) delete doOp; /* if(pointSet->IndexExists(id)) { std::cout<<"[FAILED]"<ExecuteOperation(doOp); MITK_TEST_CONDITION(pointSet->GetSelectInfo(4) , "check PointOperation OpSELECTPOINT " ) delete doOp; /* if (!pointSet->GetSelectInfo(4)) { std::cout<<"[FAILED]"<GetNumberOfSelected() == 1 , "check GetNumeberOfSelected " ) /* if(pointSet->GetNumberOfSelected() != 1) { std::cout<<"[FAILED]"<SearchSelectedPoint() == 4 , "check SearchSelectedPoint " ) /* if( pointSet->SearchSelectedPoint() != 4) { std::cout<<"[FAILED]"<ExecuteOperation(doOp); MITK_TEST_CONDITION(!pointSet->GetSelectInfo(4) , "check PointOperation OpDESELECTPOINT " ) MITK_TEST_CONDITION(pointSet->GetNumberOfSelected() == 0 , "check GetNumeberOfSelected " ) delete doOp; /* if (pointSet->GetSelectInfo(4)) { std::cout<<"[FAILED]"<GetNumberOfSelected() != 0) { std::cout<<"[FAILED]"<GetPoint(id); mitk::PointOperation* doOp = new mitk::PointOperation(mitk::OpMOVEPOINTUP, point4, id); pointSet->ExecuteOperation(doOp); tempPoint = pointSet->GetPoint(id-1); MITK_TEST_CONDITION(tempPoint == point , "check PointOperation OpMOVEPOINTUP " ) delete doOp; /* if (tempPoint != point) { std::cout<<"[FAILED]"<GetPoint(id); mitk::PointOperation* doOp = new mitk::PointOperation(mitk::OpMOVEPOINTDOWN, point2, id); pointSet->ExecuteOperation(doOp); tempPoint = pointSet->GetPoint(id+1); MITK_TEST_CONDITION(tempPoint == point , "check PointOperation OpMOVEPOINTDOWN " ) delete doOp; /* if (tempPoint != point) { std::cout<<"[FAILED]"<SetSelectInfo(2, true); MITK_TEST_CONDITION(pointSet->GetSelectInfo(2) , "check SetSelectInfo" ) /* if (!pointSet->GetSelectInfo(2)) { std::cout<<"[FAILED]"<SetPoint(5, point5, mitk::PTEDGE ); tempPoint = pointSet->GetPoint(5); MITK_TEST_CONDITION(tempPoint == point5, "check InsertPoint with PointSpecification" ) /* if (tempPoint != point5) { std::cout<<"[FAILED]"<GetPointIfExists(5, &tmpPoint); MITK_TEST_CONDITION(tmpPoint == point5, "check GetPointIfExists: " ) /* if (tmpPoint != point5) { std::cout<<"[FAILED]"<InsertPoint(10, p10); pointSet->InsertPoint(11, p11); pointSet->InsertPoint(12, p12); MITK_TEST_CONDITION((pointSet->IndexExists(10) == true) || (pointSet->IndexExists(11) == true) || (pointSet->IndexExists(12) == true), "add points with id 10, 11, 12: " ) //check OpREMOVE ExecuteOperation int id = 11; mitk::PointOperation* doOp = new mitk::PointOperation(mitk::OpREMOVE, point, id); pointSet->ExecuteOperation(doOp); MITK_TEST_CONDITION(!pointSet->IndexExists(id), "remove point id 11: ") /* if(pointSet->IndexExists(id)) { std::cout<<"[FAILED]"<ExecuteOperation(doOp); delete doOp; //check OpMOVEPOINTUP ExecuteOperation doOp = new mitk::PointOperation(mitk::OpMOVEPOINTUP, p12, 12); pointSet->ExecuteOperation(doOp); delete doOp; mitk::PointSet::PointType newP10 = pointSet->GetPoint(10); mitk::PointSet::PointType newP12 = pointSet->GetPoint(12); MITK_TEST_CONDITION(((newP10 == p12) && (newP12 == p10)) == true, "check PointOperation OpMOVEPOINTUP for point id 12:" ) //check OpMOVEPOINTDOWN ExecuteOperation doOp = new mitk::PointOperation(mitk::OpMOVEPOINTDOWN, p10, 10); pointSet->ExecuteOperation(doOp); delete doOp; newP10 = pointSet->GetPoint(10); newP12 = pointSet->GetPoint(12); MITK_TEST_CONDITION(((newP10 == p10) && (newP12 == p12)) == true, "check PointOperation OpMOVEPOINTDOWN for point id 10: ") } static void TestOpMovePointUpOnFirstPoint(mitk::PointSet *pointSet) { //check OpMOVEPOINTUP on first point ExecuteOperation mitk::PointSet::PointType p1 = pointSet->GetPoint(1); mitk::PointSet::PointType p2 = pointSet->GetPoint(2); mitk::PointOperation* doOp = new mitk::PointOperation(mitk::OpMOVEPOINTUP, p1, 1); pointSet->ExecuteOperation(doOp); delete doOp; mitk::PointSet::PointType newP1 = pointSet->GetPoint(1); mitk::PointSet::PointType newP2 = pointSet->GetPoint(2); MITK_TEST_CONDITION(((newP1 == p1) && (newP2 == p2)) == true, "check PointOperation OpMOVEPOINTUP for point id 1: ") /* if (((newP1 == p1) && (newP2 == p2)) == false) { std::cout<<"[FAILED]"<GetPointSet()->GetPoints(); mitk::PointSet::PointDataContainer* pd = ps->GetPointSet()->GetPointData(); MITK_TEST_CONDITION_REQUIRED(pc->Size() == pd->Size(), "PointContainer and PointDataContainer have same size"); mitk::PointSet::PointsContainer::ConstIterator pIt = pc->Begin(); mitk::PointSet::PointDataContainer::ConstIterator dIt = pd->Begin(); bool failed = false; for (; pIt != pc->End(); ++pIt, ++dIt) if (pIt->Index() != dIt->Index()) { failed = true; break; } MITK_TEST_CONDITION(failed == false, "Indices in PointContainer and PointDataContainer are equal"); } }; int mitkPointSetTest(int /*argc*/, char* /*argv*/[]) { MITK_TEST_BEGIN("PointSet") //Create PointSet mitk::PointSet::Pointer pointSet = mitk::PointSet::New(); MITK_TEST_CONDITION_REQUIRED(pointSet.IsNotNull(),"Testing instantiation") mitkPointSetTestClass::TestGetITKPointSet(pointSet); mitkPointSetTestClass::TestGetSizeIsZero(pointSet); mitkPointSetTestClass::TestIsEmpty(pointSet); mitkPointSetTestClass::TestCreateOperationAndAddPoint(pointSet); mitk::Point3D point2, point3, point4; point2.Fill(3); point3.Fill(4); point4.Fill(5); pointSet->InsertPoint(2,point2); pointSet->InsertPoint(3,point3); pointSet->InsertPoint(4,point4); mitkPointSetTestClass::TestAddSecondPoint(pointSet); mitkPointSetTestClass::TestIsNotEmpty(pointSet); mitkPointSetTestClass::TestSwapPointPositionUpwards(pointSet); mitkPointSetTestClass::TestSwapPointPositionUpwardsNotPossible(pointSet); mitkPointSetTestClass::TestSwapPointPositionDownwards(pointSet); mitkPointSetTestClass::TestSwapPointPositionDownwardsNotPossible(pointSet); mitkPointSetTestClass::TestPointOperationOpMove(pointSet); mitkPointSetTestClass::TestPointOperationOpRemove(pointSet); mitkPointSetTestClass::TestPointOperationOpSelectPoint(pointSet); mitkPointSetTestClass::TestGetNumberOfSelected(pointSet); mitkPointSetTestClass::TestSearchSelectedPoint(pointSet); mitkPointSetTestClass::TestOpDeselectPoint(pointSet); mitkPointSetTestClass::TestOpMovePointUp(pointSet); mitkPointSetTestClass::TestOpMovePointDown(pointSet); mitkPointSetTestClass::TestSetSelectInfo(pointSet); mitkPointSetTestClass::TestInsertPointWithPointSpecification(pointSet); mitkPointSetTestClass::TestGetPointIfExists(pointSet); mitkPointSetTestClass::TestCreateHoleInThePointIDs(pointSet); mitkPointSetTestClass::TestOpMovePointUpOnFirstPoint(pointSet); MITK_TEST_OUTPUT(<< "Test InsertPoint(), SetPoint() and SwapPointPosition()"); mitk::PointSet::PointType point; mitk::FillVector3D(point, 2.2, 3.3, -4.4); /* call everything that might modify PointContainer and PointDataContainer */ pointSet->InsertPoint(17, point); pointSet->SetPoint(4, point); pointSet->SetPoint(7, point); pointSet->SetPoint(2, point); pointSet->SwapPointPosition(7, true); pointSet->SwapPointPosition(3, true); pointSet->SwapPointPosition(2, false); mitkPointSetTestClass::TestPointContainerPointDataContainer(pointSet); MITK_TEST_OUTPUT(<< "Test OpREMOVE"); mitk::PointOperation op1(mitk::OpREMOVE, mitk::Point3D(), 2); // existing index pointSet->ExecuteOperation(&op1); mitk::PointOperation op1b(mitk::OpREMOVE, mitk::Point3D(), 112); // non existing index pointSet->ExecuteOperation(&op1b); mitkPointSetTestClass::TestPointContainerPointDataContainer(pointSet); MITK_TEST_OUTPUT(<< "Test OpMove"); mitk::PointOperation op2(mitk::OpMOVE, mitk::Point3D(), 4); // existing index pointSet->ExecuteOperation(&op2); mitk::PointOperation op3(mitk::OpMOVE, mitk::Point3D(), 34); // non existing index pointSet->ExecuteOperation(&op3); mitkPointSetTestClass::TestPointContainerPointDataContainer(pointSet); MITK_TEST_OUTPUT(<< "Test OpINSERT"); mitk::PointOperation op4(mitk::OpINSERT, mitk::Point3D(), 38); // non existing index pointSet->ExecuteOperation(&op4); mitk::PointOperation op5(mitk::OpINSERT, mitk::Point3D(), 17); // existing index pointSet->ExecuteOperation(&op5); mitkPointSetTestClass::TestPointContainerPointDataContainer(pointSet); MITK_TEST_END(); } diff --git a/Core/Code/Testing/mitkSlicedGeometry3DTest.cpp b/Core/Code/Testing/mitkSlicedGeometry3DTest.cpp index ef88935be2..d63dd2995d 100644 --- a/Core/Code/Testing/mitkSlicedGeometry3DTest.cpp +++ b/Core/Code/Testing/mitkSlicedGeometry3DTest.cpp @@ -1,257 +1,257 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "mitkImage.h" #include "mitkPlaneGeometry.h" #include "mitkTimeSlicedGeometry.h" #include "mitkSlicedGeometry3D.h" #include "mitkTestingMacros.h" #include #include #include void mitkSlicedGeometry3D_ChangeImageGeometryConsideringOriginOffset_Test() { //Tests for Offset MITK_TEST_OUTPUT( << "====== NOW RUNNING: Tests for pixel-center-based offset concerns ========"); // create a SlicedGeometry3D mitk::SlicedGeometry3D::Pointer slicedGeo3D=mitk::SlicedGeometry3D::New(); int num_slices = 5; - slicedGeo3D->Initialize(num_slices); // 5 slices + slicedGeo3D->InitializeSlicedGeometry(num_slices); // 5 slices mitk::Point3D newOrigin; newOrigin[0] = 91.3; newOrigin[1] = -13.3; newOrigin[2] = 0; slicedGeo3D->SetOrigin(newOrigin); mitk::Vector3D newSpacing; newSpacing[0] = 1.0f; newSpacing[1] = 0.9f; newSpacing[2] = 0.3f; slicedGeo3D->SetSpacing(newSpacing); // create subslices as well for (int i=0; i < num_slices; i++) { mitk::Geometry2D::Pointer geo2d = mitk::Geometry2D::New(); geo2d->Initialize(); slicedGeo3D->SetGeometry2D(geo2d,i); } // now run tests MITK_TEST_OUTPUT( << "Testing whether slicedGeo3D->GetImageGeometry() is false by default"); MITK_TEST_CONDITION_REQUIRED( slicedGeo3D->GetImageGeometry()==false, ""); MITK_TEST_OUTPUT( << "Testing whether first and last geometry in the SlicedGeometry3D have GetImageGeometry()==false by default"); mitk::Geometry3D* subSliceGeo2D_first = slicedGeo3D->GetGeometry2D(0); mitk::Geometry3D* subSliceGeo2D_last = slicedGeo3D->GetGeometry2D(num_slices-1); MITK_TEST_CONDITION_REQUIRED( subSliceGeo2D_first->GetImageGeometry()==false, ""); MITK_TEST_CONDITION_REQUIRED( subSliceGeo2D_last->GetImageGeometry()==false, ""); // Save some Origins and cornerpoints mitk::Point3D OriginSlicedGeo( slicedGeo3D->GetOrigin() ); mitk::Point3D OriginFirstGeo( subSliceGeo2D_first->GetOrigin() ); mitk::Point3D OriginLastGeo( subSliceGeo2D_last->GetOrigin() ); mitk::Point3D CornerPoint0SlicedGeo(slicedGeo3D->GetCornerPoint(0)); mitk::Point3D CornerPoint1FirstGeo(subSliceGeo2D_first->GetCornerPoint(1)); mitk::Point3D CornerPoint2LastGeo(subSliceGeo2D_last->GetCornerPoint(2)); MITK_TEST_OUTPUT( << "Calling slicedGeo3D->ChangeImageGeometryConsideringOriginOffset(true)"); //std::cout << "vorher Origin: " << subSliceGeo2D_first->GetOrigin() << std::endl; //std::cout << "vorher Corner: " << subSliceGeo2D_first->GetCornerPoint(0) << std::endl; slicedGeo3D->ChangeImageGeometryConsideringOriginOffset(true); //std::cout << "nachher Origin: " << subSliceGeo2D_first->GetOrigin() << std::endl; //std::cout << "nachher Corner: " << subSliceGeo2D_first->GetCornerPoint(0) << std::endl; MITK_TEST_OUTPUT( << "Testing whether slicedGeo3D->GetImageGeometry() is now true"); MITK_TEST_CONDITION_REQUIRED( slicedGeo3D->GetImageGeometry()==true, ""); MITK_TEST_OUTPUT( << "Testing whether first and last geometry in the SlicedGeometry3D have GetImageGeometry()==true now"); MITK_TEST_CONDITION_REQUIRED( subSliceGeo2D_first->GetImageGeometry()==true, ""); MITK_TEST_CONDITION_REQUIRED( subSliceGeo2D_last->GetImageGeometry()==true, ""); MITK_TEST_OUTPUT( << "Testing wether offset has been added to origins"); // Manually adding Offset. OriginSlicedGeo[0] += (slicedGeo3D->GetSpacing()[0]) / 2; OriginSlicedGeo[1] += (slicedGeo3D->GetSpacing()[1]) / 2; OriginSlicedGeo[2] += (slicedGeo3D->GetSpacing()[2]) / 2; OriginFirstGeo[0] += (subSliceGeo2D_first->GetSpacing()[0]) / 2; OriginFirstGeo[1] += (subSliceGeo2D_first->GetSpacing()[1]) / 2; OriginFirstGeo[2] += (subSliceGeo2D_first->GetSpacing()[2]) / 2; OriginLastGeo[0] += (subSliceGeo2D_last->GetSpacing()[0]) / 2; OriginLastGeo[1] += (subSliceGeo2D_last->GetSpacing()[1]) / 2; OriginLastGeo[2] += (subSliceGeo2D_last->GetSpacing()[2]) / 2; MITK_TEST_CONDITION_REQUIRED( subSliceGeo2D_first->GetCornerPoint(1)==CornerPoint1FirstGeo, ""); MITK_TEST_CONDITION_REQUIRED( subSliceGeo2D_last->GetCornerPoint(2)==CornerPoint2LastGeo, ""); MITK_TEST_CONDITION_REQUIRED( slicedGeo3D->GetCornerPoint(0)==CornerPoint0SlicedGeo, ""); MITK_TEST_CONDITION_REQUIRED( slicedGeo3D->GetOrigin()==OriginSlicedGeo, ""); MITK_TEST_CONDITION_REQUIRED( subSliceGeo2D_first->GetOrigin()==OriginFirstGeo, ""); MITK_TEST_CONDITION_REQUIRED( subSliceGeo2D_last->GetOrigin()==OriginLastGeo, ""); MITK_TEST_OUTPUT( << "Calling slicedGeo3D->ChangeImageGeometryConsideringOriginOffset(false)"); slicedGeo3D->ChangeImageGeometryConsideringOriginOffset(false); MITK_TEST_OUTPUT( << "Testing whether slicedGeo3D->GetImageGeometry() is now false"); MITK_TEST_CONDITION_REQUIRED( slicedGeo3D->GetImageGeometry()==false, ""); MITK_TEST_OUTPUT( << "Testing whether first and last geometry in the SlicedGeometry3D have GetImageGeometry()==false now"); MITK_TEST_CONDITION_REQUIRED( subSliceGeo2D_first->GetImageGeometry()==false, ""); MITK_TEST_CONDITION_REQUIRED( subSliceGeo2D_last->GetImageGeometry()==false, ""); MITK_TEST_OUTPUT( << "Testing wether offset has been added to origins of geometry"); // Manually substracting Offset. OriginSlicedGeo[0] -= (slicedGeo3D->GetSpacing()[0]) / 2; OriginSlicedGeo[1] -= (slicedGeo3D->GetSpacing()[1]) / 2; OriginSlicedGeo[2] -= (slicedGeo3D->GetSpacing()[2]) / 2; OriginFirstGeo[0] -= (subSliceGeo2D_first->GetSpacing()[0]) / 2; OriginFirstGeo[1] -= (subSliceGeo2D_first->GetSpacing()[1]) / 2; OriginFirstGeo[2] -= (subSliceGeo2D_first->GetSpacing()[2]) / 2; OriginLastGeo[0] -= (subSliceGeo2D_last->GetSpacing()[0]) / 2; OriginLastGeo[1] -= (subSliceGeo2D_last->GetSpacing()[1]) / 2; OriginLastGeo[2] -= (subSliceGeo2D_last->GetSpacing()[2]) / 2; MITK_TEST_CONDITION_REQUIRED( subSliceGeo2D_first->GetCornerPoint(1)==CornerPoint1FirstGeo, ""); MITK_TEST_CONDITION_REQUIRED( subSliceGeo2D_last->GetCornerPoint(2)==CornerPoint2LastGeo, ""); MITK_TEST_CONDITION_REQUIRED( slicedGeo3D->GetCornerPoint(0)==CornerPoint0SlicedGeo, ""); MITK_TEST_CONDITION_REQUIRED( slicedGeo3D->GetOrigin()==OriginSlicedGeo, ""); MITK_TEST_CONDITION_REQUIRED( subSliceGeo2D_first->GetOrigin()==OriginFirstGeo, ""); MITK_TEST_CONDITION_REQUIRED( subSliceGeo2D_last->GetOrigin()==OriginLastGeo, ""); MITK_TEST_OUTPUT( << "ALL SUCCESSFULLY!"); } int mitkSlicedGeometry3DTest(int /*argc*/, char* /*argv*/[]) { mitk::PlaneGeometry::Pointer planegeometry1 = mitk::PlaneGeometry::New(); mitk::Point3D origin; mitk::Vector3D right, bottom, normal; mitk::ScalarType width, height; mitk::ScalarType widthInMM, heightInMM, thicknessInMM; width = 100; widthInMM = width; height = 200; heightInMM = height; thicknessInMM = 3.5; mitk::FillVector3D(origin, 4.5, 7.3, 11.2); mitk::FillVector3D(right, widthInMM, 0, 0); mitk::FillVector3D(bottom, 0, heightInMM, 0); mitk::FillVector3D(normal, 0, 0, thicknessInMM); std::cout << "Initializing planegeometry1 by InitializeStandardPlane(rightVector, downVector, spacing = NULL): "<InitializeStandardPlane(right.Get_vnl_vector(), bottom.Get_vnl_vector()); std::cout << "Setting planegeometry2 to a cloned version of planegeometry1: "<(planegeometry1->Clone().GetPointer());; std::cout << "Changing the IndexToWorldTransform of planegeometry2 to a rotated version by SetIndexToWorldTransform() (keep origin): "<GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix(); mitk::VnlVector axis(3); mitk::FillVector3D(axis, 1.0, 1.0, 1.0); axis.normalize(); vnl_quaternion rotation(axis, 0.123); vnlmatrix = rotation.rotation_matrix_transpose()*vnlmatrix; mitk::Matrix3D matrix; matrix = vnlmatrix; transform->SetMatrix(matrix); transform->SetOffset(planegeometry2->GetIndexToWorldTransform()->GetOffset()); right.Set_vnl_vector( rotation.rotation_matrix_transpose()*right.Get_vnl_vector() ); bottom.Set_vnl_vector(rotation.rotation_matrix_transpose()*bottom.Get_vnl_vector()); normal.Set_vnl_vector(rotation.rotation_matrix_transpose()*normal.Get_vnl_vector()); planegeometry2->SetIndexToWorldTransform(transform); std::cout << "Setting planegeometry3 to the backside of planegeometry2: " <InitializeStandardPlane(planegeometry2, mitk::PlaneGeometry::Transversal, 0, false); std::cout << "Testing SlicedGeometry3D::InitializeEvenlySpaced(planegeometry3, zSpacing = 1, slices = 5, flipped = false): " <InitializeEvenlySpaced(planegeometry3, 1, numSlices, false); std::cout << "Testing availability and type (PlaneGeometry) of first geometry in the SlicedGeometry3D: "; mitk::PlaneGeometry* accessedplanegeometry3 = dynamic_cast(slicedWorldGeometry->GetGeometry2D(0)); if(accessedplanegeometry3==NULL) { std::cout<<"[FAILED]"<GetAxisVector(0), planegeometry3->GetAxisVector(0))==false) || (mitk::Equal(accessedplanegeometry3->GetAxisVector(1), planegeometry3->GetAxisVector(1))==false) || (mitk::Equal(accessedplanegeometry3->GetAxisVector(2), planegeometry3->GetAxisVector(2))==false) || (mitk::Equal(accessedplanegeometry3->GetOrigin(), planegeometry3->GetOrigin())==false)) { std::cout<<"[FAILED]"<(slicedWorldGeometry->GetGeometry2D(numSlices-1)); mitk::Point3D origin3last; origin3last = planegeometry3->GetOrigin()+slicedWorldGeometry->GetDirectionVector()*(numSlices-1); if(accessedplanegeometry3last==NULL) { std::cout<<"[FAILED]"<GetAxisVector(0), planegeometry3->GetAxisVector(0))==false) || (mitk::Equal(accessedplanegeometry3last->GetAxisVector(1), planegeometry3->GetAxisVector(1))==false) || (mitk::Equal(accessedplanegeometry3last->GetAxisVector(2), planegeometry3->GetAxisVector(2))==false) || (mitk::Equal(accessedplanegeometry3last->GetOrigin(), origin3last)==false) || (mitk::Equal(accessedplanegeometry3last->GetIndexToWorldTransform()->GetOffset(), origin3last.GetVectorFromOrigin())==false)) { std::cout<<"[FAILED]"<(slicedWorldGeometry->GetGeometry2D(0)); if(accessedplanegeometry3==NULL) { std::cout<<"[FAILED]"<GetAxisVector(0), planegeometry3->GetAxisVector(0))==false) || (mitk::Equal(accessedplanegeometry3->GetAxisVector(1), planegeometry3->GetAxisVector(1))==false) || (mitk::Equal(accessedplanegeometry3->GetAxisVector(2), planegeometry3->GetAxisVector(2))==false) || (mitk::Equal(accessedplanegeometry3->GetOrigin(), planegeometry3->GetOrigin())==false) || (mitk::Equal(accessedplanegeometry3->GetIndexToWorldTransform()->GetOffset(), planegeometry3->GetOrigin().GetVectorFromOrigin())==false)) { std::cout<<"[FAILED]"< #include #include void mitkTimeSlicedGeometry_ChangeImageGeometryConsideringOriginOffset_Test() { // additional tests to check the function ChangeImageGeometryConsideringOriginOffset(..) //first create a new timeslicedgeometry mitk::TimeSlicedGeometry::Pointer geoTime = mitk::TimeSlicedGeometry::New(); mitk::Geometry3D::Pointer geo3d = mitk::Geometry3D::New(); geo3d->Initialize(); int numOfTimeSteps = 5; geoTime->InitializeEvenlyTimed(geo3d, numOfTimeSteps); for (int i=0; i < numOfTimeSteps; i++) { mitk::Geometry3D::Pointer geo3d_sub = mitk::Geometry3D::New(); geo3d_sub->Initialize(); geoTime->SetGeometry3D(geo3d_sub, i); } MITK_TEST_OUTPUT( << "Testing whether geoTime->GetImageGeometry() is false by default"); MITK_TEST_CONDITION_REQUIRED( geoTime->GetImageGeometry()==false, ""); MITK_TEST_OUTPUT( << "Testing whether first and last geometry in the geoTime have GetImageGeometry()==false by default"); mitk::Geometry3D* subSliceGeo3D_first = geoTime->GetGeometry3D(0); mitk::Geometry3D* subSliceGeo3D_last = geoTime->GetGeometry3D(numOfTimeSteps-1); MITK_TEST_CONDITION_REQUIRED( subSliceGeo3D_first->GetImageGeometry()==false, ""); MITK_TEST_CONDITION_REQUIRED( subSliceGeo3D_last->GetImageGeometry()==false, ""); // Save some Origins and cornerpoints mitk::Point3D OriginTimeGeo( geoTime->GetOrigin() ); mitk::Point3D OriginFirstGeo( subSliceGeo3D_first->GetOrigin() ); mitk::Point3D OriginLastGeo( subSliceGeo3D_last->GetOrigin() ); mitk::Point3D CornerPoint0TimeGeo(geoTime->GetCornerPoint(0)); mitk::Point3D CornerPoint1FirstGeo(subSliceGeo3D_first->GetCornerPoint(1)); mitk::Point3D CornerPoint2LastGeo(subSliceGeo3D_last->GetCornerPoint(2)); //std::cout << "vorher Origin: " << subSliceGeo3D_first->GetOrigin() << std::endl; //std::cout << "vorher Corner: " << subSliceGeo3D_first->GetCornerPoint(0) << std::endl; MITK_TEST_OUTPUT( << "Calling geoTime->ChangeImageGeometryConsideringOriginOffset(true)"); geoTime->ChangeImageGeometryConsideringOriginOffset(true); //std::cout << "nachher Origin: " << subSliceGeo3D_first->GetOrigin() << std::endl; //std::cout << "nachher Corner: " << subSliceGeo3D_first->GetCornerPoint(0) << std::endl; MITK_TEST_OUTPUT( << "Testing whether geoTime->GetImageGeometry() is now true"); MITK_TEST_CONDITION_REQUIRED( geoTime->GetImageGeometry()==true, ""); MITK_TEST_OUTPUT( << "Testing whether first and last geometry in the SlicedGeometry3D have GetImageGeometry()==true now"); MITK_TEST_CONDITION_REQUIRED( subSliceGeo3D_first->GetImageGeometry()==true, ""); MITK_TEST_CONDITION_REQUIRED( subSliceGeo3D_last->GetImageGeometry()==true, ""); MITK_TEST_OUTPUT( << "Testing wether offset has been added to origins"); // Manually adding Offset. OriginTimeGeo[0] += (geoTime->GetSpacing()[0]) / 2; OriginTimeGeo[1] += (geoTime->GetSpacing()[1]) / 2; OriginTimeGeo[2] += (geoTime->GetSpacing()[2]) / 2; OriginFirstGeo[0] += (subSliceGeo3D_first->GetSpacing()[0]) / 2; OriginFirstGeo[1] += (subSliceGeo3D_first->GetSpacing()[1]) / 2; OriginFirstGeo[2] += (subSliceGeo3D_first->GetSpacing()[2]) / 2; OriginLastGeo[0] += (subSliceGeo3D_last->GetSpacing()[0]) / 2; OriginLastGeo[1] += (subSliceGeo3D_last->GetSpacing()[1]) / 2; OriginLastGeo[2] += (subSliceGeo3D_last->GetSpacing()[2]) / 2; MITK_TEST_CONDITION_REQUIRED( subSliceGeo3D_first->GetCornerPoint(1)==CornerPoint1FirstGeo, ""); MITK_TEST_CONDITION_REQUIRED( subSliceGeo3D_last->GetCornerPoint(2)==CornerPoint2LastGeo, ""); MITK_TEST_CONDITION_REQUIRED( geoTime->GetCornerPoint(0)==CornerPoint0TimeGeo, ""); MITK_TEST_CONDITION_REQUIRED( geoTime->GetOrigin()==OriginTimeGeo, ""); MITK_TEST_CONDITION_REQUIRED( subSliceGeo3D_first->GetOrigin()==OriginFirstGeo, ""); MITK_TEST_CONDITION_REQUIRED( subSliceGeo3D_last->GetOrigin()==OriginLastGeo, ""); MITK_TEST_OUTPUT( << "Calling geoTime->ChangeImageGeometryConsideringOriginOffset(false)"); geoTime->ChangeImageGeometryConsideringOriginOffset(false); MITK_TEST_OUTPUT( << "Testing whether geoTime->GetImageGeometry() is now false"); MITK_TEST_CONDITION_REQUIRED( geoTime->GetImageGeometry()==false, ""); MITK_TEST_OUTPUT( << "Testing whether first and last geometry in the geoTime have GetImageGeometry()==false now"); MITK_TEST_CONDITION_REQUIRED( subSliceGeo3D_first->GetImageGeometry()==false, ""); MITK_TEST_CONDITION_REQUIRED( subSliceGeo3D_last->GetImageGeometry()==false, ""); MITK_TEST_OUTPUT( << "Testing wether offset has been added to origins"); // Manually substracting Offset. OriginTimeGeo[0] -= (geoTime->GetSpacing()[0]) / 2; OriginTimeGeo[1] -= (geoTime->GetSpacing()[1]) / 2; OriginTimeGeo[2] -= (geoTime->GetSpacing()[2]) / 2; OriginFirstGeo[0] -= (subSliceGeo3D_first->GetSpacing()[0]) / 2; OriginFirstGeo[1] -= (subSliceGeo3D_first->GetSpacing()[1]) / 2; OriginFirstGeo[2] -= (subSliceGeo3D_first->GetSpacing()[2]) / 2; OriginLastGeo[0] -= (subSliceGeo3D_last->GetSpacing()[0]) / 2; OriginLastGeo[1] -= (subSliceGeo3D_last->GetSpacing()[1]) / 2; OriginLastGeo[2] -= (subSliceGeo3D_last->GetSpacing()[2]) / 2; MITK_TEST_CONDITION_REQUIRED( subSliceGeo3D_first->GetCornerPoint(1)==CornerPoint1FirstGeo, ""); MITK_TEST_CONDITION_REQUIRED( subSliceGeo3D_last->GetCornerPoint(2)==CornerPoint2LastGeo, ""); MITK_TEST_CONDITION_REQUIRED( geoTime->GetCornerPoint(0)==CornerPoint0TimeGeo, ""); MITK_TEST_CONDITION_REQUIRED( geoTime->GetOrigin()==OriginTimeGeo, ""); MITK_TEST_CONDITION_REQUIRED( subSliceGeo3D_first->GetOrigin()==OriginFirstGeo, ""); MITK_TEST_CONDITION_REQUIRED( subSliceGeo3D_last->GetOrigin()==OriginLastGeo, ""); } int mitkTimeSlicedGeometryTest(int /*argc*/, char* /*argv*/[]) { mitk::PlaneGeometry::Pointer planegeometry = mitk::PlaneGeometry::New(); mitk::Point3D origin; mitk::Vector3D right, bottom, normal; mitk::ScalarType width, height; mitk::ScalarType widthInMM, heightInMM, thicknessInMM; width = 100; widthInMM = width*0.5; height = 200; heightInMM = height*1.2; thicknessInMM = 1.5; mitk::FillVector3D(origin, 2.5, -3.3, 17.2); mitk::FillVector3D(right, widthInMM, 0, 0); mitk::FillVector3D(bottom, 0, heightInMM, 0); mitk::FillVector3D(normal, 0, 0, thicknessInMM); std::cout << "Creating TimeSlicedGeometry" <Initialize(numOfTimeSteps); + timeSlicedGeometry->InitializeEvenlyTimed(numOfTimeSteps); std::cout<<"[PASSED]"<GetTimeSteps()!=numOfTimeSteps) { std::cout<<"[FAILED]"<GetEvenlyTimed()!=true) { std::cout<<"[FAILED]"<InitializeStandardPlane(right.Get_vnl_vector(), bottom.Get_vnl_vector()); std::cout<<"[PASSED]"<SetTimeBounds(timeBounds1); std::cout<<"[PASSED]"<GetTimeBounds() != timeBounds1) { std::cout<<"[FAILED]"<InitializeEvenlyTimed(planegeometry, numOfTimeSteps); std::cout<<"[PASSED]"<GetTimeSteps() != numOfTimeSteps) { std::cout<<"[FAILED]"<GetEvenlyTimed()!=true) { std::cout<<"[FAILED]"<TimeStepToMS( 2 ) - 3.5) > mitk::eps) { std::cout<<"[FAILED]"<MSToTimeStep( 3.6 ) != 2) { std::cout<<"[FAILED]"<Initialize(); geometry->SetTimeBounds( timeBounds ); timeSlicedGeometry->InitializeEvenlyTimed( geometry, numOfTimeSteps+1 ); if(timeSlicedGeometry2->TimeStepToTimeStep( timeSlicedGeometry, 4 ) != 2) { std::cout<<"[FAILED]"<(timeSlicedGeometry2->GetGeometry3D(0)); if(accessedplanegeometry==NULL) { std::cout<<"[FAILED]"<GetAxisVector(0), planegeometry->GetAxisVector(0))==false) || (mitk::Equal(accessedplanegeometry->GetAxisVector(1), planegeometry->GetAxisVector(1))==false) || (mitk::Equal(accessedplanegeometry->GetAxisVector(2), planegeometry->GetAxisVector(2))==false) || (mitk::Equal(accessedplanegeometry->GetOrigin(), planegeometry->GetOrigin())==false)) { std::cout<<"[FAILED]"<GetTimeBounds() ) { std::cout<<"[FAILED]"<(timeSlicedGeometry2->GetGeometry3D(1)); if(secondplanegeometry==NULL) { std::cout<<"[FAILED]"<GetTimeBounds(); if( (timeBounds1[1] != secondtimebounds[0]) || (secondtimebounds[1] != secondtimebounds[0] + timeBounds1[1]-timeBounds1[0]) ) { std::cout<<"[FAILED]"<GetAxisVector(0), planegeometry->GetAxisVector(0))==false) || (mitk::Equal(secondplanegeometry->GetAxisVector(1), planegeometry->GetAxisVector(1))==false) || (mitk::Equal(secondplanegeometry->GetAxisVector(2), planegeometry->GetAxisVector(2))==false) || (mitk::Equal(secondplanegeometry->GetOrigin(), planegeometry->GetOrigin())==false)) { std::cout<<"[FAILED]"<InitializeEmpty(numOfTimeSteps); std::cout << "Testing TimeSlicedGeometry::GetEvenlyTimed():" <GetEvenlyTimed()!=false) { std::cout<<"[FAILED]"<SetEvenlyTimed(false); std::cout<<"[PASSED]"<GetEvenlyTimed()!=false) { std::cout<<"[FAILED]"<GetTimeSteps() != numOfTimeSteps) { std::cout<<"[FAILED]"<GetGeometry3D(0); if(accessedgeometry!=NULL) { std::cout<<"[FAILED]"<SetGeometry3D(planegeometry, 0); std::cout<<"[PASSED]"<(timeSlicedGeometry2->GetGeometry3D(0)); if(accessedplanegeometry==NULL) { std::cout<<"[FAILED]"<GetGeometry3D(1); if(accessedgeometry!=NULL) { std::cout<<"[FAILED]"<(planegeometry->Clone().GetPointer());; std::cout<<"[PASSED]"<SetTimeBounds(timeBounds3); std::cout<<"[PASSED]"<SetGeometry3D(planegeometry2, 1); std::cout<<"[PASSED]"<(timeSlicedGeometry2->GetGeometry3D(1)); if(accessedplanegeometry==NULL) { std::cout<<"[FAILED]"<GetTimeBounds() ) { std::cout<<"[FAILED]"<MitkRenderOverlay(renderer); Disable2DOpenGL(); m_OdfMapper->MitkRenderOverlay(renderer); } virtual void MitkRenderOpaqueGeometry(BaseRenderer* renderer) { Enable2DOpenGL(); m_ImgMapper->MitkRenderOpaqueGeometry(renderer); Disable2DOpenGL(); m_OdfMapper->MitkRenderOpaqueGeometry(renderer); if( mitk::RenderingManager::GetInstance()->GetNextLOD( renderer ) == 0 ) { renderer->Modified(); } } virtual void MitkRenderTranslucentGeometry(BaseRenderer* renderer) { Enable2DOpenGL(); m_ImgMapper->MitkRenderTranslucentGeometry(renderer); Disable2DOpenGL(); m_OdfMapper->MitkRenderTranslucentGeometry(renderer); } #if ( ( VTK_MAJOR_VERSION >= 5 ) && ( VTK_MINOR_VERSION>=2) ) virtual void MitkRenderVolumetricGeometry(BaseRenderer* renderer) { Enable2DOpenGL(); m_ImgMapper->MitkRenderVolumetricGeometry(renderer); Disable2DOpenGL(); m_OdfMapper->MitkRenderVolumetricGeometry(renderer); } #endif void SetDataNode(DataNode* node) { m_DataNode = node; m_ImgMapper->SetDataNode(node); m_OdfMapper->SetDataNode(node); } mitk::ImageMapperGL2D::Pointer GetImageMapper() { ImageMapperGL2D* retval = m_ImgMapper; return retval; } bool IsVtkBased() const { return m_OdfMapper->IsVtkBased(); } bool HasVtkProp( const vtkProp* prop, BaseRenderer* renderer ) { return m_OdfMapper->HasVtkProp(prop, renderer); } void ReleaseGraphicsResources(vtkWindow* window) { m_ImgMapper->ReleaseGraphicsResources(window); m_OdfMapper->ReleaseGraphicsResources(window); } static void SetDefaultProperties(DataNode* node, BaseRenderer* renderer = NULL, bool overwrite = false ) { mitk::OdfVtkMapper2D::SetDefaultProperties(node, renderer, overwrite); mitk::CopyImageMapper2D::SetDefaultProperties(node, renderer, overwrite); mitk::LevelWindow opaclevwin; opaclevwin.SetRangeMinMax(0,255); opaclevwin.SetWindowBounds(0,0); mitk::LevelWindowProperty::Pointer prop = mitk::LevelWindowProperty::New(opaclevwin); node->AddProperty( "opaclevelwindow", prop ); } bool IsLODEnabled( BaseRenderer * renderer ) const { return m_ImgMapper->IsLODEnabled(renderer) || m_OdfMapper->IsLODEnabled(renderer); } vtkProp* GetProp(mitk::BaseRenderer* renderer) { return m_OdfMapper->GetProp(renderer); } void SetGeometry3D(const mitk::Geometry3D* aGeometry3D) { m_ImgMapper->SetGeometry3D(aGeometry3D); m_OdfMapper->SetGeometry3D(aGeometry3D); } void Enable2DOpenGL(); void Disable2DOpenGL(); protected: virtual void GenerateData() { m_OdfMapper->GenerateData(); } - virtual void GenerateData(mitk::BaseRenderer* renderer) + virtual void GenerateDataForRenderer(mitk::BaseRenderer* renderer) { - m_ImgMapper->GenerateData(renderer); + m_ImgMapper->GenerateDataForRenderer(renderer); if( mitk::RenderingManager::GetInstance()->GetNextLOD( renderer ) > 0 ) { m_OdfMapper->GenerateData(renderer); } } CompositeMapper(); virtual ~CompositeMapper(); private: mitk::OdfVtkMapper2D::Pointer m_OdfMapper; mitk::CopyImageMapper2D::Pointer m_ImgMapper; }; } // namespace mitk #endif /* COMPOSITEMAPPER_H_HEADER_INCLUDED */ diff --git a/Modules/IGT/Testing/mitkTrackingVolumeGeneratorTest.cpp b/Modules/IGT/Testing/mitkTrackingVolumeGeneratorTest.cpp index 9d16c2e230..d4680ad1d9 100644 --- a/Modules/IGT/Testing/mitkTrackingVolumeGeneratorTest.cpp +++ b/Modules/IGT/Testing/mitkTrackingVolumeGeneratorTest.cpp @@ -1,142 +1,142 @@ /*==================================================================== Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include #include #include "mitkCommon.h" #include "mitkTestingMacros.h" #include "vtkPolyData.h" #include #include class mitkTrackingVolumeGeneratorTestClass { public: static void TestInstantiation() { // let's create an object of our class mitk::TrackingVolumeGenerator::Pointer myTVGenerator = mitk::TrackingVolumeGenerator::New(); MITK_TEST_CONDITION_REQUIRED(myTVGenerator.IsNotNull(),"Testing instantiation"); } static void TestTrackingSystemNotSpecified() { MITK_TEST_OUTPUT(<<"---- Testing Trackingsystem not specified ----"); mitk::TrackingVolumeGenerator::Pointer myTVGenerator = mitk::TrackingVolumeGenerator::New(); MITK_TEST_CONDITION((myTVGenerator->GetTrackingDeviceType() == mitk::TrackingSystemNotSpecified), "Tracking System not specified:"); myTVGenerator->Update(); mitk::Surface::Pointer volume = myTVGenerator->GetOutput(); - MITK_TEST_CONDITION((volume->IsEmpty(0) == false),"Output contains data"); + MITK_TEST_CONDITION((volume->IsEmptyTimeStep(0) == false),"Output contains data"); } static void TestClaronTrackingVolume() { MITK_TEST_OUTPUT(<< "---- Testing MicronTracker 2 Tracking Volume ----"); mitk::TrackingVolumeGenerator::Pointer myTVGenerator = mitk::TrackingVolumeGenerator::New (); myTVGenerator->SetTrackingDeviceType(mitk::ClaronMicron); MITK_TEST_CONDITION((myTVGenerator->GetTrackingDeviceType() == mitk::ClaronMicron),"loading MicronTracker Volume data:"); myTVGenerator->Update(); mitk::Surface::Pointer volume = myTVGenerator->GetOutput(); - MITK_TEST_CONDITION((volume->IsEmpty(0) == false),"Output contains data"); + MITK_TEST_CONDITION((volume->IsEmptyTimeStep(0) == false),"Output contains data"); } static void TestNDIAuroraTrackingVolume() { MITK_TEST_OUTPUT(<< "---- Testing NDI Aurora Tracking Volume ----"); mitk::TrackingVolumeGenerator::Pointer myTVGenerator = mitk::TrackingVolumeGenerator::New (); myTVGenerator->SetTrackingDeviceType(mitk::NDIAurora); MITK_TEST_CONDITION((myTVGenerator->GetTrackingDeviceType() == mitk::NDIAurora),"loading Aurora Volume data:"); myTVGenerator->Update(); mitk::Surface::Pointer volume = myTVGenerator->GetOutput(); - MITK_TEST_CONDITION((volume->IsEmpty(0) == false),"Output contains data"); + MITK_TEST_CONDITION((volume->IsEmptyTimeStep(0) == false),"Output contains data"); } static void TestNDIPolarisTrackingVolume() { MITK_TEST_OUTPUT(<< "---- Testing NDI Polaris Tracking Volume ----"); mitk::TrackingVolumeGenerator::Pointer myTVGenerator = mitk::TrackingVolumeGenerator::New (); myTVGenerator->SetTrackingDeviceType(mitk::NDIPolaris); MITK_TEST_CONDITION((myTVGenerator->GetTrackingDeviceType() == mitk::NDIPolaris),"loading Polaris Volume data:"); myTVGenerator->Update(); mitk::Surface::Pointer volume = myTVGenerator->GetOutput(); - MITK_TEST_CONDITION((volume->IsEmpty(0) == false),"Output contains data"); + MITK_TEST_CONDITION((volume->IsEmptyTimeStep(0) == false),"Output contains data"); } static void TestIntuitiveDaVinciTrackingVolume() { MITK_TEST_OUTPUT(<< "---- Testing Intuitive Da Vinci Tracking Volume ----"); mitk::TrackingVolumeGenerator::Pointer myTVGenerator = mitk::TrackingVolumeGenerator::New (); myTVGenerator->SetTrackingDeviceType(mitk::IntuitiveDaVinci); MITK_TEST_CONDITION((myTVGenerator->GetTrackingDeviceType() == mitk::IntuitiveDaVinci),"loading Da Vinci Volume data:"); myTVGenerator->Update(); mitk::Surface::Pointer volume = myTVGenerator->GetOutput(); - MITK_TEST_CONDITION((volume->IsEmpty(0) == false),"Output contains data"); + MITK_TEST_CONDITION((volume->IsEmptyTimeStep(0) == false),"Output contains data"); } static void TestInvalidInputBehaviour() { MITK_TEST_OUTPUT(<< "---- Testing Invalid Inputs (errors should occure) ----"); mitk::TrackingVolumeGenerator::Pointer myTVGenerator = mitk::TrackingVolumeGenerator::New (); myTVGenerator->SetTrackingDeviceType(mitk::TrackingSystemInvalid); //MicroBird not implemented yet, so using as test dummy MITK_TEST_CONDITION((myTVGenerator->GetTrackingDeviceType() == mitk::TrackingSystemInvalid),"testing device type"); myTVGenerator->Update(); MITK_TEST_CONDITION(myTVGenerator->GetOutput()->GetVtkPolyData()->GetNumberOfVerts()==0,"testing (invalid) output"); } static void TestSetTrackingDevice() { MITK_TEST_OUTPUT(<< "---- Testing method SetTrackingDevice() ----"); mitk::ClaronTrackingDevice::Pointer testTrackingDevice = mitk::ClaronTrackingDevice::New(); mitk::TrackingVolumeGenerator::Pointer myTVGenerator = mitk::TrackingVolumeGenerator::New (); myTVGenerator->SetTrackingDevice(dynamic_cast(testTrackingDevice.GetPointer())); MITK_TEST_CONDITION((myTVGenerator->GetTrackingDeviceType() == mitk::ClaronMicron),"testing SetTrackingDevice()"); } /* The isInside() method is not implemented so far. So please activate is as soon as this is done. Then we could load * the different Trackingvolumens (Polaris, MicronTracker, etc) and test different points inside and outside in this method. static void TestIsInside() { MITK_TEST_OUTPUT(<< "---- Testing IsInside-Method ----") mitk::TrackingVolume::Pointer myTrackingVolume = mitk::TrackingVolume::New(); mitk::Point3D p1; mitk::FillVector3D(p1,(float)0,(float)0,(float)0); MITK_TEST_CONDITION(myTrackingVolume->IsInside(p1)==false,"... successfull") } */ }; /** This function is testing the TrackingVolume class. */ int mitkTrackingVolumeGeneratorTest(int /* argc */, char* /*argv*/[]) { MITK_TEST_BEGIN("TrackingVolumeGenerator"); mitkTrackingVolumeGeneratorTestClass::TestInstantiation(); mitkTrackingVolumeGeneratorTestClass::TestTrackingSystemNotSpecified (); mitkTrackingVolumeGeneratorTestClass::TestClaronTrackingVolume(); mitkTrackingVolumeGeneratorTestClass::TestNDIAuroraTrackingVolume(); mitkTrackingVolumeGeneratorTestClass::TestNDIPolarisTrackingVolume(); mitkTrackingVolumeGeneratorTestClass::TestIntuitiveDaVinciTrackingVolume(); mitkTrackingVolumeGeneratorTestClass::TestInvalidInputBehaviour(); mitkTrackingVolumeGeneratorTestClass::TestSetTrackingDevice(); //mitkTrackingVolumeTestClass::TestIsInside(); Activate this code when method isInside() is implemented! MITK_TEST_END() ; } diff --git a/Modules/MitkExt/Algorithms/mitkPlaneCutFilter.h b/Modules/MitkExt/Algorithms/mitkPlaneCutFilter.h index 9faede0175..5d7f699398 100644 --- a/Modules/MitkExt/Algorithms/mitkPlaneCutFilter.h +++ b/Modules/MitkExt/Algorithms/mitkPlaneCutFilter.h @@ -1,77 +1,77 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef PLANECUTFILTER_H_HEADER_INCLUDED_C1F48A22 #define PLANECUTFILTER_H_HEADER_INCLUDED_C1F48A22 #include "mitkCommon.h" #include "MitkExtExports.h" #include "mitkImageToImageFilter.h" #include "mitkPlaneGeometry.h" namespace itk { template class ITK_EXPORT Image; } namespace mitk { /** \brief Filter to cut an image with a plane. Everything in the direction of the normal of the planes (if fill mode is set to "FILL") will be set to a specified value. */ class MitkExt_EXPORT PlaneCutFilter : public ImageToImageFilter { public: mitkClassMacro(PlaneCutFilter, ImageToImageFilter); /** Method for creation through the object factory. */ itkNewMacro(Self); typedef enum {FILL, FILL_INVERSE} FillMode; //##Documentation //## @brief Set background grey level itkSetMacro(BackgroundLevel, float); itkGetMacro(BackgroundLevel, float); - itkSetMacro(FillMode, FillMode); - itkGetMacro(FillMode, FillMode); + itkSetEnumMacro(FillMode, FillMode); + itkGetEnumMacro(FillMode, FillMode); itkSetObjectMacro(Plane, const PlaneGeometry); itkGetObjectMacro(Plane, const PlaneGeometry); protected: float m_BackgroundLevel; PlaneGeometry::ConstPointer m_Plane; FillMode m_FillMode; PlaneCutFilter(); ~PlaneCutFilter(); virtual void GenerateData(); template void _computeIntersection(itk::Image *itkImage, const PlaneGeometry *plane, const Geometry3D *geometry); }; } // namespace mitk #endif /* PLANECUTFILTER_H_HEADER_INCLUDED_C1F48A22 */ diff --git a/Modules/MitkExt/Algorithms/mitkPlanesPerpendicularToLinesFilter.cpp b/Modules/MitkExt/Algorithms/mitkPlanesPerpendicularToLinesFilter.cpp index 19e41695e5..82d9da2155 100644 --- a/Modules/MitkExt/Algorithms/mitkPlanesPerpendicularToLinesFilter.cpp +++ b/Modules/MitkExt/Algorithms/mitkPlanesPerpendicularToLinesFilter.cpp @@ -1,213 +1,213 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "mitkPlanesPerpendicularToLinesFilter.h" #include #include #include mitk::PlanesPerpendicularToLinesFilter::PlanesPerpendicularToLinesFilter() : m_Plane(NULL), m_UseAllPoints(false), m_CreatedGeometries(NULL), normal(3), targetRight(3) { m_CreatedGeometries = mitk::SlicedGeometry3D::New(); } mitk::PlanesPerpendicularToLinesFilter::~PlanesPerpendicularToLinesFilter() { } void mitk::PlanesPerpendicularToLinesFilter::GenerateOutputInformation() { mitk::Mesh::ConstPointer input = this->GetInput(); mitk::GeometryData::Pointer output = this->GetOutput(); itkDebugMacro(<<"GenerateOutputInformation()"); if(input.IsNull()) return; output->SetGeometry(m_CreatedGeometries); } void mitk::PlanesPerpendicularToLinesFilter::CreatePlane(const mitk::Point3D& curr) { int j; for(j=0;j<3;++j) normal[j] = last[j]-curr[j]; //@todo globally define normal direction of display xxx normal.normalize(); down = vnl_cross_3d(normal, targetRight); down.normalize(); right = vnl_cross_3d(down, normal); right.normalize(); itk2vtk(last.Get_vnl_vector()-right*halfWidthInMM-down*halfHeightInMM, origin); right *= targetSpacing[0]; down *= targetSpacing[1]; normal *= targetSpacing[2]; mitk::Matrix3D matrix; matrix.GetVnlMatrix().set_column(0, right); matrix.GetVnlMatrix().set_column(1, down); matrix.GetVnlMatrix().set_column(2, normal); PlaneGeometry::Pointer plane = PlaneGeometry::New(); plane->GetIndexToWorldTransform()->SetMatrix(matrix); plane->SetOrigin(origin); plane->SetBounds(bounds); planes.push_back(plane); last = curr; } void mitk::PlanesPerpendicularToLinesFilter::GenerateData() { mitk::Mesh::ConstPointer input = this->GetInput(); mitk::GeometryData::Pointer output = this->GetOutput(); if(m_Plane.IsNotNull()) { targetRight = m_Plane->GetMatrixColumn(0); targetSpacing = m_Plane->GetSpacing(); bounds = m_Plane->GetBoundingBox()->GetBounds(); halfWidthInMM = m_Plane->GetExtentInMM(0)*0.5; halfHeightInMM = m_Plane->GetExtentInMM(1)*0.5; } else { FillVector3D(targetRight, 1.0, 0.0, 0.0); targetSpacing.Fill(1.0); halfWidthInMM=halfHeightInMM=100.0; ScalarType stdBounds[6] = {0.0, 2.0*halfWidthInMM, 0.0, 2.0*halfHeightInMM, 0.0, 0.0}; bounds = stdBounds; } if(m_UseAllPoints==false) { int i, size; //iterate through all cells and build planes Mesh::ConstCellIterator cellIt, cellEnd; cellEnd = input->GetMesh()->GetCells()->End(); for( cellIt = input->GetMesh()->GetCells()->Begin(); cellIt != cellEnd; ++cellIt ) { Mesh::CellType& cell = *cellIt->Value(); Mesh::PointIdIterator ptIt, ptEnd; ptEnd = cell.PointIdsEnd(); size=cell.GetNumberOfPoints(); if(size<=1) continue; ptIt = cell.PointIdsBegin(); last = input->GetPoint(*ptIt); ++ptIt; for(i=1;iGetPoint(*ptIt)); } } } else //m_UseAllPoints==true { //iterate through all points and build planes mitk::PointSet::PointsConstIterator it, pend = input->GetPointSet()->GetPoints()->End(); it=input->GetPointSet()->GetPoints()->Begin(); last = it.Value(); ++it; for(;it!=pend;++it) { CreatePlane(it.Value()); } } if(planes.size()>0) { //initialize sliced-geometry for the number of created planes - m_CreatedGeometries->Initialize(planes.size()+1); + m_CreatedGeometries->InitializeSlicedGeometry(planes.size()+1); //set last plane at last point with same normal as the one before the last PlaneGeometry::Pointer plane = static_cast((*planes.rbegin())->Clone().GetPointer()); itk2vtk(last.Get_vnl_vector()-right*halfWidthInMM-down*halfHeightInMM, origin); plane->SetOrigin(origin); m_CreatedGeometries->SetGeometry2D(plane, planes.size()); //add all planes to sliced-geometry int s; for(s=0; planes.empty()==false; planes.pop_front(), ++s) { m_CreatedGeometries->SetGeometry2D(planes.front(), s); } m_CreatedGeometries->SetEvenlySpaced(false); if(m_FrameGeometry.IsNotNull()) { m_CreatedGeometries->SetIndexToWorldTransform(m_FrameGeometry->GetIndexToWorldTransform()); m_CreatedGeometries->SetBounds(m_FrameGeometry->GetBounds()); m_CreatedGeometries->SetReferenceGeometry(m_FrameGeometry); } } output->SetGeometry(m_CreatedGeometries); } void mitk::PlanesPerpendicularToLinesFilter::SetPlane(const mitk::PlaneGeometry* aPlane) { if(aPlane!=NULL) { m_Plane = static_cast(aPlane->Clone().GetPointer()); } else { if(m_Plane.IsNull()) return; m_Plane=NULL; } Modified(); } const mitk::Mesh *mitk::PlanesPerpendicularToLinesFilter::GetInput(void) { if (this->GetNumberOfInputs() < 1) { return 0; } return static_cast (this->ProcessObject::GetInput(0) ); } void mitk::PlanesPerpendicularToLinesFilter::SetInput(const mitk::Mesh *input) { // Process object is not const-correct so the const_cast is required here this->ProcessObject::SetNthInput(0, const_cast< mitk::Mesh * >( input ) ); } void mitk::PlanesPerpendicularToLinesFilter::SetFrameGeometry(const mitk::Geometry3D* frameGeometry) { if((frameGeometry != NULL) && (frameGeometry->IsValid())) { m_FrameGeometry = static_cast(frameGeometry->Clone().GetPointer()); } else { m_FrameGeometry = NULL; } } diff --git a/Modules/MitkExt/DataManagement/mitkBoundingObjectGroup.cpp b/Modules/MitkExt/DataManagement/mitkBoundingObjectGroup.cpp index 7191e8b3fa..40f104bdb7 100644 --- a/Modules/MitkExt/DataManagement/mitkBoundingObjectGroup.cpp +++ b/Modules/MitkExt/DataManagement/mitkBoundingObjectGroup.cpp @@ -1,215 +1,215 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "mitkBoundingObjectGroup.h" #include "mitkBaseProcess.h" #include #include mitk::BoundingObjectGroup::BoundingObjectGroup() :m_BoundingObjects(0), m_Counter(0), m_CSGMode(Union)// m_CSGMode(Difference) //m_CSGMode(Intersection) { - GetTimeSlicedGeometry()->Initialize(1); + GetTimeSlicedGeometry()->InitializeEvenlyTimed(1); GetGeometry(0)->SetIndexToWorldTransform(GetTimeSlicedGeometry()->GetIndexToWorldTransform()); SetVtkPolyData(NULL); } mitk::BoundingObjectGroup::~BoundingObjectGroup() { } void mitk::BoundingObjectGroup::UpdateOutputInformation() { if ( this->GetSource() ) { this->GetSource()->UpdateOutputInformation(); } // calculate global bounding box if(m_BoundingObjects.size() < 1 ) // if there is no BoundingObject, the bounding box is zero { mitk::BoundingBox::BoundsArrayType boundsArray; boundsArray.Fill(0); - GetTimeSlicedGeometry()->Initialize(1); + GetTimeSlicedGeometry()->InitializeEvenlyTimed(1); GetGeometry()->SetBounds(boundsArray); GetTimeSlicedGeometry()->UpdateInformation(); return; } // initialize container mitk::BoundingBox::PointsContainer::Pointer pointscontainer=mitk::BoundingBox::PointsContainer::New(); mitk::BoundingBox::PointIdentifier pointid=0; mitk::Point3D point; mitk::AffineTransform3D* transform = GetTimeSlicedGeometry()->GetIndexToWorldTransform(); mitk::AffineTransform3D::Pointer inverse = mitk::AffineTransform3D::New(); transform->GetInverse(inverse); // calculate a bounding box that includes all BoundingObjects // \todo probably we should do this additionally for each time-step //while (boundingObjectsIterator != boundingObjectsIteratorEnd) for(unsigned int j = 0; jGetUpdatedTimeSlicedGeometry(); unsigned char i; for(i=0; i<8; ++i) { point = inverse->TransformPoint(geometry->GetCornerPoint(i)); if(point[0]*point[0]+point[1]*point[1]+point[2]*point[2] < mitk::large) pointscontainer->InsertElement( pointid++, point); else { itkGenericOutputMacro( << "Unrealistically distant corner point encountered. Ignored. BoundingObject: " << m_BoundingObjects.at(j) ); } } } mitk::BoundingBox::Pointer boundingBox = mitk::BoundingBox::New(); boundingBox->SetPoints(pointscontainer); boundingBox->ComputeBoundingBox(); /* BoundingBox is centered around the center of all sub bounding objects */ //Point3D center = boundingBox->GetCenter(); //Point3D minimum, maximum; //minimum.Fill(0); maximum.Fill(0); //minimum += boundingBox->GetMinimum() - center; //maximum += boundingBox->GetMaximum() - center; //boundingBox->SetMinimum(minimum); //boundingBox->SetMaximum(maximum); Geometry3D* geometry3d = GetGeometry(0); geometry3d->SetIndexToWorldTransform(transform); geometry3d->SetBounds(boundingBox->GetBounds()); /* the objects position is the center of all sub bounding objects */ //geometry3d->SetOrigin(center); GetTimeSlicedGeometry()->InitializeEvenlyTimed(geometry3d, GetTimeSlicedGeometry()->GetTimeSteps()); } void mitk::BoundingObjectGroup::AddBoundingObject(mitk::BoundingObject::Pointer boundingObject) { if (boundingObject->GetPositive()) m_BoundingObjects.push_front(boundingObject); else m_BoundingObjects.push_back(boundingObject); ++m_Counter; UpdateOutputInformation(); } void mitk::BoundingObjectGroup::RemoveBoundingObject(mitk::BoundingObject::Pointer boundingObject) { std::deque::iterator it = m_BoundingObjects.begin(); for (unsigned int i=0 ; iIsInside(p) && inside; if (!inside) // shortcut, it is enough to find one object that does not contain the point i=m_BoundingObjects.size(); break; case Union: case Difference: posInside = false; negInside = false; // calculate union: each point, that is inside least one BoundingObject is considered inside the group if (m_BoundingObjects.at(i)->GetPositive()) posInside = m_BoundingObjects.at(i)->IsInside(p) || posInside; else negInside = m_BoundingObjects.at(i)->IsInside(p) || negInside; if (posInside && !negInside) inside = true; else inside = false; break; default: inside = false; // calculate union: each point, that is inside least one BoundingObject is considered inside the group inside = m_BoundingObjects.at(i)->IsInside(p) || inside; if (inside) // shortcut, it is enough to find one object that contains the point i=m_BoundingObjects.size(); break; } } return inside; } unsigned int mitk::BoundingObjectGroup::GetCount() const { return m_Counter; } bool mitk::BoundingObjectGroup::VerifyRequestedRegion() { return m_Counter > 0; } mitk::Geometry3D * mitk::BoundingObjectGroup::GetGeometry (int t) const { //if ( m_BoundingObjects == NULL ) return Superclass::GetGeometry(t); //mitk::BoundingObjectGroup::BoundingObjectContainer::ConstIterator boI = m_BoundingObjects->Begin(); //const mitk::BoundingObjectGroup::BoundingObjectContainer::ConstIterator boIEnd = m_BoundingObjects->End(); //mitk::Geometry3D* currentGeometry = NULL; //while ( boI != boIEnd ) //{ // currentGeometry = boI.Value()->GetGeometry( t ); // boI++; //} //return currentGeometry; } void mitk::BoundingObjectGroup::SetBoundingObjects(const std::deque boundingObjects) { m_BoundingObjects = boundingObjects; } std::deque mitk::BoundingObjectGroup::GetBoundingObjects() { return m_BoundingObjects; } diff --git a/Modules/MitkExt/DataManagement/mitkContour.cpp b/Modules/MitkExt/DataManagement/mitkContour.cpp index bd268949bd..13f9362b53 100644 --- a/Modules/MitkExt/DataManagement/mitkContour.cpp +++ b/Modules/MitkExt/DataManagement/mitkContour.cpp @@ -1,152 +1,152 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "mitkContour.h" mitk::Contour::Contour() : m_ContourPath (PathType::New()), m_CurrentWindow ( NULL ), m_BoundingBox (BoundingBoxType::New()), m_Vertices ( BoundingBoxType::PointsContainer::New() ), m_Closed ( true ), m_Selected ( false ), m_Width (3.0) { Superclass::InitializeTimeSlicedGeometry(); } mitk::Contour::~Contour() { } void mitk::Contour::AddVertex(mitk::Point3D newPoint) { BoundingBoxType::PointType p; p.CastFrom(newPoint); m_Vertices->InsertElement(m_Vertices->Size(), p); ContinuousIndexType idx; idx.CastFrom(newPoint); m_ContourPath->AddVertex(idx); m_BoundingBox->SetPoints(m_Vertices); Modified(); } void mitk::Contour::UpdateOutputInformation() { // \todo probably we should do this additionally for each time-step float mitkBounds[6]; if (m_Vertices->Size() == 0) { mitkBounds[0] = 0.0; mitkBounds[1] = 0.0; mitkBounds[2] = 0.0; mitkBounds[3] = 0.0; mitkBounds[4] = 0.0; mitkBounds[5] = 0.0; } else { m_BoundingBox->ComputeBoundingBox(); BoundingBoxType::BoundsArrayType tmp = m_BoundingBox->GetBounds(); mitkBounds[0] = tmp[0]; mitkBounds[1] = tmp[1]; mitkBounds[2] = tmp[2]; mitkBounds[3] = tmp[3]; mitkBounds[4] = tmp[4]; mitkBounds[5] = tmp[5]; } Geometry3D* geometry3d = GetGeometry(0); geometry3d->SetBounds(mitkBounds); GetTimeSlicedGeometry()->UpdateInformation(); } void mitk::Contour::SetRequestedRegionToLargestPossibleRegion() { } bool mitk::Contour::RequestedRegionIsOutsideOfTheBufferedRegion() { return false; } bool mitk::Contour::VerifyRequestedRegion() { return true; } void mitk::Contour::SetRequestedRegion(itk::DataObject*) { } mitk::Contour::PathType::Pointer mitk::Contour::GetContourPath() const { return m_ContourPath; } void mitk::Contour::SetCurrentWindow(vtkRenderWindow* rw) { m_CurrentWindow = rw; } vtkRenderWindow* mitk::Contour::GetCurrentWindow() const { return m_CurrentWindow; } void mitk::Contour::Initialize() { m_ContourPath = PathType::New(); m_ContourPath->Initialize(); m_BoundingBox = BoundingBoxType::New(); m_Vertices = BoundingBoxType::PointsContainer::New(); - GetTimeSlicedGeometry()->Initialize(1); + GetTimeSlicedGeometry()->InitializeEvenlyTimed(1); } unsigned int mitk::Contour::GetNumberOfPoints() const { return m_Vertices->Size(); } mitk::Contour::PointsContainerPointer mitk::Contour::GetPoints() const { return m_Vertices; } void mitk::Contour::SetPoints(mitk::Contour::PointsContainerPointer points) { m_Vertices = points; Modified(); } void mitk::Contour::PrintSelf( std::ostream& os, itk::Indent indent) const { Superclass::PrintSelf( os, indent ); os << indent << "Number of verticies: " << GetNumberOfPoints() << std::endl; mitk::Contour::PointsContainerIterator pointsIt = m_Vertices->Begin(), end = m_Vertices->End(); os << indent << "Verticies: " << std::endl; int i = 0; while ( pointsIt != end ) { os << indent << indent << i << ": " << pointsIt.Value() << std::endl; ++pointsIt; ++i; } } diff --git a/Modules/MitkExt/DataManagement/mitkContourSet.cpp b/Modules/MitkExt/DataManagement/mitkContourSet.cpp index 09fc6c19b4..810f0df9f6 100644 --- a/Modules/MitkExt/DataManagement/mitkContourSet.cpp +++ b/Modules/MitkExt/DataManagement/mitkContourSet.cpp @@ -1,122 +1,122 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "mitkContourSet.h" mitk::ContourSet::ContourSet() : m_ContourVector( ContourVectorType() ), m_NumberOfContours (0) { - GetTimeSlicedGeometry()->Initialize(1); + GetTimeSlicedGeometry()->InitializeEvenlyTimed(1); } mitk::ContourSet::~ContourSet() { } void mitk::ContourSet::AddContour(unsigned int index, mitk::Contour::Pointer contour) { m_ContourVector.insert(std::make_pair( index , contour) ); } void mitk::ContourSet::RemoveContour(unsigned long index) { m_ContourVector.erase( index ); } void mitk::ContourSet::UpdateOutputInformation() { mitk::ContourSet::ContourVectorType contourVec = GetContours(); mitk::ContourSet::ContourIterator contoursIterator = contourVec.begin(); mitk::ContourSet::ContourIterator contoursIteratorEnd = contourVec.end(); // initialize container mitk::BoundingBox::PointsContainer::Pointer pointscontainer=mitk::BoundingBox::PointsContainer::New(); mitk::BoundingBox::PointIdentifier pointid=0; mitk::Point3D point; mitk::AffineTransform3D* transform = GetTimeSlicedGeometry()->GetIndexToWorldTransform(); mitk::AffineTransform3D::Pointer inverse = mitk::AffineTransform3D::New(); transform->GetInverse(inverse); // calculate a bounding box that includes all contours // \todo probably we should do this additionally for each time-step while (contoursIterator != contoursIteratorEnd) { const Geometry3D* geometry = (*contoursIterator).second->GetUpdatedTimeSlicedGeometry(); unsigned char i; for(i=0; i<8; ++i) { point = inverse->TransformPoint(geometry->GetCornerPoint(i)); if(point[0]*point[0]+point[1]*point[1]+point[2]*point[2] < mitk::large) pointscontainer->InsertElement( pointid++, point); else { itkGenericOutputMacro( << "Unrealistically distant corner point encountered. Ignored. BoundingObject: " << (*contoursIterator).second ); } } ++contoursIterator; } mitk::BoundingBox::Pointer boundingBox = mitk::BoundingBox::New(); boundingBox->SetPoints(pointscontainer); boundingBox->ComputeBoundingBox(); Geometry3D* geometry3d = GetGeometry(0); geometry3d->SetIndexToWorldTransform(transform); geometry3d->SetBounds(boundingBox->GetBounds()); GetTimeSlicedGeometry()->InitializeEvenlyTimed(geometry3d, GetTimeSlicedGeometry()->GetTimeSteps()); } void mitk::ContourSet::SetRequestedRegionToLargestPossibleRegion() { } bool mitk::ContourSet::RequestedRegionIsOutsideOfTheBufferedRegion() { return true; } bool mitk::ContourSet::VerifyRequestedRegion() { return true; } void mitk::ContourSet::SetRequestedRegion(itk::DataObject*) { } void mitk::ContourSet::Initialize() { m_ContourVector = ContourVectorType(); - GetTimeSlicedGeometry()->Initialize(1); + GetTimeSlicedGeometry()->InitializeEvenlyTimed(1); } unsigned int mitk::ContourSet::GetNumberOfContours() { return m_ContourVector.size(); } mitk::ContourSet::ContourVectorType mitk::ContourSet::GetContours() { return m_ContourVector; } diff --git a/Modules/MitkExt/DataManagement/mitkExternAbstractTransformGeometry.cpp b/Modules/MitkExt/DataManagement/mitkExternAbstractTransformGeometry.cpp index 5106754011..da85c2e3e1 100644 --- a/Modules/MitkExt/DataManagement/mitkExternAbstractTransformGeometry.cpp +++ b/Modules/MitkExt/DataManagement/mitkExternAbstractTransformGeometry.cpp @@ -1,64 +1,62 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "mitkExternAbstractTransformGeometry.h" #include mitk::ExternAbstractTransformGeometry::ExternAbstractTransformGeometry() { } +mitk::ExternAbstractTransformGeometry::ExternAbstractTransformGeometry(const ExternAbstractTransformGeometry& other) : Superclass(other) +{ +} mitk::ExternAbstractTransformGeometry::~ExternAbstractTransformGeometry() { } void mitk::ExternAbstractTransformGeometry::SetVtkAbstractTransform(vtkAbstractTransform* aVtkAbstractTransform) { Superclass::SetVtkAbstractTransform(aVtkAbstractTransform); } void mitk::ExternAbstractTransformGeometry::SetPlane(const mitk::PlaneGeometry* aPlane) { Superclass::SetPlane(aPlane); } void mitk::ExternAbstractTransformGeometry::SetParametricBounds(const BoundingBox::BoundsArrayType& bounds) { Superclass::SetParametricBounds(bounds); //@warning affine-transforms and bounding-box should be set by specific sub-classes! SetBounds(bounds); if(m_Plane.IsNotNull()) { m_Plane->SetSizeInUnits(bounds[1]-bounds[0], bounds[3]-bounds[2]); m_Plane->SetBounds(bounds); } } mitk::AffineGeometryFrame3D::Pointer mitk::ExternAbstractTransformGeometry::Clone() const { - Self::Pointer newGeometry = Self::New(); - newGeometry->Initialize(); - InitializeGeometry(newGeometry); + Self::Pointer newGeometry = new ExternAbstractTransformGeometry(*this); + newGeometry->UnRegister(); return newGeometry.GetPointer(); } -void mitk::ExternAbstractTransformGeometry::InitializeGeometry(Self * newGeometry) const -{ - Superclass::InitializeGeometry(newGeometry); -} diff --git a/Modules/MitkExt/DataManagement/mitkExternAbstractTransformGeometry.h b/Modules/MitkExt/DataManagement/mitkExternAbstractTransformGeometry.h index fed23bb175..8577802bf5 100644 --- a/Modules/MitkExt/DataManagement/mitkExternAbstractTransformGeometry.h +++ b/Modules/MitkExt/DataManagement/mitkExternAbstractTransformGeometry.h @@ -1,71 +1,71 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef MITKEXTERNABSTRACTTRANSFORMPLANEGEOMETRY_H_HEADER_INCLUDED_C1C68A2C #define MITKEXTERNABSTRACTTRANSFORMPLANEGEOMETRY_H_HEADER_INCLUDED_C1C68A2C #include "mitkCommon.h" #include "MitkExtExports.h" #include "mitkAbstractTransformGeometry.h" namespace mitk { //##Documentation //## @brief Identical with AbstractTransformGeometry, except that //## it can be externally configured. //## //## In contrast to its superclass (AbstractTransformGeometry), this class //## provides write access to the vtkAbstractTransform and m_Plane. //## @note The PlaneGeometry is cloned, @em not linked/referenced. //## @note The bounds of the PlaneGeometry are used as the parametric bounds. //## @sa AbstractTransformGeometry //## @ingroup Geometry class MitkExt_EXPORT ExternAbstractTransformGeometry : public AbstractTransformGeometry { public: mitkClassMacro(ExternAbstractTransformGeometry, AbstractTransformGeometry); itkNewMacro(Self); //##Documentation //## @brief Set the vtkAbstractTransform (stored in m_VtkAbstractTransform) virtual void SetVtkAbstractTransform(vtkAbstractTransform* aVtkAbstractTransform); //##Documentation //## @brief Set the rectangular area that is used for transformation by //## m_VtkAbstractTransform and therewith defines the 2D manifold described by //## ExternAbstractTransformGeometry //## //## @note The bounds of the PlaneGeometry are used as the parametric bounds. //## @note The PlaneGeometry is cloned, @em not linked/referenced. virtual void SetPlane(const mitk::PlaneGeometry* aPlane); virtual void SetParametricBounds(const BoundingBox::BoundsArrayType& bounds); virtual AffineGeometryFrame3D::Pointer Clone() const; protected: ExternAbstractTransformGeometry(); + ExternAbstractTransformGeometry(const ExternAbstractTransformGeometry& other); virtual ~ExternAbstractTransformGeometry(); - void InitializeGeometry(Self * newGeometry) const; }; } // namespace mitk #endif /* MITKEXTERNABSTRACTTRANSFORMPLANEGEOMETRY_H_HEADER_INCLUDED_C1C68A2C */ diff --git a/Modules/MitkExt/DataManagement/mitkExtrudedContour.cpp b/Modules/MitkExt/DataManagement/mitkExtrudedContour.cpp index 92630ea703..1d0d6927ef 100644 --- a/Modules/MitkExt/DataManagement/mitkExtrudedContour.cpp +++ b/Modules/MitkExt/DataManagement/mitkExtrudedContour.cpp @@ -1,402 +1,402 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "mitkExtrudedContour.h" #include "mitkVector.h" #include "mitkBaseProcess.h" #include #include #include #include #include #include #include #include #include #include #include //vtkButterflySubdivisionFilter * subdivs; #include #include #include #include #include mitk::ExtrudedContour::ExtrudedContour() : m_Contour(NULL), m_ClippingGeometry(NULL), m_AutomaticVectorGeneration(false) { - GetTimeSlicedGeometry()->Initialize(1); + GetTimeSlicedGeometry()->InitializeEvenlyTimed(1); FillVector3D(m_Vector, 0.0, 0.0, 1.0); m_RightVector.Fill(0.0); m_ExtrusionFilter = vtkLinearExtrusionFilter::New(); m_ExtrusionFilter->CappingOff(); m_ExtrusionFilter->SetExtrusionTypeToVectorExtrusion(); #if ((VTK_MAJOR_VERSION > 4) || ((VTK_MAJOR_VERSION==4) && (VTK_MINOR_VERSION>=4) )) double vtkvector[3]={0,0,1}; #else float vtkvector[3]={0,0,1}; #endif // set extrusion vector m_ExtrusionFilter->SetVector(vtkvector); m_TriangleFilter = vtkTriangleFilter::New(); m_TriangleFilter->SetInput(m_ExtrusionFilter->GetOutput()); m_SubdivisionFilter = vtkLinearSubdivisionFilter::New(); m_SubdivisionFilter->SetInput(m_TriangleFilter->GetOutput()); m_SubdivisionFilter->SetNumberOfSubdivisions(4); m_ClippingBox = vtkPlanes::New(); m_ClipPolyDataFilter = vtkClipPolyData::New(); m_ClipPolyDataFilter->SetInput(m_SubdivisionFilter->GetOutput()); m_ClipPolyDataFilter->SetClipFunction(m_ClippingBox); m_ClipPolyDataFilter->InsideOutOn(); m_Polygon = vtkPolygon::New(); m_ProjectionPlane = mitk::PlaneGeometry::New(); } mitk::ExtrudedContour::~ExtrudedContour() { m_ClipPolyDataFilter->Delete(); m_ClippingBox->Delete(); m_SubdivisionFilter->Delete(); m_TriangleFilter->Delete(); m_ExtrusionFilter->Delete(); m_Polygon->Delete(); } bool mitk::ExtrudedContour::IsInside(const Point3D& worldPoint) const { #if ((VTK_MAJOR_VERSION > 4) || ((VTK_MAJOR_VERSION==4) && (VTK_MINOR_VERSION>=4) )) static double polygonNormal[3]={0.0,0.0,1.0}; #else static float polygonNormal[3]={0.0,0.0,1.0}; #endif // project point onto plane float xt[3]; itk2vtk(worldPoint, xt); xt[0] = worldPoint[0]-m_Origin[0]; xt[1] = worldPoint[1]-m_Origin[1]; xt[2] = worldPoint[2]-m_Origin[2]; float dist=xt[0]*m_Normal[0]+xt[1]*m_Normal[1]+xt[2]*m_Normal[2]; xt[0] -= dist*m_Normal[0]; xt[1] -= dist*m_Normal[1]; xt[2] -= dist*m_Normal[2]; #if ((VTK_MAJOR_VERSION > 4) || ((VTK_MAJOR_VERSION==4) && (VTK_MINOR_VERSION>=4) )) double x[3]; #else float x[3]; #endif x[0] = xt[0]*m_Right[0]+xt[1]*m_Right[1]+xt[2]*m_Right[2]; x[1] = xt[0]*m_Down[0] +xt[1]*m_Down[1] +xt[2]*m_Down[2]; x[2] = 0; #if ((VTK_MAJOR_VERSION > 4) || ((VTK_MAJOR_VERSION==4) && (VTK_MINOR_VERSION>=4) )) // determine whether it's in the selection loop and then evaluate point // in polygon only if absolutely necessary. if ( x[0] >= this->m_ProjectedContourBounds[0] && x[0] <= this->m_ProjectedContourBounds[1] && x[1] >= this->m_ProjectedContourBounds[2] && x[1] <= this->m_ProjectedContourBounds[3] && this->m_Polygon->PointInPolygon(x, m_Polygon->Points->GetNumberOfPoints(), ((vtkDoubleArray *)this->m_Polygon->Points->GetData())->GetPointer(0), (double*)const_cast(this)->m_ProjectedContourBounds, polygonNormal) == 1 ) return true; else return false; #else // determine whether it's in the selection loop and then evaluate point // in polygon only if absolutely necessary. if ( x[0] >= this->m_ProjectedContourBounds[0] && x[0] <= this->m_ProjectedContourBounds[1] && x[1] >= this->m_ProjectedContourBounds[2] && x[1] <= this->m_ProjectedContourBounds[3] && this->m_Polygon->PointInPolygon(x, m_Polygon->Points->GetNumberOfPoints(), ((vtkFloatArray *)this->m_Polygon->Points->GetData())->GetPointer(0), const_cast(this)->m_ProjectedContourBounds, polygonNormal) == 1 ) return true; else return false; #endif } mitk::ScalarType mitk::ExtrudedContour::GetVolume() { return -1.0; } void mitk::ExtrudedContour::UpdateOutputInformation() { if ( this->GetSource() ) { this->GetSource()->UpdateOutputInformation(); } if(GetMTime() > m_LastCalculateExtrusionTime) { BuildGeometry(); BuildSurface(); } //if ( ( m_CalculateBoundingBox ) && ( m_PolyDataSeries.size() > 0 ) ) // CalculateBoundingBox(); } void mitk::ExtrudedContour::BuildSurface() { if(m_Contour.IsNull()) { SetVtkPolyData(NULL); return; } // set extrusion contour vtkPolyData *polyData = vtkPolyData::New(); vtkCellArray *polys = vtkCellArray::New(); polys->InsertNextCell(m_Polygon->GetPointIds()); polyData->SetPoints(m_Polygon->GetPoints()); //float vtkpoint[3]; //unsigned int i, numPts = m_Polygon->GetNumberOfPoints(); //for(i=0; im_Polygon->Points->GetPoint(i); // pointids[i]=loopPoints->InsertNextPoint(vtkpoint); //} //polys->InsertNextCell( i, pointids ); //delete [] pointids; //polyData->SetPoints( loopPoints ); polyData->SetPolys( polys ); polys->Delete(); m_ExtrusionFilter->SetInput(polyData); polyData->Delete(); // set extrusion scale factor m_ExtrusionFilter->SetScaleFactor(GetGeometry()->GetExtentInMM(2)); SetVtkPolyData(m_SubdivisionFilter->GetOutput()); //if(m_ClippingGeometry.IsNull()) //{ // SetVtkPolyData(m_SubdivisionFilter->GetOutput()); //} //else //{ // m_ClipPolyDataFilter->SetInput(m_SubdivisionFilter->GetOutput()); // mitk::BoundingBox::BoundsArrayType bounds=m_ClippingGeometry->GetBounds(); // m_ClippingBox->SetBounds(bounds[0], bounds[1], bounds[2], bounds[3], bounds[4], bounds[5]); // m_ClippingBox->SetTransform(GetGeometry()->GetVtkTransform()); // m_ClipPolyDataFilter->SetClipFunction(m_ClippingBox); // m_ClipPolyDataFilter->SetValue(0); // SetVtkPolyData(m_ClipPolyDataFilter->GetOutput()); //} m_LastCalculateExtrusionTime.Modified(); } void mitk::ExtrudedContour::BuildGeometry() { if(m_Contour.IsNull()) return; // Initialize(1); Vector3D nullvector; nullvector.Fill(0.0); float xProj[3]; unsigned int i; unsigned int numPts = 20; //m_Contour->GetNumberOfPoints(); mitk::Contour::PathPointer path = m_Contour->GetContourPath(); mitk::Contour::PathType::InputType cstart = path->StartOfInput(); mitk::Contour::PathType::InputType cend = path->EndOfInput(); mitk::Contour::PathType::InputType cstep = (cend-cstart)/numPts; mitk::Contour::PathType::InputType ccur; // Part I: guarantee/calculate legal vectors m_Vector.Normalize(); itk2vtk(m_Vector, m_Normal); // check m_Vector if(mitk::Equal(m_Vector, nullvector) || m_AutomaticVectorGeneration) { if ( m_AutomaticVectorGeneration == false) itkWarningMacro("Extrusion vector is 0 ("<< m_Vector << "); trying to use normal of polygon"); vtkPoints *loopPoints = vtkPoints::New(); //mitk::Contour::PointsContainerIterator pointsIt = m_Contour->GetPoints()->Begin(); #if ((VTK_MAJOR_VERSION > 4) || ((VTK_MAJOR_VERSION==4) && (VTK_MINOR_VERSION>=4) )) double vtkpoint[3]; #else float vtkpoint[3]; #endif unsigned int i=0; for(i=0, ccur=cstart; iEvaluate(ccur), vtkpoint); loopPoints->InsertNextPoint(vtkpoint); } // Make sure points define a loop with a m_Normal vtkPolygon::ComputeNormal(loopPoints, m_Normal); loopPoints->Delete(); vtk2itk(m_Normal, m_Vector); if(mitk::Equal(m_Vector, nullvector)) { itkExceptionMacro("Cannot calculate normal of polygon"); } } // check m_RightVector if((mitk::Equal(m_RightVector, nullvector)) || (mitk::Equal(m_RightVector*m_Vector, 0.0)==false)) { if(mitk::Equal(m_RightVector, nullvector)) { itkDebugMacro("Right vector is 0. Calculating."); } else { itkWarningMacro("Right vector ("<InitializeStandardPlane(rightDV, downDV); // create vtkPolygon from contour and simultaneously determine 2D bounds of // contour projected on m_ProjectionPlane //mitk::Contour::PointsContainerIterator pointsIt = m_Contour->GetPoints()->Begin(); m_Polygon->Points->Reset(); m_Polygon->Points->SetNumberOfPoints(numPts); m_Polygon->PointIds->Reset(); m_Polygon->PointIds->SetNumberOfIds(numPts); mitk::Point2D pt2d; mitk::Point3D pt3d; mitk::Point2D min, max; min.Fill(ScalarTypeNumericTraits::max()); max.Fill(ScalarTypeNumericTraits::min()); xProj[2]=0.0; for(i=0, ccur=cstart; iEvaluate(ccur)); m_ProjectionPlane->Map(pt3d, pt2d); xProj[0]=pt2d[0]; if(pt2d[0]max[0]) max[0]=pt2d[0]; xProj[1]=pt2d[1]; if(pt2d[1]max[1]) max[1]=pt2d[1]; m_Polygon->Points->SetPoint(i, xProj); m_Polygon->PointIds->SetId(i, i); } // shift parametric origin to (0,0) for(i=0; i 4) || ((VTK_MAJOR_VERSION==4) && (VTK_MINOR_VERSION>=4) )) double * pt = this->m_Polygon->Points->GetPoint(i); #else float * pt = this->m_Polygon->Points->GetPoint(i); #endif pt[0]-=min[0]; pt[1]-=min[1]; itkDebugMacro( << i << ": (" << pt[0] << "," << pt[1] << "," << pt[2] << ")" ); } this->m_Polygon->GetBounds(m_ProjectedContourBounds); //m_ProjectedContourBounds[4]=-1.0; m_ProjectedContourBounds[5]=1.0; // calculate origin (except translation along the normal) and bounds // of m_ProjectionPlane: // origin is composed of the minimum x-/y-coordinates of the polygon, // bounds from the extent of the polygon, both after projecting on the plane mitk::Point3D origin; m_ProjectionPlane->Map(min, origin); ScalarType bounds[6]={0, max[0]-min[0], 0, max[1]-min[1], 0, 1}; m_ProjectionPlane->SetBounds(bounds); m_ProjectionPlane->SetOrigin(origin); // Part III: initialize geometry if(m_ClippingGeometry.IsNotNull()) { ScalarType min_dist=ScalarTypeNumericTraits::max(), max_dist=ScalarTypeNumericTraits::min(), dist; unsigned char i; for(i=0; i<8; ++i) { dist = m_ProjectionPlane->SignedDistance( m_ClippingGeometry->GetCornerPoint(i) ); if(distmax_dist) max_dist=dist; } //incorporate translation along the normal into origin origin = origin+m_Vector*min_dist; m_ProjectionPlane->SetOrigin(origin); bounds[5]=max_dist-min_dist; } else bounds[5]=20; itk2vtk(origin, m_Origin); mitk::TimeSlicedGeometry::Pointer timeGeometry = this->GetTimeSlicedGeometry(); mitk::Geometry3D::Pointer g3d = timeGeometry->GetGeometry3D( 0 ); assert( g3d.IsNotNull() ); g3d->SetBounds(bounds); g3d->SetIndexToWorldTransform(m_ProjectionPlane->GetIndexToWorldTransform()); g3d->TransferItkToVtkTransform(); timeGeometry->InitializeEvenlyTimed(g3d, 1); } unsigned long mitk::ExtrudedContour::GetMTime() const { unsigned long latestTime = Superclass::GetMTime(); if(m_Contour.IsNotNull()) { unsigned long localTime; localTime = m_Contour->GetMTime(); if(localTime > latestTime) latestTime = localTime; } return latestTime; } diff --git a/Modules/MitkExt/DataManagement/mitkOrganTypeProperty.h b/Modules/MitkExt/DataManagement/mitkOrganTypeProperty.h index ccd9d9e376..0109569fe0 100644 --- a/Modules/MitkExt/DataManagement/mitkOrganTypeProperty.h +++ b/Modules/MitkExt/DataManagement/mitkOrganTypeProperty.h @@ -1,60 +1,61 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef mitkOrganTypeProperty_h_Included #define mitkOrganTypeProperty_h_Included #include "mitkCommon.h" #include "MitkExtExports.h" #include "mitkEnumerationProperty.h" #include namespace mitk { /** \brief Enumerates all known organs :-) \sa QmitkInteractiveSegmentation \ingroup ToolManagerEtAl \ingroup DataManagement Last contributor $Author$ */ class MitkExt_EXPORT OrganTypeProperty : public EnumerationProperty { public: mitkClassMacro(OrganTypeProperty, EnumerationProperty); itkNewMacro(OrganTypeProperty); mitkNewMacro1Param(OrganTypeProperty, const IdType&); mitkNewMacro1Param(OrganTypeProperty, const std::string&); + virtual BaseProperty& operator=(const BaseProperty& other) { return Superclass::operator=(other); } protected: OrganTypeProperty(); OrganTypeProperty( const IdType& value ); OrganTypeProperty( const std::string& value ); virtual ~OrganTypeProperty(); virtual void AddEnumerationTypes(); }; } // namespace #endif diff --git a/Modules/MitkExt/Interactions/mitkAffineInteractor3D.cpp b/Modules/MitkExt/Interactions/mitkAffineInteractor3D.cpp index 4dd92ff173..9b9dfaf8ad 100644 --- a/Modules/MitkExt/Interactions/mitkAffineInteractor3D.cpp +++ b/Modules/MitkExt/Interactions/mitkAffineInteractor3D.cpp @@ -1,490 +1,493 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date: 2008-10-02 16:21:08 +0200 (Do, 02 Okt 2008) $ Version: $Revision: 13129 $ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "mitkAffineInteractor3D.h" #include "mitkPointOperation.h" #include "mitkPositionEvent.h" #include "mitkStatusBar.h" #include "mitkDataNode.h" #include "mitkInteractionConst.h" #include "mitkAction.h" #include "mitkStateEvent.h" #include "mitkOperationEvent.h" #include "mitkUndoController.h" #include "mitkStateMachineFactory.h" #include "mitkStateTransitionOperation.h" #include "mitkBaseRenderer.h" #include "mitkRenderingManager.h" #include "mitkRotationOperation.h" #include #include #include #include #include #include #include #include namespace mitk { //how precise must the user pick the point //default value AffineInteractor3D ::AffineInteractor3D(const char * type, DataNode* dataNode, int /* n */ ) : Interactor( type, dataNode ), m_Precision( 6.5 ), m_InteractionMode( INTERACTION_MODE_TRANSLATION ) { m_OriginalGeometry = Geometry3D::New(); // Initialize vector arithmetic m_ObjectNormal[0] = 0.0; m_ObjectNormal[1] = 0.0; m_ObjectNormal[2] = 1.0; } AffineInteractor3D::~AffineInteractor3D() { } void AffineInteractor3D::SetInteractionMode( unsigned int interactionMode ) { m_InteractionMode = interactionMode; } void AffineInteractor3D::SetInteractionModeToTranslation() { m_InteractionMode = INTERACTION_MODE_TRANSLATION; } void AffineInteractor3D::SetInteractionModeToRotation() { m_InteractionMode = INTERACTION_MODE_ROTATION; } unsigned int AffineInteractor3D::GetInteractionMode() const { return m_InteractionMode; } void AffineInteractor3D::SetPrecision( ScalarType precision ) { m_Precision = precision; } // Overwritten since this class can handle it better! float AffineInteractor3D ::CanHandleEvent(StateEvent const* stateEvent) const { float returnValue = 0.5; // If it is a key event that can be handled in the current state, // then return 0.5 DisplayPositionEvent const *disPosEvent = dynamic_cast (stateEvent->GetEvent()); // Key event handling: if (disPosEvent == NULL) { // Check if the current state has a transition waiting for that key event. if (this->GetCurrentState()->GetTransition(stateEvent->GetId())!=NULL) { return 0.5; } else { return 0.0; } } //on MouseMove do nothing! //if (stateEvent->GetEvent()->GetType() == Type_MouseMove) //{ // return 0.0; //} //if the event can be understood and if there is a transition waiting for that event if (this->GetCurrentState()->GetTransition(stateEvent->GetId())!=NULL) { returnValue = 0.5;//it can be understood } //int timeStep = disPosEvent->GetSender()->GetTimeStep(); //CurveModel *curveModel = dynamic_cast( // m_DataNode->GetData() ); //if ( curveModel != NULL ) //{ // // Get the Geometry2D of the window the user interacts with (for 2D point // // projection) // BaseRenderer *renderer = stateEvent->GetEvent()->GetSender(); // const Geometry2D *projectionPlane = renderer->GetCurrentWorldGeometry2D(); // // For reading on the points, Ids etc // //CurveModel::PointSetType *pointSet = curveModel->GetPointSet( timeStep ); // //if ( pointSet == NULL ) // //{ // // return 0.0; // //} //} return returnValue; } bool AffineInteractor3D ::ExecuteAction( Action *action, StateEvent const *stateEvent ) { bool ok = false; // Get data object BaseData *data = m_DataNode->GetData(); if ( data == NULL ) { MITK_ERROR << "No data object present!"; return ok; } // Get Event and extract renderer const Event *event = stateEvent->GetEvent(); BaseRenderer *renderer = NULL; vtkRenderWindow *renderWindow = NULL; vtkRenderWindowInteractor *renderWindowInteractor = NULL; vtkRenderer *currentVtkRenderer = NULL; vtkCamera *camera = NULL; if ( event != NULL ) { renderer = event->GetSender(); if ( renderer != NULL ) { renderWindow = renderer->GetRenderWindow(); if ( renderWindow != NULL ) { renderWindowInteractor = renderWindow->GetInteractor(); if ( renderWindowInteractor != NULL ) { currentVtkRenderer = renderWindowInteractor ->GetInteractorStyle()->GetCurrentRenderer(); if ( currentVtkRenderer != NULL ) { camera = currentVtkRenderer->GetActiveCamera(); } } } } } // Check if we have a DisplayPositionEvent const DisplayPositionEvent *dpe = dynamic_cast< const DisplayPositionEvent * >( stateEvent->GetEvent() ); if ( dpe != NULL ) { m_CurrentPickedPoint = dpe->GetWorldPosition(); m_CurrentPickedDisplayPoint = dpe->GetDisplayPosition(); } // Get the timestep to also support 3D+t int timeStep = 0; ScalarType timeInMS = 0.0; if ( renderer != NULL ) { timeStep = renderer->GetTimeStep( data ); timeInMS = renderer->GetTime(); } // If data is an mitk::Surface, extract it Surface *surface = dynamic_cast< Surface * >( data ); vtkPolyData *polyData = NULL; if ( surface != NULL ) { polyData = surface->GetVtkPolyData( timeStep ); // Extract surface normal from surface (if existent, otherwise use default) vtkPointData *pointData = polyData->GetPointData(); if ( pointData != NULL ) { vtkDataArray *normal = polyData->GetPointData()->GetVectors( "planeNormal" ); if ( normal != NULL ) { m_ObjectNormal[0] = normal->GetComponent( 0, 0 ); m_ObjectNormal[1] = normal->GetComponent( 0, 1 ); m_ObjectNormal[2] = normal->GetComponent( 0, 2 ); } } } // Get geometry object m_Geometry = data->GetGeometry( timeStep ); // Make sure that the data (if time-resolved) has enough entries; // if not, create the required extra ones (empty) data->Expand( timeStep+1 ); switch (action->GetActionId()) { case AcDONOTHING: ok = true; break; case AcCHECKOBJECT: { // Re-enable VTK interactor (may have been disabled previously) if ( renderWindowInteractor != NULL ) { renderWindowInteractor->Enable(); } // Check if we have a DisplayPositionEvent const DisplayPositionEvent *dpe = dynamic_cast< const DisplayPositionEvent * >( stateEvent->GetEvent() ); if ( dpe == NULL ) { ok = true; break; } // Check if an object is present at the current mouse position DataNode *pickedNode = dpe->GetPickedObjectNode(); StateEvent *newStateEvent; if ( pickedNode == m_DataNode ) { // Yes: object will be selected newStateEvent = new StateEvent( EIDYES ); } else { // No: back to start state newStateEvent = new StateEvent( EIDNO ); } this->HandleEvent( newStateEvent ); ok = true; break; } case AcDESELECTOBJECT: { // Color object white m_DataNode->SetColor( 1.0, 1.0, 1.0 ); RenderingManager::GetInstance()->RequestUpdateAll(); // Colorize surface / wireframe as inactive this->ColorizeSurface( polyData, m_CurrentPickedPoint, -1.0 ); ok = true; break; } case AcSELECTPICKEDOBJECT: { // Color object red m_DataNode->SetColor( 1.0, 0.0, 0.0 ); RenderingManager::GetInstance()->RequestUpdateAll(); // Colorize surface / wireframe dependend on distance from picked point this->ColorizeSurface( polyData, m_CurrentPickedPoint, 0.0 ); ok = true; break; } case AcINITMOVE: { // Disable VTK interactor until MITK interaction has been completed if ( renderWindowInteractor != NULL ) { renderWindowInteractor->Disable(); } // Check if we have a DisplayPositionEvent const DisplayPositionEvent *dpe = dynamic_cast< const DisplayPositionEvent * >( stateEvent->GetEvent() ); if ( dpe == NULL ) { ok = true; break; } //DataNode *pickedNode = dpe->GetPickedObjectNode(); m_InitialPickedPoint = m_CurrentPickedPoint; m_InitialPickedDisplayPoint = m_CurrentPickedDisplayPoint; if ( currentVtkRenderer != NULL ) { vtkInteractorObserver::ComputeDisplayToWorld( currentVtkRenderer, m_InitialPickedDisplayPoint[0], m_InitialPickedDisplayPoint[1], 0.0, //m_InitialInteractionPickedPoint[2], m_InitialPickedPointWorld ); } // Make deep copy of current Geometry3D of the plane data->UpdateOutputInformation(); // make sure that the Geometry is up-to-date m_OriginalGeometry = static_cast< Geometry3D * >( data->GetGeometry( timeStep )->Clone().GetPointer() ); ok = true; break; } case AcMOVE: { // Check if we have a DisplayPositionEvent const DisplayPositionEvent *dpe = dynamic_cast< const DisplayPositionEvent * >( stateEvent->GetEvent() ); if ( dpe == NULL ) { ok = true; break; } if ( currentVtkRenderer != NULL ) { vtkInteractorObserver::ComputeDisplayToWorld( currentVtkRenderer, m_CurrentPickedDisplayPoint[0], m_CurrentPickedDisplayPoint[1], 0.0, //m_InitialInteractionPickedPoint[2], m_CurrentPickedPointWorld ); } Vector3D interactionMove; interactionMove[0] = m_CurrentPickedPointWorld[0] - m_InitialPickedPointWorld[0]; interactionMove[1] = m_CurrentPickedPointWorld[1] - m_InitialPickedPointWorld[1]; interactionMove[2] = m_CurrentPickedPointWorld[2] - m_InitialPickedPointWorld[2]; if ( m_InteractionMode == INTERACTION_MODE_TRANSLATION ) { Point3D origin = m_OriginalGeometry->GetOrigin(); Vector3D transformedObjectNormal; data->GetGeometry( timeStep )->IndexToWorld( m_ObjectNormal, transformedObjectNormal ); data->GetGeometry( timeStep )->SetOrigin( origin + transformedObjectNormal * (interactionMove * transformedObjectNormal) ); } else if ( m_InteractionMode == INTERACTION_MODE_ROTATION ) { if ( camera ) { vtkFloatingPointType vpn[3]; camera->GetViewPlaneNormal( vpn ); Vector3D viewPlaneNormal; viewPlaneNormal[0] = vpn[0]; viewPlaneNormal[1] = vpn[1]; viewPlaneNormal[2] = vpn[2]; Vector3D rotationAxis = itk::CrossProduct( viewPlaneNormal, interactionMove ); rotationAxis.Normalize(); int *size = currentVtkRenderer->GetSize(); double l2 = (m_CurrentPickedDisplayPoint[0] - m_InitialPickedDisplayPoint[0]) * (m_CurrentPickedDisplayPoint[0] - m_InitialPickedDisplayPoint[0]) + (m_CurrentPickedDisplayPoint[1] - m_InitialPickedDisplayPoint[1]) * (m_CurrentPickedDisplayPoint[1] - m_InitialPickedDisplayPoint[1]); double rotationAngle = 360.0 * sqrt(l2/(size[0]*size[0]+size[1]*size[1])); // Use center of data bounding box as center of rotation Point3D rotationCenter = m_OriginalGeometry->GetCenter();; // Reset current Geometry3D to original state (pre-interaction) and // apply rotation RotationOperation op( OpROTATE, rotationCenter, rotationAxis, rotationAngle ); Geometry3D::Pointer newGeometry = static_cast< Geometry3D * >( m_OriginalGeometry->Clone().GetPointer() ); newGeometry->ExecuteOperation( &op ); - data->SetGeometry( newGeometry, timeStep ); - + mitk::TimeSlicedGeometry::Pointer timeSlicedGeometry = data->GetTimeSlicedGeometry(); + if (timeSlicedGeometry.IsNotNull()) + { + timeSlicedGeometry->SetGeometry3D( newGeometry, timeStep ); + } } } RenderingManager::GetInstance()->RequestUpdateAll(); ok = true; break; } default: return Superclass::ExecuteAction( action, stateEvent ); } return ok; } bool AffineInteractor3D::ColorizeSurface( vtkPolyData *polyData, const Point3D & /*pickedPoint*/, double scalar ) { if ( polyData == NULL ) { return false; } //vtkPoints *points = polyData->GetPoints(); vtkPointData *pointData = polyData->GetPointData(); if ( pointData == NULL ) { return false; } vtkDataArray *scalars = pointData->GetScalars(); if ( scalars == NULL ) { return false; } for ( unsigned int i = 0; i < pointData->GetNumberOfTuples(); ++i ) { scalars->SetComponent( i, 0, scalar ); } polyData->Modified(); pointData->Update(); return true; } } // namespace diff --git a/Modules/MitkExt/Rendering/mitkContourVtkMapper3D.cpp b/Modules/MitkExt/Rendering/mitkContourVtkMapper3D.cpp index 555ada0468..8e7081a0f4 100644 --- a/Modules/MitkExt/Rendering/mitkContourVtkMapper3D.cpp +++ b/Modules/MitkExt/Rendering/mitkContourVtkMapper3D.cpp @@ -1,181 +1,181 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "mitkContourVtkMapper3D.h" #include "mitkDataNode.h" #include "mitkProperties.h" #include "mitkColorProperty.h" #include "mitkVtkPropRenderer.h" #include "mitkContour.h" #include #include #include #pragma GCC diagnostic ignored "-Wstrict-aliasing" #include #pragma GCC diagnostic warning "-Wstrict-aliasing" #include #include #include #include #include #include #include #include #include #include mitk::ContourVtkMapper3D::ContourVtkMapper3D() { m_VtkPolyDataMapper = vtkPolyDataMapper::New(); m_VtkPointList = vtkAppendPolyData::New(); m_Actor = vtkActor::New(); m_Actor->SetMapper(m_VtkPolyDataMapper); m_TubeFilter = vtkTubeFilter::New(); } mitk::ContourVtkMapper3D::~ContourVtkMapper3D() { if(m_VtkPolyDataMapper) m_VtkPolyDataMapper->Delete(); if(m_TubeFilter) m_TubeFilter->Delete(); if(m_VtkPointList) m_VtkPointList->Delete(); if(m_Contour) m_Contour->Delete(); if(m_Actor) m_Actor->Delete(); } vtkProp* mitk::ContourVtkMapper3D::GetVtkProp(mitk::BaseRenderer* /*renderer*/) { return m_Actor; } -void mitk::ContourVtkMapper3D::GenerateData(mitk::BaseRenderer* renderer) +void mitk::ContourVtkMapper3D::GenerateDataForRenderer(mitk::BaseRenderer* renderer) { if ( IsVisible(renderer)==false ) { m_Actor->VisibilityOff(); return; } m_Actor->VisibilityOn(); m_Contour = vtkPolyData::New(); mitk::Contour::Pointer input = const_cast(this->GetInput()); bool makeContour = true; if ( makeContour ) { vtkSmartPointer points = vtkSmartPointer::New(); vtkSmartPointer lines = vtkSmartPointer::New(); int numPts=input->GetNumberOfPoints(); if ( numPts > 200000 ) numPts = 200000; mitk::Contour::PathPointer path = input->GetContourPath(); mitk::Contour::PathType::InputType cstart = path->StartOfInput(); mitk::Contour::PathType::InputType cend = path->EndOfInput(); mitk::Contour::PathType::InputType cstep = (cend-cstart+1)/numPts; mitk::Contour::PathType::InputType ccur; vtkIdType ptIndex = 0; vtkIdType lastPointIndex = 0; mitk::Contour::PointsContainerPointer contourPoints = input->GetPoints(); mitk::Contour::PointsContainerIterator pointsIt = contourPoints->Begin(); vtkFloatingPointType vtkpoint[3]; int i; float pointSize = 2; this->GetDataNode()->GetFloatProperty("spheres size", pointSize); bool showPoints = true; this->GetDataNode()->GetBoolProperty("show points", showPoints); if ( showPoints ) { m_VtkPointList = vtkAppendPolyData::New(); } for ( i=0, ccur=cstart; iEvaluate(ccur), vtkpoint); points->InsertPoint(ptIndex, vtkpoint); if ( ptIndex > 0 ) { int cell[2] = {ptIndex-1,ptIndex}; lines->InsertNextCell((vtkIdType)2,(vtkIdType*) cell); } lastPointIndex = ptIndex; ++ptIndex; if ( showPoints ) { vtkSmartPointer sphere = vtkSmartPointer::New(); sphere->SetRadius(pointSize); sphere->SetCenter(vtkpoint); m_VtkPointList->AddInput(sphere->GetOutput()); sphere->Update(); } } if ( input->GetClosed() ) { int cell[2] = {lastPointIndex,0}; lines->InsertNextCell((vtkIdType)2,(vtkIdType*) cell); } m_Contour->SetPoints(points); m_Contour->SetLines(lines); m_Contour->Update(); m_TubeFilter->SetInput(m_Contour); m_TubeFilter->SetRadius(pointSize / 2.0f); m_TubeFilter->SetNumberOfSides(8); m_TubeFilter->Update(); if ( showPoints ) { m_VtkPointList->AddInput(m_TubeFilter->GetOutput()); m_VtkPolyDataMapper->SetInput(m_VtkPointList->GetOutput()); } else { m_VtkPolyDataMapper->SetInput(m_TubeFilter->GetOutput()); } vtkFloatingPointType rgba[4]={0.0f,1.0f,0.0f,0.6f}; m_Actor->GetProperty()->SetColor(rgba); m_Actor->SetMapper(m_VtkPolyDataMapper); } SetVtkMapperImmediateModeRendering(m_VtkPolyDataMapper); } const mitk::Contour* mitk::ContourVtkMapper3D::GetInput() { return static_cast ( GetData() ); } diff --git a/Modules/MitkExt/Rendering/mitkContourVtkMapper3D.h b/Modules/MitkExt/Rendering/mitkContourVtkMapper3D.h index e439511b88..cef2d7200e 100644 --- a/Modules/MitkExt/Rendering/mitkContourVtkMapper3D.h +++ b/Modules/MitkExt/Rendering/mitkContourVtkMapper3D.h @@ -1,69 +1,69 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef MITK_CONTOUR_VTK_MAPPER_3D_H #define MITK_CONTOUR_VTK_MAPPER_3D_H #include "MitkExtExports.h" #include "mitkVtkMapper3D.h" #include #include class vtkPolyDataMapper; class vtkAppendPolyData; class vtkActor; class vtkTubeFilter; namespace mitk { class BaseRenderer; class Contour; /** @brief Vtk-based mapper for mitk::Contour @ingroup Mapper */ class MitkExt_EXPORT ContourVtkMapper3D : public VtkMapper3D { public: mitkClassMacro(ContourVtkMapper3D, VtkMapper3D); itkNewMacro(Self); virtual const mitk::Contour* GetInput(); virtual vtkProp* GetVtkProp(mitk::BaseRenderer* renderer); protected: ContourVtkMapper3D(); virtual ~ContourVtkMapper3D(); - virtual void GenerateData(mitk::BaseRenderer* renderer); + virtual void GenerateDataForRenderer(mitk::BaseRenderer* renderer); vtkSmartPointer m_VtkPolyDataMapper; vtkSmartPointer m_TubeFilter; vtkSmartPointer m_VtkPointList; vtkSmartPointer m_Contour; vtkSmartPointer m_Actor; }; } // namespace mitk #endif // MITK_CONTOUR_VTK_MAPPER_3D_H diff --git a/Modules/MitkExt/Rendering/mitkGPUVolumeMapper3D.cpp b/Modules/MitkExt/Rendering/mitkGPUVolumeMapper3D.cpp index cd94557cae..3d51ec5566 100644 --- a/Modules/MitkExt/Rendering/mitkGPUVolumeMapper3D.cpp +++ b/Modules/MitkExt/Rendering/mitkGPUVolumeMapper3D.cpp @@ -1,711 +1,711 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date: 2009-06-18 15:59:04 +0200 (Thu, 18 Jun 2009) $ Version: $Revision: 17786 $ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #define GPU_INFO MITK_INFO("mapper.vr") #define GPU_WARN MITK_WARN("mapper.vr") #define GPU_ERROR MITK_ERROR("mapper.vr") #include "mitkGPUVolumeMapper3D.h" #include "mitkDataNode.h" #include "mitkProperties.h" #include "mitkLevelWindow.h" #include "mitkColorProperty.h" #include "mitkLevelWindowProperty.h" #include "mitkLookupTableProperty.h" #include "mitkTransferFunctionProperty.h" #include "mitkTransferFunctionInitializer.h" #include "mitkColorProperty.h" #include "mitkVtkPropRenderer.h" #include "mitkRenderingManager.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Only with VTK 5.6 or above #if ((VTK_MAJOR_VERSION > 5) || ((VTK_MAJOR_VERSION==5) && (VTK_MINOR_VERSION>=6) )) #include "vtkMitkGPUVolumeRayCastMapper.h" #endif #include "vtkMitkOpenGLGPUVolumeRayCastMapper.h" #include "vtkMitkOpenGLVolumeTextureMapper3D.h" const mitk::Image* mitk::GPUVolumeMapper3D::GetInput() { return static_cast ( GetData() ); } void mitk::GPUVolumeMapper3D::MitkRenderVolumetricGeometry(mitk::BaseRenderer* renderer) { LocalStorage *ls = m_LSH.GetLocalStorage(renderer); VtkMapper3D::MitkRenderVolumetricGeometry(renderer); if(ls->m_gpuInitialized) ls->m_MapperGPU->UpdateMTime(); } bool mitk::GPUVolumeMapper3D::InitGPU(mitk::BaseRenderer* renderer) { LocalStorage *ls = m_LSH.GetLocalStorage(renderer); if(ls->m_gpuInitialized) return ls->m_gpuSupported; GPU_INFO << "initializing gpu-slicing-vr (vtkMitkOpenGLVolumeTextureMapper3D)"; ls->m_MapperGPU = vtkMitkOpenGLVolumeTextureMapper3D::New(); ls->m_MapperGPU->SetUseCompressedTexture(false); ls->m_MapperGPU->SetSampleDistance(1.0); ls->m_VolumePropertyGPU = vtkVolumeProperty::New(); ls->m_VolumePropertyGPU->ShadeOn(); ls->m_VolumePropertyGPU->SetAmbient (0.25f); //0.05f ls->m_VolumePropertyGPU->SetDiffuse (0.50f); //0.45f ls->m_VolumePropertyGPU->SetSpecular(0.40f); //0.50f ls->m_VolumePropertyGPU->SetSpecularPower(16.0f); ls->m_VolumePropertyGPU->SetInterpolationTypeToLinear(); ls->m_VolumeGPU = vtkVolume::New(); ls->m_VolumeGPU->SetMapper( ls->m_MapperGPU ); ls->m_VolumeGPU->SetProperty( ls->m_VolumePropertyGPU ); ls->m_VolumeGPU->VisibilityOn(); ls->m_MapperGPU->SetInput( this->m_UnitSpacingImageFilter->GetOutput() ); ls->m_gpuSupported = ls->m_MapperGPU->IsRenderSupported(renderer->GetVtkRenderer(),ls->m_VolumePropertyGPU); ls->m_gpuInitialized = true; return ls->m_gpuSupported; } void mitk::GPUVolumeMapper3D::InitCPU(mitk::BaseRenderer* renderer) { LocalStorage *ls = m_LSH.GetLocalStorage(renderer); if(ls->m_cpuInitialized) return; int numThreads = itk::MultiThreader::GetGlobalDefaultNumberOfThreads(); GPU_INFO << "initializing cpu-raycast-vr (vtkFixedPointVolumeRayCastMapper) (" << numThreads << " threads)"; ls->m_MapperCPU = vtkFixedPointVolumeRayCastMapper::New(); ls->m_MapperCPU->SetSampleDistance(1.0); // ls->m_MapperCPU->LockSampleDistanceToInputSpacingOn(); ls->m_MapperCPU->SetImageSampleDistance(1.0); ls->m_MapperCPU->IntermixIntersectingGeometryOn(); ls->m_MapperCPU->SetAutoAdjustSampleDistances(0); ls->m_MapperCPU->SetNumberOfThreads( numThreads ); ls->m_VolumePropertyCPU = vtkVolumeProperty::New(); ls->m_VolumePropertyCPU->ShadeOn(); ls->m_VolumePropertyCPU->SetAmbient (0.10f); //0.05f ls->m_VolumePropertyCPU->SetDiffuse (0.50f); //0.45f ls->m_VolumePropertyCPU->SetSpecular(0.40f); //0.50f ls->m_VolumePropertyCPU->SetSpecularPower(16.0f); ls->m_VolumePropertyCPU->SetInterpolationTypeToLinear(); ls->m_VolumeCPU = vtkVolume::New(); ls->m_VolumeCPU->SetMapper( ls->m_MapperCPU ); ls->m_VolumeCPU->SetProperty( ls->m_VolumePropertyCPU ); ls->m_VolumeCPU->VisibilityOn(); ls->m_MapperCPU->SetInput( m_UnitSpacingImageFilter->GetOutput() );//m_Resampler->GetOutput()); ls->m_cpuInitialized=true; } void mitk::GPUVolumeMapper3D::DeinitGPU(mitk::BaseRenderer* renderer) { LocalStorage *ls = m_LSH.GetLocalStorage(renderer); if(ls->m_gpuInitialized) { GPU_INFO << "deinitializing gpu-slicing-vr"; ls->m_VolumeGPU->Delete(); ls->m_MapperGPU->Delete(); ls->m_VolumePropertyGPU->Delete(); ls->m_gpuInitialized=false; } } void mitk::GPUVolumeMapper3D::DeinitCPU(mitk::BaseRenderer* renderer) { LocalStorage *ls = m_LSH.GetLocalStorage(renderer); if(!ls->m_cpuInitialized) return; GPU_INFO << "deinitializing cpu-raycast-vr"; ls->m_VolumeCPU->Delete(); ls->m_MapperCPU->Delete(); ls->m_VolumePropertyCPU->Delete(); ls->m_cpuInitialized=false; } mitk::GPUVolumeMapper3D::GPUVolumeMapper3D() { m_VolumeNULL=0; m_commonInitialized=false; } mitk::GPUVolumeMapper3D::~GPUVolumeMapper3D() { DeinitCommon(); if(m_VolumeNULL) m_VolumeNULL->Delete(); } void mitk::GPUVolumeMapper3D::InitCommon() { if(m_commonInitialized) return; m_UnitSpacingImageFilter = vtkImageChangeInformation::New(); m_UnitSpacingImageFilter->SetOutputSpacing( 1.0, 1.0, 1.0 ); CreateDefaultTransferFunctions(); m_commonInitialized=true; } void mitk::GPUVolumeMapper3D::DeinitCommon() { if(!m_commonInitialized) return; m_UnitSpacingImageFilter->Delete(); m_DefaultColorTransferFunction->Delete(); m_DefaultOpacityTransferFunction->Delete(); m_DefaultGradientTransferFunction->Delete(); m_BinaryColorTransferFunction->Delete(); m_BinaryOpacityTransferFunction->Delete(); m_BinaryGradientTransferFunction->Delete(); m_commonInitialized=false; } bool mitk::GPUVolumeMapper3D::IsRenderable(mitk::BaseRenderer* renderer) { if(!IsVisible(renderer)) return false; if(!GetDataNode()) return false; bool value = false; if(!GetDataNode()->GetBoolProperty("volumerendering",value,renderer)) return false; if(!value) return false; mitk::Image *input = const_cast< mitk::Image * >( this->GetInput() ); if ( !input || !input->IsInitialized() ) return false; vtkImageData *inputData = input->GetVtkImageData( this->GetTimestep() ); if(inputData==NULL) return false; return true; } void mitk::GPUVolumeMapper3D::InitVtkMapper(mitk::BaseRenderer* renderer) { // Only with VTK 5.6 or above #if ((VTK_MAJOR_VERSION > 5) || ((VTK_MAJOR_VERSION==5) && (VTK_MINOR_VERSION>=6) )) if(IsRAYEnabled(renderer)) { DeinitCPU(renderer); DeinitGPU(renderer); if(!InitRAY(renderer)) { GPU_WARN << "hardware renderer can't initialize ... falling back to software renderer"; goto fallback; } } else #endif if(IsGPUEnabled(renderer)) { DeinitCPU(renderer); // Only with VTK 5.6 or above #if ((VTK_MAJOR_VERSION > 5) || ((VTK_MAJOR_VERSION==5) && (VTK_MINOR_VERSION>=6) )) DeinitRAY(renderer); #endif if(!InitGPU(renderer)) { GPU_WARN << "hardware renderer can't initialize ... falling back to software renderer"; goto fallback; } } else { fallback: DeinitGPU(renderer); // Only with VTK 5.6 or above #if ((VTK_MAJOR_VERSION > 5) || ((VTK_MAJOR_VERSION==5) && (VTK_MINOR_VERSION>=6) )) DeinitRAY(renderer); #endif InitCPU(renderer); } } vtkProp *mitk::GPUVolumeMapper3D::GetVtkProp(mitk::BaseRenderer *renderer) { if(!IsRenderable(renderer)) { if(!m_VolumeNULL) { m_VolumeNULL = vtkVolume::New(); m_VolumeNULL->VisibilityOff(); } return m_VolumeNULL; } InitCommon(); InitVtkMapper( renderer ); LocalStorage *ls = m_LSH.GetLocalStorage(renderer); // Only with VTK 5.6 or above #if ((VTK_MAJOR_VERSION > 5) || ((VTK_MAJOR_VERSION==5) && (VTK_MINOR_VERSION>=6) )) if(ls->m_rayInitialized) return ls->m_VolumeRAY; #endif if(ls->m_gpuInitialized) return ls->m_VolumeGPU; return ls->m_VolumeCPU; } -void mitk::GPUVolumeMapper3D::GenerateData( mitk::BaseRenderer *renderer ) +void mitk::GPUVolumeMapper3D::GenerateDataForRenderer( mitk::BaseRenderer *renderer ) { if(!IsRenderable(renderer)) return; InitCommon(); InitVtkMapper( renderer ); mitk::Image *input = const_cast< mitk::Image * >( this->GetInput() ); vtkImageData *inputData = input->GetVtkImageData( this->GetTimestep() ); m_UnitSpacingImageFilter->SetInput( inputData ); LocalStorage *ls = m_LSH.GetLocalStorage(renderer); // Only with VTK 5.6 or above #if ((VTK_MAJOR_VERSION > 5) || ((VTK_MAJOR_VERSION==5) && (VTK_MINOR_VERSION>=6) )) if(ls->m_rayInitialized) { GenerateDataRAY(renderer); } else #endif if(ls->m_gpuInitialized) { GenerateDataGPU(renderer); } else { GenerateDataCPU(renderer); } // UpdateTransferFunctions UpdateTransferFunctions( renderer ); } void mitk::GPUVolumeMapper3D::GenerateDataGPU( mitk::BaseRenderer *renderer ) { LocalStorage *ls = m_LSH.GetLocalStorage(renderer); bool useCompression = false; GetDataNode()->GetBoolProperty("volumerendering.gpu.usetexturecompression",useCompression,renderer); ls->m_MapperGPU->SetUseCompressedTexture(useCompression); if( IsLODEnabled(renderer) && mitk::RenderingManager::GetInstance()->GetNextLOD( renderer ) == 0 ) ls->m_MapperGPU->SetSampleDistance(2.0); else ls->m_MapperGPU->SetSampleDistance(1.0); // Updating shadings { float value=0; if(GetDataNode()->GetFloatProperty("volumerendering.gpu.ambient",value,renderer)) ls->m_VolumePropertyGPU->SetAmbient(value); if(GetDataNode()->GetFloatProperty("volumerendering.gpu.diffuse",value,renderer)) ls->m_VolumePropertyGPU->SetDiffuse(value); if(GetDataNode()->GetFloatProperty("volumerendering.gpu.specular",value,renderer)) ls->m_VolumePropertyGPU->SetSpecular(value); if(GetDataNode()->GetFloatProperty("volumerendering.gpu.specular.power",value,renderer)) ls->m_VolumePropertyGPU->SetSpecularPower(value); } } void mitk::GPUVolumeMapper3D::GenerateDataCPU( mitk::BaseRenderer *renderer ) { LocalStorage *ls = m_LSH.GetLocalStorage(renderer); int nextLod = mitk::RenderingManager::GetInstance()->GetNextLOD( renderer ); if( IsLODEnabled(renderer) && nextLod == 0 ) { ls->m_MapperCPU->SetImageSampleDistance(3.5); ls->m_MapperCPU->SetSampleDistance(1.25); ls->m_VolumePropertyCPU->SetInterpolationTypeToNearest(); } else { ls->m_MapperCPU->SetImageSampleDistance(1.0); ls->m_MapperCPU->SetSampleDistance(1.0); ls->m_VolumePropertyCPU->SetInterpolationTypeToLinear(); } // Check raycasting mode if(IsMIPEnabled(renderer)) ls->m_MapperCPU->SetBlendModeToMaximumIntensity(); else ls->m_MapperCPU->SetBlendModeToComposite(); // Updating shadings { float value=0; if(GetDataNode()->GetFloatProperty("volumerendering.cpu.ambient",value,renderer)) ls->m_VolumePropertyCPU->SetAmbient(value); if(GetDataNode()->GetFloatProperty("volumerendering.cpu.diffuse",value,renderer)) ls->m_VolumePropertyCPU->SetDiffuse(value); if(GetDataNode()->GetFloatProperty("volumerendering.cpu.specular",value,renderer)) ls->m_VolumePropertyCPU->SetSpecular(value); if(GetDataNode()->GetFloatProperty("volumerendering.cpu.specular.power",value,renderer)) ls->m_VolumePropertyCPU->SetSpecularPower(value); } } void mitk::GPUVolumeMapper3D::CreateDefaultTransferFunctions() { m_DefaultOpacityTransferFunction = vtkPiecewiseFunction::New(); m_DefaultOpacityTransferFunction->AddPoint( 0.0, 0.0 ); m_DefaultOpacityTransferFunction->AddPoint( 255.0, 0.8 ); m_DefaultOpacityTransferFunction->ClampingOn(); m_DefaultGradientTransferFunction = vtkPiecewiseFunction::New(); m_DefaultGradientTransferFunction->AddPoint( 0.0, 0.0 ); m_DefaultGradientTransferFunction->AddPoint( 255.0, 0.8 ); m_DefaultGradientTransferFunction->ClampingOn(); m_DefaultColorTransferFunction = vtkColorTransferFunction::New(); m_DefaultColorTransferFunction->AddRGBPoint( 0.0, 0.0, 0.0, 0.0 ); m_DefaultColorTransferFunction->AddRGBPoint( 127.5, 1, 1, 0.0 ); m_DefaultColorTransferFunction->AddRGBPoint( 255.0, 0.8, 0.2, 0 ); m_DefaultColorTransferFunction->ClampingOn(); m_BinaryOpacityTransferFunction = vtkPiecewiseFunction::New(); m_BinaryOpacityTransferFunction->AddPoint( 0, 0.0 ); m_BinaryOpacityTransferFunction->AddPoint( 1, 1.0 ); m_BinaryGradientTransferFunction = vtkPiecewiseFunction::New(); m_BinaryGradientTransferFunction->AddPoint( 0.0, 1.0 ); m_BinaryColorTransferFunction = vtkColorTransferFunction::New(); } void mitk::GPUVolumeMapper3D::UpdateTransferFunctions( mitk::BaseRenderer * renderer ) { LocalStorage *ls = m_LSH.GetLocalStorage(renderer); vtkPiecewiseFunction *opacityTransferFunction = m_DefaultOpacityTransferFunction; vtkPiecewiseFunction *gradientTransferFunction = m_DefaultGradientTransferFunction; vtkColorTransferFunction *colorTransferFunction = m_DefaultColorTransferFunction; bool isBinary = false; GetDataNode()->GetBoolProperty("binary", isBinary, renderer); if(isBinary) { opacityTransferFunction = m_BinaryOpacityTransferFunction; gradientTransferFunction = m_BinaryGradientTransferFunction; colorTransferFunction = m_BinaryColorTransferFunction; colorTransferFunction->RemoveAllPoints(); float rgb[3]; if( !GetDataNode()->GetColor( rgb,renderer ) ) rgb[0]=rgb[1]=rgb[2]=1; colorTransferFunction->AddRGBPoint( 0,rgb[0],rgb[1],rgb[2] ); colorTransferFunction->Modified(); } else { mitk::TransferFunctionProperty *transferFunctionProp = dynamic_cast(this->GetDataNode()->GetProperty("TransferFunction",renderer)); if( transferFunctionProp ) { opacityTransferFunction = transferFunctionProp->GetValue()->GetScalarOpacityFunction(); gradientTransferFunction = transferFunctionProp->GetValue()->GetGradientOpacityFunction(); colorTransferFunction = transferFunctionProp->GetValue()->GetColorTransferFunction(); } } if(ls->m_gpuInitialized) { ls->m_VolumePropertyGPU->SetColor( colorTransferFunction ); ls->m_VolumePropertyGPU->SetScalarOpacity( opacityTransferFunction ); ls->m_VolumePropertyGPU->SetGradientOpacity( gradientTransferFunction ); } // Only with VTK 5.6 or above #if ((VTK_MAJOR_VERSION > 5) || ((VTK_MAJOR_VERSION==5) && (VTK_MINOR_VERSION>=6) )) if(ls->m_rayInitialized) { ls->m_VolumePropertyRAY->SetColor( colorTransferFunction ); ls->m_VolumePropertyRAY->SetScalarOpacity( opacityTransferFunction ); ls->m_VolumePropertyRAY->SetGradientOpacity( gradientTransferFunction ); } #endif if(ls->m_cpuInitialized) { ls->m_VolumePropertyCPU->SetColor( colorTransferFunction ); ls->m_VolumePropertyCPU->SetScalarOpacity( opacityTransferFunction ); ls->m_VolumePropertyCPU->SetGradientOpacity( gradientTransferFunction ); } } void mitk::GPUVolumeMapper3D::ApplyProperties(vtkActor* /*actor*/, mitk::BaseRenderer* /*renderer*/) { //GPU_INFO << "ApplyProperties"; } void mitk::GPUVolumeMapper3D::SetDefaultProperties(mitk::DataNode* node, mitk::BaseRenderer* renderer, bool overwrite) { //GPU_INFO << "SetDefaultProperties"; node->AddProperty( "volumerendering", mitk::BoolProperty::New( false ), renderer, overwrite ); node->AddProperty( "volumerendering.usemip", mitk::BoolProperty::New( false ), renderer, overwrite ); node->AddProperty( "volumerendering.uselod", mitk::BoolProperty::New( false ), renderer, overwrite ); node->AddProperty( "volumerendering.cpu.ambient", mitk::FloatProperty::New( 0.10f ), renderer, overwrite ); node->AddProperty( "volumerendering.cpu.diffuse", mitk::FloatProperty::New( 0.50f ), renderer, overwrite ); node->AddProperty( "volumerendering.cpu.specular", mitk::FloatProperty::New( 0.40f ), renderer, overwrite ); node->AddProperty( "volumerendering.cpu.specular.power", mitk::FloatProperty::New( 16.0f ), renderer, overwrite ); bool usegpu = true; #ifdef __APPLE__ usegpu = false; node->AddProperty( "volumerendering.uselod", mitk::BoolProperty::New( true ), renderer, overwrite ); #endif node->AddProperty( "volumerendering.usegpu", mitk::BoolProperty::New( usegpu ), renderer, overwrite ); // Only with VTK 5.6 or above #if ((VTK_MAJOR_VERSION > 5) || ((VTK_MAJOR_VERSION==5) && (VTK_MINOR_VERSION>=6) )) node->AddProperty( "volumerendering.useray", mitk::BoolProperty::New( false ), renderer, overwrite ); node->AddProperty( "volumerendering.ray.ambient", mitk::FloatProperty::New( 0.25f ), renderer, overwrite ); node->AddProperty( "volumerendering.ray.diffuse", mitk::FloatProperty::New( 0.50f ), renderer, overwrite ); node->AddProperty( "volumerendering.ray.specular", mitk::FloatProperty::New( 0.40f ), renderer, overwrite ); node->AddProperty( "volumerendering.ray.specular.power", mitk::FloatProperty::New( 16.0f ), renderer, overwrite ); #endif node->AddProperty( "volumerendering.gpu.ambient", mitk::FloatProperty::New( 0.25f ), renderer, overwrite ); node->AddProperty( "volumerendering.gpu.diffuse", mitk::FloatProperty::New( 0.50f ), renderer, overwrite ); node->AddProperty( "volumerendering.gpu.specular", mitk::FloatProperty::New( 0.40f ), renderer, overwrite ); node->AddProperty( "volumerendering.gpu.specular.power", mitk::FloatProperty::New( 16.0f ), renderer, overwrite ); node->AddProperty( "volumerendering.gpu.usetexturecompression", mitk::BoolProperty ::New( false ), renderer, overwrite ); node->AddProperty( "volumerendering.gpu.reducesliceartifacts" , mitk::BoolProperty ::New( false ), renderer, overwrite ); node->AddProperty( "binary", mitk::BoolProperty::New( false ), renderer, overwrite ); mitk::Image::Pointer image = dynamic_cast(node->GetData()); if(image.IsNotNull() && image->IsInitialized()) { if((overwrite) || (node->GetProperty("levelwindow", renderer)==NULL)) { mitk::LevelWindowProperty::Pointer levWinProp = mitk::LevelWindowProperty::New(); mitk::LevelWindow levelwindow; levelwindow.SetAuto( image ); levWinProp->SetLevelWindow( levelwindow ); node->SetProperty( "levelwindow", levWinProp, renderer ); } if((overwrite) || (node->GetProperty("TransferFunction", renderer)==NULL)) { // add a default transfer function mitk::TransferFunction::Pointer tf = mitk::TransferFunction::New(); mitk::TransferFunctionInitializer::Pointer tfInit = mitk::TransferFunctionInitializer::New(tf); tfInit->SetTransferFunctionMode(0); node->SetProperty ( "TransferFunction", mitk::TransferFunctionProperty::New ( tf.GetPointer() ) ); } } Superclass::SetDefaultProperties(node, renderer, overwrite); } bool mitk::GPUVolumeMapper3D::IsLODEnabled( mitk::BaseRenderer * renderer ) const { bool value = false; return GetDataNode()->GetBoolProperty("volumerendering.uselod",value,renderer) && value; } bool mitk::GPUVolumeMapper3D::IsMIPEnabled( mitk::BaseRenderer * renderer ) { bool value = false; return GetDataNode()->GetBoolProperty("volumerendering.usemip",value,renderer) && value; } bool mitk::GPUVolumeMapper3D::IsGPUEnabled( mitk::BaseRenderer * renderer ) { LocalStorage *ls = m_LSH.GetLocalStorage(renderer); bool value = false; return ls->m_gpuSupported && GetDataNode()->GetBoolProperty("volumerendering.usegpu",value,renderer) && value; } // Only with VTK 5.6 or above #if ((VTK_MAJOR_VERSION > 5) || ((VTK_MAJOR_VERSION==5) && (VTK_MINOR_VERSION>=6) )) bool mitk::GPUVolumeMapper3D::InitRAY(mitk::BaseRenderer* renderer) { LocalStorage *ls = m_LSH.GetLocalStorage(renderer); if(ls->m_rayInitialized) return ls->m_raySupported; GPU_INFO << "initializing gpu-raycast-vr (vtkMitkOpenGLGPUVolumeRayCastMapper)"; ls->m_MapperRAY = vtkMitkOpenGLGPUVolumeRayCastMapper::New(); ls->m_MapperRAY->SetAutoAdjustSampleDistances(0); ls->m_MapperRAY->SetSampleDistance(1.0); ls->m_VolumePropertyRAY = vtkVolumeProperty::New(); ls->m_VolumePropertyRAY->ShadeOn(); ls->m_VolumePropertyRAY->SetAmbient (0.25f); //0.05f ls->m_VolumePropertyRAY->SetDiffuse (0.50f); //0.45f ls->m_VolumePropertyRAY->SetSpecular(0.40f); //0.50f ls->m_VolumePropertyRAY->SetSpecularPower(16.0f); ls->m_VolumePropertyRAY->SetInterpolationTypeToLinear(); ls->m_VolumeRAY = vtkVolume::New(); ls->m_VolumeRAY->SetMapper( ls->m_MapperRAY ); ls->m_VolumeRAY->SetProperty( ls->m_VolumePropertyRAY ); ls->m_VolumeRAY->VisibilityOn(); ls->m_MapperRAY->SetInput( this->m_UnitSpacingImageFilter->GetOutput() ); ls->m_raySupported = ls->m_MapperRAY->IsRenderSupported(renderer->GetRenderWindow(),ls->m_VolumePropertyRAY); ls->m_rayInitialized = true; return ls->m_raySupported; } void mitk::GPUVolumeMapper3D::DeinitRAY(mitk::BaseRenderer* renderer) { LocalStorage *ls = m_LSH.GetLocalStorage(renderer); if(ls->m_rayInitialized) { GPU_INFO << "deinitializing gpu-raycast-vr"; ls->m_VolumeRAY->Delete(); ls->m_MapperRAY->Delete(); ls->m_VolumePropertyRAY->Delete(); ls->m_rayInitialized=false; } } void mitk::GPUVolumeMapper3D::GenerateDataRAY( mitk::BaseRenderer *renderer ) { LocalStorage *ls = m_LSH.GetLocalStorage(renderer); if( IsLODEnabled(renderer) && mitk::RenderingManager::GetInstance()->GetNextLOD( renderer ) == 0 ) ls->m_MapperRAY->SetImageSampleDistance(4.0); else ls->m_MapperRAY->SetImageSampleDistance(1.0); // Check raycasting mode if(IsMIPEnabled(renderer)) ls->m_MapperRAY->SetBlendModeToMaximumIntensity(); else ls->m_MapperRAY->SetBlendModeToComposite(); // Updating shadings { float value=0; if(GetDataNode()->GetFloatProperty("volumerendering.ray.ambient",value,renderer)) ls->m_VolumePropertyRAY->SetAmbient(value); if(GetDataNode()->GetFloatProperty("volumerendering.ray.diffuse",value,renderer)) ls->m_VolumePropertyRAY->SetDiffuse(value); if(GetDataNode()->GetFloatProperty("volumerendering.ray.specular",value,renderer)) ls->m_VolumePropertyRAY->SetSpecular(value); if(GetDataNode()->GetFloatProperty("volumerendering.ray.specular.power",value,renderer)) ls->m_VolumePropertyRAY->SetSpecularPower(value); } } bool mitk::GPUVolumeMapper3D::IsRAYEnabled( mitk::BaseRenderer * renderer ) { LocalStorage *ls = m_LSH.GetLocalStorage(renderer); bool value = false; return ls->m_raySupported && GetDataNode()->GetBoolProperty("volumerendering.useray",value,renderer) && value; } #endif diff --git a/Modules/MitkExt/Rendering/mitkGPUVolumeMapper3D.h b/Modules/MitkExt/Rendering/mitkGPUVolumeMapper3D.h index c10b614a42..3bc49e7137 100644 --- a/Modules/MitkExt/Rendering/mitkGPUVolumeMapper3D.h +++ b/Modules/MitkExt/Rendering/mitkGPUVolumeMapper3D.h @@ -1,204 +1,204 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date: 2009-05-26 17:32:07 +0200 (Tue, 26 May 2009) $ Version: $Revision: 17418 $ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef MITKGPUVOLUMEMAPPER3D_H_HEADER_INCLUDED #define MITKGPUVOLUMEMAPPER3D_H_HEADER_INCLUDED #include "mitkCommon.h" #include "MitkExtExports.h" #include "mitkBaseRenderer.h" #include "mitkVtkMapper3D.h" #include "mitkImage.h" #include #include "vtkMitkVolumeTextureMapper3D.h" // Only with VTK 5.6 or above #if ((VTK_MAJOR_VERSION > 5) || ((VTK_MAJOR_VERSION==5) && (VTK_MINOR_VERSION>=6) )) #include "vtkMitkGPUVolumeRayCastMapper.h" #endif #include #include namespace mitk { /************************************************************************/ /* Properties that influence the mapper are: * * - \b "level window": for the level window of the volume data * - \b "LookupTable" : for the lookup table of the volume data * - \b "TransferFunction" (mitk::TransferFunctionProperty): for the used transfer function of the volume data ************************************************************************/ //##Documentation //## @brief Vtk-based mapper for VolumeData //## //## @ingroup Mapper class MitkExt_EXPORT GPUVolumeMapper3D : public VtkMapper3D { public: mitkClassMacro(GPUVolumeMapper3D, VtkMapper3D); itkNewMacro(Self); virtual const mitk::Image* GetInput(); virtual vtkProp *GetVtkProp(mitk::BaseRenderer *renderer); virtual void ApplyProperties(vtkActor* actor, mitk::BaseRenderer* renderer); static void SetDefaultProperties(mitk::DataNode* node, mitk::BaseRenderer* renderer = NULL, bool overwrite = false); /** Returns true if this Mapper currently allows for Level-of-Detail rendering. * This reflects whether this Mapper currently invokes StartEvent, EndEvent, and * ProgressEvent on BaseRenderer. */ virtual bool IsLODEnabled( BaseRenderer *renderer = NULL ) const; bool IsMIPEnabled( BaseRenderer *renderer = NULL ); bool IsGPUEnabled( BaseRenderer *renderer = NULL ); bool IsRAYEnabled( BaseRenderer *renderer = NULL ); virtual void MitkRenderVolumetricGeometry(mitk::BaseRenderer* renderer); protected: GPUVolumeMapper3D(); virtual ~GPUVolumeMapper3D(); bool IsRenderable(mitk::BaseRenderer* renderer); void InitCommon(); void DeinitCommon(); void InitCPU(mitk::BaseRenderer* renderer); void DeinitCPU(mitk::BaseRenderer* renderer); void GenerateDataCPU(mitk::BaseRenderer* renderer); bool InitGPU(mitk::BaseRenderer* renderer); void DeinitGPU(mitk::BaseRenderer* renderer); void GenerateDataGPU(mitk::BaseRenderer* renderer); // Only with VTK 5.6 or above #if ((VTK_MAJOR_VERSION > 5) || ((VTK_MAJOR_VERSION==5) && (VTK_MINOR_VERSION>=6) )) bool InitRAY(mitk::BaseRenderer* renderer); void DeinitRAY(mitk::BaseRenderer* renderer); void GenerateDataRAY(mitk::BaseRenderer* renderer); #endif void InitVtkMapper(mitk::BaseRenderer* renderer); - virtual void GenerateData(mitk::BaseRenderer* renderer); + virtual void GenerateDataForRenderer(mitk::BaseRenderer* renderer); void CreateDefaultTransferFunctions(); void UpdateTransferFunctions( mitk::BaseRenderer *renderer ); vtkVolume * m_VolumeNULL; bool m_commonInitialized; vtkImageChangeInformation* m_UnitSpacingImageFilter; vtkPiecewiseFunction *m_DefaultOpacityTransferFunction; vtkPiecewiseFunction *m_DefaultGradientTransferFunction; vtkColorTransferFunction *m_DefaultColorTransferFunction; vtkPiecewiseFunction *m_BinaryOpacityTransferFunction; vtkPiecewiseFunction *m_BinaryGradientTransferFunction; vtkColorTransferFunction *m_BinaryColorTransferFunction; class LocalStorage : public mitk::Mapper::BaseLocalStorage { public: bool m_cpuInitialized; vtkVolume *m_VolumeCPU; vtkFixedPointVolumeRayCastMapper* m_MapperCPU; vtkVolumeProperty* m_VolumePropertyCPU; bool m_gpuSupported; bool m_gpuInitialized; vtkVolume *m_VolumeGPU; vtkMitkVolumeTextureMapper3D* m_MapperGPU; vtkVolumeProperty* m_VolumePropertyGPU; // Only with VTK 5.6 or above #if ((VTK_MAJOR_VERSION > 5) || ((VTK_MAJOR_VERSION==5) && (VTK_MINOR_VERSION>=6) )) bool m_raySupported; bool m_rayInitialized; vtkVolume *m_VolumeRAY; vtkMitkGPUVolumeRayCastMapper* m_MapperRAY; vtkVolumeProperty* m_VolumePropertyRAY; #endif LocalStorage() { m_cpuInitialized = false; m_gpuInitialized = false; m_gpuSupported = true; // assume initially gpu slicing is supported // Only with VTK 5.6 or above #if ((VTK_MAJOR_VERSION > 5) || ((VTK_MAJOR_VERSION==5) && (VTK_MINOR_VERSION>=6) )) m_rayInitialized = false; m_raySupported = true; // assume initially gpu raycasting is supported #endif } ~LocalStorage() { if(m_cpuInitialized) { m_VolumeCPU->Delete(); m_MapperCPU->Delete(); m_VolumePropertyCPU->Delete(); m_cpuInitialized=false; } if(m_gpuInitialized) { m_VolumeGPU->Delete(); m_MapperGPU->Delete(); m_VolumePropertyGPU->Delete(); m_gpuInitialized=false; } // Only with VTK 5.6 or above #if ((VTK_MAJOR_VERSION > 5) || ((VTK_MAJOR_VERSION==5) && (VTK_MINOR_VERSION>=6) )) if(m_rayInitialized) { m_VolumeRAY->Delete(); m_MapperRAY->Delete(); m_VolumePropertyRAY->Delete(); m_rayInitialized=false; } #endif } }; mitk::Mapper::LocalStorageHandler m_LSH; }; } // namespace mitk #endif /* MITKVOLUMEDATAVTKMAPPER3D_H_HEADER_INCLUDED */ diff --git a/Modules/QmitkExt/QmitkPointListView.cpp b/Modules/QmitkExt/QmitkPointListView.cpp index 8d696d12cc..e2d625fe87 100644 --- a/Modules/QmitkExt/QmitkPointListView.cpp +++ b/Modules/QmitkExt/QmitkPointListView.cpp @@ -1,417 +1,417 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision: 1.12 $ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "QmitkPointListView.h" #include "QmitkPointListModel.h" #include "QmitkStdMultiWidget.h" #include "QmitkEditPointDialog.h" #include "mitkRenderingManager.h" #include #include #include #include #include QmitkPointListView::QmitkPointListView( QWidget* parent ) :QListView( parent ), m_PointListModel( new QmitkPointListModel() ), m_SelfCall( false ), m_showFading(false), m_MultiWidget( NULL) { QListView::setAlternatingRowColors( true ); // logic QListView::setSelectionBehavior( QAbstractItemView::SelectRows ); QListView::setSelectionMode( QAbstractItemView::SingleSelection ); QListView::setModel( m_PointListModel ); QString tooltip = QString("Use the F2/F3 keys to move a point up/down, the Del key to remove a point\nand the mouse wheel to change the timestep.\n\nTimeStep:\t%1").arg(0); QListView::setToolTip(tooltip); //m_FadeTimer = new QTimer(); this->setContextMenuPolicy(Qt::CustomContextMenu); m_TimeStepFaderLabel = new QLabel(this); QFont font("Arial", 17); m_TimeStepFaderLabel->setFont(font); //Define Size this->setMinimumHeight(40); //horizontal, vertical this->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored); //connect connect( m_PointListModel, SIGNAL(SignalUpdateSelection()), this, SLOT(OnPointSetSelectionChanged()) ); connect( this, SIGNAL(doubleClicked ( const QModelIndex & )), this, SLOT(OnPointDoubleClicked( const QModelIndex & )) ); connect( QListView::selectionModel(), SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)), this, SLOT(OnListViewSelectionChanged(const QItemSelection& , const QItemSelection&)) ); connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(ctxMenu(const QPoint &))); } QmitkPointListView::~QmitkPointListView() { delete m_PointListModel; } void QmitkPointListView::SetPointSetNode( mitk::DataNode* pointSetNode ) { m_PointListModel->SetPointSetNode( pointSetNode); } const mitk::PointSet* QmitkPointListView::GetPointSet() const { return m_PointListModel->GetPointSet(); } void QmitkPointListView::SetMultiWidget( QmitkStdMultiWidget* multiWidget ) { m_MultiWidget = multiWidget; } QmitkStdMultiWidget* QmitkPointListView::GetMultiWidget() const { return m_MultiWidget; } void QmitkPointListView::OnPointDoubleClicked(const QModelIndex & index) { mitk::PointSet::PointType p; mitk::PointSet::PointIdentifier id; m_PointListModel->GetPointForModelIndex(index, p, id); QmitkEditPointDialog _EditPointDialog(this); _EditPointDialog.SetPoint(m_PointListModel->GetPointSet(), id, m_PointListModel->GetTimeStep()); _EditPointDialog.exec(); } void QmitkPointListView::OnPointSetSelectionChanged() { const mitk::PointSet* pointSet = m_PointListModel->GetPointSet(); if (pointSet == NULL) return; // update this view's selection status as a result to changes in the point set data structure m_SelfCall = true; int timeStep = m_PointListModel->GetTimeStep(); if ( pointSet->GetNumberOfSelected( timeStep ) > 1 ) { MITK_ERROR << "Point set has multiple selected points. This view is not designed for more than one selected point."; } int selectedIndex = pointSet->SearchSelectedPoint( timeStep ); if (selectedIndex == -1) // no selected point is found { m_SelfCall = false; return; } QModelIndex index; bool modelIndexOkay = m_PointListModel->GetModelIndexForPointID(selectedIndex, index); if (modelIndexOkay == true) QListView::selectionModel()->select( index , QItemSelectionModel::ClearAndSelect ); emit SignalPointSelectionChanged(); m_SelfCall = false; } void QmitkPointListView::OnListViewSelectionChanged(const QItemSelection& selected, const QItemSelection& /*deselected*/) { if (m_SelfCall) return; mitk::PointSet* pointSet = const_cast( m_PointListModel->GetPointSet() ); if (pointSet == NULL) return; // (take care that this widget doesn't react to self-induced changes by setting m_SelfCall) m_SelfCall = true; // update selection of all points in pointset: select the one(s) that are selected in the view, deselect all others QModelIndexList selectedIndexes = selected.indexes(); for (mitk::PointSet::PointsContainer::Iterator it = pointSet->GetPointSet(m_PointListModel->GetTimeStep())->GetPoints()->Begin(); it != pointSet->GetPointSet(m_PointListModel->GetTimeStep())->GetPoints()->End(); ++it) { QModelIndex index; if (m_PointListModel->GetModelIndexForPointID(it->Index(), index)) { if (selectedIndexes.indexOf(index) != -1) // index is found in the selected indices list { pointSet->SetSelectInfo(it->Index(), true, m_PointListModel->GetTimeStep()); if ( m_MultiWidget != NULL) { m_MultiWidget->MoveCrossToPosition(pointSet->GetPoint(it->Index(), m_PointListModel->GetTimeStep())); } } else { pointSet->SetSelectInfo(it->Index(), false, m_PointListModel->GetTimeStep()); } } } m_SelfCall = false; emit SignalPointSelectionChanged(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkPointListView::keyPressEvent( QKeyEvent * e ) { if (m_PointListModel == NULL) return; int key = e->key(); switch (key) { case Qt::Key_F2: m_PointListModel->MoveSelectedPointUp(); break; case Qt::Key_F3: m_PointListModel->MoveSelectedPointDown(); break; case Qt::Key_Delete: m_PointListModel->RemoveSelectedPoint(); break; default: break; } } void QmitkPointListView::wheelEvent(QWheelEvent *event) { if (!m_PointListModel || !m_PointListModel->GetPointSet() || (int)(m_PointListModel->GetPointSet()->GetTimeSteps()) == 1 /*|| !m_4DPointSet*/) return; int whe = event->delta(); mitk::PointSet::Pointer ps = dynamic_cast(m_PointListModel->GetPointSet()); unsigned int numberOfTS = ps->GetTimeSteps(); if(numberOfTS == 1) return; int currentTS = this->m_PointListModel->GetTimeStep(); if(whe > 0) { if((currentTS >= (int)(m_PointListModel->GetPointSet()->GetTimeSteps()))) return; this->m_PointListModel->SetTimeStep(++currentTS); } else { if((currentTS <= 0)) return; this->m_PointListModel->SetTimeStep(--currentTS); } QString tooltip = QString("Use the F2/F3 keys to move a point up/down, the Del key to remove a point\nand the mouse wheel to change the timestep.\n\nTimeStep:\t%1").arg(currentTS); this->setToolTip(tooltip); fadeTimeStepIn(); } void QmitkPointListView::fadeTimeStepIn() { //Setup Widget QWidget *m_TimeStepFader = new QWidget(this); QHBoxLayout *layout = new QHBoxLayout(m_TimeStepFader); int x = (int)(this->geometry().x()+this->width()*0.6); int y = (int)(this->geometry().y()+this->height()*0.8); m_TimeStepFader->move(x,y); m_TimeStepFader->resize(60, 55); m_TimeStepFader->setLayout(layout); m_TimeStepFader->setAttribute(Qt::WA_DeleteOnClose); //setup Label // QLabel *label = new QLabel(QString("%1").arg(this->m_PointListModel->GetTimeStep())); layout->addWidget(m_TimeStepFaderLabel); m_TimeStepFaderLabel->setAlignment(Qt::AlignCenter); m_TimeStepFaderLabel->setFrameStyle(QFrame::StyledPanel | QFrame::Raised); m_TimeStepFaderLabel->setLineWidth(2); m_TimeStepFaderLabel->setText(QString("%1").arg(this->m_PointListModel->GetTimeStep())); //give the widget opacity and some colour QPalette pal = m_TimeStepFaderLabel->palette(); QColor semiTransparentColor(139, 192, 223, 50); QColor labelTransparentColor(0,0,0,200); pal.setColor(m_TimeStepFaderLabel->backgroundRole(), semiTransparentColor); pal.setColor(m_TimeStepFaderLabel->foregroundRole(), labelTransparentColor); m_TimeStepFaderLabel->setAutoFillBackground(true); m_TimeStepFaderLabel->setPalette(pal); //show the widget m_TimeStepFader->show(); //and start the timer m_TimeStepFaderLabel->setVisible(true); QTimer::singleShot(2000, this, SLOT(fadeTimeStepOut())); } void QmitkPointListView::fadeTimeStepOut() { m_TimeStepFaderLabel->hide(); } void QmitkPointListView::ctxMenu(const QPoint &pos) { QMenu *menu = new QMenu; // menu->setStyle(); // menu->addAction(tr("Test Item"), this, SLOT(test_slot())); //add Fading check QAction *showFading = new QAction(this); showFading->setCheckable(false); //TODO: reset when fading is working showFading->setEnabled(false); //TODO: reset when fading is working showFading->setText("Fade TimeStep"); connect(showFading, SIGNAL(triggered(bool)), this, SLOT(SetFading(bool))); menu->addAction(showFading); //add Clear action QAction *clearList = new QAction(this); clearList->setText("Clear List"); connect(clearList, SIGNAL(triggered()), this, SLOT(ClearPointList())); menu->addAction(clearList); //add Clear TimeStep action QAction *clearTS = new QAction(this); clearTS->setText("Clear current time step"); connect(clearTS, SIGNAL(triggered()), this, SLOT(ClearPointListTS())); menu->addAction(clearTS); // //add "show time step in list" option // QAction *viewTS = new QAction(this); // viewTS->setText("Show time step in list"); // viewTS->setCheckable(true); // viewTS->setChecked(false); // connect(viewTS, SIGNAL(triggered(bool)), this, SLOT(ClearPointList(bool))); // menu->addAction(viewTS); menu->exec(this->mapToGlobal(pos)); } void QmitkPointListView::SetFading(bool onOff) { m_showFading = onOff; } void QmitkPointListView::ClearPointList() { if(!m_PointListModel->GetPointSet()) return; mitk::PointSet::Pointer curPS = m_PointListModel->GetPointSet(); if ( curPS->GetSize() == 0) return; switch( QMessageBox::question( this, tr("Clear Points"), tr("Remove all points from the displayed list?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No)) { case QMessageBox::Yes: { // m_PointListModel->ClearList(); // /* // if (curPS) // { // curPS->Clear(); // } // */ // mitk::RenderingManager::GetInstance()->RequestUpdateAll(); // break; mitk::PointSet::PointsIterator it; mitk::PointSet::PointsContainer *curPsPoints; - while( !curPS->IsEmpty(0)) + while( !curPS->IsEmptyTimeStep(0)) { curPsPoints = curPS->GetPointSet()->GetPoints(); it = curPsPoints->Begin(); curPS->SetSelectInfo(it->Index(),true); m_PointListModel->RemoveSelectedPoint(); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); break; } case QMessageBox::No: default: break; } // emit PointListChanged(); } void QmitkPointListView::ClearPointListTS() { // mitk::PointSet* /*::Pointer*/ curPS = m_PointListModel->GetPointSet(); // if ( curPS->GetSize() == 0) // return; // int ts = this->m_PointListModel->GetTimeStep(); // switch( QMessageBox::question( this, tr("Clear Points in Timestep"), // tr("Remove all points from the list with the timestep %1?").arg(ts), // QMessageBox::Yes | QMessageBox::No, QMessageBox::No)) // { // case QMessageBox::Yes: // if (curPS) // { // mitk::PointSet::DataType::Pointer curPSwithTS = curPS->GetPointSet(ts); // //curPSwithTS->Clear(); // } // mitk::RenderingManager::GetInstance()->RequestUpdateAll(); // break; // case QMessageBox::No: // default: // break; // } // // emit PointListChanged(); }