Tell me how to make this look right


#1

Two side by side rectangles:

graphics.drawRect( 100, 100, 50, 20, 1.0f );

graphics.drawRoundedRectangle( 160, 100, 50, 20, 4.0f, 1.0f );

Because of the anti-aliasing the drawRoundedRectangle rectangle is twice as thick and the drawRect rectangle at normal screen resolutions. This is definitely wrong. What can I do to get this to look right? I absolutely hate the anti-aliasing in juce and users should have a way to turn it off. You wouldn’t believe the tricks I have done to make it look correctly on the screen.

PLEASE give us a way to turn it off, so we can do our own anti-aliasing. This has been mentioned many times.

Every paint program, every drawing environment, has a way to disable it just for reasons like this.


#2

The reason it appears ‘twice as thick’ is because you’re actually drawing a line between two pixels, thus it must be represented in both. You need to bear in mind the fact that pixels actually have an area; to draw a line that starts in the centre of the ‘0,0’ pixel, you should consider that it is a box 1 pixel wide, with a top-left coordinate of 0,0 and a bottom right coordinate of 1,1. The starting point of a line from the centre of that box would be 0.5,0.5.

Try adding 0.5 to your top-left coordinate values, and you should see an improvement.

[I’m not sure if the integer drawRect function already takes this into account - though tbh i’m not sure which version it would choose in your case where you have all int coords but a float thickness parameter…]


#3

Thank you Haydxn for trying,

This is closer but it still does not work. I cannot get this simple thing to work. I need a one pixel line to be drawn for the borders.

//These two calls produce different size borders on the rectangle drawRectangle( 100, 100, 50, 20, 1.0 ); drawRoundedRectangle( 100, 100, 50, 20, 4.0, 1.0 );
PLEASE someone tell me how to get these to look consistent and PLEASE test it before giving an answer. Theory and what juce does are two different things.

This is what I have noticed: (Juce 2.0.3)

  1. drawRectangle with floats passed in always draws a thick line with or without adding/subtracting .5 from it’s coordinates.
  2. drawRoundedRectangle with floats passed in draws a single line when adding adding/subtracting .5 from it’s coordinates and a thick line when on integer boundaries.

I can get closer using drawRect with an rectangle passed in and using drawRoundedRectangle with floats passed in and subtracting .5, but when the line thickness thickens, this starts to fail.

Help!


#4

I just tried this and got a 1 pixel thick rectangle in both cases

g.drawRect ( 10, 100, 50, 20, 1.0 ); g.drawRoundedRectangle( 10.5, 55.5, 50, 20, 4.0, 1.0 );

Are your complaints about the perceived thickness of the rounded corners, or are you simply not getting this result?


#5

The rounded corners are fine. I get this result using with thickness of 1.0 and cast the thickness to an int on both calls, but try a thickness of 5.0. The rounded rectangle is wider and taller with a larger thickness.

or try doing this using floats for both drawRectangle and drawRoundedRectangle.

I’ll try to figure out why and believe me I hope it is something on my end.


#6

I just tried with a thickness of 5, and the line is absolutely no thicker, but you are right that the rectangle appears as though it is a different size. However, this is actually expected behaviour, and lines up with the documentation…

Here I draw the same rectangles, once with a 5.0 thickness black outline, and then again with a 1.0 thickness pink outline.

g.setColour (Colours::black); float thickness = 5.0f; g.drawRect ( 10.0f, 100.0f, 50.0f, 20.0f, thickness ); g.drawRoundedRectangle( 10.5, 55.5, 50, 20, 4.0, thickness ); g.setColour(Colours::hotpink); thickness = 1.0f; g.drawRect ( 10.0f, 100.0f, 50.0f, 20.0f, 1.0f ); g.drawRoundedRectangle( 10.5, 55.5, 50, 20, 4.0, thickness );This results in the following output:

You can see that drawRect uses the rectangle as the outer bound, and the thickness extends inwards, as stated in the documentation - the line is used as a guide for the ‘outer edge’ of the brush. drawRoundedRectangle draws the line as a stroked path of the rectangle, where the line is used as a guide for the centre of the brush.

