About class CRect & Rect, Width = right - left - c++

It is a problem about C++ and mfc.
For example, left = 3, right = 8. Doesn't it mean there are 6 pixel from left to right? Why the width = right - left? If I know a rect which represents the image rect, when I allocate memory for the image data, which one should I use? Width = right-left, or Width = right-left+1? I am a beginner of image process. It really confuses me. Thank you for your help!

If we are talking about CRect and RECT the documentation is clear.
By convention, the right and bottom edges of the rectangle are normally considered exclusive. In other words, the pixel whose coordinates are ( right, bottom ) lies immediately outside of the rectangle. For example, when RECT is passed to the FillRect function, the rectangle is filled up to, but not including, the right column and bottom row of pixels. This structure is identical to the RECTL structure.
The principles of "inclusive lower bound, exclusive upper bound" is used here to. So the number of elements is always the difference between the boundaries.

Another way to think about this is that the width of the rectangle is a measure of DISTANCE from left to right. When left equals right (e.g.: left = 1 and right = 1), the distance between them is zero (note that the distance can be negative).
When using a RECT to represent pixel coordinates, we often want to know the count of pixels going from left to right. When left equals right (e.g.: left = 1 and right = 1), we know we have only one pixel in the left/right direction. There isn't a pre-made function to compute this count, so you need take the absolute value of the width and add 1.
In C/C++:
int count = abs(myRect.right - myRect.left) + 1;

Related

How can I maintain points inside a rectangle that keeps its aspect ratio inside and changing outer container?

So my problem involves trying to keep points drawn into a rectangle at the same position of the rectangle while an outer container box is scaled to any size.
The rectangle containing the points will keep its aspect ratio while it grows and shrinks in the center of the outer box.
I'm able to keep the inner box's aspect ratio constant but am having problems drawing the points in the correct place when scaling the outer box. Here's an example of my problem.
I'd like the point to stay on the same spot the picture is no matter how the outer box is scaled. The coordinate system has 0,0 as the topleft of the outer box and the inner box is centered using offsets allowing the inner box to be big as possible while maintaining its aspect ratio, however I'm stuck on getting points I add to maintain their position in the box. Here's a look at what I think I should be doing:
void PointsHandler::updatePoints()
{
double imgRatio = boxSize.width() / boxSize.height();
double oldXOffset = (oldContainerSize.width() - oldBoxSize.width()) / 2;
double oldYOffset = (oldContainerSize.height() - oldBoxSize.height()) / 2;
double newXOffset = (containerSize.width() - boxSize.width()) / 2;
double newYOffset = (containerSize.height() - boxSize.height()) / 2;
for(int i = 0; i < points.size(); i++){
double newX = ((points[i].x() - oldXOffset) + newXOffset) * boxRatio;
double newY = ((points[i].y() - oldYOffset) + newYOffset) * boxRatio;
points.replace(i, Point(newX, newY));
}
}
The requested transformations are only translations and scale.
To preserve the original aspect ratio of the inner box, the scale factor must be the same for the x and the y axes. To choose which one to apply, the user should compare the ratio between the width and the height of the new outer box with the aspect ratio of the old inner box. If it's lower, the scale should be the ratio between the new width and the old one, otherwise the ratio between the heights.
To respect the correct order of the transformations, you need to first apply a translation of the points so that the old center of inner box coincides with the origin of the axes (the top left corner of the outer box, apparently), then scale the points and finally translate back to the new center of the outer box. That's not what the posted code attempts to do, because it seems that the scale is applied last.

Text is not appearing at specified position in Qt

I have a QGraphicsView which contains many QGraphicsItem like rectangle, polylines etc.
I want to name each rectangle and name is on the rectangle.
Name should be centrally aligned i.e. half of the string name characters should be left side of mid position and half of the characters should be right side of mid position.
For that I used following psuedo code:
int firstPosition = GetMidPosition () - (strLength / 2);
int secondPosition = some points
DrawText( firstPosition , secondPosition );
Now if I print co-ordinates of firstPosition, secondPosition , GetMidPosition() they comes perfectly as I expect.
But, the text does not come properly. I have to manually adjust it.
int firstPosition = GetMidPosition () - 6 *(strLength / 2);
Now it appears centrally. Why this is happening ? Co-ordinates are correct then why I have to manually adjust it.
I want to avoid that adjustment (i.e. 6 * )
If tomorrow, I changed the font size of text, then I will have to
change the multiplication factor 6 into something else. That should
not be happened. How to write general purpose logic for this ?

