Skip to content

Commit

Permalink
ENH: Add miscellaneous improvements to markups VTK widgets
Browse files Browse the repository at this point in the history
- Improve organization of actors/mappers in VTK markup widgets
    - Mappers, actors, etc. are now grouped together
- Remove UpdateOccludedRelativeCoincidentTopologyOffsets and update UpdateRelativeCoincidentTopologyOffsets to accept two arguments.
- Add explanation for default OccludedRelativeOffset
- Reduce opacity maximum to 0.99 (was 0.99999999) to prevent floating point issues
- Indentation fixes
  • Loading branch information
Sunderlandkyl committed Sep 1, 2020
1 parent 3f3f72f commit 412b656
Show file tree
Hide file tree
Showing 12 changed files with 139 additions and 123 deletions.
Expand Up @@ -145,7 +145,7 @@ class VTK_MRML_DISPLAYABLEMANAGER_EXPORT vtkMRMLAbstractWidgetRepresentation : p
/// using the renderer of this class.
void GetRendererComputedDisplayPositionFromWorldPosition(const double worldPos[3], double displayPos[2]);

void UpdateRelativeCoincidentTopologyOffsets(vtkMapper* mapper);
virtual void UpdateRelativeCoincidentTopologyOffsets(vtkMapper* mapper);

