QwtPlot with equal axes and auto scale - c++

I'm developing a Qt5 application with QWidgets. I’m using QwtPlot from the Qwt-library for plotting live data in my tool. I'm setting my plot-axis to auto-scale via ui.qwtPlot->setAxisAutoScale(axis), because I want my plot to automatically adjust to the incoming data.
Now some clients are requesting the possibility, to have a plot with equally spaced axes x and y. I found QwtPlotRescaler, which seems to be the right thing for this purpose. I’ve successfully added it to my plot which now has equal axes if needed. (I can disable / enable this functionality by an additional button.)
However I noticed, that the auto-scale functionality is disabled, whenever I activate equal axes. With my dynamically incoming data, I would still like to have a rescaling plot. The axes should be automatically growing and shrinking, whenever the contents (items in the plot) change. So just like the normal autoscaling, but keeping the axes equal in the meantime. How can I archive this?
Do you need any additional information?
Thanks for your help!

Let's say your y axis should depend on the x axis, so that you always have a fixed aspect ratio for your coordinate system.
Then Qwt has to adjust the range of y axis and has to ignore the bounding interval of the data in y direction - there is no solution to do both.
What could be done is to add extra margins to the x axis, so that the range of the y axis grows according to the aspect ratio - finally including the bounding interval of the data. But finding good margins to achieve this is not implemented by QwtPlotRescaler.
But if it helps: all what the autoscaler does is to adjust the scales according to the boundingRect of the curves. You can also do this on your own, whenever you change your data.

Related

Inkscape: enlarge figure without creating distortions

(a) what I have, (b) what I get, (c) what I want
I have a simple vector graphic in Inkscape, which consists of a rectangle, filled points and stars. Since the axis ranges are not really nice (the height equals approximatly 3 times the width of the picture) for a publication, I want to rescale the picture. However, I do not have the raw data, such that I can plot it again. How can I rescale my graphic (see figure (a)), such that the x-range is more wide (see figure (c)) without getting distortions (see figure (b))? In the end I want to create a PDF file out of it.
Any ideas on that?
Thanks for your help.
You can try to do it in 2 steps, using the Object -> Transform tool (Shift-Ctrl-M).
First, select everything, and with the transform tool select the Scale tab, and scale horizontally by, say, 300%. All figures will be distorted.
Now, unselect the rectangle, and scale horizontally again by 33.3%, but first click on Apply to each object separately. This will undo the distortion (but not the translation) of each object.
Note that 300% followed by 33.3% should leave the individual objects with the same size.
Documentation here.

Qt 3D scatter graph: how can I adjust the scale of an axis?

I'm currently developing a Qt desktop application using the Q3DScatter class. I'm inspecting Qt's 3D Scatter example project and I tried to modify the data item set to plot my own data. The data is plotted except that one axis is not well scaled and my 3D plot looks really messy. I'm looking for a way to adjust this axis. I've tried to change the range and the segment count of the axis, I even tried to set the "AutoAdjustRange" of the axis to true, but nothing seemed to solve the problem.
Would really appreciate some help.
PS: Here's a screen capture of what my 3D scatter graph looks like (the "messy" axis is shown with the red arrow)
I figured this out by creating a CustomFormatter class by subclassing QValue3DAxisFormatter and reimplementing some of its functions (I followed this tutorial). Then I set up my axis formatter to my custom formatter (m_graph->axisZ()->setFormatter(cf);).
Subclassing QValue3DAxisFormatter will not work: it determines where ticks and labels are placed, but not how large the axex actually are.
To do that, you can set the (horizontal) aspect ratio, that is a property of Q3DScatter. The following settings will make the data into a cube volume:
plot->setAspectRatio(1.0);
plot->setHorizontalAspectRatio(1.0);

Tracking circular mouse movement in OpenGL