C++ DirectX11 2d Game: Stopping enemy sprites moving over each other?

I am using IntersectsWith(this->boundingBox)) method to detect collisions between sprites and player. I want to somehow be able to use this method in detecting my enemy sprites that collide with each other, and when they do to make sure they don't move over one another.
All of the enemy sprites follow the player.
MainGame.cpp
Loops over each enemy in the vector and does the update loop:
for (auto &enemyMobsObj : this->enemyMobs)
{
enemyMobsObj->Update(tickTotal, tickDelta, timeTotal, timeDelta, windowBounds, this->ship, this->firstBoss,
this->enemyMobs, this->bullets, this->missiles, NULL, "NULL", "NULL");
}
Here is what I tried before to stop each sprite moving over each other:
EnemyMobOne::Update:
int nextEnemy;
for (int i = 0; i < enemyMobOne.size(); i++)
{
nextEnemy = i + 1;
if (nextEnemy < enemyMobOne.size())
{
//Deal with mobs collision
if (enemyMobOne[i].boundingBox.IntersectsWith(enemyMobOne[nextEnemy].boundingBox))
{
enemyMobOne[i].position.x = enemyMobOne[nextEnemy].position.x - enemyMobOne[i].boundingBox.Width;
}
}
}
However this makes each enemy sprite obviously stick to each other, which doesn't look right, it also makes them teleport.
Anyone know the correct code to stop them moving over each other? Thanks.
When you detect an intersection between two collision objects, you need to make a decision about how you're going to counteract the overlap (as I'm sure you figured out). However, how one does this is a bit trickier than simply "pushing" them to one side (as you've done in your code). What you likely want to do is to have a counter-force to the applied force, so to speak. Basically, you want to calculate the minimum translation, or the direction by which the least amount of movement would be required, to get at least ONE of the boxes to move OUT of the other one.
This is a bit more complicated than simply "put me on the right (or left, depending on how you set up your coordinates, I suppose) side of the other guy," which is more or less what your code does, now.
For a simple solution, just check if one of the colliders is closer to the left, right, top, or bottom of the other. To do this, you can simply take the collision intersection position and check the relative distance between that point and the minimum and maximum x and y coordinates relative to one of the colliders, then move the one or both of the sprites, accordingly.
Ex:
[Edit] After reviewing my previous answer for this, I realized you would need to calculate the overlap of the boxes, which would make it much easier to accomplish this all like so:
float minX = min(sprite0.boundingBox.maxX, sprite1.boundingBox.maxX);// Minimum of the boxes' right-side points (top right and bottom right) x coordinates
float minY = min(sprite0.boundingBox.maxY, sprite1.boundingBox.maxY);// Minimum of the boxes' top-side points (top left and top right) y coordinates
float maxX = max(sprite0.boundingBox.minX, sprite1.boundingBox.minX);// Maximum of the boxes' left-side points (top left and bottom left) x coordinates
float maxY = max(sprite0.boundingBox.minY, sprite1.boundingBox.minY);// Maximum of the boxes' bottom-side points (bottom left and bottom right) y coordinates
float distHoriz = minX - maxX;// The horizontal intersection distance
float distVert = minY - maxY;// The vertical instersection distance
// If the boxes are overlapping less on the horizontal axis than the vertical axis,
// move one of the sprites (in this case, sprite0) in the opposite direction of the
// x-axis overlap
if(abs(distHoriz) < abs(distVert))
{
sprite0.x -= distHoriz;
}
// Else, move one of the sprites (again, I just decided to use sprite0 here,
// arbitrarily) in the opposite direction of the y-axis overlap
else
{
sprite0.y -= distVert;
}
To further clarify (beyond the comments), what we're basically doing here is checking the distance between the overlapping lines. For example:
Box 0 x-axis xmin0|------------------|xmax0
Box 1 x-axis xmin1|----------------------|xmax1
|----|<-- Overlap (xmax0 - xmin1)
Notice that the minimum from the two bounding boxes that is used for the overlap is the maximum among the two minima (xmin0 and xmin1), and the maximum that is used for the overlap is the minimum among the two maxima (xmax0 and xmax1).
The y-axis calculation works exactly the same way. Once we have both axes, we simply check to see which one has a lower absolute value (which distance is shorter) and move along that distance to counteract the intersection.

Uneven Circles in Connect 4 Board

I'm in the process of creating a 2P Connect 4 game, but I can't seem to get the circular areas to place tokens spaced evenly.
Here's the code that initializes the positions of each circle:
POINT tilePos;
for (int i = 0; i < Board::Dims::MAXX; ++i)
{
tileXY.push_back (std::vector<POINT> (Board::Dims::MAXY)); //add column
for (int j = 0; j < Board::Dims::MAXY; ++j)
{
tilePos.x = boardPixelDims.left + (i + 1./2) * (boardPixelDims.width / Board::Dims::MAXX);
tilePos.y = boardPixelDims.top + (j + 1./2) * (boardPixelDims.height / Board::Dims::MAXY);
tileXY.at (i).push_back (tilePos); //add circle in column
}
}
I use a 2D vector of POINTs, tileXY, to store the positions. Recall the board is 7 circles wide by 6 circles high.
My logic is such that the first circle starts (for X) at:
left + width / #circles * 0 + width / #circles / 2
and increases by width / #circles each time, which is easy to picture for smaller numbers of circles.
Later, I draw the circles like this:
for (const std::vector<POINT> &col : _tileXY)
{
for (const POINT pos : col)
{
if (g.FillEllipse (&red, (int)(pos.x - CIRCLE_RADIUS), pos.y - CIRCLE_RADIUS, CIRCLE_RADIUS, CIRCLE_RADIUS) != Gdiplus::Status::Ok)
MessageBox (_windows.gameWindow, "FillEllipse failed.", 0, MB_SYSTEMMODAL);
}
}
Those loops iterate through each element of the vector and draws each circle in red (to stand out at the moment). The int conversion is to disambiguate the function call. The first two arguments after the brush are the top-left corner, and CIRCLE_RADIUS is 50.
The problem is that my board looks like this (sorry if it hurts your eyes a bit):
As you can see, the circles are too far up and left. They're also too small, but that's easily fixed. I tried changing some ints to doubles, but ultimately ended up with this being the closest I ever got to the real pattern. The expanded formula (expanding (i + 1./2)) for the positions looks the same as well.
Have I missed a small detail, or is my whole logic behind it off?
Edit:
As requested, types:
tilePos.x: POINT (the windows API one, type used is LONG)
boardPixelDims.*: double
Board::Dims::MAXX/MAXY: enum values (integral, contain 7 and 6 respectively)
Depending on whether CIRCLE_SIZE is intended as radius or diameter, two of your parameters seem to be wrong in the FillEllipse call. If it's a diameter, then you should be setting location to pos.x - CIRCLE_SIZE/2 and pos.y - CIRCLE_SIZE/2. If it's a radius, then the height and width paramters should each be 2*CIRCLE_SIZE rather than CIRCLE_SIZE.
Update - since you changed the variable name to CIRCLE_RADIUS, the latter solution is now obviously the correct one.
The easiest way I remember what arguments the shape related functions take is to always think in rectangles. FillEllipse will just draw an ellipse to fill the rectangle you give it. x, y, width and height.
A simple experiment to practice with is if you change your calls to FillRect, get everything positioned okay, and then change them to FillEllipse.

DirectDraw Blt function parameters

Just a simple blt function:
RECT dstRect = {dstL, dstT, dstR, dstB};
RECT srcRect = {srcL, srcT, srcR, srcB};
HRESULT hr = _surface->Blt(&dstRect,source,&srcRect,DDBLT_WAIT, NULL);
My question is:
let's say I have a buffer of width 'w', I specify dstL = 0. What should be dstR ? w or w-1 ?
meaning is dstR included or not ? (< or <=) ?
DirectDraw rectangles are like GDI rectangles in that they cover the area up to (but not including) the right column and bottom row. So it should be w.
Reference: http://msdn.microsoft.com/en-us/library/aa911080.aspx :
The RECT structures are defined so that the right and bottom members are exclusive: right minus left equals the width of the rectangle, not one less than the width.