How to get consistent gradient fill in GDI+ when using a rotated LinearGradientBrush? - rotation

I'm using GDI+ in my application, and I need to use a rotated LinearGradientBrush to paint several rects in the exact same way. However, although I'm calling the same code to fill each rect, the results aren't what I expect. Here's the code to create the gradient fill, where rcDraw is the rect containing the area to paint for each rect. These coordinates are in the parent window's coordinates, so they are not identical for the 2 rects.
g_hbrLinear = new LinearGradientBrush( Rect( 0, rcDraw.top, 0, rcDraw.bottom - rcDraw.top ),
clrStart, clrEnd, (REAL) 80, FALSE );
What I see on screen looks like this (http://www.nnanime.com/bugs/LinGradBrush-rotate10.png). You can see that it's as if the fill from the first rect continues into the second one. What I really want is to have the 2 rects look identical. I think I can do that if I paint each rect separately using its own client coordinates, but for the purposes of my app, I need to use the parent window's coordinates.
I guess what I'm asking is, how does GDI+ calculate the "origin" of a fill? Is it always based on 0,0 in the coordinate system you use? Is there a way to shift it? I tried TranslateTransform, but it doesn't seem to shift the fill in a way that I find predictable or understandable.

The rect passed to the linear gradient brush determines the where the left and right colors will sit, and the gradient will be painted within this rectangle.
So, I think you need to create a brush for each rectangle you are painting, where the rectangle you are painting is also passed to the constructor for the linear gradient brush.

My experience with the "transform" of linear gradient brushes matches yours; I haven't been able to understand what it's supposed to do.
You can think of a brush in GDI+ as a function mapping world co-ordinates to a color. What the brush looks like at a given point does not change based on the shape being filled.
It does change with the transform of the Graphics object you're drawing on. So, if you don't want to change the brush, you could temporarily change the transform of the Graphics object so that the rectangle you're drawing has a specific, known size and position in world coordinates. The BeginContainer and EndContainer methods should make this easy.
(There is also the RenderingOrigin property but it only affects hatch brushes, which oddly are unaffected by world transforms.)

Related

How do I draw a rounded rectangle without filling it (in MFC)?

Another drawing question for you MFC/GDI gurus out there... :-)
I'm using MFC, and I'm doing some drawing with a CDC object. That works fine.
But now I want to draw a rectangle with rounded corners, the line being a couple of pixels wide. But I dont want any filling to occur! There is a method CDC::RoundRect - I just set the pen I want and get a beautiful rounded rectangle with that pen. But CDC::RoundRect also fills the rectangle with the current brush.
Is there any way to draw just the line, with no filling? Any other method I haven't found? Or can I create some sort of "null brush" that doesn't alter what's in the middle of the rectangle?
I'd be very grateful for some good advice!
/Anders from Sweden
Just select a NULL brush before drawing the rounded rectangle, like
CPen pen;
CBrush* pOldBrush;
CPen* pOldPen;
if (!pen.CreatePenIndirect(&m_logpen))
return;
pOldBrush = (CBrush*)pDC->SelectStockObject(NULL_BRUSH);
pOldPen = pDC->SelectObject(&pen);
pDC->RoundRect(m_rect, m_roundness);
pDC->SelectObject(pOldBrush);
pDC->SelectObject(pOldPen);

Need line drawing algorithm for simulating natural pencil

I'm writing a drawing program that uses a pressure sensitive table for input. I'd like to be able to simulate the soft pencil effect that many other art programs have (such as Paint Tool SAI, Art Rage). Technique I'm using at the moment is functional, but is missing the cleanness I see in more professional programs.
My algorithm at the moment works like this:
Create a bitmap representing the head of the brush. This is just a transparent bitmap with a black circle drawn on it. The circle has an inner radius that is solid black and an outer radius. The blackness linearly fades from opaque to transparent as you move from the inner to the outer radius.
Capture input events from my tablet. Each point contains an (x, y) coordinate as well as a pressure value
For every point after the first one, draw a line from the previous point to the current one. This is done by drawing (daubing) the brush bitmap several times between the two points. The step size between each daub is chosen so there is an overlap between subsequent daubs.
This works reasonably well, but the result is a line that is somewhat blobby and jagged.
One thing I need to do is somehow smooth out the input points so that the stroke as a whole is smooth.
The other thing I need to do is figure out how to 'drag' the brush head along this path to make the stroke. If the spacing is too far apart, the stroke looks like a line of circles. If too close together, the stroke builds up on itself and becomes very dark. (I tried to fix this by attenuating the brush by the spacing. This does make things more consistent, but stops the stroke from being fully opaque).
Anyhow, I'd expect that there's a lot of research already done on this, if only I knew where to look. Please let me know if there are any better pencil drawing algorithms out there.
Instead of drawing the new circle over what has already been drawn, using the standard blending functions (so that regions of overlap get a higher opacity), you need to keep the maximum opacity so far.
Only after you have built up the complete stroke (as on a white sheet), you can blend it to the existing line art.
The picture illustrates the difference between blending and keeping the maximum opacity.

