Graphics.FillRectangle / TransformPoints Bug??

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • JBiagio

    Graphics.FillRectangle / TransformPoints Bug??

    Hello All,

    I am attempting to learn a bit about the GDI+ transforms and charting data and I
    feel like I'm getting a handle on how the transforms work. My chart object has a
    large "canvas" bitmap that all data is scaled to and rendered on, and I display
    a smaller "window" of the canvas that the user can page through left and right.

    I've been able to scale my data (for the purposes of this discussion, x values
    are 0 - 2PI and y values are -1 to 1; I'm charting Cosine) to the canvas bitmap
    using the transforms applied to the graphics object and to a transformation
    matrix, which I then useto transform the points and draw them on a graphics
    object that has no transforms applied. I used both methods because I wanted to
    learn how each works. So far, so good.

    Next, I attempted to draw rectangles to highlight particular regions of
    interest. This is where I get confused. I first worked with the transformed
    graphics object and was able to get the rectangle to draw, but the values that I
    had to use for its starting location do not make sense to me. Let me show the
    transforms necessary to scale and fit my data to the canvas.

    The canvas is 4096 x 100 pixels; the window is 512 x 100 pixels. Data is 0 - 2PI
    for x values and -1 to 1 for y values. The transforms are as follows:

    o Scale(1, -1) ; flip y coordinates
    o Translate(0, -1) ; move ymin to origin
    o Scale((4096/2PI), (100/(1 - -1)))
    o Translate(0, 100)

    This works out to be:

    o Scale(1, -1)
    o Translate(0, ymin)
    o Scale((canvas_w idth/(xmax - xmmin)), (canvas_height/(ymax - ymin)))
    o Translate(0, canvas_height)

    I believe the first Translate call works because the ymin of -1 is first scaled
    by -1 and becomes 1, 1 - 1 = 0 so we are back at the origin.

    The crux of this is that I can draw rectangles using the graphics object that
    has transforms applied to it, and it works as expected (i.e. if I want to draw a
    rectangle that covers half of my window, I say:
    FillRectangle(0 , -1, PI/8.0, 2)

    Two questions: How does the y-value of -1 work, because when you apply all of
    the transforms, -1 = 100 (-1 * -1 = 1 -1 = 0 * (100/2.0) = 0 + 100 = 100). If
    you were to attempt to fill a rectangle at location 0,100 with width of 256 and
    height of 100 on a bitmap of size (512, 100), nothing would be displayed. Unless
    I am misunderstandin g how the transforms work, this call should not work, but it
    does.

    Why must the height of the rectangle be given as 2 (i.e. 1 - -1)
    or ymax-ymin? If the other coordinates and measurements can be given in their
    appropriate units, why must the height be different?

    However, if I attempt to create the points and transform them with a
    transformation matrix, the location of (0, -1) (i.e. xmin, ymin) does not work.
    I must use *ymax* as the y-value of the location.

    Is the transformed FillRectangle call (the one with the Cornsilk brush) doing
    something strange to the coordinates? Does Matrix.Transfor mPoints call not work
    properly?

    I apologize that this is such a long post. If you need more info or my source
    code, feel free to email me: jwbiagio at sbcglobal dot net.

    Regards,
    JBiagio

    ---------------------------------------
    Here are the functions that I am using:

    Public Function CreateMatrix(By Val W As Single, ByVal H As Single, _
    ByVal Xmin As Single, ByVal Xmax As Single, _
    ByVal Ymin As Single, ByVal Ymax As Single) _
    As Matrix
    Dim m As New Matrix()
    m.Translate(0, H) '4
    m.Scale(W / (Xmax - Xmin), H / (Ymax - Ymin)) '3
    m.Translate(-Xmin, Ymin) '1
    m.Scale(1, -1) '2
    '2134
    Dim o(5) As Object
    m.Elements.Copy To(o, 0)
    Console.WriteLi ne("{0}, {1}, {2}, {3}, {4}, {5}", o)
    Return m
    End Function

    Protected Sub DrawCanvas()

    'points range x: 0 - 2PI, y: -1 - 1
    Dim g As Graphics = Graphics.FromIm age(canvas)

    'move the negative y-coord up one (1)
    g.TranslateTran sform(0, -1, MatrixOrder.Pre pend)
    g.ScaleTransfor m(1, -1, MatrixOrder.Pre pend) 'flip y coordinate (2)
    'append because we want to move before we scale (3)
    g.ScaleTransfor m(4096 / (Math.PI * 2.0), 50, MatrixOrder.App end)

    'move negative y coord up (i.e. 1 * -1 = -1 + -1 = -2 * (100/2.0) = -100) (4)
    g.TranslateTran sform(0, 100, MatrixOrder.App end)
    '2134
    Dim pt() As PointF = GeneratePoints( )
    Dim m As Matrix = CreateMatrix(40 96, 100, 0, 2 * Math.PI, -1, 1)
    m.TransformPoin ts(pt)
    'g.TransformPoi nts(CoordinateS pace.Page, CoordinateSpace .World, pt)

    Dim r As New RectangleF(0, -1, CSng(Math.PI / 8.0), 2)

    'Draw rectangle with transformed graphics object
    g.FillRectangle (Brushes.Cornsi lk, r)

    g.ResetTransfor m()

    'set up a location that will be next to the rectangle drawn by the
    'transformed graphics object
    Dim pt3() As PointF = {New PointF(CSng(Mat h.PI / 8.0), 1)}
    m.TransformPoin ts(pt3)

    'note that height and width are in page coordinates because the graphics
    'object is no longer transformed
    g.FillRectangle (Brushes.Indigo , pt3(0).X, pt3(0).Y, 256, 100)

    Dim p As New Pen(Color.Black , 1.0)

    g.DrawLines(p, pt)

    p.Dispose()
    g.Dispose()

    End Sub

    Protected Function GeneratePoints( ) As PointF()
    'This function will generate 20,000 points for Cosine(10x) from 0-2pi.
    Dim pt(19999) As PointF
    Dim i As Integer
    Dim d As Double

    For i = 0 To 19999
    d = (i / 19999.0) * 2 * Math.PI
    pt(i) = New PointF(d, Math.Cos(10 * d))
    Next

    Return pt
    End Function

    Protected Overrides Sub OnPaint(ByVal e As System.Windows. Forms.PaintEven tArgs)
    'This is a cobbled-together test. I need to create a much-larger bitmap and
    'then scale some dummy data to it.

    'Then the paint method will get a "slice" of the canvas bitmap and draw it
    'on the form.

    Dim bmp As Bitmap = canvas.Clone(Ne w Rectangle(posit ion * 512, 0, 512, 100), _
    Imaging.PixelFo rmat.DontCare)

    Dim font As New Font("Arial Bold", 13)

    e.Graphics.Draw String(position .ToString, font, Brushes.Blue, 10, 10)

    e.Graphics.Draw ImageUnscaled(b mp, 50, 50)
    End Sub
  • Supra

    #2
    Re: Graphics.FillRe ctangle / TransformPoints Bug??




    JBiagio wrote:
    [color=blue]
    >Hello All,
    >
    >I am attempting to learn a bit about the GDI+ transforms and charting data and I
    >feel like I'm getting a handle on how the transforms work. My chart object has a
    >large "canvas" bitmap that all data is scaled to and rendered on, and I display
    >a smaller "window" of the canvas that the user can page through left and right.
    >
    >I've been able to scale my data (for the purposes of this discussion, x values
    >are 0 - 2PI and y values are -1 to 1; I'm charting Cosine) to the canvas bitmap
    >using the transforms applied to the graphics object and to a transformation
    >matrix, which I then useto transform the points and draw them on a graphics
    >object that has no transforms applied. I used both methods because I wanted to
    >learn how each works. So far, so good.
    >
    >Next, I attempted to draw rectangles to highlight particular regions of
    >interest. This is where I get confused. I first worked with the transformed
    >graphics object and was able to get the rectangle to draw, but the values that I
    >had to use for its starting location do not make sense to me. Let me show the
    >transforms necessary to scale and fit my data to the canvas.
    >
    >The canvas is 4096 x 100 pixels; the window is 512 x 100 pixels. Data is 0 - 2PI
    >for x values and -1 to 1 for y values. The transforms are as follows:
    >
    > o Scale(1, -1) ; flip y coordinates
    > o Translate(0, -1) ; move ymin to origin
    > o Scale((4096/2PI), (100/(1 - -1)))
    > o Translate(0, 100)
    >
    >This works out to be:
    >
    > o Scale(1, -1)
    > o Translate(0, ymin)
    > o Scale((canvas_w idth/(xmax - xmmin)), (canvas_height/(ymax - ymin)))
    > o Translate(0, canvas_height)
    >
    >I believe the first Translate call works because the ymin of -1 is first scaled
    >by -1 and becomes 1, 1 - 1 = 0 so we are back at the origin.
    >
    >The crux of this is that I can draw rectangles using the graphics object that
    >has transforms applied to it, and it works as expected (i.e. if I want to draw a
    >rectangle that covers half of my window, I say:
    > FillRectangle(0 , -1, PI/8.0, 2)
    >
    >Two questions: How does the y-value of -1 work, because when you apply all of
    >the transforms, -1 = 100 (-1 * -1 = 1 -1 = 0 * (100/2.0) = 0 + 100 = 100). If
    >you were to attempt to fill a rectangle at location 0,100 with width of 256 and
    >height of 100 on a bitmap of size (512, 100), nothing would be displayed. Unless
    >I am misunderstandin g how the transforms work, this call should not work, but it
    >does.
    >
    >Why must the height of the rectangle be given as 2 (i.e. 1 - -1)
    >or ymax-ymin? If the other coordinates and measurements can be given in their
    >appropriate units, why must the height be different?
    >
    >However, if I attempt to create the points and transform them with a
    >transformati on matrix, the location of (0, -1) (i.e. xmin, ymin) does not work.
    >I must use *ymax* as the y-value of the location.
    >
    >Is the transformed FillRectangle call (the one with the Cornsilk brush) doing
    >something strange to the coordinates? Does Matrix.Transfor mPoints call not work
    >properly?
    >
    >I apologize that this is such a long post. If you need more info or my source
    >code, feel free to email me: jwbiagio at sbcglobal dot net.
    >
    >Regards,
    >JBiagio
    >
    >---------------------------------------
    >Here are the functions that I am using:
    >
    >Public Function CreateMatrix(By Val W As Single, ByVal H As Single, _
    > ByVal Xmin As Single, ByVal Xmax As Single, _
    > ByVal Ymin As Single, ByVal Ymax As Single) _
    > As Matrix
    > Dim m As New Matrix()
    > m.Translate(0, H) '4
    > m.Scale(W / (Xmax - Xmin), H / (Ymax - Ymin)) '3
    > m.Translate(-Xmin, Ymin) '1
    > m.Scale(1, -1) '2
    > '2134
    > Dim o(5) As Object
    > m.Elements.Copy To(o, 0)
    > Console.WriteLi ne("{0}, {1}, {2}, {3}, {4}, {5}", o)
    > Return m
    >End Function
    >
    >Protected Sub DrawCanvas()
    >
    > 'points range x: 0 - 2PI, y: -1 - 1
    > Dim g As Graphics = Graphics.FromIm age(canvas)
    >
    > 'move the negative y-coord up one (1)
    > g.TranslateTran sform(0, -1, MatrixOrder.Pre pend)
    > g.ScaleTransfor m(1, -1, MatrixOrder.Pre pend) 'flip y coordinate (2)
    > 'append because we want to move before we scale (3)
    > g.ScaleTransfor m(4096 / (Math.PI * 2.0), 50, MatrixOrder.App end)
    >
    > 'move negative y coord up (i.e. 1 * -1 = -1 + -1 = -2 * (100/2.0) = -100) (4)
    > g.TranslateTran sform(0, 100, MatrixOrder.App end)
    > '2134
    > Dim pt() As PointF = GeneratePoints( )
    > Dim m As Matrix = CreateMatrix(40 96, 100, 0, 2 * Math.PI, -1, 1)
    > m.TransformPoin ts(pt)
    > 'g.TransformPoi nts(CoordinateS pace.Page, CoordinateSpace .World, pt)
    >
    > Dim r As New RectangleF(0, -1, CSng(Math.PI / 8.0), 2)
    >
    > 'Draw rectangle with transformed graphics object
    > g.FillRectangle (Brushes.Cornsi lk, r)
    >
    > g.ResetTransfor m()
    >
    > 'set up a location that will be next to the rectangle drawn by the
    > 'transformed graphics object
    > Dim pt3() As PointF = {New PointF(CSng(Mat h.PI / 8.0), 1)}
    > m.TransformPoin ts(pt3)
    >
    > 'note that height and width are in page coordinates because the graphics
    > 'object is no longer transformed
    > g.FillRectangle (Brushes.Indigo , pt3(0).X, pt3(0).Y, 256, 100)
    >
    > Dim p As New Pen(Color.Black , 1.0)
    >
    > g.DrawLines(p, pt)
    >
    > p.Dispose()
    > g.Dispose()
    >
    >End Sub
    >
    >Protected Function GeneratePoints( ) As PointF()
    > 'This function will generate 20,000 points for Cosine(10x) from 0-2pi.
    > Dim pt(19999) As PointF
    > Dim i As Integer
    > Dim d As Double
    >
    > For i = 0 To 19999
    > d = (i / 19999.0) * 2 * Math.PI
    > pt(i) = New PointF(d, Math.Cos(10 * d))
    > Next
    >
    > Return pt
    >End Function
    >
    >Protected Overrides Sub OnPaint(ByVal e As System.Windows. Forms.PaintEven tArgs)
    > 'This is a cobbled-together test. I need to create a much-larger bitmap and
    > 'then scale some dummy data to it.
    >
    > 'Then the paint method will get a "slice" of the canvas bitmap and draw it
    > 'on the form.
    >
    > Dim bmp As Bitmap = canvas.Clone(Ne w Rectangle(posit ion * 512, 0, 512, 100), _
    > Imaging.PixelFo rmat.DontCare)
    >
    > Dim font As New Font("Arial Bold", 13)
    >
    > e.Graphics.Draw String(position .ToString, font, Brushes.Blue, 10, 10)
    >
    > e.Graphics.Draw ImageUnscaled(b mp, 50, 50)
    >End Sub
    >
    >[/color]

    Comment

    • Cor Ligthert

      #3
      Re: Graphics.FillRe ctangle / TransformPoints Bug??

      JBiagio,

      Did you know you have the most change on an answer for your question in the
      newsgroup.

      microsoft.publi c.dotnet.framew ork.drawing
      with probably as second best
      microsoft.publi c.dotnet.langua ges.vb

      You can also crosspost it to those newsgroups, (sending one message to both
      newsgroups at once). However in this case I would first try it with a single
      post to the first.

      And as advice do make a snippet of your problem. It is very rare in this
      newsgroups that questions with so much code are answered.

      I hope this helps?

      Cor


      Comment

      Working...