2

In my program, users can draw shapes atop a matplotlib plot and do various actions with those shapes. I'm currently trying to implement scaling of these shapes to maintain their location in reference to the main plot, even when zoomed in.


My objects are represented by a list of vertices,

obj = [(1, 1), (2, 1), (1, 0), (2, 0)] # represents a 1 unit square

of course this is a simplified breakdown of how my polygons are represented, but the only useful attribute of them in this case is the vertices.


The User can select a bounding box of where he would like to zoom in, shown below

enter image description here

Once the mouse is released the application will zoom to that location, the only problem is my polygons do not zoom with this. While the canvas is zoomed, the polygons will remain in their exact location and now represent a whole different area than they did before. This is because the zoom is handled by matplotlib, which is a backend to the actual application. what I would like to do is along the lines of what the picture shows below if the user were to zoom in on the selected location above: enter image description here

So what I do know is

  • The list of vertices of the object [(1,2),(1,0)....]
  • A list of handles to all objects contained inside the bounded zoom targets = [itemHandle1, itemHandle2....]
  • The location of the bounded zoom box via the topleft and bottom right coordinate e.g. zoomboundedbox = [(162, 62), (937, 560)]

I believe I know all the required data about my objects to scale these objects correctly, but I don't know the algorithm that will allow me to accomplish this ...

def receive(self, lim):
'''
Calculate new coordinates of polygons visible to screen, this function
is called when the user releases the mouse button on the zoom function,
the parameters of the bounding box are internally stored as (x,y) tuples
in xyf (x,y first) and xyl (x,y last)
'''

    # Grab all item handles to polygons that intersect with the zoom
    # Stored in `targets`

    for shape in self.activePolygonList:         # loop through active polygons on screen
        if shape.handle() in targets:            # if the polygon is a target to be scaled
            print "scaling...."
            # ?                                   
            shape.redrawShape()
Syntactic Fructose
  • 18,936
  • 23
  • 91
  • 177
  • Take a look at my answer to [_Rotate line around center point given two vertices_](http://stackoverflow.com/questions/14842090/rotate-line-around-center-point-given-two-vertices/14842362#14842362). What I say about rotating them generally applies to scaling them, as well. The formula for translate-scale-untranslate is, of course, a bit different. – martineau Jun 29 '15 at 21:12
  • @martineau Thanks! your post helped a lot, do you have any knowledge on the formula for scaling the image? – Syntactic Fructose Jun 30 '15 at 13:02
  • Syntactic: My linked answer + the modifications suggested would scale all the polygons in the image. It would be the same value for each one of them—so I'm not sure what you mean. In your case, I would think it would just be how much "zoom" you want. If the scale/zoom factor was `2.0`, each polygon would become twice a big as it was. Things are a little more complicated because you effectively want to also implement panning at the same time (due to the zoomboundedbox idea) the image is being zoomed (but the general idea and techniques shown all still apply). – martineau Oct 13 '17 at 17:04
  • In short, what you want to do involves more than just the scaling of the polygon given only a list of their vertices. They also need to be translated to be relative to the zoom boundingbox (which isn't part of their list of vertices). If you edit your question and show how to access the polygon vertices given their "handle", I may be able to formulate a more specific answer than the one currently posted—if you even care about this topic any longer. – martineau Oct 13 '17 at 17:24

1 Answers1

8

As I said in comment, I think you can use something similar to what I did in my answer to Rotate line around center point given two vertices.

The only difference would be that the mathematical formulas to scale a point (x,y) by a factor of S relative to the point (cx, cy) are:

x_new = (  S * (x - cx) ) + cx
y_new = (  S * (y - cy) ) + cy

And these are what determines how the computation of points (p1x, p1y) and (p2x, p2y) from (x1, y1) and (x2, y2) is done in the inner loop.

Another difference might be that you would want to scale all your polygons relative to the center of the user's bounding box rather than the center of each polygon. That would mean you wouldn't have to compute cx and cy for each polygon (which would make it faster).

martineau
  • 119,623
  • 25
  • 170
  • 301