User interaction in Processing

I have a general question (I know I should present specific code with a problem, but in my case the problem is of a more general nature).
In Processing, let's say I make an ellipse:
ellipse(30, 30, 10, 10);
Now, is there a way to get the pixels where this ellipse is on the canvas? The reason would be to have a way of creating user interaction with the mouse (for instance). So when someone clicks the mouse over the ellipse, something happens.
I thought of turning everything into objects and use a constructor to somehow store the position of the shape, but this is easier said than done, particularly for more complex shapes. And that is what I am interested in. It's one thing to calculate the position of an ellipse, but what about more complex shapes? Are there any libraries?
Check out the geomerative library. It has a way to check whether the mouse is inside any SVG shape. I can't remember off the top of my head but it works something like you make a shape:
myShape = RG.loadShape("shape.svg");
and a point:
RPoint p = new RPoint(mouseX, mouseY);
and the boolean function contains() will tell you if the point is inside the shape:
myShape.contains(p);
It's better to use a mathematical formula than pixel-by-pixel checking of the mouse position (it's much faster, and involves less code).
For a perfect circle, you can calculate the Euclidean distance using Pythagoras' theorem. Assume your circle is centred at position (circleX,circleY), and has a radius (not diameter) of circleR. You can check if the mouse is over the circle like this:
if(sq(mouseX-circleX)+sq(mouseY-circleY) <= sq(circleR)) {
// mouse is over circle
} else {
// mouse is not over circle
}
This approach basically imagines a right-angled triangle, where the hypotenuse (the longest side) runs from the centre of the circle to the mouse position. It uses Pythagoras' theorem to calculate the length of that hypotenuse, and if it's less than the circle's radius then the mouse is inside the circle. (It includes a slight optimisation though -- it's comparing squares to avoid doing a square root, as that can be comparatively slow.)
An alternative to my original mathematical answer also occurred to me. If you can afford the memory and processing power of drawing all your UI elements twice then you can get good results by using a secondary buffer.
The principle involves having an off-screen graphics buffer (e.g. using PGraphics). It must be exactly the same size as the main display, and have anti-aliasing disabled. Draw all your interactive UI elements (buttons etc.) to this buffer. However, instead of drawing them the normal way, give each one a unique colour which it uses for fill and stroke (don't add any text or images... just solid colours). For example, one button might be entirely red, and another entirely green. Any other RGB value works, as long as each item has a unique colour. Make sure the background has a unique colour too.
The user never sees that buffer, so don't draw it to the screen (unless you're debugging or something). When you want to detect what item the mouse is over, just lookup the mouse position on that off-screen buffer. Get the pixel colour at that location, and match it to the UI element.
After you've done all that, just go ahead and draw everything to the main display as normal.
It's worth noting that you can cut-down the processing time of this approach a lot if your UI elements never (or rarely) move. You only need to redraw the secondary buffer when something appears/disappears, animates, or changes size/position.

Limiting the drawing to a rectangle in OpenGLES

I need to limit the drawing of an object to a rectangle. I can't just change the viewport to match the rectangle becouse the ModelView matrix (that should change the rectangle, but not the content) may not be identity. A solution that would work is to draw to a FBO that match the rectangle, then draw the FBO to the screen, but it seems to slow. Is there any better option to do that?
If I understood you correctly, glScissor should be the function you are looking for. It crops the rendering to a selected sub-rectangle of the viewport. This does not modify the viewport. So the objects cover the same size on the screen, it just prevents you from drawing any pixels outside of the scissor region. If this is not what you want and you want the sub-rectangle to contain the whole scene and thus your objects to shrink, then changing the viewport is the solution of choice.
EDIT: If you want the rectangle to be transformable and especially rotatable (and therefore not a rectangle anymore on the screen), then rendering into an FBO and using this as texture on a quad is probably the best solution. Otherwise you could probably also just modify the vertex coordinates after projection, thus multiplying the transformation matrix of the target rectangle with the projection matrix and using this as new projection matrix, but I'm not completely sure about that (but at least something similar should do it.

polyline with gradient

Is there a way to draw a line along a curved path with a gradient that varies in a direction perpendicular to the direction of the line? I am using the GDI+ framework for my graphics.
The simple answer is no. You can create a GraphicsPath in order to describe what you would like to draw, using AddPoint/AddLine/AddBezier and so forth as needed to describe the complex path of what you want to draw. When you draw the path you can provide a Brush which can be something like LinearGradientBrush or RadialGradientBrush. Neither of those gradient brushes reacts to the actual path being drawn in the sense of changing direction as the drawing occurs. You have to specify the angles etc as constant for the entire gradient area.
One possible method you can use is to set the clip region of the Graphics object to be that of the line only. Then draw a Linear Gradient over the extremes of the line e.g.
GraphicsPath gp = new GraphicsPath();
gp.AddArc(); // etc...
graphics.SetClip( gp );
graphics.FillRectangle( myLinearGradientBrush, gp.GetBounds());
The above code might give you what you are looking for.

Resources