diff --git a/cmake/version.cmake b/cmake/version.cmake index 3348688..83b3b2e 100644 --- a/cmake/version.cmake +++ b/cmake/version.cmake @@ -3,7 +3,7 @@ # set (VTK_CONTRIB_MAJOR_VERSION "5") -set (VTK_CONTRIB_MINOR_VERSION "10") +set (VTK_CONTRIB_MINOR_VERSION "11") set (VTK_CONTRIB_RELEASE_VERSION "0") set (VTK_CONTRIB_VERSION ${VTK_CONTRIB_MAJOR_VERSION}.${VTK_CONTRIB_MINOR_VERSION}.${VTK_CONTRIB_RELEASE_VERSION}) diff --git a/src/VtkContrib/public/VtkContrib/vtkFrustumWidget.h b/src/VtkContrib/public/VtkContrib/vtkFrustumWidget.h new file mode 100644 index 0000000..56d8c71 --- /dev/null +++ b/src/VtkContrib/public/VtkContrib/vtkFrustumWidget.h @@ -0,0 +1,271 @@ +/** + * Widget de saisie d'un tronc dans l'espace. + * @author Charles PIGNEROL, CEA/DAM/DCLC + * @date 03/10/2025 + */ + +#ifndef VTK_FRUSTUM_WIDGET_H +#define VTK_FRUSTUM_WIDGET_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +class vtkPlaneWidgetCallbackCommand; + +/** + *

Un widget pour saisir interactivement un tronc. Un tronc est ici défini comme étant la zone intérieure à 6 plans qui en définissent la bordure. + * Les plans sont numérotés de 0 à 6 comme suit : gauche, droit, haut, bas, derrière, devant.

+ * + *

tests/frustum_widget.cpp est un exemple d'utilisation avec callback permettant de connaître le tronc défini.

