PCL visualization in Qt using QVTK - c++

I am rather new in Qt programming, and I am trying to visualize a point cloud from PCL inside a Qt Widget. I have tried to use this approach: https://stackoverflow.com/a/11939703/2339680, or (similar): http://www.pcl-users.org/QT-PCLVisualizer-mostly-working-td3285187.html.
I get the compile error: "invalid static_cast from type ‘vtkObjectBase* const’ to type ‘vtkRenderWindow*’" when trying to set the render window in my QVTKWidget.
For reference, I have included code from the second source below, which reproduces the error.
#include <pcl/sample_consensus/sac_model_plane.h>
#include <pcl/visualization/cloud_viewer.h>
#include <pcl/common/common.h>
#include <QVTKWidget.h>
int main(int argc, char** argv)
{
QApplication app(argc, argv);
QVTKWidget widget;
widget.resize(512, 256);
//
{
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_xyz (new pcl::PointCloud<pcl::PointXYZ>);
{
for (float y = -0.5f; y <= 0.5f; y += 0.01f)
{
for (float z = -0.5f; z <= 0.5f; z += 0.01f)
{
pcl::PointXYZ point;
point.x = 2.0f - y;
point.y = y;
point.z = z;
cloud_xyz->points.push_back (point);
}
}
cloud_xyz->width = cloud_xyz->points.size ();
cloud_xyz->height = 1;
}
// this creates and displays a window named "test_viz"
// upon calling PCLVisualizerInteractor interactor_->Initialize ();
// how to disable that?
pcl::visualization::PCLVisualizer pviz ("test_viz");
pviz.addPointCloud<pcl::PointXYZ>(cloud_xyz);
pviz.setBackgroundColor(0, 0, 0.1);
vtkSmartPointer<vtkRenderWindow> renderWindow = pviz.getRenderWindow();
widget.SetRenderWindow(renderWindow);
}
widget.show();
app.exec();
return EXIT_SUCCESS;
}
The error is occures at the line
widget.SetRenderWindow(renderWindow);
I am using Qt 4.8.0 and PCL 1.7.0. Does anyone know if it is possible to get around this?

With inspiration from https://stackoverflow.com/a/5808864/2339680 i guess that the problem is, that vtkRenderWindow is only available to the compiler as a forward declaration. If you include
#include "vtkRenderWindow.h"
in the beginning, everything should compile.

Related

Open3D - C++: how to animate 3D point cloud

In Open3D, with C++, how to animate 3D point cloud: same question that this one in python Open3d: How to update point cloud during window running? but can't get this to work.
The following code (inspired from github repo example examples/cpp/PointCloud.cpp) compile, run (the viewer and point appears), but animation is not rendered
>> cat ../examples/cpp/PtCloud.cpp
#include <Eigen/Dense>
#include <iostream>
#include <memory>
#include "open3d/Open3D.h"
#include <unistd.h> // sleep
using namespace open3d;
void PrintPointCloud(const std::shared_ptr<geometry::PointCloud> &pointcloud) {
using namespace open3d;
bool pointcloud_has_normal = pointcloud->HasNormals();
utility::LogInfo("Pointcloud has %d points.",
(int)pointcloud->points_.size());
Eigen::Vector3d min_bound = pointcloud->GetMinBound();
Eigen::Vector3d max_bound = pointcloud->GetMaxBound();
utility::LogInfo(
"Bounding box is: ({:.4f}, {:.4f}, {:.4f}) - ({:.4f}, {:.4f}, "
"{:.4f})",
min_bound(0), min_bound(1), min_bound(2), max_bound(0),
max_bound(1), max_bound(2));
for (size_t i = 0; i < pointcloud->points_.size(); i++) {
if (pointcloud_has_normal) {
const Eigen::Vector3d &point = pointcloud->points_[i];
const Eigen::Vector3d &normal = pointcloud->normals_[i];
utility::LogInfo("{:.6f} {:.6f} {:.6f} {:.6f} {:.6f} {:.6f}",
point(0), point(1), point(2), normal(0), normal(1),
normal(2));
} else {
const Eigen::Vector3d &point = pointcloud->points_[i];
utility::LogInfo("{:.6f} {:.6f} {:.6f}", point(0), point(1),
point(2));
}
}
utility::LogInfo("End of the list.");
}
std::shared_ptr<geometry::PointCloud> pointcloud(new geometry::PointCloud);
bool AnimatePointCloud(visualization::Visualizer * visualizer) {
if (!visualizer) return false;
for (int i = 0; i < 10; i++) {
sleep(2);
pointcloud->points_.push_back(Eigen::Vector3d(0.0, 0.0, i+1.0));
pointcloud->points_.push_back(Eigen::Vector3d(1.0, 0.0, i+1.0));
pointcloud->points_.push_back(Eigen::Vector3d(0.0, 1.0, i+1.0));
PrintPointCloud(pointcloud);
visualizer->UpdateGeometry(pointcloud);
visualizer->PollEvents();
visualizer->UpdateRender();
visualizer->Run();
}
return true;
}
int main(int argc, char *argv[]) {
// 1. test basic pointcloud functions.
pointcloud->points_.push_back(Eigen::Vector3d(0.0, 0.0, 0.0));
pointcloud->points_.push_back(Eigen::Vector3d(1.0, 0.0, 0.0));
pointcloud->points_.push_back(Eigen::Vector3d(0.0, 1.0, 0.0));
PrintPointCloud(pointcloud);
// 2. test pointcloud visualization
visualization::Visualizer visualizer;
visualizer.CreateVisualizerWindow("Open3D", 1600, 900);
visualizer.AddGeometry(pointcloud);
visualizer.RegisterAnimationCallback(AnimatePointCloud);
visualizer.Run();
visualizer.DestroyVisualizerWindow();
return 0;
}
The code is supposed to animate points that stack up in animated way: the viewer seems to freeze. Didn't find any C++ example. What's wrong?

