Mesh generating algorithm for a voxel game - c++

Im currently making a voxel game like Minecraft for fun with DirectX11.
Game works with chunk system like any other voxel game, but my current algorithm for generating chunk mesh is not expandable.
Block class has a few attributes like is block full and mesh type.
class Block
{
public:
bool isFull = true;
MeshType type = MeshType::FullBlock;
Vector2i texture = { 9, 1 };
Vector2i topTexture = { 9, 1 };
const char* sound;
Block(){}
Block(bool isFull, MeshType type, Vector2i texture, Vector2i topTexture, const char* sound): isFull(isFull), type(type), texture(texture), topTexture(topTexture), sound(sound){}
Block(bool isFull, MeshType type, Vector2i texture, const char* sound) : isFull(isFull), type(type), texture(texture), topTexture(texture), sound(sound) {}
Block(bool isFull, MeshType type, Vector2i texture) : isFull(isFull), type(type), texture(texture), topTexture(texture) {}
};
Every block is then initialised in a vector
blocks.reserve(64);
Block air(false, MeshType::Empty, {0 ,0});
blocks.emplace_back(air);
Block grass(true, MeshType::FullBlock, { 3, 0 }, { 0, 0 }, "Audio/grass1.ogg");
blocks.emplace_back(grass);
Block stone(true, MeshType::FullBlock, { 1, 0 }, "Audio/stone1.ogg");
blocks.emplace_back(stone);
Block rose(false, MeshType::Cross, { 12 ,0 }, "Audio/grass1.ogg");
blocks.emplace_back(rose);
Block wheat(false, MeshType::Hash, { 8 ,3 });
blocks.emplace_back(wheat);
//and so on...
I have a function that accepts a vector of vertices and chunk data.
That function loops through all the blocks with a few optimisations and emplaces data back into the vector that gets sent to the buffer.
for (int x = 0; x < ChunkWidth; x++)
{
for (int y = 0; y < ChunkHeight; y++)
{
for (int z = 0; z < ChunkWidth; z++)
{
if (IsDrawable[x][y][z] == 1)
{
switch (blocks[chunk->BlockID[x + 16 * y + 16 * 256 * z]].type)
{
case MeshType::FullBlock:
BuildBlock(chunk, vertices, x, y, z);
break;
case MeshType::Cross:
FillCross(vertices, blocks[chunk->BlockID[x + 16 * y + 16 * 256 * z]], x + chunk->x * ChunkWidth, y, z + chunk->z * ChunkWidth);
break;
case MeshType::Hash:
FillHash(vertices, blocks[chunk->BlockID[x + 16 * y + 16 * 256 * z]], x + chunk->x * ChunkWidth, y, z + chunk->z * ChunkWidth);
break;
}
}
}
}
}
With every new mesh type the switch statement gets bigger and I think that is not the way to go.
Im asking if there are better ways of doing this.
I thank you in advance.

