Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions DynamicModeler/Logic/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ set(${KIT}_SRCS
vtkSlicer${MODULE_NAME}ROICutTool.h
vtkSlicer${MODULE_NAME}SelectByPointsTool.cxx
vtkSlicer${MODULE_NAME}SelectByPointsTool.h
vtkSlicer${MODULE_NAME}SubdivideTool.cxx
vtkSlicer${MODULE_NAME}SubdivideTool.h
vtkSlicer${MODULE_NAME}Tool.cxx
vtkSlicer${MODULE_NAME}Tool.h
vtkSlicer${MODULE_NAME}ToolFactory.cxx
Expand Down
221 changes: 221 additions & 0 deletions DynamicModeler/Logic/vtkSlicerDynamicModelerSubdivideTool.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
/*==============================================================================

This dynamic modeler tool was developed by Mauro I. Dominguez, Independent
as Ad-Honorem work.

Copyright (c) All Rights Reserved.

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

==============================================================================*/

#include "vtkSlicerDynamicModelerSubdivideTool.h"

#include "vtkMRMLDynamicModelerNode.h"

// MRML includes
#include <vtkMRMLModelNode.h>
#include <vtkMRMLTransformNode.h>

// VTK includes
#include <vtkCommand.h>
#include <vtkGeneralTransform.h>
#include <vtkSmartPointer.h>
#include <vtkStringArray.h>
#include <vtkTransform.h>
#include <vtkTransformPolyDataFilter.h>
#include <vtkButterflySubdivisionFilter.h>
#include <vtkLinearSubdivisionFilter.h>
#include <vtkLoopSubdivisionFilter.h>
#include <vtkTriangleFilter.h>

//----------------------------------------------------------------------------
vtkToolNewMacro(vtkSlicerDynamicModelerSubdivideTool);

const char* SUBDIVIDE_INPUT_MODEL_REFERENCE_ROLE = "Subdivide.InputModel";
const char* SUBDIVIDE_OUTPUT_MODEL_REFERENCE_ROLE = "Subdivide.OutputModel";

//----------------------------------------------------------------------------
vtkSlicerDynamicModelerSubdivideTool::vtkSlicerDynamicModelerSubdivideTool()
{
/////////
// Inputs
vtkNew<vtkIntArray> inputModelEvents;
inputModelEvents->InsertNextTuple1(vtkCommand::ModifiedEvent);
inputModelEvents->InsertNextTuple1(vtkMRMLModelNode::MeshModifiedEvent);
inputModelEvents->InsertNextTuple1(vtkMRMLTransformableNode::TransformModifiedEvent);
vtkNew<vtkStringArray> inputModelClassNames;
inputModelClassNames->InsertNextValue("vtkMRMLModelNode");
NodeInfo inputModel(
"Model node",
"Model node to subdivide.",
inputModelClassNames,
SUBDIVIDE_INPUT_MODEL_REFERENCE_ROLE,
true,
false,
inputModelEvents
);
this->InputNodeInfo.push_back(inputModel);

/////////
// Outputs
NodeInfo outputModel(
"Output model (subdivided)",
"Result from using the selected subdivision filter.",
inputModelClassNames,
SUBDIVIDE_OUTPUT_MODEL_REFERENCE_ROLE,
false,
false
);
this->OutputNodeInfo.push_back(outputModel);

/////////
// Parameters
ParameterInfo parameterOperationType(
"Subdivision algorithm",
"Method used to calculate the new cells of the output mesh.",
"SubdivisionAlgorithm",
PARAMETER_STRING_ENUM,
"Butterfly"
);

vtkNew<vtkStringArray> possibleValues;
parameterOperationType.PossibleValues = possibleValues;
parameterOperationType.PossibleValues->InsertNextValue("Butterfly");
parameterOperationType.PossibleValues->InsertNextValue("Linear");
parameterOperationType.PossibleValues->InsertNextValue("Loop");
this->InputParameterInfo.push_back(parameterOperationType);

ParameterInfo parameterNumberOfIterations(
"Number of iterations",
"Number of times the subdivision algorithm is applied. If 0, the input mesh is only triangulated.",
"NumberOfIterations",
PARAMETER_INT,
1
);

vtkNew<vtkDoubleArray> numberOfIterationsRange;
numberOfIterationsRange->SetNumberOfComponents(1);
numberOfIterationsRange->SetNumberOfValues(2);
numberOfIterationsRange->SetValue(0, 0);
numberOfIterationsRange->SetValue(1, 20);
parameterNumberOfIterations.NumbersRange = numberOfIterationsRange;

this->InputParameterInfo.push_back(parameterNumberOfIterations);

this->InputModelToWorldTransformFilter = vtkSmartPointer<vtkTransformPolyDataFilter>::New();
this->InputModelNodeToWorldTransform = vtkSmartPointer<vtkGeneralTransform>::New();
this->InputModelToWorldTransformFilter->SetTransform(this->InputModelNodeToWorldTransform);

this->AuxiliarTriangleFilter = vtkSmartPointer<vtkTriangleFilter>::New();
this->AuxiliarTriangleFilter->SetInputConnection(this->InputModelToWorldTransformFilter->GetOutputPort());

this->ButterflySubdivisionFilter = vtkSmartPointer<vtkButterflySubdivisionFilter>::New();
this->LinearSubdivisionFilter = vtkSmartPointer<vtkLinearSubdivisionFilter>::New();
this->LoopSubdivisionFilter = vtkSmartPointer<vtkLoopSubdivisionFilter>::New();
this->ButterflySubdivisionFilter->SetInputConnection(this->AuxiliarTriangleFilter->GetOutputPort());
this->LinearSubdivisionFilter->SetInputConnection(this->AuxiliarTriangleFilter->GetOutputPort());
this->LoopSubdivisionFilter->SetInputConnection(this->AuxiliarTriangleFilter->GetOutputPort());

this->OutputModelToWorldTransformFilter = vtkSmartPointer<vtkTransformPolyDataFilter>::New();
this->OutputWorldToModelTransform = vtkSmartPointer<vtkGeneralTransform>::New();
this->OutputModelToWorldTransformFilter->SetTransform(this->OutputWorldToModelTransform);
}

//----------------------------------------------------------------------------
vtkSlicerDynamicModelerSubdivideTool::~vtkSlicerDynamicModelerSubdivideTool()
= default;

//----------------------------------------------------------------------------
const char* vtkSlicerDynamicModelerSubdivideTool::GetName()
{
return "Subdivide";
}

//----------------------------------------------------------------------------
bool vtkSlicerDynamicModelerSubdivideTool::RunInternal(vtkMRMLDynamicModelerNode* surfaceEditorNode)
{
if (!this->HasRequiredInputs(surfaceEditorNode))
{
vtkErrorMacro("Invalid number of inputs");
return false;
}

vtkMRMLModelNode* outputModelNode = vtkMRMLModelNode::SafeDownCast(surfaceEditorNode->GetNodeReference(SUBDIVIDE_OUTPUT_MODEL_REFERENCE_ROLE));
if (!outputModelNode)
{
// Nothing to output.
return true;
}

int numberOfIterations = this->GetNthInputParameterValue(1, surfaceEditorNode).ToInt();
if (numberOfIterations >= 1)
{
this->ButterflySubdivisionFilter->SetNumberOfSubdivisions(numberOfIterations);
this->LinearSubdivisionFilter->SetNumberOfSubdivisions(numberOfIterations);
this->LoopSubdivisionFilter->SetNumberOfSubdivisions(numberOfIterations);

std::string subdivisionAlgorithm = this->GetNthInputParameterValue(0, surfaceEditorNode).ToString();
if (subdivisionAlgorithm == "Butterfly")
{
this->OutputModelToWorldTransformFilter->SetInputConnection(this->ButterflySubdivisionFilter->GetOutputPort());
}
else if (subdivisionAlgorithm == "Linear")
{
this->OutputModelToWorldTransformFilter->SetInputConnection(this->LinearSubdivisionFilter->GetOutputPort());
}
else if (subdivisionAlgorithm == "Loop")
{
this->OutputModelToWorldTransformFilter->SetInputConnection(this->LoopSubdivisionFilter->GetOutputPort());
}
}
else
{
this->OutputModelToWorldTransformFilter->SetInputConnection(this->AuxiliarTriangleFilter->GetOutputPort());
}

vtkMRMLModelNode* inputModelNode = vtkMRMLModelNode::SafeDownCast(surfaceEditorNode->GetNodeReference(SUBDIVIDE_INPUT_MODEL_REFERENCE_ROLE));
if (!inputModelNode)
{
vtkErrorMacro("Invalid input model node!");
return false;
}

if (!inputModelNode->GetMesh() || inputModelNode->GetMesh()->GetNumberOfPoints() == 0)
{
return true;
}

if (inputModelNode->GetParentTransformNode())
{
inputModelNode->GetParentTransformNode()->GetTransformToWorld(this->InputModelNodeToWorldTransform);
}
else
{
this->InputModelNodeToWorldTransform->Identity();
}
if (outputModelNode && outputModelNode->GetParentTransformNode())
{
outputModelNode->GetParentTransformNode()->GetTransformFromWorld(this->OutputWorldToModelTransform);
}
else
{
this->OutputWorldToModelTransform->Identity();
}

this->InputModelToWorldTransformFilter->SetInputConnection(inputModelNode->GetMeshConnection());

this->OutputModelToWorldTransformFilter->Update();
vtkNew<vtkPolyData> outputMesh;
outputMesh->DeepCopy(this->OutputModelToWorldTransformFilter->GetOutput());

MRMLNodeModifyBlocker blocker(outputModelNode);
outputModelNode->SetAndObserveMesh(outputMesh);
outputModelNode->InvokeCustomModifiedEvent(vtkMRMLModelNode::MeshModifiedEvent);

return true;
}
80 changes: 80 additions & 0 deletions DynamicModeler/Logic/vtkSlicerDynamicModelerSubdivideTool.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*==============================================================================

This dynamic modeler tool was developed by Mauro I. Dominguez, Independent
as Ad-Honorem work.

Copyright (c) All Rights Reserved.

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

==============================================================================*/

#ifndef __vtkSlicerDynamicModelerSubdivideTool_h
#define __vtkSlicerDynamicModelerSubdivideTool_h

#include "vtkSlicerDynamicModelerModuleLogicExport.h"

// VTK includes
#include <vtkObject.h>
#include <vtkSmartPointer.h>

// STD includes
#include <map>
#include <string>
#include <vector>

class vtkDataObject;
class vtkGeneralTransform;
class vtkMRMLDynamicModelerNode;
class vtkButterflySubdivisionFilter;
class vtkLinearSubdivisionFilter;
class vtkLoopSubdivisionFilter;
class vtkTriangleFilter;
class vtkPolyData;
class vtkTransformPolyDataFilter;

#include "vtkSlicerDynamicModelerTool.h"

/// \brief Dynamic modeler tool to subdivide cells of a mesh.
///
/// Has one node inputs (Surface), and one output (The subdivided surface).
class VTK_SLICER_DYNAMICMODELER_MODULE_LOGIC_EXPORT vtkSlicerDynamicModelerSubdivideTool : public vtkSlicerDynamicModelerTool
{
public:
static vtkSlicerDynamicModelerSubdivideTool* New();
vtkSlicerDynamicModelerTool* CreateToolInstance() override;
vtkTypeMacro(vtkSlicerDynamicModelerSubdivideTool, vtkSlicerDynamicModelerTool);

/// Human-readable name of the mesh modification tool
const char* GetName() override;

/// Run the subdivision algorithm on the input model node
bool RunInternal(vtkMRMLDynamicModelerNode* surfaceEditorNode) override;

protected:
vtkSlicerDynamicModelerSubdivideTool();
~vtkSlicerDynamicModelerSubdivideTool() override;
void operator=(const vtkSlicerDynamicModelerSubdivideTool&);

protected:
vtkSmartPointer<vtkTransformPolyDataFilter> InputModelToWorldTransformFilter;
vtkSmartPointer<vtkGeneralTransform> InputModelNodeToWorldTransform;

vtkSmartPointer<vtkTriangleFilter> AuxiliarTriangleFilter;

vtkSmartPointer<vtkButterflySubdivisionFilter> ButterflySubdivisionFilter;
vtkSmartPointer<vtkLinearSubdivisionFilter> LinearSubdivisionFilter;
vtkSmartPointer<vtkLoopSubdivisionFilter> LoopSubdivisionFilter;

vtkSmartPointer<vtkTransformPolyDataFilter> OutputModelToWorldTransformFilter;
vtkSmartPointer<vtkGeneralTransform> OutputWorldToModelTransform;

private:
vtkSlicerDynamicModelerSubdivideTool(const vtkSlicerDynamicModelerSubdivideTool&) = delete;
};

#endif // __vtkSlicerDynamicModelerSubdivideTool_h
2 changes: 2 additions & 0 deletions DynamicModeler/Logic/vtkSlicerDynamicModelerToolFactory.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ limitations under the License.
#include "vtkSlicerDynamicModelerPlaneCutTool.h"
#include "vtkSlicerDynamicModelerROICutTool.h"
#include "vtkSlicerDynamicModelerSelectByPointsTool.h"
#include "vtkSlicerDynamicModelerSubdivideTool.h"
#include "vtkSlicerDynamicModelerToolFactory.h"
#include "vtkSlicerDynamicModelerTool.h"

Expand Down Expand Up @@ -127,6 +128,7 @@ void vtkSlicerDynamicModelerToolFactory::classInitialize()
vtkSlicerDynamicModelerToolFactoryInstance->RegisterDynamicModelerTool(vtkSmartPointer<vtkSlicerDynamicModelerPlaneCutTool>::New());
vtkSlicerDynamicModelerToolFactoryInstance->RegisterDynamicModelerTool(vtkSmartPointer<vtkSlicerDynamicModelerExtrudeTool>::New());
vtkSlicerDynamicModelerToolFactoryInstance->RegisterDynamicModelerTool(vtkSmartPointer<vtkSlicerDynamicModelerRevolveTool>::New());
vtkSlicerDynamicModelerToolFactoryInstance->RegisterDynamicModelerTool(vtkSmartPointer<vtkSlicerDynamicModelerSubdivideTool>::New());
vtkSlicerDynamicModelerToolFactoryInstance->RegisterDynamicModelerTool(vtkSmartPointer<vtkSlicerDynamicModelerHollowTool>::New());
vtkSlicerDynamicModelerToolFactoryInstance->RegisterDynamicModelerTool(vtkSmartPointer<vtkSlicerDynamicModelerMarginTool>::New());
vtkSlicerDynamicModelerToolFactoryInstance->RegisterDynamicModelerTool(vtkSmartPointer<vtkSlicerDynamicModelerMirrorTool>::New());
Expand Down
Binary file added DynamicModeler/Resources/Icons/Subdivide.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions DynamicModeler/Resources/qSlicerDynamicModelerModule.qrc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<file>Icons/DynamicModeler.png</file>
<file>Icons/Extrude.png</file>
<file>Icons/Revolve.png</file>
<file>Icons/Subdivide.png</file>
<file>Icons/Hollow.png</file>
<file>Icons/Margin.png</file>
<file>Icons/PlaneCut.png</file>
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@
<file>Icons/Mirror.png</file>
<file>Icons/ROICut.png</file>
<file>Icons/SelectByPoints.png</file>
<file>Icons/Subdivide.png</file>
</qresource>
</RCC>
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
#include "vtkSlicerDynamicModelerPlaneCutTool.h"
#include "vtkSlicerDynamicModelerROICutTool.h"
#include "vtkSlicerDynamicModelerSelectByPointsTool.h"
#include "vtkSlicerDynamicModelerSubdivideTool.h"

// DynamicModeler MRML includes
#include <vtkMRMLDynamicModelerNode.h>
Expand Down Expand Up @@ -248,6 +249,12 @@ QIcon qSlicerSubjectHierarchyDynamicModelerPlugin::icon(vtkIdType itemID)
return QIcon(":Icons/Revolve.png");
}