+ */ +class vtkFrustumWidget : public vtk3DWidget +{ + friend class vtkPlaneWidgetCallbackCommand; + + public : + + vtkTypeMacro(vtkFrustumWidget,vtk3DWidget) + + /** + * Pour l'accès au paramétrage des 6 plans du tronc (ordre de la classe vtkFrustumSource). + */ + enum SIDE { LEFT, RIGHT, BOTTOM, TOP, BACK, FRONT }; + + /** + * Créé une représentation de type vtkConstrainedPointHandleRepresentation2. + */ + virtual void CreateDefaultRepresentation ( ); + + /** + * Instanciation de la classe. + */ + static vtkFrustumWidget* New ( ); + + //@{ + /** + * Methods that satisfy the superclass' API. + */ + virtual void SetInteractor (vtkRenderWindowInteractor* iren); + virtual void SetEnabled (int); + virtual void PlaceWidget(double bounds [6]); + virtual void SetPlaceFactor (double factor); + //@} + + /** + * @param indice du plan modifié ou consulté. + * @param nouvelle origine. + * @param nouvelle normale. + */ + virtual void SetPlane (SIDE p, double origin [3], double normal [3]); + virtual void GetPlane (SIDE p, double origin [3], double normal [3]); + virtual void SetPlaneOrigin (SIDE p, double origin [3]); + virtual void GetPlaneOrigin (SIDE p, double origin [3]); + virtual void SetPlaneNormal (SIDE p, double normal [3]); + virtual void GetPlaneNormal (SIDE p, double normal [3]); + + //@{ + /** + * Modifications des propriété du widget. + */ + + // @param Opacité du tronc (6 plans) affiché. + virtual void SetOpacity (double opacity); + + /** + * @param Composantes RGB des 3 interacteurs axiaux (gauche/droite, bas/haut, arrière/avant). + * @warning SetInteractorEnabled doit être invoqué après On ( ) pour être effectif. + */ + virtual void SetInteractorColor (SIDE axis, double rgb [3]); + virtual void SetInteractorEnabled (SIDE axis, bool enabled); + //@} + + /** + * @return La boite englobante du tronc. + */ + virtual void GetBounds (double bounds [6]); + + /** + * @return La définition du tronc. + */ + virtual const vtkPlanes& GetPlanes ( ) const; + virtual vtkPlanes& GetPlanes ( ); + + /** + * Modification des 6 plans. + */ + virtual void SetPlanes (vtkPlanes& planes); + + /** + * Ajoute le couple de plans p1 et p2 de la liste des paires de plan devant rester parallèles. + * Dans sa forme à 1 argument le second plan est celui implicitement apairé (gauche/droite, bas/haut, arrière/avant). + */ + virtual void AddParallelPlanes (SIDE p1, SIDE p2); + virtual void AddParallelPlanes (SIDE p); + + /** + * Enlève le couple de plans p1 et p2 de la liste des paires de plan devant rester parallèles. + */ + virtual void RemoveParallelPlanes (SIDE p1, SIDE p2); + virtual void RemoveParallelPlanes (SIDE p); + + /** + * @return Les couples de plans restant parallèles. + */ + virtual std::map GetParallelPlanes ( ) const; + + + protected : + + /** + * Classe permettant de contourner des difficultés rencontrées. + * Un objectif est également de ne pas grossir les interacteurs car par défaut ils prennent beaucoup de place + * et il en faut 6 pour le tronc. + */ + class vtkInternalPlaneWidget : public vtkImplicitPlaneWidget + { + public : + + static vtkInternalPlaneWidget* New ( ); + + /** + * Ne grossissent pas les interacteurs. + */ + virtual void PlaceWidget (double bounds [6]); + virtual void SizeHandles ( ); + + /** + * Nouvelle position => actualise la représentation sans recalculer la position qui est transmise en argument. + */ + virtual void UpdateRepresentation (double origin [3]); + + /** + * @return Le rayon de la poignée. + */ + virtual double GetHandleRadius ( ); + + /** + * Affecte la couleur transmise en argument à l'interacteur. + */ + virtual void SetInteractorColor (double rgb [3]); + + /** + * (Dés)active l'interacteur tout en le laissant visible. + */ + virtual void SetInteractorEnabled (bool enabled); + + + protected : + + vtkInternalPlaneWidget ( ); + virtual ~vtkInternalPlaneWidget ( ); + + + private : + + vtkInternalPlaneWidget (const vtkInternalPlaneWidget&); + vtkInternalPlaneWidget& operator = (const vtkInternalPlaneWidget&); + + /// true si en cours de placement du widget. + bool _placing; + }; // class vtkInternalPlaneWidget + + /** + * @return le p-ième plan du tronc + */ + virtual vtkInternalPlaneWidget* GetPlane (SIDE p); + virtual const vtkInternalPlaneWidget* GetPlane (SIDE p) const; + + /** + * Actualisation lors de la modification d'un plan. + */ + virtual void Update (vtkInternalPlaneWidget* caller); + + + private : + + /** + * Constructeur. + */ + vtkFrustumWidget ( ); + + /** + * Destructeur. RAS. + */ + virtual ~vtkFrustumWidget ( ); + + /** + * Constructeur et opérateur = : interdits. + */ + vtkFrustumWidget (const vtkFrustumWidget&); + vtkFrustumWidget& operator = (const vtkFrustumWidget&); + + /** Le tronc et sa représentation. */ + vtkSmartPointer _frustum; + vtkSmartPointer _planes; + vtkSmartPointer _frustumMapper; + vtkSmartPointer _frustumActor; + /** Le contour du tronc et sa représentation. */ + vtkSmartPointer _contourFilter; + vtkSmartPointer _contourMapper; + vtkSmartPointer _contourActor; + /** Les widgets interactifs. */ + std::vector> _planeWidgets; + vtkSmartPointer _planeCallback; + /** Pour des opérations temporaires de récupération de données. */ + vtkSmartPointer _tmpPlane; + + /* Les paires de plans parallèles entre-eux. */ + std::map _parallelPlanes; +}; // class vtkFrustumWidget + + +class vtkPlaneWidgetCallbackCommand : public vtkCommand +{ + public : + + static vtkPlaneWidgetCallbackCommand* New ( ) + { return new vtkPlaneWidgetCallbackCommand ( ); } + + virtual ~vtkPlaneWidgetCallbackCommand ( ) + { } + + virtual void Execute (vtkObject* caller, unsigned long id, void* calldata); + + virtual void SetFrustumWidget (vtkFrustumWidget* widget) + { + _frustumWidget = widget; + } // SetFrustumWidget + + protected : + + vtkPlaneWidgetCallbackCommand ( ) + : vtkCommand ( ), _frustumWidget (0) + { } + + + private : + + vtkPlaneWidgetCallbackCommand (const vtkPlaneWidgetCallbackCommand&) + { assert (0 && "vtkPlaneWidgetCallbackCommand copy constructor is not allowed."); } + vtkPlaneWidgetCallbackCommand& operator = (const vtkPlaneWidgetCallbackCommand&) + { + assert (0 && "vtkPlaneWidgetCallbackCommand assignment operator is not allowed."); + return *this; + } + + vtkFrustumWidget* _frustumWidget; +}; // class vtkPlaneWidgetCallbackCommand + + +#endif // VTK_FRUSTUM_WIDGET_H diff --git a/src/VtkContrib/vtkFrustumWidget.cpp b/src/VtkContrib/vtkFrustumWidget.cpp new file mode 100644 index 0000000..4a54adc --- /dev/null +++ b/src/VtkContrib/vtkFrustumWidget.cpp @@ -0,0 +1,733 @@ +/** + * Widget de saisie d'un tronc dans l'espace. + * @author Charles PIGNEROL, CEA/DAM/DCLC + * @date 03/10/2025 + */ + +#include "VtkContrib/vtkFrustumWidget.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace std; + + +// ============================================================================================================================= +// LA CLASSE vtkFrustumWidget::vtkInternalPlaneWidget +// ============================================================================================================================= + +vtkFrustumWidget::vtkInternalPlaneWidget* vtkFrustumWidget::vtkInternalPlaneWidget::New ( ) +{ + return new vtkFrustumWidget::vtkInternalPlaneWidget ( ); +} // vtkInternalPlaneWidget::New + + +vtkFrustumWidget::vtkInternalPlaneWidget::vtkInternalPlaneWidget ( ) + : vtkImplicitPlaneWidget ( ), _placing (false) +{ + // Restreindre l'affichage des 6 plans au tronc => on n'affiche plus le contour du plan de vtkImplicitPlaneWidget. + if (0 != this->EdgesActor) + this->EdgesActor->VisibilityOff ( ); + if (0 != this->OutlineActor) + this->OutlineActor->VisibilityOff ( ); + + // On a 6 plans interactifs => pour les opérations de sélection via les 6 manipulateurs, avoir une acuité assez fine + // lors de leur utilisation => on désactive les sélections "grossières" : + if (0 != this->Picker) + { + if (0 != this->CutActor) + this->Picker->DeletePickList (this->CutActor); + if (0 != this->OutlineActor) + this->Picker->DeletePickList (this->OutlineActor); + } // if (0 != this->Picker) +} // vtkInternalPlaneWidget::vtkInternalPlaneWidget + + +vtkFrustumWidget::vtkInternalPlaneWidget::vtkInternalPlaneWidget (const vtkFrustumWidget::vtkInternalPlaneWidget&) + : vtkImplicitPlaneWidget ( ), _placing (false) +{ + assert (0 && "vtkInternalPlaneWidget copy constructor is not allowed."); +} // vtkInternalPlaneWidget::vtkInternalPlaneWidget + + +vtkFrustumWidget::vtkInternalPlaneWidget& vtkFrustumWidget::vtkInternalPlaneWidget::operator = (const vtkFrustumWidget::vtkInternalPlaneWidget&) +{ + assert (0 && "vtkFrustumWidget::vtkInternalPlaneWidget assignment operator is not allowed."); + return *this; +} // vtkInternalPlaneWidget::operator = + + +vtkFrustumWidget::vtkInternalPlaneWidget::~vtkInternalPlaneWidget ( ) +{ +} // vtkInternalPlaneWidget::~vtkInternalPlaneWidget + + +void vtkFrustumWidget::vtkInternalPlaneWidget::PlaceWidget (double bounds [6]) +{ + _placing = true; + vtkImplicitPlaneWidget::PlaceWidget (bounds); + _placing = false; +} // vtkInternalPlaneWidget::PlaceWidget + + +void vtkFrustumWidget::vtkInternalPlaneWidget::SizeHandles ( ) +{ + if (false == _placing) + return; + + // Code VTK 7.1.1 légèrement retouché : + double radius = this->vtk3DWidget::SizeHandles(1.); // 1.35); code VTK 7.1.1 + + this->ConeSource->SetHeight(2.0*radius); + this->ConeSource->SetRadius(radius); + this->ConeSource2->SetHeight(2.0*radius); + this->ConeSource2->SetRadius(radius); + + this->Sphere->SetRadius(radius); + + this->EdgesTuber->SetRadius(0.25*radius); +} // vtkInternalPlaneWidget::SizeHandles + + +void vtkFrustumWidget::vtkInternalPlaneWidget::UpdateRepresentation (double origin [3]) +{ + // Issu du code de vtkImplicitPlaneWidget::UpdateRepresentation ( ) de VTK 7.1.1, mais en prnant pour origine celle transmise en argument. + if ( ! this->CurrentRenderer ) + { + return; + } + +// double *origin = this->Plane->GetOrigin(); + double *normal = this->Plane->GetNormal(); + double p2[3]; +/* + if( !this->OutsideBounds ) + { + double *bounds = this->GetInput()->GetBounds(); + for (int i=0; i<3; i++) + { + if ( origin[i] < bounds[2*i] ) + { + origin[i] = bounds[2*i]; + } + else if ( origin[i] > bounds[2*i+1] ) + { + origin[i] = bounds[2*i+1]; + } + } + } +*/ + // Setup the plane normal + double d = this->Outline->GetOutput()->GetLength(); + + const double ratio = this->DiagonalRatio; + p2[0] = origin[0] + ratio * d * normal[0]; + p2[1] = origin[1] + ratio * d * normal[1]; + p2[2] = origin[2] + ratio * d * normal[2]; + + this->LineSource->SetPoint1(origin); + this->LineSource->SetPoint2(p2); + this->ConeSource->SetCenter(p2); + this->ConeSource->SetDirection(normal); + + p2[0] = origin[0] - ratio * d * normal[0]; + p2[1] = origin[1] - ratio * d * normal[1]; + p2[2] = origin[2] - ratio * d * normal[2]; + + this->LineSource2->SetPoint1(origin[0],origin[1],origin[2]); + this->LineSource2->SetPoint2(p2); + this->ConeSource2->SetCenter(p2); + this->ConeSource2->SetDirection(normal[0],normal[1],normal[2]); + + // Set up the position handle + this->Sphere->SetCenter(origin[0],origin[1],origin[2]); + + // Control the look of the edges + if ( this->Tubing ) + { + this->EdgesMapper->SetInputConnection( + this->EdgesTuber->GetOutputPort()); + } + else + { + this->EdgesMapper->SetInputConnection( + this->Edges->GetOutputPort()); + } +} // vtkInternalPlaneWidget::UpdateRepresentation + + +double vtkFrustumWidget::vtkInternalPlaneWidget::GetHandleRadius ( ) +{ + return 0 == this->EdgesTuber ? 0. : this->EdgesTuber->GetRadius ( ); +} // vtkInternalPlaneWidget::GetHandleRadius + + +void vtkFrustumWidget::vtkInternalPlaneWidget::SetInteractorColor (double rgb [3]) +{ + if (0 != GetNormalProperty ( )) + GetNormalProperty ( )->SetColor (rgb); +} // vtkInternalPlaneWidget::SetInteractorColor + + +void vtkFrustumWidget::vtkInternalPlaneWidget::SetInteractorEnabled (bool enabled) +{ + if (0 != this->Picker) + { + if (true == enabled) + { + if (0 != this->ConeActor) + this->Picker->AddPickList (this->ConeActor); + if (0 != this->ConeActor) + this->Picker->AddPickList (this->ConeActor2); + if (0 != this->LineActor) + this->Picker->AddPickList (this->LineActor); + if (0 != this->LineActor2) + this->Picker->AddPickList (this->LineActor2); + if (0 != this->SphereActor) + this->Picker->AddPickList (this->SphereActor); + } + else + { + if (0 != this->ConeActor) + this->Picker->DeletePickList (this->ConeActor); + if (0 != this->ConeActor) + this->Picker->DeletePickList (this->ConeActor2); + if (0 != this->LineActor) + this->Picker->DeletePickList (this->LineActor); + if (0 != this->LineActor2) + this->Picker->DeletePickList (this->LineActor2); + if (0 != this->SphereActor) + this->Picker->DeletePickList (this->SphereActor); + } // if (true == enabled) + } // if (0 != this->Picker) + else + vtkErrorMacro ("vtkFrustumWidget::SetInteractorEnabled : null picker.") +} // vtkInternalPlaneWidget::SetInteractorEnabled + + +// ============================================================================================================================= +// LA CLASSE vtkPlaneWidgetCallbackCommand +// ============================================================================================================================= + +void vtkPlaneWidgetCallbackCommand::Execute (vtkObject* caller, unsigned long id, void* calldata) +{ + if (0 != _frustumWidget) + _frustumWidget->Update (static_cast(caller)); +} // vtkPlaneWidgetCallbackCommand::Execute + + +// ============================================================================================================================= +// LA CLASSE vtkFrustumWidget +// ============================================================================================================================= + +vtkFrustumWidget::vtkFrustumWidget ( ) + : vtk3DWidget ( ), _parallelPlanes ( ) +{ + _frustum = vtkSmartPointer::Take (vtkFrustumSource::New ( )); + _planes = vtkSmartPointer::Take (vtkPlanes::New ( )); + _frustumMapper = vtkSmartPointer::Take (vtkPolyDataMapper::New ( )); + _frustumActor = vtkSmartPointer::Take (vtkActor::New ( )); + _frustumMapper->SetInputConnection (_frustum->GetOutputPort ( )); + _frustumActor->SetMapper (_frustumMapper); + _contourFilter = vtkSmartPointer::Take (vtkTubeFilter::New ( )); + _contourMapper = vtkSmartPointer::Take (vtkPolyDataMapper::New ( )); + _contourActor = vtkSmartPointer::Take (vtkActor::New ( )); + _planeCallback = vtkSmartPointer::Take (vtkPlaneWidgetCallbackCommand::New ( )); + _planeCallback->SetFrustumWidget (this); + for (int i = 0; i < 6; i++) + { + _planeWidgets.push_back (vtkSmartPointer::Take (vtkFrustumWidget::vtkInternalPlaneWidget::New ( ))); + _planeWidgets [i]->AddObserver (vtkCommand::InteractionEvent, _planeCallback); + } // for (int i = 0; i < 6; i++) + _tmpPlane = vtkSmartPointer::Take (vtkPlane::New ( )); + vtkSmartPointer edges = vtkSmartPointer::Take (vtkFeatureEdges::New ( )); + edges->SetInputConnection (_frustum->GetOutputPort ( )); + _contourFilter->SetInputConnection (edges->GetOutputPort ( )); + _contourFilter->SetNumberOfSides (12); + _contourFilter->SetRadius (5 * _planeWidgets [0]->GetHandleRadius ( )); + _contourMapper->SetInputConnection (_contourFilter->GetOutputPort ( )); + _contourActor->SetMapper (_contourMapper); + + // Emplacement non idéal, il faudrait que ce soit dans une méthode type Init ( ) : + CreateDefaultRepresentation ( ); +} // vtkFrustumWidget::vtkFrustumWidget + + +vtkFrustumWidget::vtkFrustumWidget (const vtkFrustumWidget&) + : vtk3DWidget ( ), _parallelPlanes ( ) +{ + assert (0 && "vtkFrustumWidget copy constructor is not allowed."); +} // vtkFrustumWidget::vtkFrustumWidget + + +vtkFrustumWidget& vtkFrustumWidget::operator = (const vtkFrustumWidget&) +{ + assert (0 && "vtkFrustumWidget assignment operator is not allowed."); + return *this; +} // vtkFrustumWidget::operator = + + +vtkFrustumWidget::~vtkFrustumWidget ( ) +{ + _planeCallback->SetFrustumWidget (0); +} // vtkFrustumWidget::~vtkFrustumWidget + + +vtkFrustumWidget* vtkFrustumWidget::New ( ) +{ + return new vtkFrustumWidget ( ); +} // vtkFrustumWidget::New + + +void vtkFrustumWidget::SetInteractor (vtkRenderWindowInteractor* iren) +{ + vtk3DWidget::SetInteractor (iren); + for (vector>::iterator it = _planeWidgets.begin ( ); _planeWidgets.end ( ) != it; it++) + (*it)->SetInteractor (iren); + SetCurrentRenderer (0 == iren ? 0 : iren->FindPokedRenderer (0, 0)); +} // vtkFrustumWidget::SetInteractor + + +void vtkFrustumWidget::SetEnabled (int enabled) +{ + vtk3DWidget::SetEnabled (enabled); + + for (vector>::iterator it = _planeWidgets.begin ( ); _planeWidgets.end ( ) != it; it++) + (*it)->SetEnabled (enabled); + + if (0 != GetCurrentRenderer ( )) + { + if (true == enabled) + { + GetCurrentRenderer ( )->AddActor (_frustumActor); + GetCurrentRenderer ( )->AddActor (_contourActor); + } + else + { + GetCurrentRenderer ( )->RemoveActor (_frustumActor); + GetCurrentRenderer ( )->RemoveActor (_contourActor); + } + } // if (0 != GetCurrentRenderer ( )) + + Update (0); +} // vtkFrustumWidget::SetEnabled + + +void vtkFrustumWidget::PlaceWidget (double bounds [6]) +{ + int i = 0; + for (vector>::iterator it = _planeWidgets.begin ( ); _planeWidgets.end ( ) != it; it++, i++) + { + double origin [3] = { (bounds [0] + bounds [1]) / 2., (bounds [2] + bounds [3]) / 2., (bounds [4] + bounds [5]) / 2. }; + switch (i) + { + case 0 : origin [0] = bounds [0]; break; + case 1 : origin [0] = bounds [1]; break; + case 2 : origin [1] = bounds [2]; break; + case 3 : origin [1] = bounds [3]; break; + case 4 : origin [2] = bounds [4]; break; + case 5 : origin [2] = bounds [5]; break; + } // switch (i) +// On est tenté d'appeler SetOrigin et PlaceWidget pour chacun des plans, mais vtkImplicitPlaneWidget::PlaceWidget ne prend pas en compte le SetOrigin et recalcule +// origine et normale au plan => on récupère ceux demandés et on les utilise : +// (*it)->SetOrigin (origin); +// (*it)->PlaceWidget (bounds); + (*it)->GetPlane (_tmpPlane); + double val [3] = { 0., 0., 0. }; + _tmpPlane->GetOrigin (val); + (*it)->PlaceWidget (bounds); + (*it)->SetOrigin (origin); + (*it)->SetNormal (val [0], val [1], val [2]); + } // for (vector>::iterator it = _planeWidgets.begin ( ); _planeWidgets.end ( ) != it; it++, i++) +} // vtkFrustumWidget::PlaceWidget + + +void vtkFrustumWidget::SetPlaceFactor (double factor) +{ + vtk3DWidget::SetPlaceFactor (factor); + + for (vector>::iterator it = _planeWidgets.begin ( ); _planeWidgets.end ( ) != it; it++) + (*it)->SetPlaceFactor (factor); +} // vtkFrustumWidget::SetPlaceFactor + + +void vtkFrustumWidget::SetPlane (SIDE p, double origin [3], double normal [3]) +{ + vtkFrustumWidget::vtkInternalPlaneWidget* planeWidget = GetPlane (p); + if (0 != planeWidget) + { + planeWidget->SetOrigin (origin); + planeWidget->SetNormal (normal); + Update (planeWidget); + } // if (0 != planeWidget) + else + vtkErrorMacro ("vtkFrustumWidget::SetPlane : 0 <= p <= 5 is not verified. p =" << p) +} // vtkFrustumWidget::SetPlane + + +void vtkFrustumWidget::GetPlane (SIDE p, double origin [3], double normal [3]) +{ + vtkFrustumWidget::vtkInternalPlaneWidget* planeWidget = GetPlane (p); + if (0 != planeWidget) + { + planeWidget->GetOrigin (origin); + planeWidget->GetNormal (normal); + } // if (0 != planeWidget) + else + vtkErrorMacro ("vtkFrustumWidget::GetPlane : 0 <= p <= 5 is not verified. p =" << p) +} // vtkFrustumWidget::GetPlane + + +void vtkFrustumWidget::SetPlaneOrigin (SIDE p, double origin [3]) +{ + vtkFrustumWidget::vtkInternalPlaneWidget* planeWidget = GetPlane (p); + if (0 != planeWidget) + { + planeWidget->SetOrigin (origin); + Update (planeWidget); + } // if (0 != planeWidget) + else + vtkErrorMacro ("vtkFrustumWidget::SetPlane : 0 <= p <= 5 is not verified. p =" << p) +} // vtkFrustumWidget::SetPlaneOrigin + + +void vtkFrustumWidget::GetPlaneOrigin (SIDE p, double origin [3]) +{ + vtkFrustumWidget::vtkInternalPlaneWidget* planeWidget = GetPlane (p); + if (0 != planeWidget) + planeWidget->GetOrigin (origin); + else + vtkErrorMacro ("vtkFrustumWidget::GetPlaneOrigin : 0 <= p <= 5 is not verified. p =" << p) +} // vtkFrustumWidget::GetPlaneOrigin + + +void vtkFrustumWidget::SetPlaneNormal (SIDE p, double normal [3]) +{ + vtkFrustumWidget::vtkInternalPlaneWidget* planeWidget = GetPlane (p); + if (0 != planeWidget) + { + planeWidget->SetNormal (normal); + Update (planeWidget); + } // if (0 != planeWidget) + else + vtkErrorMacro ("vtkFrustumWidget::SetPlane : 0 <= p <= 5 is not verified. p =" << p) +} // vtkFrustumWidget::SetPlaneNormal + + +void vtkFrustumWidget::GetPlaneNormal (SIDE p, double normal [3]) +{ + vtkFrustumWidget::vtkInternalPlaneWidget* planeWidget = GetPlane (p); + if (0 != planeWidget) + planeWidget->GetNormal (normal); + else + vtkErrorMacro ("vtkFrustumWidget::GetPlaneNormal : 0 <= p <= 5 is not verified. p =" << p) +} // vtkFrustumWidget::GetPlaneNormal + + +void vtkFrustumWidget::SetOpacity (double opacity) +{ + if ((0 != _frustumActor) && (0 != _frustumActor->GetProperty ( ))) + _frustumActor->GetProperty ( )->SetOpacity (opacity); +} // vtkFrustumWidget::SetOpacity + + +void vtkFrustumWidget::SetInteractorColor (SIDE axis, double rgb [3]) +{ + if ((axis >= _planeWidgets.size ( )) || (0 == _planeWidgets [axis])) + { + vtkErrorMacro ("vtkFrustumWidget::SetInteractorColor : 0 <= axis <= " << _planeWidgets.size ( ) << " is not verified. axis =" << axis) + return; + } // if ((axis >= _planeWidgets.size ( )) || (0 == _planeWidgets [axis])) + + switch (axis) + { + case LEFT : + case RIGHT : + _planeWidgets [0]->SetInteractorColor (rgb); + _planeWidgets [1]->SetInteractorColor (rgb); + break; + case BOTTOM : + case TOP : + _planeWidgets [2]->SetInteractorColor (rgb); + _planeWidgets [3]->SetInteractorColor (rgb); + break; + default : + _planeWidgets [4]->SetInteractorColor (rgb); + _planeWidgets [5]->SetInteractorColor (rgb); + } // switch (axis) +} // vtkFrustumWidget::SetInteractorColor + + +void vtkFrustumWidget::SetInteractorEnabled (SIDE p, bool enabled) +{ + vtkFrustumWidget::vtkInternalPlaneWidget* planeWidget = GetPlane (p); + if (0 != planeWidget) + planeWidget->SetInteractorEnabled (enabled); + else + vtkErrorMacro ("vtkFrustumWidget::SetInteractorEnabled : 0 <= p <= 5 is not verified. p =" << p) +} // vtkFrustumWidget::SetInteractorEnabled + + +void vtkFrustumWidget::GetBounds (double bounds [6]) +{ + vtkPolyData* frustum = 0 == _frustum ? 0 : _frustum->GetOutput ( ); + + if (0 == frustum) + vtkErrorMacro ("vtkFrustumWidget::GetBounds : null frustum.") + else + { + // frustum->GetBounds (bounds); + /* On n'utilise pas frustum->GetBounds (bounds) car notre polydata contient des lignes qui parfois, de manière non reproductible, + * sortent carrément du domaine observé, à savoir qu'une composante d'une coordonnée peut être de l'ordre de 10E+30 ! Parfois veut ici + * dire environ 1 fois sur 15, et c'est semble-t-il toujours au premier appel de cette fonction. Problème d'initialisation d'une + * variable statique ??? + * => on recalcule ici la boite englobante du domaine observé à partir de ses seuls (6) polygones : + */ + for (int i = 0; i < 3; i++) + { + bounds [2 * i] = DBL_MAX; + bounds [2 * i + 1] = -DBL_MAX; + } // for (int i = 0; i < 3; i++) + for (int i = 0; i < frustum->GetNumberOfCells ( ); i++) + { + vtkCell* cell = frustum->GetCell (i); + const VTKCellType type = (VTKCellType)cell->GetCellType ( ); + if ((type < VTK_TRIANGLE) || (type > VTK_QUAD)) + continue; + + double cellBounds [6] = { DBL_MAX, -DBL_MAX, DBL_MAX, -DBL_MAX, DBL_MAX, -DBL_MAX }; + cell->GetBounds (cellBounds); + for (int j = 0; j < 3; j++) + { + bounds [2 * j] = min (bounds [2 * j], cellBounds [2 * j]); + bounds [2 * j + 1] = max (bounds [2 * j + 1], cellBounds [2 * j + 1]); + } // for (int j = 0; j < 3; j++) + } // for (int i = 0; i < frustum->GetNumberOfCells ( ); i++) + } // else if (0 == frustum) +} // vtkFrustumWidget::GetBounds + + +const vtkPlanes& vtkFrustumWidget::GetPlanes ( ) const +{ + return *(_planes.GetPointer ( )); +} // vtkFrustumWidget::GetPlane + + +vtkPlanes& vtkFrustumWidget::GetPlanes ( ) +{ + return *(_planes.GetPointer ( )); +} // vtkFrustumWidget::GetPlane + + +void vtkFrustumWidget::SetPlanes (vtkPlanes& planes) +{ + vtkPoints* points = planes.GetPoints ( ); + vtkDataArray* normals = planes.GetNormals ( ); + if ((6 == planes.GetNumberOfPlanes ( )) && (0 != points) && (0 != normals) && (6 == points->GetNumberOfPoints ( )) && (6 == normals->GetNumberOfTuples ( ))) + { + for (int p = 0; p < 6; p++) + { + double coords [3] = { 0., 0., 0. }; + double* normal = normals->GetTuple3 (p); + points->GetPoint (p, coords); + vtkFrustumWidget::vtkInternalPlaneWidget* planeWidget = GetPlane ((SIDE)p); + if (0 != planeWidget) + { + planeWidget->SetOrigin (coords); + planeWidget->SetNormal (normal); + } // if (0 != planeWidget) + SetPlane ((SIDE)p, coords, normal); // => Update parallel planes + } // for (int p = 0; p < 6; p++) + + Update (0); + } + else + vtkErrorMacro ("vtkFrustumWidget::SetPlane : 0 <= planes.GetNumberOfPlanes ( ) <= 5 is not verified. p =" << planes.GetNumberOfPlanes ( )) +} // vtkFrustumWidget::SetPlanes + + +void vtkFrustumWidget::AddParallelPlanes (SIDE p1, SIDE p2) +{ + _parallelPlanes.insert (pair(min ((int)p1, (int)p2), max ((int)p1, (int)p2))); +} // vtkFrustumWidget::AddParallelPlanes + + +void vtkFrustumWidget::RemoveParallelPlanes (SIDE p1, SIDE p2) +{ + _parallelPlanes.erase (min ((int)p1, (int)p2)); +} // vtkFrustumWidget::RemoveParallelPlanes + + +void vtkFrustumWidget::AddParallelPlanes (SIDE p) +{ + switch (p) + { + case LEFT : + case RIGHT : AddParallelPlanes (LEFT, RIGHT); break; + case BOTTOM : + case TOP : AddParallelPlanes (BOTTOM, TOP); break; + case FRONT : + case BACK : AddParallelPlanes (FRONT, BACK); break; + default : vtkErrorMacro ("vtkFrustumWidget::AddParallelPlanes : 0 <= p <= 5 is not verified. p =" << p) + } // switch (p) +} // vtkFrustumWidget::AddParallelPlanes + + +void vtkFrustumWidget::RemoveParallelPlanes (SIDE p) +{ + switch (p) + { + case LEFT : + case RIGHT : RemoveParallelPlanes (LEFT, RIGHT); break; + case BOTTOM : + case TOP : RemoveParallelPlanes (BOTTOM, TOP); break; + case FRONT : + case BACK : RemoveParallelPlanes (FRONT, BACK); break; + default : vtkErrorMacro ("vtkFrustumWidget::RemoveParallelPlanes : 0 <= p <= 5 is not verified. p =" << p) + } // switch (p) +} // vtkFrustumWidget::RemoveParallelPlanes + + +std::map vtkFrustumWidget::GetParallelPlanes ( ) const +{ + return _parallelPlanes; +} // vtkFrustumWidget::GetParallelPlanes + + +void vtkFrustumWidget::CreateDefaultRepresentation ( ) +{ // vtkFrustumSource::GetPlanes ( ) : The 6 planes are defined in this order: left,right,bottom,top,far,near. + vtkSmartPointer points = vtkSmartPointer::Take (vtkPoints::New ( )); + vtkSmartPointer normals = vtkSmartPointer::Take (vtkDoubleArray::New ( )); + normals->SetNumberOfComponents (3); + for (int i = 0; i < 6; i++) + { + double coords [3] = { 0., 0., 0. }; + switch (i) + { + case 0 : coords [0] = -1.;break; + case 1 : coords [0] = 1.; break; + case 2 : coords [1] = -1.;break; + case 3 : coords [1] = 1.; break; + case 4 : coords [2] = -1.; break; + case 5 : coords [2] = 1.; break; + } // switch (i) + points->InsertNextPoint (coords); + normals->InsertNextTuple3 (coords [0], coords [1], coords [2]); + _planeWidgets [i]->SetOrigin (coords); + _planeWidgets [i]->SetNormal (coords); + _planeWidgets [i]->TubingOff ( ); + _planeWidgets [i]->DrawPlaneOff ( ); + _planeWidgets [i]->OriginTranslationOff ( ); + _planeWidgets [i]->OutlineTranslationOff ( ); + + } // for (int i = 0; i < 6; i++) + _planes->SetPoints (points); + _planes->SetNormals (normals); + _frustum->SetPlanes (_planes); + _frustum->Update ( ); + // On confère à ce widget le look de la classe vtkImplicitPlaneWidget : + _frustumActor->SetProperty (_planeWidgets [0]->GetPlaneProperty ( )); +} // vtkFrustumWidget::CreateDefaultRepresentation + + +vtkFrustumWidget::vtkInternalPlaneWidget* vtkFrustumWidget::GetPlane (SIDE p) +{ + return p >= _planeWidgets.size ( ) ? 0 : _planeWidgets [p]; +} // vtkFrustumWidget::GetPlane + + +const vtkFrustumWidget::vtkInternalPlaneWidget* vtkFrustumWidget::GetPlane (SIDE p) const +{ + return p >= _planeWidgets.size ( ) ? 0 : _planeWidgets [p]; +} // vtkFrustumWidget::GetPlane + + +void vtkFrustumWidget::Update (vtkFrustumWidget::vtkInternalPlaneWidget* planeWidget) +{ + vtkPoints* points = _planes->GetPoints ( ); + vtkDataArray* normals = _planes->GetNormals ( ); + + // MAJ normale opposée si nécessaire : + if (0 != planeWidget) + { + double normal [3] = { 0., 0., 0. }; + planeWidget->GetNormal (normal); + for (int i = 0; i < 3; i++) + normal [i] = -normal [i]; + + for (map::const_iterator itp = _parallelPlanes.begin ( ); _parallelPlanes.end ( ) != itp; itp++) + { + if (planeWidget == _planeWidgets [(*itp).first]) + _planeWidgets [(*itp).second]->SetNormal (normal); + if (planeWidget == _planeWidgets [(*itp).second]) + _planeWidgets [(*itp).first]->SetNormal (normal); + } // for (map::const_iterator itp = _parallelPlanes.begin ( ); _parallelPlanes.end ( ) != itp; itp++) + } // if (0 != planeWidget) + + // Actualisation du tronc affiché : + for (int i = 0; i < 6; i++) + { + _planeWidgets [i]->GetPlane (_tmpPlane); + double val [3] = { 0., 0., 0. }; + _tmpPlane->GetOrigin (val); + points->SetPoint (i, val); + _tmpPlane->GetNormal (val); + normals->SetTuple3 (i, val [0], val [1], val [2]); + } // for (int i = 0; i < 6; i++) + _planes->SetPoints (points); + _planes->SetNormals (normals); + _frustum->SetPlanes (_planes); + _frustum->Modified ( ); + _frustum->Update ( ); + + // Recentrer les manipulateurs sur leur face : + vtkPolyData* frustum = _frustum->GetOutput ( ); + if ((0 == frustum) || (6 != frustum->GetNumberOfPolys ( ))) + return; + + int currentCell = 0; + bool recentered [6] = { false, false, false, false, false, false }; // Eviter de modifier 2 fois le même plan (et 0 fois un autre). + for (int i = 0; i < frustum->GetNumberOfCells ( ); i++) + { + vtkCell* cell = frustum->GetCell (i); + if ((cell->GetCellType ( ) < VTK_TRIANGLE) || (cell->GetCellType ( ) > VTK_QUAD)) + continue; + + double bounds [6] = { 0., 0., 0., 0., 0., 0. }; + cell->GetBounds (bounds); + double center [3] = { (bounds [0] + bounds [1]) / 2., (bounds [2] + bounds [3]) / 2., (bounds [4] + bounds [5]) / 2. }; + double distance = DBL_MAX; + int plane = -1; + for (int p = 0; p < 6; p++) + { + _planeWidgets [p]->GetPlane (_tmpPlane); + double d = _tmpPlane->DistanceToPlane (center); + if ((d < distance) && (false == recentered [p])) + { + distance = d; + plane = p; + } // if ((d < distance) && (false == recentered [p])) + } // for (int p = 0; p < 6; p++) + if ((plane >= 0) && (plane < 6)) + { + recentered [plane] = true; + _planeWidgets [plane]->UpdateRepresentation (center); + } + currentCell++; + } // for (int i = 0; i < frustum->GetNumberOfCells ( ); i++) + + this->InvokeEvent (vtkCommand::InteractionEvent, NULL); +} // vtkFrustumWidget::Update diff --git a/src/VtkContrib/vtkTrihedron.cpp b/src/VtkContrib/vtkTrihedron.cpp index 0c80149..ce63900 100644 --- a/src/VtkContrib/vtkTrihedron.cpp +++ b/src/VtkContrib/vtkTrihedron.cpp @@ -119,7 +119,7 @@ vtkTrihedron::vtkTrihedron ( ) m_yLabelActor->SetMapper(yLabelMapper); m_yLabelActor->SetScale(0.4,0.4,0.4); m_yLabelActor->AddPosition(0.0,1.1,0.0); - m_yLabelActor->RotateZ (90); +// m_yLabelActor->RotateZ (90); m_yTextMapper->SetInput ("y"); m_yTextMapper->GetTextProperty ( )->SetFontFamilyToArial ( ); m_yTextMapper->GetTextProperty ( )->SetFontSize (24); diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index 1c084eb..5e0e12b 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -5,7 +5,7 @@ find_package (GUIToolkitsVariables) include (${GUIToolkitsVariables_CMAKE_DIR}/common.cmake) include (${GUIToolkitsVariables_CMAKE_DIR}/workarounds.cmake) -set (ALL_EXECUTABLES areapicker point_widget point_widget2 trihedrons torus viewcube) +set (ALL_EXECUTABLES areapicker point_widget point_widget2 frustum_widget trihedrons torus viewcube) foreach (exe ${ALL_EXECUTABLES}) add_executable (${exe} ${exe}.cpp) diff --git a/src/tests/frustum_widget.cpp b/src/tests/frustum_widget.cpp new file mode 100644 index 0000000..1fa0c3a --- /dev/null +++ b/src/tests/frustum_widget.cpp @@ -0,0 +1,124 @@ +#include +#include "VtkContrib/vtkFrustumWidget.h" +#include "VtkContrib/vtkLandmarkActor.h" + +#include +#include +#include +#include +#include +#include +#include +#include + + +#include +#include +#include +using namespace std; + + + +int main ( int argc, char *argv[] ) +{ + // Create the RenderWindow, Renderer and both Actors + // + vtkSmartPointer ren1 = vtkSmartPointer::New(); + vtkSmartPointer renWin = vtkSmartPointer::New(); + renWin->AddRenderer(ren1); + + vtkSmartPointer iren = vtkSmartPointer::New(); + iren->SetRenderWindow(renWin); + + double bounds [6] = { -1., 2., -1., 1., -1., 1. }; + + vtkSmartPointer cubeSource = vtkSmartPointer::New ( ); + cubeSource->SetBounds (bounds); + cubeSource->Update ( ); + + vtkPolyDataMapper* cubeMapper = vtkPolyDataMapper::New ( ); + cubeMapper->SetInputConnection (cubeSource->GetOutputPort ( )); + vtkActor* cubeActor = vtkActor::New ( ); + cubeActor->SetMapper (cubeMapper); + cubeActor->GetProperty ( )->SetColor (0, 0, 1); +// ren1->AddActor (cubeActor); + + vtkSmartPointer frustumWidget = vtkSmartPointer::New ( ); + frustumWidget->SetPlaceFactor (1.); + frustumWidget->PlaceWidget (bounds); + frustumWidget->SetInteractor (iren); +// frustumWidget->AddParallelPlanes (vtkFrustumWidget::LEFT, vtkFrustumWidget::RIGHT); + frustumWidget->AddParallelPlanes (vtkFrustumWidget::LEFT); +// frustumWidget->RemoveParallelPlanes (vtkFrustumWidget::BACK, vtkFrustumWidget::FRONT); + frustumWidget->On ( ); + frustumWidget->SetInteractorEnabled (vtkFrustumWidget::TOP, false); + + double origin [3] = { -0.5, 0.5, 0.8 }; + double normal [3] = { 0., 1., 1. }; + frustumWidget->SetPlane (vtkFrustumWidget::FRONT, origin, normal); + vtkSmartPointer planes = vtkSmartPointer::New ( ); + vtkPoints* points = vtkPoints::New ( ); + vtkDoubleArray* normals = vtkDoubleArray::New ( ); + normals->SetNumberOfComponents (3); + points->InsertNextPoint (-0.8, 0., 0.); + points->InsertNextPoint (0.8, 0., 0.); + points->InsertNextPoint (0., -0.8, 0.); + points->InsertNextPoint (0., 0.8, 0.); + points->InsertNextPoint (0., 0., -0.8); + points->InsertNextPoint (0., 0., 0.8); + normals->InsertNextTuple3 (-0.7, 0.3, 0.); + normals->InsertNextTuple3 (0.7, 0.3, 0.); + normals->InsertNextTuple3 (0., -1., 0.); + normals->InsertNextTuple3 (0., 1, 0.); + normals->InsertNextTuple3 (0., 0.3, -0.7); + normals->InsertNextTuple3 (0., 0.3, 0.7); + planes->SetPoints (points); + planes->SetNormals (normals); + frustumWidget->SetPlanes (*(planes.Get ( ))); + +// Test : + vtkLandmarkActor* landmarkActor = vtkLandmarkActor::New ( ); + landmarkActor->SetBounds (bounds); + landmarkActor->GetProperty ( )->SetColor (0., 1., 0.); + landmarkActor->SetXAxisColor (1., 0.67, 0.); + landmarkActor->SetYAxisColor (0., 0.82, 1.); + landmarkActor->SetZAxisColor (0., 0., 1.); + landmarkActor->SetXTitle ("X"); + landmarkActor->SetYTitle ("Y"); + landmarkActor->SetZTitle ("Z"); + landmarkActor->SetXAxisLabelVisibility (1); + landmarkActor->SetYAxisLabelVisibility (1); + landmarkActor->SetZAxisLabelVisibility (1); + landmarkActor->SetXLabelFormat ("%g"); + landmarkActor->SetYLabelFormat ("%g"); + landmarkActor->SetZLabelFormat ("%g"); + landmarkActor->SetXAxisTickVisibility (1); + landmarkActor->SetYAxisTickVisibility (1); + landmarkActor->SetZAxisTickVisibility (1); + landmarkActor->SetXAxisMinorTickVisibility (1); + landmarkActor->SetYAxisMinorTickVisibility (1); + landmarkActor->SetZAxisMinorTickVisibility (1); + landmarkActor->SetTickLocationToOutside ( ); + landmarkActor->SetCamera (ren1->GetActiveCamera ( )); + landmarkActor->SetDrawXGridlines (1); + landmarkActor->SetDrawYGridlines (1); + landmarkActor->SetDrawZGridlines (1); + landmarkActor->SetCornerOffset (0.); + landmarkActor->PickableOff ( ); + ren1->AddActor (landmarkActor); + + iren->Initialize(); + renWin->Render(); +// handleWidget->EnabledOn(); + ren1->SetBackground(0.1, 0.2, 0.4); + renWin->SetSize(1800, 1200); + ren1->ResetCamera(); + ren1->ResetCameraClippingRange(); + renWin->Render(); + + iren->Start(); + + return EXIT_SUCCESS; + +} + diff --git a/versions.txt b/versions.txt index 9fe6033..fbbeb21 100644 --- a/versions.txt +++ b/versions.txt @@ -1,3 +1,11 @@ +Version 5.11.0 : 03/10/25 +================ + +Classe vtkFrustumWidget et test associé frustum_widget. + +vtkTrihedron : annulation de la rotation de 90° de l'affichage du "Y". + + Version 5.10.0 : 15/04/25 ================