Using Qt Quick 3D QML and without having additional C++, how could I multiply two quaternions?
I have a fixed rotation value given in quaternion (Qt.quaternion(a,b,c)), to which I would like to add a variable part.
Documentation is very scarce about that (I only found quaternion and Transform) and apparently there is no "times()" property similar to the one from vector. On the C++ side, I can multiply and normalize quaternions (QQuaternion)
I would recommend writing your own JavaScript function doing the multiplication. One example implementation (multiplyQuaternion()) can be seen in this answer to another question.
You can also take a look into implementation of inline const QQuaternion operator*(const QQuaternion &q1, const QQuaternion& q2) in QQuaternion class for reference when writing your own JS function.
Another possibility might be to utilize some ready-made JS implementation (if found) by importing a JS file in question into your QML.
You could also write QObject-based C++ wrapper which utilizes QQuaternion class and then expose it to QML. But you would have to link with Qt Gui module and write quite a lot of boilerplate code because of that one function which probably doesn't make too much sense.
In Qt6, there are many useful methods on quaternion for multiplying with another quaternion, vector, or scalar values.
var a = Qt.quaternion(1 / Math.sqrt(2), 1 / Math.sqrt(2), 0, 0);
var b = Qt.quaternion(1 / Math.sqrt(2), 0, 1 / Math.sqrt(2), 0);
var c = b.times(a);
console.log(c.toString()); // QQuaternion(0.5, 0.5, 0.5, -0.5)
var a = Qt.quaternion(0.5,0.5,0.5,-0.5);
var b = Qt.vector3d(4,5,6);
var c = a.times(b);
console.log(c.toString()); // QVector3D(5, -6, -4)
var a = Qt.quaternion(1,2,3,4);
var b = 4.48;
var c = a.times(b);
console.log(c.toString()); // QQuaternion(4.48, 8.96, 13.44, 17.92)
See https://doc.qt.io/qt-6/qml-quaternion.html
Related
Qt has a set of graphical classes that come in 2 variants: with integer precision and floating point precision.
These are the ones I can remember
| QLine | QLineF |
| QMargins | QMarginsF |
| QPoint | QPointF |
| QRect | QRectF |
| QSize | QSizeF |
Apart from the obvious difference, that one uses integers and the other uses floats, as stated in their names and in the official documentation, I have quite a few doubts...
What are the use cases for one family of classes and the other?
Positions and sizes bigger than their integer counterpart?
Fractional values?
Does it make a difference when drawing?
Are plots smoother if I use QLineF instead of QLine?
While those classes are often interchangeable and have almost the same implementations, there are peculiar differences in their usage and result.
Integer based classes are mostly used for screen coordinates (widget positions, sizes, etc), which is normally considered based on pixel units (which are obviously integers).
There are important differences when dealing with positioning/collision and drawing, though.
Consider the following:
>>> p = QtCore.QPoint(1, 1)
>>> r = QtCore.QRect(0, 0, 1, 1)
>>> print(r.contains(p))
False
>>> r = QtCore.QRectF(0, 0, 1, 1)
>>> print(r.contains(p))
True
This is because QRect considers only the integer ("pixel") size, and obviously (1, 1) is on "another pixel".
QRect is also peculiar for the right() and bottom() functions, because (as explained in the documentation) they always return left+width-1 and top+height-1 for historical reasons:
>>> r = QtCore.QRect(0, 0, 1, 1)
>>> print(r.right())
0
In light of this, always keep in mind that the same works for the setters of those coordinates (both set* and move*):
>>> r.setRight(1)
>>> print(r)
PyQt5.QtCore.QRect(0, 0, 2, 1)
>>> r.moveRight(0)
>>> print(r)
PyQt5.QtCore.QRect(-1, 0, 2, 1)
Floating point classes also have features not available to integer based ones (mostly because it wouldn't be possible/useful/reasonable to implement them).
For example, the QLineF class:
can return an intersection point with another QLineF (or the intersection of their extension);
has functions to get and set the angle of the line itself (from its p1 starting point), or the angle created with another line (or, better, their extensions, if they don't intersect) [1];
can be created from a polar, given a length and an angle;
Floating point classes allow more precise drawing and positioning, which are important aspects when you need antialiased painting or you're dealing with content that can be scaled or is based on proportional values (consider a magnified QGraphicsScene, or text displaying since fonts are vector based).
For instance, the following will give you very different results:
painter.setRenderHints(painter.Antialiasing)
painter.drawRect(QtCore.QRect(1, 1, 2, 2))
painter.drawRect(QtCore.QRectF(1, 1, 2.5, 2.5))
Then, it's important to remember that all simple drawing functions of QPainter that accept numeric values as main parameters will always use integer values (I believe that's due to Python's dynamic typing, as C++ functions only accept signed integers):
painter.drawRect(0.5, 0.5, 5.5, 5.5)
# same as:
painter.drawRect(0, 0, 5, 5)
# so you should use:
painter.drawRect(QtCore.QRectF(0.5, 0.5, 5.5, 5.5))
Finally, while Qt (and Python) sometimes allows transparent usage of both types, in general one or the other is strictly required:
all widget geometry related functions only accept integer classes (setGeometry(QRect), resize(QSize), etc.);
the same goes for function overrides that must return geometry values, such as sizeHint(), the SizeHintRole of an item model, rectangles returned by a QStyle subclass or set for a QStyleOption;
QRegion can only accept QPolygon and QRect, since it's a pixel mapped object;
QGraphicsRectItem, QGraphicsEllipseItem and QGraphicsPolygonItem only allow floating point classes in their constructors or setters;
complex constructors use classes of their precision type (QRect won't accept QPointF or QSizeF, etc.);
all functions that map QGraphicsScene coordinates must use integer classes when mapping to the scene and floating point when from the scene;
Whenever you need a conversion from one type to the other, just use the constructor of the floating point class or the to[*] function it provides:
intRect = QtCore.QRect(0, 0, 10, 10)
floatRect = QtCore.QRectF(intRect)
newIntRect = floatRect.toRect()
intTopLeft = floatRect.topLeft().toPoint()
intSize = floatRect.size().toSize()
midRadiusLine = QtCore.QLineF.fromPolar(
intRect.width() * .5, 45).translated(floatRect.center())
intMidRadiusLine = midRadius.toLine()
[1] Be aware that setting angles outside the 0-360 range might give you unexpected results: line.setAngle(361) will result in a line.angle() equal to 0.9999999999999748 due to floating point "[im]precision" and the nature of Pi.
What is the best (in sense of performance and memory consumption) way to represent QR code graphically in Qt Quick application?
I think QR code bitmap can be represented graphically as square matrix of black and white cells using some shader. It would be performance-optimal solution.
Currently I can only create a GridView with a bunch of Rectangles. It is considered as a waste of memory to store and CPU/GPU time to render.
How may the shader looks like?
Say, given QBitArray of n*n size.
The shader itself would be trivial, basically you divide the fragment position x and y by the qr code size and floor that to get row and column, and then find the 1d index by adding the two, then lookup the qt data array at that index, if it contains a 0, the fragment color is white, if it contains 1, the color is black.
However, QML shaders currently don't provide facilities to pass regular 1d arrays.
You would have to convert the array to a bitmap image, and pass it to the array, which means you will also have to implement an image provider in order to get QImage to work with QML, because amazingly, it still doesn't by default.
I wouldn't bother about performance too much, that's premature optimization, which is bad in 99% of the cases. Even a trivial, 100% QML solution is sufficiently fast:
ApplicationWindow {
id: main
visible: true
width: 640
height: 480
color: "darkgray"
property var qrdata: []
MouseArea {
anchors.fill: parent
onClicked: {
qrdata = []
for (var i = 0; i < (100 * 100); ++i) qrdata.push(Math.round(Math.random()))
code.requestPaint()
}
}
Canvas {
id: code
width: 300
height: 300
onPaint: {
console.time("p")
var c = getContext("2d")
c.fillStyle = Qt.rgba(1, 1, 1, 1);
c.fillRect(0, 0, width, height)
c.fillStyle = Qt.rgba(0, 0, 0, 1);
var l = qrdata.length
var step = Math.sqrt(l)
var size = width / step
for (var i = 0; i < l; ++i) {
if (qrdata[i]) {
var rw = Math.floor(i / step), cl = i % step
c.fillRect(cl * size, rw * size, size, size)
}
}
console.timeEnd("p")
}
}
}
On my system, drawing a 100 x 100 qr code takes about 2 milliseconds. IMO that's sufficiently good and it is not really worth it to invest time into making are more complex low level solution.
However, what I would personally do is implement an image provider, convert the qr code data into an image, then scale that image as large as I want with smooth: false which will avoid blurring and preserve a crisp result. That is by far the most direct, efficient and straightforward solution.
If you've got just one QR code in the application then save your time and do a GridView.
Other options are:
C++ custom QQuickItem: generate and load a texture (Qt SceneGraph API)
C++ custom QQuickFramebufferObject: generate and load a texture (mostly pure OpenGL API)
C++ custom QQuickPaintedItem(QPainter 2D API)
QML-JS Canvas/Context2D (HTML 2D API)
QML-JS Canvas3D/Context3D: generate and load a texture (WebGL API) - like all other C++ options, but in JS version of OpenGL
C++ custom QQuickImageProvider: generate and load a texture (ImageProvider and OpenGL API) while passing the whole QR data as an image name to your custom QQuickImageProvider (maybe a bit too clever)
Using vertex-buffers/uniform-buffers instead of textures may work, but it needs an unusual shader code. QR fits more as a texture, I think.
I am using google tango tablet to acquire point cloud data and RGB camera images. I want to create 3D scan of the room. For that i need to map 2D image pixels to point cloud point. I will be doing this with a lot of point clouds and corresponding images.Thus I need to write a code script which has two inputs 1. point cloud and 2. image taken from the same point in same direction and the script should output colored point cloud. How should i approach this & which platforms will be very simple to use?
Here is the math to map a 3D point v to 2D pixel space in the camera image (assuming that v already incorporates the extrinsic camera position and orientation, see note at bottom*):
// Project to tangent space.
vec2 imageCoords = v.xy/v.z;
// Apply radial distortion.
float r2 = dot(imageCoords, imageCoords);
float r4 = r2*r2;
float r6 = r2*r4;
imageCoords *= 1.0 + k1*r2 + k2*r4 + k3*r6;
// Map to pixel space.
vec3 pixelCoords = cameraTransform*vec3(imageCoords, 1);
Where cameraTransform is the 3x3 matrix:
[ fx 0 cx ]
[ 0 fy cy ]
[ 0 0 1 ]
with fx, fy, cx, cy, k1, k2, k3 from TangoCameraIntrinsics.
pixelCoords is declared vec3 but is actually 2D in homogeneous coordinates. The third coordinate is always 1 and so can be ignored for practical purposes.
Note that if you want texture coordinates instead of pixel coordinates, that is just another linear transform that can be premultiplied onto cameraTransform ahead of time (as is any top-to-bottom vs. bottom-to-top scanline addressing).
As for what "platform" (which I loosely interpreted as "language") is simplest, the native API seems to be the most straightforward way to get your hands on camera pixels, though it appears people have also succeeded with Unity and Java.
* Points delivered by TangoXYZij already incorporate the depth camera extrinsic transform. Technically, because the current developer tablet shares the same hardware between depth and color image acquisition, you won't be able to get a color image that exactly matches unless both your device and your scene are stationary. Fortunately in practice, most applications can probably assume that neither the camera pose nor the scene changes enough in one frame time to significantly affect color lookup.
This answer is not original, it is simply meant as a convenience for Unity users who would like the correct answer, as provided by #rhashimoto, worked out for them. My contribution (hopefully) is providing code that reduces the normal 16 multiplies and 12 adds (given Unity only does 4x4 matrices) to 2 multiplies and 2 adds by dropping out all of the zero results. I ran a little under a million points through the test, checking each time that my calculations agreed with the basic matrix calculations - defined as the absolute difference between the two results being less than machine epsilon - I'm as comfortable with this as I can be knowing that #rhashimoto may show up and poke a giant hole in it :-)
If you want to switch back and forth, remember this is C#, so the USEMATRIXMATH define must appear at the beginning of the file.
Given there's only one Tango device right now, and I'm assuming the intrinsics are constant across all of the devices, I just dumped them in as constants, such that
fx = 1042.73999023438
fy = 1042.96997070313
cx = 637.273986816406
cy = 352.928985595703
k1 = 0.228532999753952
k2 = -0.663019001483917
k3 = 0.642908990383148
Yes they can be dumped in as constants, which would make things more readable, and C# is probably smart enough to optimize it out - however, I spent too much of my life in Agner Fogg's stuff, and will always be paranoid.
The commented out code at the bottom is for testing the difference, should you desire. You'll have to uncomment some other stuff, and comment out the returns if you want to test the results.
My thanks again to #rhashimoto, this is far far better than what I had
I have stayed true to his logic, remember these are pixel coordinates, not UV coordinates - he is correct that you can premultiply the transform to get normalized UV values, but since he schooled me on this once already, I will stick with exactly the math he presented before I fiddle with too much :-)
static public Vector2 PictureUV(Vector3 tangoDepthPoint)
{
Vector2 imageCoords = new Vector2(tangoDepthPoint.x / tangoDepthPoint.z, tangoDepthPoint.y / tangoDepthPoint.z);
float r2 = Vector2.Dot(imageCoords, imageCoords);
float r4 = r2*r2;
float r6 = r2*r4;
imageCoords *= 1.0f + 0.228532999753952f*r2 + -0.663019001483917f*r4 + 0.642908990383148f*r6;
Vector3 ic3 = new Vector3(imageCoords.x,imageCoords.y,1);
#if USEMATRIXMATH
Matrix4x4 cameraTransform = new Matrix4x4();
cameraTransform.SetRow(0,new Vector4(1042.73999023438f,0,637.273986816406f,0));
cameraTransform.SetRow(1, new Vector4(0, 1042.96997070313f, 352.928985595703f, 0));
cameraTransform.SetRow(2, new Vector4(0, 0, 1, 0));
cameraTransform.SetRow(3, new Vector4(0, 0, 0, 1));
Vector3 pixelCoords = cameraTransform * ic3;
return new Vector2(pixelCoords.x, pixelCoords.y);
#else
//float v1 = 1042.73999023438f * imageCoords.x + 637.273986816406f;
//float v2 = 1042.96997070313f * imageCoords.y + 352.928985595703f;
//float v3 = 1;
return new Vector2(1042.73999023438f * imageCoords.x + 637.273986816406f,1042.96997070313f * imageCoords.y + 352.928985595703);
#endif
//float dx = Math.Abs(v1 - pixelCoords.x);
//float dy = Math.Abs(v2 - pixelCoords.y);
//float dz = Math.Abs(v3 - pixelCoords.z);
//if (dx > float.Epsilon || dy > float.Epsilon || dz > float.Epsilon)
// UnityEngine.Debug.Log("Well, that didn't work");
//return new Vector2(v1, v2);
}
As one final note, do note the code he provided is GLSL - if you're just using this for pretty pictures, use it - this is for those that actually need to perform additional processing.
New to Processing working on understanding this code:
import com.onformative.leap.LeapMotionP5;
import java.util.*;
LeapMotionP5 leap;
LinkedList<Integer> values;
public void setup() {
size(800, 300);
frameRate(120); //Specifies the number of frames to be displayed every second
leap = new LeapMotionP5(this);
values = new LinkedList<Integer>();
stroke(255);
}
int lastY = 0;
public void draw() {
**translate(0, 180)**; //(x, y, z)
background(0);
if (values.size() >= width) {
values.removeFirst();
}
values.add((int) leap.getVelocity(leap.getHand(0)).y);
System.out.println((int) leap.getVelocity(leap.getHand(0)).y);
int counter = 0;
** for (Integer val : values)** {
**val = (int) map(val, 0, 1500, 0, height);**
line(counter, val, counter - 1, lastY);
point(counter, val);
lastY = val;
counter++;
}
** line(0, map(1300, 0, 1500, 0, height), width, map(1300, 0, 1500, 0, height)); //(x1, y1, x2, y2)**
}
It basically draw of graph of movement detected on the y axis using the Leap Motion sensor. Output looks like this:
I eventually need to do something similar to this that would detect amplitude instead of velocity simultaneously on all 3 axis instead of just the y.
The use of Map and Translate are whats really confusing me. I've read the definitions of these functions on the Processing website so I know what they are and the syntax, but what I dont understand is the why?! (which is arguably the most important part.
I am asking if someone can provide simple examples that explain the WHY behind using these 2 functions. For instance, given a program that needs to do A, B, and C, with data foo, y, and x, you would use Map or Translate because A, B, and C.
I think programming guides often overlook this important fact but to me it is very important to truly understanding a function.
Bonus points for explaining:
for (Integer val : values) and LinkedList<Integer> values; (cant find any documentation on the processing website for these)
Thanks!
First, we'll do the easiest one. LinkedList is a data structure similar to ArrayList, which you may be more familiar with. If not, then it's just a list of values (of the type between the angle braces, in this case integer) that you can insert and remove from. It's a bit complicated on the inside, but if it doesn't appear in the Processing documentation, it's a safe bet that it's built into Java itself (java documentation).
This line:
for (Integer val : values)
is called a "for-each" or "foreach" loop, which has plenty of very good explanation on the internet, but I'll give a brief explanation here. If you have some list (perhaps a LinkedList, perhaps an ArrayList, whatever) and want to do something with all the elements, you might do something like this:
for(int i = 0; i < values.size(); i++){
println(values.get(i)); //or whatever
println(values.get(i) * 2);
println(pow(values.get(i),3) - 2*pow(values.get(i),2) + values.get(i));
}
If you're doing a lot of manipulation with each element, it quickly gets tedious to write out values.get(i) each time. The solution would be to capture values.get(i) into some variable at the start of the loop and use that everywhere instead. However, this is not 100% elegant, so java has a built-in way to do this, which is the for-each loop. The code
for (Integer val : values){
//use val
}
is equivalent to
for(int i = 0; i < values.size(); i++){
int val = values.get(i);
//use val
}
Hopefully that makes sense.
map() takes a number in one linear system and maps it onto another linear system. Imagine if I were an evil professor and wanted to give students random grades from 0 to 100. I have a function that returns a random decimal between 0 and 1, so I can now do map(rand(),0,1,0,100); and it will convert the number for me! In this example, you could also just multiply by 100 and get the same result, but it is usually not so trivial. In this case, you have a sensor reading between 0 and 1500, but if you just plotted that value directly, sometimes it would go off the screen! So you have to scale it to an appropriate scale, which is what that does. 1500 is the max that the reading can be, and presumably we want the maximum graphing height to be at the edge of the screen.
I'm not familiar with your setup, but it looks like the readings can be negative, which means that they might get graphed off the screen, too. The better solution would be to map the readings from -1500,1500 to 0,height, but it looks like they chose to do it a different way. Whenever you call a drawing function in processing (eg point(x,y)), it draws the pixels at (x,y) offset from (0,0). Sometimes you don't want it to draw it relative to (0,0), so the translate() function allows you to change what it draws things relative against. In this case, translating allows you to plot some point (x,0) somewhere in the middle of the screen, rather than on the edge.
Hope that helps!
I'm porting an old awt java game to playn framework,
I've some graphics.copyArea calls..
there is some way to map this call into some play.core.Canvas calls ?
Thanks
You should be able to use the same canvas as the source and destination of a Canvas.drawImage call:
CanvasImage image = graphics().createImage(100, 100);
// draw stuff in your canvas image
// define the source of the copyArea: 15x15+5+5
float sx = 5, sy = 5, swidth = 15, sheight = 15;
// note that we use swidth/sheight for dwidth/dheight because we don't want to scale,
// we just want to copy data from one place in the image to another
image.canvas().drawImage(image, 25, 25, swidth, sheight, sx, sy, swidth, sheight);
However, if you're really rendering everything to a Canvas on every frame, you're probably going to discover that that's very slow. You'll be better off restructuring things to use ImageLayer and other constructs that can be hardware accelerated.