Interactive digitization of a map

Hello,

I am developing an application which can be used for digitize a geographical map through GUI and mouse interaction. Well, here are the list of objects that need to be created using mouse clicks.

  1. Points
  2. Polyline
  3. Polygon
  4. Rectangle/Square
  5. Ellipse/Circle
  6. Text

Drawing points on mouse click is very easy and I was able to do it. I am wondering how to go ahead with drawing polyline. Is it necessary that after every mouse click, canvas has to be refreshed? I mean to ask, now suppose I have drawn two points, and now I am going to draw third point. Once mouse click takes place for third point, I say

canvas->Refresh();

As far as my understanding, when this function is invoked, all the OnPaint() method gets executed and thus first two points also get rendered. Am I right? Now since the number of points (or objects in general) is less, it works fine. If there are millions of objects, then won’t the rendering performance come down? If yes, then is there any way, to keep the previous objects intact(without rendering) and only new object should be rendered?

Sorry for such a long question. But this issue is very critical for me to progress.

Thanks in advance

Regards
Rakesh Patil

Indeed you have to redraw everything, every frame.
Provided you group coordinates data in buffers, it should stay fast. For millions of objects, it will start to slow down of course.
There are possible tricks such as render everything static to a texture once, and for every subsequent frame, simply draw a texture quad + the points being currently dynamically edited.

Hi ZbuffeR,

Thanks for your reply. Can you explain me a bit more?

There are possible tricks such as render everything static to a texture once, and for every subsequent frame, simply draw a texture quad + the points being currently dynamically edited.

If I render everything static, then how can it be edited dynamically? What are the possible tricks can you tell me?

Thanks again

By edit do you mean move and/or delete? If you do, you have to re-render after the edit. (This not because you are using OpenGL the same would be true with GDI).

For moving a line segment, the way I do this is

  1. on button down, find the line segment selected (you need to keep a list of line segments somewhere)

  2. render everything except this line segment

  3. capture the frame buffer

  4. while the mouse moves
    a) render the captured buffer to the frame buffer
    b) render the modified line segment

  5. when button up, render everything including the modified segment

For adding a line segment

  1. render the prevoiusly captured frame buffer

  2. render the new line segment

  3. capture the frame buffer for next action

The most difficult tasks are deciding what have been selected and scrolling the view window while a line segment is edited (this requires redrawing the captured frame buffer to reflect the changed view data)

Dear Tonyo_au,

By edit do you mean move and/or delete?

Yes by editing, I do mean to move and/or delete.

  1. while the mouse moves
    a) render the captured buffer to the frame buffer
    b) render the modified line segment

Capturing frame buffer is understood. But the above two points which you mentioned is slightly breaking up my head. Can you explain me bit more how to do that? A small example(piece of code) will be easy to understand.

Thanks

Hi,

I did some R & D searching for what you suggested. I guess I need to use these two functions


glReadBuffer(GL_BACK);
glDrawBuffer(GL_BACK);

Isn’t it? But glDrawBuffer must be called before rendering function. And my rendering function draws all the objects. You are telling to display only captured buffer. So how do I do that?

Thanks in advance.

Ok, I was a bit quick there. Lets assume you are not using multisampling for the moment to keep it a bit simpler.

To capture the buffer to a texture we do


glReadBuffer(GL_BACK);
glReadPixels(0, 0, window_width, window_height, GL_RGBA, GL_UNSIGNED_BYTE, buffer);

now while you draw the line you repeat something like this

to copy the captured data back we need a texture buffer


glGenTextures( 1, &texture_id );
glBindTexture( GL_TEXTURE_2D, texture_id );
glTexImage2D( c_GL_TEXTURE_2D, 0, RGBA,  window_width, c_Height, 0, RGBA, GL_UNSIGNED_BYTE,buffer);  // load data into a texture
// bind and render this texture
glActiveTexture(GL_TEXTURE0);

glBegin(GL_QUADS);
glTexCoord2d(0.0,0.0); glVertex2i(0,0);
glTexCoord2d(1.0,0.0); glVertex2i(window_width,0);
glTexCoord2d(1.0,1.0); glVertex2i(window_width,window_height);
glTexCoord2d(0.0,1.0); glVertex2i(0,window_height);
glEnd();

now draw you line.

If you know how to use frame buffers this can be done a lot more efficiently by blitting the back buffer to a frame buffer and then using this frame buffer instead of the texture.
The frame buffer must have the same dimensions as the window and have the same sampling level.

checkout glBlitFramebuffer

Hi Tonyo_au,

So, it’s like when an object is moved, the current window texture is generated and is displayed, and only the object under the mouse is refreshed every time is it? that means I need to have two different display functions. One to display all objects and second to display objects being edited. Am I right?

Yes that’s right. The trade-off here is faster rendering but more code

Hi Tonyo_au,

Where exactly this piece of code should be written?

glReadBuffer(GL_BACK);glReadPixels(0, 0, window_width, window_height, GL_RGBA, GL_UNSIGNED_BYTE, buffer);


glGenTextures( 1, &texture_id );
glBindTexture( GL_TEXTURE_2D, texture_id );
glTexImage2D( c_GL_TEXTURE_2D, 0, RGBA,  window_width, c_Height, 0, RGBA, GL_UNSIGNED_BYTE,buffer);  // load data into a texture
// bind and render this texture
glActiveTexture(GL_TEXTURE0);


glBegin(GL_QUADS);
glTexCoord2d(0.0,0.0); glVertex2i(0,0);
glTexCoord2d(1.0,0.0); glVertex2i(window_width,0);
glTexCoord2d(1.0,1.0); glVertex2i(window_width,window_height);
glTexCoord2d(0.0,1.0); glVertex2i(0,window_height);
glEnd();

In mouse click down event or OnPaint() event?