10

I am rendering an interpolation curve thusly:

e.Graphics.DrawLines(new Pen(Color.Red), _interpolationPoints.ToArray());

which sometimes throws an OverflowException.

Examination of the _interpolationPoints array shows some very large values in scientific notation e.g. {X = 0.0 Y = -1.985174E+10}

I suspect that Y = -1.985174E+10 is a value that GDI+ cannot handle. That's fine but what are the max/min X and Y values into which I can draw and so constrain the data (and warn the user) rather than catching the overflow exception during paint? Are the limits documented?

For example, I would like to do something like this:

if (yVal < float.MinValue || yval > float.MaxValue) 
      throw new OverflowException("Interpolation value too large to be rendered.");

during the population of the _interpolationPoints array and stop the process. (float mix/max does not work btw. i still get the exception.)

Paul Sasik
  • 79,492
  • 20
  • 149
  • 189
  • Thanks very much. It's interesting how little info there is about these limitations. Surely I'm not the first person to write code to draw interpolations in GDI+ and needed to catch the edge values. – Paul Sasik Aug 12 '10 at 17:45
  • @Vulcan: Make sure to check out the answer below. The question above only contains ideas that DID NOT work for the sake of completion. E.g. float.MaxValue IS NOT a valid test of the limit! – Paul Sasik Aug 12 '10 at 17:58
  • 1
    I did check out the answer and the article as well. – Agnel Kurian Aug 12 '10 at 18:34

3 Answers3

9

OK, I needed to know so I tested incrementally and came up with these limits:

positive:    1,073,741,951
negative:   -1,073,741,760

The code I used looked something like this:

int lastGoodVal = 0;
for (int i = -1073000000; i > -1073832999; i -= 1)
{
    g.DrawLine(Pens.Blue, new Point(0,0), new Point(0, i));
    lastGoodVal = i;
}

The loop above was the final test, stepping by 1, through a range of negative values established by earlier tests. As you can see, lastGoodVal holds the last successful painting iteration and therefore the real limit which I'll use as a constant.

I tried to correlate these numbers to a value in the .NET primitives but couldn't. Each limit is close to the value of 2^30 but is not exactly on it. Any other insight would be much appreciated.

I also only tested with the DrawLine method. It's possible that different limits exist for other functions in the API but I have not had a chance to explore that yet.

Also, after finishing this experiment and then Googling for the value 1073741951 I came across this article which correlates my findings. I also found this in a Mono code archive of some sort which mentions a near, though not exact correlation to float limits.

Andrew Morton
  • 24,203
  • 9
  • 60
  • 84
Paul Sasik
  • 79,492
  • 20
  • 149
  • 189
4

FYI - I ran into this situation with a simple implementation of a 2D plot. When I zoomed in too far on the image the corresponding pixel locations were WAY off the display area and caused Graphics.DrawLine to throw an OverflowException. So naturally I added a check to ensure that the values where within the limits defined by Paul above. Interestingly though when the Y value got too large (but less than suggested positive value of 1,073,741,951) the resulting line went from being drawn down as expected (to a Y pixel location greater than my last reasonable point) to being drawn up (to the top of the window).

After further investigation I discovered that a value of 8,388,607 (0x7FFFFF) draws the line correctly and a value of 8,388,608 (0x800000) inverts the line.

Looks like signed 24-bit values are used here.

hyde
  • 60,639
  • 21
  • 115
  • 176
  • +1 Interesting observation but I'm not quite sure that it's a signed/unsigned issue. The values of `0x7FFFFF` and `0x800000` do represent a 24 bit piece of data but are nowhere "close" to a boundary where overflow or signed/unsigned problems would come into play. Those HEX values would look more like: `0xFFFFFF` and `0xFFFFFE` etc. I'm also not familiar with any system that has a 24-bit architecture... I'm guessing that this is a semi-arbitrary boundary set internally, maybe a tweak for performance reasons. – Paul Sasik Apr 24 '14 at 22:08
1

I've not heard of specific limits for DrawLines() or any other GDI drawing function. Why don't you use e.ClipRectangle as a constraint?

Drawing points outside the visible region is not needed anyway. Just make sure that only lines are discarded that have both points outside.

msteiger
  • 2,024
  • 16
  • 22
  • +1 I think your last comment is key: `Just make sure that only lines are discarded that have both points outside.` I recall that I ran into the issue when I got to curve fitting and display for polynomial and linear regression. The lines connecting the end points of those fits often shot up or down past the ranges I listed in my answer and there was no built-in way, besides exception handling, to handle the error. Exception handling caused terrible performance issues and, as you mentioned, I had to check and discard those problematic lines with custom code. – Paul Sasik Apr 24 '14 at 22:24