Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is Graphics.DrawLine drawing a wedge shape?

I am trying to draw a bus route as a simple sequence of lines. Nothing fancy. But instead of lines, I'm getting wedges. Initially I was fine with this, because the wedges sortof look like arrows and always face towards the second point. But now I want to improve the look, and the wedges are becoming a big problem.

My suspicion is some sort of floating-point issue due to the graphics transform (lat/lons are fed in and the transform turns them into x/y on the bitmap [assuming lat/lon is euclidean is accurate enough for my purposes], so the scaling is several orders of magnitude).

Screenshot:

'Wedge' line overlayed over a road

It actually kind of looks like the line was split into two triangles but only one of them was drawn.

Relevant Code (note: drawing is done asynchronously, which is why I'm creating a bitmap):

'-- Creating the transform --'
Dim bitmap = New Bitmap(Math.Max(1, PictureBox1.Width), Math.Max(1, PictureBox1.Height))

Dim g = Graphics.FromImage(bitmap)
g.TranslateTransform(0, bitmap.Height)
g.ScaleTransform(1, -1)
g.ScaleTransform(CSng(bitmap.Width) / (maxLon - minLon), CSng(bitmap.Height) / (maxLat - minLat))
g.TranslateTransform(-minLon, -minLat)

'-- Drawing the lines (in a method called asynchronously) --'
using pen = New Pen(Brushes.Black, 0.0001)
Dim shapes = busData.TripsInGroup(tripGroup.Value).
             Select(Function(e) e.Shape).
             Distinct()
For Each shape In shapes
    For i = 0 To shape.Points.Count - 2
        Dim e1 = shape.Points(i)
        Dim e2 = shape.Points(i + 1)
        Dim p1 = New PointF(CSng(e1.Longitude), CSng(e1.Latitude))
        Dim p2 = New PointF(CSng(e2.Longitude), CSng(e2.Latitude))
        g.DrawLine(pen, p1, p2)
    Next
Next

Example values:

cenLat = 44.657176
cenLon = -63.549471
spnLat = 0.071921
spnLon = 0.179729
minLat = cenLat - spnLat / 2
maxLat = cenLat + spnLat / 2
minLon = cenLon - spnLon / 2
maxLon = cenLon + spnLon / 2
shpts = {(Lat: 44.6518683235, Lon: -63.5930836628), 
         (Lat: 44.6512537117, Lon: -63.5927528307), 
         (Lat: 44.6508013753, Lon: -63.5924572976), 
         (Lat: 44.6503312812, Lon: -63.5921923044), 
         (Lat: 44.6503312812, Lon: -63.5921923044), 
         (Lat: 44.6502137576, Lon: -63.5921260568), 
         (Lat: 44.6495810455, Lon: -63.5917829189), 
         (Lat: 44.648893839, Lon: -63.5913776026), 
         (Lat: 44.6485468163, Lon: -63.5911976944), 
         (Lat: 44.6485468163, Lon: -63.5911976944), 
         (Lat: 44.6475084762, Lon: -63.5906617219), 
         (Lat: 44.6475084762, Lon: -63.5906617219)}

Notes and discoveries:

  • Using DrawLines instead of DrawLine solves the issue (but why?)
  • Increasing the pen thickness makes the issue go away (but the lines are too thick)
  • Zooming out (increasing lat/lon view window) makes the issue go away, eventually (but I want to zoom in!)
like image 797
Craig Gidney Avatar asked Nov 04 '11 16:11

Craig Gidney


People also ask

What is the significance of drawLine () function?

The drawLine() function is an inbuilt function in the GraphicsMagick library which is used to draw the line with specified coordinates.

What is a drawLine?

DrawLine(Pen, Single, Single, Single, Single) Draws a line connecting the two points specified by the coordinate pairs. DrawLine(Pen, Point, Point) Draws a line connecting two Point structures.

Which Method is used to Draw a line?

In order to draw a line, you need to use the drawLine method of the Graphics class. This method takes four parameters, the starting x and y coordinates and the ending x and y coordinates.

What is PaintEventArgs?

A PaintEventArgs specifies the Graphics to use to paint the control and the ClipRectangle in which to paint.


2 Answers

I had this same issue, and stumbled across this thread. Unlike the OP I found that DrawLines did not solve the issue and suffered from the same problem as DrawLine.

Gabe is correct in that the issue is with regard to the precision of the internal drawing algorithms.

I solved the problem by scaling up the lat/long values by a factor of 10 (although if you are doing more zooming in you may need to scale up by more) before passing them to any drawing algorithm.

like image 183
rjpageuk Avatar answered Oct 26 '22 23:10

rjpageuk


Self-answer:

Workaround the issue by using DrawLines instead of DrawLine. DrawLines, for whatever reason, doesn't have this issue.

like image 44
Craig Gidney Avatar answered Oct 27 '22 00:10

Craig Gidney