Solved

Implementing an eraser pen?

Posted on 2000-02-28
34
303 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
ID: 2564663
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
ID: 2564676
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
ID: 2564708
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
Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

 
LVL 22

Expert Comment

by:nietod
ID: 2564840
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
ID: 2564847
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
ID: 2564856
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 31

Accepted Solution

by:
Zoppo earned 200 total points
ID: 2564978
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
ID: 2565000
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
ID: 2566551
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
ID: 2567679
even faster, only blt the section of the window that has changed.
0
 

Author Comment

by:gil_mo
ID: 2567956
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
ID: 2568214
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
ID: 2575683
Adjusted points to 75
0
 

Author Comment

by:gil_mo
ID: 2575684
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
ID: 2578269
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
ID: 2584486
Adjusted points to 100
0
 

Author Comment

by:gil_mo
ID: 2584487
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
 
LVL 11

Expert Comment

by:mikeblas
ID: 2585342
gil_mo> or upon WM_TIMER every 20 milliseconds.

How big is the rectangle?

..B ekiM
0
 
LVL 10

Expert Comment

by:RONSLOW
ID: 2585940
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
ID: 2586575
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
ID: 2594204
> 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
ID: 2594483
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
ID: 2594775
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
ID: 2594803
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
ID: 2594842
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
ID: 2595811
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
ID: 2595924
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
ID: 2596203
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
ID: 2596306
Adjusted points to 200
0
 

Author Comment

by:gil_mo
ID: 2596307
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
ID: 2596442
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
ID: 2596554
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
ID: 2596882
>> 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
ID: 2600245
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

Announcing the Most Valuable Experts of 2016

MVEs are more concerned with the satisfaction of those they help than with the considerable points they can earn. They are the types of people you feel privileged to call colleagues. Join us in honoring this amazing group of Experts.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

This article shows a few slightly more advanced techniques for Windows 7 gadget programming, including how to save and restore user settings for your gadget and how to populate the "details" panel that is displayed in the Windows 7 gadget gallery.  …
This article describes a technique for converting RTF (Rich Text Format) data to HTML and provides C++ source that does it all in just a few lines of code. Although RTF is coming to be considered a "legacy" format, it is still in common use... po…
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…
A short tutorial showing how to set up an email signature in Outlook on the Web (previously known as OWA). For free email signatures designs, visit https://www.mail-signatures.com/articles/signature-templates/?sts=6651 If you want to manage em…

790 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