setTransform question


#1

I’m doing zooming using a call to AffineTransform::scaled(), and then calling setTransform on the object I want to scale. The object is drawn by a simple g.drawRect() call, where the Rectangle comes from g.getClipBounds();

For the most part, this is working swimmingly. What I am seeing is the thickening and thinning of lines that comes from boundary alignment issues. The same object, at different zoom levels can look like this, e.g.:

I’m sure the issues are the result of how the vertical lines fall on pixel boundaries, but I would have expected drawing to get better as the rectangles got larger, and the lines covered more pixels. What’s the proper technique for avoiding this kind of drawing problem?


#2

I think that drawRect was intended as a fast way to get a rectangle on integer boundaries without a transform (i.e. filling solid areas). If you want a “real” rectangle then add your rectangle to a Path and use strokePath with the appropriate thickness.


#3

Interesting. I didn’t know that strokePath would yield a different result.

So, I tried that, and voila! The outline is drawn much more consistently.

What I miss are the crisp, black lines that drawRect() affords me when the object isn’t
scaled, instead the lines are always anti-aliased, so they are sometimes crisp, sometimes
grey, and sometimes fuzzy (but consistently so!)

Is there an easy way to check to see if any element in the view hierarchy has been transformed?
isTransformed() only applies to the object itself, and it would be nice to see if a parent (or grandparent)
has been scaled, so I could adjust my drawing calls accordingly.


#4

I’m afraid that the future is going to involve a lot of resolution-independent graphics. Probably in 10 years the younger programmers won’t really know what we mean by a “pixel” because they’ll never have squinted hard enough to have seen one. Best to get into the habit of thinking that way now!


#5

I agree, the future is fuzzy, and resolution-independent.

That said, Is there an easy way to find out if an object has had an AffineTransform applied to it,
either directly, or higher up in the view hierarchy? I’d like to vary my object’s line thickness based
on how much it has been scaled, and avoid code that looks like this:

if (isTransformed() || getParent()->isTransformed() || getParent()->getParent()->isTransformed){
   //get the transform and find the scale factor for the line thickness
}

What’s the best way to accomplish this?


#6

No, I don’t think there’s an easy way to do that - you’d need to write something to recurse the tree and calculate it.


#7

[quote=“igor”]What I miss are the crisp, black lines that drawRect() affords me when the object isn’t
scaled, instead the lines are always anti-aliased[/quote]

That’s because you need to inset the rectangle, in floating point coordinates, by half of the stroke thickness. The stroke is centered on the rectangle. If your rectangle is at integer coordinates, then with a stroke width of 1.0 you will have half the stroke in one pixel, half in the other.

Try this:

int x, y, w, h; // initialize these
float thickness;
Path path;
path.addRectangle (x+thickness/2, y+thickness/2, w-thickness, h-thickness);
g.strokePath (path, thickness);

#8

That’s like saying that learning cursive is pointless because everyone uses a keyboard.


#9

TBH I do struggle with handwriting these days, as I seem to very rarely put a real pen to paper any more!


#10

You and I both, Jules. You and I both.

Unfortunately, scientific studies show that children who learn to write in cursive helps to develop specific parts of the brain used for spatial recognition and math. So even if it is never used (due to the ubiquity of computers), learning the skill is valuable. Sadly, schools in the United States have abandoned these traditional teaching methods and as a result, education has suffered.

References:

Better Learning Through Handwriting

The Pen May Be Mightier Than The Keyboard