Manipulating a QGradient to follow a path - c++

I am using Qt to draw something that looks like a pipe which can curve and arc using a QPainterPath. I use a QLinearGradient to fill the pipe in order to give it a three dimensional look. What I can't figure out is how to curve/arc the pipe and have the gradient follow those same curves so that the 3D effect remains. Any thoughts?
In other words, the color stops on the QGradient need to rotate along with the curves in the path.

As far as i can see from qt examples the gradient with which you fill your path is all same. So you define a nice gradient, than a path and add the gradient to all your shape with a code like this:
QLinearGradient myGradient;
QPen myPen;
QPainterPath myPath;
myPath.cubicTo(c1, c2, endPoint);
QPainter painter(this);
painter.setBrush(myGradient);
painter.setPen(myPen);
painter.drawPath(myPath);
The hardest part is define a pipe that moves smootly...Could you share your code so we can see your problem?

Related

QChart and using QGradients with accelerated OpenGL rendering

What is going wrong:
Currently my chart works completely fine, it has gradients, and single colored series for example:
This works fine, but when I enable openGL acceleration (for more performance) on the 3 series using fooSeries->setUseOpenGL(true) the graph turns into this:
As you can see the color for the gradient series turn black, while the single colored series turns white. Also the Rounded Caps and Rounded Joins also seem to have gone. I did some experimentation to see what may be causing it.
Attemped fixes/experimentation:
I color the series as follows:
// fooGradient is a QLinearGradient described elsewhere as an example.
QBrush fooGradientPenBrush = QBrush(fooGradient);
fooPen = new QPen(fooGradientPenBrush, 5, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
//There are actually 2 QPens for two separate gradients in the program, but this is just for the example.
QBrush barPenBrush = QBrush(QRgb(0xFFFFFF));
barPen = new QPen(barPenBrush, 3, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
Then later attach these pens top their respective series:
fooSeries->setPen(*fooPen);
barSeries->setPen(*barPen);
Then they are attached to the chart. That's it. I will keep experimenting and looking at the documentation to see if I missed something, it may just be that the openGL acceleration only accepts solid colors, but it is said no where in the documentation that I can find. I'll leave a link to the setUseOpenGl documentation if anyone would like to take a look here.
After more research, I seemed to have missed an important detail in the documentation:
Pen styles and marker shapes are ignored for accelerated series. Only solid lines and plain scatter dots are supported. The scatter dots may be circular or rectangular, depending on the underlying graphics hardware and drivers.
I still wonder if there is a way to implement rounded corners and what not to accelerated lines.

Drawing on top of QImage using QPainter

I'm essentially trying to include an odometer in my application.For that, I want to display a PNG image of an odometer, and then draw a line to represent the needle.I have used QImage on a Qlabel to display the image, however, I can't seem to draw anything on it using QPainter.The following is my code:
QImage img(200,200,QImage::Format_ARGB32);
img.load("C:/meter.png");
QPainter paint(&img);
paint.begin(&img);
paint.setPen(Qt::blue);
paint.drawLine(0,0,500,1080);
paint.end();
ui->cont->setPixmap(QPixmap::fromImage(img));
ui->cont->show();
I am afraid it might have something to do with qts coordinate system.I know that origin is the top left of your screen and 1 pixel represents 1 increment in the coordinates, is there something I can do to get the location of a point on screen and shift the coordinates to it?

C++ and Qt: Paint Program - Rendering Transparent Lines Without Alpha Joint Overlap

I have started to create a paint program that interacts with drawing tablets. Depending on the pressure of the pen on the tablet I change the alpha value of the line being drawn. That mechanism works.
Thin lines look decent and it looks a real sketch. But since I am drawing lines between two points (like in the Qt scribble tutorial) to paint there is an alpha overlap between the line joints and it is very noticeable for thick strokes.
This is the effect with line to line conjuction:
As you can see, there is an ugly alpha blend between the line segments.
In order to solve this I decided to use a QPainterPath to render lines.
Two problems with this:
A long, continuous, thick path quickly lags the program.
Since the path is connected it acts as one, so any change to the alpha value affects the the entire path(which I don't want since I want to preserve a blending effect).
The following images use a QPainterPath.
The blend effect I want to keep.
The following image shows the 2nd problem which changes the alpha and thickness of the entire path
The red text should read: "if more pressure is added without removing the pen from the tablet surface the line thickens" (and alpha becomes opaque)
Another thing is that with this approach I can only get a blending trail from a dark to light (or thick to thin path width) but not light to dark. I am not sure why this effect occurs but my best guess is that it has to do with the line segments of the path updating as whole.
I did make the program increase/decrease alpha and line thickness based on the pressure of the pen on the tablet.
The problem is that I want to render lines without the alpha overlap and QPainterPath updates the entire path's alpha and thickness which I don't want.
This is the code that creates the path:
switch(event->type()){
case QEvent::TabletPress:
if(!onTablet){
onTablet = true;
//empty for new segment
freePainterPath();
path = new QPainterPath(event->pos());
} break;
case QEvent::TabletRelease:
if(onTablet)
onTablet = false;
break;
case QEvent::TabletMove:
if(path != NULL)
path->lineTo(event->pos());
if(onTablet){
//checks for pressure of pen on tablet to change alpha/line thickness
brushEffect(event);
QPainter painter(&pixmap);
//renders the path
paintPixmap(painter, event);
} break;
default:;
}
update();
The desired effect that I want as a single path (image created with Krita paint program):
To emulate the Krita paint program:
Keep a backup of the original target surface.
Paint with your brush onto a scratch surface that starts out completely transparent.
On that surface, your composting rule is "take maximum opacity".
Keep track of the dirty regions of that surface, and do a traditional composite of (scratch surface) onto (original target surface) and display the result. Make sure this operation doesn't damage the original target surface.
Now, you don't have to keep the entire original target surface -- just the parts you have drawn on with this tool. (A good tile based lazy-write imaging system will make this easy).
Depending on the segment size you are drawing with, you may want to interpolate between segments to make the strength of the brush be a bit less sharp. The shape of your brush may also need work. But these are independent of the transparency problem.
As for the Qt strangeness, I don't know enough Qt to tell you how to deal with the quirks of Qt's brush code. But the above "key-mask" strategy should solve your alpha overlap problem.
I do not know how to do this in Qt. Glancing at the Qt compositing modes I don't see an obvious way to say "take maximum" as the resulting alpha. Maybe something involving both color and alpha channels in some clever way.
I know this question is very old, and has an accepted answer, but in case someone else needs the answer, here it is:
You need to set the composition mode of painter to source. It draws both source and destination right now.
painter.setCompositionMode(QPainter::CompositionMode_Source);
If you want your transparent areas to show through underlying drawings, you need to set the composition mode of your result back to CompositionMode_SourceOver and draw over destination.
I don't know if you still look for an answer, but I hope this helps someone.

Open and edit SVG files using C/C++

I'm developping an editor that must use SVG shapes to create diagrams.
To open and display SVGs I use librsvg which is actually pretty good but only useful to render SVGs not to edit them.
I would like to access to shape's property and change their values (i.e. width, size ).
I use Cairo to draw them to the screen but I don't want to use the cairo's scale feature, cause it's not the same as changing the size of the shapes.
I use C++ builder XE3 on Win32.
Is anyone knows a good C/C++ library I could use to do so ?
Thanks for your help.
Cairo's scale function scales the entire coordinate system, but you can use it on an individual shape if you translate first to the shape's origin; and if you bracket these changes with a save/restore pair it will only affect drawing done within this span. Resetting the matrix before stroking allows you to resize a drawing without changing the stroke-width (alternately, you can adjust the stroke_width by 1/scaling-factor).
cairo_matrix_t m;
cairo_get_matrix(cr, &m);
cairo_save(cr);
cairo_translate(shape_x, shape_y);
cairo_scale(shape_w, shape_h);
//cairo_move_to(cr, x, y); //perform the actual drawing
//cairo_line_to(cr, x, y);
//cairo_closepath(cr);
cairo_set_matrix(cr, &m);
cairo_stroke(cr);
cairo_restore(cr);
And if resetting the matrix explicitly like this, you don't actually need the save/restore anymore (translate and scale don't affect anything but the matrix, and stroke resets the path).

QT Graph plotting, how to change coordinate system/geometry of QGraphicsView

I am using QT and try to plot a graph with QGraphicsView and QGraphicsScene..i dont want any additional dependencies, thats why i dont use QWT. When i plot my data, at the moment i use
scene->drawLine(x1,y1,x2,y2,pen);
then this draws a line between the 2 points in the QGraphicScene. But this uses a top left x=0 y=0 system... i would like to use my own system like in the picture below. Another problem is that i have double values from -3 to +3..has anyone some experience with QGraphicScene and QGraphicsView and can tell me how i can accomplish this?
Try looking into QGraphicsView::setTransform. This matrix defines how "scene coordinates" are translated to "view coordinates", it's a common concept in graphics programming.
There are also convenience functions scale(), rotate(), translate() and shear() which modify the view's current transformation matrix.
So you could do something like this:
scale(1.0, -1.0); // invert Y axis
// translate to account for fact that Y coordinates start at -3
translate(0.0, 3.0);
// scale Y coordinates to height of widget
scale(1.0, (qreal)viewport()->size().height()/6.0);
And since this is dependent on the size of the widget, you'd also want to catch any resize events and reset the transformation matrix again there. Assuming you want "3" to represent the top of the viewport and "-3" the bottom.