Re: Scaling of data into dc
- From: Joseph M. Newcomer <newcomer@xxxxxxxxxxxx>
- Date: Mon, 14 May 2007 09:42:04 -0400
It should scale up and down, I'll have to investigate this. I know I've used it
successfully,but my code was not nearly as convoluted as this code is.
For other comments, see below...
On Mon, 14 May 2007 14:38:35 +0200, Matthias Pospiech <matthias79@xxxxxx> wrote:
Short summery: Skaling up works as expected, scaling down shows only the****
fraction windowsize/Datasize which I do not understand at all.
Joseph M. Newcomer schrieb:
First I have to say that the whole class CMemDC is not my product, soI do apply these commands to the dc of MemDC (so it is inside the MemDC*****
class), and not to the dc of the window like it is done in your example,
see also code at the end.
So what does
SetMapMode(pDX->GetMapMode())
really do? Since SetMapMode is a method of a DC, it would have to be written as
dc.SetMapMode(pDX->GetMapMode());
which would set the map mode of the 'dc' to the map mode of some other DC. But here you
have not said which DC is which, so your code is hard to understand, and it is not clear
why you would set the mapping mode of the memory DC to be the mapping mode of the window
DC, or set the extent and size of the memory DC to be the same as the extent and size of
the window DC. Since the meanings of m_rect_dest and m_rect_source are not specified, the
code is moderately incomprehenisible at best.
please do not blame me for its content. It is written by Keith Rule and
the example for doing flickerfree drawing (I was pointed to this class
several times).
pDC inside CMemDC is the memoryDC, wheras m_pDC is the dc of the window.
The meaning of m_rect_source and m_rect_dest is the Rect of the data to
draw and the Rect of the window to draw into.
To create a bitmap, you would create a bitmap the same size as the client area of the
window.
m_bitmap.CreateCompatibleBitmap(pDC,
m_rect_dest.Width(),
m_rect_dest.Height());
This is a bitmap of the size of the window (m_rect_dest is equal to rect
of GetClientRect)
You would create a memory DC and select the bitmap into it.You mean:
CreateCompatibleDC(pDC);
You would then set
the viewport extent to be the dimensions of the bitmap and the window extent to be the
logical coordinate system. For example, if you drew a line from coordinates 0,0 to
1000,1000, you would SetWindowExt(1000, 1000); and if your window was 300x300 you would
SetViewportExt(300,300). Scaling will then be automatic.
So that would be
pDC->SetMapMode(MM_ANISOTROPIC);
// Data source
pDC->SetWindowExt(m_rect_source.Width(), m_rect_source.Height());
// Window Size
pDC->SetViewportExt(m_rect_dest.Width(), m_rect_dest.Height());
I believe that is correct. I usually have to think carefully about scalling to get the
parameters correct.
*****
****I understand.
There's a bit more to all of this if the window and viewport are small, so to avoid ugly
roundoff artifacts you sometimes want to set the window extent to be a multiple of the
scale and scale to larger logical values.
*****Bitmap has the same dimensions:
So for double buffering, you set the Viewport extent to be the dimensions of the bitmap.
****
m_bitmap.CreateCompatibleBitmap(pDC, m_rect_dest.Width(),
m_rect_dest.Height());
Is what I am doing not exactly this ?********BitBlt is necessary for the double buffering.
Yes, that's right. It is not clear you even need the extra MemDC and the BitBlt, unless
you have other reasons for doing this
*****
Then scale your MemDC
****
But if your window is scaled, you get additional complications. So if you want to be
sure, you will need to set the mapping mode of the target DC to MM_TEXT before doing the
BitBlt. Otherwise, you may be seeing some of the problems you are reporting. BitBlt
works in logical coordinates, and if there is a mapping mode on the window DC, BitBlt will
copy things in terms of logical coordinates, not physical coordinates. You should be able
to say
ASSERT(m_pDC.GetMapMode() == MM_TEXT);
and it should not assert.
*****
****
So with the following code using your instructions it now does scale up,
but if the data is greater than the windowsize it does not show the
whole content:
It does scale correct, but shown is only a part of the whole image. If
the data has twice the value, on the screen is only a fourth and if the
data is three times (so lets say 300x300) the screen shows of the window
with size (100x100) only 33x33 so the division of the two.
And that was my problem I already had with the StrechBlt Code.
--------------------------------------
class CMemDC : public CDC {
private:
CBitmap m_bitmap; // Offscreen bitmap
CBitmap* m_oldBitmap; // bitmap originally found in CMemDC
CDC* m_pDC; // Saves CDC passed in constructor
Choosing a better name for this, like m_pTargetDC, would make the code a lot clearer.
****
CRect m_rect_dest; // Rectangle of drawing area.****
CRect m_rect_source; // Rectangle of source area.
BOOL m_bMemDC; // TRUE if CDC really is a Memory DC.
public:
CMemDC(CDC* pDC, const CRect* pSourceRect = NULL, const CRect*
pDestRect = NULL) : CDC()
{
ASSERT(pDC != NULL);
// Some initialization
m_pDC = pDC;
m_oldBitmap = NULL;
m_bMemDC = !pDC->IsPrinting();
// Get the rectangle to draw
if (pDestRect == NULL) {
pDC->GetClipBox(&m_rect_dest);
} else {
m_rect_dest = *pDestRect;
}
// Get the rectangle to draw
if (pSourceRect == NULL) {
pDC->GetClipBox(&m_rect_source);
} else {
m_rect_source = *pSourceRect;
}
if (m_bMemDC) {
// Create a Memory DC
CreateCompatibleDC(pDC);
pDC->LPtoDP(&m_rect_dest);
m_bitmap.CreateCompatibleBitmap(pDC, m_rect_dest.Width(),
m_rect_dest.Height());
m_oldBitmap = SelectObject(&m_bitmap);
//SetMapMode(pDC->GetMapMode());
pDC->SetMapMode(MM_ANISOTROPIC);
//SetWindowExt(pDC->GetWindowExt());
pDC->SetWindowExt(m_rect_source.Width(), m_rect_source.Height());
//SetViewportExt(pDC->GetViewportExt());
pDC->SetViewportExt(m_rect_dest.Width(), m_rect_dest.Height());
pDC->DPtoLP(&m_rect_dest);
SetWindowOrg(m_rect_dest.left, m_rect_dest.top);
} else {
// Make a copy of the relevent parts of the current DC for printing
m_bPrinting = pDC->m_bPrinting;
m_hDC = pDC->m_hDC;
m_hAttribDC = pDC->m_hAttribDC;
}
// Fill background
FillSolidRect(m_rect_dest, pDC->GetBkColor());
}
~CMemDC()
{
if (m_bMemDC) {
//m_pDC->StretchBlt(
// m_rect_dest.left, // x-coord of destination upper-left corner
// m_rect_dest.top, // y-coord of destination upper-left corner
// m_rect_dest.Width(), // width of destination rectangle
// m_rect_dest.Height(), // height of destination rectangle
// this, // handle to source DC
// 0, // x-coord of source upper-left corner
// 0, // y-coord of source upper-left corner
// m_rect_source.Width(), // width of source rectangle
// m_rect_source.Height(), // height of source rectangle
// SRCCOPY);
m_pDC->BitBlt(
m_rect_dest.left, // x-coord of destination upper-left corner
m_rect_dest.top, // y-coord of destination upper-left corner
m_rect_dest.Width(), // width of destination rectangle
m_rect_dest.Height(), // height of destination rectangle
this,
m_rect_dest.left, // x-coord of destination upper-left corner
m_rect_dest.top, // y-coord of destination upper-left corner
SRCCOPY);
//Swap back the original bitmap.
SelectObject(m_oldBitmap);
} else {
// All we need to do is replace the DC with an illegal value,
// this keeps us from accidently deleting the handles associated with
// the CDC that was passed to the constructor.
m_hDC = m_hAttribDC = NULL;
}
}
// Allow usage as a pointer
CMemDC* operator->()
{
return this;
}
// Allow usage as a pointer
operator CMemDC*()
{
return this;
}
};
Was copied from somewhere else, but I understand why you are surprised.****
------------ Painting in the overloaded CStatic Class
void CGraphCtrl::OnPaint()
{
CPaintDC dc(this); // device context for painting
CRect (rc_dest);
What's with the unnecessary parentheses? I'm surprised this even compiles!
****The reason is that I can use the function as a parameter elsewhere.
rc_dest=GetSize();*****
THis seems a remarkably clumsy way to write
GetClientRect(&rc_dest);
It is just a wrapper that is true.
*****I understand your concerns and I do know enough C++ to understand why
CRect (rc_source);*****
This is not a declaration; it is a constructor that creates a rectangle, initializes it to
the values in rc_source, then discards it completely. Learning C++ syntax will be a major
step in the right direction.
*****
this should be written differend.
Mostly because it appears that this way is wrong. I see a CRect constructor creating a
temporary CRect, iniitialiing it to rc_source, and then discarding it entirely.
CRect rc_source;
would declare a variable.
*****
*****
They return the size of the data (in difference to the window size).rc_source=GetPlotDataSize();*****
A clumsy way to write the code of the function that is called; and what are the meanings
of those numbers in that function?
*****
They are set with
----------
void CGraphCtrl::SetPlotDataSize(const int x, const int y)
{
PixelNumber.x = x;
PixelNumber.y = y;
if ((x>=0) && (y>=0))
{
PlotData.resize(PixelNumber.x);
for(int x = 0; x < PixelNumber.x; x++)
PlotData[x].resize(PixelNumber.y);
}
}
This code seems a bit odd. What is the representation here? What is the resize method
doing? There are massive pieces of missing information.
Given the point seems to be that this creates a new bitrmap, why doesn't it just create a
new bitmap?
*****
----------*****
Fixed. I probably have just copied the pDC, it is no pointer so you are****
CMemDC pDC(&dc,&rc_source, &rc_dest); // Double Buffering
Since this is not a pointer to a DC, why are you using the HN that indicates it is a
pointer? If you do not understand Hungarian Notation, DON'T USE IT AT ALL!!!!!
*****
right.
good question, have changed it to &.*****
PlotToDC(& pDC);
You have a perfectly good DC. Why are you taking the & of it?
*****
****I am not a C++ guru. I thought it would be standard to declare at the
{*****
COLORREF c;
Since 'c' is not used until the inner part of the loop, why declare it out here?
top of a function.
The methodology of declaring things at the top of a function died with Pascal. C never
required this; it only requires declarations be at the start of a block. Therefore, what
I'm suggesting is both valid C and valid C++. C++ additionally allows declarations
anywhere, without the top-of-block restriction.
It is good policy to declare as late as possible, with the smallest possible scope.
*****
**********
Have not thought of that.if ((m_PixelNumberX>0) && (m_PixelNumberY > 0))****
This test seems unnecesary since the for loops already do nothing if the values are 0. So
why add a pointless test to the computation?
*****
*****I do believe you, but I did not get anywhere the answer how to do it
c=PlotData[ix][iy];*****
pDC->SetPixel(ix,iy,c);
This is going to be REALLY SLOW! Why not just copy the data directly into the bitmap?
different...
Sizes range from 128x128 to 1024x1024.
Performance doesn't matter until it matters, then it matters a lot. In this case, doing
SetPixel calls is known to be unbelievably slow, and should be avoided unless you are
dealing with really tiny bitmaps.
*****
1024x1024 is a million pixels. SetPixel will take many, many seconds to copy a bitmap
this size. The delay will be noticeable and aggravating.
*****
*****It however does compile, so I was not pointed at this error.-------------- Sizes*****
CRect CGraphCtrl::GetSize()
{
CRect rc;
GetClientRect(rc);
return rc;
}
This whole functions eems pointless (it is also syntactically incorrect, since the correct
call is
GetClientRect(&rc);
and what you wrote should not even compile.
*****
How else should I create the rect of my datasize ?--------------*****
CRect CGraphCtrl::GetPlotDataSize() // Size of dataarray to be plotted
{
CRect rc(0,0,m_PixelNumberX, m_PixelNumberY);
return rc;
}
This seems equally unnecessary.
not my code, so please do not blame me...============== MemDC class*****
class CMemDC : public CDC {
private:
private is usually a bad idea. Use protected in most cases
[...]
*****This is the concept of the whole class. As long as the class instance is
Why is a destructor doing a BitBlt? This seems an odd program organization...
***
valid one only prints inside the memDC. If the class instance gets
deconstructed it plots to the screen.
And that's what I find as odd. What if you want to abort without drawing?
*****
*****
[...]
*****
I find this code bewildering. If it is this hard to understand, it needs either better
comments or it needs to be simplified.
Since this class is the first reference to flickerfree drawing with MFC
and you have so many complains I believe it would be great if a newer
version of this class with less problems and better commenting would be
published.
Probably true. But I can't control that.
*****
Joseph M. Newcomer [MVP]
Matthias
email: newcomer@xxxxxxxxxxxx
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
.
- Follow-Ups:
- Re: Scaling of data into dc
- From: Matthias Pospiech
- Re: Scaling of data into dc
- References:
- Scaling of data into dc
- From: Matthias Pospiech
- Re: Scaling of data into dc
- From: Joseph M . Newcomer
- Re: Scaling of data into dc
- From: Matthias Pospiech
- Re: Scaling of data into dc
- From: Joseph M . Newcomer
- Re: Scaling of data into dc
- From: Matthias Pospiech
- Re: Scaling of data into dc
- From: Joseph M . Newcomer
- Re: Scaling of data into dc
- From: Matthias Pospiech
- Scaling of data into dc
- Prev by Date: Re: XML formatting question.
- Next by Date: Re: Preventing task manager from closing my application.
- Previous by thread: Re: Scaling of data into dc
- Next by thread: Re: Scaling of data into dc
- Index(es):
Relevant Pages
|