I think making different derived classes with a common parent class Block is the way to go here. You add a virtual method in it whose behaviour is overridden in the derived classes. Then you place them in a polymorphic vector of std::shared_ptr<Block> and call them. If you are afraid that for some reason this might be too slow you might replace the virtual functions with the Curiously Recurring Template Pattern (CRTP) to achieve static polymorphism. So something like:
Implementatin of the base class Block: Can stay roughly the same bout you add a virtual method draw(...) which is the common interface for all derived classes:
class Block {
public:
bool isFull = true;
Vector2i texture = { 9, 1 };
Vector2i topTexture = { 9, 1 };
const char* sound;
Block() {
return;
}
Block(bool isFull, Vector2i const& texture, Vector2i const& topTexture, const char* sound)
: isFull(isFull), texture(texture), topTexture(topTexture), sound(sound) {
return;
}
Block(bool isFull, Vector2i const& texture, const char* sound)
: isFull(isFull), texture(texture), topTexture(texture), sound(sound) {
return;
}
Block(bool const& isFull, Vector2i const& texture)
: isFull(isFull), texture(texture), topTexture(texture) {
return;
}
// Virtual method that every derived class should override
// Could contain default behaviour but here I declared it as pure virtual method (therefore the = 0)
// Didn't know the data types for chunk and vertices so I used Chunk and Vertices respectively
virtual void draw(Chunk const& chunk, Vertices const& vertices, int x, int y, int z, int chunkWidth) = 0;
};
The different types of blocks are introduced as derived classes that inherit the constructor (or you might implement a new one as well) and override the behaviour of the draw(...) class. If you are not planning to inherit from this derived class then you can mark it as final or if you won't be overriding draw in a derived class you can mark only draw as final
class Empty: public Block {
public:
using Block::Block; // Use the constructor of the base class
// Overwrite behaviour of the base class here
void draw(Chunk const& chunk, Vertices const& vertices, int x, int y, int z, int chunkWidth) override {
return;
}
};
class FullBlock: public Block {
public:
using Block::Block;
void draw(Chunk const& chunk, Vertices const& vertices, int x, int y, int z, int chunkWidth) override {
// Move contents of BuildBlock here
BuildBlock(chunk, vertices, x, y, z);
return;
}
};
class Cross final: public Block {
public:
using Block::Block;
void draw(Chunk const& chunk, Vertices const& vertices, int x, int y, int z, int chunkWidth) override {
// Move contents of FillCross here! No need to pass blocks[i] or rewrite FillCross to take something else than a Block, e.g. a std::shared_ptr<Block>
FillCross(vertices, *this, x + chunk->x * chunkWidth, y, z + chunk->z * chunkWidth);
return;
}
};
class Hash final: public Block {
public:
using Block::Block;
void draw(Chunk const& chunk, Vertices const& vertices, int x, int y, int z, int chunkWidth) override {
// Same here
FillHash(vertices, *this, x + chunk->x * chunkWidth, y, z + chunk->z * chunkWidth);
return;
}
};
Then you add all the blocks as std::shared_ptr or better std::unique_ptr if the resources are not shared! (a wrapper for a plain pointer from #include <memory>)
// Consider using std::unique_ptr if you are not using the individual objects outside of the std::vector
std::vector<std::shared_ptr<Block>> blocks = {};
blocks.reserve(64);
auto air = std::make_shared<Empty>(false, {0 ,0});
blocks.emplace_back(air);
auto grass = std::make_shared<FullBlock>(true, { 3, 0 }, { 0, 0 }, "Audio/grass1.ogg");
blocks.emplace_back(grass);
auto stone = std::make_shared<FullBlock>(true, { 1, 0 }, "Audio/stone1.ogg");
blocks.emplace_back(stone);
auto rose = std::make_shared<Cross>(false, { 12 ,0 }, "Audio/grass1.ogg");
blocks.emplace_back(rose);
auto wheat = std::make_shared<Hash>(false, { 8 ,3 });
blocks.emplace_back(wheat);
You can call then the implementation of the different derived classes as follows:
for (int x = 0; x < chunkWidth; x++) {
for (int y = 0; y < chunkHeight; y++) {
for (int z = 0; z < chunkWidth; z++) {
if (IsDrawable[x][y][z] == 1) {
blocks[chunk->BlockID[x + 16 * y + 16 * 256 * z]]->draw(chunk, vertices, x, y, z, chunkWidth);
}
}
}
}
Here I put together a simplified working example to play around with in an online compiler.

Related

What causes this vector subscript out of range Error?

I am currently mapping a Graph to a Minesweeper like grid, where every Block represents a node.
Here is my Graph class:
class Graph : public sf::Drawable
{
public:
Graph(uint32_t numNodesWidth, uint32_t numNodesHeight);
[[nodiscard]] std::vector<Node> & operator[](std::size_t i)
{ return data[i]; }
[[nodiscard]] sf::Vector2u dimension() const
{ return {static_cast<uint32_t>(data.size()),
static_cast<uint32_t>(data[0].size())};}
...
...
private:
std::vector<std::vector<Node>> data;
};
here is the implementation of the constructor:
Graph::Graph(uint32_t numNodesWidth, uint32_t numNodesHeight)
{
data.resize(numNodesHeight);
for(auto & row : data)
{
row.resize(numNodesWidth);
}
}
Somewhere in another class I read mouse coordinates and convert them to "Graph Coordinates":
sf::Vector2u translatedCoords = toGraphCoords(sf::Mouse::getPosition(window), nodeSize_);
bool inBounds = checkGraphBounds(translatedCoords, graph.dimension());
Here are the helper functions:
sf::Vector2u toGraphCoords(sf::Vector2i mouseCoord, sf::Vector2f nodeSize)
{
return {static_cast<uint32_t>(mouseCoord.y / nodeSize.y),
static_cast<uint32_t>(mouseCoord.x / nodeSize.x)};
}
bool checkGraphBounds(sf::Vector2u mouseCoord, sf::Vector2u bounds)
{
return mouseCoord.x >= 0 &&
mouseCoord.y >= 0 &&
mouseCoord.x < bounds.x &&
mouseCoord.y < bounds.y ;
}
Somehow I get the vector subscript out of range 1655 error when I try to use these new checked Coordinates which is somehow strange, can someone explain to me what I am doing wrong. This error always shows when I try to hover beyond the "Bounds" of the Interactive area, slightly behind or in front the first or the last Node.
Thanks in advance.
There is no guarantee that bounds <= num_nodes * node_size. This is especially risky since there are integer divisions involved, which means that you are at the mercy of rounding.
You could shuffle code around until such a guarantee is present, but there's a better way.
If the checkGraphBounds() function operated on the same math that the grid does, you could be sure that the result would be consistent with grid, no matter how that relates to the bounds.
The ideal way to do so would be to actually use toGraphCoords() as part of it:
bool checkGraphBounds(sf::Vector2u mouseCoord, const Graph& graph,
sf::Vector2f nodeSize)
{
auto coord = toGraphCoords(mouseCoord, nodeSize);
return coord.x >= 0 &&
coord.y >= 0 &&
coord.x < graph.dimensions().x &&
coord.y < graph.dimensions().y) ;
}
With this, you can formally guarantee that should a mouseCoord pass that test, static_cast<uint32_t>(mouseCoord.x / nodeSize.x)} will for certain return a value no greater than graph.dimensions().x.
Personally, I would combine both functions as a method of Graph like so:
class Graph : public sf::Drawable {
// Make nodeSize a member of the Graph
sf::Vector2f nodeSize_;
// This is one of the cases where caching an inferable value is worth it.
sf::Vector2u dimensions_;
public:
std::optional<sf::Vector2u> toGraphCoords(sf::Vector2i mouseCoord) {
sf::Vector2u coord{
static_cast<uint32_t>(mouseCoord.y / nodeSize_.y),
static_cast<uint32_t>(mouseCoord.x / nodeSize_.x)};
};
// No need to compare against 0, we are dealing with unsigned ints
if(coord.x < dimensions_.x &&
coord.y < dimensions_.y ) {
return coord;
}
return std::nullopt;
}
// ...
};
Usage:
void on_click(sf::Vector2i mouse_loc) {
auto maybe_graph_coord = the_graph.toGraphCoords(mouse_loc);
if(maybe_graph_coord) {
sf::Vector2u graph_coord = *maybe_graph_coord;
// ...
}
}

