The example draws a red circle around mouse position by vtkContextItem, vtkContext2D and vtkContextActor. When moving mouse, the red circle following it.
CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
project(vtk802)
find_package( VTK REQUIRED )
add_executable(${PROJECT_NAME}
"main.cpp"
"point.hpp"
"CustomIteractorStyle.h"
"CustomIteractorStyle.cpp"
"ULog.h"
"UPaintBrush.h"
"UPaintBrush.cpp")
#find_package( VTK COMPONENTS vtkCommonCore vtkRenderingCore vtkInteractionStyle )
if (VTK_VERSION VERSION_LESS "8.90.0")
# old system
include(${VTK_USE_FILE})
else ()
# vtk_module_autoinit is needed
vtk_module_autoinit(
TARGETS ${PROJECT_NAME}
MODULES ${VTK_LIBRARIES}
)
endif ()
target_link_libraries( ${PROJECT_NAME} ${VTK_LIBRARIES} )
CustomIteractorStyle.h:
#pragma once
#include <iostream>
#include <vtkSmartPointer.h>
#include <vtkInteractorStyleTrackballCamera.h>
#include <vtkActor.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkTransform.h>
#include "point.hpp"
#define CPP_SET_MACRO(name,type) \
void Set##name(type _arg) \
{ \
if (this->name != _arg) \
{ \
this->name = _arg; \
} \
}
#define vtkSPtr vtkSmartPointer
#define vtkSPtrNew(Var, Type) vtkSPtr<Type> Var = vtkSPtr<Type>::New();
class UPaintBrush;
class CustomIteractorStyle: public vtkInteractorStyleTrackballCamera
{
public:
static CustomIteractorStyle *New(){ return new CustomIteractorStyle(); }
void OnMouseMove() override;
void SetRenderer( vtkSmartPointer<vtkRenderer> renderer );
protected:
CustomIteractorStyle();
~CustomIteractorStyle() override;
UPaintBrush *m_Brush;
vtkSPtr<vtkRenderer> m_Renderer;
};
CustomIteractorStyle.cpp
#include "CustomIteractorStyle.h"
#include "point.hpp"
#include "UPaintBrush.h"
#include <vtkCamera.h>
void CustomIteractorStyle::OnMouseMove()
{
if( m_Brush )
{
int *eventPos = GetInteractor()->GetEventPosition();
m_Brush->UpdateItem( eventPos[0], eventPos[1] );
m_Renderer->GetRenderWindow()->Render();
}
}
void CustomIteractorStyle::SetRenderer(vtkSmartPointer<vtkRenderer> renderer)
{
m_Renderer = renderer;
if( m_Brush ) m_Brush->UpdateRenderer( renderer );
}
CustomIteractorStyle::CustomIteractorStyle()
{
m_Brush = new UPaintBrush();
m_Renderer = nullptr;
}
CustomIteractorStyle::~CustomIteractorStyle()
{
delete m_Brush;
m_Brush = nullptr;
}
UPaintBrush.h
#pragma once
#include <vtkContextItem.h>
#include <vtkContext2D.h>
#include <vtkObjectFactory.h>
#include <vtkPoints2D.h>
#include <vtkSmartPointer.h>
#include <vtkContextActor.h>
#include <vtkRenderer.h>
struct PaintBrushSettings
{
double radius = 5;
};
class BrushItem : public vtkContextItem
{
public:
static BrushItem* New();
vtkTypeMacro(BrushItem, vtkContextItem);
virtual bool Paint(vtkContext2D* painter);
void SetMousePos( double x, double y );
void SetRadius(double radius);
protected:
BrushItem();
double m_MousePos[2];
vtkSmartPointer<vtkPoints2D> m_BrushPts;
};
class UPaintBrush
{
public:
UPaintBrush();
void UpdateRenderer(vtkSmartPointer<vtkRenderer> renderer);
void UpdateItem(double x, double y);
protected:
PaintBrushSettings m_BrushSettings;
vtkSmartPointer<vtkContextActor> m_BrushActor;
vtkSmartPointer<vtkRenderer> m_CurRenderer;
};
UPaintBrush.cpp
#include "UPaintBrush.h"
#include "ULog.h"
#include <vtkPen.h>
#include <vtkTransform2D.h>
#include <vtkMath.h>
#include <vtkContextScene.h>
#include <vtkContextDevice2D.h>
vtkStandardNewMacro(BrushItem);
BrushItem::BrushItem()
: m_BrushPts( vtkSmartPointer<vtkPoints2D>::New() )
{
m_MousePos[0] = m_MousePos[1] = 10;
}
// draw circle, the following PushMatrix and PopMatrix is used to avoid affecting other drawing.
// So you have to update m_MousePos before this interface if you want to make circle to move with your mouse.
bool BrushItem::Paint(vtkContext2D *painter)
{
painter->GetPen()->SetColor(255, 0, 0);
painter->GetPen()->SetWidth( 3 );
painter->PushMatrix();
vtkNew<vtkTransform2D> tran;
tran->Translate(m_MousePos[0], m_MousePos[1]);
painter->AppendTransform(tran);
painter->DrawPoly( m_BrushPts );
painter->PopMatrix();
return true;
}
void BrushItem::SetMousePos(double x, double y)
{
m_MousePos[0] = x;
m_MousePos[1] = y;
}
void BrushItem::SetRadius(double radius)
{
unsigned int n = 360;
m_BrushPts->Allocate(n+1);
// draw a circle with radius and center (0, 0).
for(int i = 0; i <= n; i++)
{
double alpha = i * 2 * vtkMath::Pi() / n;
double x = cos(alpha)*radius, y = sin(alpha)*radius;
m_BrushPts->InsertNextPoint(x, y);
}
}
UPaintBrush::UPaintBrush()
: m_BrushActor( vtkSmartPointer<vtkContextActor>::New() )
, m_CurRenderer( nullptr )
{
}
void UPaintBrush::UpdateRenderer(vtkSmartPointer<vtkRenderer> renderer)
{
if( m_CurRenderer != nullptr )
{
if( m_CurRenderer != renderer )
{
m_CurRenderer->RemoveActor( m_BrushActor );
}
else {
return;
}
}
m_CurRenderer = renderer;
if( m_CurRenderer )
{
m_CurRenderer->AddActor( m_BrushActor );
}
Log( IInfo, "m_CurRenderer: ", m_CurRenderer );
}
void UPaintBrush::UpdateItem(double x, double y)
{
m_BrushActor->GetScene()->ClearItems();
vtkSmartPointer<BrushItem> brushItem = vtkSmartPointer<BrushItem>::New();
brushItem->SetRadius( m_BrushSettings.radius );
brushItem->SetMousePos( x, y );
brushItem->Update();
m_BrushActor->GetScene()->AddItem( brushItem );
Log( IInfo, "finished! " );
}
main.cpp
#include <iostream>
#include <vtkSmartPointer.h>
#include <vtkSphereSource.h>
#include <vtkActor.h>
#include <vtkConeSource.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkPolyDataMapper.h>
#include <vtkRenderWindowInteractor.h>
#include "CustomIteractorStyle.h"
#define vtkSPtr vtkSmartPointer
#define vtkSPtrNew(Var, Type) vtkSPtr<Type> Var = vtkSPtr<Type>::New();
using namespace std;
int main()
{
vtkSPtrNew( cone, vtkConeSource );
vtkSPtrNew( mapper, vtkPolyDataMapper );
mapper->SetInputConnection( cone->GetOutputPort() );
vtkSPtrNew( actor, vtkActor );
actor->SetMapper( mapper );
vtkSPtrNew( renderer, vtkRenderer );
renderer->AddActor(actor);
renderer->SetBackground( 0, 0, 0 );
vtkSPtrNew( renderWindow, vtkRenderWindow );
renderWindow->AddRenderer( renderer );
vtkSPtrNew( renderWindowInteractor, vtkRenderWindowInteractor );
renderWindowInteractor->SetRenderWindow( renderWindow );
vtkSPtrNew( iStyle, CustomIteractorStyle );
iStyle->SetRenderer( renderer );
renderWindowInteractor->SetInteractorStyle( iStyle );
renderer->ResetCamera();
renderWindow->Render();
renderWindowInteractor->Start();
return 0;
}
[…] This article is a sequel to the previous one https://www.weiy.city/2023/04/draw-a-circle-around-mouse-postion-on-screen/. […]