vtkNew<vtkSlicerDynamicModelerSubdivideTool> subdivideTool;
if (strcmp(associatedNode->GetToolName(), subdivideTool->GetName()) == 0)
{
return QIcon(":Icons/Subdivide.png");
}

vtkNew<vtkSlicerDynamicModelerHollowTool> hollowTool;
if (strcmp(associatedNode->GetToolName(), hollowTool->GetName()) == 0)
{
Expand Down
5 changes: 5 additions & 0 deletions DynamicModeler/qSlicerDynamicModelerModuleWidget.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
#include <vtkSlicerDynamicModelerPlaneCutTool.h>
#include <vtkSlicerDynamicModelerROICutTool.h>
#include <vtkSlicerDynamicModelerSelectByPointsTool.h>
#include <vtkSlicerDynamicModelerSubdivideTool.h>
#include <vtkSlicerDynamicModelerToolFactory.h>

// DynamicModeler MRML includes
Expand Down Expand Up @@ -133,6 +134,10 @@ void qSlicerDynamicModelerModuleWidget::setup()
this->addToolButton(QIcon(":/Icons/Revolve.png"), revolveTool, buttonPosition / columns, buttonPosition % columns);
buttonPosition++;

vtkNew<vtkSlicerDynamicModelerSubdivideTool> subdivideTool;
this->addToolButton(QIcon(":/Icons/Subdivide.png"), subdivideTool, buttonPosition / columns, buttonPosition % columns);
buttonPosition++;

vtkNew<vtkSlicerDynamicModelerHollowTool> hollowTool;
this->addToolButton(QIcon(":/Icons/Hollow.png"), hollowTool, buttonPosition / columns, buttonPosition % columns);
buttonPosition++;
Expand Down