Retina - linewidth

PenWidth/PenHeight are Integer values so the smallest non-zero value is 1
however because Retina/HDPI is 4 points per pixel (2x2) it would be nice to draw a linewidth of 0.5

Is there a magic way to do this that I’m not aware of?

g.penwidth=0.5 // would be nice :(
g.drawline 0,0, 100,0

I THINK this is the correct approach…

g.scaleX=0.5
g.scaleY=0.5
g.drawline 0,0, (100/g.scalex),0
g.scaleX=1 // reset or subsequent graphics operations will possibly be scewed.
g.scaleY=1

royal PITA, as you have to divde all “normal coordinates” by g.scale

EDIT : actually that does NOT seem to do it… it does draw the line “slightly” different… but it is not 1 point wide
it is still 1 PIXEL (2points) wide :frowning:
I just need to do this for an overlay grid… all other drawing I need in normal "pixel"s

here is what I am using (g is the graphics object of a PICTURE object)

		If zGrid>=5 Then 
				mult=0.5
				g.scalex=mult
				g.scaley=mult
				g.ForeColor=ContrastColor(g.ForeColor)
				
				g.PenWidth=1
				For x=(lr+gr)/mult To (lr+w)/mult Step gr/mult
						g.drawline x,tb/mult,x,(tb+h)/mult
				Next x
				For y=(tb+gr)/mult To (tb+h)/mult Step gr/mult
						g.drawline lr/mult,y,(lr+w)/mult,y
				Next y
				g.scalex=1
				g.scaley=1
		End If

You could use CoreGraphics API on the macOS, it accepts a float for the line width. Just bear in mind that Xojo draws top->down and CoreGraphics draws bottom->up.

Dave, I’m curious why you chose 0.5 for the scale? On non-retina screen, the scale should be 1.0, on a scaled screen it would be higher (2.0 on Apple Retina or matching the scale factor in windows, 200% = 2.0)

I would think that what you actually want is:

Dim currentScale as double = g.scaleX g.scaleX = 1 g.ScaleY = 1 g.PenWidth = 1 g.PenHeight = 1 g.drawline x,y,x2,y2 g.scaleX = currentScale g.scaleY = currentScale

Ah I can see what you’re running into.

The issue is that the Xojo framework draws on the pixel boundaries. What you’re seeing is the anti-aliased line on either side.

[quote=362700:@Greg O’Lone]Dave, I’m curious why you chose 0.5 for the scale? On non-retina screen, the scale should be 1.0, on a scaled screen it would be higher (2.0 on Apple Retina or matching the scale factor in windows, 200% = 2.0)

I would think that what you actually want is:

Dim currentScale as double = g.scaleX g.scaleX = 1 g.ScaleY = 1 g.PenWidth = 1 g.PenHeight = 1 g.drawline x,y,x2,y2 g.scaleX = currentScale g.scaleY = currentScale[/quote]

I chose 0.5 because to be honest, the docs on ScaleX/Y are rather vague.

ScaleX/y ARE 1 to begin with (I checked with the debugger)
as to AntiAlias… I agree… to a point
with the code I had above… (taking a screen shot and magnifiying it)
the line is actually 4 pixels wide (anti-alias really light/transparent on both sides of a two wide gray line)
if I turn AntiAlias off then its just two wide, and darker

Note this IS on a Retina screen… if I do the same on a Non-Retina… the line is ONE pixel wide

On a CANVAS the g.ScaleX/Y IS 2, but as I mentioned this is being drawn as part of a PICTURE
all the other drawing is fine not messing with anything… but there is a GRID being drawn, and I’d like it to be hairline

Note : since this app needs to run on Retina/Non-Retina computers, and there will be hundreds of routines to draw objects on this “picture”, trying draw a huge picture may be an issue… but perhaps it is something I need to thing about

Ok… now I know why I am seeing what I’m seeing…
the PICTURE is created as @1x… so scaleX/Y = 1
but when I display it, (ie. in the Paint Event of a Canvas)… for a retina screen it actually expands it by 2x… so anything I drew as 1 pixel wide now shows as two pixels :frowning:

Now someone will probably suggest doing it the opposite… create a 2x picture to start with, and reduce it in the canvas

HOWEVER, that will create an “ugly” picture for a non-retina display, since it would be possible that some/all the “grid lines” would not show (or any other hairline drawn on an odd boundary)

actually, either create two and make a multi res picture or just check Window.ScaleFactor and make it at the correct size.

If you you need to use pictures for speed I would suggest that each time you see a new screen resolution you create a picture for it and cache it…

For best quality I suggest you do it dynamically and not assume only specific scale factors upfront , as I THINK Windows can have non integer screen scale settings and you never know how things will change in the future with screen resolution.

And I too have found dealing with this type of stuff a bit confusing!

  • Karen