QChart and using QGradients with accelerated OpenGL rendering - c++

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.

Related

How to get bounding rectangle of an ArcGIS TextSymbol?

I'm using the Qt C++ ArcGIS Runtime SDK v100.9 and I have various shapes and labels being drawn on a map.
I want to be able to find out the area (bounding rectangle) of Graphic (which is a text label (TextSymbol) at a given point (SpatialReference::wgs84) on the map) so I can determine if the width of the label is more or less than another Graphic (lets say it has a Polygon for its Geometry which is being used to draw a circle) in order to decide if the label should be set to visible or not.
Within a class derived from Esri::ArcGISRuntime::MapGraphicsView the circle and the text label are created along the lines of:
Point centerWgs84(0.0, 0.0, SpatialReference::wgs84());
Graphic* circleGraphic_p = new Graphic(GeometryEngine::bufferGeodetic(centerWgs84, 1000.0, LinearUnit::meters(), 0.5, GeodeticCurveType::Geodesic));
this->graphicsOverlays()->at(0)->graphics()->append(circleGraphic_p);
circleGraphic_p->setSymbol(new SimpleLineSymbol(SimpleLineSymbolStyle::Solid, QColor(Qt::blue), 1.0));
circleGraphic_p->setVisible(true);
TextSymbol* textMarker_p = new TextSymbol("Some Label", Qt::black, 12.0, HorizontalAlignment::Center, VerticalAlignment::Bottom);
Graphic* labelGraphic_p = new Graphic(centerWgs84, textMarker_p);
this->graphicsOverlays()->at(0)->graphics()->append(labelGraphic_p);
labelGraphic_p->setVisible(true);
Rather than always setting the label visibility to true, I thought I would be able to take the Geometry of each Graphic and use it to construct an Envelope which would allow me to then get the width of each envelope that could then be compared:
Envelope circleEnvelope(circleGraphic_p->geometry());
Envelope labelEnvelope(labelGraphic_p->geometry());
labelGraphic_p->setVisible(circleEnvelope.width() >= labelEnvelope.width());
but when I try and do this, the width of each envelope is always a very small negative value (such as -2.25017... e-98)
Any suggestions on what I am doing wrong or if there is a better way to get the size on the map (or in device independent units) of the text label and a Graphic described by the Geometry of a Polyline or Polygon?
EDIT: I've discovered that the Geometry object has an extent() method from which I can get the width of the circle but the Geometry of the Graphic being used for the text label results in a width of zero from its extent() method. I expect this is because the Geometry is just a Point which has no width or height. So the question still stands of how to get the bounding rectangle of a TextSymbol?
You are correct, the extent is being returned of the underlying geometry, not the TextSymbol. I don't think you will be able to achieve what you are wanting in the way you are going about it, as there isn't a way to get the bounding box or screen coordinates of the symbol itself. Instead, have you considered using LabelDefinitions and setting the various deconfliction options? This sample shows labels on layers, but can be applied to graphics as well. There are many labeling options you can apply, and this would allow the internal labeling engine to deconflict for you.

cv::detail::MultiBandBlender strange white streaks at the end of the photo

