diff --git a/CMakeExternals/MITKData.cmake b/CMakeExternals/MITKData.cmake
index bee95e81b3..ca7fee4d86 100644
--- a/CMakeExternals/MITKData.cmake
+++ b/CMakeExternals/MITKData.cmake
@@ -1,36 +1,36 @@
#-----------------------------------------------------------------------------
# MITK Data
#-----------------------------------------------------------------------------
# Sanity checks
if(DEFINED MITK_DATA_DIR AND NOT EXISTS ${MITK_DATA_DIR})
message(FATAL_ERROR "MITK_DATA_DIR variable is defined but corresponds to non-existing directory")
endif()
set(proj MITK-Data)
set(proj_DEPENDENCIES)
set(MITK-Data_DEPENDS ${proj})
if(BUILD_TESTING)
- set(revision_tag 3be15a2d)
+ set(revision_tag 81f5a871)
# ^^^^^^^^ these are just to check correct length of hash part
ExternalProject_Add(${proj}
URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/MITK-Data_${revision_tag}.tar.gz
UPDATE_COMMAND ""
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
DEPENDS ${proj_DEPENDENCIES}
)
set(MITK_DATA_DIR ${ep_source_dir}/${proj})
else()
mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}")
endif(BUILD_TESTING)
diff --git a/Core/Code/Interactions/mitkEventRecorder.cpp b/Core/Code/Interactions/mitkEventRecorder.cpp
index f14294a3fb..b260013615 100644
--- a/Core/Code/Interactions/mitkEventRecorder.cpp
+++ b/Core/Code/Interactions/mitkEventRecorder.cpp
@@ -1,163 +1,171 @@
/*===================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.
This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.
See LICENSE.txt or http://www.mitk.org for details.
===================================================================*/
#include "mitkEventRecorder.h"
#include "mitkEventFactory.h"
#include "mitkInteractionEvent.h"
#include "mitkInteractionEventConst.h"
#include "mitkBaseRenderer.h"
static void WriteEventXMLHeader(std::ofstream& stream)
{
stream << mitk::InteractionEventConst::xmlHead() << "\n";
}
static void WriteEventXMLConfig(std::ofstream& stream)
{
//
stream << " <" << mitk::InteractionEventConst::xmlTagConfigRoot() << ">\n";
//write renderer config
//for all registered 2D renderers write name and viewdirection.
mitk::BaseRenderer::BaseRendererMapType::iterator rendererIterator = mitk::BaseRenderer::baseRendererMap.begin();
mitk::BaseRenderer::BaseRendererMapType::iterator end = mitk::BaseRenderer::baseRendererMap.end();
for(; rendererIterator != end; rendererIterator++)
{
std::string rendererName = (*rendererIterator).second->GetName();
+
mitk::SliceNavigationController::ViewDirection viewDirection = (*rendererIterator).second->GetSliceNavigationController()->GetDefaultViewDirection();
mitk::BaseRenderer::MapperSlotId mapperID = (*rendererIterator).second->GetMapperID();
- //
- stream << " <" << mitk::InteractionEventConst::xmlTagRenderer() << " " << mitk::InteractionEventConst::xmlEventPropertyRendererName() << "=\"" << rendererName << "\" " << mitk::InteractionEventConst::xmlEventPropertyViewDirection() << "=\"" << viewDirection << "\" " << mitk::InteractionEventConst::xmlEventPropertyMapperID() << "=\"" << mapperID << "\"/>\n";
+ //
+ stream << " <" << mitk::InteractionEventConst::xmlTagRenderer() << " "
+ << mitk::InteractionEventConst::xmlEventPropertyRendererName() << "=\""<< rendererName << "\" "
+ << mitk::InteractionEventConst::xmlEventPropertyViewDirection() << "=\""<< viewDirection << "\" "
+ << mitk::InteractionEventConst::xmlEventPropertyMapperID() << "=\"" << mapperID << "\" "
+ << mitk::InteractionEventConst::xmlRenderSizeX() << "=\"" << (*rendererIterator).second->GetSize()[0] << "\" "
+ << mitk::InteractionEventConst::xmlRenderSizeY() << "=\"" << (*rendererIterator).second->GetSize()[1] << "\" "
+ << mitk::InteractionEventConst::xmlRenderSizeZ() << "=\"" << (*rendererIterator).second->GetSize()[2] << "\" "
+ << "/>\n";
}
//
stream << " " << mitk::InteractionEventConst::xmlTagConfigRoot() << ">\n";
}
static void WriteEventXMLEventsOpen(std::ofstream& stream)
{
stream << " <" << mitk::InteractionEventConst::xmlTagEvents() << ">\n";
}
static void WriteEventXMLEventsClose(std::ofstream& stream)
{
stream << " " << mitk::InteractionEventConst::xmlTagEvents() << ">\n";
}
static void WriteEventXMLInteractionsOpen(std::ofstream& stream)
{
stream << "<" << mitk::InteractionEventConst::xmlTagInteractions() << ">\n";
}
static void WriteEventXMLInteractionsClose(std::ofstream& stream)
{
stream << "" << mitk::InteractionEventConst::xmlTagInteractions() << ">";
}
static void WriteEventXMLClose(std::ofstream& stream)
{
WriteEventXMLEventsClose(stream);
WriteEventXMLInteractionsClose(stream);
}
mitk::EventRecorder::EventRecorder()
: m_Active(false)
{
}
mitk::EventRecorder::~EventRecorder()
{
if (m_FileStream.is_open())
{
m_FileStream.flush();
m_FileStream.close();
}
}
void mitk::EventRecorder::Notify(mitk::InteractionEvent *interactionEvent, bool /*isHandled*/)
{
if (m_FileStream.is_open())
m_FileStream << EventFactory::EventToXML(interactionEvent) << "\n";
}
void mitk::EventRecorder::SetEventIgnoreList(std::vector list)
{
m_IgnoreList = list;
}
void mitk::EventRecorder::StartRecording()
{
if (m_FileName == "")
{
MITK_ERROR << "EventRecorder::StartRecording - Filename needs to be set first.";
return;
}
if (m_FileStream.is_open())
{
MITK_ERROR << "EventRecorder::StartRecording - Still recording. Stop recording before starting it again.";
return;
}
m_FileStream.open(m_FileName.c_str(), std::ofstream::out );
if ( !m_FileStream.good() )
{
MITK_ERROR << "File " << m_FileName << " could not be opened!";
m_FileStream.close();
return;
}
m_Active = true;
//write head and config
//
//
//
//
//
// ...
//
//
WriteEventXMLHeader(m_FileStream);
WriteEventXMLInteractionsOpen(m_FileStream);
WriteEventXMLConfig(m_FileStream);
WriteEventXMLEventsOpen(m_FileStream);
}
void mitk::EventRecorder::StopRecording()
{
if (m_FileStream.is_open())
{
//write end tag
//
//
WriteEventXMLClose(m_FileStream);
m_FileStream.flush();
m_FileStream.close();
m_Active =false;
}
}
diff --git a/Core/Code/Interactions/mitkInteractionEventConst.cpp b/Core/Code/Interactions/mitkInteractionEventConst.cpp
index a61354c688..7615c30aaf 100644
--- a/Core/Code/Interactions/mitkInteractionEventConst.cpp
+++ b/Core/Code/Interactions/mitkInteractionEventConst.cpp
@@ -1,165 +1,183 @@
/*===================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.
This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.
See LICENSE.txt or http://www.mitk.org for details.
===================================================================*/
#include "mitkInteractionEventConst.h"
namespace mitk {
const std::string InteractionEventConst::xmlHead()
{
static const std::string xmlHead = "";
return xmlHead;
}
const std::string InteractionEventConst::xmlTagConfigRoot()
{
static const std::string xmlTagConfigRoot = "config";
return xmlTagConfigRoot;
}
const std::string InteractionEventConst::xmlTagEvents()
{
static const std::string xmlTagEvents = "events";
return xmlTagEvents;
}
const std::string InteractionEventConst::xmlTagInteractions()
{
static const std::string xmlTagInteractions = "interactions";
return xmlTagInteractions;
}
const std::string InteractionEventConst::xmlTagRenderer()
{
static const std::string xmlTagRenderer = "renderer";
return xmlTagRenderer;
}
const std::string InteractionEventConst::xmlTagParam()
{
static const std::string xmlTagParam = "param";
return xmlTagParam;
}
const std::string InteractionEventConst::xmlTagEventVariant()
{
static const std::string xmlTagEventVariant = "event_variant";
return xmlTagEventVariant;
}
const std::string InteractionEventConst::xmlTagAttribute()
{
static const std::string xmlTagAttribute = "attribute";
return xmlTagAttribute;
}
const std::string InteractionEventConst::xmlParameterName()
{
static const std::string xmlParameterName = "name";
return xmlParameterName;
}
const std::string InteractionEventConst::xmlParameterValue()
{
static const std::string xmlParameterValue = "value";
return xmlParameterValue;
}
const std::string InteractionEventConst::xmlParameterEventVariant()
{
static const std::string xmlParameterEventVariant = "event_variant";
return xmlParameterEventVariant;
}
const std::string InteractionEventConst::xmlParameterEventClass()
{
static const std::string xmlParameterEventClass = "class";
return xmlParameterEventClass;
}
const std::string InteractionEventConst::xmlEventPropertyModifier()
{
static const std::string xmlEventPropertyModifier = "Modifiers";
return xmlEventPropertyModifier;
}
const std::string InteractionEventConst::xmlEventPropertyEventButton()
{
static const std::string xmlEventPropertyEventButton = "EventButton";
return xmlEventPropertyEventButton;
}
const std::string InteractionEventConst::xmlEventPropertyButtonState()
{
static const std::string xmlEventPropertyButtonState = "ButtonState";
return xmlEventPropertyButtonState;
}
const std::string InteractionEventConst::xmlEventPropertyPositionInWorld()
{
static const std::string xmlEventPropertyPosition = "PositionInWorld";
return xmlEventPropertyPosition;
}
const std::string InteractionEventConst::xmlEventPropertyPositionOnScreen()
{
static const std::string xmlEventPropertyPosition = "PositionOnScreen";
return xmlEventPropertyPosition;
}
const std::string InteractionEventConst::xmlEventPropertyKey()
{
static const std::string xmlEventPropertyKey = "Key";
return xmlEventPropertyKey;
}
const std::string InteractionEventConst::xmlEventPropertyScrollDirection()
{
static const std::string xmlEventPropertyScrollDirection = "ScrollDirection";
return xmlEventPropertyScrollDirection;
}
const std::string InteractionEventConst::xmlEventPropertyWheelDelta()
{
static const std::string xmlEventPropertyWheelDelta = "WheelDelta";
return xmlEventPropertyWheelDelta;
}
const std::string InteractionEventConst::xmlEventPropertySignalName()
{
static const std::string xmlEventPropertySignalName = "SignalName";
return xmlEventPropertySignalName;
}
const std::string InteractionEventConst::xmlEventPropertyRendererName()
{
static const std::string xmlEventPropertyRendererName = "RendererName";
return xmlEventPropertyRendererName;
}
const std::string InteractionEventConst::xmlEventPropertyViewDirection()
{
static const std::string xmlEventPropertyViewDirection = "ViewDirection";
return xmlEventPropertyViewDirection;
}
const std::string InteractionEventConst::xmlEventPropertyMapperID()
{
static const std::string xmlEventPropertyMapperID = "MapperID";
return xmlEventPropertyMapperID;
}
+const std::string mitk::InteractionEventConst::xmlRenderSizeX()
+{
+ static const std::string xmlSize = "RenderSizeX";
+ return xmlSize;
+}
+
+const std::string mitk::InteractionEventConst::xmlRenderSizeY()
+{
+ static const std::string xmlSize = "RenderSizeY";
+ return xmlSize;
+}
+
+const std::string mitk::InteractionEventConst::xmlRenderSizeZ()
+{
+ static const std::string xmlSize = "RenderSizeZ";
+ return xmlSize;
+}
+
}
diff --git a/Core/Code/Interactions/mitkInteractionEventConst.h b/Core/Code/Interactions/mitkInteractionEventConst.h
index 02589cac20..137aaf0552 100644
--- a/Core/Code/Interactions/mitkInteractionEventConst.h
+++ b/Core/Code/Interactions/mitkInteractionEventConst.h
@@ -1,64 +1,68 @@
/*===================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.
This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.
See LICENSE.txt or http://www.mitk.org for details.
===================================================================*/
#ifndef MITKINTERACTEVENTCONST_H
#define MITKINTERACTEVENTCONST_H
#include
#include
namespace mitk
{
/**
* @brief Constants to describe Mouse Events and special Key Events.
*/
struct MITK_CORE_EXPORT InteractionEventConst
{
static const std::string xmlHead(); // = "";
// XML Tags
static const std::string xmlTagConfigRoot(); // = "config";
static const std::string xmlTagEvents(); // = "events";
static const std::string xmlTagInteractions(); // = "interactions";
static const std::string xmlTagParam(); // = "param";
static const std::string xmlTagEventVariant(); // = "event_variant";
static const std::string xmlTagAttribute(); // = "attribute";
static const std::string xmlTagRenderer(); // = "renderer";
// XML Param
static const std::string xmlParameterName(); // = "name";
static const std::string xmlParameterValue(); // = "value";
static const std::string xmlParameterEventVariant(); // = "event_variant";
static const std::string xmlParameterEventClass(); // = "class";
// Event Description
static const std::string xmlEventPropertyModifier(); // = "Modifiers";
static const std::string xmlEventPropertyEventButton(); // = "EventButton";
static const std::string xmlEventPropertyButtonState(); // = "ButtonState";
static const std::string xmlEventPropertyPositionInWorld(); // = "PositionInWorld";
static const std::string xmlEventPropertyPositionOnScreen(); // = "PositionOnScreen";
static const std::string xmlEventPropertyKey(); // = "Key";
static const std::string xmlEventPropertyScrollDirection(); // = "ScrollDirection";
static const std::string xmlEventPropertyWheelDelta(); // = "WheelDelta";
static const std::string xmlEventPropertySignalName(); // = "SignalName";
static const std::string xmlEventPropertyRendererName(); // = "RendererName";
static const std::string xmlEventPropertyViewDirection(); // = "ViewDirection";
static const std::string xmlEventPropertyMapperID(); // = "MapperID";
+
+ static const std::string xmlRenderSizeX(); // = "RenderSizeX";
+ static const std::string xmlRenderSizeY(); // = "RenderSizeY";
+ static const std::string xmlRenderSizeZ(); // = "RenderSizeZ";
};
} //namespace mitk
#endif //ifndef MITKINTERACTEVENTCONST_H
diff --git a/Core/Code/TestingHelper/mitkInteractionTestHelper.cpp b/Core/Code/TestingHelper/mitkInteractionTestHelper.cpp
index 1e8759440f..d2c65d5136 100644
--- a/Core/Code/TestingHelper/mitkInteractionTestHelper.cpp
+++ b/Core/Code/TestingHelper/mitkInteractionTestHelper.cpp
@@ -1,220 +1,242 @@
/*===================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.
This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.
See LICENSE.txt or http://www.mitk.org for details.
===================================================================*/
//MITK
#include
#include
#include
#include
#include
//us
#include
#include
mitk::InteractionTestHelper::InteractionTestHelper(const std::string &interactionXmlFilePath)
: m_InteractionFilePath(interactionXmlFilePath)
{
this->Initialize(interactionXmlFilePath);
}
void mitk::InteractionTestHelper::Initialize(const std::string &interactionXmlFilePath)
{
//TiXmlDocument document(interactionXmlPath.c_str());
TiXmlDocument document(interactionXmlFilePath);
bool loadOkay = document.LoadFile();
if (loadOkay)
{
// Global interaction must(!) be initialized
if(! mitk::GlobalInteraction::GetInstance()->IsInitialized())
mitk::GlobalInteraction::GetInstance()->Initialize("global");
//get RenderingManager instance
mitk::RenderingManager* rm = mitk::RenderingManager::GetInstance();
//create data storage
m_DataStorage = mitk::StandaloneDataStorage::New();
//for each renderer found create a render window and configure
for( TiXmlElement* element = document.FirstChildElement(mitk::InteractionEventConst::xmlTagInteractions())->FirstChildElement(mitk::InteractionEventConst::xmlTagConfigRoot())->FirstChildElement(mitk::InteractionEventConst::xmlTagRenderer());
element != NULL;
element = element->NextSiblingElement(mitk::InteractionEventConst::xmlTagRenderer()) )
{
//get name of renderer
const char* rendererName = element->Attribute(mitk::InteractionEventConst::xmlEventPropertyRendererName().c_str());
//get view direction
mitk::SliceNavigationController::ViewDirection viewDirection = mitk::SliceNavigationController::Axial;
if(element->Attribute(mitk::InteractionEventConst::xmlEventPropertyViewDirection()) != NULL)
{
int viewDirectionNum = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlEventPropertyViewDirection())->c_str());
viewDirection = static_cast(viewDirectionNum);
}
//get mapper slot id
mitk::BaseRenderer::MapperSlotId mapperID = mitk::BaseRenderer::Standard2D;
if(element->Attribute(mitk::InteractionEventConst::xmlEventPropertyMapperID()) != NULL)
{
int mapperIDNum = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlEventPropertyMapperID())->c_str());
mapperID = static_cast(mapperIDNum);
}
+
+ // Get Size of Render Windows
+ int size[3];
+ size[0]=size[1]=size[2]=0;
+ if(element->Attribute(mitk::InteractionEventConst::xmlRenderSizeX()) != NULL)
+ {
+ size[0] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlRenderSizeX())->c_str());
+ }
+ if(element->Attribute(mitk::InteractionEventConst::xmlRenderSizeY()) != NULL)
+ {
+ size[1] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlRenderSizeY())->c_str());
+ }
+ if(element->Attribute(mitk::InteractionEventConst::xmlRenderSizeZ()) != NULL)
+ {
+ size[2] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlRenderSizeZ())->c_str());
+ }
+
//create renderWindow, renderer and dispatcher
mitk::RenderWindow::Pointer rw = mitk::RenderWindow::New(NULL, rendererName, rm); //VtkRenderWindow is created within constructor if NULL
+ if (size[0] != 0 && size[1] != 0)
+ rw->SetSize(size[0],size[1]);
+
//set storage of renderer
rw->GetRenderer()->SetDataStorage(m_DataStorage);
//set view direction to axial
rw->GetSliceNavigationController()->SetDefaultViewDirection( viewDirection );
//set renderer to render 2D
rw->GetRenderer()->SetMapperID(mapperID);
//connect SliceNavigationControllers to timestep changed event of TimeNavigationController
rw->GetSliceNavigationController()->ConnectGeometryTimeEvent(rm->GetTimeNavigationController(), false);
rm->GetTimeNavigationController()->ConnectGeometryTimeEvent(rw->GetSliceNavigationController(), false);
//add to list of kown render windows
m_RenderWindowList.push_back(rw);
}
//TODO: check the following lines taken from QmitkStdMultiWidget and adapt them to be executed in our code here.
// mitkWidget1->GetSliceNavigationController()
// ->ConnectGeometrySendEvent(mitk::BaseRenderer::GetInstance(mitkWidget4->GetRenderWindow()));
//########### register display interactor to handle scroll events ##################
//use MouseModeSwitcher to ensure that the statemachine of DisplayInteractor is loaded correctly
m_MouseModeSwitcher = mitk::MouseModeSwitcher::New();
}
else
{
mitkThrow() << "Can not load interaction xml file <" << m_InteractionFilePath << ">";
}
}
mitk::InteractionTestHelper::~InteractionTestHelper()
{
mitk::RenderingManager* rm = mitk::RenderingManager::GetInstance();
//unregister renderers
InteractionTestHelper::RenderWindowListType::iterator it = m_RenderWindowList.begin();
InteractionTestHelper::RenderWindowListType::iterator end = m_RenderWindowList.end();
for(; it != end; it++)
{
rm->GetTimeNavigationController()->Disconnect((*it)->GetSliceNavigationController());
(*it)->GetSliceNavigationController()->Disconnect(rm->GetTimeNavigationController());
mitk::BaseRenderer::RemoveInstance((*it)->GetVtkRenderWindow());
}
rm->RemoveAllObservers();
}
mitk::DataStorage::Pointer mitk::InteractionTestHelper::GetDataStorage()
{
return m_DataStorage;
}
void mitk::InteractionTestHelper::AddNodeToStorage(mitk::DataNode::Pointer node)
{
this->m_DataStorage->Add(node);
mitk::RenderingManager::GetInstance()->InitializeViewsByBoundingObjects(m_DataStorage);
}
void mitk::InteractionTestHelper::PlaybackInteraction()
{
//load events if not loaded yet
if(m_Events.empty())
this->LoadInteraction();
//playback all events in queue
for (unsigned long i=0; i < m_Events.size(); ++i)
{
//let dispatcher of sending renderer process the event
m_Events.at(i)->GetSender()->GetDispatcher()->ProcessEvent(m_Events.at(i));
}
}
void mitk::InteractionTestHelper::LoadInteraction()
{
//load interaction pattern from xml file
std::ifstream xmlStream(m_InteractionFilePath.c_str());
mitk::XML2EventParser parser(xmlStream);
m_Events = parser.GetInteractions();
xmlStream.close();
+ // Avoid VTK warning: Trying to delete object with non-zero reference count.
+ parser.SetReferenceCount(0);
}
void mitk::InteractionTestHelper::SetTimeStep(int newTimeStep)
{
bool timeStepIsvalid = mitk::RenderingManager::GetInstance()->GetTimeNavigationController()->GetCreatedWorldGeometry()->IsValidTimeStep(newTimeStep);
if(timeStepIsvalid)
{
mitk::RenderingManager::GetInstance()->GetTimeNavigationController()->GetTime()->SetPos(newTimeStep);
}
}
mitk::RenderWindow* mitk::InteractionTestHelper::GetRenderWindowByName(const std::string &name)
{
InteractionTestHelper::RenderWindowListType::iterator it = m_RenderWindowList.begin();
InteractionTestHelper::RenderWindowListType::iterator end = m_RenderWindowList.end();
for(; it != end; it++)
{
if( name.compare( (*it)->GetRenderer()->GetName() ) == 0)
return (*it).GetPointer();
}
return NULL;
}
mitk::RenderWindow* mitk::InteractionTestHelper::GetRenderWindowByDefaultViewDirection(mitk::SliceNavigationController::ViewDirection viewDirection)
{
InteractionTestHelper::RenderWindowListType::iterator it = m_RenderWindowList.begin();
InteractionTestHelper::RenderWindowListType::iterator end = m_RenderWindowList.end();
for(; it != end; it++)
{
if( viewDirection == (*it)->GetSliceNavigationController()->GetDefaultViewDirection() )
return (*it).GetPointer();
}
return NULL;
}
mitk::RenderWindow* mitk::InteractionTestHelper::GetRenderWindow(unsigned int index)
{
if( index < m_RenderWindowList.size() )
{
return m_RenderWindowList.at(index).GetPointer();
}
else
{
return NULL;
}
}
diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarAngle.cpp b/Modules/PlanarFigure/DataManagement/mitkPlanarAngle.cpp
index 338f9b7023..f559a6ffd7 100644
--- a/Modules/PlanarFigure/DataManagement/mitkPlanarAngle.cpp
+++ b/Modules/PlanarFigure/DataManagement/mitkPlanarAngle.cpp
@@ -1,171 +1,184 @@
/*===================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.
This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.
See LICENSE.txt or http://www.mitk.org for details.
===================================================================*/
#include "mitkPlanarAngle.h"
#include "mitkPlaneGeometry.h"
mitk::PlanarAngle::PlanarAngle()
: FEATURE_ID_ANGLE( this->AddFeature( "Angle", "deg" ) )
{
// Start with two control points
this->ResetNumberOfControlPoints( 2 );
this->SetNumberOfPolyLines(1);
this->SetNumberOfHelperPolyLines(1);
m_HelperPolyLinesToBePainted->InsertElement( 0, false );
}
mitk::PlanarAngle::~PlanarAngle()
{
}
void mitk::PlanarAngle::GeneratePolyLine()
{
this->ClearPolyLines();
for ( unsigned int i=0; iGetNumberOfControlPoints(); i++ )
this->AppendPointToPolyLine(0, this->GetControlPoint(i));
}
void mitk::PlanarAngle::GenerateHelperPolyLine(double mmPerDisplayUnit, unsigned int displayHeight)
{
// Generate helper-poly-line for angle
if ( this->GetNumberOfControlPoints() < 3)
{
m_HelperPolyLinesToBePainted->SetElement(0, false);
return; //We do not need to draw an angle as there are no two arms yet
}
this->ClearHelperPolyLines();
const Point2D centerPoint = this->GetControlPoint( 1 );
const Point2D boundaryPointOne = this->GetControlPoint( 0 );
const Point2D boundaryPointTwo = this->GetControlPoint( 2 );
double radius = centerPoint.EuclideanDistanceTo( boundaryPointOne );
if ( radius > centerPoint.EuclideanDistanceTo( boundaryPointTwo ) )
{
radius = centerPoint.EuclideanDistanceTo( boundaryPointTwo );
}
//Fixed size radius depending on screen size for the angle
double nonScalingRadius = displayHeight * mmPerDisplayUnit * 0.05;
if (nonScalingRadius > radius)
{
m_HelperPolyLinesToBePainted->SetElement(0, false);
return; //if the arc has a radius that is longer than the shortest arm it should not be painted
}
m_HelperPolyLinesToBePainted->SetElement(0, true);
radius = nonScalingRadius;
double angle = this->GetQuantity( FEATURE_ID_ANGLE );
//Determine from which arm the angle should be drawn
Vector2D v0 = boundaryPointOne - centerPoint;
Vector2D v1 = boundaryPointTwo - centerPoint;
Vector2D v2;
v2[0] = 1.0;
v2[1] = 0.0;
v0[0] = v0[0] * cos( 0.001 ) - v0[1] * sin( 0.001 ); //rotate one arm a bit
v0[1] = v0[0] * sin( 0.001 ) + v0[1] * cos( 0.001 );
v0.Normalize();
v1.Normalize();
double testAngle = acos( v0 * v1 );
//if the rotated arm is closer to the other arm than before it is the one from which we start drawing
//else we start drawing from the other arm (we want to draw in the mathematically positive direction)
if( angle > testAngle )
{
v1[0] = v0[0] * cos( -0.001 ) - v0[1] * sin( -0.001 );
v1[1] = v0[0] * sin( -0.001 ) + v0[1] * cos( -0.001 );
//We determine if the arm is mathematically forward or backward
//assuming we rotate between -pi and pi
if ( acos( v0 * v2 ) > acos ( v1 * v2 ))
{
testAngle = acos( v1 * v2 );
}
else
{
testAngle = -acos( v1 * v2 );
}
}
else
{
v0[0] = v1[0] * cos( -0.001 ) - v1[1] * sin( -0.001 );
v0[1] = v1[0] * sin( -0.001 ) + v1[1] * cos( -0.001 );
//We determine if the arm is mathematically forward or backward
//assuming we rotate between -pi and pi
if ( acos( v0 * v2 ) < acos ( v1 * v2 ))
{
testAngle = acos( v1 * v2 );
}
else
{
testAngle = -acos( v1 * v2 );
}
}
// Generate poly-line with 16 segments
for ( int t = 0; t < 16; ++t )
{
double alpha = (double) t * angle / 15.0 + testAngle;
Point2D polyLinePoint;
polyLinePoint[0] = centerPoint[0] + radius * cos( alpha );
polyLinePoint[1] = centerPoint[1] + radius * sin( alpha );
this->AppendPointToHelperPolyLine(0, polyLinePoint);
}
}
void mitk::PlanarAngle::EvaluateFeaturesInternal()
{
if ( this->GetNumberOfControlPoints() < 3 )
{
// Angle not yet complete.
return;
}
// Calculate angle between lines
const Point2D &p0 = this->GetControlPoint( 0 );
const Point2D &p1 = this->GetControlPoint( 1 );
const Point2D &p2 = this->GetControlPoint( 2 );
Vector2D v0 = p1 - p0;
Vector2D v1 = p1 - p2;
v0.Normalize();
v1.Normalize();
double angle = acos( v0 * v1 );
this->SetQuantity( FEATURE_ID_ANGLE, angle );
}
void mitk::PlanarAngle::PrintSelf( std::ostream& os, itk::Indent indent) const
{
Superclass::PrintSelf( os, indent );
}
+
+bool mitk::PlanarAngle::Equals(const PlanarFigure &other) const
+{
+ const mitk::PlanarAngle* otherAngle = dynamic_cast(&other);
+ if ( otherAngle )
+ {
+ return Superclass::Equals(other);
+ }
+ else
+ {
+ return false;
+ }
+}
diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarAngle.h b/Modules/PlanarFigure/DataManagement/mitkPlanarAngle.h
index 9ed5435fed..ab2a69c49c 100644
--- a/Modules/PlanarFigure/DataManagement/mitkPlanarAngle.h
+++ b/Modules/PlanarFigure/DataManagement/mitkPlanarAngle.h
@@ -1,88 +1,90 @@
/*===================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.
This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.
See LICENSE.txt or http://www.mitk.org for details.
===================================================================*/
#ifndef _MITK_PLANAR_ANGLE_H_
#define _MITK_PLANAR_ANGLE_H_
#include "mitkPlanarFigure.h"
#include
namespace mitk
{
class PlaneGeometry;
/**
* \brief Implementation of PlanarFigure to display an angle
* through three control points
*/
class MitkPlanarFigure_EXPORT PlanarAngle : public PlanarFigure
{
public:
mitkClassMacro( PlanarAngle, PlanarFigure );
itkFactorylessNewMacro(Self)
itkCloneMacro(Self)
public:
// Feature identifiers
const unsigned int FEATURE_ID_ANGLE;
/** \brief Place figure in its minimal configuration (a point at least)
* onto the given 2D geometry.
*
* Must be implemented in sub-classes.
*/
//virtual void Initialize();
/** \brief Angle has 3 control points per definition. */
unsigned int GetMinimumNumberOfControlPoints() const
{
return 3;
}
/** \brief Angle has 3 control points per definition. */
unsigned int GetMaximumNumberOfControlPoints() const
{
return 3;
}
+ virtual bool Equals(const mitk::PlanarFigure& other) const;
+
protected:
PlanarAngle();
virtual ~PlanarAngle();
mitkCloneMacro(Self);
/** \brief Generates the poly-line representation of the planar figure. */
virtual void GeneratePolyLine();
/** \brief Generates the poly-lines that should be drawn the same size regardless of zoom.*/
virtual void GenerateHelperPolyLine(double mmPerDisplayUnit, unsigned int displayHeight);
/** \brief Calculates feature quantities of the planar figure. */
virtual void EvaluateFeaturesInternal();
virtual void PrintSelf( std::ostream &os, itk::Indent indent ) const;
private:
};
} // namespace mitk
#endif //_MITK_PLANAR_ANGLE_H_
diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarArrow.cpp b/Modules/PlanarFigure/DataManagement/mitkPlanarArrow.cpp
index 2f8c2d0892..6185f0e685 100644
--- a/Modules/PlanarFigure/DataManagement/mitkPlanarArrow.cpp
+++ b/Modules/PlanarFigure/DataManagement/mitkPlanarArrow.cpp
@@ -1,117 +1,132 @@
/*===================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.
This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.
See LICENSE.txt or http://www.mitk.org for details.
===================================================================*/
#include "mitkPlanarArrow.h"
#include "mitkPlaneGeometry.h"
mitk::PlanarArrow::PlanarArrow()
: FEATURE_ID_LENGTH( this->AddFeature( "Length", "mm" ) )
{
// Directed arrow has two control points
this->ResetNumberOfControlPoints( 2 );
m_ArrowTipScaleFactor = -1.0;
this->SetNumberOfPolyLines( 1 );
this->SetNumberOfHelperPolyLines( 2 );
// Create helper polyline object (for drawing the orthogonal orientation line)
m_HelperPolyLinesToBePainted->InsertElement( 0, false );
m_HelperPolyLinesToBePainted->InsertElement( 1, false );
}
mitk::PlanarArrow::~PlanarArrow()
{
}
void mitk::PlanarArrow::GeneratePolyLine()
{
this->ClearPolyLines();
this->AppendPointToPolyLine(0, this->GetControlPoint(0));
this->AppendPointToPolyLine(0, this->GetControlPoint(1));
}
void mitk::PlanarArrow::GenerateHelperPolyLine(double mmPerDisplayUnit, unsigned int displayHeight)
{
// Generate helper polyline (orientation line orthogonal to first line)
// if the third control point is currently being set
if ( this->GetNumberOfControlPoints() != 2 )
{
m_HelperPolyLinesToBePainted->SetElement( 0, false );
m_HelperPolyLinesToBePainted->SetElement( 1, false );
return;
}
this->ClearHelperPolyLines();
m_HelperPolyLinesToBePainted->SetElement( 0, true );
m_HelperPolyLinesToBePainted->SetElement( 1, true );
//Fixed size depending on screen size for the angle
float scaleFactor = 0.015;
if ( m_ArrowTipScaleFactor > 0.0 )
{
scaleFactor = m_ArrowTipScaleFactor;
}
double nonScalingLength = displayHeight * mmPerDisplayUnit * scaleFactor;
// Calculate arrow peak
const Point2D p1 = this->GetControlPoint( 0 );
const Point2D p2 = this->GetControlPoint( 1 );
Vector2D n1 = p1 - p2;
n1.Normalize();
double degrees = 100.0;
Vector2D temp;
temp[0] = n1[0] * cos(degrees) - n1[1] * sin(degrees);
temp[1] = n1[0] * sin(degrees) + n1[1] * cos(degrees);
Vector2D temp2;
temp2[0] = n1[0] * cos(-degrees) - n1[1] * sin(-degrees);
temp2[1] = n1[0] * sin(-degrees) + n1[1] * cos(-degrees);
this->AppendPointToHelperPolyLine(0, p1);
this->AppendPointToHelperPolyLine(0, Point2D(p1 - temp * nonScalingLength));
this->AppendPointToHelperPolyLine(1, p1);
this->AppendPointToHelperPolyLine(1, Point2D(p1 - temp2 * nonScalingLength));
}
void mitk::PlanarArrow::EvaluateFeaturesInternal()
{
// Calculate line length
const Point3D &p0 = this->GetWorldControlPoint( 0 );
const Point3D &p1 = this->GetWorldControlPoint( 1 );
double length = p0.EuclideanDistanceTo( p1 );
this->SetQuantity( FEATURE_ID_LENGTH, length );
}
-
void mitk::PlanarArrow::PrintSelf( std::ostream& os, itk::Indent indent) const
{
Superclass::PrintSelf( os, indent );
}
void mitk::PlanarArrow::SetArrowTipScaleFactor( float scale )
{
m_ArrowTipScaleFactor = scale;
}
+
+bool mitk::PlanarArrow::Equals(mitk::PlanarFigure& other)
+{
+ mitk::PlanarArrow* otherArrow = dynamic_cast(&other);
+ if ( otherArrow )
+ {
+ if ( std::abs(this->m_ArrowTipScaleFactor - otherArrow->m_ArrowTipScaleFactor) > mitk::eps)
+ return false;
+
+ return Superclass::Equals(other);
+ }
+ else
+ {
+ return false;
+ }
+}
diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarArrow.h b/Modules/PlanarFigure/DataManagement/mitkPlanarArrow.h
index c0a517da91..9375c529f7 100644
--- a/Modules/PlanarFigure/DataManagement/mitkPlanarArrow.h
+++ b/Modules/PlanarFigure/DataManagement/mitkPlanarArrow.h
@@ -1,97 +1,99 @@
/*===================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.
This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.
See LICENSE.txt or http://www.mitk.org for details.
===================================================================*/
#ifndef _MITK_PLANAR_ARROW_H_
#define _MITK_PLANAR_ARROW_H_
#include "mitkPlanarFigure.h"
#include
namespace mitk
{
class PlaneGeometry;
/**
* \brief Implementation of PlanarFigure representing an arrow
* through two control points
*/
class MitkPlanarFigure_EXPORT PlanarArrow : public PlanarFigure
{
public:
mitkClassMacro( PlanarArrow, PlanarFigure );
itkFactorylessNewMacro(Self)
itkCloneMacro(Self)
/** \brief Place figure in its minimal configuration (a point at least)
* onto the given 2D geometry.
*
* Must be implemented in sub-classes.
*/
//virtual void Initialize();
/** \brief Line has 2 control points per definition. */
unsigned int GetMinimumNumberOfControlPoints() const
{
return 2;
}
/** \brief Line has 2 control points per definition. */
unsigned int GetMaximumNumberOfControlPoints() const
{
return 2;
}
void SetArrowTipScaleFactor( float scale );
+ virtual bool Equals(mitk::PlanarFigure& other);
+
protected:
PlanarArrow();
virtual ~PlanarArrow();
mitkCloneMacro(Self);
/** \brief Generates the poly-line representation of the planar figure. */
virtual void GeneratePolyLine();
/** \brief Generates the poly-lines that should be drawn the same size regardless of zoom.*/
virtual void GenerateHelperPolyLine(double mmPerDisplayUnit, unsigned int displayHeight);
/** \brief Calculates feature quantities of the planar figure. */
virtual void EvaluateFeaturesInternal();
virtual void PrintSelf( std::ostream &os, itk::Indent indent ) const;
// Feature identifiers
const unsigned int FEATURE_ID_LENGTH;
// ScaleFactor defining size of helper-lines in relation to display size
float m_ArrowTipScaleFactor;
private:
};
} // namespace mitk
#endif //_MITK_PLANAR_ARROW_H_
diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarBezierCurve.cpp b/Modules/PlanarFigure/DataManagement/mitkPlanarBezierCurve.cpp
index fe6e689199..cab3d12c23 100644
--- a/Modules/PlanarFigure/DataManagement/mitkPlanarBezierCurve.cpp
+++ b/Modules/PlanarFigure/DataManagement/mitkPlanarBezierCurve.cpp
@@ -1,120 +1,136 @@
/*===================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.
This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.
See LICENSE.txt or http://www.mitk.org for details.
===================================================================*/
#include "mitkPlanarBezierCurve.h"
#include
#include
mitk::PlanarBezierCurve::PlanarBezierCurve()
: FEATURE_ID_LENGTH(Superclass::AddFeature("Length", "mm")),
m_NumberOfSegments(100)
{
this->ResetNumberOfControlPoints(2);
this->SetNumberOfPolyLines(1);
this->SetNumberOfHelperPolyLines(1);
}
mitk::PlanarBezierCurve::~PlanarBezierCurve()
{
}
void mitk::PlanarBezierCurve::EvaluateFeaturesInternal()
{
double length = 0.0;
for (unsigned int i = 0; i < m_NumberOfSegments; ++i)
length += static_cast(m_PolyLines[0][i]).EuclideanDistanceTo(static_cast(m_PolyLines[0][i + 1]));
this->SetQuantity(FEATURE_ID_LENGTH, length);
}
unsigned int mitk::PlanarBezierCurve::GetNumberOfSegments() const
{
return m_NumberOfSegments;
}
void mitk::PlanarBezierCurve::SetNumberOfSegments(unsigned int numSegments)
{
m_NumberOfSegments = std::max(1U, numSegments);
if (this->IsPlaced())
{
this->GeneratePolyLine();
this->Modified();
}
}
void mitk::PlanarBezierCurve::GenerateHelperPolyLine(double, unsigned int)
{
this->ClearHelperPolyLines();
unsigned int numHelperPolyLinePoints = m_ControlPoints.size();
for (unsigned int i = 0; i < numHelperPolyLinePoints; ++i)
this->AppendPointToHelperPolyLine(0, m_ControlPoints[i]);
}
void mitk::PlanarBezierCurve::GeneratePolyLine()
{
this->ClearPolyLines();
const unsigned int numPolyLinePoints = m_NumberOfSegments + 1;
for (unsigned int i = 0; i < numPolyLinePoints; ++i)
this->AppendPointToPolyLine(0, this->ComputeDeCasteljauPoint(i / static_cast(m_NumberOfSegments)));
}
mitk::Point2D mitk::PlanarBezierCurve::ComputeDeCasteljauPoint(mitk::ScalarType t)
{
unsigned int n = m_ControlPoints.size() - 1;
if (m_DeCasteljauPoints.size() != n)
m_DeCasteljauPoints.resize(n);
for (unsigned int i = 0; i < n; ++i)
{
m_DeCasteljauPoints[i][0] = (1 - t) * m_ControlPoints[i][0] + t * m_ControlPoints[i + 1][0];
m_DeCasteljauPoints[i][1] = (1 - t) * m_ControlPoints[i][1] + t * m_ControlPoints[i + 1][1];
}
for (--n; n > 0; --n)
{
for (unsigned int i = 0; i < n; ++i)
{
m_DeCasteljauPoints[i][0] = (1 - t) * m_DeCasteljauPoints[i][0] + t * m_DeCasteljauPoints[i + 1][0];
m_DeCasteljauPoints[i][1] = (1 - t) * m_DeCasteljauPoints[i][1] + t * m_DeCasteljauPoints[i + 1][1];
}
}
return m_DeCasteljauPoints[0];
}
unsigned int mitk::PlanarBezierCurve::GetMaximumNumberOfControlPoints() const
{
return std::numeric_limits::max();
}
unsigned int mitk::PlanarBezierCurve::GetMinimumNumberOfControlPoints() const
{
return 2;
}
bool mitk::PlanarBezierCurve::IsHelperToBePainted(unsigned int index)
{
return index == 0 && m_ControlPoints.size() > 2;
}
+bool mitk::PlanarBezierCurve::Equals(const PlanarFigure &other) const
+{
+ const mitk::PlanarBezierCurve* otherBezierCurve = dynamic_cast(&other);
+ if ( otherBezierCurve )
+ {
+ if( this->m_NumberOfSegments != otherBezierCurve->m_NumberOfSegments )
+ return false;
+ if( this->m_DeCasteljauPoints != otherBezierCurve->m_DeCasteljauPoints )
+ return false;
+ return Superclass::Equals(other);
+ }
+ else
+ {
+ return false;
+ }
+}
diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarBezierCurve.h b/Modules/PlanarFigure/DataManagement/mitkPlanarBezierCurve.h
index dd45e0f207..905c6fc1fe 100644
--- a/Modules/PlanarFigure/DataManagement/mitkPlanarBezierCurve.h
+++ b/Modules/PlanarFigure/DataManagement/mitkPlanarBezierCurve.h
@@ -1,60 +1,62 @@
/*===================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.
This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.
See LICENSE.txt or http://www.mitk.org for details.
===================================================================*/
#ifndef mitkPlanarBezierCurve_h
#define mitkPlanarBezierCurve_h
#include
#include
namespace mitk
{
class MitkPlanarFigure_EXPORT PlanarBezierCurve : public PlanarFigure
{
public:
mitkClassMacro(PlanarBezierCurve, PlanarFigure)
itkFactorylessNewMacro(Self)
itkCloneMacro(Self)
unsigned int GetNumberOfSegments() const;
void SetNumberOfSegments(unsigned int numSegments);
virtual unsigned int GetMaximumNumberOfControlPoints() const;
virtual unsigned int GetMinimumNumberOfControlPoints() const;
virtual bool IsHelperToBePainted(unsigned int index);
const unsigned int FEATURE_ID_LENGTH;
+ virtual bool Equals(const mitk::PlanarFigure& other)const;
+
protected:
PlanarBezierCurve();
virtual ~PlanarBezierCurve();
mitkCloneMacro(Self)
virtual void EvaluateFeaturesInternal();
virtual void GenerateHelperPolyLine(double, unsigned int);
virtual void GeneratePolyLine();
private:
Point2D ComputeDeCasteljauPoint(ScalarType t);
std::vector m_DeCasteljauPoints;
unsigned int m_NumberOfSegments;
};
}
#endif
diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarCircle.cpp b/Modules/PlanarFigure/DataManagement/mitkPlanarCircle.cpp
index 43b80d29e5..d6e248be95 100644
--- a/Modules/PlanarFigure/DataManagement/mitkPlanarCircle.cpp
+++ b/Modules/PlanarFigure/DataManagement/mitkPlanarCircle.cpp
@@ -1,175 +1,188 @@
/*===================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.
This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.
See LICENSE.txt or http://www.mitk.org for details.
===================================================================*/
#include "mitkPlanarCircle.h"
#include "mitkPlaneGeometry.h"
#include "mitkProperties.h"
mitk::PlanarCircle::PlanarCircle()
: FEATURE_ID_RADIUS( this->AddFeature( "Radius", "mm" ) ),
FEATURE_ID_DIAMETER( this->AddFeature( "Diameter", "mm" ) ),
FEATURE_ID_AREA( this->AddFeature( "Area", "mm2" ) ),
m_MinRadius(0),
m_MaxRadius(100),
m_MinMaxRadiusContraintsActive(false)
{
// Circle has two control points
this->ResetNumberOfControlPoints( 2 );
this->SetNumberOfPolyLines( 1 );
this->SetProperty( "closed", mitk::BoolProperty::New(true) );
}
mitk::PlanarCircle::~PlanarCircle()
{
}
bool mitk::PlanarCircle::SetControlPoint( unsigned int index, const Point2D &point, bool /*createIfDoesNotExist*/ )
{
// moving center point
if(index == 0)
{
const Point2D ¢erPoint = GetControlPoint( 0 );
Point2D boundaryPoint = GetControlPoint( 1 );
vnl_vector vec = (point.GetVnlVector() - centerPoint.GetVnlVector());
boundaryPoint[0] += vec[0];
boundaryPoint[1] += vec[1];
PlanarFigure::SetControlPoint( 0, point );
PlanarFigure::SetControlPoint( 1, boundaryPoint );
return true;
}
else if ( index == 1 )
{
PlanarFigure::SetControlPoint( index, point );
return true;
}
return false;
}
mitk::Point2D mitk::PlanarCircle::ApplyControlPointConstraints(unsigned int index, const Point2D &point)
{
if ( this->GetPlaneGeometry() == NULL )
{
return point;
}
Point2D indexPoint;
this->GetPlaneGeometry()->WorldToIndex( point, indexPoint );
BoundingBox::BoundsArrayType bounds = this->GetPlaneGeometry()->GetBounds();
if ( indexPoint[0] < bounds[0] ) { indexPoint[0] = bounds[0]; }
if ( indexPoint[0] > bounds[1] ) { indexPoint[0] = bounds[1]; }
if ( indexPoint[1] < bounds[2] ) { indexPoint[1] = bounds[2]; }
if ( indexPoint[1] > bounds[3] ) { indexPoint[1] = bounds[3]; }
Point2D constrainedPoint;
this->GetPlaneGeometry()->IndexToWorld( indexPoint, constrainedPoint );
if(m_MinMaxRadiusContraintsActive)
{
if( index != 0)
{
const Point2D ¢erPoint = this->GetControlPoint(0);
double euclideanDinstanceFromCenterToPoint1 = centerPoint.EuclideanDistanceTo(point);
Vector2D vectorProjectedPoint;
vectorProjectedPoint = point - centerPoint;
vectorProjectedPoint.Normalize();
if( euclideanDinstanceFromCenterToPoint1 > m_MaxRadius )
{
vectorProjectedPoint *= m_MaxRadius;
constrainedPoint = centerPoint;
constrainedPoint += vectorProjectedPoint;
}
else if( euclideanDinstanceFromCenterToPoint1 < m_MinRadius )
{
vectorProjectedPoint *= m_MinRadius;
constrainedPoint = centerPoint;
constrainedPoint += vectorProjectedPoint;
}
}
}
return constrainedPoint;
}
void mitk::PlanarCircle::GeneratePolyLine()
{
// TODO: start circle at specified boundary point...
// clear the PolyLine-Contrainer, it will be reconstructed soon enough...
this->ClearPolyLines();
const Point2D ¢erPoint = GetControlPoint( 0 );
const Point2D &boundaryPoint = GetControlPoint( 1 );
double radius = centerPoint.EuclideanDistanceTo( boundaryPoint );
// Generate poly-line with 64 segments
for ( int t = 0; t < 64; ++t )
{
double alpha = (double) t * vnl_math::pi / 32.0;
// construct the new polyline point ...
Point2D polyLinePoint;
polyLinePoint[0] = centerPoint[0] + radius * cos( alpha );
polyLinePoint[1] = centerPoint[1] + radius * sin( alpha );
// ... and append it to the PolyLine.
// No extending supported here, so we can set the index of the PolyLineElement to '0'
this->AppendPointToPolyLine(0, polyLinePoint);
}
}
void mitk::PlanarCircle::GenerateHelperPolyLine(double /*mmPerDisplayUnit*/, unsigned int /*displayHeight*/)
{
// A circle does not require a helper object
}
void mitk::PlanarCircle::EvaluateFeaturesInternal()
{
// Calculate circle radius and area
const Point3D &p0 = this->GetWorldControlPoint( 0 );
const Point3D &p1 = this->GetWorldControlPoint( 1 );
double radius = p0.EuclideanDistanceTo( p1 );
double area = vnl_math::pi * radius * radius;
this->SetQuantity( FEATURE_ID_RADIUS, radius );
this->SetQuantity( FEATURE_ID_DIAMETER, 2*radius );
this->SetQuantity( FEATURE_ID_AREA, area );
}
void mitk::PlanarCircle::PrintSelf( std::ostream& os, itk::Indent indent) const
{
Superclass::PrintSelf( os, indent );
}
bool mitk::PlanarCircle::SetCurrentControlPoint( const Point2D& point )
{
if ( m_SelectedControlPoint < 0 )
{
m_SelectedControlPoint = 1;
}
return this->SetControlPoint( m_SelectedControlPoint, point, false);
}
+
+ bool mitk::PlanarCircle::Equals(const PlanarFigure &other) const
+ {
+ const mitk::PlanarCircle* otherCircle = dynamic_cast(&other);
+ if ( otherCircle )
+ {
+ return Superclass::Equals(other);
+ }
+ else
+ {
+ return false;
+ }
+ }
diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarCircle.h b/Modules/PlanarFigure/DataManagement/mitkPlanarCircle.h
index 2839b76f90..8e40da1975 100644
--- a/Modules/PlanarFigure/DataManagement/mitkPlanarCircle.h
+++ b/Modules/PlanarFigure/DataManagement/mitkPlanarCircle.h
@@ -1,138 +1,139 @@
/*===================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.
This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.
See LICENSE.txt or http://www.mitk.org for details.
===================================================================*/
#ifndef _MITK_PLANAR_CIRCLE_H_
#define _MITK_PLANAR_CIRCLE_H_
#include "mitkPlanarFigure.h"
#include
namespace mitk
{
class PlaneGeometry;
/**
* \brief Implementation of PlanarFigure representing a circle
* through two control points
*/
class MitkPlanarFigure_EXPORT PlanarCircle : public PlanarFigure
{
public:
mitkClassMacro( PlanarCircle, PlanarFigure );
itkFactorylessNewMacro(Self)
itkCloneMacro(Self)
/** \brief Place figure in its minimal configuration (a point at least)
* onto the given 2D geometry.
*
* Must be implemented in sub-classes.
*/
//virtual void Initialize();
bool SetControlPoint( unsigned int index, const Point2D &point, bool createIfDoesNotExist = false );
/** \brief Circle has 2 control points per definition. */
unsigned int GetMinimumNumberOfControlPoints() const
{
return 2;
}
/** \brief Circle has 2 control points per definition. */
unsigned int GetMaximumNumberOfControlPoints() const
{
return 2;
}
/** \brief Sets the minimum radius
*/
void SetMinimumRadius( double radius )
{
m_MinRadius = radius;
}
/** \brief Gets the minimum radius
*/
double GetMinimumRadius()
{
return m_MinRadius;
}
/** \brief Sets the maximum radius
*/
void SetMaximumRadius( double radius )
{
m_MaxRadius = radius;
}
/** \brief Gets the minimum radius
*/
double GetMaximumRadius()
{
return m_MaxRadius;
}
void ActivateMinMaxRadiusContstraints( bool active )
{
m_MinMaxRadiusContraintsActive = active;
}
virtual bool SetCurrentControlPoint( const Point2D& point );
+ virtual bool Equals(const mitk::PlanarFigure& other) const;
protected:
PlanarCircle();
virtual ~PlanarCircle();
mitkCloneMacro(Self);
/** \brief Generates the poly-line representation of the planar figure. */
virtual void GeneratePolyLine();
/** \brief Generates the poly-lines that should be drawn the same size regardless of zoom.*/
virtual void GenerateHelperPolyLine(double mmPerDisplayUnit, unsigned int displayHeight);
/** \brief Spatially constrain control points of second (orthogonal) line */
virtual Point2D ApplyControlPointConstraints( unsigned int index, const Point2D& point );
/** \brief Calculates feature quantities of the planar figure. */
virtual void EvaluateFeaturesInternal();
virtual void PrintSelf( std::ostream &os, itk::Indent indent ) const;
// Feature identifiers
const unsigned int FEATURE_ID_RADIUS;
const unsigned int FEATURE_ID_DIAMETER;
const unsigned int FEATURE_ID_AREA;
//Member variables:
double m_MinRadius;
double m_MaxRadius;
bool m_MinMaxRadiusContraintsActive;
private:
};
} // namespace mitk
#endif //_MITK_PLANAR_CIRCLE_H_
diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarCross.cpp b/Modules/PlanarFigure/DataManagement/mitkPlanarCross.cpp
index be15c91a58..7ed28a6cc3 100644
--- a/Modules/PlanarFigure/DataManagement/mitkPlanarCross.cpp
+++ b/Modules/PlanarFigure/DataManagement/mitkPlanarCross.cpp
@@ -1,344 +1,356 @@
/*===================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.
This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.
See LICENSE.txt or http://www.mitk.org for details.
===================================================================*/
#include "mitkPlanarCross.h"
#include "mitkPlaneGeometry.h"
#include "mitkProperties.h"
mitk::PlanarCross::PlanarCross()
: FEATURE_ID_LONGESTDIAMETER( this->AddFeature( "Longest Axis", "mm" ) ),
FEATURE_ID_SHORTAXISDIAMETER( this->AddFeature( "Short Axis", "mm" ) )
{
// Cross has two control points at the beginning
this->ResetNumberOfControlPoints( 2 );
// Create property for SingleLineMode (default: false)
this->SetProperty( "SingleLineMode", mitk::BoolProperty::New( false ) );
// Create helper polyline object (for drawing the orthogonal orientation line)
this->SetNumberOfHelperPolyLines( 1 );
m_HelperPolyLinesToBePainted->InsertElement( 0, false );
}
mitk::PlanarCross::~PlanarCross()
{
}
void mitk::PlanarCross::SetSingleLineMode( bool singleLineMode )
{
this->SetProperty( "SingleLineMode", mitk::BoolProperty::New( singleLineMode ) );
this->Modified();
}
bool mitk::PlanarCross::GetSingleLineMode() const
{
mitk::BoolProperty* singleLineMode = dynamic_cast< mitk::BoolProperty* >(
this->GetProperty( "SingleLineMode" ).GetPointer() );
if ( singleLineMode != NULL )
{
return singleLineMode->GetValue();
}
return false;
}
bool mitk::PlanarCross::ResetOnPointSelect()
{
if ( this->GetSingleLineMode() )
{
// In single line mode --> nothing to reset
return false;
}
switch ( m_SelectedControlPoint )
{
default:
// Nothing selected --> nothing to reset
return false;
case 0:
{
// Control point 0 selected: exchange points 0 and 1
Point2D tmpPoint = this->GetControlPoint( 0 );
this->SetControlPoint( 0, this->GetControlPoint( 1 ) );
this->SetControlPoint( 1, tmpPoint );
// FALLS THROUGH!
}
case 1:
{
// Control point 0 or 1 selected: reset number of control points to two
this->ResetNumberOfControlPoints( 2 );
this->SelectControlPoint( 1 );
return true;
}
case 2:
{
// Control point 2 selected: replace point 0 with point 3 and point 1 with point 2
this->SetControlPoint( 0, this->GetControlPoint( 3 ) );
this->SetControlPoint( 1, this->GetControlPoint( 2 ) );
// Adjust selected control point, reset number of control points to two
this->ResetNumberOfControlPoints( 2 );
this->SelectControlPoint( 1 );
return true;
}
case 3:
{
// Control point 3 selected: replace point 0 with point 2 and point 1 with point 3
this->SetControlPoint( 0, this->GetControlPoint( 2 ) );
this->SetControlPoint( 1, this->GetControlPoint( 3 ) );
// Adjust selected control point, reset number of control points to two
this->ResetNumberOfControlPoints( 2 );
this->SelectControlPoint( 1 );
return true;
}
}
}
unsigned int mitk::PlanarCross::GetNumberOfFeatures() const
{
if ( this->GetSingleLineMode() || (this->GetNumberOfControlPoints() < 4) )
{
return 1;
}
else
{
return 2;
}
}
mitk::Point2D mitk::PlanarCross::ApplyControlPointConstraints( unsigned int index, const Point2D& point )
{
// Apply spatial constraints from superclass and from this class until the resulting constrained
// point converges. Although not an optimal implementation, this iterative approach
// helps to respect both constraints from the superclass and from this class. Without this,
// situations may occur where control points are constrained by the superclass, but again
// moved out of the superclass bounds by the subclass, or vice versa.
unsigned int count = 0; // ensures stop of approach if point does not converge in reasonable time
Point2D confinedPoint = point;
Point2D superclassConfinedPoint;
do
{
superclassConfinedPoint = Superclass::ApplyControlPointConstraints( index, confinedPoint );
confinedPoint = this->InternalApplyControlPointConstraints( index, superclassConfinedPoint );
++count;
} while ( (confinedPoint.EuclideanDistanceTo( superclassConfinedPoint ) > mitk::eps)
&& (count < 32) );
return confinedPoint;
}
mitk::Point2D mitk::PlanarCross::InternalApplyControlPointConstraints( unsigned int index, const Point2D& point )
{
// Apply constraints depending on current interaction state
switch ( index )
{
case 2:
{
// Check if 3rd control point is outside of the range (2D area) defined by the first
// line (via the first two control points); if it is outside, clip it to the bounds
const Point2D p1 = this->GetControlPoint( 0 );
const Point2D p2 = this->GetControlPoint( 1 );
Vector2D n1 = p2 - p1;
n1.Normalize();
Vector2D v1 = point - p1;
double dotProduct = n1 * v1;
Point2D crossPoint = p1 + n1 * dotProduct;;
Vector2D crossVector = point - crossPoint;
if ( dotProduct < 0.0 )
{
// Out-of-bounds on the left: clip point to left boundary
return (p1 + crossVector);
}
else if ( dotProduct > p2.EuclideanDistanceTo( p1 ) )
{
// Out-of-bounds on the right: clip point to right boundary
return (p2 + crossVector);
}
else
{
// Pass back original point
return point;
}
}
case 3:
{
// Constrain 4th control point so that with the 3rd control point it forms
// a line orthogonal to the first line (constraint 1); the 4th control point
// must lie on the opposite side of the line defined by the first two control
// points than the 3rd control point (constraint 2)
const Point2D p1 = this->GetControlPoint( 0 );
const Point2D p2 = this->GetControlPoint( 1 );
const Point2D p3 = this->GetControlPoint( 2 );
// Calculate distance of original point from orthogonal line the corrected
// point should lie on to project the point onto this line
Vector2D n1 = p2 - p1;
n1.Normalize();
Vector2D v1 = point - p3;
double dotProduct1 = n1 * v1;
Point2D pointOnLine = point - n1 * dotProduct1;
// Project new point onto line [p1, p2]
Vector2D v2 = pointOnLine - p1;
double dotProduct2 = n1 * v2;
Point2D crossingPoint = p1 + n1 * dotProduct2;
// Determine whether the projected point on the line, or the crossing point should be
// used (according to the second constraint in the comment above)
if ( (pointOnLine.SquaredEuclideanDistanceTo( p3 ) > crossingPoint.SquaredEuclideanDistanceTo( p3 ))
&& (pointOnLine.SquaredEuclideanDistanceTo( p3 ) > pointOnLine.SquaredEuclideanDistanceTo( crossingPoint )) )
{
return pointOnLine;
}
else
{
return crossingPoint;
}
}
default:
return point;
}
}
void mitk::PlanarCross::GeneratePolyLine()
{
this->SetNumberOfPolyLines(1);
this->ClearPolyLines();
if (this->GetNumberOfControlPoints() > 2)
this->SetNumberOfPolyLines( 2 );
for (unsigned int i = 0; i < this->GetNumberOfControlPoints(); ++i)
{
if (i < 2)
this->AppendPointToPolyLine(0, this->GetControlPoint(i));
if (i > 1)
this->AppendPointToPolyLine(1, this->GetControlPoint(i));
}
}
void mitk::PlanarCross::GenerateHelperPolyLine(double /*mmPerDisplayUnit*/, unsigned int /*displayHeight*/)
{
// Generate helper polyline (orientation line orthogonal to first line)
// if the third control point is currently being set
if ( this->GetNumberOfControlPoints() != 3 )
{
m_HelperPolyLinesToBePainted->SetElement( 0, false );
return;
}
m_HelperPolyLinesToBePainted->SetElement( 0, true );
this->ClearHelperPolyLines();
// Calculate cross point of first line (p1 to p2) and orthogonal line through
// the third control point (p3)
const Point2D p1 = this->GetControlPoint( 0 );
const Point2D p2 = this->GetControlPoint( 1 );
const Point2D p3 = this->GetControlPoint( 2 );
Vector2D n1 = p2 - p1;
n1.Normalize();
Vector2D v1 = p3 - p1;
Point2D crossPoint = p1 + n1 * (n1 * v1);
Vector2D v2 = crossPoint - p3;
if ( v2.GetNorm() < 1.0 )
{
// If third point is on the first line, draw orthogonal "infinite" line
// through cross point on line
Vector2D v0;
v0[0] = n1[1];
v0[1] = -n1[0];
this->AppendPointToHelperPolyLine(0, Point2D(p3 - v0 * 10000.0));
this->AppendPointToHelperPolyLine(0, Point2D(p3 + v0 * 10000.0));
}
else
{
// Else, draw orthogonal line starting from third point and crossing the
// first line, open-ended only on the other side
this->AppendPointToHelperPolyLine(0, p3);
this->AppendPointToHelperPolyLine(0, Point2D(p3 + v2 * 10000.0));
}
}
void mitk::PlanarCross::EvaluateFeaturesInternal()
{
// Calculate length of first line
const Point3D &p0 = this->GetWorldControlPoint( 0 );
const Point3D &p1 = this->GetWorldControlPoint( 1 );
double l1 = p0.EuclideanDistanceTo( p1 );
// Calculate length of second line
double l2 = 0.0;
if ( !this->GetSingleLineMode() && (this->GetNumberOfControlPoints() > 3) )
{
const Point3D &p2 = this->GetWorldControlPoint( 2 );
const Point3D &p3 = this->GetWorldControlPoint( 3 );
l2 = p2.EuclideanDistanceTo( p3 );
}
double longestDiameter;
double shortAxisDiameter;
if ( l1 > l2 )
{
longestDiameter = l1;
shortAxisDiameter = l2;
}
else
{
longestDiameter = l2;
shortAxisDiameter = l1;
}
this->SetQuantity( FEATURE_ID_LONGESTDIAMETER, longestDiameter );
this->SetQuantity( FEATURE_ID_SHORTAXISDIAMETER, shortAxisDiameter );
}
-
void mitk::PlanarCross::PrintSelf( std::ostream& os, itk::Indent indent) const
{
Superclass::PrintSelf( os, indent );
}
+
+ bool mitk::PlanarCross::Equals(const mitk::PlanarFigure& other) const
+ {
+ const mitk::PlanarCross* otherCross = dynamic_cast(&other);
+ if ( otherCross )
+ {
+ return Superclass::Equals(other);
+ }
+ else
+ {
+ return false;
+ }
+ }
diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarCross.h b/Modules/PlanarFigure/DataManagement/mitkPlanarCross.h
index 217ed8c5ac..83a667e4df 100644
--- a/Modules/PlanarFigure/DataManagement/mitkPlanarCross.h
+++ b/Modules/PlanarFigure/DataManagement/mitkPlanarCross.h
@@ -1,132 +1,133 @@
/*===================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.
This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.
See LICENSE.txt or http://www.mitk.org for details.
===================================================================*/
#ifndef _MITK_PLANAR_CROSS_H_
#define _MITK_PLANAR_CROSS_H_
#include "mitkPlanarFigure.h"
#include
namespace mitk
{
class PlaneGeometry;
/**
* \brief Implementation of PlanarFigure modeling a cross with two orthogonal lines
* on a plane.
*
* The cross consists of two two orthogonal lines, which are defined by four control points
* lying on a plane. The two control points of the first line are freely placable within
* the bounds of the underlying 2D geometry, while the two control points of the second line
* are ensured to meet the following constraints:
*
* 1.) The lines must be orthogonal to each other
* 2.) The second line must lie within the 2D area defined by the first line
* 3.) The two lines must intersect (at least with their boundaries)
*
* When placing the second line interactively, a graphical helper polyline is provided to the
* user to indicate the position and orthogonal orientation of the line if it would be placed
* at the current mouse position.
*
* When modifying one of the lines by interactively moving its control points, the respective
* other line is deleted and the user is prompted to draw it again.
*
* The class provide a special mode for drawing single lines (SingleLineModeOn/Off); in this
* case, interaction stops after the first line has been placed.
*
* The class provides the lengths of both lines via the "feature" interface, ordered by size.
*
* \sa PlanarFigureMapper2D
*/
class MitkPlanarFigure_EXPORT PlanarCross : public PlanarFigure
{
public:
mitkClassMacro( PlanarCross, PlanarFigure );
itkFactorylessNewMacro(Self)
itkCloneMacro(Self)
/** \brief Indicates whether the PlanarFigure shall represent only a single line instead of an
* orthogonal cross. */
void SetSingleLineMode( bool singleLineMode );
/** \brief Indicates whether the PlanarFigure shall represent only a single line instead of an
* orthogonal cross. */
bool GetSingleLineMode() const;
/** \brief Indicates whether the PlanarFigure shall represent only a single line instead of an
* orthogonal cross. */
itkBooleanMacro( SingleLineMode ); // No need to reimplement; calls SetSingleLineMode()
/** \brief PlanarCross has either two or four control points, depending on the operation mode. */
unsigned int GetMinimumNumberOfControlPoints() const
{
return this->GetSingleLineMode() ? 2 : 4;
}
/** \brief PlanarCross has either two or four control points, depending on the operation mode. */
unsigned int GetMaximumNumberOfControlPoints() const
{
return this->GetSingleLineMode() ? 2 : 4;
}
/** \brief The cross shall be reset to a single line when a control point is selected. */
virtual bool ResetOnPointSelect();
/** \brief Returns the number of features available for this PlanarCross (1 or 2). */
virtual unsigned int GetNumberOfFeatures() const;
+ virtual bool Equals(const mitk::PlanarFigure& other) const;
protected:
PlanarCross();
virtual ~PlanarCross();
mitkCloneMacro(Self);
/** \brief Spatially constrain control points of second (orthogonal) line */
virtual Point2D ApplyControlPointConstraints( unsigned int index, const Point2D& point );
/** \brief Generates the poly-line representation of the planar figure. */
virtual void GeneratePolyLine();
/** \brief Generates the poly-lines that should be drawn the same size regardless of zoom.*/
virtual void GenerateHelperPolyLine(double mmPerDisplayUnit, unsigned int displayHeight);
/** \brief Calculates feature quantities of the planar figure. */
virtual void EvaluateFeaturesInternal();
virtual void PrintSelf( std::ostream &os, itk::Indent indent ) const;
// Feature identifiers
const unsigned int FEATURE_ID_LONGESTDIAMETER;
const unsigned int FEATURE_ID_SHORTAXISDIAMETER;
private:
/** Internal method for applying spatial constraints. */
virtual Point2D InternalApplyControlPointConstraints( unsigned int index, const Point2D& point );
};
} // namespace mitk
#endif //_MITK_PLANAR_CROSS_H_
diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarDoubleEllipse.cpp b/Modules/PlanarFigure/DataManagement/mitkPlanarDoubleEllipse.cpp
index 68dfab03db..5068f00549 100644
--- a/Modules/PlanarFigure/DataManagement/mitkPlanarDoubleEllipse.cpp
+++ b/Modules/PlanarFigure/DataManagement/mitkPlanarDoubleEllipse.cpp
@@ -1,251 +1,270 @@
/*===================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.
This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.
See LICENSE.txt or http://www.mitk.org for details.
===================================================================*/
#include "mitkPlanarDoubleEllipse.h"
#include
#include
mitk::PlanarDoubleEllipse::PlanarDoubleEllipse()
: FEATURE_ID_MAJOR_AXIS(Superclass::AddFeature("Major Axis", "mm")),
FEATURE_ID_MINOR_AXIS(Superclass::AddFeature("Minor Axis", "mm")),
FEATURE_ID_THICKNESS(Superclass::AddFeature("Thickness", "mm")),
m_NumberOfSegments(64),
m_ConstrainCircle(true),
m_ConstrainThickness(true)
{
this->ResetNumberOfControlPoints(4);
this->SetNumberOfPolyLines(2);
this->SetProperty("closed", mitk::BoolProperty::New(true));
}
mitk::PlanarDoubleEllipse::~PlanarDoubleEllipse()
{
}
mitk::Point2D mitk::PlanarDoubleEllipse::ApplyControlPointConstraints(unsigned int index, const Point2D& point)
{
if (index == 2 && !m_ConstrainCircle)
{
Point2D centerPoint = this->GetControlPoint(0);
Vector2D outerMajorVector = this->GetControlPoint(1) - centerPoint;
Vector2D minorDirection;
minorDirection[0] = outerMajorVector[1];
minorDirection[1] = -outerMajorVector[0];
minorDirection.Normalize();
double outerMajorRadius = outerMajorVector.GetNorm();
double innerMajorRadius = (this->GetControlPoint(3) - centerPoint).GetNorm();
ScalarType radius = std::max(outerMajorRadius - innerMajorRadius, std::min(centerPoint.EuclideanDistanceTo(point), outerMajorRadius));
return centerPoint + minorDirection * radius;
}
else if (index == 3 && !m_ConstrainThickness)
{
Point2D centerPoint = this->GetControlPoint(0);
Vector2D outerMajorVector = this->GetControlPoint(1) - centerPoint;
double outerMajorRadius = outerMajorVector.GetNorm();
double outerMinorRadius = (this->GetControlPoint(2) - centerPoint).GetNorm();
ScalarType radius = std::max(outerMajorRadius - outerMinorRadius, std::min(centerPoint.EuclideanDistanceTo(point), outerMajorRadius));
outerMajorVector.Normalize();
return centerPoint - outerMajorVector * radius;
}
return point;
}
void mitk::PlanarDoubleEllipse::EvaluateFeaturesInternal()
{
Point2D centerPoint = this->GetControlPoint(0);
ScalarType outerMajorRadius = centerPoint.EuclideanDistanceTo(this->GetControlPoint(1));
this->SetQuantity(FEATURE_ID_MAJOR_AXIS, 2 * outerMajorRadius);
this->SetQuantity(FEATURE_ID_MINOR_AXIS, 2 * centerPoint.EuclideanDistanceTo(this->GetControlPoint(2)));
this->SetQuantity(FEATURE_ID_THICKNESS, outerMajorRadius - centerPoint.EuclideanDistanceTo(this->GetControlPoint(3)));
}
void mitk::PlanarDoubleEllipse::GenerateHelperPolyLine(double, unsigned int)
{
}
void mitk::PlanarDoubleEllipse::GeneratePolyLine()
{
this->ClearPolyLines();
Point2D centerPoint = this->GetControlPoint(0);
Point2D outerMajorPoint = this->GetControlPoint(1);
Vector2D direction = outerMajorPoint - centerPoint;
direction.Normalize();
const ScalarType deltaAngle = vnl_math::pi / (m_NumberOfSegments / 2);
int start = 0;
int end = m_NumberOfSegments;
if (direction[1] < 0.0)
{
direction[0] = -direction[0];
end = m_NumberOfSegments / 2;
start = -end;
}
vnl_matrix_fixed rotation;
rotation[1][0] = std::sin(std::acos(direction[0]));
rotation[0][0] = direction[0];
rotation[1][1] = direction[0];
rotation[0][1] = -rotation[1][0];
ScalarType outerMajorRadius = centerPoint.EuclideanDistanceTo(outerMajorPoint);
ScalarType outerMinorRadius = centerPoint.EuclideanDistanceTo(this->GetControlPoint(2));
ScalarType innerMajorRadius = centerPoint.EuclideanDistanceTo(this->GetControlPoint(3));
ScalarType innerMinorRadius = innerMajorRadius - (outerMajorRadius - outerMinorRadius);
ScalarType angle;
ScalarType cosAngle;
ScalarType sinAngle;
vnl_vector_fixed vector;
Point2D point;
for (int i = start; i < end; ++i)
{
angle = i * deltaAngle;
cosAngle = std::cos(angle);
sinAngle = std::sin(angle);
vector[0] = outerMajorRadius * cosAngle;
vector[1] = outerMinorRadius * sinAngle;
vector = rotation * vector;
point[0] = centerPoint[0] + vector[0];
point[1] = centerPoint[1] + vector[1];
this->AppendPointToPolyLine(0, point);
vector[0] = innerMajorRadius * cosAngle;
vector[1] = innerMinorRadius * sinAngle;
vector = rotation * vector;
point[0] = centerPoint[0] + vector[0];
point[1] = centerPoint[1] + vector[1];
this->AppendPointToPolyLine(1, point);
}
}
unsigned int mitk::PlanarDoubleEllipse::GetNumberOfSegments() const
{
return m_NumberOfSegments;
}
void mitk::PlanarDoubleEllipse::SetNumberOfSegments(unsigned int numSegments)
{
m_NumberOfSegments = std::max(4U, numSegments);
if (this->IsPlaced())
{
this->GeneratePolyLine();
this->Modified();
}
}
unsigned int mitk::PlanarDoubleEllipse::GetMaximumNumberOfControlPoints() const
{
return 4;
}
unsigned int mitk::PlanarDoubleEllipse::GetMinimumNumberOfControlPoints() const
{
return 4;
}
bool mitk::PlanarDoubleEllipse::SetControlPoint(unsigned int index, const Point2D& point, bool createIfDoesNotExist)
{
switch (index)
{
case 0:
{
Point2D centerPoint = this->GetControlPoint(0);
Vector2D vector = point - centerPoint;
Superclass::SetControlPoint(0, point, createIfDoesNotExist);
Superclass::SetControlPoint(1, this->GetControlPoint(1) + vector, createIfDoesNotExist);
Superclass::SetControlPoint(2, this->GetControlPoint(2) + vector, createIfDoesNotExist);
Superclass::SetControlPoint(3, this->GetControlPoint(3) + vector, createIfDoesNotExist);
break;
}
case 1:
{
Vector2D vector = point - this->GetControlPoint(1);
Superclass::SetControlPoint(1, point, createIfDoesNotExist);
Point2D centerPoint = this->GetControlPoint(0);
Vector2D outerMajorVector = point - centerPoint;
Vector2D outerMinorVector;
outerMinorVector[0] = outerMajorVector[1];
outerMinorVector[1] = -outerMajorVector[0];
if (!m_ConstrainCircle)
{
outerMinorVector.Normalize();
outerMinorVector *= centerPoint.EuclideanDistanceTo(this->GetControlPoint(2));
}
Superclass::SetControlPoint(2, centerPoint + outerMinorVector, createIfDoesNotExist);
Vector2D innerMajorVector = outerMajorVector;
if (!m_ConstrainThickness)
{
innerMajorVector.Normalize();
innerMajorVector *= centerPoint.EuclideanDistanceTo(this->GetControlPoint(3) - vector);
}
Superclass::SetControlPoint(3, centerPoint - innerMajorVector, createIfDoesNotExist);
break;
}
case 2:
{
m_ConstrainCircle = false;
Superclass::SetControlPoint(2, point, createIfDoesNotExist);
break;
}
case 3:
{
m_ConstrainThickness = false;
Superclass::SetControlPoint(3, point, createIfDoesNotExist);
break;
}
default:
return false;
}
return true;
}
+
+ bool mitk::PlanarDoubleEllipse::Equals(const mitk::PlanarFigure& other) const
+ {
+ const mitk::PlanarDoubleEllipse* otherDoubleEllipse = dynamic_cast(&other);
+ if ( otherDoubleEllipse )
+ {
+ if( this->m_ConstrainCircle != otherDoubleEllipse->m_ConstrainCircle)
+ return false;
+ if( this->m_ConstrainThickness != otherDoubleEllipse->m_ConstrainThickness)
+ return false;
+ if( this->m_NumberOfSegments != otherDoubleEllipse->m_NumberOfSegments)
+ return false;
+ return Superclass::Equals(other);
+ }
+ else
+ {
+ return false;
+ }
+ }
diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarDoubleEllipse.h b/Modules/PlanarFigure/DataManagement/mitkPlanarDoubleEllipse.h
index ff67568439..7f42148beb 100644
--- a/Modules/PlanarFigure/DataManagement/mitkPlanarDoubleEllipse.h
+++ b/Modules/PlanarFigure/DataManagement/mitkPlanarDoubleEllipse.h
@@ -1,61 +1,63 @@
/*===================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.
This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.
See LICENSE.txt or http://www.mitk.org for details.
===================================================================*/
#ifndef mitkPlanarDoubleEllipse_h
#define mitkPlanarDoubleEllipse_h
#include
#include
namespace mitk
{
class MitkPlanarFigure_EXPORT PlanarDoubleEllipse : public PlanarFigure
{
public:
mitkClassMacro(PlanarDoubleEllipse, PlanarFigure);
itkFactorylessNewMacro(Self)
itkCloneMacro(Self)
unsigned int GetNumberOfSegments() const;
void SetNumberOfSegments(unsigned int numSegments);
virtual unsigned int GetMaximumNumberOfControlPoints() const;
virtual unsigned int GetMinimumNumberOfControlPoints() const;
virtual bool SetControlPoint(unsigned int index, const Point2D& point, bool createIfDoesNotExist = true);
const unsigned int FEATURE_ID_MAJOR_AXIS;
const unsigned int FEATURE_ID_MINOR_AXIS;
const unsigned int FEATURE_ID_THICKNESS;
+ virtual bool Equals(const mitk::PlanarFigure& other) const;
+
protected:
PlanarDoubleEllipse();
virtual ~PlanarDoubleEllipse();
mitkCloneMacro(Self)
virtual mitk::Point2D ApplyControlPointConstraints(unsigned int index, const Point2D& point);
virtual void EvaluateFeaturesInternal();
virtual void GenerateHelperPolyLine(double, unsigned int);
virtual void GeneratePolyLine();
private:
unsigned int m_NumberOfSegments;
bool m_ConstrainCircle;
bool m_ConstrainThickness;
};
}
#endif
diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarEllipse.cpp b/Modules/PlanarFigure/DataManagement/mitkPlanarEllipse.cpp
index 49ddb0f02d..443e89b7f7 100644
--- a/Modules/PlanarFigure/DataManagement/mitkPlanarEllipse.cpp
+++ b/Modules/PlanarFigure/DataManagement/mitkPlanarEllipse.cpp
@@ -1,280 +1,296 @@
/*===================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.
This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.
See LICENSE.txt or http://www.mitk.org for details.
===================================================================*/
#include
#include "mitkPlanarEllipse.h"
#include "mitkPlaneGeometry.h"
#include "mitkProperties.h"
#include
mitk::PlanarEllipse::PlanarEllipse()
: FEATURE_ID_MAJOR_AXIS(Superclass::AddFeature("Major Axis", "mm")),
FEATURE_ID_MINOR_AXIS(Superclass::AddFeature("Minor Axis", "mm")),
m_MinRadius(0),
m_MaxRadius(100),
m_MinMaxRadiusContraintsActive(false),
m_TreatAsCircle(true)
{
// Ellipse has three control points
this->ResetNumberOfControlPoints( 4 );
this->SetNumberOfPolyLines( 2 );
this->SetProperty( "closed", mitk::BoolProperty::New(true) );
}
mitk::PlanarEllipse::~PlanarEllipse()
{
}
bool mitk::PlanarEllipse::SetControlPoint( unsigned int index, const Point2D &point, bool createIfDoesNotExist )
{
if(index == 0) // moving center point and control points accordingly
{
const Point2D ¢erPoint = GetControlPoint( 0 );
Point2D boundaryPoint1 = GetControlPoint( 1 );
Point2D boundaryPoint2 = GetControlPoint( 2 );
Point2D boundaryPoint3 = GetControlPoint( 3 );
vnl_vector vec = (point.GetVnlVector() - centerPoint.GetVnlVector());
boundaryPoint1[0] += vec[0];
boundaryPoint1[1] += vec[1];
boundaryPoint2[0] += vec[0];
boundaryPoint2[1] += vec[1];
boundaryPoint3[0] += vec[0];
boundaryPoint3[1] += vec[1];
PlanarFigure::SetControlPoint( 0, point, createIfDoesNotExist );
PlanarFigure::SetControlPoint( 1, boundaryPoint1, createIfDoesNotExist );
PlanarFigure::SetControlPoint( 2, boundaryPoint2, createIfDoesNotExist );
PlanarFigure::SetControlPoint( 3, boundaryPoint3, createIfDoesNotExist );
return true;
}
else if (index < 3)
{
PlanarFigure::SetControlPoint( index, point, createIfDoesNotExist );
int otherIndex = index+1;
if (otherIndex > 2)
otherIndex = 1;
const Point2D ¢erPoint = GetControlPoint( 0 );
Point2D otherPoint = GetControlPoint( otherIndex );
Point2D point3 = GetControlPoint( 3 );
Vector2D vec1 = point - centerPoint;
Vector2D vec2;
if (index == 1 && m_TreatAsCircle )
{
float x = vec1[0];
vec2[0] = vec1[1];
vec2[1] = x;
if (index==1)
vec2[0] *= -1;
else
vec2[1] *= -1;
otherPoint = centerPoint+vec2;
PlanarFigure::SetControlPoint( otherIndex, otherPoint, createIfDoesNotExist );
float r = centerPoint.EuclideanDistanceTo(otherPoint);
// adjust additional third control point
Point2D p3 = this->GetControlPoint(3);
Vector2D vec3;
vec3[0] = p3[0]-centerPoint[0];
vec3[1] = p3[1]-centerPoint[1];
if (vec3[0]!=0 || vec3[1]!=0)
{
vec3.Normalize();
vec3 *= r;
}
else
{
vec3[0] = r;
vec3[1] = 0;
}
point3 = centerPoint + vec3;
PlanarFigure::SetControlPoint( 3, point3, createIfDoesNotExist );
}
else if ( vec1.GetNorm() > 0 )
{
float r = centerPoint.EuclideanDistanceTo(otherPoint);
float x = vec1[0];
vec2[0] = vec1[1];
vec2[1] = x;
if (index==1)
vec2[0] *= -1;
else
vec2[1] *= -1;
vec2.Normalize(); vec2 *= r;
if ( vec2.GetNorm() > 0 )
{
otherPoint = centerPoint+vec2;
PlanarFigure::SetControlPoint( otherIndex, otherPoint, createIfDoesNotExist );
}
// adjust third control point
Vector2D vec3 = point3 - centerPoint; vec3.Normalize();
double r1 = centerPoint.EuclideanDistanceTo( GetControlPoint( 1 ) );
double r2 = centerPoint.EuclideanDistanceTo( GetControlPoint( 2 ) );
Point2D newPoint = centerPoint + vec3*std::max(r1, r2);
PlanarFigure::SetControlPoint( 3, newPoint, createIfDoesNotExist );
m_TreatAsCircle = false;
}
return true;
}
else if (index == 3)
{
Point2D centerPoint = GetControlPoint( 0 );
Vector2D vec3 = point - centerPoint; vec3.Normalize();
double r1 = centerPoint.EuclideanDistanceTo( GetControlPoint( 1 ) );
double r2 = centerPoint.EuclideanDistanceTo( GetControlPoint( 2 ) );
Point2D newPoint = centerPoint + vec3*std::max(r1, r2);
PlanarFigure::SetControlPoint( index, newPoint, createIfDoesNotExist );
m_TreatAsCircle = false;
return true;
}
return false;
}
void mitk::PlanarEllipse::PlaceFigure( const mitk::Point2D &point )
{
PlanarFigure::PlaceFigure( point );
m_SelectedControlPoint = 1;
}
mitk::Point2D mitk::PlanarEllipse::ApplyControlPointConstraints(unsigned int index, const Point2D &point)
{
return point;
Point2D indexPoint;
this->GetPlaneGeometry()->WorldToIndex( point, indexPoint );
BoundingBox::BoundsArrayType bounds = this->GetPlaneGeometry()->GetBounds();
if ( indexPoint[0] < bounds[0] ) { indexPoint[0] = bounds[0]; }
if ( indexPoint[0] > bounds[1] ) { indexPoint[0] = bounds[1]; }
if ( indexPoint[1] < bounds[2] ) { indexPoint[1] = bounds[2]; }
if ( indexPoint[1] > bounds[3] ) { indexPoint[1] = bounds[3]; }
Point2D constrainedPoint;
this->GetPlaneGeometry()->IndexToWorld( indexPoint, constrainedPoint );
if(m_MinMaxRadiusContraintsActive)
{
if( index != 0)
{
const Point2D ¢erPoint = this->GetControlPoint(0);
double euclideanDinstanceFromCenterToPoint1 = centerPoint.EuclideanDistanceTo(point);
Vector2D vectorProjectedPoint;
vectorProjectedPoint = point - centerPoint;
vectorProjectedPoint.Normalize();
if( euclideanDinstanceFromCenterToPoint1 > m_MaxRadius )
{
vectorProjectedPoint *= m_MaxRadius;
constrainedPoint = centerPoint;
constrainedPoint += vectorProjectedPoint;
}
else if( euclideanDinstanceFromCenterToPoint1 < m_MinRadius )
{
vectorProjectedPoint *= m_MinRadius;
constrainedPoint = centerPoint;
constrainedPoint += vectorProjectedPoint;
}
}
}
return constrainedPoint;
}
void mitk::PlanarEllipse::GeneratePolyLine()
{
// clear the PolyLine-Contrainer, it will be reconstructed soon enough...
this->ClearPolyLines();
const Point2D ¢erPoint = GetControlPoint( 0 );
const Point2D &boundaryPoint1 = GetControlPoint( 1 );
const Point2D &boundaryPoint2 = GetControlPoint( 2 );
Vector2D dir = boundaryPoint1 - centerPoint; dir.Normalize();
vnl_matrix_fixed rot;
// differentiate between clockwise and counterclockwise rotation
int start = 0;
int end = 64;
if (dir[1]<0)
{
dir[0] = -dir[0];
start = -32;
end = 32;
}
// construct rotation matrix to align ellipse with control point vector
rot[0][0] = dir[0];
rot[1][1] = rot[0][0];
rot[1][0] = sin(acos(rot[0][0]));
rot[0][1] = -rot[1][0];
double radius1 = centerPoint.EuclideanDistanceTo( boundaryPoint1 );
double radius2 = centerPoint.EuclideanDistanceTo( boundaryPoint2 );
// Generate poly-line with 64 segments
for ( int t = start; t < end; ++t )
{
double alpha = (double) t * vnl_math::pi / 32.0;
// construct the new polyline point ...
vnl_vector_fixed< float, 2 > vec;
vec[0] = radius1 * cos( alpha );
vec[1] = radius2 * sin( alpha );
vec = rot*vec;
Point2D polyLinePoint;
polyLinePoint[0] = centerPoint[0] + vec[0];
polyLinePoint[1] = centerPoint[1] + vec[1];
// ... and append it to the PolyLine.
// No extending supported here, so we can set the index of the PolyLineElement to '0'
this->AppendPointToPolyLine(0, polyLinePoint);
}
this->AppendPointToPolyLine(1, centerPoint);
this->AppendPointToPolyLine(1, this->GetControlPoint(3));
}
void mitk::PlanarEllipse::GenerateHelperPolyLine(double /*mmPerDisplayUnit*/, unsigned int /*displayHeight*/)
{
// A circle does not require a helper object
}
void mitk::PlanarEllipse::EvaluateFeaturesInternal()
{
Point2D centerPoint = this->GetControlPoint(0);
this->SetQuantity(FEATURE_ID_MAJOR_AXIS, 2 * centerPoint.EuclideanDistanceTo(this->GetControlPoint(1)));
this->SetQuantity(FEATURE_ID_MINOR_AXIS, 2 * centerPoint.EuclideanDistanceTo(this->GetControlPoint(2)));
}
void mitk::PlanarEllipse::PrintSelf( std::ostream& os, itk::Indent indent) const
{
Superclass::PrintSelf( os, indent );
}
+
+ bool mitk::PlanarEllipse::Equals(const mitk::PlanarFigure& other) const
+ {
+ const mitk::PlanarEllipse* otherEllipse = dynamic_cast(&other);
+ if ( otherEllipse )
+ {
+ if(this->m_TreatAsCircle != otherEllipse->m_TreatAsCircle)
+ return false;
+
+ return Superclass::Equals(other);
+ }
+ else
+ {
+ return false;
+ }
+ }
diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarEllipse.h b/Modules/PlanarFigure/DataManagement/mitkPlanarEllipse.h
index ea900bf835..5654e737cb 100644
--- a/Modules/PlanarFigure/DataManagement/mitkPlanarEllipse.h
+++ b/Modules/PlanarFigure/DataManagement/mitkPlanarEllipse.h
@@ -1,140 +1,142 @@
/*===================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.
This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.
See LICENSE.txt or http://www.mitk.org for details.
===================================================================*/
#ifndef _MITK_PLANAR_ELLIPSE_H_
#define _MITK_PLANAR_ELLIPSE_H_
#include "mitkPlanarFigure.h"
#include
namespace mitk
{
class PlaneGeometry;
/**
* \brief Implementation of PlanarFigure representing a circle
* through two control points
*/
class MitkPlanarFigure_EXPORT PlanarEllipse : public PlanarFigure
{
public:
mitkClassMacro( PlanarEllipse, PlanarFigure )
itkFactorylessNewMacro(Self)
itkCloneMacro(Self)
/** \brief Place figure in its minimal configuration (a point at least)
* onto the given 2D geometry.
*
* Must be implemented in sub-classes.
*/
virtual void PlaceFigure( const Point2D &point );
bool SetControlPoint( unsigned int index, const Point2D &point, bool createIfDoesNotExist = true );
/** \brief Ellipse has 3 control points per definition. */
unsigned int GetMinimumNumberOfControlPoints() const
{
return 4;
}
/** \brief Ellipse has 3 control points per definition. */
unsigned int GetMaximumNumberOfControlPoints() const
{
return 4;
}
/** \brief Sets the minimum radius
*/
void SetMinimumRadius( double radius )
{
m_MinRadius = radius;
}
/** \brief Gets the minimum radius
*/
double GetMinimumRadius()
{
return m_MinRadius;
}
/** \brief Sets the maximum radius
*/
void SetMaximumRadius( double radius )
{
m_MaxRadius = radius;
}
/** \brief Gets the minimum radius
*/
double GetMaximumRadius()
{
return m_MaxRadius;
}
void ActivateMinMaxRadiusContstraints( bool active )
{
m_MinMaxRadiusContraintsActive = active;
}
/** \brief Treat ellipse as circle (equal radii)
*/
void SetTreatAsCircle( bool active )
{
m_TreatAsCircle = active;
}
+ virtual bool Equals(const mitk::PlanarFigure& other) const;
+
const unsigned int FEATURE_ID_MAJOR_AXIS;
const unsigned int FEATURE_ID_MINOR_AXIS;
protected:
PlanarEllipse();
virtual ~PlanarEllipse();
mitkCloneMacro(Self);
/** \brief Generates the poly-line representation of the planar figure. */
virtual void GeneratePolyLine();
/** \brief Generates the poly-lines that should be drawn the same size regardless of zoom.*/
virtual void GenerateHelperPolyLine(double mmPerDisplayUnit, unsigned int displayHeight);
/** \brief Spatially constrain control points of second (orthogonal) line */
virtual Point2D ApplyControlPointConstraints( unsigned int index, const Point2D& point );
/** \brief Calculates feature quantities of the planar figure. */
virtual void EvaluateFeaturesInternal();
virtual void PrintSelf( std::ostream &os, itk::Indent indent ) const;
//Member variables:
double m_MinRadius;
double m_MaxRadius;
bool m_MinMaxRadiusContraintsActive;
bool m_TreatAsCircle;
private:
};
} // namespace mitk
#endif //_MITK_PLANAR_ELLIPSE_H_
diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarFigure.cpp b/Modules/PlanarFigure/DataManagement/mitkPlanarFigure.cpp
index 2b4fdbbbb0..5d69c365d6 100644
--- a/Modules/PlanarFigure/DataManagement/mitkPlanarFigure.cpp
+++ b/Modules/PlanarFigure/DataManagement/mitkPlanarFigure.cpp
@@ -1,780 +1,895 @@
/*===================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.
This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.
See LICENSE.txt or http://www.mitk.org for details.
===================================================================*/
#include "mitkPlanarFigure.h"
#include "mitkPlaneGeometry.h"
#include
#include
#include
#ifdef __GNUC__
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#elif __clang__
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
#elif _MSC_VER
# pragma warning (push)
# pragma warning (disable: 4996)
#endif
mitk::PlanarFigure::PolyLineElement::PolyLineElement(Point2D point, int index)
: Point(point),
Index(index)
{
}
mitk::PlanarFigure::PolyLineElement::PolyLineElement(const Point2D& point)
: Point(point),
Index(-1)
{
}
mitk::PlanarFigure::PolyLineElement::PolyLineElement(const PolyLineElement &other)
: Point(other.Point),
Index(other.Index)
{
}
mitk::PlanarFigure::PolyLineElement& mitk::PlanarFigure::PolyLineElement::operator=(const PolyLineElement &other)
{
if (this != &other)
{
Point = other.Point;
Index = other.Index;
}
return *this;
}
mitk::PlanarFigure::PolyLineElement::operator mitk::Point2D&()
{
return Point;
}
mitk::PlanarFigure::PolyLineElement::operator const mitk::Point2D&() const
{
return Point;
}
mitk::PlanarFigure::PlanarFigure()
: m_SelectedControlPoint( -1 ),
m_PreviewControlPointVisible( false ),
m_FigurePlaced( false ),
m_PlaneGeometry( NULL ),
m_PolyLineUpToDate(false),
m_HelperLinesUpToDate(false),
m_FeaturesUpToDate(false),
m_FeaturesMTime( 0 )
{
m_HelperPolyLinesToBePainted = BoolContainerType::New();
m_DisplaySize.first = 0.0;
m_DisplaySize.second = 0;
this->SetProperty( "closed", mitk::BoolProperty::New( false ) );
// Currently only single-time-step geometries are supported
this->InitializeTimeGeometry( 1 );
}
mitk::PlanarFigure::~PlanarFigure()
{
}
mitk::PlanarFigure::PlanarFigure(const Self& other)
: BaseData(other),
m_ControlPoints(other.m_ControlPoints),
m_NumberOfControlPoints(other.m_NumberOfControlPoints),
m_SelectedControlPoint(other.m_SelectedControlPoint),
m_PolyLines(other.m_PolyLines),
m_HelperPolyLines(other.m_HelperPolyLines),
m_HelperPolyLinesToBePainted(other.m_HelperPolyLinesToBePainted->Clone()),
m_PreviewControlPoint(other.m_PreviewControlPoint),
m_PreviewControlPointVisible(other.m_PreviewControlPointVisible),
m_FigurePlaced(other.m_FigurePlaced),
m_PlaneGeometry(other.m_PlaneGeometry), // do not clone since SetPlaneGeometry() doesn't clone either
m_PolyLineUpToDate(other.m_PolyLineUpToDate),
m_HelperLinesUpToDate(other.m_HelperLinesUpToDate),
m_FeaturesUpToDate(other.m_FeaturesUpToDate),
m_Features(other.m_Features),
m_FeaturesMTime(other.m_FeaturesMTime),
m_DisplaySize(other.m_DisplaySize)
{
}
void mitk::PlanarFigure::SetPlaneGeometry( mitk::PlaneGeometry *geometry )
{
this->SetGeometry( geometry );
m_PlaneGeometry = dynamic_cast(GetGeometry(0));//geometry;
}
const mitk::PlaneGeometry *mitk::PlanarFigure::GetPlaneGeometry() const
{
return m_PlaneGeometry;
}
bool mitk::PlanarFigure::IsClosed() const
{
mitk::BoolProperty* closed = dynamic_cast< mitk::BoolProperty* >( this->GetProperty( "closed" ).GetPointer() );
if ( closed != NULL )
{
return closed->GetValue();
}
return false;
}
void mitk::PlanarFigure::PlaceFigure( const mitk::Point2D& point )
{
for ( unsigned int i = 0; i < this->GetNumberOfControlPoints(); ++i )
{
m_ControlPoints.push_back( this->ApplyControlPointConstraints( i, point ) );
}
m_FigurePlaced = true;
m_SelectedControlPoint = 1;
}
bool mitk::PlanarFigure::AddControlPoint( const mitk::Point2D& point, int position )
{
// if we already have the maximum number of control points, do nothing
if ( m_NumberOfControlPoints < this->GetMaximumNumberOfControlPoints() )
{
// if position has not been defined or position would be the last control point, just append the new one
// we also append a new point if we click onto the line between the first two control-points if the second control-point is selected
// -> special case for PlanarCross
if ( position == -1 || position > (int)m_NumberOfControlPoints-1 || (position == 1 && m_SelectedControlPoint == 2) )
{
if ( m_ControlPoints.size() > this->GetMaximumNumberOfControlPoints()-1 )
{
// get rid of deprecated control points in the list. This is necessary
// as ::ResetNumberOfControlPoints() only sets the member, does not resize the list!
m_ControlPoints.resize( this->GetNumberOfControlPoints() );
}
m_ControlPoints.push_back( this->ApplyControlPointConstraints( m_NumberOfControlPoints, point ) );
m_SelectedControlPoint = m_NumberOfControlPoints;
}
else
{
// insert the point at the given position and set it as selected point
ControlPointListType::iterator iter = m_ControlPoints.begin() + position;
m_ControlPoints.insert( iter, this->ApplyControlPointConstraints( position, point ) );
for( unsigned int i = 0; i < m_ControlPoints.size(); ++i )
{
if( point == m_ControlPoints.at(i) )
{
m_SelectedControlPoint = i;
}
}
}
// polylines & helperpolylines need to be repainted
m_PolyLineUpToDate = false;
m_HelperLinesUpToDate = false;
m_FeaturesUpToDate = false;
// one control point more
++m_NumberOfControlPoints;
return true;
}
else
{
return false;
}
}
bool mitk::PlanarFigure::SetControlPoint( unsigned int index, const Point2D& point, bool createIfDoesNotExist )
{
bool controlPointSetCorrectly = false;
if (createIfDoesNotExist)
{
if ( m_NumberOfControlPoints <= index )
{
m_ControlPoints.push_back( this->ApplyControlPointConstraints( index, point ) );
m_NumberOfControlPoints++;
}
else
{
m_ControlPoints.at( index ) = this->ApplyControlPointConstraints( index, point );
}
controlPointSetCorrectly = true;
}
else if ( index < m_NumberOfControlPoints )
{
m_ControlPoints.at( index ) = this->ApplyControlPointConstraints( index, point );
controlPointSetCorrectly = true;
}
else
{
return false;
}
if ( controlPointSetCorrectly )
{
m_PolyLineUpToDate = false;
m_HelperLinesUpToDate = false;
m_FeaturesUpToDate = false;
}
return controlPointSetCorrectly;
}
bool mitk::PlanarFigure::SetCurrentControlPoint( const Point2D& point )
{
if ( (m_SelectedControlPoint < 0) || (m_SelectedControlPoint >= (int)m_NumberOfControlPoints) )
{
return false;
}
return this->SetControlPoint(m_SelectedControlPoint, point, false);
}
unsigned int mitk::PlanarFigure::GetNumberOfControlPoints() const
{
return m_NumberOfControlPoints;
}
bool mitk::PlanarFigure::SelectControlPoint( unsigned int index )
{
if ( index < this->GetNumberOfControlPoints() )
{
m_SelectedControlPoint = index;
return true;
}
else
{
return false;
}
}
bool mitk::PlanarFigure::DeselectControlPoint()
{
bool wasSelected = ( m_SelectedControlPoint != -1);
m_SelectedControlPoint = -1;
return wasSelected;
}
void mitk::PlanarFigure::SetPreviewControlPoint( const Point2D& point )
{
m_PreviewControlPoint = point;
m_PreviewControlPointVisible = true;
}
void mitk::PlanarFigure::ResetPreviewContolPoint()
{
m_PreviewControlPointVisible = false;
}
mitk::Point2D mitk::PlanarFigure::GetPreviewControlPoint()
{
return m_PreviewControlPoint;
}
bool mitk::PlanarFigure::IsPreviewControlPointVisible()
{
return m_PreviewControlPointVisible;
}
mitk::Point2D mitk::PlanarFigure::GetControlPoint( unsigned int index ) const
{
if ( index < m_NumberOfControlPoints )
{
return m_ControlPoints.at( index );
}
itkExceptionMacro( << "GetControlPoint(): Invalid index!" );
}
mitk::Point3D mitk::PlanarFigure::GetWorldControlPoint( unsigned int index ) const
{
Point3D point3D;
if ( (m_PlaneGeometry != NULL) && (index < m_NumberOfControlPoints) )
{
m_PlaneGeometry->Map( m_ControlPoints.at( index ), point3D );
return point3D;
}
itkExceptionMacro( << "GetWorldControlPoint(): Invalid index!" );
}
const mitk::PlanarFigure::PolyLineType
mitk::PlanarFigure::GetPolyLine(unsigned int index)
{
mitk::PlanarFigure::PolyLineType polyLine;
if ( index > m_PolyLines.size() || !m_PolyLineUpToDate )
{
this->GeneratePolyLine();
m_PolyLineUpToDate = true;
}
return m_PolyLines.at( index );;
}
const mitk::PlanarFigure::PolyLineType
mitk::PlanarFigure::GetPolyLine(unsigned int index) const
{
return m_PolyLines.at( index );
}
void mitk::PlanarFigure::ClearPolyLines()
{
for ( std::vector::size_type i=0; iGenerateHelperPolyLine(mmPerDisplayUnit, displayHeight);
m_HelperLinesUpToDate = true;
// store these parameters to be able to check next time if somebody zoomed in or out
m_DisplaySize.first = mmPerDisplayUnit;
m_DisplaySize.second = displayHeight;
}
helperPolyLine = m_HelperPolyLines.at(index);
}
return helperPolyLine;
}
void mitk::PlanarFigure::ClearHelperPolyLines()
{
for ( std::vector::size_type i=0; iGeneratePolyLine();
}
this->EvaluateFeaturesInternal();
m_FeaturesUpToDate = true;
}
}
void mitk::PlanarFigure::UpdateOutputInformation()
{
// Bounds are NOT calculated here, since the PlaneGeometry defines a fixed
// frame (= bounds) for the planar figure.
Superclass::UpdateOutputInformation();
this->GetTimeGeometry()->Update();
}
void mitk::PlanarFigure::SetRequestedRegionToLargestPossibleRegion()
{
}
bool mitk::PlanarFigure::RequestedRegionIsOutsideOfTheBufferedRegion()
{
return false;
}
bool mitk::PlanarFigure::VerifyRequestedRegion()
{
return true;
}
void mitk::PlanarFigure::SetRequestedRegion(const itk::DataObject * /*data*/ )
{
}
void mitk::PlanarFigure::ResetNumberOfControlPoints( int numberOfControlPoints )
{
// DO NOT resize the list here, will cause crash!!
m_NumberOfControlPoints = numberOfControlPoints;
}
mitk::Point2D mitk::PlanarFigure::ApplyControlPointConstraints( unsigned int /*index*/, const Point2D& point )
{
if ( m_PlaneGeometry == NULL )
{
return point;
}
Point2D indexPoint;
m_PlaneGeometry->WorldToIndex( point, indexPoint );
BoundingBox::BoundsArrayType bounds = m_PlaneGeometry->GetBounds();
if ( indexPoint[0] < bounds[0] ) { indexPoint[0] = bounds[0]; }
if ( indexPoint[0] > bounds[1] ) { indexPoint[0] = bounds[1]; }
if ( indexPoint[1] < bounds[2] ) { indexPoint[1] = bounds[2]; }
if ( indexPoint[1] > bounds[3] ) { indexPoint[1] = bounds[3]; }
Point2D constrainedPoint;
m_PlaneGeometry->IndexToWorld( indexPoint, constrainedPoint );
return constrainedPoint;
}
unsigned int mitk::PlanarFigure::AddFeature( const char *featureName, const char *unitName )
{
unsigned int index = m_Features.size();
Feature newFeature( featureName, unitName );
m_Features.push_back( newFeature );
return index;
}
void mitk::PlanarFigure::SetFeatureName( unsigned int index, const char *featureName )
{
if ( index < m_Features.size() )
{
m_Features[index].Name = featureName;
}
}
void mitk::PlanarFigure::SetFeatureUnit( unsigned int index, const char *unitName )
{
if ( index < m_Features.size() )
{
m_Features[index].Unit = unitName;
}
}
void mitk::PlanarFigure::SetQuantity( unsigned int index, double quantity )
{
if ( index < m_Features.size() )
{
m_Features[index].Quantity = quantity;
}
}
void mitk::PlanarFigure::ActivateFeature( unsigned int index )
{
if ( index < m_Features.size() )
{
m_Features[index].Active = true;
}
}
void mitk::PlanarFigure::DeactivateFeature( unsigned int index )
{
if ( index < m_Features.size() )
{
m_Features[index].Active = false;
}
}
void mitk::PlanarFigure::InitializeTimeGeometry( unsigned int timeSteps )
{
mitk::PlaneGeometry::Pointer geometry2D = mitk::PlaneGeometry::New();
geometry2D->Initialize();
// The geometry is propagated automatically to all time steps,
// if EvenlyTimed is true...
ProportionalTimeGeometry::Pointer timeGeometry = ProportionalTimeGeometry::New();
timeGeometry->Initialize(geometry2D, timeSteps);
SetTimeGeometry(timeGeometry);
}
void mitk::PlanarFigure::PrintSelf( std::ostream& os, itk::Indent indent) const
{
Superclass::PrintSelf( os, indent );
os << indent << this->GetNameOfClass() << ":\n";
if (this->IsClosed())
os << indent << "This figure is closed\n";
else
os << indent << "This figure is not closed\n";
os << indent << "Minimum number of control points: " << this->GetMinimumNumberOfControlPoints() << std::endl;
os << indent << "Maximum number of control points: " << this->GetMaximumNumberOfControlPoints() << std::endl;
os << indent << "Current number of control points: " << this->GetNumberOfControlPoints() << std::endl;
os << indent << "Control points:" << std::endl;
for ( unsigned int i = 0; i < this->GetNumberOfControlPoints(); ++i )
{
//os << indent.GetNextIndent() << i << ": " << m_ControlPoints->ElementAt( i ) << std::endl;
os << indent.GetNextIndent() << i << ": " << m_ControlPoints.at( i ) << std::endl;
}
os << indent << "Geometry:\n";
this->GetPlaneGeometry()->Print(os, indent.GetNextIndent());
}
unsigned short mitk::PlanarFigure::GetPolyLinesSize()
{
if ( !m_PolyLineUpToDate )
{
this->GeneratePolyLine();
m_PolyLineUpToDate = true;
}
return m_PolyLines.size();
}
unsigned short mitk::PlanarFigure::GetHelperPolyLinesSize()
{
return m_HelperPolyLines.size();
}
bool mitk::PlanarFigure::IsHelperToBePainted(unsigned int index)
{
return m_HelperPolyLinesToBePainted->GetElement( index );
}
bool mitk::PlanarFigure::ResetOnPointSelect()
{
return false;
}
void mitk::PlanarFigure::RemoveControlPoint( unsigned int index )
{
if ( index > m_ControlPoints.size() )
return;
if ( (m_ControlPoints.size() -1) < this->GetMinimumNumberOfControlPoints() )
return;
ControlPointListType::iterator iter;
iter = m_ControlPoints.begin() + index;
m_ControlPoints.erase( iter );
m_PolyLineUpToDate = false;
m_HelperLinesUpToDate = false;
m_FeaturesUpToDate = false;
--m_NumberOfControlPoints;
}
void mitk::PlanarFigure::RemoveLastControlPoint()
{
RemoveControlPoint( m_ControlPoints.size()-1 );
}
void mitk::PlanarFigure::DeepCopy(Self::Pointer oldFigure)
{
//DeepCopy only same types of planar figures
//Notice to get typeid polymorph you have to use the *operator
if(typeid(*oldFigure) != typeid(*this))
{
itkExceptionMacro( << "DeepCopy(): Inconsistent type of source (" << typeid(*oldFigure).name() << ") and destination figure (" << typeid(*this).name() << ")!" );
return;
}
m_ControlPoints.clear();
this->ClearPolyLines();
this->ClearHelperPolyLines();
// clone base data members
SetPropertyList(oldFigure->GetPropertyList()->Clone());
/// deep copy members
m_FigurePlaced = oldFigure->m_FigurePlaced;
m_SelectedControlPoint = oldFigure->m_SelectedControlPoint;
m_FeaturesMTime = oldFigure->m_FeaturesMTime;
m_Features = oldFigure->m_Features;
m_NumberOfControlPoints = oldFigure->m_NumberOfControlPoints;
//copy geometry 2D of planar figure
PlaneGeometry::Pointer affineGeometry = oldFigure->m_PlaneGeometry->Clone();
SetPlaneGeometry(affineGeometry.GetPointer());
for(unsigned long index=0; index < oldFigure->GetNumberOfControlPoints(); index++)
{
m_ControlPoints.push_back( oldFigure->GetControlPoint( index ));
}
//After setting the control points we can generate the polylines
this->GeneratePolyLine();
}
void mitk::PlanarFigure::SetNumberOfPolyLines( unsigned int numberOfPolyLines )
{
m_PolyLines.resize(numberOfPolyLines);
}
void mitk::PlanarFigure::SetNumberOfHelperPolyLines( unsigned int numberOfHerlperPolyLines )
{
m_HelperPolyLines.resize(numberOfHerlperPolyLines);
}
void mitk::PlanarFigure::AppendPointToPolyLine( unsigned int index, PolyLineElement element )
{
if ( index < m_PolyLines.size() )
{
if(element.Index == -1)
element.Index = m_PolyLines[index].size();
m_PolyLines[index].push_back(element);
m_PolyLineUpToDate = false;
}
else
{
MITK_ERROR << "Tried to add point to PolyLine " << index+1 << ", although only " << m_PolyLines.size() << " exists";
}
}
void mitk::PlanarFigure::AppendPointToHelperPolyLine( unsigned int index, PolyLineElement element )
{
if ( index < m_HelperPolyLines.size() )
{
if(element.Index == -1)
element.Index = m_HelperPolyLines[index].size();
m_HelperPolyLines[index].push_back(element);
m_HelperLinesUpToDate = false;
}
else
{
MITK_ERROR << "Tried to add point to HelperPolyLine " << index+1 << ", although only " << m_HelperPolyLines.size() << " exists";
}
}
#ifdef __GNUC__
# pragma GCC diagnostic error "-Wdeprecated-declarations"
#elif __clang__
# pragma clang diagnostic error "-Wdeprecated-declarations"
#elif _MSC_VER
# pragma warning (pop)
#endif
+
+bool mitk::PlanarFigure::Equals(const mitk::PlanarFigure& other) const
+{
+ //check geometries
+ if ( this->GetPlaneGeometry() && other.GetPlaneGeometry() )
+ {
+ if( !Equal(*(this->GetPlaneGeometry()), *(other.GetPlaneGeometry()), mitk::eps, true))
+ {
+ return false;
+ }
+ }
+ else
+ {
+ MITK_ERROR << "Geometry is not equal";
+ return false;
+ }
+
+ //check isPlaced member
+ if ( this->m_FigurePlaced != other.m_FigurePlaced)
+ {
+ MITK_ERROR << "Is_Placed is not equal";
+ return false;
+ }
+
+ //check closed property
+ if (this->IsClosed() != other.IsClosed())
+ {
+ MITK_ERROR << "Is_closed is not equal";
+ return false;
+ }
+
+ //check poly lines
+ if (this->m_PolyLines.size() != other.m_PolyLines.size())
+ {
+ return false;
+ }
+ else
+ {
+ std::vector::const_iterator itThis = this->m_PolyLines.begin();
+ std::vector::const_iterator itEnd = this->m_PolyLines.end();
+ std::vector::const_iterator itOther = other.m_PolyLines.begin();
+
+ while( itThis != itEnd )
+ {
+ if(itThis->size() != itOther->size())
+ return false;
+ else
+ {
+ PolyLineType::const_iterator itLineThis = itThis->begin();
+ PolyLineType::const_iterator itLineEnd = itThis->end();
+ PolyLineType::const_iterator itLineOther = itOther->begin();
+
+ while(itLineThis != itLineEnd)
+ {
+ Point2D p1 = *itLineThis;
+ Point2D p2 = *itLineOther;
+ ScalarType delta = fabs(p1[0]-p2[0])+fabs(p1[1]-p2[1]);
+ if(delta > .001)
+ {
+ MITK_ERROR << "Poly line is not equal";
+ MITK_ERROR << p1 << "/" << p2;
+ return false;
+ }
+
+ ++itLineThis;
+ ++itLineOther;
+ }
+ }
+ ++itThis;
+ ++itOther;
+ }
+ }
+
+ //check features
+ if (this->GetNumberOfFeatures() != other.GetNumberOfFeatures())
+ {
+ MITK_ERROR << "Number of Features is Different";
+ return false;
+ }
+ else
+ {
+ std::vector::const_iterator itThis = m_Features.begin();
+ std::vector::const_iterator itEnd = m_Features.end();
+ std::vector::const_iterator itOther = other.m_Features.begin();
+
+ while(itThis != itEnd)
+ {
+ if(( itThis->Quantity - itOther->Quantity) > .001 )
+ {
+ MITK_ERROR << "Quantity is Different" << itThis->Quantity << "/" << itOther->Quantity;
+ return false;
+ }
+ if( itThis->Unit.compare(itOther->Unit) != 0 )
+ {
+ MITK_ERROR << "Unit is Different" << itThis->Unit << "/" << itOther->Unit;
+ return false;
+ }
+ if( itThis->Name.compare(itOther->Name) != 0 )
+ {
+ MITK_ERROR << "Name of Measure is Different " << itThis->Name << "/ " << itOther->Name;;
+ return false;
+ }
+
+ ++itThis;
+ ++itOther;
+ }
+ }
+
+ return true;
+}
+
+bool mitk::Equal( const mitk::PlanarFigure& leftHandSide, const mitk::PlanarFigure& rightHandSide, ScalarType eps, bool verbose )
+{
+ return leftHandSide.Equals(rightHandSide);
+}
diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarFigure.h b/Modules/PlanarFigure/DataManagement/mitkPlanarFigure.h
index 210646a320..b781f8d13d 100644
--- a/Modules/PlanarFigure/DataManagement/mitkPlanarFigure.h
+++ b/Modules/PlanarFigure/DataManagement/mitkPlanarFigure.h
@@ -1,434 +1,441 @@
/*===================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.
This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.
See LICENSE.txt or http://www.mitk.org for details.
===================================================================*/
#ifndef _MITK_PLANAR_FIGURE_H_
#define _MITK_PLANAR_FIGURE_H_
#include
#include "mitkBaseData.h"
#include "mitkCommon.h"
#include
namespace mitk
{
class PlaneGeometry;
/**
* \brief Base-class for geometric planar (2D) figures, such as
* lines, circles, rectangles, polygons, etc.
*
* \warning Currently does not support time-resolved data handling
*
* Behavior and appearance of PlanarFigures are controlled by various properties; for a detailed
* list of appearance properties see mitk::PlanarFigureMapper2D
*
* The following properties control general PlanarFigure behavior:
*
*
* - "selected": true if the planar figure is selected
*
- "planarfigure.ishovering": true if the mouse "hovers" over the planar figure
*
- "planarfigure.iseditable": true if the planar figure can be edited (otherwise,
* it can only be picked/selected, but its control points cannot be edited); default is true
*
- "planarfigure.isextendable": true if new control points can be inserted into the list of control points;
* default is false
*
*
*
* TODO: Implement local 2D transform (including center of rotation...)
*
*/
class MitkPlanarFigure_EXPORT PlanarFigure : public BaseData
{
public:
mitkClassMacro( PlanarFigure, BaseData )
itkCloneMacro( Self )
/** \brief Treat as Point2D by implicitly using conversion operators.
*
* \deprecatedSince{2014_06} "struct PolyLineElement {...};" will be changed to "typedef Point2D PolyLineElement;".
*/
struct MitkPlanarFigure_EXPORT PolyLineElement
{
DEPRECATED(PolyLineElement(Point2D point, int index));
PolyLineElement(const Point2D& point);
PolyLineElement(const PolyLineElement &other);
PolyLineElement& operator=(const PolyLineElement &other);
operator Point2D&();
operator const Point2D&() const;
DEPRECATED(Point2D Point);
DEPRECATED(int Index);
};
typedef itk::VectorContainer< unsigned long, bool> BoolContainerType;
typedef std::deque< Point2D > ControlPointListType;
typedef std::vector< PolyLineElement > PolyLineType;
/** \brief Sets the 2D geometry on which this figure will be placed.
*
* In most cases, this is a Geometry already owned by another object, e.g.
* describing the slice of the image on which measurements will be
* performed.
*/
virtual void SetPlaneGeometry( mitk::PlaneGeometry *geometry );
/**
* \deprecatedSince{2014_06} Please use SetPlaneGeometry
*/
DEPRECATED(void SetGeometry2D(PlaneGeometry* geo)){SetPlaneGeometry(geo);};
/** \brief Returns (previously set) 2D geometry of this figure. */
virtual const PlaneGeometry *GetPlaneGeometry() const;
/**
* \deprecatedSince{2014_06} Please use GetPlaneGeometry
*/
DEPRECATED(const PlaneGeometry* GetGeometry2D()){return GetPlaneGeometry();};
/** \brief True if the planar figure is closed.
*
* Default is false. The "closed" boolean property must be set in sub-classes. */
virtual bool IsClosed() const;
/** \brief True if the planar figure has been placed (and can be
* displayed/interacted with). */
virtual bool IsPlaced() const { return m_FigurePlaced; };
/** \brief Place figure at the given point (in 2D index coordinates) onto
* the given 2D geometry.
*
* By default, the first two control points of the figure are set to the
* passed point. Further points can be set via AddControlPoint(), if the
* current number of control points is below the maximum number of control
* points.
*
* Can be re-implemented in sub-classes as needed.
*/
virtual void PlaceFigure( const Point2D& point );
/**
* \brief Adds / inserts new control-points
*
* This method adds a new control-point with the coordinates defined by point at the given index.
* If 'index' == -1 or index is greater than the number of control-points the new point is appended
* to the back of the list of control points.
* If a control-point already exists for 'index', an additional point is inserted at that position.
* It is not possible to add more points if the maximum number of control-points (GetMaximumNumberOfControlPoints())
* has been reached.
*/
virtual bool AddControlPoint( const Point2D& point, int index = -1 );
virtual bool SetControlPoint( unsigned int index, const Point2D& point, bool createIfDoesNotExist = false);
virtual bool SetCurrentControlPoint( const Point2D& point );
/** \brief Returns the current number of 2D control points defining this figure. */
unsigned int GetNumberOfControlPoints() const;
/** \brief Returns the minimum number of control points needed to represent
* this figure.
*
* Must be implemented in sub-classes.
*/
virtual unsigned int GetMinimumNumberOfControlPoints() const = 0;
/** \brief Returns the maximum number of control points allowed for
* this figure (e.g. 3 for triangles).
*
* Must be implemented in sub-classes.
*/
virtual unsigned int GetMaximumNumberOfControlPoints() const = 0;
/** \brief Selects currently active control points. */
virtual bool SelectControlPoint( unsigned int index );
/** \brief Deselect control point; no control point active. */
virtual bool DeselectControlPoint();
/** \brief Return currently selected control point. */
virtual int GetSelectedControlPoint() const { return m_SelectedControlPoint; }
/** \brief Returns specified control point in 2D world coordinates. */
Point2D GetControlPoint( unsigned int index ) const;
/** \brief Returns specified control point in world coordinates. */
Point3D GetWorldControlPoint( unsigned int index ) const;
/** \brief Returns the polyline representing the planar figure
* (for rendering, measurements, etc.). */
const PolyLineType GetPolyLine(unsigned int index);
/** \brief Returns the polyline representing the planar figure
* (for rendering, measurments, etc.). */
const PolyLineType GetPolyLine(unsigned int index) const;
/** \brief Returns the polyline that should be drawn the same size at every scale
* (for text, angles, etc.). */
const PolyLineType GetHelperPolyLine( unsigned int index, double mmPerDisplayUnit, unsigned int displayHeight );
/** \brief Sets the position of the PreviewControlPoint. Automatically sets it visible.*/
void SetPreviewControlPoint( const Point2D& point );
/** \brief Marks the PreviewControlPoint as invisible.*/
void ResetPreviewContolPoint();
/** \brief Returns whether or not the PreviewControlPoint is visible.*/
bool IsPreviewControlPointVisible();
/** \brief Returns the coordinates of the PreviewControlPoint. */
Point2D GetPreviewControlPoint();
/** \brief Returns the number of features available for this PlanarFigure
* (such as, radius, area, ...). */
virtual unsigned int GetNumberOfFeatures() const;
/** \brief Returns the name (identifier) of the specified features. */
const char *GetFeatureName( unsigned int index ) const;
/** \brief Returns the physical unit of the specified features. */
const char *GetFeatureUnit( unsigned int index ) const;
/** Returns quantity of the specified feature (e.g., length, radius,
* area, ... ) */
double GetQuantity( unsigned int index ) const;
/** \brief Returns true if the feature with the specified index exists and
* is active (an inactive feature may e.g. be the area of a non-closed
* polygon. */
bool IsFeatureActive( unsigned int index ) const;
/** \brief Returns true if the feature with the specified index exists and is set visible */
bool IsFeatureVisible( unsigned int index ) const;
/** \brief Defines if the feature with the specified index will be shown as an
* overlay in the RenderWindow */
void SetFeatureVisible( unsigned int index, bool visible );
/** \brief Calculates quantities of all features of this planar figure. */
virtual void EvaluateFeatures();
/** \brief Intherited from parent */
virtual void UpdateOutputInformation();
/** \brief Intherited from parent */
virtual void SetRequestedRegionToLargestPossibleRegion();
/** \brief Intherited from parent */
virtual bool RequestedRegionIsOutsideOfTheBufferedRegion();
/** \brief Intherited from parent */
virtual bool VerifyRequestedRegion();
/** \brief Intherited from parent */
virtual void SetRequestedRegion( const itk::DataObject *data);
/** \brief Returns the current number of polylines */
virtual unsigned short GetPolyLinesSize();
/** \brief Returns the current number of helperpolylines */
virtual unsigned short GetHelperPolyLinesSize();
/** \brief Returns whether a helper polyline should be painted or not */
virtual bool IsHelperToBePainted(unsigned int index);
/** \brief Returns true if the planar figure is reset to "add points" mode
* when a point is selected.
*
* Default return value is false. Subclasses can overwrite this method and
* execute any reset / initialization statements required. */
virtual bool ResetOnPointSelect();
/** \brief removes the point with the given index from the list of controlpoints. */
virtual void RemoveControlPoint( unsigned int index );
/** \brief Removes last control point */
virtual void RemoveLastControlPoint();
/** \brief Copies contents and state of a figre provided as parameter to the current object.
*
* Requires a matching type of both figures.
*
* \note Deprecated, use Clone() instead.
*/
DEPRECATED(void DeepCopy(Self::Pointer oldFigure));
/** \brief Allow sub-classes to apply constraints on control points.
*
* Sub-classes can define spatial constraints to certain control points by
* overwriting this method and returning a constrained point. By default,
* the points are constrained by the image bounds. */
virtual Point2D ApplyControlPointConstraints( unsigned int /*index*/, const Point2D& point );
+ /**
+ * \brief Compare two PlanarFigure objects
+ * Note: all subclasses have to implement the method on their own.
+ */
+ virtual bool Equals(const mitk::PlanarFigure& other) const;
protected:
PlanarFigure();
virtual ~PlanarFigure();
PlanarFigure(const Self& other);
/** \brief Set the initial number of control points of the planar figure */
void ResetNumberOfControlPoints( int numberOfControlPoints );
/** Adds feature (e.g., circumference, radius, angle, ...) to feature vector
* of a planar figure object and returns integer ID for the feature element.
* Should be called in sub-class constructors. */
virtual unsigned int AddFeature( const char *featureName, const char *unitName );
/** Sets the name of the specified feature. INTERNAL METHOD. */
void SetFeatureName( unsigned int index, const char *featureName );
/** Sets the physical unit of the specified feature. INTERNAL METHOD. */
void SetFeatureUnit( unsigned int index, const char *unitName );
/** Sets quantity of the specified feature. INTERNAL METHOD. */
void SetQuantity( unsigned int index, double quantity );
/** Sets the specified feature as active. INTERAL METHOD. */
void ActivateFeature( unsigned int index );
/** Sets the specified feature as active. INTERAL METHOD. */
void DeactivateFeature( unsigned int index );
/** \brief Generates the poly-line representation of the planar figure.
* Must be implemented in sub-classes. */
virtual void GeneratePolyLine() = 0;
/** \brief Generates the poly-lines that should be drawn the same size regardless of zoom.
* Must be implemented in sub-classes. */
virtual void GenerateHelperPolyLine(double mmPerDisplayUnit, unsigned int displayHeight) = 0;
/** \brief Calculates quantities of all features of this planar figure.
* Must be implemented in sub-classes. */
virtual void EvaluateFeaturesInternal() = 0;
/** \brief Initializes the TimeGeometry describing the (time-resolved)
* geometry of this figure. Note that each time step holds one PlaneGeometry.
*/
virtual void InitializeTimeGeometry( unsigned int timeSteps = 1 );
/** \brief defines the number of PolyLines that will be available */
void SetNumberOfPolyLines( unsigned int numberOfPolyLines );
/** \brief Append a point to the PolyLine # index */
void AppendPointToPolyLine( unsigned int index, PolyLineElement element );
/** \brief clears the list of PolyLines. Call before re-calculating a new Polyline. */
void ClearPolyLines();
/** \brief defines the number of HelperPolyLines that will be available */
void SetNumberOfHelperPolyLines( unsigned int numberOfHelperPolyLines );
/** \brief Append a point to the HelperPolyLine # index */
void AppendPointToHelperPolyLine( unsigned int index, PolyLineElement element );
/** \brief clears the list of HelperPolyLines. Call before re-calculating a new HelperPolyline. */
void ClearHelperPolyLines();
virtual void PrintSelf( std::ostream& os, itk::Indent indent ) const;
ControlPointListType m_ControlPoints;
unsigned int m_NumberOfControlPoints;
// Currently selected control point; -1 means no point selected
int m_SelectedControlPoint;
std::vector m_PolyLines;
std::vector m_HelperPolyLines;
BoolContainerType::Pointer m_HelperPolyLinesToBePainted;
// this point is used to store the coordiantes an additional 'ControlPoint' that is rendered
// when the mouse cursor is above the figure (and not a control-point) and when the
// property 'planarfigure.isextendable' is set to true
Point2D m_PreviewControlPoint;
bool m_PreviewControlPointVisible;
bool m_FigurePlaced;
private:
// not implemented to prevent PlanarFigure::New() calls which would create an itk::Object.
static Pointer New();
struct Feature
{
Feature( const char *name, const char *unit )
: Name( name ), Unit( unit ), Quantity( 0.0 ), Active( true ), Visible( true )
{
}
std::string Name;
std::string Unit;
double Quantity;
bool Active;
bool Visible;
};
virtual itk::LightObject::Pointer InternalClone() const = 0;
PlaneGeometry *m_PlaneGeometry;
bool m_PolyLineUpToDate;
bool m_HelperLinesUpToDate;
bool m_FeaturesUpToDate;
// Vector of features available for this geometric figure
typedef std::vector< Feature > FeatureVectorType;
FeatureVectorType m_Features;
unsigned long m_FeaturesMTime;
// this pair is used to store the mmInDisplayUnits (m_DisplaySize.first) and the displayHeight (m_DisplaySize.second)
// that the helperPolyLines have been calculated for.
// It's used to determine whether or not GetHelperPolyLine() needs to recalculate the HelperPolyLines.
std::pair m_DisplaySize;
};
+MITK_CORE_EXPORT bool Equal( const mitk::PlanarFigure& leftHandSide, const mitk::PlanarFigure& rightHandSide, ScalarType eps, bool verbose );
+
} // namespace mitk
#endif //_MITK_PLANAR_FIGURE_H_
diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarFourPointAngle.cpp b/Modules/PlanarFigure/DataManagement/mitkPlanarFourPointAngle.cpp
index ddd3d8c262..ca7c048a98 100644
--- a/Modules/PlanarFigure/DataManagement/mitkPlanarFourPointAngle.cpp
+++ b/Modules/PlanarFigure/DataManagement/mitkPlanarFourPointAngle.cpp
@@ -1,79 +1,92 @@
/*===================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.
This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.
See LICENSE.txt or http://www.mitk.org for details.
===================================================================*/
#include "mitkPlanarFourPointAngle.h"
#include "mitkPlaneGeometry.h"
mitk::PlanarFourPointAngle::PlanarFourPointAngle()
: FEATURE_ID_ANGLE( this->AddFeature( "Angle", "deg" ) )
{
// Four point angle has two control points
this->ResetNumberOfControlPoints( 2 );
this->SetNumberOfPolyLines( 2 );
}
mitk::PlanarFourPointAngle::~PlanarFourPointAngle()
{
}
void mitk::PlanarFourPointAngle::GeneratePolyLine()
{
this->ClearPolyLines();
for (unsigned int i = 0; i < this->GetNumberOfControlPoints(); ++i)
this->AppendPointToPolyLine(i / 2, this->GetControlPoint(i));
}
void mitk::PlanarFourPointAngle::GenerateHelperPolyLine(double /*mmPerDisplayUnit*/, unsigned int /*displayHeight*/)
{
// Generate helper-poly-line for an four point angle
// Need to discuss a sensible implementation
}
void mitk::PlanarFourPointAngle::EvaluateFeaturesInternal()
{
if ( this->GetNumberOfControlPoints() < 4 )
{
// Angle not yet complete.
return;
}
// Calculate angle between lines
const Point2D &p0 = this->GetControlPoint( 0 );
const Point2D &p1 = this->GetControlPoint( 1 );
const Point2D &p2 = this->GetControlPoint( 2 );
const Point2D &p3 = this->GetControlPoint( 3 );
Vector2D v0 = p1 - p0;
Vector2D v1 = p3 - p2;
v0.Normalize();
v1.Normalize();
double angle = acos( v0 * v1 );
this->SetQuantity( FEATURE_ID_ANGLE, angle );
}
void mitk::PlanarFourPointAngle::PrintSelf( std::ostream& os, itk::Indent indent) const
{
Superclass::PrintSelf( os, indent );
}
+
+ bool mitk::PlanarFourPointAngle::Equals(const mitk::PlanarFigure& other) const
+ {
+ const mitk::PlanarFourPointAngle* otherFourPtAngle = dynamic_cast(&other);
+ if ( otherFourPtAngle )
+ {
+ return Superclass::Equals(other);
+ }
+ else
+ {
+ return false;
+ }
+ }
diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarFourPointAngle.h b/Modules/PlanarFigure/DataManagement/mitkPlanarFourPointAngle.h
index b485beb721..44189715de 100644
--- a/Modules/PlanarFigure/DataManagement/mitkPlanarFourPointAngle.h
+++ b/Modules/PlanarFigure/DataManagement/mitkPlanarFourPointAngle.h
@@ -1,93 +1,94 @@
/*===================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.
This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.
See LICENSE.txt or http://www.mitk.org for details.
===================================================================*/
#ifndef _MITK_PLANAR_FOURPOINTANGLE_H_
#define _MITK_PLANAR_FOURPOINTANGLE_H_
#include "mitkPlanarFigure.h"
#include
namespace mitk
{
class PlaneGeometry;
/**
* \brief Implementation of PlanarFigure representing a four point
* angle, which is defined by two non-intersecting lines in 2D. Each of those lines
* is defined by two control points.
*/
class MitkPlanarFigure_EXPORT PlanarFourPointAngle : public PlanarFigure
{
public:
mitkClassMacro( PlanarFourPointAngle, PlanarFigure );
itkFactorylessNewMacro(Self)
itkCloneMacro(Self)
public:
// Feature identifiers
const unsigned int FEATURE_ID_ANGLE;
/** \brief Place figure in its minimal configuration (a point at least)
* onto the given 2D geometry.
*
* Must be implemented in sub-classes.
*/
//virtual void Initialize();
/** \brief Four point angle has 4 control points per definition. */
unsigned int GetMinimumNumberOfControlPoints() const
{
return 4;
}
/** \brief Four point angle has 4 control points per definition. */
unsigned int GetMaximumNumberOfControlPoints() const
{
return 4;
}
+ virtual bool Equals(const mitk::PlanarFigure& other) const ;
protected:
PlanarFourPointAngle();
virtual ~PlanarFourPointAngle();
mitkCloneMacro(Self);
/** \brief Generates the poly-line representation of the planar figure. */
virtual void GeneratePolyLine();
/** \brief Generates the poly-lines that should be drawn the same size regardless of zoom.*/
virtual void GenerateHelperPolyLine(double mmPerDisplayUnit, unsigned int displayHeight);
/** \brief Calculates feature quantities of the planar figure. */
virtual void EvaluateFeaturesInternal();
virtual void PrintSelf( std::ostream &os, itk::Indent indent ) const;
private:
};
} // namespace mitk
#endif //_MITK_PLANAR_FOURPOINTANGLE_H_
diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarLine.cpp b/Modules/PlanarFigure/DataManagement/mitkPlanarLine.cpp
index a534089a6a..ffee0a38bd 100644
--- a/Modules/PlanarFigure/DataManagement/mitkPlanarLine.cpp
+++ b/Modules/PlanarFigure/DataManagement/mitkPlanarLine.cpp
@@ -1,65 +1,78 @@
/*===================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.
This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.
See LICENSE.txt or http://www.mitk.org for details.
===================================================================*/
#include "mitkPlanarLine.h"
#include "mitkPlaneGeometry.h"
mitk::PlanarLine::PlanarLine()
: FEATURE_ID_LENGTH( this->AddFeature( "Length", "mm" ) )
{
// Line has two control points
this->ResetNumberOfControlPoints( 2 );
this->SetNumberOfPolyLines( 1 );
}
mitk::PlanarLine::~PlanarLine()
{
}
void mitk::PlanarLine::GeneratePolyLine()
{
this->ClearPolyLines();
this->AppendPointToPolyLine(0, this->GetControlPoint(0));
this->AppendPointToPolyLine(0, this->GetControlPoint(1));
}
void mitk::PlanarLine::GenerateHelperPolyLine(double /*mmPerDisplayUnit*/, unsigned int /*displayHeight*/)
{
// A line does not require a helper object
}
void mitk::PlanarLine::EvaluateFeaturesInternal()
{
// Calculate line length
const Point3D &p0 = this->GetWorldControlPoint( 0 );
const Point3D &p1 = this->GetWorldControlPoint( 1 );
double length = p0.EuclideanDistanceTo( p1 );
this->SetQuantity( FEATURE_ID_LENGTH, length );
}
void mitk::PlanarLine::PrintSelf( std::ostream& os, itk::Indent indent) const
{
Superclass::PrintSelf( os, indent );
}
+
+ bool mitk::PlanarLine::Equals(const PlanarFigure &other) const
+ {
+ const mitk::PlanarLine* otherLine = dynamic_cast(&other);
+ if ( otherLine )
+ {
+ return Superclass::Equals(other);
+ }
+ else
+ {
+ return false;
+ }
+ }
diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarLine.h b/Modules/PlanarFigure/DataManagement/mitkPlanarLine.h
index 09732fcef3..cdfd7bfd55 100644
--- a/Modules/PlanarFigure/DataManagement/mitkPlanarLine.h
+++ b/Modules/PlanarFigure/DataManagement/mitkPlanarLine.h
@@ -1,93 +1,94 @@
/*===================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.
This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.
See LICENSE.txt or http://www.mitk.org for details.
===================================================================*/
#ifndef _MITK_PLANAR_LINE_H_
#define _MITK_PLANAR_LINE_H_
#include "mitkPlanarFigure.h"
#include
namespace mitk
{
class PlaneGeometry;
/**
* \brief Implementation of PlanarFigure representing a line
* through two control points
*/
class MitkPlanarFigure_EXPORT PlanarLine : public PlanarFigure
{
public:
mitkClassMacro( PlanarLine, PlanarFigure );
itkFactorylessNewMacro(Self)
itkCloneMacro(Self)
/** \brief Place figure in its minimal configuration (a point at least)
* onto the given 2D geometry.
*
* Must be implemented in sub-classes.
*/
//virtual void Initialize();
/** \brief Line has 2 control points per definition. */
unsigned int GetMinimumNumberOfControlPoints() const
{
return 2;
}
/** \brief Line has 2 control points per definition. */
unsigned int GetMaximumNumberOfControlPoints() const
{
return 2;
}
+ virtual bool Equals(const mitk::PlanarFigure& other) const;
protected:
PlanarLine();
virtual ~PlanarLine();
mitkCloneMacro(Self);
/** \brief Generates the poly-line representation of the planar figure. */
virtual void GeneratePolyLine();
/** \brief Generates the poly-lines that should be drawn the same size regardless of zoom.*/
virtual void GenerateHelperPolyLine(double mmPerDisplayUnit, unsigned int displayHeight);
/** \brief Calculates feature quantities of the planar figure. */
virtual void EvaluateFeaturesInternal();
virtual void PrintSelf( std::ostream &os, itk::Indent indent ) const;
// Feature identifiers
const unsigned int FEATURE_ID_LENGTH;
private:
};
} // namespace mitk
#endif //_MITK_PLANAR_LINE_H_
diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarPolygon.cpp b/Modules/PlanarFigure/DataManagement/mitkPlanarPolygon.cpp
index 669d952f3f..e47a71eebd 100644
--- a/Modules/PlanarFigure/DataManagement/mitkPlanarPolygon.cpp
+++ b/Modules/PlanarFigure/DataManagement/mitkPlanarPolygon.cpp
@@ -1,274 +1,287 @@
/*===================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.
This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.
See LICENSE.txt or http://www.mitk.org for details.
===================================================================*/
#include "mitkPlanarPolygon.h"
#include "mitkPlaneGeometry.h"
#include "mitkProperties.h"
// stl related includes
#include
mitk::PlanarPolygon::PlanarPolygon()
: FEATURE_ID_CIRCUMFERENCE( this->AddFeature( "Circumference", "mm" ) ),
FEATURE_ID_AREA( this->AddFeature( "Area", "mm2" ) )
{
// Polygon has at least two control points
this->ResetNumberOfControlPoints( 2 );
this->SetNumberOfPolyLines( 1 );
// Polygon is closed by default
this->SetProperty( "closed", mitk::BoolProperty::New( true ) );
this->SetProperty( "subdivision", mitk::BoolProperty::New( false ) );
}
mitk::PlanarPolygon::~PlanarPolygon()
{
}
void mitk::PlanarPolygon::SetClosed( bool closed )
{
this->SetProperty( "closed", mitk::BoolProperty::New( closed ) );
if ( !closed )
{
// For non-closed polygons: use "Length" as feature name; disable area
this->SetFeatureName( FEATURE_ID_CIRCUMFERENCE, "Length" );
this->DeactivateFeature( FEATURE_ID_AREA );
}
else
{
// For closed polygons: use "Circumference" as feature name; enable area
this->SetFeatureName( FEATURE_ID_CIRCUMFERENCE, "Circumference" );
this->ActivateFeature( FEATURE_ID_AREA );
}
this->Modified();
}
void mitk::PlanarPolygon::GeneratePolyLine()
{
this->ClearPolyLines();
for (ControlPointListType::size_type i = 0; i < m_ControlPoints.size(); ++i)
this->AppendPointToPolyLine(0, this->GetControlPoint(i));
}
void mitk::PlanarPolygon::GenerateHelperPolyLine(double /*mmPerDisplayUnit*/, unsigned int /*displayHeight*/)
{
// A polygon does not require helper objects
}
void mitk::PlanarPolygon::EvaluateFeaturesInternal()
{
// Calculate circumference
double circumference = 0.0;
unsigned int i,j;
PolyLineType polyLine = m_PolyLines[0];
if(polyLine.empty())
return;
for ( i = 0; i <(polyLine.size()-1); ++i )
{
circumference += static_cast(polyLine[i]).EuclideanDistanceTo(
static_cast(polyLine[i + 1]) );
}
if ( this->IsClosed() )
{
circumference += static_cast(polyLine[i]).EuclideanDistanceTo(
static_cast(polyLine.front()) );
}
this->SetQuantity( FEATURE_ID_CIRCUMFERENCE, circumference );
// Calculate polygon area (if closed)
double area = 0.0;
bool intersection = false;
if ( this->IsClosed() && (this->GetPlaneGeometry() != NULL) )
{
// does PlanarPolygon overlap/intersect itself?
unsigned int numberOfPoints = polyLine.size();
if( numberOfPoints >= 4)
{
for ( i = 0; i < (numberOfPoints - 1); ++i )
{
// line 1
Point2D p0 = polyLine[i];
Point2D p1 = polyLine[i + 1];
// check for intersection with all other lines
for (j = i+1; j < (numberOfPoints - 1); ++j )
{
Point2D p2 = polyLine[j];
Point2D p3 = polyLine[j + 1];
intersection = CheckForLineIntersection(p0,p1,p2,p3);
if (intersection) break;
}
if (intersection) break; // only because the inner loop might have changed "intersection"
// last line from p_x to p_0
Point2D p2 = polyLine.front();
Point2D p3 = polyLine.back();
intersection = CheckForLineIntersection(p0,p1,p2,p3);
if (intersection) break;
}
}
// calculate area
for ( i = 0; i < polyLine.size(); ++i )
{
Point2D p0 = polyLine[i];
Point2D p1 = polyLine[ (i + 1) % polyLine.size() ];
area += p0[0] * p1[1] - p1[0] * p0[1];
}
area /= 2.0;
}
// set area if appropiate (i.e. closed and not intersected)
if(this->IsClosed() && !intersection)
{
SetQuantity( FEATURE_ID_AREA, fabs( area ) );
this->ActivateFeature( FEATURE_ID_AREA );
}
else
{
SetQuantity( FEATURE_ID_AREA, 0 );
this->DeactivateFeature( FEATURE_ID_AREA );
}
}
void mitk::PlanarPolygon::PrintSelf( std::ostream& os, itk::Indent indent) const
{
Superclass::PrintSelf( os, indent );
if (this->IsClosed())
os << indent << "Polygon is closed\n";
else
os << indent << "Polygon is not closed\n";
}
// based on
// http://flassari.is/2008/11/line-line-intersection-in-cplusplus/
bool mitk::PlanarPolygon::CheckForLineIntersection( const mitk::Point2D& p1, const mitk::Point2D& p2, const mitk::Point2D& p3, const mitk::Point2D& p4, Point2D& intersection ) const
{
// do not check for intersections with control points
if(p1 == p2 || p1 == p3 || p1 == p4 ||
p2 == p3 || p2 == p4 ||
p3 == p4)
return false;
// Store the values for fast access and easy
// equations-to-code conversion
double x1 = p1[0], x2 = p2[0], x3 = p3[0], x4 = p4[0];
double y1 = p1[1], y2 = p2[1], y3 = p3[1], y4 = p4[1];
double d = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
// If d is zero, there is no intersection
//if (d < mitk::eps) return false;
if (d == 0) return false;
// Get the x and y
double pre = (x1*y2 - y1*x2);
double post = (x3*y4 - y3*x4);
double x = ( pre * (x3 - x4) - (x1 - x2) * post ) / d;
double y = ( pre * (y3 - y4) - (y1 - y2) * post ) / d;
double tolerance = 0.001;
// Check if the x coordinates are within both lines, including tolerance
if ( x < ( std::min(x1, x2) - tolerance )
|| x > ( std::max(x1, x2) + tolerance )
|| x < ( std::min(x3, x4) - tolerance )
|| x > ( std::max(x3, x4) + tolerance )
)
{
return false;
}
// Check if the y coordinates are within both lines, including tolerance
if ( y < ( std::min(y1, y2) - tolerance )
|| y > ( std::max(y1, y2) + tolerance )
|| y < ( std::min(y3, y4) - tolerance )
|| y > ( std::max(y3, y4) + tolerance )
)
{
return false;
}
// point of intersection
Point2D ret; ret[0] = x; ret[1] = y;
intersection = ret;
return true;
}
bool mitk::PlanarPolygon::CheckForLineIntersection( const mitk::Point2D& p1, const mitk::Point2D& p2, const mitk::Point2D& p3, const mitk::Point2D& p4 ) const
{
mitk::Point2D intersection;
return mitk::PlanarPolygon::CheckForLineIntersection( p1, p2, p3, p4, intersection );
}
std::vector mitk::PlanarPolygon::CheckForLineIntersection( const mitk::Point2D& p1, const mitk::Point2D& p2 ) const
{
std::vector intersectionList;
ControlPointListType polyLinePoints;
PolyLineType tempList = m_PolyLines[0];
PolyLineType::iterator iter;
for( iter = tempList.begin(); iter != tempList.end(); ++iter )
{
polyLinePoints.push_back(*iter);
}
for ( ControlPointListType::size_type i=0; iIsClosed() )
{
mitk::Point2D intersection, lastControlPoint, firstControlPoint;
lastControlPoint = polyLinePoints.back();
firstControlPoint = polyLinePoints.front();
if ( mitk::PlanarPolygon::CheckForLineIntersection( lastControlPoint,
firstControlPoint, p1, p2, intersection ) )
{
intersectionList.push_back( intersection );
}
}
return intersectionList;
}
+
+ bool mitk::PlanarPolygon::Equals(const mitk::PlanarFigure& other) const
+ {
+ const mitk::PlanarPolygon* otherPolygon = dynamic_cast(&other);
+ if ( otherPolygon )
+ {
+ return Superclass::Equals(other);
+ }
+ else
+ {
+ return false;
+ }
+ }
diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarPolygon.h b/Modules/PlanarFigure/DataManagement/mitkPlanarPolygon.h
index fa5c0c19b4..e37b70934b 100644
--- a/Modules/PlanarFigure/DataManagement/mitkPlanarPolygon.h
+++ b/Modules/PlanarFigure/DataManagement/mitkPlanarPolygon.h
@@ -1,103 +1,104 @@
/*===================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.
This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.
See LICENSE.txt or http://www.mitk.org for details.
===================================================================*/
#ifndef _MITK_PLANAR_POLYGON_H_
#define _MITK_PLANAR_POLYGON_H_
#include "mitkPlanarFigure.h"
#include
namespace mitk
{
class PlaneGeometry;
/**
* \brief Implementation of PlanarFigure representing a polygon
* with two or more control points
*/
class MitkPlanarFigure_EXPORT PlanarPolygon : public PlanarFigure
{
public:
mitkClassMacro( PlanarPolygon, PlanarFigure );
itkFactorylessNewMacro(Self)
itkCloneMacro(Self)
/** \brief Set whether the polygon should be closed between first and last control point or not. */
virtual void SetClosed( bool closed );
itkBooleanMacro( Closed ); // Calls SetClosed(); no need to re-implement
/** \brief Place figure in its minimal configuration (a point at least)
* onto the given 2D geometry.
*
* Must be implemented in sub-classes.
*/
//virtual void Initialize();
/** \brief Polygon has 3 control points per definition. */
unsigned int GetMinimumNumberOfControlPoints() const
{
return 3;
}
/** \brief Polygon maximum number of control points is principally not limited. */
unsigned int GetMaximumNumberOfControlPoints() const
{
return 1000;
}
std::vector CheckForLineIntersection( const Point2D& p1, const Point2D& p2 ) const;
+ virtual bool Equals(const mitk::PlanarFigure& other) const;
protected:
PlanarPolygon();
virtual ~PlanarPolygon();
mitkCloneMacro(Self);
/** \brief Generates the poly-line representation of the planar figure. */
virtual void GeneratePolyLine();
/** \brief Generates the poly-lines that should be drawn the same size regardless of zoom.*/
virtual void GenerateHelperPolyLine(double mmPerDisplayUnit, unsigned int displayHeight);
/** \brief Calculates feature quantities of the planar figure. */
virtual void EvaluateFeaturesInternal();
bool CheckForLineIntersection(const mitk::Point2D& p1, const mitk::Point2D& p2, const mitk::Point2D& p3, const mitk::Point2D& p4, Point2D& intersection) const ;
bool CheckForLineIntersection( const mitk::Point2D& p1, const mitk::Point2D& p2, const mitk::Point2D& p3, const mitk::Point2D& p4 ) const;
virtual void PrintSelf( std::ostream &os, itk::Indent indent ) const;
const unsigned int FEATURE_ID_CIRCUMFERENCE;
const unsigned int FEATURE_ID_AREA;
private:
};
} // namespace mitk
#endif //_MITK_PLANAR_POLYGON_H_
diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarRectangle.cpp b/Modules/PlanarFigure/DataManagement/mitkPlanarRectangle.cpp
index cc7169ece3..d4fdeb80d6 100644
--- a/Modules/PlanarFigure/DataManagement/mitkPlanarRectangle.cpp
+++ b/Modules/PlanarFigure/DataManagement/mitkPlanarRectangle.cpp
@@ -1,146 +1,159 @@
/*===================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.
This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.
See LICENSE.txt or http://www.mitk.org for details.
===================================================================*/
#include "mitkProperties.h"
#include "mitkPlanarRectangle.h"
#include "mitkPlaneGeometry.h"
mitk::PlanarRectangle::PlanarRectangle()
: FEATURE_ID_CIRCUMFERENCE( this->AddFeature( "Circumference", "mm" ) ),
FEATURE_ID_AREA( this->AddFeature( "Area", "mm2" ) )
{
// Rectangle has four control points
this->ResetNumberOfControlPoints( 4 );
this->SetProperty( "closed", mitk::BoolProperty::New(true) );
this->SetNumberOfPolyLines( 1 );
}
mitk::PlanarRectangle::~PlanarRectangle()
{
}
bool mitk::PlanarRectangle::SetControlPoint( unsigned int index, const Point2D &point, bool createIfDoesNotExist )
{
// heres the deal with the rectangle:
// when a point is moved all corresponding corner points are moved with him
// e.g. if the lower right point (index=3) is moved the upper right point (index=1)
// is moved in the same x direction
// and the lower left point (index=2) is moved in the same y direction
// the upper left point (index=0) is left untouched
bool set = PlanarFigure::SetControlPoint( index, point, createIfDoesNotExist );
if(set)
{
// can be made better ...
unsigned int horizontalCorrespondingPointIndex = 1;
unsigned int verticalCorrespondingPointIndex = 3;
if(index == 1)
{
horizontalCorrespondingPointIndex = 0;
verticalCorrespondingPointIndex = 2;
}
else if(index == 2)
{
horizontalCorrespondingPointIndex = 3;
verticalCorrespondingPointIndex = 1;
}
else if(index == 3)
{
horizontalCorrespondingPointIndex = 2;
verticalCorrespondingPointIndex = 0;
}
Point2D verticalCorrespondingPoint = GetControlPoint( verticalCorrespondingPointIndex );
verticalCorrespondingPoint[0] = point[0];
PlanarFigure::SetControlPoint( verticalCorrespondingPointIndex, verticalCorrespondingPoint );
Point2D horizontalCorrespondingPoint = GetControlPoint( horizontalCorrespondingPointIndex );
horizontalCorrespondingPoint[1] = point[1];
PlanarFigure::SetControlPoint( horizontalCorrespondingPointIndex, horizontalCorrespondingPoint );
}
return set;
}
void mitk::PlanarRectangle::PlaceFigure( const mitk::Point2D &point )
{
PlanarFigure::PlaceFigure( point );
m_SelectedControlPoint = 3;
}
void mitk::PlanarRectangle::GeneratePolyLine()
{
this->ClearPolyLines();
for (unsigned int i = 0; i < this->GetNumberOfControlPoints(); ++i)
this->AppendPointToPolyLine(0, this->GetControlPoint(i));
}
void mitk::PlanarRectangle::GenerateHelperPolyLine(double /*mmPerDisplayUnit*/, unsigned int /*displayHeight*/)
{
// A polygon does not require helper objects
}
void mitk::PlanarRectangle::EvaluateFeaturesInternal()
{
// Calculate circumference
double circumference = 0.0;
unsigned int i;
for ( i = 0; i < this->GetNumberOfControlPoints(); ++i )
{
circumference += this->GetWorldControlPoint( i ).EuclideanDistanceTo(
this->GetWorldControlPoint( (i + 1) % this->GetNumberOfControlPoints() ) );
}
this->SetQuantity( FEATURE_ID_CIRCUMFERENCE, circumference );
// Calculate rectangle area (well, done a bit clumsy...)
double area = 0.0;
if ( this->GetPlaneGeometry() != NULL )
{
for ( i = 0; i < this->GetNumberOfControlPoints(); ++i )
{
Point2D p0 = this->GetControlPoint( i );
Point2D p1 = this->GetControlPoint( (i + 1) % this->GetNumberOfControlPoints() );
area += p0[0] * p1[1] - p1[0] * p0[1];
}
area /= 2.0;
}
this->SetQuantity( FEATURE_ID_AREA, fabs(area) );
}
void mitk::PlanarRectangle::PrintSelf( std::ostream& os, itk::Indent indent) const
{
Superclass::PrintSelf( os, indent );
os << indent << "Number of control points: " << this->GetNumberOfControlPoints() << std::endl;
os << indent << "Control points:" << std::endl;
for ( unsigned int i = 0; i < this->GetNumberOfControlPoints(); ++i )
{
os << indent << indent << i << ": " <(&other);
+ if ( otherRectangle )
+ {
+ return Superclass::Equals(other);
+ }
+ else
+ {
+ return false;
+ }
+ }
diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarRectangle.h b/Modules/PlanarFigure/DataManagement/mitkPlanarRectangle.h
index 2943a626c5..b4890c5ce8 100644
--- a/Modules/PlanarFigure/DataManagement/mitkPlanarRectangle.h
+++ b/Modules/PlanarFigure/DataManagement/mitkPlanarRectangle.h
@@ -1,93 +1,94 @@
/*===================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.
This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.
See LICENSE.txt or http://www.mitk.org for details.
===================================================================*/
#ifndef _MITK_PLANAR_RECTANGLE_H_
#define _MITK_PLANAR_RECTANGLE_H_
#include "mitkPlanarPolygon.h"
#include
namespace mitk
{
class PlaneGeometry;
/**
* \brief Implementation of PlanarFigure representing a polygon
* with two or more control points
*/
class MitkPlanarFigure_EXPORT PlanarRectangle : public PlanarFigure
{
public:
mitkClassMacro( PlanarRectangle, PlanarFigure );
itkFactorylessNewMacro(Self)
itkCloneMacro(Self)
/** \brief Place figure in its minimal configuration (a point at least)
* onto the given 2D geometry.
*
* Must be implemented in sub-classes.
*/
//virtual void Initialize();
virtual void PlaceFigure( const Point2D &point );
/** \brief Polygon has 2 control points per definition. */
virtual unsigned int GetMinimumNumberOfControlPoints() const
{
return 4;
}
/** \brief Polygon maximum number of control points is principally not limited. */
virtual unsigned int GetMaximumNumberOfControlPoints() const
{
return 4;
}
virtual bool SetControlPoint( unsigned int index, const Point2D &point, bool createIfDoesNotExist = false);
protected:
PlanarRectangle();
virtual ~PlanarRectangle();
mitkCloneMacro(Self);
/** \brief Generates the poly-line representation of the planar figure. */
virtual void GeneratePolyLine();
/** \brief Generates the poly-lines that should be drawn the same size regardless of zoom.*/
virtual void GenerateHelperPolyLine(double mmPerDisplayUnit, unsigned int displayHeight);
/** \brief Calculates feature quantities of the planar figure. */
virtual void EvaluateFeaturesInternal();
virtual void PrintSelf( std::ostream &os, itk::Indent indent ) const;
const unsigned int FEATURE_ID_CIRCUMFERENCE;
const unsigned int FEATURE_ID_AREA;
+ virtual bool Equals(const mitk::PlanarFigure& other) const;
private:
};
} // namespace mitk
#endif //_MITK_PLANAR_POLYGON_H_
diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarSubdivisionPolygon.cpp b/Modules/PlanarFigure/DataManagement/mitkPlanarSubdivisionPolygon.cpp
index db3ac6657b..2b63f2dffd 100644
--- a/Modules/PlanarFigure/DataManagement/mitkPlanarSubdivisionPolygon.cpp
+++ b/Modules/PlanarFigure/DataManagement/mitkPlanarSubdivisionPolygon.cpp
@@ -1,132 +1,149 @@
/*===================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.
This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.
See LICENSE.txt or http://www.mitk.org for details.
===================================================================*/
#include "mitkPlanarSubdivisionPolygon.h"
#include "mitkPlaneGeometry.h"
#include "mitkProperties.h"
// stl related includes
#include
mitk::PlanarSubdivisionPolygon::PlanarSubdivisionPolygon():
m_TensionParameter(0.0625),
m_SubdivisionRounds(5)
{
// Polygon is subdivision (in contrast to parent class PlanarPolygon
this->SetProperty( "closed", mitk::BoolProperty::New( true ) );
this->SetProperty( "subdivision", mitk::BoolProperty::New( true ) );
// Other properties are inherited / already initialized by parent class PlanarPolygon
}
mitk::PlanarSubdivisionPolygon::~PlanarSubdivisionPolygon()
{
}
void mitk::PlanarSubdivisionPolygon::GeneratePolyLine()
{
this->ClearPolyLines();
ControlPointListType subdivisionPoints;
ControlPointListType newSubdivisionPoints;
subdivisionPoints.clear();
subdivisionPoints = m_ControlPoints;
if( m_ControlPoints.size() >= GetMinimumNumberOfControlPoints() )
{
for( unsigned int i=0; i < GetSubdivisionRounds(); i++ )
{
// Indices
unsigned int index, indexPrev, indexNext, indexNextNext;
unsigned int numberOfPoints = subdivisionPoints.size();
Point2D newPoint;
// Keep cycling our array indices forward until they wrap around at the end
for ( index = 0; index < numberOfPoints; ++index )
{
// Create new subdivision point according to formula
// p_new = (0.5 + tension) * (p_here + p_next) - tension * (p_prev + p_nextnext)
indexPrev = (numberOfPoints + index - 1) % numberOfPoints;
indexNext = (index + 1) % numberOfPoints;
indexNextNext = (index + 2) % numberOfPoints;
newPoint[0] = (0.5 + GetTensionParameter()) * (double)( subdivisionPoints[index][0] + subdivisionPoints[indexNext][0] )
- GetTensionParameter() * (double)( subdivisionPoints[indexPrev][0] + subdivisionPoints[indexNextNext][0]);
newPoint[1] = (0.5 + GetTensionParameter()) * (double)( subdivisionPoints[index][1] + subdivisionPoints[indexNext][1] )
- GetTensionParameter() * (double)( subdivisionPoints[indexPrev][1] + subdivisionPoints[indexNextNext][1]);
newSubdivisionPoints.push_back( newPoint );
}
ControlPointListType mergedSubdivisionPoints;
ControlPointListType::iterator it, itNew;
for ( it = subdivisionPoints.begin() , itNew = newSubdivisionPoints.begin();
it != subdivisionPoints.end();
++it, ++itNew )
{
mergedSubdivisionPoints.push_back( *it );
mergedSubdivisionPoints.push_back( *itNew );
}
subdivisionPoints = mergedSubdivisionPoints;
newSubdivisionPoints.clear();
}
}
bool isInitiallyPlaced = this->GetProperty("initiallyplaced");
unsigned int i;
ControlPointListType::iterator it;
for ( it = subdivisionPoints.begin(), i = 0;
it != subdivisionPoints.end();
++it, ++i )
{
// Determine the index of the control point FOLLOWING this poly-line element
// (this is needed by PlanarFigureInteractor to insert new points at the correct position,
// namely BEFORE the next control point)
unsigned int nextIndex;
if ( i == 0 )
{
// For the FIRST polyline point, use the index of the LAST control point
// (it will used to check if the mouse is near the very last polyline element)
nextIndex = m_ControlPoints.size() - 1;
}
else
{
// For all other polyline points, use the index of the control point succeeding it
// (for polyline points lying on control points, the index of the previous control point
// is used)
nextIndex = (((i - 1) >> this->GetSubdivisionRounds()) + 1) % m_ControlPoints.size();
if(!isInitiallyPlaced && nextIndex > m_ControlPoints.size()-2)
{
PolyLineElement elem( m_ControlPoints[m_ControlPoints.size()-1], nextIndex );
this->AppendPointToPolyLine( 0, elem );
break;
}
}
PolyLineElement elem( *it, nextIndex );
this->AppendPointToPolyLine( 0, elem );
}
subdivisionPoints.clear();
}
+
+ bool mitk::PlanarSubdivisionPolygon::Equals(const mitk::PlanarFigure& other) const
+ {
+ const mitk::PlanarSubdivisionPolygon* otherSubDivPoly = dynamic_cast(&other);
+ if ( otherSubDivPoly )
+ {
+ if ( this->m_SubdivisionRounds != otherSubDivPoly->m_SubdivisionRounds)
+ return false;
+ if ( std::abs(this->m_TensionParameter - otherSubDivPoly->m_TensionParameter) > mitk::eps)
+ return false;
+ return Superclass::Equals(other);
+ }
+ else
+ {
+ return false;
+ }
+ }
diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarSubdivisionPolygon.h b/Modules/PlanarFigure/DataManagement/mitkPlanarSubdivisionPolygon.h
index 9d086cb88c..8f17c66805 100644
--- a/Modules/PlanarFigure/DataManagement/mitkPlanarSubdivisionPolygon.h
+++ b/Modules/PlanarFigure/DataManagement/mitkPlanarSubdivisionPolygon.h
@@ -1,107 +1,109 @@
/*===================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.
This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.
See LICENSE.txt or http://www.mitk.org for details.
===================================================================*/
#ifndef _MITK_PLANAR_SUBDIVISION_POLYGON_H_
#define _MITK_PLANAR_SUBDIVISION_POLYGON_H_
#include "mitkPlanarFigure.h"
#include
#include "mitkPlanarPolygon.h"
namespace mitk
{
class PlaneGeometry;
/**
* \brief Implementation of PlanarFigure representing a polygon
* with two or more control points
*/
class MitkPlanarFigure_EXPORT PlanarSubdivisionPolygon : public PlanarPolygon
{
public:
mitkClassMacro( PlanarSubdivisionPolygon, PlanarFigure );
itkFactorylessNewMacro(Self)
itkCloneMacro(Self)
/** \brief Subdivision Polygon has 3 control points per definition. */
unsigned int GetMinimumNumberOfControlPoints() const
{
return 3;
}
/** \brief Polygon maximum number of control points is principally not limited. */
unsigned int GetMaximumNumberOfControlPoints() const
{
return 1000;
}
/** \brief How many times should we generate a round of subdivisions? */
unsigned int GetSubdivisionRounds() const
{
return m_SubdivisionRounds;
}
void SetSubdivisionRounds( int subdivisionRounds )
{
m_SubdivisionRounds = subdivisionRounds;
}
/** \brief Parameter w_tension defines the tension.
* the higher w_tension, the lower the "tension" on points.
* Rule: 0 < w_tension < 0.1
* 0.0625 (1 / 16) seems to be a good value.
*/
float GetTensionParameter() const
{
return m_TensionParameter;
}
void SetTensionParameter(float tensionParameter )
{
m_TensionParameter = tensionParameter;
}
std::vector CheckForLineIntersection( const Point2D& p1, const Point2D& p2 ) const;
void IncreaseSubdivisions();
void DecreaseSubdivisions();
+ virtual bool Equals(const mitk::PlanarFigure& other) const;
+
protected:
PlanarSubdivisionPolygon();
virtual ~PlanarSubdivisionPolygon();
mitkCloneMacro(Self);
/** \brief Generates the poly-line representation of the planar figure. */
virtual void GeneratePolyLine();
float m_TensionParameter;
int m_SubdivisionRounds;
private:
};
} // namespace mitk
#endif //_MITK_PLANAR_SUBDIVISION_POLYGON_H_
diff --git a/Modules/PlanarFigure/IO/mitkPlanarFigureReader.cpp b/Modules/PlanarFigure/IO/mitkPlanarFigureReader.cpp
index 8937d098e9..431e4cbbc2 100644
--- a/Modules/PlanarFigure/IO/mitkPlanarFigureReader.cpp
+++ b/Modules/PlanarFigure/IO/mitkPlanarFigureReader.cpp
@@ -1,469 +1,479 @@
/*===================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.
This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.
See LICENSE.txt or http://www.mitk.org for details.
===================================================================*/
#include "mitkPlanarFigureReader.h"
#include "mitkPlanarAngle.h"
#include "mitkPlanarCircle.h"
#include "mitkPlanarLine.h"
#include "mitkPlanarArrow.h"
#include "mitkPlanarCross.h"
#include "mitkPlanarFourPointAngle.h"
#include "mitkPlanarPolygon.h"
#include "mitkPlanarSubdivisionPolygon.h"
#include "mitkPlanarRectangle.h"
#include "mitkPlaneGeometry.h"
#include "mitkPlanarEllipse.h"
#include "mitkPlanarDoubleEllipse.h"
#include "mitkPlanarBezierCurve.h"
#include "mitkBasePropertySerializer.h"
#include
#include
mitk::PlanarFigureReader::PlanarFigureReader() : PlanarFigureSource(), FileReader(),
m_FileName(""), m_FilePrefix(""), m_FilePattern(""), m_Success(false)
{
this->SetNumberOfRequiredOutputs(1);
this->SetNumberOfIndexedOutputs(1);
this->SetNthOutput(0, this->MakeOutput(0));
m_CanReadFromMemory = true;
//this->Modified();
//this->GetOutput()->Modified();
//this->GetOutput()->ReleaseData();
}
mitk::PlanarFigureReader::~PlanarFigureReader()
{}
void mitk::PlanarFigureReader::GenerateData()
{
const std::string& locale = "C";
const std::string& currLocale = setlocale( LC_ALL, NULL );
if ( locale.compare(currLocale)!=0 )
{
try
{
setlocale(LC_ALL, locale.c_str());
}
catch(...)
{
MITK_INFO << "Could not set locale " << locale;
}
}
m_Success = false;
this->SetNumberOfIndexedOutputs(0); // reset all outputs, we add new ones depending on the file content
TiXmlDocument document;
if(m_ReadFromMemory)
{
if(m_MemoryBuffer == NULL || m_MemorySize == 0)
{
//check
itkWarningMacro( << "Sorry, memory buffer has not been set!" );
return;
}
if(m_MemoryBuffer[ m_MemorySize - 1 ] == '\0')
{
document.Parse(m_MemoryBuffer);
}
else
{
char * tmpArray = new char[(int)m_MemorySize+1];
tmpArray[m_MemorySize] = '\0';
memcpy(tmpArray,m_MemoryBuffer,m_MemorySize);
document.Parse(m_MemoryBuffer);
delete [] tmpArray;
}
}
else
{
if (m_FileName.empty())
{
itkWarningMacro( << "Sorry, filename has not been set!" );
return;
}
if (this->CanReadFile( m_FileName.c_str()) == false)
{
itkWarningMacro( << "Sorry, can't read file " << m_FileName << "!" );
return;
}
if (!document.LoadFile(m_FileName))
{
MITK_ERROR << "Could not open/read/parse " << m_FileName << ". TinyXML reports: '" << document.ErrorDesc() << "'. "
<< "The error occurred in row " << document.ErrorRow() << ", column " << document.ErrorCol() << ".";
return;
}
}
int fileVersion = 1;
TiXmlElement* versionObject = document.FirstChildElement("Version");
if (versionObject != NULL)
{
if ( versionObject->QueryIntAttribute( "FileVersion", &fileVersion ) != TIXML_SUCCESS )
{
MITK_WARN << m_FileName << " does not contain version information! Trying version 1 format." << std::endl;
}
}
else
{
MITK_WARN << m_FileName << " does not contain version information! Trying version 1 format." << std::endl;
}
if (fileVersion != 1) // add file version selection and version specific file parsing here, if newer file versions are created
{
MITK_WARN << "File version > 1 is not supported by this reader.";
return;
}
/* file version 1 reader code */
for( TiXmlElement* pfElement = document.FirstChildElement("PlanarFigure");
pfElement != NULL;
pfElement = pfElement->NextSiblingElement("PlanarFigure") )
{
if (pfElement == NULL)
continue;
std::string type = pfElement->Attribute("type");
mitk::PlanarFigure::Pointer planarFigure = NULL;
if (type == "PlanarAngle")
{
planarFigure = mitk::PlanarAngle::New();
}
else if (type == "PlanarCircle")
{
planarFigure = mitk::PlanarCircle::New();
}
else if (type == "PlanarEllipse")
{
planarFigure = mitk::PlanarEllipse::New();
}
else if (type == "PlanarCross")
{
planarFigure = mitk::PlanarCross::New();
}
else if (type == "PlanarFourPointAngle")
{
planarFigure = mitk::PlanarFourPointAngle::New();
}
else if (type == "PlanarLine")
{
planarFigure = mitk::PlanarLine::New();
}
else if (type == "PlanarPolygon")
{
planarFigure = mitk::PlanarPolygon::New();
}
else if (type == "PlanarSubdivisionPolygon")
{
planarFigure = mitk::PlanarSubdivisionPolygon::New();
}
else if (type == "PlanarRectangle")
{
planarFigure = mitk::PlanarRectangle::New();
}
else if (type == "PlanarArrow")
{
planarFigure = mitk::PlanarArrow::New();
}
else if (type == "PlanarDoubleEllipse")
{
planarFigure = mitk::PlanarDoubleEllipse::New();
}
else if (type == "PlanarBezierCurve")
{
planarFigure = mitk::PlanarBezierCurve::New();
}
else
{
// unknown type
MITK_WARN << "encountered unknown planar figure type '" << type << "'. Skipping this element.";
continue;
}
// Read properties of the planar figure
for( TiXmlElement* propertyElement = pfElement->FirstChildElement("property");
propertyElement != NULL;
propertyElement = propertyElement->NextSiblingElement("property") )
{
const char* keya = propertyElement->Attribute("key");
std::string key( keya ? keya : "");
const char* typea = propertyElement->Attribute("type");
std::string type( typea ? typea : "");
// hand propertyElement to specific reader
std::stringstream propertyDeserializerClassName;
propertyDeserializerClassName << type << "Serializer";
std::list readers =
itk::ObjectFactoryBase::CreateAllInstance(propertyDeserializerClassName.str().c_str());
if (readers.size() < 1)
{
MITK_ERROR << "No property reader found for " << type;
}
if (readers.size() > 1)
{
MITK_WARN << "Multiple property readers found for " << type << ". Using arbitrary first one.";
}
for ( std::list::iterator iter = readers.begin();
iter != readers.end();
++iter )
{
if (BasePropertySerializer* reader = dynamic_cast( iter->GetPointer() ) )
{
BaseProperty::Pointer property = reader->Deserialize( propertyElement->FirstChildElement() );
if (property.IsNotNull())
{
planarFigure->GetPropertyList()->ReplaceProperty(key, property);
}
else
{
MITK_ERROR << "There were errors while loading property '" << key << "' of type " << type << ". Your data may be corrupted";
}
break;
}
}
}
// If we load a planarFigure, it has definitely been placed correctly.
// If we do not set this property here, we cannot load old planarFigures
// without messing up the interaction (PF-Interactor needs this property.
planarFigure->GetPropertyList()->SetBoolProperty( "initiallyplaced", true );
+ // Which features (length or circumference etc) a figure has is decided by whether it is closed or not
+ // the function SetClosed has to be called in case of PlanarPolygons to ensure they hold the correct feature
+ PlanarPolygon* planarPolygon = dynamic_cast (planarFigure.GetPointer());
+ if (planarPolygon != NULL)
+ {
+ bool isClosed = false;
+ planarFigure->GetPropertyList()->GetBoolProperty( "closed", isClosed);
+ planarPolygon->SetClosed(isClosed);
+ }
+
// Read geometry of containing plane
TiXmlElement* geoElement = pfElement->FirstChildElement("Geometry");
if (geoElement != NULL)
{
try
{
// Create plane geometry
mitk::PlaneGeometry::Pointer planeGeo = mitk::PlaneGeometry::New();
// Extract and set plane transform parameters
DoubleList transformList = this->GetDoubleAttributeListFromXMLNode( geoElement->FirstChildElement( "transformParam" ), "param", 12 );
typedef mitk::BaseGeometry::TransformType TransformType;
TransformType::ParametersType parameters;
parameters.SetSize( 12 );
unsigned int i;
DoubleList::iterator it;
for ( it = transformList.begin(), i = 0;
it != transformList.end();
++it, ++i )
{
parameters.SetElement( i, *it );
}
typedef mitk::BaseGeometry::TransformType TransformType;
TransformType::Pointer affineGeometry = TransformType::New();
affineGeometry->SetParameters( parameters );
planeGeo->SetIndexToWorldTransform( affineGeometry );
// Extract and set plane bounds
DoubleList boundsList = this->GetDoubleAttributeListFromXMLNode( geoElement->FirstChildElement( "boundsParam" ), "bound", 6 );
typedef mitk::BaseGeometry::BoundsArrayType BoundsArrayType;
BoundsArrayType bounds;
for ( it = boundsList.begin(), i = 0;
it != boundsList.end();
++it, ++i )
{
bounds[i] = *it;
}
planeGeo->SetBounds( bounds );
// Extract and set spacing and origin
Vector3D spacing = this->GetVectorFromXMLNode(geoElement->FirstChildElement("Spacing"));
planeGeo->SetSpacing( spacing );
Point3D origin = this->GetPointFromXMLNode(geoElement->FirstChildElement("Origin"));
planeGeo->SetOrigin( origin );
planarFigure->SetPlaneGeometry(planeGeo);
}
catch (...)
{
}
}
TiXmlElement* cpElement = pfElement->FirstChildElement("ControlPoints");
bool first = true;
if (cpElement != NULL)
for( TiXmlElement* vertElement = cpElement->FirstChildElement("Vertex"); vertElement != NULL; vertElement = vertElement->NextSiblingElement("Vertex"))
{
if (vertElement == NULL)
continue;
int id = 0;
mitk::Point2D::ValueType x = 0.0;
mitk::Point2D::ValueType y = 0.0;
if (vertElement->QueryIntAttribute("id", &id) == TIXML_WRONG_TYPE)
return; // TODO: can we do a better error handling?
if (vertElement->QueryDoubleAttribute("x", &x) == TIXML_WRONG_TYPE)
return; // TODO: can we do a better error handling?
if (vertElement->QueryDoubleAttribute("y", &y) == TIXML_WRONG_TYPE)
return; // TODO: can we do a better error handling?
Point2D p;
p.SetElement(0, x);
p.SetElement(1, y);
if (first == true) // needed to set m_FigurePlaced to true
{
planarFigure->PlaceFigure(p);
first = false;
}
planarFigure->SetControlPoint(id, p, true);
}
// Calculate feature quantities of this PlanarFigure
planarFigure->EvaluateFeatures();
// Make sure that no control point is currently selected
planarFigure->DeselectControlPoint();
// \TODO: what about m_FigurePlaced and m_SelectedControlPoint ??
this->SetNthOutput( this->GetNumberOfOutputs(), planarFigure ); // add planarFigure as new output of this filter
}
try
{
setlocale(LC_ALL, currLocale.c_str());
}
catch(...)
{
MITK_INFO << "Could not reset locale " << currLocale;
}
m_Success = true;
}
mitk::Point3D mitk::PlanarFigureReader::GetPointFromXMLNode(TiXmlElement* e)
{
if (e == NULL)
throw std::invalid_argument("node invalid"); // TODO: can we do a better error handling?
mitk::Point3D point;
mitk::ScalarType p(-1.0);
if (e->QueryDoubleAttribute("x", &p) == TIXML_WRONG_TYPE)
throw std::invalid_argument("node malformatted"); // TODO: can we do a better error handling?
point.SetElement(0, p);
if (e->QueryDoubleAttribute("y", &p) == TIXML_WRONG_TYPE)
throw std::invalid_argument("node malformatted"); // TODO: can we do a better error handling?
point.SetElement(1, p);
if (e->QueryDoubleAttribute("z", &p) == TIXML_WRONG_TYPE)
throw std::invalid_argument("node malformatted"); // TODO: can we do a better error handling?
point.SetElement(2, p);
return point;
}
mitk::Vector3D mitk::PlanarFigureReader::GetVectorFromXMLNode(TiXmlElement* e)
{
if (e == NULL)
throw std::invalid_argument("node invalid"); // TODO: can we do a better error handling?
mitk::Vector3D vector;
mitk::ScalarType p(-1.0);
if (e->QueryDoubleAttribute("x", &p) == TIXML_WRONG_TYPE)
throw std::invalid_argument("node malformatted"); // TODO: can we do a better error handling?
vector.SetElement(0, p);
if (e->QueryDoubleAttribute("y", &p) == TIXML_WRONG_TYPE)
throw std::invalid_argument("node malformatted"); // TODO: can we do a better error handling?
vector.SetElement(1, p);
if (e->QueryDoubleAttribute("z", &p) == TIXML_WRONG_TYPE)
throw std::invalid_argument("node malformatted"); // TODO: can we do a better error handling?
vector.SetElement(2, p);
return vector;
}
mitk::PlanarFigureReader::DoubleList
mitk::PlanarFigureReader::GetDoubleAttributeListFromXMLNode(TiXmlElement* e, const char *attributeNameBase, unsigned int count)
{
DoubleList list;
if (e == NULL)
throw std::invalid_argument("node invalid"); // TODO: can we do a better error handling?
for ( unsigned int i = 0; i < count; ++i )
{
mitk::ScalarType p(-1.0);
std::stringstream attributeName;
attributeName << attributeNameBase << i;
if (e->QueryDoubleAttribute( attributeName.str().c_str(), &p ) == TIXML_WRONG_TYPE)
throw std::invalid_argument("node malformatted"); // TODO: can we do a better error handling?
list.push_back( p );
}
return list;
}
void mitk::PlanarFigureReader::GenerateOutputInformation()
{
}
int mitk::PlanarFigureReader::CanReadFile ( const char *name )
{
if (std::string(name).empty())
return false;
return (itksys::SystemTools::LowerCase(itksys::SystemTools::GetFilenameLastExtension(name)) == ".pf"); //assume, we can read all .pf files
//TiXmlDocument document(name);
//if (document.LoadFile() == false)
// return false;
//return (document.FirstChildElement("PlanarFigure") != NULL);
}
bool mitk::PlanarFigureReader::CanReadFile(const std::string filename, const std::string, const std::string)
{
if (filename.empty())
return false;
return (itksys::SystemTools::LowerCase(itksys::SystemTools::GetFilenameLastExtension(filename)) == ".pf"); //assume, we can read all .pf files
//TiXmlDocument document(filename);
//if (document.LoadFile() == false)
// return false;
//return (document.FirstChildElement("PlanarFigure") != NULL);
}
void mitk::PlanarFigureReader::ResizeOutputs( const unsigned int& num )
{
unsigned int prevNum = this->GetNumberOfOutputs();
this->SetNumberOfIndexedOutputs( num );
for ( unsigned int i = prevNum; i < num; ++i )
{
this->SetNthOutput( i, this->MakeOutput( i ).GetPointer() );
}
}
diff --git a/Modules/PlanarFigure/Testing/files.cmake b/Modules/PlanarFigure/Testing/files.cmake
index 3e8d679a26..5c683c9c48 100644
--- a/Modules/PlanarFigure/Testing/files.cmake
+++ b/Modules/PlanarFigure/Testing/files.cmake
@@ -1,12 +1,19 @@
set(MODULE_TESTS
mitkPlanarCrossTest.cpp
mitkPlanarPolygonTest.cpp
mitkPlanarSubdivisionPolygonTest.cpp
mitkPlanarFigureIOTest.cpp
mitkPlanarFigureObjectFactoryTest.cpp
mitkPlanarArrowTest.cpp
)
set(MODULE_CUSTOM_TESTS
mitkViewportRenderingTest.cpp
)
+
+if(MITK_ENABLE_RENDERING_TESTING) #since mitkInteractionTestHelper is currently creating a vtkRenderWindow
+set(MODULE_TESTS
+ ${MODULE_TESTS}
+ mitkPlanarFigureInteractionTest.cpp
+)
+endif()
diff --git a/Modules/PlanarFigure/Testing/mitkPlanarFigureInteractionTest.cpp b/Modules/PlanarFigure/Testing/mitkPlanarFigureInteractionTest.cpp
new file mode 100644
index 0000000000..8812bbddbf
--- /dev/null
+++ b/Modules/PlanarFigure/Testing/mitkPlanarFigureInteractionTest.cpp
@@ -0,0 +1,189 @@
+/*===================================================================
+
+The Medical Imaging Interaction Toolkit (MITK)
+
+Copyright (c) German Cancer Research Center,
+Division of Medical and Biological Informatics.
+All rights reserved.
+
+This software is distributed WITHOUT ANY WARRANTY; without
+even the implied warranty of MERCHANTABILITY or FITNESS FOR
+A PARTICULAR PURPOSE.
+
+See LICENSE.txt or http://www.mitk.org for details.
+
+===================================================================*/
+
+#include "mitkTestingMacros.h"
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "usModuleRegistry.h"
+
+class mitkPlanarFigureInteractionTestSuite : public mitk::TestFixture
+{
+
+ CPPUNIT_TEST_SUITE(mitkPlanarFigureInteractionTestSuite);
+ MITK_TEST(AngleInteractionCreate);
+ MITK_TEST(BezierCurveInteractionCreate);
+ MITK_TEST(CircleInteractionCreate);
+ MITK_TEST(DoubleEllipseInteractionCreate);
+ MITK_TEST(PlanarFourPointAngleInteractionCreate);
+ MITK_TEST(PlanarLineInteractionCreate);
+ MITK_TEST(PlanarPolygonInteractionCreate);
+ MITK_TEST(NonClosedPlanarPolygonInteractionCreate);
+ MITK_TEST(RectangleInteractionCreate);
+ MITK_TEST(PlanarSubdivisionInteractionCreate);
+
+ CPPUNIT_TEST_SUITE_END();
+
+
+public:
+
+ void setUp()
+ {
+ }
+
+ void tearDown()
+ {
+ }
+
+ void RunTest(mitk::PlanarFigure::Pointer figure, std::string interactionXmlPath, std::string referenceFigurePath)
+ {
+ mitk::DataNode::Pointer node;
+ mitk::PlanarFigureInteractor::Pointer figureInteractor;
+
+ //Create DataNode as a container for our PlanarFigure
+ node = mitk::DataNode::New();
+ node->SetData(figure);
+
+ mitk::InteractionTestHelper interactionTestHelper(GetTestDataFilePath(interactionXmlPath));
+
+
+ //Load a bounding image
+ mitk::Image::Pointer testImage = mitk::IOUtil::LoadImage(GetTestDataFilePath("InteractionTestData/InputData/scaledSingleSlice.nrrd"));
+
+ mitk::DataNode::Pointer dn = mitk::DataNode::New();
+ dn->SetData(testImage);
+ interactionTestHelper.AddNodeToStorage(dn);
+ interactionTestHelper.GetDataStorage()->Add(node, dn);
+
+
+ node->SetName("PLANAR FIGURE");
+ // set as selected
+ node->SetSelected(true);
+ node->AddProperty("selected", mitk::BoolProperty::New(true));
+
+ //Load state machine
+ figureInteractor = mitk::PlanarFigureInteractor::New();
+ us::Module* planarFigureModule = us::ModuleRegistry::GetModule("MitkPlanarFigure");
+ figureInteractor->LoadStateMachine("PlanarFigureInteraction.xml", planarFigureModule );
+ figureInteractor->SetEventConfig( "PlanarFigureConfig.xml", planarFigureModule );
+ figureInteractor->SetDataNode( node );
+
+
+ //Start Interaction
+ interactionTestHelper.PlaybackInteraction();
+
+ //Load reference PlanarFigure
+ mitk::PlanarFigureReader::Pointer reader = mitk::PlanarFigureReader::New();
+ reader->SetFileName(GetTestDataFilePath(referenceFigurePath));
+ reader->Update();
+ mitk::PlanarFigure::Pointer reference = reader->GetOutput(0);
+
+ //Compare figures
+ MITK_ASSERT_EQUAL(figure, reference, "Compare figure with reference");
+ }
+
+ void AngleInteractionCreate()
+ {
+ mitk::PlanarFigure::Pointer figure;
+ figure = mitk::PlanarAngle::New();
+ RunTest(figure, "InteractionTestData/Interactions/Angle.xml", "InteractionTestData/ReferenceData/Angle.pf");
+ }
+
+ void BezierCurveInteractionCreate()
+ {
+ mitk::PlanarFigure::Pointer figure;
+ figure = mitk::PlanarBezierCurve::New();
+ RunTest(figure, "InteractionTestData/Interactions/Bezier.xml", "InteractionTestData/ReferenceData/Bezier.pf");
+ }
+
+ void CircleInteractionCreate()
+ {
+ mitk::PlanarFigure::Pointer figure;
+ figure = mitk::PlanarCircle::New();
+ RunTest(figure, "InteractionTestData/Interactions/Circle.xml", "InteractionTestData/ReferenceData/Circle.pf");
+ }
+
+ void DoubleEllipseInteractionCreate()
+ {
+ mitk::PlanarFigure::Pointer figure;
+ figure = mitk::PlanarDoubleEllipse::New();
+ RunTest(figure, "InteractionTestData/Interactions/DoubleEllipse.xml", "InteractionTestData/ReferenceData/DoubleEllipse.pf");
+ }
+
+ void PlanarSubdivisionInteractionCreate()
+ {
+ mitk::PlanarFigure::Pointer figure;
+ figure = mitk::PlanarSubdivisionPolygon::New();
+ RunTest(figure, "InteractionTestData/Interactions/SubDivision.xml", "InteractionTestData/ReferenceData/SubDivision.pf");
+ }
+
+ void PlanarFourPointAngleInteractionCreate()
+ {
+ mitk::PlanarFigure::Pointer figure;
+ figure = mitk::PlanarFourPointAngle::New();
+ RunTest(figure, "InteractionTestData/Interactions/Planar4PointAngle.xml", "InteractionTestData/ReferenceData/Planar4PointAngle.pf");
+ }
+
+ void PlanarLineInteractionCreate()
+ {
+ mitk::PlanarFigure::Pointer figure;
+ figure = mitk::PlanarLine::New();
+ RunTest(figure, "InteractionTestData/Interactions/Line.xml", "InteractionTestData/ReferenceData/Line.pf");
+ }
+
+ void PlanarPolygonInteractionCreate()
+ {
+ mitk::PlanarFigure::Pointer figure;
+ figure = mitk::PlanarPolygon::New();
+ RunTest(figure, "InteractionTestData/Interactions/Polygon.xml", "InteractionTestData/ReferenceData/Polygon.pf");
+ }
+
+ void NonClosedPlanarPolygonInteractionCreate()
+ {
+ mitk::PlanarPolygon::Pointer figure;
+ figure = mitk::PlanarPolygon::New();
+ figure->ClosedOff();
+ RunTest(figure.GetPointer(), "InteractionTestData/Interactions/Path.xml", "InteractionTestData/ReferenceData/Path.pf");
+ }
+
+ void RectangleInteractionCreate()
+ {
+ mitk::PlanarFigure::Pointer figure;
+ figure = mitk::PlanarRectangle::New();
+ RunTest(figure, "InteractionTestData/Interactions/Rectangle.xml", "InteractionTestData/ReferenceData/Rectangle.pf");
+ }
+
+};
+
+MITK_TEST_SUITE_REGISTRATION(mitkPlanarFigureInteraction)