Really, these draw operations should take an alignment parameter (i.e. centre, inside, outside). Unfortunately, they don’t (right now, at least!).

You can of course draw a non-rounded rectangle using drawRoundedRectangle (and providing a corner size of zero). This way you at least get the same stroke behaviour regardless. However, If you want the rectangle to be entirely contained inside your ‘input’ rectangle (as with drawRect), you’ll need to shrink the rectangle you pass in by half the thickness.

For example…

[code]void drawRoundedRectangleInside (Graphics& g, const Rectangle& rect, float cornerSize, float thickness)
{
g.drawRoundedRectangle (rect.reduced(thickness/2, thickness/2), cornerSize, thickness);
}

void MyComponent::paint (Graphics& g)
{
g.setColour (Colours::black);
float thickness = 4.0f;
g.drawRect ( 10.0f, 10.0f, 50.0f, 20.0f, thickness );
drawRoundedRectangleInside (g, Rectangle(10.0f,40.0f,50.0f,20.0f), 0.0f, thickness);
drawRoundedRectangleInside (g, Rectangle(10.0f,70.0f,50.0f,20.0f), 4.0f, thickness);
thickness = 1.0f;
g.drawRect ( 70.0f, 10.0f, 50.0f, 20.0f, thickness );
drawRoundedRectangleInside (g, Rectangle(70.0f,40.0f,50.0f,20.0f), 0.0f, thickness);
drawRoundedRectangleInside (g, Rectangle(70.0f,70.0f,50.0f,20.0f), 4.0f, thickness);
}[/code]

… gives the following result…

You may also want to note that, in this approach, there is no need to manually add 0.5 to the coordinates, since that is automatically catered for by the adjustment for thickness.

Hope this helps!


#7

The reason the rounded rect looks bigger is because internally it uses a Path to draw itself. When a Path is stroked the lines extend outwards in both directions from the co-ordinate line. The drawRect methods actually fills the 4 sides of the rectangle as paths so can effectively draw the lines inwards as noted by the documentation. This is useful for quickly creating bounding boxes etc. If you reduce the rounded rectangle by half the line thickness you can simulate this behaviour. Try out the following code to see the difference:

[code]g.setColour (Colours::black);

const float thickness = 5.0f;
Rectangle<int> intRect (10, 10, 100, 50);
Rectangle<float> floatRect (intRect.toFloat());
g.drawRect (intRect, (int) thickness);

intRect = intRect.translated (0, 60);
g.drawRect (intRect.toFloat(), (int) thickness);

intRect = intRect.translated (0, 60);
g.drawRoundedRectangle (intRect.toFloat(), 5.0f, thickness);

intRect = intRect.translated (0, 60);
floatRect = intRect.toFloat().reduced (thickness / 2);
g.drawRoundedRectangle (floatRect, 5.0f, thickness);[/code]

Which gives the following results:[attachment=0]Screen Shot 2013-05-20 at 21.45.06.png[/attachment]


#8

This definitely helps. I just needed some consistent method of drawing these.


#9

Beat me to it, much more thorough explanation though Hadyxn.


#10

[quote=“haydxn”]The reason it appears ‘twice as thick’ is because you’re actually drawing a line between two pixels, thus it must be represented in both. You need to bear in mind the fact that pixels actually have an area; to draw a line that starts in the centre of the ‘0,0’ pixel, you should consider that it is a box 1 pixel wide, with a top-left coordinate of 0,0 and a bottom right coordinate of 1,1. The starting point of a line from the centre of that box would be 0.5,0.5.

Try adding 0.5 to your top-left coordinate values, and you should see an improvement.

[I’m not sure if the integer drawRect function already takes this into account - though tbh i’m not sure which version it would choose in your case where you have all int coords but a float thickness parameter…][/quote]

Ah, great, thanks! I had wondered why my rounded rects looked blurry. Adding 0.5f to the x and y parameters gives nice sharp rounded rects, lovely!