See the Shape documentation:
Most nodes tend to have only integer translations applied to them and
quite often they are defined using integer coordinates as well. For
this common case, fills of shapes with straight line edges tend to be
crisp since they line up with the cracks between pixels that fall on
integer device coordinates and thus tend to naturally cover entire
pixels.
On the other hand, stroking those same shapes can often lead to fuzzy
outlines because the default stroking attributes specify both that the
default stroke width is 1.0 coordinates which often maps to exactly 1
device pixel and also that the stroke should straddle the border of
the shape, falling half on either side of the border. Since the
borders in many common shapes tend to fall directly on integer
coordinates and those integer coordinates often map precisely to
integer device locations, the borders tend to result in 50% coverage
over the pixel rows and columns on either side of the border of the
shape rather than 100% coverage on one or the other. Thus, fills may
typically be crisp, but strokes are often fuzzy.
Two common solutions to avoid these fuzzy outlines are to use wider
strokes that cover more pixels completely - typically a stroke width
of 2.0 will achieve this if there are no scale transforms in effect -
or to specify either the StrokeType.INSIDE or StrokeType.OUTSIDE
stroke styles - which will bias the default single unit stroke onto
one of the full pixel rows or columns just inside or outside the
border of the shape.
And see also the documentation of Node:
At the device pixel level, integer coordinates map onto the corners
and cracks between the pixels and the centers of the pixels appear at
the midpoints between integer pixel locations. Because all coordinate
values are specified with floating point numbers, coordinates can
precisely point to these corners (when the floating point values have
exact integer values) or to any location on the pixel. For example, a
coordinate of (0.5, 0.5) would point to the center of the upper left
pixel on the Stage. Similarly, a rectangle at (0, 0) with dimensions
of 10 by 10 would span from the upper left corner of the upper left
pixel on the Stage to the lower right corner of the 10th pixel on the
10th scanline. The pixel center of the last pixel inside that
rectangle would be at the coordinates (9.5, 9.5).
So your options for clean lines when you have an odd stroke width are:
- Use a StrokeType.INSIDE or StrokeType.OUTSIDE stroke style.
- Offset the co-ordinates of shapes by 0.5 of a pixel so that the strokes line up on the lines rather than the cracks between lines.
- Just use the next even number up as the stroke width, e.g. 1 => 2, 3 => 4, etc.
As to why setSmooth(false)
does not work, I don't know exactly, my guess is that the antialiasing it refers to is independent of the antialiasing styles performed when strokes are centered on the cracks between pixels, but I would not know why that would be.