QScrollArea - Resize content widgets by keeping the aspect ratio

I have a layout that looks like this.
Where:
Blue: rectangle it's a ScrollArea
Orange: rectangles are the widgets from that ScrollArea
My code:
#include <QtWidgets>
///////////////////////////////////////////////////////////////////////////////////////
class RoundedPolygon : public QPolygon {
public:
RoundedPolygon() { SetRadius(10); }
void SetRadius(unsigned int iRadius) { m_iRadius = iRadius; }
const QPainterPath &GetPath() {
m_path = QPainterPath();
if (count() < 3) {
qDebug() << "!! Polygon should have at least 3 points !!";
return m_path;
}
QPointF pt1;
QPointF pt2;
for (int i = 0; i < count(); i++) {
pt1 = GetLineStart(i);
if (i == 0)
m_path.moveTo(pt1);
else
m_path.quadTo(at(i), pt1);
pt2 = GetLineEnd(i);
m_path.lineTo(pt2);
}
// close the last corner
pt1 = GetLineStart(0);
m_path.quadTo(at(0), pt1);
return m_path;
}
private:
QPointF GetLineStart(int i) const {
QPointF pt;
QPoint pt1 = at(i);
QPoint pt2 = at((i + 1) % count());
float fRat = m_iRadius / GetDistance(pt1, pt2);
if (fRat > 0.5f)
fRat = 0.5f;
pt.setX((1.0f - fRat) * pt1.x() + fRat * pt2.x());
pt.setY((1.0f - fRat) * pt1.y() + fRat * pt2.y());
return pt;
}
QPointF GetLineEnd(int i) const {
QPointF pt;
QPoint pt1 = at(i);
QPoint pt2 = at((i + 1) % count());
float fRat = m_iRadius / GetDistance(pt1, pt2);
if (fRat > 0.5f)
fRat = 0.5f;
pt.setX(fRat * pt1.x() + (1.0f - fRat) * pt2.x());
pt.setY(fRat * pt1.y() + (1.0f - fRat) * pt2.y());
return pt;
}
float GetDistance(QPoint pt1, QPoint pt2) const {
int fD = (pt1.x() - pt2.x()) * (pt1.x() - pt2.x()) + (pt1.y() - pt2.y()) * (pt1.y() - pt2.y());
return sqrtf(fD);
}
private:
QPainterPath m_path;
unsigned int m_iRadius{};
};
class PolygonButtonWidget : public QWidget {
Q_OBJECT
public:
explicit PolygonButtonWidget(QWidget *parent = nullptr) : QWidget(parent) {}
~PolygonButtonWidget() override = default;
protected:
void resizeEvent(QResizeEvent *event) override {
float ratioW = 8;
float ratioH = 3;
// ui->scrollAreaWidgetContents->setFixedSize(5000, h);
float thisAspectRatio = (float) event->size().width() / event->size().height();
if (thisAspectRatio < ratioW / ratioH) {
float w = event->size().height() * ratioW / ratioH;
float h = event->size().height();
qDebug() << hasHeightForWidth() << " " << w << " " << h;
this->resize(w, h);
if (m_nrButtons != 0) {
this->move((w + 20) * m_nrButtons, this->y());
}
}
QWidget::resizeEvent(event);
}
int m_nrButtons{};
public:
void setMNrButtons(int mNrButtons) {
m_nrButtons = mNrButtons;
}
protected:
void paintEvent(QPaintEvent *event) override {
int offset = 50;
m_polygon.clear();
m_polygon.emplace_back(0, height()); //DOWN-LEFT
m_polygon.emplace_back(width() - offset, height()); //DOWN-RIGHT
m_polygon.emplace_back(width(), 0); //TOP-RIGHT
m_polygon.emplace_back(0 + offset, 0);
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
RoundedPolygon poly;
poly.SetRadius(15);
for (QPoint point: m_polygon) {
poly << point;
}
QBrush fillBrush;
fillBrush.setColor(Qt::darkBlue);
fillBrush.setStyle(Qt::SolidPattern);
QPainterPath path;
path.addPath(poly.GetPath());
painter.fillPath(path, fillBrush);
}
void mousePressEvent(QMouseEvent *event) override {
auto cursorPos = mapFromGlobal(QCursor::pos());
qDebug() << "X: " << cursorPos.x() << " Y: " << cursorPos.y();
inside(cursorPos, m_polygon);
qDebug() << "Pressed";
}
private:
std::vector<QPoint> m_polygon;
bool inside(QPoint point, std::vector<QPoint> polygon) {
auto x = point.x();
auto y = point.y();
auto inside = false;
auto i = 0;
auto j = polygon.size() - 1;
while (i < polygon.size()) {
auto xi = polygon[i].x();
auto yi = polygon[i].y();
auto xj = polygon[j].x();
auto yj = polygon[j].y();
auto intersect = ((yi > y) != (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
if (intersect) inside = !inside;
j = i++;
}
qDebug() << inside;
return inside;
}
};
///////////////////////////////////////////////////////////////////////////////////////
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
QWidget root;
QHBoxLayout layout{&root};
for (int i = 0; i < 10; ++i) {
auto p = new PolygonButtonWidget();
p->setMinimumSize(100, 100);
p->setMNrButtons(i);
layout.addWidget(p);
}
root.setStyleSheet("background-color: rgb(19,19,19);");
QScrollArea view;
view.setWidget(&root);
view.show();
app.exec();
}
#include "main.moc"
The problem arises when I'm trying to resize the window. In the moment of resizing, I want my widgets to keep their aspect ratio. But that's not going to happen.
I have scroll list of widgets which is looking like this (if it's expended on X way too much)
If I will scale it on Y-axis it's going to look like this.
After I've changed the resizeEvent now it's going to look something like this
or like this
How can I fix this? For some reason, some of my widgets are going to disappear, what should be my approach in order to fix this issue?
The problem is caused by the assumption that there's any mechanism that will automatically resize the widgets for you. There isn't. A QScrollArea acts as a layout barrier and any layouts inside of it are isolated from its size, and thus from any resize events.
You must resize the container widget (the one with blue outline on your diagram) yourself anytime the scroll area changes size, and you need first to prepare a test case for the widgets such that their size changes are properly managed when placed in the layout of your choice, and said layout is resized.
Finally, the pet peeve of mine: It's unlikely that you actually need the QMainWindow for anything. It's just a silly Qt Creator template. But unless you want an MDI interface and docking, you shouldn't be using the QMainWindow - and especially not when making a self-contained example. All you need here is QScrollArea as a top-level widget. That's literally all. Any QWidget can be a top-level window!
For future submissions, please provide all the code needed in a single main.cpp file that begins with #include <QtWidgets> and ends with #include "main.moc". You won't need any other includes for Qt classes, and you can write class definitions Java-style, with all the methods defined within the class declaration itself. This provides for short code - after all, a SO question isn't an Enterprise project. It's supposed to be minimal, and that really means that anything not necessary must be removed. No need for header files, multiple includes, nor other fluff - i.e. use Qt containers instead of C++ STL so that you don't need more includes etc.
Your example should look roughly as follows:
#include <QtWidgets>
class PolygonButtonWidget : public QAbstractButton {
Q_OBJECT
/* without seeing the code here, your question is unanswerable */
};
int main(int argc, char* argv[]) {
QApplication app(argc, argv);
QWidget root;
QHBoxLayout layout{&root};
PolygonButtonWidget buttons[10];
for (auto &button : buttons)
layout.addWidget(&button);
QScrollArea view;
view.setWidget(&root);
view.show();
app.exec();
view.takeWidget();
}
#include "main.moc"
Without such an example, your question is hard to answer, since:
How can we debug it? Debugging means using a debugger. If your code cannot be immediately compiled, then it's quite unlikely that someone will bother debugging it, and debugging by inspection is often error-prone.
How can we provide a tested answer if we'd have to first write the entire "test case" for it?
How can we know what's inside your button widget? The behavior of that widget does affect the ultimate solution.
It'd also help if you described a few use cases that you'd expect to work. That is, mock up (with a drawing) the state of the widgets before and after the view is resized, so that we can easily see what it is that you expect to happen. A lot of it is very easy to miss when explaining your needs in words. Use cases are a lingua franca of software specifications. If you don't use them, it's highly likely that you yourself don't know what behavior you expect in all cases.

How to tell VTK pipeline to use new vtkPolyData updated via TimerEvent?

Intention
I wrote a VTK application that generates a spiral using vtkPoints > vtkPolyLine > vtkPolyData > vtkPolyDataMapper and displays it. This works fine, if done static at the initialization of the program.
Now, I want to add new data points dynamically. The intention is to visualize measurements in real time, so new data will be added in certain intervals.
Issues
Currently, I just implemented a TimerEvent to update the vtkPoints and vtkPolyLine. But, the program just shows the static data generated before the vtkRenderWindowInteractor was started. I also tried to use "Modified()" and "Update()" calls to nearly all objects, tried to remove, regenerate and add a new actor to the renderer -- but without success! I added my C++ code below...
Related-Questions
The following mailing list question is about this issues, but the solution given doen't work for me:
http://public.kitware.com/pipermail/vtkusers/2006-November/038377.html
The following question seems to be related, but there are no useful answers:
VTK: update data points in renderWindow at every simulation timestep
Questions
How to tell VTK that the vtkPolyData object has changed?
Which of the VTK UsersGuide should I probably have a closer look at?
Details / Source Code
I'm using Visual Studio Community 2017 and VTK 8.0.0, both compiled as Win32 target.
#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkRenderingContextOpenGL2);
VTK_MODULE_INIT(vtkRenderingVolumeOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);
VTK_MODULE_INIT(vtkRenderingFreeType);
#include <vtkSmartPointer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkConeSource.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkProperty.h>
#include <vtkPoints.h>
#include <vtkPolyLine.h>
vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
vtkSmartPointer<vtkPolyLine> polyLine = vtkSmartPointer<vtkPolyLine>::New();
int numOfPoints = 0;
double t = 0;
void NextPoint() {
double x = t * cos(t);
double y = t * sin(t);
points->InsertNextPoint(x, y, t);
polyLine->GetPointIds()->InsertNextId(numOfPoints);
numOfPoints++;
t += 0.1;
}
vtkSmartPointer<vtkPolyData> generateEllipse() {
// Add some points so we actually see something at all...
for (int i = 0; i < 100; ++i) {
NextPoint();
}
vtkSmartPointer<vtkCellArray> cells = vtkSmartPointer<vtkCellArray>::New();
cells->InsertNextCell(polyLine);
vtkSmartPointer<vtkPolyData> polyData = vtkSmartPointer<vtkPolyData>::New();
polyData->SetPoints(points);
polyData->SetLines(cells);
return polyData;
}
class vtkTimerCallback : public vtkCommand
{
public:
static vtkTimerCallback *New()
{
vtkTimerCallback *cb = new vtkTimerCallback;
cb->TimerCount = 0;
return cb;
}
virtual void Execute(vtkObject *vtkNotUsed(caller), unsigned long eventId,
void *vtkNotUsed(callData))
{
if (vtkCommand::TimerEvent == eventId)
{
NextPoint(); // Add another point to polyData
++this->TimerCount;
cout << this->TimerCount << endl;
}
}
private:
int TimerCount;
};
int main(int argc, char** argv) {
vtkSmartPointer<vtkRenderWindow> renderWindow =
vtkSmartPointer<vtkRenderWindow>::New();
vtkSmartPointer<vtkRenderWindowInteractor> rwi = vtkSmartPointer<vtkRenderWindowInteractor>::New();
rwi->SetRenderWindow(renderWindow);
vtkSmartPointer<vtkPolyData> data = generateEllipse();
vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
mapper->SetInputData(data);
vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
actor->SetMapper(mapper);
actor->GetProperty()->SetDiffuseColor(255, 255, 0);
vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();
renderWindow->AddRenderer(renderer);
renderer->AddActor(actor);
renderer->ResetCamera();
renderWindow->Render();
// Add Timer Event...
rwi->Initialize();
vtkSmartPointer<vtkTimerCallback> cb = vtkSmartPointer<vtkTimerCallback>::New();
rwi->AddObserver(vtkCommand::TimerEvent, cb);
int timerId = rwi->CreateRepeatingTimer(100); // every 100ms
std::cout << "timerId: " << timerId << std::endl;
// Start Displaying...
rwi->Start();
return 0;
}
the problem is that the cells are not stored by pointer - when you call cells->InsertNextCell(polyLine); the data is copied, not pointed to, in order to create an efficient storage of the cells in an array (the whole implementation is actually in the header of vtkCellArray so you can check it out). So then when you update polyLine, it has no effect in the polydata, because the polydata have their own copy that you did not update. The following code works for me (you have to expose the polydata and the cellArray):
virtual void Execute(vtkObject *vtkNotUsed(caller), unsigned long eventId,
void *vtkNotUsed(callData))
{
if (vtkCommand::TimerEvent == eventId)
{
NextPoint(); // Add another point to polyData
cells->Initialize(); // reset the cells to remove the old spiral
cells->InsertNextCell(polyLine); // re-insert the updated spiral
cells->Modified(); // required to update
data->Modified(); // required to update
++this->TimerCount;
cout << polyLine->GetNumberOfPoints() << endl;
renderWindow->Render(); // refresh the render window after each update
}
}
Yesterday I worked out an alternative solution using a vtkProgrammableDataObjectSource as DataSource. Tomj's solution is the more direct and simple solution... However, there is no C++ Example Code at vtk.org that explains how to use vtkProgrammableDataObjectSource and I had to work it out by trial and error. So I'll post it here, as it might help others:
#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkRenderingContextOpenGL2);
VTK_MODULE_INIT(vtkRenderingVolumeOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);
VTK_MODULE_INIT(vtkRenderingFreeType);
#include <vtkSmartPointer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkConeSource.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkProperty.h>
#include <vtkPoints.h>
#include <vtkPolyLine.h>
#include <vtkProgrammableFilter.h>
#include <vtkCallbackCommand.h>
#include <vtkPolyDataStreamer.h>
#include <vtkProgrammableDataObjectSource.h>
vtkSmartPointer<vtkProgrammableDataObjectSource> pDOS = vtkSmartPointer<vtkProgrammableDataObjectSource>::New();
vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();
vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
vtkSmartPointer<vtkPolyLine> polyLine = vtkSmartPointer<vtkPolyLine>::New();
int numOfPoints = 0;
double t = 0;
void NextPoint() {
double x = t * cos(t);
double y = t * sin(t);
points->InsertNextPoint(x, y, t);
polyLine->GetPointIds()->InsertNextId(numOfPoints);
numOfPoints++;
t += 0.1;
}
void generateEllipse(void *caller) {
vtkProgrammableDataObjectSource *pDOS = vtkProgrammableDataObjectSource::SafeDownCast((vtkObjectBase*)caller);
vtkSmartPointer<vtkCellArray> cells = vtkSmartPointer<vtkCellArray>::New();
cells->InsertNextCell(polyLine);
vtkSmartPointer<vtkPolyData> polyData = vtkSmartPointer<vtkPolyData>::New();
polyData->SetPoints(points);
polyData->SetLines(cells);
pDOS->SetOutput(polyData);
}
int counter2 = 0;
void TimerCallbackFunction(vtkObject* caller, long unsigned int vtkNotUsed(eventId), void* clientData, void* vtkNotUsed(callData)) {
cout << "timer callback: " << counter2 << endl;
// To avoid globals we can implement this later...
// vtkSmartPointer<vtkProgrammableDataObjectSource> pDOS =
// static_cast<vtkProgrammableDataObjectSource*>(clientData);
vtkRenderWindowInteractor *rwi =
static_cast<vtkRenderWindowInteractor*>(caller);
NextPoint();
pDOS->Modified();
rwi->Render();
renderer->ResetCamera(); // Optional: Reposition Camera, so it displays the whole object
counter2++;
}
int main(int argc, char** argv) {
vtkSmartPointer<vtkRenderWindow> renderWindow =
vtkSmartPointer<vtkRenderWindow>::New();
vtkSmartPointer<vtkRenderWindowInteractor> rwi = vtkSmartPointer<vtkRenderWindowInteractor>::New();
rwi->SetRenderWindow(renderWindow);
pDOS->SetExecuteMethod(&generateEllipse, pDOS);
vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
mapper->SetInputConnection(pDOS->GetOutputPort());
vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
actor->SetMapper(mapper);
actor->GetProperty()->SetDiffuseColor(255, 255, 0);
renderWindow->AddRenderer(renderer);
renderer->AddActor(actor);
renderer->ResetCamera();
renderWindow->Render();
// Add Timer Event...
vtkSmartPointer<vtkCallbackCommand> timerCallback = vtkSmartPointer<vtkCallbackCommand>::New();
timerCallback->SetCallback(TimerCallbackFunction);
rwi->Initialize();
rwi->CreateRepeatingTimer(100);
rwi->AddObserver(vtkCommand::TimerEvent, timerCallback);
// Start Displaying...
rwi->Start();
return 0;
}

Gtkmm scroll_to() purpose

I'm wondering about this member-function's scroll_to(TextBuffer::iterator& iter, double within_margin = 0) parameter within_margin. The API says this:
The effective screen for purposes of this function is reduced by a margin of size within_margin.
...
Parameters
within_margin margin as a [0.0,0.5] fraction of screen size.
I just don't get it. What and when does this parameter modifies the behaviour? Every langugage-binding of Gtk includes the same description. I've written a small application, so you can change the passed argument to the parameter yourself.
#include <gtkmm.h>
#include <iostream>
#include <string>
using namespace std;
Gtk::TextView* text_view;
void on_add_button_clicked();
void on_scroll_button_clicked();
int main(int argc, char* argv[]) {
Glib::RefPtr<Gtk::Application> app = Gtk::Application::create(argc, argv, "org.gtkmm.examples.base");
Gtk::Window window;
Glib::RefPtr<Gdk::Monitor> primary_monitor = window.get_screen()->get_display()->get_primary_monitor();
Gdk::Rectangle monitor_size;
primary_monitor->get_geometry(monitor_size);
// half-size of primary-monitor
int width = monitor_size.get_width() / 2;
int height = monitor_size.get_height() / 2;
window.set_default_size(width, height);
window.set_title(__FILE__);
Gtk::Grid grid;
grid.set_row_spacing(5);
grid.set_column_spacing(5);
Gtk::ScrolledWindow scroll_window;
text_view = new Gtk::TextView();
text_view->set_editable(true);
scroll_window.add(*text_view);
scroll_window.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
scroll_window.set_hexpand(true);
scroll_window.set_vexpand(true);
Glib::RefPtr<Gtk::TextBuffer> text_buffer = text_view->get_buffer();
text_buffer->set_text("Hello!\n");
text_view->set_buffer(text_buffer);
grid.attach(scroll_window, 0, 0, 2, 2);
Gtk::Button add_button("add text");
add_button.signal_clicked().connect(sigc::ptr_fun(&on_add_button_clicked));
grid.attach_next_to(add_button, scroll_window, Gtk::POS_BOTTOM, 1, 1);
Gtk::Button scroll_button("scroll to somewhere");
scroll_button.signal_clicked().connect(sigc::ptr_fun(&on_scroll_button_clicked));
grid.attach_next_to(scroll_button, add_button, Gtk::POS_RIGHT, 1, 1);
window.add(grid);
window.show_all();
return app->run(window);
}
void on_add_button_clicked() {
Glib::RefPtr<Gtk::TextBuffer> text_buffer = text_view->get_buffer();
for (int i = 0; i != 100; ++i) {
text_buffer->insert_at_cursor("foobar\n");
}
}
void on_scroll_button_clicked() {
Glib::RefPtr<Gtk::TextBuffer> text_buffer = text_view->get_buffer();
Gtk::TextBuffer::iterator it = text_buffer->end();
text_view->scroll_to(it, 0.49);
}
You can compile the code with g++ -o scroll scroll.cpp -Wall -pedantic-errors `pkg-config gtkmm-3.0 --cflags --libs` .
Thank you
If margin is 0, then scroll_to() is free to put the target anywhere in the screen. If margin is 0.45, for example, then scroll_to() will put the target in the middle 10% of the screen, if possible.
The reason you don't see this in your example, is because you are scrolling to the end iterator, and it's not possible to scroll view so that the end of the text is displayed in the middle of the screen. (Some text views include extra space after the text in order to make this possible; Gtk::TextView doesn't.)

Rotate a 3D object (OSG & vc++)

I'm developing a 3D environment using VC++ and OSG and I need some help
I'm using this code below to charge the 3D models for the scene
mueble00Node = osgDB::readNodeFile("Model/mueble_desk.3ds");
mueble00Transform = new osg::MatrixTransform;
mueble00Transform->setName("mueble00");
mueble00Transform->setDataVariance(osg::Object::STATIC);
mueble00Transform->addChild(mueble00Node);
sceneRoot->addChild(mueble00Transform);
I've tried with some lines to rotate the 3D models, but with no result
Could anybody explain to me how to rotate the models on its own axis?
Use MatrixTransform::setMatrix() to change the orientation of the child node.
MatrixTransform* transform = new osg::MatrixTransform;
const double angle = 0.8;
const Vec3d axis(0, 0, 1);
transform->setMatrix(Matrix::rotate(angle, axis));
Below is a complete program that loads and displays a 3D object with and without the transformation added.
#include <string>
#include <osg/Object>
#include <osg/Node>
#include <osg/Transform>
#include <osg/Matrix>
#include <osg/MatrixTransform>
#include <osgDB/ReadFile>
#include <osgViewer/Viewer>
#include <osgGA/TrackballManipulator>
using namespace osg;
int main(int argc, char** argv)
{
if (argc != 2) {
std::cerr << "Usage: " << argv[0] << "<file>\n";
exit(1);
}
const std::string file = argv[1];
// Load a node.
Node* node = osgDB::readNodeFile(file);
if (!node) {
std::cerr << "Can't load node from file '" << file << "'\n";
exit(1);
}
// Set a transform for the node.
MatrixTransform* transform = new osg::MatrixTransform;
const double angle = 0.8;
const Vec3d axis(0, 0, 1);
transform->setMatrix(Matrix::rotate(angle, axis));
transform->setName(file);
transform->addChild(node);
// Add the node with and without the transform.
Group* scene = new Group();
scene->addChild(transform);
scene->addChild(node);
// Start a scene graph viewer.
osgViewer::Viewer viewer;
viewer.setSceneData(scene);
viewer.setCameraManipulator(new osgGA::TrackballManipulator());
viewer.realize();
while (!viewer.done()) viewer.frame();
}
You'll want to use a quat
http://www.openscenegraph.org/documentation/OpenSceneGraphReferenceDocs/a00568.html
It has a number of functions you can use for rotation.