I have a qwt plot, here a simple example, with a QWtPlotZoomer. The zoom in works, but zoom back reset the scale to 0-1000, instead the original scale.
I tried to solve this with (what is the difference between these lines ?)
zoomer->setZoomBase(false);
zoomer->zoom(0);
but that has no effect. What needs to be done to get the correct initial scale for the zoomer? A trivial solution is to implement the zoomer after the curve attachment, but in a real work example that is not applicable:
#include <QtWidgets/QApplication>
#include <QtWidgets/QMainWindow>
#include <QDebug>
#include <qwt_plot.h>
#include <qwt_plot_curve.h>
#include <qwt_plot_zoomer.h>
#include <vector>
using std::vector;
int main( int argc, char **argv )
{
QApplication a( argc, argv );
QwtPlot * plot = new QwtPlot();
plot->setAxisAutoScale(QwtPlot::xBottom);
plot->setAxisAutoScale(QwtPlot::yLeft);
QwtPlotZoomer *zoomer;
zoomer = new QwtPlotZoomer( QwtPlot::xBottom, QwtPlot::yLeft, plot->canvas() );
// create data
vector<double> x(100);
vector<double> y1(x.size());
for (size_t i = 0; i< x.size(); ++i) { x[i] = int(i)-50; }
for (size_t i = 0; i< y1.size(); ++i) { y1[i] = pow(double(abs(i-50))/10,2); }
// first curve
QwtPlotCurve *curve = new QwtPlotCurve();
curve->setRawSamples(&x[0], &y1[0], x.size());
curve->attach( plot );
zoomer->setZoomBase(false);
zoomer->zoom(0);
plot->replot();
QMainWindow window;
window.setCentralWidget(plot);
window.resize(800, 600);
window.show();
return a.exec();
}
Create the zoomer after attaching the curves ( having valid data ) or modify your code to zoomer->setZoomBase(true);
The line zoomer->zoom(0) is pointless and the final replot is not necessary as it is done by the zoomer to initialize its zoom stack.
When having a zoom base of [0,1000] you usually have initialized the zoom stack of your zoomer with a plot, where the scales have not been calculated before.
Note that attaching the curves does not update the ranges immediately - it is done before the next replot ( or better QwtPlot::updateAxes() ).
Related
I just recently started to use QT3D for a sideproject at work. And i'm surprised how fast you get something that looks pretty decent (at least for my case).
But i still have an issue with rendering speed and CPU usage.
I've written a small test program to showcase this (see below).
As we use Ubuntu i though it may be an issue with the NVIDIA driver but i tested it at home on my Windows PC as well.
And had the same results:
CPU usage is very high - 100% on one Core all the time.
GPU usage show no real difference if the application is running or not.
So my best guess is that it uses software rendering instead of the hardware?
Any ideas?
The example just draws 2000 Cuboids with random sizes on random positions with a light source above.
#include <QGuiApplication>
#include <QRandomGenerator>
#include <QHBoxLayout>
#include <Qt3DRender/QCamera>
#include <Qt3DCore/QEntity>
#include <QtWidgets/QApplication>
#include <QtWidgets/QWidget>
#include <QtGui/QScreen>
#include <Qt3DCore/QTransform>
#include <Qt3DCore/QAspectEngine>
#include <Qt3DExtras/QForwardRenderer>
#include <Qt3DRender/QPointLight>
#include <Qt3DExtras/QCuboidMesh>
#include <Qt3DExtras/QDiffuseSpecularMaterial>
#include <Qt3DExtras/Qt3DWindow>
#include <Qt3DExtras/QOrbitCameraController>
int main(int argc, char **argv)
{
//basic window/widget stuff
QApplication app(argc, argv);
Qt3DExtras::Qt3DWindow *view = new Qt3DExtras::Qt3DWindow();
view->defaultFrameGraph()->setClearColor(QColor(QRgb(0x4d4d4f)));
QWidget *container = QWidget::createWindowContainer(view);
QSize screenSize = view->screen()->size();
container->setMinimumSize(QSize(200, 100));
container->setMaximumSize(screenSize);
QWidget *widget = new QWidget;
QHBoxLayout *hLayout = new QHBoxLayout(widget);
hLayout->addWidget(container, 1);
//root entity
Qt3DCore::QEntity *rootEntity = new Qt3DCore::QEntity();
view->setRootEntity(rootEntity);
//setup camera
view->camera()->lens()->setPerspectiveProjection(45.0f, 16.0f/9.0f, 10.0f, 5000.0f);
view->camera()->setPosition(QVector3D(0, 0, 3000));
view->camera()->setUpVector(QVector3D(0, 1, 0));
view->camera()->setViewCenter(QVector3D(0, 0, 0));
//orbit camera controller
Qt3DExtras::QOrbitCameraController *camController = new Qt3DExtras::QOrbitCameraController(rootEntity);
camController->setCamera(view->camera());
camController->setLookSpeed(500);
//add light
Qt3DCore::QEntity *lightEntity = new Qt3DCore::QEntity(rootEntity);
Qt3DRender::QPointLight *light = new Qt3DRender::QPointLight(lightEntity);
light->setColor("white");
light->setIntensity(1);
lightEntity->addComponent(light);
Qt3DCore::QTransform *lightTransform = new Qt3DCore::QTransform(lightEntity);
lightTransform->setTranslation(QVector3D(0, 5000, 0));
lightEntity->addComponent(lightTransform);
//add objects
QRandomGenerator rng(1234);
for(int i = 0; i <= 2000; i++)
{
Qt3DCore::QEntity* shapeEntity = new Qt3DCore::QEntity(rootEntity);
Qt3DExtras::QCuboidMesh* mesh = new Qt3DExtras::QCuboidMesh();
mesh->setXExtent(int(rng.generate() % 30)+20);
mesh->setYExtent(int(rng.generate() % 30)+20);
mesh->setZExtent(int(rng.generate() % 30)+20);
shapeEntity->addComponent(mesh);
Qt3DExtras::QDiffuseSpecularMaterial *material = new Qt3DExtras::QDiffuseSpecularMaterial();
material->setAmbient(QColor(Qt::red).darker(150));
material->setDiffuse(QColor(Qt::red));
shapeEntity->addComponent(material);
Qt3DCore::QTransform* pTrans = new Qt3DCore::QTransform();
pTrans->setTranslation(QVector3D(int(rng.generate() % 2000)-1000, int(rng.generate() % 2000)-1000, int(rng.generate() % 2000)-1000));
shapeEntity->addComponent(pTrans);
}
//show
widget->show();
widget->resize(1200, 800);
return app.exec();
}
The use case is a 2D map with a vehicle at the origin. The map shall also be translated in case the vehicle moves e.g. 0.5 pixels. I believe this should be feasible using bilinear interpolation or similar.
If there is no simple solution using Qt, I would appreciate hints to non-Qt-solutions.
Minimal example:
#include <QtWidgets/QApplication>
#include <QtGui/QImage>
#include <QLabel>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
// Parameters
QString PATH_IMG_IN = "../img_test_rect.jpg";
QString PATH_IMG_OUT = "../img_out.png";
float TRANSLATE_IN_PX = 0.5;
// load image
QImage img;
img.load(PATH_IMG_IN);
// rotate image.
QTransform trans;
trans.translate(0,TRANSLATE_IN_PX);
QImage img_new = img.transformed(trans, Qt::SmoothTransformation);
// save image
img_new.save(PATH_IMG_OUT, nullptr, 100);
// optional: Get info about true transformation matrix
QTransform trans_true = QImage::trueMatrix(trans, img.width(), img.height());
return app.exec();
}
Given an input image with a sharp border (see below), I would expect the output image to have a blurred border. This is not the case:
How to fix that?
I tested openCV and its function cv::warpAffine allows translation with sub-pixel precision (see MWE below).
After founding some old, unanswered threads on qtcentre.org, it seems to me that Qt simply does not allow translation with sub-pixel precision. Please correct me if I am wrong.
For Qt, I only found workarounds to scale the image first, translate with pixel accuracy and scale down again. Unfortunately, this approach is too computationally expensive for my use case.
MWE with opencv:
#include "opencv2/opencv.hpp"
#include "opencv2/highgui/highgui.hpp"
int main(int argc, char** argv) {
// parameters
std::string PATH_IMG_IN = "../img_test_rect.jpg";
std::string PATH_IMG_OUT = "../img_out.jpg";
// load image
cv::Mat img = cv::imread(PATH_IMG_IN, CV_LOAD_IMAGE_GRAYSCALE);
if (!img.data) // Check for invalid input
{
std::cout << "Could not open or find the image" << std::endl;
return -1;
}
// rotate image
cv::Mat img_new = cv::Mat::ones(img.size(), img.type()) * 0.5; // another type = CV_8U
cv::Mat mat_transform = (cv::Mat_<float>(2, 3) << 1, 0, 0.5, 0, 1, 0);
cv::warpAffine(img, img_new, mat_transform, img_new.size());
// show image
cv::imshow("Display window", img_new);
// save image
cv::imwrite(PATH_IMG_OUT, img_new);
// wait for the user to press any key:
cv::waitKey(0);
return 0;
}
I am trying to create a minimal obj file viewer. Following is my code mostly copy pasted with some minor modifications.
#include <QGuiApplication>
#include <QApplication>
#include <Qt3DCore/QEntity>
#include <Qt3DCore/QTransform>
#include <Qt3DCore/QAspectEngine>
#include <Qt3DRender/qrenderaspect.h>
#include <Qt3DRender/QCamera>
#include <Qt3DRender/QMaterial>
#include <Qt3DRender/QMesh>
#include <Qt3DExtras/Qt3DWindow>
#include <Qt3DExtras/QTorusMesh>
#include <Qt3DExtras/QOrbitCameraController>
#include <Qt3DExtras/QPhongMaterial>
Qt3DCore::QEntity* createTestScene()
{
Qt3DCore::QEntity* root = new Qt3DCore::QEntity;
Qt3DCore::QEntity* torus = new Qt3DCore::QEntity(root);
Qt3DRender::QMesh* mesh = new Qt3DRender::QMesh(root);
mesh->setSource(QUrl::fromLocalFile("/Users/neel/model.obj"));
Qt3DCore::QTransform* transform = new Qt3DCore::QTransform;
// transform->setScale3D(QVector3D(1.5, 1, 0.5));
transform->setRotation(QQuaternion::fromAxisAndAngle(QVector3D(1,0,0), 45.f ));
Qt3DRender::QMaterial* material = new Qt3DExtras::QPhongMaterial(root);
torus->addComponent(mesh);
torus->addComponent(transform);
torus->addComponent(material);
return root;
}
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
Qt3DExtras::Qt3DWindow view;
Qt3DCore::QEntity* scene = createTestScene();
// camera
Qt3DRender::QCamera *camera = view.camera();
camera->lens()->setPerspectiveProjection(45.0f, 16.0f/9.0f, 0.1f, 1000.0f);
camera->setPosition(QVector3D(0, 0, 40.0f));
camera->setViewCenter(QVector3D(0, 0, 0));
// manipulator
Qt3DExtras::QOrbitCameraController* manipulator = new Qt3DExtras::QOrbitCameraController(scene);
manipulator->setLinearSpeed(50.f);
manipulator->setLookSpeed(180.f);
manipulator->setCamera(camera);
view.setRootEntity(scene);
view.show();
return app.exec();
}
With the above I can load obj files but there are two problems.
I can Pan and zoom the model, however I cannot rotate using my mouse or trackpad. How can I add that functionality.
My obj files have different colours in them. With this code what I see is only black in. the entire model. In other obj viewers I can see multiple colours.
you need to look on the sceneloader function in Qt for such loading process.
i mean with mtl fui
I'm working on UI using QT. The ui is simple, it's app based like IPhone or Android. Say there are 9 items (3 rows x 3 cols).
What I want to do is to navigate between widgets using arrow keys.
If the focus is in [row 1,col 1] and I press down arrow, I want it to go to [row 2, col 1]
another example.
If the focus is in [row 2,col 3] and I press up arrow, I want it to go to [row 1, col 3]
But the current behavior is up and right always go to next widget and down and left always go to previous widget.
Is there any way to do this in qt? or I need to create some algorithm to do this?
Thanks
UPDATE: See amazing example at the end.
Basic Widget focus navigation starts out with this:
http://qt-project.org/doc/qt-4.8/focus.html
Arrow navigation is available easily with a QTableView:
http://qt-project.org/doc/qt-4.8/qtableview.html#navigation
If you can get your widgets to work inside the structure of a QTableView, then you don't need to implement it, it comes as a part of the wrapper/view widget.
http://qt-project.org/doc/qt-4.8/qtablewidget.html#details
http://qt-project.org/doc/qt-4.8/model-view-programming.html
Model View programming does have a learning curve, but it is worth while to learn and use.
But this is by no means the only way to accomplish this.
There are event filters, key events, focus events that can be leveraged to accomplish this feat without using a QTableView or QTableWidget. But figuring out the best way to do it without making it look messy may take some time.
http://qt-project.org/doc/qt-4.8/qcoreapplication.html#notify
http://doc.qt.digia.com/qq/qq11-events.html
http://qt-project.org/doc/qt-4.8/eventsandfilters.html
http://qt-project.org/doc/qt-4.8/qkeyevent.html#details
http://qt-project.org/doc/qt-4.8/qfocusevent.html
Key events are set to the item with the focus, and if they ignore the event it propagates up to its parent. So as long as your items in your table/grid ignore the key events having to do with the arrow keys, then you could have your parent widget listen for the key events and handle them appropriately.
http://qt-project.org/doc/qt-4.8/qt.html#Key-enum
http://qt-project.org/doc/qt-4.8/qt.html#FocusReason-enum
http://qt-project.org/doc/qt-4.8/qwidget.html#setFocus
http://qt-project.org/doc/qt-4.8/qapplication.html#focusWidget
Hope that helps.
EDIT: Fully working example in QGraphicsView of what you want to do:
Qt Creator > Welcome tab > Examples > Pad Navigator Example
http://qt-project.org/doc/qt-4.8/graphicsview-padnavigator.html
Here is the relevant code from the example:
// Enable key navigation using state transitions
for (int y = 0; y < rows; ++y) {
for (int x = 0; x < columns; ++x) {
QState *state = stateGrid[y][x];
QKeyEventTransition *rightTransition = new QKeyEventTransition(this, QEvent::KeyPress,
Qt::Key_Right, state);
QKeyEventTransition *leftTransition = new QKeyEventTransition(this, QEvent::KeyPress,
Qt::Key_Left, state);
QKeyEventTransition *downTransition = new QKeyEventTransition(this, QEvent::KeyPress,
Qt::Key_Down, state);
QKeyEventTransition *upTransition = new QKeyEventTransition(this, QEvent::KeyPress,
Qt::Key_Up, state);
rightTransition->setTargetState(stateGrid[y][(x + 1) % columns]);
leftTransition->setTargetState(stateGrid[y][((x - 1) + columns) % columns]);
downTransition->setTargetState(stateGrid[(y + 1) % rows][x]);
upTransition->setTargetState(stateGrid[((y - 1) + rows) % rows][x]);
EDIT:
Amazing example using QShortcuts and a QGridLayout and a bunch of QPushButtons:
widget.cpp
#include "widget.h"
#include <QPushButton>
#include <QApplication>
#include <QShortcut>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
m_grid = new QGridLayout;
for(int r = 0; r < 10; r++)
{
for(int c = 0; c < 10; c++)
{
m_grid->addWidget(new QPushButton("Row " + QString::number(r)
+ ", Col " + QString::number(c)),
r, c);
}
}
this->setLayout(m_grid);
m_grid->itemAtPosition(1, 1)->widget()->setFocus();
this->setStyleSheet("QPushButton::focus{ background: black; color: white;}");
// only works for in Qt for Embedded Linux, Symbian and Windows CE only.
// QApplication::setNavigationMode(Qt::NavigationModeKeypadDirectional);
QShortcut * shortcut;
shortcut = new QShortcut(QKeySequence(Qt::Key_Up),this,
SLOT(on_up()));
shortcut = new QShortcut(QKeySequence(Qt::Key_Down),this,
SLOT(on_down()));
shortcut = new QShortcut(QKeySequence(Qt::Key_Left),this,
SLOT(on_left()));
shortcut = new QShortcut(QKeySequence(Qt::Key_Right),this,
SLOT(on_right()));
}
void Widget::on_up()
{
moveFocus(0, -1);
}
void Widget::on_down()
{
moveFocus(0, 1);
}
void Widget::on_left()
{
moveFocus(-1, 0);
}
void Widget::on_right()
{
moveFocus(1, 0);
}
void Widget::moveFocus(int dx, int dy)
{
if(qApp->focusWidget() == 0)
return;
int idx = m_grid->indexOf(qApp->focusWidget());
if(idx == -1)
return;
int r, c, rowSpan, colSpan;
m_grid->getItemPosition(idx, &r, &c, &rowSpan, &colSpan);
QLayoutItem* layoutItem = m_grid->itemAtPosition(r + dy, c + dx);
if(layoutItem == 0)
return;
layoutItem->widget()->setFocus();
}
Widget::~Widget()
{
}
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QGridLayout>
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = 0);
~Widget();
QGridLayout * m_grid;
public slots:
void on_up();
void on_down();
void on_left();
void on_right();
void moveFocus(int dx, int dy);
};
#endif // WIDGET_H
main.cpp
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
To enable keypad navigation, build Qt with QT_KEYPAD_NAVIGATION defined.
https://het.as.utexas.edu/HET/Software/html/qapplication.html#keypadNavigationEnabled
I'd like to create a rotating circle drawn with a Qt:DotLine pen, using the Graphics View Framework. Using QGraphicsItemAnimation, I can rotate other shapes but not the circle. The program below demonstrates the problem: instead of the rectangle and the circle rotating together, the circle jerks around while the rectangle rotates gracefully.
#include <QApplication>
#include <QGraphicsView>
#include <QGraphicsItem>
#include <QTimeLine>
#include <QGraphicsItemAnimation>
QRectF rect (int r)
{
return QRectF (-r, -r, r * 2, r * 2);
}
void setupRot (QTimeLine *timeline, QGraphicsItem *item)
{
QGraphicsItemAnimation *animation = new QGraphicsItemAnimation;
animation->setItem(item);
animation->setTimeLine(timeline);
animation->setRotationAt (1, 360);
QObject::connect (timeline, SIGNAL(finished()), animation, SLOT(deleteLater()));
}
int main(int argc, char *argv[])
{
QApplication app (argc, argv);
QGraphicsScene scene;
QTimeLine *timeline = new QTimeLine;
timeline->setDuration (3000);
timeline->setCurveShape (QTimeLine::LinearCurve);
QObject::connect (timeline, SIGNAL(finished()), timeline, SLOT(deleteLater()));
setupRot (timeline, scene.addEllipse (rect (50), QPen (QBrush (QColor ("blue")), 8, Qt::DotLine)));
setupRot (timeline, scene.addRect (rect (60)));
scene.addEllipse (rect (40), QPen (QBrush (QColor ("red")), 8));
scene.setSceneRect (-100, -100, 200, 200);
QGraphicsView view (&scene);
view.show ();
timeline->setLoopCount (0);
timeline->start();
return app.exec ();
}
p.s.: I've found some sample code on the web where people are creating intermediate animation steps manually, like this:
const int steps = 100;
for (int i = 0; i < steps; ++i)
animation->setRotationAt (i / (float)steps, 360 / (float)steps * i);
Is this just a sign of people not understanding the concept of interpolation, or is there some advantage of setting (seemingly superfluous) control points?
Which version/platform? If I run your code as is (or slowed down 2x), the dotted circle rotation looks as good as the rectangle in Windows with Qt 4.7.