split viewport for Qt and VtkViewer
This commit is contained in:
228
src/Vtk/vtkViewport.cpp
Normal file
228
src/Vtk/vtkViewport.cpp
Normal file
@@ -0,0 +1,228 @@
|
||||
#include "vtkViewport.h"
|
||||
|
||||
#include <vtkAxes.h>
|
||||
#include <vtkAxesActor.h>
|
||||
#include <vtkCamera.h>
|
||||
#include <vtkCameraOrientationWidget.h>
|
||||
#include <vtkInteractorStyleTrackballCamera.h>
|
||||
#include <vtkObjectFactory.h>
|
||||
#include <vtkPlaneSource.h>
|
||||
#include <vtkRenderWindow.h>
|
||||
#include <vtkRenderWindowInteractor.h>
|
||||
#include <vtkSmartPointer.h>
|
||||
#include <vtkNew.h>
|
||||
#include <vtkTextProperty.h>
|
||||
|
||||
#include <vtkPolyDataMapper.h>
|
||||
|
||||
#include <vtkNamedColors.h>
|
||||
#include <vtkProperty.h>
|
||||
#include <vtkCallbackCommand.h>
|
||||
#include <vtkMath.h>
|
||||
#include <vtkActor.h>
|
||||
#include <cmath>
|
||||
|
||||
namespace uLib {
|
||||
namespace Vtk {
|
||||
|
||||
Viewport::Viewport()
|
||||
: m_Renderer(vtkRenderer::New())
|
||||
, m_Annotation(vtkCornerAnnotation::New())
|
||||
, m_Marker(vtkOrientationMarkerWidget::New())
|
||||
, m_CameraWidget(nullptr)
|
||||
, m_Colors(vtkNamedColors::New())
|
||||
{
|
||||
}
|
||||
|
||||
Viewport::~Viewport()
|
||||
{
|
||||
if (m_Renderer) {
|
||||
m_Renderer->RemoveAllViewProps();
|
||||
m_Renderer->Clear();
|
||||
}
|
||||
|
||||
if (m_Annotation) m_Annotation->Delete();
|
||||
if (m_Marker) m_Marker->Delete();
|
||||
if (m_CameraWidget) m_CameraWidget->Delete();
|
||||
if (m_Renderer) m_Renderer->Delete();
|
||||
if (m_Colors) m_Colors->Delete();
|
||||
}
|
||||
|
||||
void Viewport::SetupPipeline(vtkRenderWindowInteractor* iren)
|
||||
{
|
||||
if (!iren) return;
|
||||
|
||||
// Trackball-camera interaction style
|
||||
vtkNew<vtkInteractorStyleTrackballCamera> style;
|
||||
iren->SetInteractorStyle(style);
|
||||
|
||||
// Corner annotation
|
||||
m_Annotation->GetTextProperty()->SetColor(1, 1, 1);
|
||||
m_Annotation->GetTextProperty()->SetFontFamilyToArial();
|
||||
m_Annotation->GetTextProperty()->SetOpacity(0.5);
|
||||
m_Annotation->SetMaximumFontSize(10);
|
||||
m_Annotation->SetText(0, "uLib VTK Viewer - OpenCMT all right reserved.");
|
||||
m_Renderer->AddViewProp(m_Annotation);
|
||||
|
||||
// Orientation axes marker (bottom-left corner)
|
||||
vtkNew<vtkAxesActor> axes;
|
||||
m_Marker->SetInteractor(iren);
|
||||
m_Marker->SetOrientationMarker(axes);
|
||||
m_Marker->SetViewport(0.0, 0.0, 0.2, 0.2);
|
||||
m_Marker->SetEnabled(true);
|
||||
m_Marker->InteractiveOff();
|
||||
|
||||
// Grid Plane centered at (0,0,0)
|
||||
m_GridSource = vtkSmartPointer<vtkPlaneSource>::New();
|
||||
m_GridActor = vtkSmartPointer<vtkActor>::New();
|
||||
vtkNew<vtkPolyDataMapper> gridMapper;
|
||||
gridMapper->SetInputConnection(m_GridSource->GetOutputPort());
|
||||
|
||||
m_GridActor->SetMapper(gridMapper);
|
||||
m_GridActor->GetProperty()->SetRepresentationToWireframe();
|
||||
m_GridActor->GetProperty()->SetColor(0.4, 0.4, 0.4);
|
||||
m_GridActor->GetProperty()->SetLighting(0);
|
||||
m_GridActor->GetProperty()->SetOpacity(0.5);
|
||||
m_GridActor->PickableOff();
|
||||
m_Renderer->AddActor(m_GridActor);
|
||||
|
||||
// Global Origin Axes
|
||||
m_OriginAxes = vtkSmartPointer<vtkAxes>::New();
|
||||
m_OriginAxes->SetScaleFactor(1.0); // will be updated
|
||||
|
||||
vtkNew<vtkPolyDataMapper> axesMapper;
|
||||
axesMapper->SetInputConnection(m_OriginAxes->GetOutputPort());
|
||||
|
||||
m_OriginAxesActor = vtkSmartPointer<vtkActor>::New();
|
||||
m_OriginAxesActor->SetMapper(axesMapper);
|
||||
m_OriginAxesActor->PickableOff();
|
||||
m_Renderer->AddActor(m_OriginAxesActor);
|
||||
|
||||
UpdateGrid();
|
||||
|
||||
// Observe interactor to update grid during interaction
|
||||
vtkNew<vtkCallbackCommand> interactionCallback;
|
||||
interactionCallback->SetClientData(this);
|
||||
interactionCallback->SetCallback([](vtkObject*, unsigned long, void* clientdata, void*){
|
||||
static_cast<Viewport*>(clientdata)->UpdateGrid();
|
||||
});
|
||||
iren->AddObserver(vtkCommand::InteractionEvent, interactionCallback);
|
||||
m_Renderer->GetActiveCamera()->AddObserver(vtkCommand::ModifiedEvent, interactionCallback);
|
||||
|
||||
|
||||
// Camera-orientation widget (VTK >= 9)
|
||||
#if VTK_MAJOR_VERSION >= 9
|
||||
m_CameraWidget = vtkCameraOrientationWidget::New();
|
||||
m_CameraWidget->SetParentRenderer(m_Renderer);
|
||||
m_CameraWidget->SetInteractor(iren);
|
||||
m_CameraWidget->On();
|
||||
#endif
|
||||
|
||||
m_Renderer->SetBackground(0.15, 0.15, 0.15);
|
||||
m_Renderer->ResetCamera();
|
||||
}
|
||||
|
||||
void Viewport::Reset()
|
||||
{
|
||||
ZoomAuto();
|
||||
Render();
|
||||
}
|
||||
|
||||
void Viewport::ZoomAuto()
|
||||
{
|
||||
if (m_Renderer) {
|
||||
m_Renderer->ResetCameraClippingRange();
|
||||
m_Renderer->ResetCamera();
|
||||
}
|
||||
}
|
||||
|
||||
void Viewport::AddPuppet(Puppet& prop)
|
||||
{
|
||||
prop.ConnectRenderer(m_Renderer);
|
||||
prop.ConnectInteractor(GetInteractor());
|
||||
Render();
|
||||
}
|
||||
|
||||
void Viewport::RemovePuppet(Puppet& prop)
|
||||
{
|
||||
prop.DisconnectRenderer(m_Renderer);
|
||||
Render();
|
||||
}
|
||||
|
||||
void Viewport::addProp(vtkProp* prop)
|
||||
{
|
||||
if (m_Renderer) {
|
||||
m_Renderer->AddActor(prop);
|
||||
Render();
|
||||
}
|
||||
}
|
||||
|
||||
void Viewport::RemoveProp(vtkProp* prop)
|
||||
{
|
||||
if (m_Renderer) {
|
||||
m_Renderer->RemoveViewProp(prop);
|
||||
Render();
|
||||
}
|
||||
}
|
||||
|
||||
void Viewport::UpdateGrid()
|
||||
{
|
||||
if (!m_Renderer || !m_GridSource) return;
|
||||
|
||||
vtkCamera* camera = m_Renderer->GetActiveCamera();
|
||||
if (!camera) return;
|
||||
|
||||
// Determine the "scale" of the view (how many units are visible vertically)
|
||||
double viewHeight;
|
||||
if (camera->GetParallelProjection()) {
|
||||
viewHeight = 2.0 * camera->GetParallelScale();
|
||||
} else {
|
||||
double distance = camera->GetDistance();
|
||||
// ViewAngle is height angle in degrees
|
||||
double angleRad = camera->GetViewAngle() * vtkMath::Pi() / 180.0;
|
||||
viewHeight = 2.0 * distance * std::tan(angleRad / 2.0);
|
||||
}
|
||||
|
||||
if (viewHeight <= 0) viewHeight = 1.0;
|
||||
|
||||
// We want roughly 5-15 grid divisions visible.
|
||||
// Spacing should be a power of 10 (1mm, 1cm, 10cm, 1m, 10m...)
|
||||
double log10Spacing = std::floor(std::log10(viewHeight / 5.0));
|
||||
double spacing = std::pow(10.0, log10Spacing);
|
||||
|
||||
// Get current focal point to center the grid near what we're looking at
|
||||
double focalPoint[3];
|
||||
camera->GetFocalPoint(focalPoint);
|
||||
|
||||
// Align center to spacing
|
||||
double centerX = std::round(focalPoint[0] / spacing) * spacing;
|
||||
double centerY = std::round(focalPoint[1] / spacing) * spacing;
|
||||
|
||||
// Number of lines: enough to cover the screen even if aspect ratio is wide
|
||||
// or if we rotate. 20x20 is usually plenty.
|
||||
int numLines = 20;
|
||||
double halfSize = (numLines / 2.0) * spacing;
|
||||
|
||||
double xmin = centerX - halfSize;
|
||||
double xmax = centerX + halfSize;
|
||||
double ymin = centerY - halfSize;
|
||||
double ymax = centerY + halfSize;
|
||||
|
||||
// Update Plane Source
|
||||
m_GridSource->SetOrigin(xmin, ymin, 0.0);
|
||||
m_GridSource->SetPoint1(xmax, ymin, 0.0);
|
||||
m_GridSource->SetPoint2(xmin, ymax, 0.0);
|
||||
m_GridSource->SetXResolution(numLines);
|
||||
m_GridSource->SetYResolution(numLines);
|
||||
m_GridSource->Update();
|
||||
|
||||
if (m_OriginAxes) {
|
||||
m_OriginAxes->SetScaleFactor(spacing);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace Vtk
|
||||
} // namespace uLib
|
||||
Reference in New Issue
Block a user