how to determine cairo drawing with line width even? - cairo

I use a cr (from Gtk's widget draw event) and I want to create a rectangle (or a line) using an even number of pixels (2,4,6 etc.) without any «context transformations». According to this the line will be "around the path". And according to this "the diameter of a pen that is circular".
But in a rectangle will it be less outside and more inside or the opposite? And in a line will be up,down, left or right?
I understand that in an odd line width, "around the path" means 1 in the center and the rest are equally around.
But in an even line width, as when the line width is 2, will be 1 pixel inside the path or outside?
Is there a stable way to determine the pixels affected or it is random?
The walk around of creating two times every stroke'ing, first with line width 1 and then by using the remainder (an odd) number is pain killing and time consuming.

But in a rectangle will it be less outside and more inside or the opposite? And in a line will be up,down, left or right?
The line will have the same width on either side of the path. If this does not align with the pixel grid, you get some anti-aliased result.
I understand that in an odd line width, "around the path" means 1 in the center and the rest are equally around. But in an even line width, as when the line width is 2, will be 1 pixel inside the path or outside?
With a line width of 3, 1.5 pixels will be drawn on either side of the path.
With a line width of 4, 2 pixels are drawn on either side of the path.
Perhaps the following example makes this clearer. This is written in Lua and uses LGI as cairo bindings for Lua, but this maps directly to the C API:
local cairo = require("lgi").cairo
s = cairo.ImageSurface(cairo.Format.RGB24, 100, 30)
cr = cairo.Context(s)
cr:set_source_rgb(1, 1, 1)
cr:paint()
cr:set_source_rgb(0, 0, 0)
cr:set_line_width(2)
cr:rectangle(5, 10, 5, 5)
cr:stroke()
cr:set_line_width(6)
cr:rectangle(15, 10, 14, 14)
cr:stroke()
cr:set_line_width(7)
cr:rectangle(40.5, 10.5, 14, 14)
cr:stroke()
cr:set_line_width(7)
cr:rectangle(70, 10, 14, 14)
cr:stroke()
s:write_to_png("out.png")
The resulting image is:
The first rectangle has a line width of 2. It is drawn with integer coordinates, so that there is e.g. a line from (5, 10) to (10, 10) (the top line). Half the line width is drawn on either side of the line, so this line corresponds to a "filled rectangle" from (4, 9) to (6, 11).
The last rectangle has a line width of 7 and is also drawn with integer coordinates. Its top line goes from (70, 10) to (70, 24). Since half the line width is on either side of the line, the "filled rectangle" goes from (66.5, 6.5) to (73.5, 27.5). These numbers are not integers and you can see in the result that some anti-aliasing was applied.
In contrast, the second to last rectangle has its position shifted by 0.5. This causes the "filled rectangle" for its "top line" to end up on the pixel grid again.
See also this FAQ entry: https://www.cairographics.org/FAQ/#sharp_lines

Related

Swift CAShapeLayer gets partially transparent at 1pt or lower

I've been trying to get a solid color when I draw a 0.5pt width line but it gets opaque when the value is 1.0 or less (see picture).
This is the code (Swift 4)
func DrawLine(from:CGPoint, to:CGPoint) {
let path = UIBezierPath()
path.move(to: from)
path.addLine(to: to)
let lineLayer = CAShapeLayer()
lineLayer.path = path.cgPath
lineLayer.lineWidth = linesWidth
lineLayer.strokeColor = linesColor.cgColor
lineLayer.isOpaque = false // trying to make it work line
lineLayer.opacity = 1 // trying to make it work line
lineLayer.shadowColor = UIColor.clear.cgColor // trying to make it work line
lineLayer.shadowOffset = .zero // trying to make it work line
lineLayer.shadowOpacity = 0 // trying to make it work line
self.layer.insertSublayer(lineLayer, at: 0)
}
Thanks.
I found an answer at https://www.raywenderlich.com/411-core-graphics-tutorial-part-1-getting-started (All because the anti-aliasing as explained in the first answer by Codo)
If you have oddly sized straight lines, you’ll need to position them
at plus or minus 0.5 points to prevent anti-aliasing
So, if the lineWidth is 1pt or less I add 0.5 points or (1 / scale).
Now the line is crispy
I think when you say opaque you rather mean partially transparent. And I guess we're talking about macOS here, right?
How do you expect a line of less than 1 pixels looks on the screen? A pixel is the smallest unit of the screen. The entire pixel has the same color. It can't be partially red and partially white.
So macOS – as part of the antialiasing – blends the thin line and the background, i.e. it makes the pixels partially transparent before drawing them on the background. The effect is that the line is perceived as thinner even though it is still 1 pixel wide.
If you don't like this effect, do not draw lines of less than 1 pixel. But it's the only way a line looks thinner than 1 pixel.
BTW: Pixel size depends on the resolution. On a retina device, 1 pixel is 0.5 point, on non-retina devices it's 1 point and there are even factors in-between.

Set MinimumBlobArea with width and height - MATLAB

I have a project to detect an object with background subtraction. But I can only set minimumblobarea with minimum pixel.. in my case, I need to set minimunblobarea to detect object in width and height to get specific object.. example : if there is an object bigger than width and height that I've set before, that object can't be detected.. so what should I do?
I Use this code
http://www.mathworks.com/help/vision/examples/motion-based-multiple-object-tracking.html
vision.BlobAnalysis returns bounding boxes of the detected blobs. The bounding box is a 4-element array of the form [x, y, width, height]. Once you have the bounding boxes you can easily check with ones have the width or the height that is too big, and exclude them.
Let's say you have N bounding boxes returned by vision.BlobAnalysys as an N-by-4 matrix called bboxes. You can use logical indexing to find boxes that are too big:
bigBoxesIdx = (bboxes(:, 3) > maxWidth) | (bboxes(:,4) > maxHeight);
bigBoxesIdx is now a logical array, where you have 1's for boxes that are too big, and 0's for the ones that are not. Note that you have to use the |, which stands for "element-wise or", rather than ||.
Now to throw away the boxes that are too big you simply do
bboxes(bigBoxesIdx, :) = [];

GtkPaned widget for arbitrary geometries?

I would like my application window to be divided into rectangles with sides perpendicular to the window borders. The number of rectangles would normally be quite large, and the user should be able to resize the rectangles.
Is there a Gtk widget which would allow for that? GTkPaned comes close - by embedding several GtkPaned widgets one can get such rectangle disivisons, but not all of them are possible - one obvious constraint is that there must be an edge which spans the whole window either horizontally or vertically. The simplest arrangement I know of which doesn't have this property, and so can't be built with Gtkpaned, is: one square in the middle and four rectangles of the same size each, around the square.
Is there a widget which allows for such arbitrary resizable rectangle arrangements in Gtk?
If you don't have to have the dividing lines draggable, then use a GtkGrid:
grid = Gtk.Grid()
grid.attach(widget1, 0, 0, 3, 1)
grid.attach(widget2, 3, 0, 1, 3)
grid.attach(widget3, 0, 1, 1, 3)
grid.attach(widget4, 1, 3, 3, 1)
grid.attach(widget5, 1, 1, 2, 2)
# 1112
# 3552
# 3552
# 3444

draw vertical lines at regular intervals in a rectangle in matlab

I need to draw vertical lines at regular intervals in a rectangular box. this is what i have used so far:
xmin=000;
xmax=70000;
ymin=0;
ymax=1000;
line1Val=900;
line2Val=600;
line3Val=300;
xlim([xmin xmax])
ylim([ymin ymax])
xl=get(gca,'XLim');
line(xl,[line1Val line1Val],'Color','y');
line(xl,[line2Val line2Val],'Color','y');
line(xl,[line3Val line3Val],'Color','y');
hold on ;
rectangle('Position',[120000,900,(280000-120000),37],'faceColor','k')
so the width of the rectangle is 160000 units i want to divide this into 4 , where the vertical line is of a different color(say red) and the height of the line is 37 units.
any ideas on how i can draw this without drawing 4 rectangles whose edges are red and are filled with black color.
You could use the parameters xstart,ystart,width and height for drawing your rectangle:
rectangle('Position',[xstart,ystart,width,height],'faceColor','k');
After that, you could determine the line positions in a loop and simply draw these lines:
for i = 1:3
x = xstart+i*width/4;
line([x x],[ystart ystart+height],'Color','r');
end
If you want a red line at the start and end of the rectangle, let i = 0:4.

CGAffineTransform help, flipping a label

I basically have a pie chart where I have lines coming out of each segment of the pie chart. So in the case where the line comes out of the circle to the left, when I draw my text, it is reversed. "100%" would look like => "%001" (Note, the 1 and % sign are actually drawn in reverse to, like if a mirror. So the little overhang on top of the 1 points to the right, rather than the left.)
I tried reading through Apple's docs for the AffineTransform, but it doesn't make complete sense to me. I tried making this transformation matrix to start:
CGAffineTransform transform1 = CGAffineTransformMake(-1, 0, 0, 1, 0, 0);
This does flip the text around its x-axis so the text now looks correct on the left side of the circle. However, the text is now on the line, rather than at the end of the line like it originally was. So I thought I could translate it by moving the text in the x-axis direction by changing the tx value in the matrix. So instead of using the above matrix, I used this:
CGAffineTransform transform1 = CGAffineTransformMake(-1, 0, 0, 1, -strlen(t1AsChar), 0);
However, the text just stays where it's at. What am I doing wrong? Thanks.
strlen() doesn't give you the size of the rendered text box, it just gives you the length of the string itself (how many characters that string has). If you're using a UITextField you can use textField.frame.size.width instead.