Simultaneous zooming graphical objects on an Timage object


When a graphical object, like a TPolyline object , is drawn on top of an Timage object, the TPolyline object does not zoom in/out at the at time as the Timage object on a pad.

It apears that I have to reimplement the ExecuteEvent method to do this.

Does any one have a suggestion or a simple example showing how this can be done?



Have a look to the example $ROOTSYS/tutorial/rose_image.C .
This example shows how to draw a line on top of a TImage in a way it will be zoomed when you zoom the image.

Hi Couet,

I have had a good look at the Rose_Image.C example before. However, the additional polygonal objects I need to draw on the TImage need to have the DistanceToPrimative function and its own unqueID, so that when I move the cursor over them, I can instantly identify these objects; delete or move them if I want.

In the Rose_Image.C example, as I understand it, “objects” drawn using TImage::DrawPolyLine do not offer those properties: I can not give it an ID; I can not delete or move them. Am I correct in making those statements?

Thanks for your reply.


In fact the zooming ability of the TImage is handled by the ExecuteEvent method of TImage itself. And only the Timage is zoomed.


When a graphical object, like a TPolyline object , is drawn on top of an Timage object, the TPolyline object does not zoom in/out at the at time as the Timage object on a pad.

It apears that I have to reimplement the ExecuteEvent method to do this.

Does any one have a suggestion or a simple example showing how this can be done?


Tim[/quote]What you should do is to implement your own “CustomCatchSelector” class to catch all mouse movements and redestribute it as needed. Check method … ToggleZoom where such approach was employed.
Pay your attention to the piece of the code there:

