You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

566 lines
17 KiB
C

/*=========================================================================
Program: Visualization Toolkit
Module: vtkContourRepresentation.h
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notice for more information.
=========================================================================*/
/**
* @class vtkContourRepresentation
* @brief represent the vtkContourWidget
*
* The vtkContourRepresentation is a superclass for various types of
* representations for vtkContourWidget.
*
* @par Managing contour points:
* The classes vtkContourRepresentationNode, vtkContourRepresentationInternals,
* and vtkContourRepresentationPoint manage the data structure used to represent
* nodes and points on a contour. A contour may contain several nodes and
* several additional points. Nodes are usually the result of user-clicked points
* on the contour. Additional points are created between nodes to generate a
* smooth curve using some Interpolator -- see the method \c SetLineInterpolator.
*
* @par Managing contour points:
* \par
* The data structure stores both the world and display positions for every
* point. (This may seem like a duplication.) The default behaviour of this
* class is to use the WorldPosition to do all the math. Typically a point is
* added at a given display position. Its corresponding world position is
* computed using the point placer, and stored. Any query of the display
* position of a stored point is done via the Renderer, which computes the
* display position given a world position.
*
* @par Managing contour points:
* \par
* So why maintain the display position? Consider drawing a contour on a
* volume widget. You might want the contour to be located at a certain world
* position in the volume or you might want to be overlaid over the window
* like an Actor2D. The default behaviour of this class is to provide the
* former behaviour.
*
* @par Managing contour points:
* \par
* To achieve the latter behaviour, override the methods that return the display
* position (to return the set display position instead of computing it from
* the world positions) and the method \c BuildLines() to interpolate lines
* using their display positions instead of world positions.
*
* @sa
* vtkContourWidget
*/
#ifndef vtkContourRepresentation_h
#define vtkContourRepresentation_h
#include "vtkInteractionWidgetsModule.h" // For export macro
#include "vtkWidgetRepresentation.h"
#include <vector> // STL Header; Required for vector
class vtkContourLineInterpolator;
class vtkIncrementalOctreePointLocator;
class vtkPointPlacer;
class vtkPolyData;
class vtkIdList;
//----------------------------------------------------------------------
class vtkContourRepresentationPoint
{
public:
double WorldPosition[3];
double NormalizedDisplayPosition[2];
// The point id. This is blank except in the case of
// vtkPolygonalSurfaceContourLineInterpolator
vtkIdType PointId;
};
class vtkContourRepresentationNode
{
public:
double WorldPosition[3];
double WorldOrientation[9];
double NormalizedDisplayPosition[2];
int Selected;
std::vector<vtkContourRepresentationPoint*> Points;
// The point id. This is blank except in the case of
// vtkPolygonalSurfaceContourLineInterpolator
vtkIdType PointId;
};
class vtkContourRepresentationInternals
{
public:
std::vector<vtkContourRepresentationNode*> Nodes;
void ClearNodes()
{
for (unsigned int i = 0; i < this->Nodes.size(); i++)
{
for (unsigned int j = 0; j < this->Nodes[i]->Points.size(); j++)
{
delete this->Nodes[i]->Points[j];
}
this->Nodes[i]->Points.clear();
delete this->Nodes[i];
}
this->Nodes.clear();
}
};
class VTKINTERACTIONWIDGETS_EXPORT vtkContourRepresentation : public vtkWidgetRepresentation
{
friend class vtkContourWidget;
public:
//@{
/**
* Standard VTK methods.
*/
vtkTypeMacro(vtkContourRepresentation, vtkWidgetRepresentation);
void PrintSelf(ostream& os, vtkIndent indent) override;
//@}
//@{
/**
* Add a node at a specific world position. Returns 0 if the
* node could not be added, 1 otherwise.
*/
virtual int AddNodeAtWorldPosition(double x, double y, double z);
virtual int AddNodeAtWorldPosition(double worldPos[3]);
virtual int AddNodeAtWorldPosition(double worldPos[3], double worldOrient[9]);
//@}
//@{
/**
* Add a node at a specific display position. This will be
* converted into a world position according to the current
* constraints of the point placer. Return 0 if a point could
* not be added, 1 otherwise.
*/
virtual int AddNodeAtDisplayPosition(double displayPos[2]);
virtual int AddNodeAtDisplayPosition(int displayPos[2]);
virtual int AddNodeAtDisplayPosition(int X, int Y);
//@}
//@{
/**
* Given a display position, activate a node. The closest
* node within tolerance will be activated. If a node is
* activated, 1 will be returned, otherwise 0 will be
* returned.
*/
virtual int ActivateNode(double displayPos[2]);
virtual int ActivateNode(int displayPos[2]);
virtual int ActivateNode(int X, int Y);
//@}
// Description:
// Move the active node to a specified world position.
// Will return 0 if there is no active node or the node
// could not be moved to that position. 1 will be returned
// on success.
virtual int SetActiveNodeToWorldPosition(double pos[3]);
virtual int SetActiveNodeToWorldPosition(double pos[3], double orient[9]);
//@{
/**
* Move the active node based on a specified display position.
* The display position will be converted into a world
* position. If the new position is not valid or there is
* no active node, a 0 will be returned. Otherwise, on
* success a 1 will be returned.
*/
virtual int SetActiveNodeToDisplayPosition(double pos[2]);
virtual int SetActiveNodeToDisplayPosition(int pos[2]);
virtual int SetActiveNodeToDisplayPosition(int X, int Y);
//@}
//@{
/**
* Set/Get whether the active or nth node is selected.
*/
virtual int ToggleActiveNodeSelected();
virtual int GetActiveNodeSelected();
virtual int GetNthNodeSelected(int);
virtual int SetNthNodeSelected(int);
//@}
/**
* Get the world position of the active node. Will return
* 0 if there is no active node, or 1 otherwise.
*/
virtual int GetActiveNodeWorldPosition(double pos[3]);
/**
* Get the world orientation of the active node. Will return
* 0 if there is no active node, or 1 otherwise.
*/
virtual int GetActiveNodeWorldOrientation(double orient[9]);
/**
* Get the display position of the active node. Will return
* 0 if there is no active node, or 1 otherwise.
*/
virtual int GetActiveNodeDisplayPosition(double pos[2]);
/**
* Get the number of nodes.
*/
virtual int GetNumberOfNodes();
/**
* Get the nth node's display position. Will return
* 1 on success, or 0 if there are not at least
* (n+1) nodes (0 based counting).
*/
virtual int GetNthNodeDisplayPosition(int n, double pos[2]);
/**
* Get the nth node's world position. Will return
* 1 on success, or 0 if there are not at least
* (n+1) nodes (0 based counting).
*/
virtual int GetNthNodeWorldPosition(int n, double pos[3]);
/**
* Get the nth node.
*/
virtual vtkContourRepresentationNode* GetNthNode(int n);
/**
* Get the nth node's world orientation. Will return
* 1 on success, or 0 if there are not at least
* (n+1) nodes (0 based counting).
*/
virtual int GetNthNodeWorldOrientation(int n, double orient[9]);
//@{
/**
* Set the nth node's display position. Display position
* will be converted into world position according to the
* constraints of the point placer. Will return
* 1 on success, or 0 if there are not at least
* (n+1) nodes (0 based counting) or the world position
* is not valid.
*/
virtual int SetNthNodeDisplayPosition(int n, int X, int Y);
virtual int SetNthNodeDisplayPosition(int n, int pos[2]);
virtual int SetNthNodeDisplayPosition(int n, double pos[2]);
//@}
//@{
/**
* Set the nth node's world position. Will return
* 1 on success, or 0 if there are not at least
* (n+1) nodes (0 based counting) or the world
* position is not valid according to the point
* placer.
*/
virtual int SetNthNodeWorldPosition(int n, double pos[3]);
virtual int SetNthNodeWorldPosition(int n, double pos[3], double orient[9]);
//@}
/**
* Get the nth node's slope. Will return
* 1 on success, or 0 if there are not at least
* (n+1) nodes (0 based counting).
*/
virtual int GetNthNodeSlope(int idx, double slope[3]);
// Description:
// For a given node n, get the number of intermediate
// points between this node and the node at
// (n+1). If n is the last node and the loop is
// closed, this is the number of intermediate points
// between node n and node 0. 0 is returned if n is
// out of range.
virtual int GetNumberOfIntermediatePoints(int n);
/**
* Get the world position of the intermediate point at
* index idx between nodes n and (n+1) (or n and 0 if
* n is the last node and the loop is closed). Returns
* 1 on success or 0 if n or idx are out of range.
*/
virtual int GetIntermediatePointWorldPosition(int n, int idx, double point[3]);
/**
* Add an intermediate point between node n and n+1
* (or n and 0 if n is the last node and the loop is closed).
* Returns 1 on success or 0 if n is out of range.
*/
virtual int AddIntermediatePointWorldPosition(int n, double point[3]);
/**
* Add an intermediate point between node n and n+1
* (or n and 0 if n is the last node and the loop is closed).
* Returns 1 on success or 0 if n is out of range. The added point is
* assigned a ptId as supplied.
*/
virtual int AddIntermediatePointWorldPosition(int n, double point[3], vtkIdType ptId);
/**
* Delete the last node. Returns 1 on success or 0 if
* there were not any nodes.
*/
virtual int DeleteLastNode();
/**
* Delete the active node. Returns 1 on success or 0 if
* the active node did not indicate a valid node.
*/
virtual int DeleteActiveNode();
/**
* Delete the nth node. Return 1 on success or 0 if n
* is out of range.
*/
virtual int DeleteNthNode(int n);
/**
* Delete all nodes.
*/
virtual void ClearAllNodes();
/**
* Given a specific X, Y pixel location, add a new node
* on the contour at this location.
*/
virtual int AddNodeOnContour(int X, int Y);
//@{
/**
* The tolerance to use when calculations are performed in
* display coordinates
*/
vtkSetClampMacro(PixelTolerance, int, 1, 100);
vtkGetMacro(PixelTolerance, int);
//@}
//@{
/**
* The tolerance to use when calculations are performed in
* world coordinates
*/
vtkSetClampMacro(WorldTolerance, double, 0.0, VTK_DOUBLE_MAX);
vtkGetMacro(WorldTolerance, double);
//@}
// Used to communicate about the state of the representation
enum
{
Outside = 0,
Nearby
};
enum
{
Inactive = 0,
Translate,
Shift,
Scale
};
//@{
/**
* Set / get the current operation. The widget is either
* inactive, or it is being translated.
*/
vtkGetMacro(CurrentOperation, int);
vtkSetClampMacro(
CurrentOperation, int, vtkContourRepresentation::Inactive, vtkContourRepresentation::Scale);
void SetCurrentOperationToInactive()
{
this->SetCurrentOperation(vtkContourRepresentation::Inactive);
}
void SetCurrentOperationToTranslate()
{
this->SetCurrentOperation(vtkContourRepresentation::Translate);
}
void SetCurrentOperationToShift() { this->SetCurrentOperation(vtkContourRepresentation::Shift); }
void SetCurrentOperationToScale() { this->SetCurrentOperation(vtkContourRepresentation::Scale); }
//@}
// Description:
// Set / get the Point Placer. The point placer is
// responsible for converting display coordinates into
// world coordinates according to some constraints, and
// for validating world positions.
void SetPointPlacer(vtkPointPlacer*);
vtkGetObjectMacro(PointPlacer, vtkPointPlacer);
//@{
/**
* Set / Get the Line Interpolator. The line interpolator
* is responsible for generating the line segments connecting
* nodes.
*/
void SetLineInterpolator(vtkContourLineInterpolator*);
vtkGetObjectMacro(LineInterpolator, vtkContourLineInterpolator);
//@}
//@{
/**
* These are methods that satisfy vtkWidgetRepresentation's API.
*/
void BuildRepresentation() override = 0;
int ComputeInteractionState(int X, int Y, int modified = 0) override = 0;
void StartWidgetInteraction(double e[2]) override = 0;
void WidgetInteraction(double e[2]) override = 0;
//@}
//@{
/**
* Methods required by vtkProp superclass.
*/
void ReleaseGraphicsResources(vtkWindow* w) override = 0;
int RenderOverlay(vtkViewport* viewport) override = 0;
int RenderOpaqueGeometry(vtkViewport* viewport) override = 0;
int RenderTranslucentPolygonalGeometry(vtkViewport* viewport) override = 0;
vtkTypeBool HasTranslucentPolygonalGeometry() override = 0;
//@}
//@{
/**
* Set / Get the ClosedLoop value. This ivar indicates whether the contour
* forms a closed loop.
*/
void SetClosedLoop(vtkTypeBool val);
vtkGetMacro(ClosedLoop, vtkTypeBool);
vtkBooleanMacro(ClosedLoop, vtkTypeBool);
//@}
//@{
/**
* A flag to indicate whether to show the Selected nodes
* Default is to set it to false.
*/
virtual void SetShowSelectedNodes(vtkTypeBool);
vtkGetMacro(ShowSelectedNodes, vtkTypeBool);
vtkBooleanMacro(ShowSelectedNodes, vtkTypeBool);
//@}
/**
* Get the points in this contour as a vtkPolyData.
*/
virtual vtkPolyData* GetContourRepresentationAsPolyData() = 0;
/**
* Get the nodes and not the intermediate points in this
* contour as a vtkPolyData.
*/
void GetNodePolyData(vtkPolyData* poly);
vtkSetMacro(RebuildLocator, bool);
protected:
vtkContourRepresentation();
~vtkContourRepresentation() override;
// Selection tolerance for the handles
int PixelTolerance;
double WorldTolerance;
vtkPointPlacer* PointPlacer;
vtkContourLineInterpolator* LineInterpolator;
int ActiveNode;
int CurrentOperation;
vtkTypeBool ClosedLoop;
// A flag to indicate whether to show the Selected nodes
vtkTypeBool ShowSelectedNodes;
vtkContourRepresentationInternals* Internal;
void AddNodeAtPositionInternal(double worldPos[3], double worldOrient[9], int displayPos[2]);
void AddNodeAtPositionInternal(double worldPos[3], double worldOrient[9], double displayPos[2]);
void SetNthNodeWorldPositionInternal(int n, double worldPos[3], double worldOrient[9]);
//@{
/**
* Given a world position and orientation, this computes the display position
* using the renderer of this class.
*/
void GetRendererComputedDisplayPositionFromWorldPosition(
double worldPos[3], double worldOrient[9], int displayPos[2]);
void GetRendererComputedDisplayPositionFromWorldPosition(
double worldPos[3], double worldOrient[9], double displayPos[2]);
//@}
virtual void UpdateLines(int index);
void UpdateLine(int idx1, int idx2);
virtual int FindClosestPointOnContour(int X, int Y, double worldPos[3], int* idx);
virtual void BuildLines() = 0;
// This method is called when something changes in the point placer.
// It will cause all points to be updated, and all lines to be regenerated.
// It should be extended to detect changes in the line interpolator too.
virtual int UpdateContour();
vtkTimeStamp ContourBuildTime;
void ComputeMidpoint(double p1[3], double p2[3], double mid[3])
{
mid[0] = (p1[0] + p2[0]) / 2;
mid[1] = (p1[1] + p2[1]) / 2;
mid[2] = (p1[2] + p2[2]) / 2;
}
/**
* Build a contour representation from externally supplied PolyData. This
* is very useful when you use an external program to compute a set of
* contour nodes (let's say based on image features) and subsequently want
* to build and display a contour that runs through those points.
* This method is protected and accessible only from
* vtkContourWidget::Initialize. The idlist here may be used to initialize
* a contour widget that uses a vtkPolygonalSurfacePointPlacer. This stores
* the point id's of the nodes, since the contour is drawn on the vertices
* of a surface mesh.
*/
virtual void Initialize(vtkPolyData*, vtkIdList*);
/**
* Overloaded initialize method, that is called when the vtkIdList is nullptr
* to maintain backwards compatibility.
*/
virtual void Initialize(vtkPolyData*);
/**
* Internal implementation, delegated to another method, so that users who
* override the method Initialize that takes in one argument are supported.
*/
virtual void InitializeContour(vtkPolyData*, vtkIdList*);
/**
* Adding a point locator to the representation to speed
* up lookup of the active node when dealing with large datasets (100k+)
*/
vtkIncrementalOctreePointLocator* Locator;
/**
* Deletes the previous locator if it exists and creates
* a new locator. Also deletes / recreates the attached data set.
*/
void ResetLocator();
void BuildLocator();
bool RebuildLocator;
private:
vtkContourRepresentation(const vtkContourRepresentation&) = delete;
void operator=(const vtkContourRepresentation&) = delete;
};
#endif