Extremely bad Cairo performance when drawing many rectangles (C++, gtkmm)

I have created a CellGrid class for my cellular automaton, and I want to draw that grid using Cairo. The cell_grid.cpp code snippet below is my implementation of the on_draw() function override.
For this example, I have set width_ = height_ = 50 and cell_buffer_ is an std::vector with a size of width_ * height_. The vector containts instances of the Cell enum class, which is defined in the cell_grid.hpp snippet below.
The problem is that for some reason, already when drawing just 50*50 or 2 500 rectangles, I get about 2fps. This Cairo implementation is actually a rewrite of an SFML implementation, on which I got about 150fps when drawing 200*100 or 20 000 rectangles. But as far as I know, SFML isn't a viable option in combination with GTK.
cell_grid.hpp snippet
class CellGrid : public Gtk::DrawingArea
{
public:
enum class Cell : uint8_t //uchar
{
Dead = 0,
Alive = 1
};
// ...
};
cell_grid.cpp snippet
// ...
bool CellGrid::on_draw(const Cairo::RefPtr<Cairo::Context>& cr)
{
const Gtk::Allocation allocation = get_allocation();
const double cell_w = allocation.get_width() / (double)width_;
const double cell_h = allocation.get_height() / (double)height_;
for(size_t y = 0; y < height_; y++)
{
for(size_t x = 0; x < width_; x++)
{
cr->set_line_width(5.0);
cr->rectangle(x * cell_w, y * cell_h, cell_w, cell_h);
cr->set_source_rgb(0.5, 0.5, 0.5);
cr->stroke_preserve();
cell_buffer_[y * width_ + x] == Cell::Alive ?
cr->set_source_rgb(1.0, 1.0, 1.0) :
cr->set_source_rgb(0.1, 0.1, 0.1);
cr->fill();
}
}
return true;
}
// ...
Thanks in advance!

