Qt How to draw a parallel double line bezier curve in QML - qt

I am trying to draw a parallel double line Bezier curve in QML as below, how may I do so?
parallel double line curve

I think you can just draw two curves with this API with a slight shift. There is not anything specific about "double curves" other than drawing two curves with a shift.
ctx.strokeStyle = Qt.rgba(0, 0, 0, 1);
ctx.lineWidth = 1;
ctx.beginPath();
ctx.moveTo(20, 0);//start point
ctx.bezierCurveTo(-10, 90, 210, 90, 180, 0);
ctx.stroke();
You will need to sort out the specifics, (cp1x, cp1y) and (cp2x, cp2y), to have the shape you want, but this seems to be the way to draw Bézier curves.

Related

CW arc with JavaFX arcTo() or similar function

Is there a easy way to paint an cw arc with JavaFX arcTo() or similar function?
gc.setFill(Color.LIGHTGRAY);
gc.fillRect(0, 0, 200, 200);
gc.beginPath();
gc.moveTo(20,20);
// CCW arc
gc.arcTo(lastPos[0], lastPos[1], newPos[0], newPos[1], Math.sqrt(offset[0]*offset[0]+offset[1]*offset[1]));
gcGCodeVis.stroke();
gcGCodeVis.closePath();
I tried with following code, but it didn't work correct:
// CW arc
gc.moveTo(newPos[0], newPos[1]);
gc.arcTo(newPos[0]+offset[0], newPos[1]+offset[1], lastPos[0], lastPos[1], Math.sqrt(offset[0]*offset[0]+offset[1]*offset[1]));
gc.moveTo(newPos[0], newPos[1]);

THREE.js: Why is my object flipping whilst travelling along a spline?

Following up from my original post Three.JS Object following a spline path - rotation / tangent issues & constant speed issue, I am still having the issue that the object flips at certain points along the path.
View this happening on this fiddle: http://jsfiddle.net/jayfield1979/T2t59/7/
function moveBox() {
if (counter <= 1) {
box.position.x = spline.getPointAt(counter).x;
box.position.y = spline.getPointAt(counter).y;
tangent = spline.getTangentAt(counter).normalize();
axis.cross(up, tangent).normalize();
var radians = Math.acos(up.dot(tangent));
box.quaternion.setFromAxisAngle(axis, radians);
counter += 0.005
} else {
counter = 0;
}
}
The above code is what moves my objects along the defined spline path (an oval in this instance). It was mentioned by #WestLangley that: "Warning: cross product is not well-defined if the two vectors are parallel.".
As you can see, from the shape of the path, I am going to encounter a number of parallel vectors. Is there anything I can do to prevent this flipping from happening?
To answer the why question in the title. The reason its happening is that at some points on the curve the vector up (1,0,0) and the tangent are parallel. This means their cross product is zero and the construction of the quaternion fails.
You could follow WestLangley suggestion. You really want the up direction to be the normal to the plane the track is in.
Quaternion rotation is tricky to understand the setFromAxisAngle function rotates around the axis by a given angle.
If the track lies in the X-Y plane then we will want to rotate around the Z-axis. To find the angle use Math.atan2 to find the angle of the tangent
var angle = Math.atan2(tangent.y,tangent.x);
putting this together set
var ZZ = new THREE.Vector3( 0, 0, 1 );
and
tangent = spline.getTangentAt(counter).normalize();
var angle = Math.atan2(tangent.y,tangent.x);
box.quaternion.setFromAxisAngle(ZZ, angle);
If the track leaves the X-Y plane things will get trickier.

Gothic pointed arch css or canvas

