Solved

Implementing an eraser pen?

Posted on 2000-02-28
34
293 Views
Last Modified: 2013-12-03
I'm drawing a curve that is rapidly changing on a background. One method to update the curve is to redraw the whole background and to draw the new curve, but this is fairly slow since the background bitmap is big.

Is there a way I could create an erasing pen that erases the curve by simply drawing over it? The pen would somehow be created using the background bitmap... OR, any faster method to perform this task?
Note, the curve pen is more than 1 pixel thick, and the background bitmap could be any picture, not just a simple filled rectangle.
0
Comment
Question by:gil_mo
  • 14
  • 10
  • 5
  • +2
34 Comments
 
LVL 22

Expert Comment

by:nietod
Comment Utility
If the bacgkground is not a solid color, and it sounds like it isn't, then there is no way to use a simple drawing tool (pen or brush) for this.

However, if you draw the curve using a XOR mode, which is common when "mouse tracking" you can erase the curve again very quickly by redrawing it a 2nd time.   I can elaborate if this is a good posibliity for you.

The other option is to copy the bakground over the curve, but to do this only for the rectanglular section the curve occupies, this will be faster than copying the entire bitmap.
0
 
LVL 22

Expert Comment

by:nietod
Comment Utility
FYI The XOR method is what drawing packages usually use to show objects being drawn in different sizes as the mouse is moved and it is the method windows uses to show a window being moved or resized (unless you have the "drag full windows" option selected).
0
 

Author Comment

by:gil_mo
Comment Utility
nietod,
The XOR method cannot be taken into account for aesthetical reasons; the curve has to be a solid, unicolor pen. the bounding rectangle method requires to calculate the rectangle for every curve and in most cases the rectangle will be just about the whole background's size.

Maybe there is some way in which the bitmap could be 'polylined' back onto the curve, thus erasing it?
0
 
LVL 22

Expert Comment

by:nietod
Comment Utility
Your next best bet is to try to find a series of rectangles that cover the curve but that don't fill the entire area and bitblt over those.  The ideal rectangle is one that is long and thin.  (long in one direction, but not in the other.)  If you know the points that make up the curve, you can start at one end and add points to the rectangle and wait until one dimension exceeds a criticla value, like 8.  Then bitblt the rectangle and continue from that point.  You could also copy individual pixels from the background over the curve, that is easier, but likely to be noticabely slower.  (BitBt() is slow, but it is faster than copy each pixel one-at-a-time.)

Do you know the points in the curve?
0
 
LVL 22

Expert Comment

by:nietod
Comment Utility
Your next best bet is to try to find a series of rectangles that cover the curve but that don't fill the entire area and bitblt over those.  The ideal rectangle is one that is long and thin.  (long in one direction, but not in the other.)  If you know the points that make up the curve, you can start at one end and add points to the rectangle and wait until one dimension exceeds a criticla value, like 8.  Then bitblt the rectangle and continue from that point.  You could also copy individual pixels from the background over the curve, that is easier, but likely to be noticabely slower.  (BitBt() is slow, but it is faster than copy each pixel one-at-a-time.)

Do you know the points in the curve?
0
 
LVL 22

Expert Comment

by:nietod
Comment Utility
Your next best bet is to try to find a series of rectangles that cover the curve but that don't fill the entire area and bitblt over those.  The ideal rectangle is one that is long and thin.  (long in one direction, but not in the other.)  If you know the points that make up the curve, you can start at one end and add points to the rectangle and wait until one dimension exceeds a criticla value, like 8.  Then bitblt the rectangle and continue from that point.  You could also copy individual pixels from the background over the curve, that is easier, but likely to be noticabely slower.  (BitBt() is slow, but it is faster than copy each pixel one-at-a-time.)

Do you know the points in the curve?
0
 
LVL 30

Accepted Solution

by:
Zoppo earned 200 total points
Comment Utility
Perhaps following is a suitable option for you:

Create a path from the curve using BeginPath()/EndPath().
Create a region from that path using PathToRegion()
Get the bounding box of the region with GetRgnBox()
Select the region as clipping region and bitblt the bounding box from the bitmap to screen.

ZOPPO
0
 
LVL 22

Expert Comment

by:nietod
Comment Utility
Maybe.  Its possible that it would be faster to do the BitBlt without that clipping region.  i.e. bitblt the whole thing with no clipping.  (I'm not sure this is true, you'd have to test, but windows is pretty bad in its handling of non-rectangular regions.)
0
 
LVL 11

Expert Comment

by:mikeblas
Comment Utility
This is an ideal application for double-buffering. Just select your background bitmap into a memory DC, then draw the curve on it, then blit it all to the screen each time you need to update.

..B ekiM
0
 
LVL 10

Expert Comment