Blender, Cycles Render, call to function cause app to crash

I am trying to get the get the color of each sample during Cycles rendering. In order to do so, I am calling the following function
void update_bcd_inputs(int x, int y, float sampleR, float sampleG, float sampleB){
float current_valueR = sStats->m_meanImage.getValue(bcd::PixelPosition(x, y), 0); // += sampleR;
float current_valueG = sStats->m_meanImage.getValue(bcd::PixelPosition(x, y), 1); // += sampleG;
float current_valueB = sStats->m_meanImage.getValue(bcd::PixelPosition(x, y), 2); // += sampleB;
sStats->m_meanImage.set(x, y, 0, current_valueR + sampleR);
sStats->m_meanImage.set(x, y, 1, current_valueG + sampleG);
sStats->m_meanImage.set(x, y, 2, current_valueB + sampleB);
}
in blender/intern/cycles/device/device_cpu.cpp
void path_trace(DeviceTask &task, RenderTile &tile, KernelGlobals *kg)
{
float *render_buffer = (float*)tile.buffer;
int start_sample = tile.start_sample;
int end_sample = tile.start_sample + tile.num_samples;
float inv_weight = 1.0f/tile.num_samples;
for(int sample = start_sample; sample < end_sample; sample++) {
if(task.get_cancel() || task_pool.canceled()) {
if(task.need_finish_queue == false)
break;
}
for(int y = tile.y; y < tile.y + tile.h; y++) {
for(int x = tile.x; x < tile.x + tile.w; x++) {
path_trace_kernel()(kg, render_buffer,
sample, x, y, tile.offset, tile.stride);
int step = tile.offset + x + y*tile.stride;
step *= kernel_data.film.pass_stride;
float sampleR = *(render_buffer +step);
float sampleG = *(render_buffer +step +1);
float sampleB = *(render_buffer +step +2);
update_bcd_inputs(x, y, sampleR*inv_weight, sampleG*inv_weight, sampleB*inv_weight);
}
}
tile.sample = sample + 1;
task.update_progress(&tile, tile.w*tile.h);
}
}
SamplesStatisticsImages sStats is an attribute of CPUDevice
struct SamplesStatisticsImages
{
SamplesStatisticsImages() = default;
SamplesStatisticsImages(int i_width, int i_height, int i_nbOfBins);
SamplesStatisticsImages(const SamplesStatisticsImages&) = default;
SamplesStatisticsImages(SamplesStatisticsImages&&) = default;
SamplesStatisticsImages& operator=(const SamplesStatisticsImages&) = default;
SamplesStatisticsImages& operator=(SamplesStatisticsImages&&) = default;
DeepImage<float> m_nbOfSamplesImage;
DeepImage<float> m_meanImage;
DeepImage<float> m_covarImage;
DeepImage<float> m_histoImage;
};
Here are the files DeepImage.hpp and DeepImage.h.
The problem is that the call to update_bcd_inputs makes Blender to crash without even trying to render an image. I just change the renderer to Cycles, try to add a new material and boom, it crashes.
I figured out it is the set function that is the problem (when I remove it, the app doesn't crash).
Can someone understand why ? I don't have strong C++ skills so I must be missing something.
Here is the crash log as well.
Thanks !
Edit: more precisions
Here is the modified device_cpu.cpp.
The sStats pointer is initialized with nullptr in the CPUDevice constructor
CPUDevice(DeviceInfo& info_, Stats &stats_, bool background_)
: Device(info_, stats_, background_),
texture_info(this, "__texture_info", MEM_TEXTURE),
histoParams(),
#define REGISTER_KERNEL(name) name ## _kernel(KERNEL_FUNCTIONS(name))
...
#undef REGISTER_KERNEL
{
...
sStats = nullptr;
}
and then allocated in
void thread_render(DeviceTask& task)
{
...
sStats = new bcd::SamplesStatisticsImages(task.w, task.h, histoParams.m_nbOfBins);
...
}
histoParams is an attribute of CPUDevice as well.
struct HistogramParameters
{
HistogramParameters() :
m_nbOfBins(20),
m_gamma(2.2f),
m_maxValue(2.5f) {}
int m_nbOfBins;
float m_gamma; ///< exponent for the exponential size increase of histogram bins
float m_maxValue;
};

Cocos2d retain() in inherited classes

So I've had a lot of trouble with Cocos2d's auto-release shenanigans, and (almost) wish that I could just handle all of that myself...
Anyways, the problem I've had is with creating some animations. I've got a class called AnimatedDamageableSprite which inherits from DamageableSprite which inherits from Sprite which inherits from CCSprite etc...
When I create an AnimatedDamageableSprite, I have a successful animation on the screen, which runs as it should.
When I create a Suicider, which (you guessed it) inherits from AnimatedDamageableSprite, the CCArray which contains the frames for animation doesn't survive beyond the first loop, and on the second update attempt, the program gets an AV error.
Here's the code for the two classes:
Sprite.h
// This class works
class AnimatedDamageableSprite :public DamageableSprite {
public:
AnimatedDamageableSprite(int hp, CCPoint pos, CCTexture2D* tex, int rows, int columns, float scaleX, float scaleY);
virtual ~AnimatedDamageableSprite();
virtual void update(float dt);
virtual bool updateFrame(float dt);
virtual SpriteType getType() { return ANIMATED_DAMAGEABLE_SPRITE; };
protected:
float m_frameNum;
CCArray* m_frames;
int m_numOfFrames;
};
// This class doesn't
class Suicider :public AnimatedDamageableSprite {
public:
Suicider(int difficulty);
virtual ~Suicider();
virtual void update(float dt);
virtual SpriteType getType() { return SUICIDER; };
private:
float m_speed;
};
Sprite.cpp
AnimatedDamageableSprite::AnimatedDamageableSprite(int hp, CCPoint pos, CCTexture2D* tex, int rows, int columns, float scaleX, float scaleY)
:DamageableSprite(hp, pos, tex, scaleX, scaleY), m_frameNum(0), m_numOfFrames(rows*columns) {
float texWidth = tex->getContentSize().width / (float)columns;
float texHeight = tex->getContentSize().height / (float)rows;
m_frames = CCArray::createWithCapacity(m_numOfFrames);
m_frames->retain();
for (unsigned int i = 0; i < columns; i++) {
for (unsigned int j = 0; j < rows; j++) {
CCRect r(i*texWidth, j*texHeight, texWidth, texHeight);
m_frames->addObject(new CCSpriteFrame);
((CCSpriteFrame*)m_frames->lastObject())->createWithTexture(tex, r);
((CCSpriteFrame*)m_frames->lastObject())->initWithTexture(tex, r);
m_frames->lastObject()->retain();
}
}
initWithSpriteFrame((CCSpriteFrame*)m_frames->objectAtIndex(m_frameNum));
setTexture(tex);
setPosition(pos);
setScaleX(scaleX);
setScaleY(scaleY);
updateTransform();
}
// This function is called every frame. It returns a boolean for unrelated reasons
bool AnimatedDamageableSprite::updateFrame(float dt) {
bool retVal = false;
// Assume animations are at 30 FPS for now
m_frameNum += dt * 0.03f;
while (m_frameNum >= m_numOfFrames) {
m_frameNum -= m_numOfFrames;
retVal = true;
}
setDisplayFrame((CCSpriteFrame*)m_frames->objectAtIndex(m_frameNum));
updateTransform();
return retVal;
}
// This class calls the constructor of the one that works, and does nothing else relevant to the problem
// It also doesn't override the updateImage() function
Suicider::Suicider(int difficulty)
: AnimatedDamageableSprite(1, CCPoint(10,10), g_textureManager.getTexture("Suicider Sheet"), 6, 10, SCALE_WIDTH, SCALE_HEIGHT) {
// ...
}
EDIT:
Seems I forgot to actually point out the problem.
The CCArray* m_frames declared in AnimatedDamageableSprite is fine when used in that instance, but it is deleted at the end of a frame when used in the Suicider class - i.e. it isn't being retained. Hence the AV error when I try to access an item inside it which no-longer exists
I tried retaining it in the Suicider constructor as well, although that didn't change anything.

Having trouble with a C++ Square Class. Member function implementation and declaration

My last question was closed after 2 minutes. I am simply asking for help with the member functions. I should have member functions checking the following:
whether the square is external to another;
whether the square contains another square;
whether the square is contained into another square;
whether the square is tangent externally to another square (that is,
whether their borders are in contact but, except those border
points, they are external to each other);
whether the square is tangent internally to another square (that is,
they have points on the borders in common but, except those border
points, one square is contained into the other one);
whether the border of the square intersects the border of another
square.
my private members are: double x,y;
Should i have the public member functions then, using both x and y to compute the perimeter and area?
This is what i have so far:
the header file
#include <iostream>
#include <cmath>
class Square
{
int x, y;
int size;
public:
Square(int x, int y, int size) : x(x), y(y), size(size) { }
~Square() {};
bool isExternal(const Square& rhs);
bool contains(const Square& otherSquare);
bool iscontained(const Square& otherSquare);
bool borderintersect (const Square& otherSquare);
bool bordertangent (const Square& otherSquare);
}
The implementation
#include "Square.h"
bool Square::isExternal(const Square& rhs) const {
return (((x < rhs.x) || ((x + size) > (rhs.x + rhs.size)) && ((y < rhs.y) || ((y + size) > (rhs.y + rhs.size))
};
bool Square::contains(const Square& otherSquare)const {
};
bool Square::iscontained(const Square& otherSquare)const {
};
bool borderintersect(const Square& othersquare)
{
// If this square's bottom is greater than the other square's top
if ((this->y - (this->size / 2)) > (othersquare->y + (othersquare->size / 2)))
{
return (false);
}
// the reverse
if ((this->y + (this->size / 2)) < (othersquare->y - (othersquare->size / 2)))
{
return (false);
}
// If this square's left is greater than the other square's right
if ((this->x - (this->size / 2)) > (othersquare->x + (othersquare->size / 2)))
{
return (false);
}
if ((this->x + (this->size / 2)) < (othersquare->x - (othersquare->size / 2)))
{
return (false);
}
return (true);
bool Square::bordertangent (const Square& otherSquare)const {
};
The test program
#include "Square.h"
#include <iostream>
using namespace std;
 
int main() {
Square sq1(0, 0, 10);
Square sq2(1, 1, 10);
if(sq1.isExternal(sq2)) {
cout<<"Square 1 is external to square 2"<<endl;
}
if(sq1.contains(sq2){
cout<<"Square 1 contains square 2"<<endl;
return 0;
}
Should i include this in the header file in order to get both the x and y of the coordinate and the size?
double getX( ) const { return x; }
double getY( ) const { return y; }
double getSize( ) const { return size; }
It seems like you're tripping up on where to start with implementing the class so I'll give you some guidance there. All of your questions deal with checking the relative positions of two squares in some coordinate space. To answer them, you will need to know two things about each square:
Position (x, y coordinates (often a corner of the square))
Size (size)
Assuming you definitely mean square, then the width and height are equal, so you only need one variable to store the size. If you can actually have rectangles, then you'll need width and height. These will need to be members of your Square class because each Square should have its own position and size. You do not need to store the coordinates of each corner of your square because you can work them out from the position and size - storing data that you can work out from data you already have is known as redundancy and is generally something you want to avoid. Here is how that would look in two different coordinate systems (one where y goes down and the other where y goes up):
x-->
y size
| (x,y).___________________
v | |
| |
| |
| |
size | |
| |
| |
| |
|___________________| (x+size, y+size)
___________________ (x+size, y+size)
| |
| |
| |
| |
size | |
| |
| |
^ | |
| (x,y).___________________|
y size
x-->
As an alternative, you could store two positions which are two opposite corners of your square. However, if you really are dealing with squares, not rectangles, you will need to manually enforce the invariant that the points must be the same distance away from each other along both axes. Rectangles would not have this invariant so this would be more applicable for them, but then operations such as translation become more complicated (you would now have to move two points rather than just one).
You will not need perimeter or area member functions. None of the questions require you to know either of these things. All of the questions can be answered by doing simple comparison between the positions and sizes of the two squares.
Whether you have them be private or not is a design issue. By making them private, you can control access to them through the Square's interface. You could then provide public member functions so that you can check for answers to some of your questions, such as bool Square::contains(const Square& otherSquare) which you would call like square.contains(otherSquare). Here's the beginnings of a possible class definition:
class Square
{
private:
int x, y, size;
public:
Square(int x, int y, int size) : x(x), y(y), size(size) { }
bool contains(const Square& other)
{
// Do comparisons between x, y, size and other.x, other.y, other.size
}
// ...
};
Alternatively, you could have the functions at namespace scope (not members of Square) and either make them friends of Square or make the position and size members of Square public. For such a simple example, this will not be a problem.
Should I include this in the header file in order to get both the x and y of the coordinate and the size?
double getX( ) const { return x; }
double getY( ) const { return y; }
double getSize( ) const { return size; }
These kinds of functions are commonly known as getters. They provide access to private member variables of a class. In your case, you do not need to provide these getters because the functions you are writing are member functions of Square. The member functions of Square have access to the private members of any other Square, so you don't need to get access through these getters.
However, if you wanted some other class to access the x, y, and size values for a given Square, then you would need to provide getters (or make the members public).
Start with something like this, and go from there
class Square
{
double m_x, m_y;
double m_length;
public:
Square(double x, double y, double length) : m_x(x), m_y(y), m_length(length) {}
~Square() {};
bool isExternal(const Square& rhs);
}
--- implementation
bool Square::isExternal(const Square& rhs)
{
bool retval = true;
// do some calculations ..
return retval;
}
--- main
int main(void)
{
Square sq1(0, 0, 10);
Square sq1(1, 1, 10);
if(sq1.isExternal(sq2) {
}
}