/// The renderer in which this widget is placed
vtkWeakPointer<vtkRenderer> Renderer;
Expand Down
Expand Up @@ -42,6 +42,7 @@ vtkStandardNewMacro(vtkSlicerAngleRepresentation3D);
vtkSlicerAngleRepresentation3D::vtkSlicerAngleRepresentation3D()
{
this->Line = vtkSmartPointer<vtkPolyData>::New();

this->Arc = vtkSmartPointer<vtkArcSource>::New();
this->Arc->SetResolution(30);

Expand All @@ -55,12 +56,20 @@ vtkSlicerAngleRepresentation3D::vtkSlicerAngleRepresentation3D()
this->ArcTubeFilter->SetNumberOfSides(20);
this->ArcTubeFilter->SetRadius(1);

// Mappers
this->LineMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
this->LineMapper->SetInputConnection(this->TubeFilter->GetOutputPort());

this->ArcMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
this->ArcMapper->SetInputConnection(this->ArcTubeFilter->GetOutputPort());

this->LineOccludedMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
this->LineOccludedMapper->SetInputConnection(this->TubeFilter->GetOutputPort());

this->ArcOccludedMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
this->ArcOccludedMapper->SetInputConnection(this->ArcTubeFilter->GetOutputPort());

// Actors
this->LineActor = vtkSmartPointer<vtkActor>::New();
this->LineActor->SetMapper(this->LineMapper);
this->LineActor->SetProperty(this->GetControlPointsPipeline(Unselected)->Property);
Expand All @@ -69,12 +78,6 @@ vtkSlicerAngleRepresentation3D::vtkSlicerAngleRepresentation3D()
this->ArcActor->SetMapper(this->ArcMapper);
this->ArcActor->SetProperty(this->GetControlPointsPipeline(Unselected)->Property);

this->LineOccludedMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
this->LineOccludedMapper->SetInputConnection(this->TubeFilter->GetOutputPort());

this->ArcOccludedMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
this->ArcOccludedMapper->SetInputConnection(this->ArcTubeFilter->GetOutputPort());

this->LineOccludedActor = vtkSmartPointer<vtkActor>::New();
this->LineOccludedActor->SetMapper(this->LineOccludedMapper);
this->LineOccludedActor->SetProperty(this->GetControlPointsPipeline(Unselected)->OccludedProperty);
Expand Down Expand Up @@ -200,10 +203,8 @@ void vtkSlicerAngleRepresentation3D::UpdateFromMRML(vtkMRMLNode* caller, unsigne

// Update lines display properties

this->UpdateRelativeCoincidentTopologyOffsets(this->LineMapper);
this->UpdateRelativeCoincidentTopologyOffsets(this->ArcMapper);
this->UpdateOccludedRelativeCoincidentTopologyOffsets(this->LineOccludedMapper);
this->UpdateOccludedRelativeCoincidentTopologyOffsets(this->ArcOccludedMapper);
this->UpdateRelativeCoincidentTopologyOffsets(this->LineMapper, this->LineOccludedMapper);
this->UpdateRelativeCoincidentTopologyOffsets(this->ArcMapper, this->ArcOccludedMapper);

double diameter = ( this->MarkupsDisplayNode->GetCurveLineSizeMode() == vtkMRMLMarkupsDisplayNode::UseLineDiameter ?
this->MarkupsDisplayNode->GetLineDiameter() : this->ControlPointSize * this->MarkupsDisplayNode->GetLineThickness() );
Expand Down
Expand Up @@ -76,22 +76,20 @@ class VTK_SLICER_MARKUPS_MODULE_VTKWIDGETS_EXPORT vtkSlicerAngleRepresentation3D
vtkSlicerAngleRepresentation3D();
~vtkSlicerAngleRepresentation3D() override;

vtkSmartPointer<vtkPolyData> Line;
vtkSmartPointer<vtkPolyDataMapper> LineMapper;
vtkSmartPointer<vtkActor> LineActor;

vtkSmartPointer<vtkArcSource> Arc;
vtkSmartPointer<vtkPolyDataMapper> ArcMapper;
vtkSmartPointer<vtkActor> ArcActor;

vtkSmartPointer<vtkTubeFilter> TubeFilter;
vtkSmartPointer<vtkTubeFilter> ArcTubeFilter;

vtkSmartPointer<vtkPolyDataMapper> LineOccludedMapper;
vtkSmartPointer<vtkActor> LineOccludedActor;

vtkSmartPointer<vtkPolyDataMapper> ArcOccludedMapper;
vtkSmartPointer<vtkActor> ArcOccludedActor;
vtkSmartPointer<vtkPolyData> Line;
vtkSmartPointer<vtkArcSource> Arc;
vtkSmartPointer<vtkTubeFilter> TubeFilter;
vtkSmartPointer<vtkTubeFilter> ArcTubeFilter;

vtkSmartPointer<vtkPolyDataMapper> LineMapper;
vtkSmartPointer<vtkPolyDataMapper> ArcMapper;
vtkSmartPointer<vtkPolyDataMapper> LineOccludedMapper;
vtkSmartPointer<vtkPolyDataMapper> ArcOccludedMapper;

vtkSmartPointer<vtkActor> LineActor;
vtkSmartPointer<vtkActor> ArcActor;
vtkSmartPointer<vtkActor> LineOccludedActor;
vtkSmartPointer<vtkActor> ArcOccludedActor;

void BuildArc();

Expand Down
Expand Up @@ -43,16 +43,18 @@ vtkSlicerCurveRepresentation3D::vtkSlicerCurveRepresentation3D()
this->TubeFilter->SetNumberOfSides(20);
this->TubeFilter->SetRadius(1);

// Mappers
this->LineMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
this->LineMapper->SetInputConnection(this->TubeFilter->GetOutputPort());

this->LineOccludedMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
this->LineOccludedMapper->SetInputConnection(this->TubeFilter->GetOutputPort());

// Actors
this->LineActor = vtkSmartPointer<vtkActor>::New();
this->LineActor->SetMapper(this->LineMapper);
this->LineActor->SetProperty(this->GetControlPointsPipeline(Unselected)->Property);

this->LineOccludedMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
this->LineOccludedMapper->SetInputConnection(this->TubeFilter->GetOutputPort());

this->LineOccludedActor = vtkSmartPointer<vtkActor>::New();
this->LineOccludedActor->SetMapper(this->LineOccludedMapper);
this->LineOccludedActor->SetProperty(this->GetControlPointsPipeline(Unselected)->OccludedProperty);
Expand Down Expand Up @@ -89,11 +91,10 @@ void vtkSlicerCurveRepresentation3D::UpdateFromMRML(vtkMRMLNode* caller, unsigne
&& this->MarkupsDisplayNode->GetTextScale() > 0.0);
controlPoints->Glypher->SetScaleFactor(this->ControlPointSize);

this->UpdateRelativeCoincidentTopologyOffsets(controlPoints->Mapper);
this->UpdateRelativeCoincidentTopologyOffsets(controlPoints->Mapper, controlPoints->OccludedMapper);
}

this->UpdateRelativeCoincidentTopologyOffsets(this->LineMapper);
this->UpdateOccludedRelativeCoincidentTopologyOffsets(this->LineOccludedMapper);
this->UpdateRelativeCoincidentTopologyOffsets(this->LineMapper, this->LineOccludedMapper);

double diameter = ( this->MarkupsDisplayNode->GetCurveLineSizeMode() == vtkMRMLMarkupsDisplayNode::UseLineDiameter ?
this->MarkupsDisplayNode->GetLineDiameter() : this->ControlPointSize * this->MarkupsDisplayNode->GetLineThickness() );
Expand Down
Expand Up @@ -80,14 +80,14 @@ class VTK_SLICER_MARKUPS_MODULE_VTKWIDGETS_EXPORT vtkSlicerCurveRepresentation3D

void SetMarkupsNode(vtkMRMLMarkupsNode *markupsNode) override;

vtkSmartPointer<vtkPolyData> Line;
vtkSmartPointer<vtkPolyDataMapper> LineMapper;
vtkSmartPointer<vtkActor> LineActor;
vtkSmartPointer<vtkPolyData> Line;
vtkSmartPointer<vtkTubeFilter> TubeFilter;

vtkSmartPointer<vtkPolyDataMapper> LineMapper;
vtkSmartPointer<vtkPolyDataMapper> LineOccludedMapper;
vtkSmartPointer<vtkActor> LineOccludedActor;

vtkSmartPointer<vtkTubeFilter> TubeFilter;
vtkSmartPointer<vtkActor> LineActor;
vtkSmartPointer<vtkActor> LineOccludedActor;

vtkSmartPointer<vtkCellLocator> CurvePointLocator;

Expand Down
Expand Up @@ -44,16 +44,18 @@ vtkSlicerLineRepresentation3D::vtkSlicerLineRepresentation3D()
this->TubeFilter->SetNumberOfSides(20);
this->TubeFilter->SetRadius(1);

// Mappers
this->LineMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
this->LineMapper->SetInputConnection(this->TubeFilter->GetOutputPort());

this->LineOccludedMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
this->LineOccludedMapper->SetInputConnection(this->TubeFilter->GetOutputPort());

// Actors
this->LineActor = vtkSmartPointer<vtkActor>::New();
this->LineActor->SetMapper(this->LineMapper);
this->LineActor->SetProperty(this->GetControlPointsPipeline(Unselected)->Property);

this->LineOccludedMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
this->LineOccludedMapper->SetInputConnection(this->TubeFilter->GetOutputPort());

this->LineOccludedActor = vtkSmartPointer<vtkActor>::New();
this->LineOccludedActor->SetMapper(this->LineOccludedMapper);
this->LineOccludedActor->SetProperty(this->GetControlPointsPipeline(Unselected)->OccludedProperty);
Expand Down Expand Up @@ -190,8 +192,7 @@ void vtkSlicerLineRepresentation3D::UpdateFromMRML(vtkMRMLNode* caller, unsigned

// Line display

this->UpdateRelativeCoincidentTopologyOffsets(this->LineMapper);
this->UpdateOccludedRelativeCoincidentTopologyOffsets(this->LineOccludedMapper);
this->UpdateRelativeCoincidentTopologyOffsets(this->LineMapper, this->LineOccludedMapper);

double diameter = ( this->MarkupsDisplayNode->GetCurveLineSizeMode() == vtkMRMLMarkupsDisplayNode::UseLineDiameter ?
this->MarkupsDisplayNode->GetLineDiameter() : this->ControlPointSize * this->MarkupsDisplayNode->GetLineThickness() );
Expand Down
Expand Up @@ -77,13 +77,13 @@ class VTK_SLICER_MARKUPS_MODULE_VTKWIDGETS_EXPORT vtkSlicerLineRepresentation3D
void UpdateInteractionPipeline() override;

vtkSmartPointer<vtkPolyData> Line;
vtkSmartPointer<vtkPolyDataMapper> LineMapper;
vtkSmartPointer<vtkActor> LineActor;
vtkSmartPointer<vtkTubeFilter> TubeFilter;

vtkSmartPointer<vtkPolyDataMapper> LineMapper;
vtkSmartPointer<vtkPolyDataMapper> LineOccludedMapper;
vtkSmartPointer<vtkActor> LineOccludedActor;

vtkSmartPointer<vtkTubeFilter> TubeFilter;
vtkSmartPointer<vtkActor> LineActor;
vtkSmartPointer<vtkActor> LineOccludedActor;

private:
vtkSlicerLineRepresentation3D(const vtkSlicerLineRepresentation3D&) = delete;
Expand Down
Expand Up @@ -55,10 +55,10 @@ vtkSlicerMarkupsWidgetRepresentation3D::ControlPointsPipeline3D::ControlPointsPi
this->Glypher->ScalingOn();
this->Glypher->SetScaleModeToDataScalingOff();
this->Glypher->SetScaleFactor(1.0);

// By default the Points are rendered as spheres
this->Glypher->SetSourceConnection(this->GlyphSourceSphere->GetOutputPort());

// Properties
this->Property = vtkSmartPointer<vtkProperty>::New();
this->Property->SetRepresentationToSurface();
this->Property->SetColor(0.4, 1.0, 1.0);
Expand All @@ -71,31 +71,15 @@ vtkSlicerMarkupsWidgetRepresentation3D::ControlPointsPipeline3D::ControlPointsPi
this->Property->SetLineWidth(2.);
this->Property->SetOpacity(1.);

this->Mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
this->Mapper->SetInputConnection(this->Glypher->GetOutputPort());
// This turns on resolve coincident topology for everything
// as it is a class static on the mapper
vtkMapper::SetResolveCoincidentTopologyToPolygonOffset();
this->Mapper->ScalarVisibilityOff();

this->Actor = vtkSmartPointer<vtkActor>::New();
this->Actor->SetMapper(this->Mapper);
this->Actor->SetProperty(this->Property);

this->OccludedMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
this->OccludedMapper->SetInputConnection(this->Glypher->GetOutputPort());
this->OccludedMapper->ScalarVisibilityOff();

this->OccludedProperty = vtkSmartPointer<vtkProperty>::New();
this->OccludedProperty->DeepCopy(this->Property);
this->OccludedProperty->SetOpacity(0.0);

this->OccludedActor = vtkSmartPointer<vtkActor>::New();
this->OccludedActor->SetMapper(this->OccludedMapper);
this->OccludedActor->SetProperty(this->OccludedProperty);

// Labels
this->OccludedTextProperty = vtkSmartPointer<vtkTextProperty>::New();
this->OccludedTextProperty->ShallowCopy(this->TextProperty);
this->OccludedTextProperty->SetOpacity(0.0);

// Label point filters
this->ControlPointIndices = vtkSmartPointer<vtkIdTypeArray>::New();
this->ControlPointIndices->SetName("controlPointIndices");
this->ControlPointIndices->Allocate(100);
Expand All @@ -112,38 +96,52 @@ vtkSlicerMarkupsWidgetRepresentation3D::ControlPointsPipeline3D::ControlPointsPi
// Updates to SelectVisiblePoints must only happen at the start of the RenderOverlay function.
this->PointSetToLabelHierarchyFilter->SetInputData(this->SelectVisiblePoints->GetOutput());

this->OccludedPointSetToLabelHierarchyFilter = vtkSmartPointer<vtkPointSetToLabelHierarchy>::New();
this->OccludedPointSetToLabelHierarchyFilter->SetTextProperty(this->OccludedTextProperty);
this->OccludedPointSetToLabelHierarchyFilter->SetLabelArrayName("labels");
this->OccludedPointSetToLabelHierarchyFilter->SetPriorityArrayName("priority");
this->OccludedPointSetToLabelHierarchyFilter->SetInputData(this->LabelControlPointsPolyData);

// Mappers
this->Mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
this->Mapper->SetInputConnection(this->Glypher->GetOutputPort());
// This turns on resolve coincident topology for everything
// as it is a class static on the mapper
vtkMapper::SetResolveCoincidentTopologyToPolygonOffset();
this->Mapper->ScalarVisibilityOff();

this->OccludedMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
this->OccludedMapper->SetInputConnection(this->Glypher->GetOutputPort());
this->OccludedMapper->ScalarVisibilityOff();

this->LabelsMapper = vtkSmartPointer<vtkLabelPlacementMapper>::New();
this->LabelsMapper->SetInputConnection(this->PointSetToLabelHierarchyFilter->GetOutputPort());

this->LabelsMapper->PlaceAllLabelsOn();

/*
We could consider showing labels with semi-transparent background:
this->LabelsMapper->SetShapeToRect();
this->LabelsMapper->SetStyleToFilled();
this->LabelsMapper->SetBackgroundOpacity(0.4);
*/

this->LabelsOccludedMapper = vtkSmartPointer<vtkLabelPlacementMapper>::New();
this->LabelsOccludedMapper->SetInputConnection(this->OccludedPointSetToLabelHierarchyFilter->GetOutputPort());
this->LabelsOccludedMapper->PlaceAllLabelsOn();

// Actors
this->Actor = vtkSmartPointer<vtkActor>::New();
this->Actor->SetMapper(this->Mapper);
this->Actor->SetProperty(this->Property);

this->OccludedActor = vtkSmartPointer<vtkActor>::New();
this->OccludedActor->SetMapper(this->OccludedMapper);
this->OccludedActor->SetProperty(this->OccludedProperty);

this->LabelsActor = vtkSmartPointer<vtkActor2D>::New();
this->LabelsActor->SetMapper(this->LabelsMapper);
this->LabelsActor->PickableOff();
this->LabelsActor->DragableOff();

// Occluded label actor
this->OccludedTextProperty = vtkSmartPointer<vtkTextProperty>::New();
this->OccludedTextProperty->ShallowCopy(this->TextProperty);
this->OccludedTextProperty->SetOpacity(0.0);

this->OccludedPointSetToLabelHierarchyFilter = vtkSmartPointer<vtkPointSetToLabelHierarchy>::New();
this->OccludedPointSetToLabelHierarchyFilter->SetTextProperty(this->OccludedTextProperty);
this->OccludedPointSetToLabelHierarchyFilter->SetLabelArrayName("labels");
this->OccludedPointSetToLabelHierarchyFilter->SetPriorityArrayName("priority");
this->OccludedPointSetToLabelHierarchyFilter->SetInputData(this->LabelControlPointsPolyData);

this->LabelsOccludedMapper = vtkSmartPointer<vtkLabelPlacementMapper>::New();
this->LabelsOccludedMapper->SetInputConnection(this->OccludedPointSetToLabelHierarchyFilter->GetOutputPort());
this->LabelsOccludedMapper->PlaceAllLabelsOn();

this->LabelsOccludedActor = vtkSmartPointer<vtkActor2D>::New();
this->LabelsOccludedActor->SetMapper(this->LabelsOccludedMapper);
this->LabelsOccludedActor->PickableOff();
Expand Down Expand Up @@ -182,7 +180,12 @@ vtkSlicerMarkupsWidgetRepresentation3D::vtkSlicerMarkupsWidgetRepresentation3D()
this->AccuratePicker = vtkSmartPointer<vtkCellPicker>::New();
this->AccuratePicker->SetTolerance(.005);

this->OccludedRelativeOffset = -25000; /// Default occluded relative offset
// Using the minimum value of -65000 creates a lot of rendering artifacts on the occluded objects, as all of the
// pixels in the occluded object will have the same depth buffer value (0.0).
// Using a default value of -25000 strikes a balance between rendering the occluded objects on top of other objects,
// while still providing enough leeway to ensure that occluded actors are rendered correctly relative to themselves
// and to other occluded actors.
this->OccludedRelativeOffset = -25000;
}

//----------------------------------------------------------------------
Expand Down Expand Up @@ -235,8 +238,7 @@ void vtkSlicerMarkupsWidgetRepresentation3D::UpdateAllPointsAndLabelsFromMRML()
continue;
}

