problem - PointToImage in virtualMode when out of bounds

Started by mtagliaf, March 20, 2015, 01:57:37 PM

Previous topic - Next topic

mtagliaf

I'm using the imageBox entirely in virtual mode, to create something like a CAD program.

When I start a new document, my virtual world is fairly small - it doesn't take up the size of the entire screen.  This is by design.  When I drag an object out of the bounds of the world, however, I would like the world's bounds to update so that it accommodates the new object.

The problem is in my MouseMove event, while dragging an object. To translate mouse coordinates to world coordinates, I call the imageBox's PointToImage method, but this method is returning (0,0) if the mouse bounds are outside of the current virtual world. 

Richard Moss

Hello,

There are two overloads for PointToImage. Doing PointToImage(Point) will constrain the result to the image bounds, returning Point.Empty if it is outside of these.

PointToImage(Point, bool) however, allows you to specify this behaviour. Setting the second parameter to false will cause the calculation to ignore the boundaries.

Hope that helps!

Regards;
Richard Moss

mtagliaf

thanks for the prompt reply, but that doesn't quite work.  It appears that the default for that value is false, meaning I'm already passing false.

public Point PointToImage(Point point)
    {
      return this.PointToImage(point, false);
    }


And in looking at the code, it looks like passing false for that param will definitely always return return <0,0>, when the point is outside of the bounds of GetImageViewport...

      viewport = this.GetImageViewPort();

      if (viewport.Contains(point) || fitToBounds)
      {
           (stuff removed)
      else
      {
        x = 0; // Return Point.Empty if we couldn't match
        y = 0;
      }

      return new Point(x, y);
    }


Passing true will get it to go into the (stuff removed) part of the code, but that code block definitely constrains to the viewport size.

Richard Moss

Should be

if (viewport.Contains(point) || !fitToBounds)

Oops  :-[. I'll get that fixed this weekend.

Thanks for the catch!

mtagliaf

Quote from: Richard Moss on March 20, 2015, 06:32:51 PM
Should be

if (viewport.Contains(point) || !fitToBounds)

Oops  :-[. I'll get that fixed this weekend.

Thanks for the catch!

Glad to be of help, but I still don't think that will match the logic you were going for.  That will make it do "fit to bounds" stuff when fitToBounds is false.

And it definitely won't solve my particular issue - I think I'm going to need to create a subclass with a PointoToImageUnconstrained method or something similar.  I need code that will calculate the (point - viewport) / ZoomFactor and then leave it even when it's outside the bounds of the viewSize...





Richard Moss

The point of that method is to do what you are trying to do, there shouldn't be a need for a custom version. I'm currently wrapping up a bunch of new tests for WebCopy bug fixes, I'll take a closer bug at the intent and logic of this method tomorrow.

Richard Moss

Hello,

Turns out that the (stuff removed) was wrong as well as it always ran boundary checks, so essentially the fitToBounds parameter was always ignored.

That's fixed now (there's a new option in the View menu of the General demo I used to check) and the source has been pushed to GitHub, along with finally an updated NuGet package.

I also had to correct the ImageBoxEx demo control as the fix managed to break its out of bounds handling.

Regards;
Richard Moss

mtagliaf


Richard Moss

Excellent, glad to hear it :) Let me know if you come across any other problems. Good luck with your project too, sounds interesting.

mtagliaf

thanks.  I wanted to point out one other thing that was different about your Imagebox and the one I wrote.  I don't expect you to make any changes based on this, just another way of thinking about implementations.

My ImageBox (which I called PaintPanel) sent everything back to the caller in world-specific coordinates, instead of translating them to screen coordinates.  So there were a bunch of extra events like WorldMouseDown that sent World coordinates back to the user.  I also preferred drawing in World coordinates, so I had a WorldPaint that was called from OnPaint.  To translate the .NET graphics object to world coordinates from my PainPanel, I did this:

Dim gs = e.Graphics.Save()

e.Graphics.PageUnit = GraphicsUnit.Pixel
e.Graphics.TranslateTransform(me.AutoScrollPosition.X, me.AutoScrollPosition.Y, MatrixOrder.Prepend)
e.Graphics.ScaleTransform(Convert.ToSingle(me.ZoomFactor), Convert.ToSingle(me.ZoomFactor), MatrixOrder.Prepend)

OnWorldPaint(e.Graphics)

e.Graphics.Restore(gs)


Now my renderer can set up rectangles and such using world coordinates.

Richard Moss

Thanks for the follow up. That's interesting info. I don't think I'll be adding that to the core control as it's probably too specialised a use case, but I don't imagine it would be that difficult to inherit from ImageBox and extend it with that functionality. Something to look at if there's a rainy day perhaps!

mtagliaf

agreed, that would be an excellent subclassed control