When to use Qt graphics floating point classes? - qt

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.

Related

How do I convert a signed 8-byte integer to normalised float? [duplicate]

I try to optimize a working compute shader. Its purpose is to create an image: find the good color (using a little palette), and call imageStore(image, ivec2, vec4).
The colors are indexed, in an array of uint, in an UniformBuffer.
One color in this UBO is packed inside one uint, as {0-255, 0-255, 0-255, 0-255}.
Here the code:
struct Entry
{
*some other data*
uint rgb;
};
layout(binding = 0) uniform SConfiguration
{
Entry materials[MATERIAL_COUNT];
} configuration;
void main()
{
Entry material = configuration.materials[currentMaterialId];
float r = (material.rgb >> 16) / 255.;
float g = ((material.rgb & G_MASK) >> 8) / 255.;
float b = (material.rgb & B_MASK) / 255.;
imageStore(outImage, ivec2(gl_GlobalInvocationID.xy), vec4(r, g, b, 0.0));
}
I would like to clean/optimize a bit, because this color conversion looks bad/useless in the shader (and should be precomputed). My question is:
Is it possible to directly pack a vec4(r, g, b, 0.0) inside the UBO, using 4 bytes (like a R8G8B8A8) ?
Is it possible to do it directly? No.
But GLSL does have a number of functions for packing/unpacking normalized values. In your case, you can pass the value as a single uint uniform, then use unpackUnorm4x8 to convert it to a vec4. So your code becomes:
vec4 color = unpackUnorm4x8(material.rgb);
This is, of course, a memory-vs-performance tradeoff. So if memory isn't an issue, you should probably just pass a vec4 (never use vec3) directly.
Is it possible to directly pack a vec4(r, g, b, 0.0) inside the UBO, using 4 bytes (like a R8G8B8A8) ?
There is no way to express this directly as 4 single byte values; there is no appropriate data type in the shader to allow you to do declare this as a byte type.
However, why do you think you need to? Just upload it as 4 floats - it's a uniform so it's not like you are replicating it thousands of times, so the additional size is unlikely to be a problem in practice.

Multipling Quaternions in Qt Quick 3D QML

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

Given 3 or more numbers or vectors, how do I interpolate between them based on a percentage?

I want to know the most basic math principles I need to interpolate a value between 3 or more other values, based on a linear percentage; as it would be applicable in programming.
For example, say I have "0", "100", "200", and I want the number that's at "50%". The math would then return something like "100" because 100 is at 50%.
Another example: I have 3 points somewhere in 3D space. If I do "75%" then the result would be a point that is exactly halfway between point 2 and 3, or if I do "25%" then it'll be half-way between 1 and 2.
Game engines like Unity use something like this for blending between multiple animations on a character, for another example.
What I've brainstormed so far is that I would somehow take the input value and find whatever the 2 neighboring "points" are closest to it (much harder in 3D or 2d space but manageable in 1d), then simply lerp between those two- but that requires me to figure out what percentage both of those points are at individually, and remap from "0 to 100%" to "A% to B%". I think it would work but It seems kind of complicated to me.
If possible, I'd like answers to include a C# example or language-agnostic psuitocode just so I can understand the math.
simple example for scalar float objects using piecewise linear interpolation:
int n=3; // number of your objects
float x[n]={ 0.5,2.0,10.0 }; // your objects
float get_object(float t) // linearly interpolate objects x[] based in parameter t = <0,1>, return value must be the same type as your objects
{
int ix;
float x0,x1; // the same type as your objects
// get segment ix and parameter t
t*=n; ix=floor(t); t-=ix;
// get closest known points x0,x1
x0=x[ix]; ix++;
if (ix<n) x1=x[ix]; else return x0;
// interpolate
return x0+(x1-x0)*t;
}
so if t=0 it returns first object in the x[] if it is t=1 is returns last and anything in between is linearly interpolated ... The idea is just to multiply our t by number of segments or point (depend on how you handle edge cases) which integer part of the result will give us index of closest 2 objects to our wanted one and then the fractional part of multiplied t will give us directly interpolation parameter in range <0,1> between the two closest points...
In case you objects are not with the same weight or are not uniformly sampled then you need to add interpolation with weights or use higher order polynomial (quadratic,cubic,...).
You can use this for "any" type T of objects you just have to implement operations T+T , T-T and T*float if they are not present.
If your gameObjects is at the same line try this code.
public Transform objStart;
public Transform objEnd;
public Transform square;
public float distance;
//percent .5 means 50%
[Range(0f,1f)]
public float percent;
public Vector3 distancePercentPosition;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
//get distance between two object
distance = Vector3.Magnitude(objEnd.position - objStart.position);
//get position based on percent;
distancePercentPosition = (objEnd.position - objStart.position).normalized * percent * distance;
square.position = objStart.position + distancePercentPosition;
}
once you get the position between lines you can now map your gameobject in each position based on percent.

how to color point cloud from image pixels?

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.

Usage of Map and Translate Functions in 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!

Resources