I'm working with OpenCV 3.4.8 with C++11 and I'm trying to blend images together.
In this example I have 2 images (thiers mask shown in the screen belowe). I have georeference, so I can easy calculate corners of this images in the final image.
The data outside the masks are black.
My code looks like something like that:
std::vector<cv::UMat> inputImages;
std::vector<cv::UMat> masks;
std::vector<cv::Point> corners;
std::vector<cv::Size> imgSizes;
/*
here is code where I load images, create thier masks
(like in the screen above) and calculate corners.
*/
cv::Ptr<cv::detail::SeamFinder> seamFinder = new cv::detail::DpSeamFinder();
seamFinder->find(inputImages, corners, masks);
cv::Ptr<cv::detail::Blender> blender = new cv::detail:: MultiBandBlender(false);
blender->prepare(corners, imgSizes);
for(size_t i = 0; i < inputImages.size(); i++)
{
blender->feed(inputImages[i], masks[i], corners[i]);
}
cv::UMat blendedImg, outMask;
blender->blend(blendedImg, outMask);
SeamFinder gives me result like in the screen above. Finded seam lines looks good and Im very satisied form them. But the other problem occurs in the next step. The MultiBandBlender is making strange white streaks when the seam line goes on the end of the data.
This is an example:
When I don't use blender, but just use masks to cut the oryginal images and just add (cv::add()) images together with additional alpha channel (made from masks) I get very good results without any holes and strange colors, but I need to have more smoothed transition :/
Can anyone help me? When I create MultiBand Blender with smaller num_bands the white streaks are smaller, and with the num_bands = 0 the results looks like with just adding images.
I looked at feed() and blend() methods in the MultiBandBlender and I think that it is connected with Gaussian or Laplacian pyramid and the final restoring images from Laplacian pyramid in the blend() method.
EDIT1:
When Gaussian and Laplacian pyramids are created the copyMakeBorder(), which prevents the MultiBandBlender from making this white streaks when images are fully filled with the data. So in my case I think that I need to create my blender almost the same like MultiBandBlender, but copyMakeBorder() method in the feed() method change to the something that will "extend" my image inside the mask, like #AlexanderKondratskiy suggested.
Now I don't know how to achive correct "extend" similar to BORDER_REFLECT or BORDER_REFLECT_101.
I suspect your input images contain white pixels outside those masks. The white banding occurs around the areas where the seam follows the mask exactly. For Laplacian for example, pixels outside the mask do influence the final result, as each layer of a pyramid is essentially some blurring kernel on the image.
If you have some kind of good data outside the mask, keep it. If you do not, I suggest "extending" your image beyond the mask to maintain a smooth transition.
Edit:
Here's two things you could try, unless someone with more experience with OpenCV comes along.
To prove/disprove my hypothesis, fill the black region with just the average or median color within the mask. This should make the transition to the outside region less sharp, and hopefully reduce the artefacts. If that does not happen, my answer is wrong.
In terms of what is probably a good generalization of "BORDER_REFLECT" when the edge is arbitrary, you could try something like this:
Find the centroid c of the mask polygon
For each pixel p outside the mask, think of the line between it and c
Calculate point p' along this line that is the same distance inside the mask area, as p is from the mask edge. (i.e. you're reflecting along the mask edge)
Linearly interpolate the color of from the neighbors of p' (as it's position may not fall exactly in the middle of a pixel). That's the color of pixel p

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.

Manipulating a QGradient to follow a path

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?

Anti-aliasing in allegro 5

How do I make allegro 5 use anti-aliasing when drawing? I need diagonal lines to appear smooth. Currently, they are only lines of shaded pixels, and the edges look hard.
To enable anti aliasing for the primitives:
// before creating the display:
al_set_new_display_option(ALLEGRO_SAMPLE_BUFFERS, 1, ALLEGRO_SUGGEST);
al_set_new_display_option(ALLEGRO_SAMPLES, 8, ALLEGRO_SUGGEST);
display = al_create_display(640, 480);
Note that anti-aliasing will only work for primitives drawn directly to the back buffer. It will not work anywhere else.
On OpenGL, your card must support the ARB_multisample extension.
To check if it was enabled (when using ALLEGRO_SUGGEST):
if (al_get_display_option(display, ALLEGRO_SAMPLE_BUFFERS)) {
printf("With multisampling, level %i\n",
al_get_display_option(display, ALLEGRO_SAMPLES));
}
else {
printf("Without multisampling.\n");
}
You have two options: line smoothing or multisampling.
You can activate line smoothing by using glEnable(GL_LINE_SMOOTH). Note that Allegro 5 may reset this when you draw lines through Allegro.
The other alternative is to create a multisampled display. This must be done before calling al_create_display. The way to do it goes something like this:
al_set_new_display_option(ALLEGRO_SAMPLE_BUFFERS, 1, ALLEGRO_REQUIRE);
al_set_new_display_option(ALLEGRO_SAMPLES, #, ALLEGRO_SUGGEST);
The # above should be the number of samples to use. How many? That's implementation-dependent, and Allegro doesn't help. That's why I used ALLEGRO_SUGGEST rather than REQUIRE for the number of samples. The more samples you use, the better quality you get. 8 samples might be a good value that's supported on most hardware.