I am working on a simple mesh viewer implementation in C++ with basic functionality such as translation, rotation, scaling.
I'm stuck with with implementing the rotation of the object along z-axis using the mouse. What I want to implement is the following:
Click and drag the mouse vertically (almost vertical will do, as I use a simple threshold to filter slight deviations along the horizontal axis) to rotate the object along y-axis (this part is done).
Click and drag the mouse horizontally just as described above to rotate the object along x-axis (this part is done too).
For z-axis rotation, I want to detect a circular (or along an arc) mouse movement. I'm stuck with this part, and don't know how to implement this.
For the above two, i just use atan2() to determine the angle of movement. But how do I detect circular movements?
The only way to deal with this is to have a delay between the user starting to make the motion and the object rotating:
When user clicks and begins to move the mouse you need to determine if its going to become a straight line movement, or a circular one. This will require a certain amount of data to be collected before that judgement can be made.
The most extreme case would be requiring the user to make one complete circle first, then the rotation begins (in reality you could do much better than this). Just how small you are able to cut this period down to will depend on a) how precise you dictate your users actions must be, and b) how good you are with pattern recognition algorithms.
To get you started heres an outline of an extremely poor algorithm:
On user click store the x and y coordinates.
Every 1/10 of a second store the new coordinates and process_for_pattern.
in process_for_pattern you're looking for:
A period where the x coordinates and the y coordinates regularly both increase, both decrease, or one increases and one decreases. Over time if this pattern changes such that either the x or the y begins to reverse whilst the other continues as it was, then at that moment you can be fairly sure you've got a circle.
This algorithm would require the user to draw a quarter circle before it was detected, and it does not account for size, direction, or largely irregular movements.
If you really want to continue with this method you can get a much better algorithm, but you might want to reconsider your control method.
Perhaps, you should define a screen region (e.g. at window boundaries), which, when was clicked, will initiate arc movement - or use some other modifier, a button or whatever.
Then at a mouse click you capture the coordinates and center of rotation (mesh axis) in 2D screen space. This gets you a vector (mesh center, button down pos)
On every mouse move you calculate a new vector (mesh center, mouse pos) and the angle between the two vectors is the angle of rotation.
I don't think it works like that...
You could convert mouse wheel rotation to z-axis, or use quaternion camera orientation, which is able to rotate along every axis almost intuitively...
The opposite is true for quarternion camera: if one tries to rotate the mesh along a straight line, the mesh appears to rotate slightly around some other weird axis -- and to compensate that, one intuitively tries to follow some slightly curved trajectory.
It's not exactly what you want, but should come close enough.
Choose a circular region within which your movements numbered 1 and 2 work as described (in the picture this would be some region that is smaller than the red circle. However, when the user clicks outside the circular region, you save the initial click position (shown in green). This defines a point which has a certain angle relative to the x-axis of your screen (you can find this easily with some trig), and it also defines the radius of the circle on which the user is working (in red). The release of the mouse adds a second point (blue). You then find the angle this point has relative to the center of the screen and the x-axis (just like before). You then project that angle onto your circle with the radius determined by the first click. The dark red arc defines the amount of rotation of the model.
This should be enough to get you started.
That will not be a good input method, I think. Because you will always need some travel distance to discriminate between a line and a curve, which means some input delay. Here is an alternative:
Only vertical mouse having their line crossing the center of the screen are considered vertical. Same for horizontal. In other cases it's considered a rotation, and to calculate its amplitude, calculate the angle between the last mouse location and the current location relatively to the center of the screen.
Alternatively you could use the center of the selected mesh if your application works like that.
You can't detect the "circular, along an arc" mouse movement with anywhere near the precision needed for 3d model viewing. What you want is something like this: http://thetechartist.com/?p=80
You nominate an axis (x, y, or z) using either keyboard shortcuts or on-screen axis indicators that you can grab with the mouse.
This will be much more precise than trying to detect an "arc" gesture. Any "arc" recognition would necessarily involve a delay while you accumulate enough mouse samples to decide whether an arc gesture has begun or not. Gesture recognition like this is non-trivial (I've done some gesture work with the Wii-mote). Similarly, even your simple "vertical" and "horizontal" mouse movement detection will require a delay for the same reason. Any "simple threshold to filter slight deviations" will make it feel dampened and weird.
For 3d viewing you want 1:1 mouse responsiveness, and that means just explicitly nominating an axis with a shortcut key or UI etc. For x-axis rotation, just restrict it to mouse x, y-axis to mouse y if you like. For z you could similarly restrict to x or y mouse input, or just take the total 2d mouse distance travelled. It depends what feels nicest to you.
As an alternative, you could try coding up support for a 3D mouse like the 3dConnexion SpaceExplorer.

Plotting a graph with given double coordinates

I receive an array of coordinates (double coordinates with -infinity < x < +infinity and 0 <= y <= 10) and want to draw a polyline using those points. I want the graph to always begin on the left border of my image, and end at the right. The bottom border of my image always represents a 0 y-value, and the top border always a 10 y-value. The width and height of the image that is created are decided by the user at runtime.
I want to realize this using Qt, and QImage in combination with QPainter seem to be my primary weapons of choice. The problem I am currently trying to solve is:
How to convert my coordinates to pixels in my image?
The y-values seem to be fairly simple, since I know the minimum and maximum of the graph beforehand, but I am struggling with the x-values. My approach so far is to find the min- and max-x-value and scale each point respectively.
Is there a more native approach?
Since one set of coordinates serves for several images with different widths and heights, I wondered whether a vector graphic (svg) may be a more suitable approach, but I couldn't find material on creating svg-files within Qt yet, just working with existing files. I would be looking for something comparable to the Windows metafiles.
Is there a close match to metafiles in Qt?
QGraphicsScene may help in this case. You plot the graph with either addPolygon() or addPath(). Then render the scene into a bitmap with QGraphicsScene::render()
The sceneRect will automatically grow as you add items to it. At the end of the "plotting" you will get the final size/bounds of the graph. Create a QImage and use it as the painter back store to render the scene.
QGraphicsScene also allows you to manipulate the transformation matrix to fit the orientation and scale to your need.
Another alternative to use QtOpenGL to render your 2d graph to a openGL context. No conversion/scaling of coordinates is required. Once you get past the opengl basics you can pick appropriate viewPort / eye parameters to achieve any zoom/pan level.

How to use and set axes in a 3D scene

I'm creating a simulator coded in python and based on ODE (Open Dynamics Engine). For visualization I chose VTK.
For every object in the simulation, I create a corresponding source (e.g. vtkCubeSource), mapper and actor. I am able to show objects correctly and update them as the simulation runs.
I want to add axes to have a point of reference and to show the direction of each axis. Doing that I realized that, by default, X and Z are in the plane of the screen and Y points outwards. In my program I have a different convention.
I've been able to display axes in 2 ways:
1) Image
axes = vtk.vtkAxes()
axesMapper = vtk.vtkPolyDataMapper()
axesMapper.SetInputConnection(axes.GetOutputPort())
axesActor = vtk.vtkActor()
axesActor.SetMapper(axesMapper)
axesActor.GetProperty().SetLineWidth(4)
2) Image (colors do not match with the first case)
axesActor = vtk.vtkAxesActor()
axesActor.AxisLabelsOn()
axesActor.SetShaftTypeToCylinder()
axesActor.SetCylinderRadius(0.05)
In the second one, the user is allowed to set many parameters related to how the axis are displayed. In the first one, I only managed to set the line width but nothing else.
So, my questions are:
Which is the correct way to define and display axes in a 3D scene? I just want them in a fixed position and orientation.
How can I set a different convention for the axes orientation, both for their display and the general visualization?
Well, if you do not mess with objects' transformation matrix for display
purposes, it could probably be sufficient to just put your camera into a
different position while using axes approach 2. The easy methods to adjust
your camera position are: Pitch(), Azimuth() and Roll().
If you mess with object transforms, then apply the same transform to the
axes.
Dženan Zukić kindly answered this question in vtkusers#vtk.org mail list.
http://www.vtk.org/pipermail/vtkusers/2011-November/119990.html