by:RONSLOW
Comment Utility
even faster, only blt the section of the window that has changed.
0
 

Author Comment

by:gil_mo
Comment Utility
Mike,
It's *that* blitting of the whole bkg from the mem DC to the screen DC that takes time. The curve is updated upon WM_MOUSEMOVE, for example, or upon WM_TIMER every 20 milliseconds.
0
 
LVL 10

Expert Comment

by:RONSLOW
Comment Utility
That is why you only need to blt the part that has changed.  You can determine the area that is dirty by calling ClipBox.

Also are you currently double-buffering the drawing (ie. bitblt background to another bitmap, then draw onto the bitmap and blt that onto the screen).  This is usually much smoother.

I assume you aren't doing something silly like re-reading the bitmap from a file every loop.

Also are you sure it is the background blt that is taking the time and not the curve?

If you want an eraser, then create another (monchrome) bitmap and draw into that, then use it as a mask.  You can then use bitblting to copy only those pixels that were in the curve back to the screen (ie rubbing it out).
0
 

Author Comment

by:gil_mo
Comment Utility
Adjusted points to 75
0
 

Author Comment

by:gil_mo
Comment Utility
RONSLOW,
Can you please elaborate on your suggestion using a monochrome mask? I tried figuring it out but it seems just as time consuming...

"blt the part that has changed": this part is mostly very close to being the whole background...
0
 
LVL 10

Expert Comment

by:RONSLOW
Comment Utility
Making the monochrome maks involves creating a monchrome bitmap of the same size as the background one and drawing your curve onto it.

Under Win2000/NT, you can then use MaskBlt to blt from ont bitmap to another onle where the mask is set.

However, unless you have WinNT/2000, you cannot use MaskBlt and have to emulate it with multiple BitBlt calls.  And to avoid flashing you'd need to do it offscreen.  So for Win95/98, this is probably going to be slower that simply redrawing the background and repainting the curve - especially if you do that offscreen anyway - its just two BitBlt's.


0
 

Author Comment

by:gil_mo
Comment Utility
Adjusted points to 100
0
 

Author Comment

by:gil_mo
Comment Utility
It seems like Zoppo's suggestion might be suitable, if there were a way to blit the bitmap into the region (NOT the bounding rect of the region). Is this possible? I'll add 50 pts + A to the supplier of a correct code snippet.
0
Highfive Gives IT Their Time Back

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 
LVL 11

Expert Comment

by:mikeblas
Comment Utility
gil_mo> or upon WM_TIMER every 20 milliseconds.

How big is the rectangle?

..B ekiM
0
 
LVL 10

Expert Comment

by:RONSLOW
Comment Utility
Zoppo seems to be suggesting the same as Nietod.

To bitblt into the region you'd need to either set up a mask and use that (unless you know it will be WinNT/2000 that's a lot of blts), or set up a clipping region (which probably won't help much anyway as the same amount of blting work would still be happening AFAIK).

I still think that blt and draw offscreen is the way to go.  Especially as you said that the curve's bounding rect will almst always be the entire window.

0
 

Author Comment

by:gil_mo
Comment Utility
Mike,
Ok, the timer is set to about 50 mSec. The rectangle could be as big as about 350x220 .

RONSLOW,
Drawing offscreen will eventually involve the blitting of the whole rect onto the screen. This will only save the time difference between drawing the curve offscreen and drawing the curve onscreen.
0
 
LVL 11

Expert Comment

by:mikeblas
Comment Utility
> The rectangle could be as big as about 350x220

Then I still think double-buffering is your best bet.


To initialize:
1) Create a bitmap of the background.

To draw:
1) Create a memory DC
2) Select the bitmap
3) Draw on it
4) Blit it over

..B ekiM
0
 
LVL 10

Expert Comment

by:RONSLOW
Comment Utility
qil_mo:
using an offscreen buffer does involve an extra blt .. but is much smoother.  Otherwise you see the curve flashing and drawing etc.  not very pretty.
0
 

Author Comment

by:gil_mo
Comment Utility
RONSLOW,
The smoothness was never the issue in this question, but time. My initial implementation was using an offscreen blitting - the time consumption is still large.

Mike,
Comparing your suggestion to the onscreen option, we get:

Having Onscreen and offscreen begin with a DC and a memDC:

1. Onscreen: selecting the bitmap, copying it into DC.
   Offscreen: selecting bitmap, copying it into memDC.

2. Onscreen: drawing a curve on the DC.
   Offscreen: drawing a curve on memDC.

3. Onscreen: Nothing.
   Offscreen: Blitting from memDC to DC.

Total: Onscreen: Blitting bitmap to DC, drawing curve on DC.
       Offscreen: Blitting bitmap to memDC, drawing curve on memDC, blitting bitmap to DC.