i wonder if someone knows a source or a way to design a Gothic pointed arch with css or canvas.
Edit:
My attempt was to style the canvas quadraticCurveTo method to fit the gothic arc. But I failed badly and had not the guts to post it here :)
var canvas = document.getElementById('arch');
var context = canvas.getContext('2d');
context.beginPath();
context.moveTo(188, 150);
context.quadraticCurveTo(288, -100, 388, 150);
context.lineWidth = 20
context.strokeStyle = 'black';
context.stroke();
http://jsfiddle.net/zumgugger/ZaqJ5/
Just because this is quirky and interesting....
Some geometry for a gothic pointed arch can be found here :
Perhaps the most recognizable feature of gothic architecture is the pointed arch. The basic gothic arch is equilateral in construction and forms the basis of many variants.
The construction of the equilateral arch is thus:
From the drawing, the compass is set to the span, a-b. With x-y as the springing line, the compass is positioned at the junction of a-x/y and a curve from x/y-q is draw as shown. The procedure is repeated with the compass placed at the junction of b-x/y, with the point at which the curves join forming the rise p-q. Drawing straight lines from a-x/y to q and b-x/y to q it can be shown that the resulting triangle is equilateral in construction with all angles being 60°.
http://www.stonecarvingcourses.com/the-geometry-of-gothic-architecture
I've put together a small fiddle that does this. http://jsfiddle.net/7c7Vc/1/
If my understanding is correct that means (and since I am not a mathematician I'll describe this in laymans terms) that you need to draw two arcs with the compass centered on points x and y respectively, from the opposite point on the x to y line to the intersect point q, given the distance between points x and y as the radius width for your compass.
In the example I use the arc method to do this, here is a sample that will draw the right hand side arc of the arch...
ctx.arc(0, archHeight, archWidth, 0, 1.5*Math.PI + _30degrees, true);
Explanation
We center the compass on point x :
ctx.arc(0, archHeight, archWidth, 0, 1.5*Math.PI + _30degrees, true);
-------------
Set the radius of our circle to be the width of the arch (the distance between point x and point y)
ctx.arc(0, archHeight, archWidth, 0, 1.5*Math.PI + _30degrees, true);
---------
Start drawing from the direction of 3'oclock (which happens to be 0 radians)
ctx.arc(0, archHeight, archWidth, 0, 1.5*Math.PI + _30degrees, true);
--
Draw the arc until we hit point q, which in terms of the arc we are drawing is 30 degrees short of the direction of 12'oclock (using local variable _30degrees which holds the equivalent value in radians) and radians : 1.5*Math.PI for the direction 12'oclock.
ctx.arc(0, archHeight, archWidth, 0, 1.5*Math.PI + _30degrees, true);
------------------------
And we want to draw this arc counter-clockwise
ctx.arc(0, archHeight, archWidth, 0, 1.5*Math.PI + _30degrees, true);
----
The reverse method is used for the other arc making up the arch, take a look at the example for this
Notes on the code:
It uses some patterns to set up a factory that will create your arch based on either height or width, the returned arch knows how to draw itself on a canvas and has been given it's calculated height and width by the factory. If you prefer not to use this pattern you can extract the calculation bits out and simplify it.

How to draw an arc with Qt?

Consider the following diagram:
I have information about the center point of both the lines, the angle in between, and the length of both the lines.
The issue is to draw an arc starting at the end of the bottom line and touching the above slanting line (the way shown below):
/
/
/
/.
/ .
/___.
I saw these arc drawing functions of Qt:
http://qt-project.org/doc/qt-5.1/qtgui/qpainter.html#drawArc
These functions need a rectangle as an argument where as I don't have any.
How should I use these functions to draw the arc as shown above?
QPointF O; // intersection of lines
QPointF B; // end point of horizontal line
QPointF A; // end point of other line
float halfSide = B.x-O.x;
QRectF rectangle(O.x - halfSide,
O.y - halfSide,
O.x + halfSide,
O.y + halfSide);
int startAngle = 0;
int spanAngle = (atan2(A.y-O.y,A.x-O.x) * 180 / M_PI) * 16;
QPainter painter(this);
painter.drawArc(rectangle, startAngle, spanAngle);
You have to calculate the boundary rectangle, than the angle between the lines using atan.

Aero: How to draw solid (opaque) colors on glass?

Using GDI+ to draw various colors:
brush = new SolidBrush(color);
graphics.FillRectangle(brush, x, y, width, height);
You'll notice that no opaque color shows properly on glass:
How do i draw solid colors on glass?
You'll also notice that a fully opaque color is handled differently depending on what color it is:
opaque black: fully transparent
opaque color: partially transparent
opaque white: fully opaque
Can anyone point me to the documentation on the desktop compositor that explains how different colors are handled?
Update 3
You'll also notice that FillRectangle behaves differently than FillEllipse:
FillEllipse with an opaque color draws an opaque color
FillRectangle with an opaque color draws partially (or fully) transparent
Explanation for non-sensical behavior please.
Update 4
Alwayslearning suggested i change the compositing mode. From MSDN:
CompositingMode Enumeration
The CompositingMode enumeration specifies how rendered colors are combined with background colors. This enumeration is used by the Graphics::GetCompositingMode and 'Graphics::SetCompositingMode' methods of the Graphics class.
CompositingModeSourceOver
Specifies that when a color is rendered, it is blended with the background color. The blend is determined by the alpha component of the color being rendered.
CompositingModeSourceCopy
Specifies that when a color is rendered, it overwrites the background color. This mode cannot be used along with TextRenderingHintClearTypeGridFit.
From the description of CompositingModeSourceCopy, it sounds like it's not the option i want. From the limitations it imposes, it sounds like the option i want. And with composition, or transparency disabled it isn't the option i want, since it performs a SourceCopy, rather than SourceBlend:
Fortunately it's not an evil i have to contemplate because it doesn't solve my actual issue. After constructing my graphics object, i tried changed the compositing mode:
graphics = new Graphics(hDC);
graphics.SetCompositingMode(CompositingModeSourceCopy); //CompositingModeSourceCopy = 1
The result has no effect on the output:
Notes
Win32 native
not .NET (i.e. native)
not Winforms (i.e. native)
GDI+ (i.e. native)
See also
Aero: How to draw ClearType text on glass?
Windows Aero: What color to paint to make “glass” appear?
Vista/7: How to get glass color?
Seems to work OK for me. With the lack of a full code example I'm assuming you've got your compositing mode wrong.
public void RenderGdiPlus()
{
List<string> colors = new List<string>(new string[] { "000000", "ff0000", "00ff00", "0000ff", "ffffff" });
List<string> alphas = new List<string>(new string[] { "00", "01", "40", "80", "c0", "fe", "ff" });
Bitmap bmp = new Bitmap(200, 300, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
Graphics graphics = Graphics.FromImage(bmp);
graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
graphics.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.None;
graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.None;
graphics.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceCopy;
graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
SolidBrush backBrush = new SolidBrush(Color.FromArgb(254, 131, 208, 129));
graphics.FillRectangle(backBrush, 0, 0, 300, 300);
graphics.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceOver;
Pen pen = new Pen(Color.Gray);
for (int row = 0; row < alphas.Count; row++)
{
string alpha = alphas[row];
for (int column=0; column<colors.Count; column++)
{
string color = "#" + alpha + colors[column];
SolidBrush brush = new SolidBrush(ColorTranslator.FromHtml(color));
graphics.DrawRectangle(pen, 40*column, 40*row, 32, 32);
graphics.FillRectangle(brush, 1+40*column, 1+40*row, 31, 31);
}
}
Graphics gr2 = Graphics.FromHwnd(this.Handle);
gr2.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceCopy;
gr2.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
gr2.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.None;
gr2.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.None;
gr2.DrawImage(bmp, 0, 0);
}
I had a similar issue, but it involved drawing onto a layered window, rather than on Aero's glass. I haven't got any code with which I can test whether this solves your problem, but I figured it's worth a shot, since the symptoms of your problem are the same as mine.
As you have noticed, there seems to be some qwerks with FillRectangle, apparent by the differences between its behaviour and FillEllipse's.
Here are two work-arounds that I came up with, which each solve my issue:
Call FillRectangle twice
SolidBrush b(Color(254, 255, 0, 0));
gfx.FillRectangle(&b, Rect(0, 0, width, height));
gfx.FillRectangle(&b, Rect(0, 0, width, height));
Since the same area is being filled twice, they should blend and create RGB(255, 0, 0) regardless of the glass colour, which leads to a result of a 100% opaque shape. I do not prefer this method, as it requires every rectangle to be drawn twice.
Use FillPolygon instead
Just as with FillEllipse, FillPolygon doesn't seem to have the colour/opacity issue, unless you call it like so:
SolidBrush b(Color(255, 255, 0, 0));
Point points[4];
points[0] = Point(0, 0);
points[1] = Point(width, 0);
points[2] = Point(width, height);
points[4] = Point(0, height);
gfx.FillPolygon(&b, points, 4); //don't copy and paste - this won't work
For me, the above code resulted in a 100% transparent shape. I am guessing that this is either due to some form of optimisation that passes the call to FillRectangle instead. Or - most likely - there is some problem with FillPolygon, which is called by FillRectangle. Regardless, if you add an extra Point to the array, you can get around it:
SolidBrush b(Color(255, 255, 0, 0));
Point points[5];
points[0] = Point(0, 0);
points[1] = Point(0, 0); //<-
points[2] = Point(width, 0);
points[3] = Point(width, height);
points[4] = Point(0, height);
gfx.FillPolygon(&b, points, 5);
The above code indeed draws a 100% opaque shape for me. I hope this also resolves your issue.
Another day, another solution by me.
Draw everything you want to appear on glass into a bitmap.
Then, clear the form background with black color.
Immediately after this, draw the bitmap on your form.
However (as with any other solution not using DrawThemeTextEx):
Text rendering will not work correctly, because it always takes the back color of your form as an antialias/cleartype hint. Use DrawThemeTextEx instead, which also supports text with a glow effect behind.
I met the same issue with GDI.
GDI uses zero alpha channel value, so the simpliest solution is to fix alpha channel like this code does:
void fix_alpha_channel()
{
std::vector<COLORREF> pixels(cx * cy);
BITMAPINFOHEADER bmpInfo = {0};
bmpInfo.biSize = sizeof(bmpInfo);
bmpInfo.biWidth = cx;
bmpInfo.biHeight = -int(cy);
bmpInfo.biPlanes = 1;
bmpInfo.biBitCount = 32;
bmpInfo.biCompression = BI_RGB;
GetDIBits(memDc, hBmp, 0, cy, &pixels[0], (LPBITMAPINFO)&bmpInfo, DIB_RGB_COLORS);
std::for_each(pixels.begin(), pixels.end(), [](COLORREF& pixel){
if(pixel != 0) // black pixels stay transparent
pixel |= 0xFF000000; // set alpha channel to 100%
});
SetDIBits(memDc, hBmp, 0, cy, &pixels[0], (LPBITMAPINFO)&bmpInfo, DIB_RGB_COLORS);
}
I've found another way around it. Use LinearGradientBrush with both colors the same:
LinearGradientBrush brush(Point(0,0), Point(0,0), Color(255,231,45,56), Color(255,231,45,56));
g.FillRectangle(&brush, 25, 25, 30, 30);
This is perhaps slower than SolidBrush, but works fine.
Do you want a stupid solution? Here you get a stupid solution. At least it's just one line of code. And causing a small but ignorable side effect.
Assumption
When drawing solid, right angle rectangles, GDI+ tends to speed things up by drawing them in a faster method than drawing other stuff. This technique is called bitbliting. That is actually pretty clever since it is the fastest way to draw rectangles on a surface. However, the rectangles to be drawn must fulfill the rule that they are right angled.
This clever optimization was done before there was DWM, Aero, Glass and all the new fancy stuff.
Internally, bitblitting just copies the RGBA color data of pixels from one memory area to another (so to say from your drawing on your window). Sadly enough, the RGB format it writes is incompatible with glass areas, resulting in the weird transparency effects you observed.
Solution
So here comes a twist.
GDI+ can respect a transformation matrix, with which every drawing can be scaled, skewed, rotated or whatever. If we apply such a matrix, the rule that rectangles are right angled anymore is not guaranteed anymore. So, GDI+ will stop bitblitting these and draw them in a fashion similar to the ellipses.
But we also don't want to skew, scale or rotate our drawing. We simply apply the smallest transformation possible: We create a transformation matrix which moves every drawing down one pixel:
// If you don't get that matrix instance, ignore it, it's just boring math
e.Graphics.Transform = new Matrix(1f, 0.001f, 0f, 1f, 0f, 0f);
Now, bitblitting is off, rectangles are solid, violets are blue. If there would be just an easier way to control that, especially one not moving the drawings!
Thus said, if you want to draw on the first pixel row, use -1 as a Y coordinate.
You can decide if this really is a solution for you, or just ignore it.

Resources