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;
}
Categories: VTK

0 0 votes
Article Rating
Subscribe
Notify of
guest

1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
trackback

[…] This article is a sequel to the previous one https://www.weiy.city/2023/04/draw-a-circle-around-mouse-postion-on-screen/. […]

Content Summary
: Input your strings, the tool can get a brief summary of the content for you.

X
1
0
Would love your thoughts, please comment.x
()
x