As you can see, the *only* time gain we get using the offscreen implementation is the difference between drawing the curve onscreen and offscreen, as I had written before (this is questionable though, since in the offscreen implementation there's an additional blitting into memDC but never mind that.)

Mike, the time consumption is beyond the off/onscreen solution, as the massive blitting (offscreen step 3 above) is a big time consumer. If there is no way to blit *only* the path that was drawn (curve), maybe there simply *isn't* any solution?
:(
0
 
LVL 11

Expert Comment

by:mikeblas
Comment Utility
You've forgotten a step:

4: Onscreen: work up some complex and expensive algorithm to erase the line

   Offscreen: absolutely nothing!


I've offered you all the help I can.  Good luck with your project.

..B ekiM
0
 

Author Comment

by:gil_mo
Comment Utility
NO Mike, this is covered in step 1: blitting a fresh copy of the bitmap onto the DC.

And as I said, I was using the offscreen method prior to this question (I always do). The time consumption is still in there.

Thanks for your help!!

Gil.
0
 
LVL 22

Expert Comment

by:nietod
Comment Utility
gil_mo, drawing operations that go on off screen are often much faster than the same drawing operations performed on-sreen.  (It depends on lots of hardware-dependant factors though.)  So you can't just compare the number of steps, you need to look at the fact that some of the steps may go much faster.  For example, in your case if steps 1 and 2 are enough faster in memory they can save time even though you have the extra step 3.
0
 

Author Comment

by:gil_mo
Comment Utility
Please nietod, step 3 offscreen is exactly the same as step 1 onscreen.
Please read through my March 07 2000 - 09:42PM comment carefully.
0
 
LVL 22

Expert Comment

by:nietod
Comment Utility
How is the curve being defined?  If you know the mathematics behind it, you can update a couple of rectangles narrow that intersect the curve, like I suggested before.
0
 

Author Comment

by:gil_mo
Comment Utility
Adjusted points to 200
0
 

Author Comment

by:gil_mo
Comment Utility
The curve is a very wavy one. Leave this method. As I said before, the BeginPath method seems like a good start, but how do I continue from there?
0
 
LVL 22

Expert Comment

by:nietod
Comment Utility
From zoppo

Create a path from the curve using BeginPath()/EndPath().
Create a region from that path using PathToRegion()
Get the bounding box of the region with GetRgnBox()

Select the region as clipping region and bitblt the bounding box from the bitmap to screen.

But that might not be very fast, but it is worth a try.  Do you have questions about any of those steps?   Creating the path might be the biggest challenge there.  how are you drawing the curve?
0
 

Author Comment

by:gil_mo
Comment Utility
From: gil_mo
"It seems like Zoppo's suggestion might be suitable, if there were a way to blit the bitmap into the region (NOT the bounding rect of the region)."

As I already wrote, the bounding rectangle of the curve will be always close to the whole bitmap.  

Curve is drawn by Polyline(). So first two steps can be done easily.
0
 
LVL 22

Expert Comment

by:nietod
Comment Utility
>> if there were a way to blit the bitmap into the
>> region (NOT the bounding rect of the region)."

BitBlt() must be passed rectangular sections to copy, but what is actually copied will be limited by the destination's clipping region.  Zoppo is hoping that by specifying a small enough clipping region the BitBlt() will work faster as it will have less points to copy. (It doesn't actually copy the portions that are outside the clipping region even if they are in the rectangle you specify.  So this might be faster.  Although the region calculations might eat up the savings and then some, but it is worth trying.  I would be pretty confident that if you specify a huge rectangle to copy and have a small rectangular clipping region, the copy would go at about the speed as if you had just copied the small rectangle.  The question is what will happen when the clipping region is not a simple rectangle?
0
 

Author Comment

by:gil_mo
Comment Utility
Actually there is no need to convert to a region. SelectClipPath can be used for this matter.

Nietod, thanks for clarifying Zoppo's answer.

Zoppo, I haven't tried it yet to see if it works, but the idea is brilliant.
0

Featured Post

How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

Join & Write a Comment

In this article, I will show how to use the Ribbon IDs Tool Window to assign the built-in Office icons to a ribbon button.  This tool will help us to find the OfficeImageId that corresponds to our desired built-in Office icon. The tool is part of…
For most people, the WrapPanel seems like a magic when they switch from WinForms to WPF. Most of us will think that the code that is used to write a control like that would be difficult. However, most of the work is done by the WPF engine, and the W…
This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA. http://www.experts-exchange.com/videos/1478/Excel-Error-Handlin…
In this tutorial you'll learn about bandwidth monitoring with flows and packet sniffing with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're interested in additional methods for monitoring bandwidt…

771 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

13 Experts available now in Live!

Get 1:1 Help Now