if (o && o->InheritsFrom(Class()->GetName())) { // Find axis if (o != l->Last()) { // make sure the TAxis3D is the last object of the Pad. l->Remove(o); l->AddLast(o); }I used to describe this technique on roottalk but can not find the proper link :frowning:

Hi valerie,

I don’t quite fully understand your suggestion.

Are you suggesting that I should somehow find a way to iterate through a list of Primitives and do something about it?

Can you provide a bit more details? Please.

I don’t know what “CustomCatchSelector” is. Sorry!!!


[quote=“timtran”]Hi valerie,

I don’t quite fully understand your suggestion.

Umm :unamused: It seems to me I can offer you a simpler solution.
I do not know what the problem you are fighting with is. :question: It may not fit your needs though :frowning:

The idea is
at some point you did something like this

create :bulb: a small proxy class

[code]class TObjectHolder : public TObject {
TObject *fObject;
TObjectHolder(TObject *o=0) : fObject(o) { SetBit(kCanDelete); }
virtual const char *GetName() const { return fObject ? fObject->GetName(); }

 virtual const char *GetTitle() const { return fObject ? fObject->GetTitle(); }

// … etc may be some other TObject method shoudl be here too, check !!!
virtual void Paint(Option_t *option){ if (fObject) fObject->Paint(option); }
virtual Int_t DistancetoPrimitive(Int_t px, Int_t py){ return 99999;}
};[/code] and use it instead of the object->Draw

TObjectHolder *wrapper = new TObjectHolder(myImageObject); wrapper->Draw();
This may not work for the TGeoShape’s and may be some other new 3D geometry classes but I should be Ok for any classic ROOT class.

Be aware the idea is brand new I did not check it :blush:

Hi Valerie,

Thanks for the example code.

As I am still a newbie in c++, I will try to see if I understand your sample code first. Hopefully, I can adapt it for my task.

Attached is an example that may help explain what I want to do. I read in an image (rose512.jpg borrowed from root tutorials). I draw a square polyline object on top of the image. Each polyline object display its own ID when clicked.

You can see when I zoom in/out of the image, the size of the square stay the same size. I want the square to be zoomed as well at the same time.

In a real situation, I will draw thousands of small polyline objects on an image, each one has its own region of interest ID; I may want to delete some regions.

Hope this explain what my task.


rose_image_mod.C (1.29 KB)

Ok, I think I undertstand.
You have to re-implement the “ExecuteEvent” rather “DistanceToPrimitives” (keep reading :smiley: ; )

You want the functionality provided by … escription class but for more simple 2D case, don’t you?

You want to be able interactively change the TPad viewport ( X/Y world coordinate scales and preserve the TPad pixel size) that would automatically lead to the zoom in /zoom out operations.

This is exactly what TAxis3D class does for 3D objects.

This means we have to go back to my first advice.
In fact, the class in question looks quite generic and it may eventually become a part of the ROOT.

One should:
[ul] 1. Create a new class derived from TObject with the dummy Paint() method (this means the Draw method does not entail any real graphical image on the screen)
2. Make sure the object place itself at the end of the ListOfPrimitives
3. DistancetoPrimitive should return ZERO to insure TPad ALWAYS picks the object
4. ExecuteEvent method should draw the rubber bands and change the TPad viewport.
5. Since TImage is not “standard” TObject. I suspect (may be TImage class author can confirm this statement) it is not aware about TPad world coordinate system, your ExecuteEvent method (see above) should detect the TImage object among others (this means it should analyze the TPad ListOfPrimitives) and treat it specially [/ul]

Of course, this functionality can be provided by the TImage::ExecuteEvent also The TImage can already draw the “rubber bands”, so the only thing one has to add is the TPad world scale adjusting. :smiley:. However the later looks quite tricky and TPad zoomming will always require the TImage object to zoom the arbiratry set of the promitives.


Thanks for the detailed explanation.

Yes. I need a solution for the 2D case instead of the 3D case.

I can see it will not be a simple task.


try TCanvas::SetCanvasSize method for zooming.

Regards. Valeriy

[quote=“Valeriy Onuchin”]try TCanvas::SetCanvasSize method for zooming.[/quote]Do you mean the mouse pointer should “try” :unamused: calling that C++ method ? Anyway we are speaking about the solution on TPad level.

The topic was
"simultaneous zooming graphical objects on an Timage object"

My solution helps to do it.

In my opinion we need to add zooming on “more general level”,
i.e. to add possibility “to zoom” any object, not only timages.

[quote=“Valeriy Onuchin”]My solution helps to do it.[/quote]The question was

The answer is “yes”, one should implement either his/her own class or re-implement some existent ExecuteEvent and the SetCanvasSize may help for single pad TCanvas.

Sure, “zooming”/“rotation”/“shifting” are just a special coordinate transformations of TPad viewport.
(see for example the slide 18 (XForm widget) … orldMatrix . Meantime as a workaround the ROOT user can provide his/her own custom TObject. This will work for any ROOT version (including the future ones, assuming the ROOT object model is stable of cource ).

In the CVS version, I have implemented the possibility to zoom other objects than TASImage. It would be nice if you could try the CVS version and let me know the result in your case.


Thanks everyone for all suggestions.

I apologize for the delayed response as I have been away.

I will try all the suggestions in the last few responses.



I tested Rene’s modification to ExecuteEvent method. It is doing what I requested: Non-TImage objects are zoomed simultaneously with the TImage object.

However, there may be two issues:

  1. Repeated moving and zooming the non-TImage object gives eroneous result.

To demonstrate the eroneous effect, run the previously attached macro “rose_image_mod.C”; change the location of the square ROI slightly with the mouse, then select a region enclosing the square for zooming. It will zoom properly after the first move. However, if the square is moved the SECOND time and zoomed again as before, the square and the TImage will be zoomed with different ratio and/or center.

I am running RHEL 4 on a DELL PC (Latitude D410).
Root version:CVS ROOT 5.11/01.

  1. The second possible issue is that the non-TImage objects use the TPad as the “bounding box”, rather than the TImage itself. Idealy, parts of the non-Timage objects should not be displayed if they extend beyond the limits of the TImage when zoomed in.

For example, select a region for zooming that includes a part of the square in the rose_Image_mod.C example. One will notice the square will be displayed beyond TImage object.

Otherwise, the requested additional functionality is provided nicely by Rene’s implementation. I guess similar functionailty can be applied to PixelMap.