this->UpdateRelativeCoincidentTopologyOffsets(controlPoints->Mapper);
this->UpdateOccludedRelativeCoincidentTopologyOffsets(controlPoints->OccludedMapper);
this->UpdateRelativeCoincidentTopologyOffsets(controlPoints->Mapper, controlPoints->OccludedMapper);

controlPoints->Glypher->SetScaleFactor(this->ControlPointSize);

Expand Down Expand Up @@ -695,7 +697,7 @@ void vtkSlicerMarkupsWidgetRepresentation3D::UpdateFromMRML(vtkMRMLNode* caller,
// To prevent some rendering artifacts, and to ensure that the occluded actor does not block point visibility,
// the maximum opacity of the occluded actor is required to be almost, but not fully opaque.
double occludedOpacity =
std::min(0.99999999, this->MarkupsDisplayNode->GetOccludedOpacity() * opacity);
std::min(0.99, this->MarkupsDisplayNode->GetOccludedOpacity() * opacity);
controlPoints->OccludedProperty->SetOpacity(occludedOpacity);
controlPoints->OccludedTextProperty->SetOpacity(occludedOpacity);
}
Expand Down Expand Up @@ -890,7 +892,7 @@ int vtkSlicerMarkupsWidgetRepresentation3D::RenderOpaqueGeometry(
{
ControlPointsPipeline3D* controlPoints = reinterpret_cast<ControlPointsPipeline3D*>(this->ControlPoints[i]);
if (controlPoints->Actor->GetVisibility())
{
{
controlPoints->Glypher->SetFollowedCameraPosition(cameraPosition);
controlPoints->Glypher->SetFollowedCameraViewUp(viewUp);
if (updateControlPointSize)
Expand Down Expand Up @@ -1257,16 +1259,25 @@ void vtkSlicerMarkupsWidgetRepresentation3D::UpdateInteractionPipeline()
}

//-----------------------------------------------------------------------------
void vtkSlicerMarkupsWidgetRepresentation3D::UpdateOccludedRelativeCoincidentTopologyOffsets(vtkMapper* mapper)
void vtkSlicerMarkupsWidgetRepresentation3D::UpdateRelativeCoincidentTopologyOffsets(vtkMapper* mapper, vtkMapper* occludedMapper)
{
Superclass::UpdateRelativeCoincidentTopologyOffsets(mapper);

if (!occludedMapper)
{
return;
}

Superclass::UpdateRelativeCoincidentTopologyOffsets(occludedMapper);

if (!this->MarkupsDisplayNode
|| !this->MarkupsDisplayNode->GetOccludedVisibility()
|| this->MarkupsDisplayNode->GetOccludedOpacity() <= 0.0)
{
return;
}
mapper->SetRelativeCoincidentTopologyLineOffsetParameters(-1, this->OccludedRelativeOffset);
mapper->SetRelativeCoincidentTopologyPolygonOffsetParameters(-1, this->OccludedRelativeOffset);
mapper->SetRelativeCoincidentTopologyPointOffsetParameter(this->OccludedRelativeOffset);

occludedMapper->SetRelativeCoincidentTopologyLineOffsetParameters(-1, this->OccludedRelativeOffset);
occludedMapper->SetRelativeCoincidentTopologyPolygonOffsetParameters(-1, this->OccludedRelativeOffset);
occludedMapper->SetRelativeCoincidentTopologyPointOffsetParameter(this->OccludedRelativeOffset);
}

0 comments on commit 412b656

Please sign in to comment.