What causes this vector subscript out of range Error? - c++

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;
// ...
}
}

Related

Mesh generating algorithm for a voxel game

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.

Sorting a vector of custom class doesn't iterate over the vector correctly

I am trying to implement a painters sort algorithm for a rendering assignment. The premise of the code is that I need to find the average depth of a polygon, and the list of polygons via the depth assigned to them by the for loop.
this is the polygons declaration, as well as a collection of the vertices of the polygon post transformation which are used for the calculation of the depth of the polygon
std::vector<Polygon3D> _polygons;
std::vector<Vertex> _transvertices;
This is the method called by the model class to sort the _polygons vector using std::sort
void Model::Sort()
{
for (int i = 0; i <= GetPolygonCount(); i++)
{
_polygons[i].SetDepth((_transvertices[_polygons[i].GetIndex(0)].Get(2) + _transvertices[_polygons[i].GetIndex(1)].Get(2) + _transvertices[_polygons[i].GetIndex(2)].Get(2)) / 3);
}
sort(_polygons.begin(), _polygons.end(), sortByDepth);
}
This code then links to this binary predicate
bool sortByDepth(const Polygon3D &lhs, const Polygon3D &rhs)
{
float m = lhs.GetDepth(); //For value testing
float n = rhs.GetDepth(); //For value testing
return lhs.GetDepth() > rhs.GetDepth();
}
The issue is, once the sort algorithm starts, the value of lhs and rhs never change - lhs always has a depth of 0 (and looking further into its assignment, it seems to be creating an entirely new polygon?) and rhs always has a value of 30.53 (the depth of the first polygon in the _polygons vertex
I'm concerned that the issue might be with not having a form of iterator linked to the Polygon3D class, but I wouldn't know where to start with making an iterator for the class.
Any help would be appreciated, I've looked through far too many similar questions, but none of them seem to be quite right for my particular problem.
EDIT:
Post got taken down because I didn't provide enough code apparently. I tried to reproduce the problem in a different project but for some reason it iterates just fine there.
This is the "shortest possible reproduction" I tried, but for some reason this doesn't seem to have the same issue as the original.
#include <vector>
#include <algorithm>
class Polygon3D
{
public:
Polygon3D(); // Example data for testing purposes
float GetDepth() const;
void SetDepth(float depth);
private:
float _depthAverage;
};
class Model
{
public:
Model();
size_t GetPolygonCount() const;
void Sort();
private:
std::vector<Polygon3D> _polygons;
std::vector<int> _vertices;
std::vector<int> _transvertices;
};
Polygon3D::Polygon3D()
{
//_depthAverage = float(rand() % 100);
}
float Polygon3D::GetDepth() const
{
return _depthAverage;
}
void Polygon3D::SetDepth(float depth)
{
_depthAverage = depth;
}
Model::Model()
{
for (int i = 0; i < 10; i++)
{
_polygons.push_back(Polygon3D());
}
this->Sort();
}
size_t Model::GetPolygonCount() const
{
return _polygons.size() - 1;
}
bool sortByDepth(const Polygon3D& lhs, const Polygon3D& rhs)
{
float m = lhs.GetDepth();
float n = rhs.GetDepth();
return lhs.GetDepth() > rhs.GetDepth();
}
void Model::Sort()
{
for (int i = 0; i <= GetPolygonCount(); i++)
{
_polygons[i].SetDepth(float(rand() % 100) / 3);
}
sort(_polygons.begin(), _polygons.end(), sortByDepth);
}
int main()
{
Model m = Model();
}
Edit 2:
I played around with just using an auto type variable to manually iterate over _polygons, and that seems to work. I dont understand why std::sort doesnt
auto begin = _polygons.begin();
while(true)
{
begin++;
}
The answer turned out to be something incredibly stupid on my own part. The issue was the copy constructor used within the Polygon3D class - I had forgotten to copy over the depth value in the copy constructor, which meant lhs did not get a depth value.

How to avoid creating of empty object?

I am making my homework and I have 2 functions unionRect and intersectRect.I am creating a set of my first class Rectangle from a file. I have to return the union and intersect rectangle of that oColl.I am having a problem with returning the values because the object returns two 0 values.
I have tried to return different things but I couldn't do it.
This is from the first class Rectangle
Rectangle unionRect(const Rectangle& rec) const {
int ux1, ux2, uy1, uy2;
ux1 = min(ix1, rec.ix1);
uy1 = min(iy1, rec.iy1);
ux2 = max(ix2, rec.ix2);
uy2 = max(iy2, rec.iy2);
Rectangle a(ux1, ux2, uy1, uy2);
return a;
}
This is second class RectangleCollection function to read from file
RectangleCollection(const string& strFileName) {
ifstream ifile(strFileName.data());
copy(istream_iterator<Rectangle>(ifile), istream_iterator<Rectangle>(), inserter(oColl,oColl.begin()));
};
this is my RectangleCollection class function for union Rect
Rectangle calcUnionColl() {
set<Rectangle>::iterator it;
Rectangle a;
for (it = oColl.begin(); it != oColl.end(); ++it) {
a = unionRect(*it);
}
return a;
}
and the .txt file is
5 5 10 10
6 6 12 12
but when i call calcUnionColl it returns me
x1:0 x2:6 y1:0 y2:12
I expect the output to be x1:5 x2:6 y1:5 y2:12.
Thank you in advance!
You are not union'ing all of the Rectangles together that are in the collection. You are union'ing each individual Rectangle only with the one Rectangle that calcUnionColl() is called on, and then you return the result of just the last union that was performed.
Try something more like this instead:
class Rectangle {
public:
...
Rectangle unionRect(const Rectangle& rec) const;
...
}
Rectangle Rectangle::unionRect(const Rectangle& rec) const {
int ux1, ux2, uy1, uy2;
ux1 = std::min(ix1, rec.ix1);
uy1 = std::min(iy1, rec.iy1);
ux2 = std::max(ix2, rec.ix2);
uy2 = std::max(iy2, rec.iy2);
return Rectangle(ux1, ux2, uy1, uy2);
}
...
class RectangleCollection {
public:
...
Rectangle calcUnionColl() const;
...
}
Rectangle RectangleCollection::calcUnionColl() const {
Rectangle a;
if (!oColl.empty()) {
std::set<Rectangle>::iterator it = oColl.begin();
a = *it++;
while (it != oColl.end()) {
a = a.unionRect(*it++);
}
}
return a;
}
The answer from Remy Lebeau has a minor issue. If oColl is empty, calcUnionColl will return the the default-constructed value of a. So if the default-constructed value of a is x1:0, x2:0, y1:0, y2:0 then if calcUnionColl returns that value, it is impossible to know if that is the actual union of the values in oColl, or if
oColl was empty.
A common trick when finding the the maximum value of multiple ints is to initialize the running maximum with INT_MIN. And in the same way, when finding a minimum value, we initialize the the running minimum with INT_MAX.
Finding the union of rectagles is nothing more than finding the min/max value of the rectangles corner coordinates, so we can use the above trick.
For instance if a = {x1:INT_MAX, x2:INT_MIN, y1:INT_MAX, y2:INT_MIN}, then when calculating the union of a and any rectangle b, we will have:
b.x1 <= a.x1 // a.x1 == INT_MAX
b.y1 <= a.y1 // a.y1 == INT_MAX
b.x2 >= a.x1 // a.x1 == INT_MIN
b.y2 >= a.y2 // a.y2 == INT_MIN
So the union of a and b in this case will be b
Making use of this in calcUnionColl():
// I assume the data-type for your rectangle coordinates is `int`.
// If you use another datatype, change this accoringly.
Rectangle RectangleCollection::calcUnionColl() const {
int i_min = std::numeric_limit<int>::min(); // c++ way of getting INT_MIN
int i_max = std::numeric_limit<int>::max(); // c++ way of getting INT_MAX
set<Rectangle>::iterator it;
Rectangle a(i_max, i_min, i_max, i_min);
for (it = oColl.begin(); it != oColl.end(); ++it) {
a = a.unionRect(*it);
}
return a;
}
Now, if oColl is empty, calcUnionColl() will return x1:INT_MAX, x2:INT_MIN, y1:INT_MAX, y2:INT_MIN. This should be an invalid value for a rectangle since x1>x2 and y1>y2, and should be easy to test for.
Sometimes you don't even have to test for it, since it often is an invalid value "that makes sense" for further calculations.

Fast Ray and Polygon Intersection

I'm working on programming my own little game which should have a visibility effect as described here. My world consists of Polygons which each have a list of Edges (sorted CW). I now want (as described in the article) to cast Rays towards the Edges of the polygons, find the intersections and retrieve a Polygon that defines the visible area.
So I wrote a classes for Vectors, Points, Edges and Polygons and adjusted the intersection-algorithm so it works with my code.
I then tested it and everything worked fine, but as I ran the Intersection algorithm in a for-loop to simulate a large amount of Edges processed(starting with 100, until 1000) the fps dropped drastically, with 100 Edges "only" 300fps (3000 before), and with 300 it dropped below 60 i think. This seems to be way to much drop for me as i wanted to reuse this code for my Lightsources and then i think i would quickly come up with processing way more than 300 Edges and it should run fast on way less powerful processors(i got an xeon e1230v3).
I figured out that only calling the EdgeIntersection the program runs many times faster, but I definitely need to loop through the Edges in my polygons so this is no option.
My Source-Code:
Vector.h/.cpp: Basic Vector class with two floats(X,Y), getters&setters, rotating
Vertex.h/.cpp: Basic Point class with a Position Vector, getters&setters and a boolean that indicates whether it is a Intersection Vertex
Edge.h/.cpp Basic Edge class with start/end-Verticies, getters&setters and rotating function(uses Vector.rotate())
Polygon.h:
#pragma once
#include <vector>
#include "Edge.h"
namespace geo
{
class Polygon
{
private:
std::vector<Edge> edges;
public:
Polygon();
Polygon(std::vector<Edge> edges);
~Polygon();
std::vector<Edge> getEdges();
Edge getEdge(int index);
int getEdgeCount();
void setEdges(std::vector<Edge> edges);
void setEdge(Edge e, int index);
void addEdge(Edge e);
void removeEdge(int index);
};
}
Ray.h:
#pragma once
#include "Vertex.h"
class Ray
{
private:
geo::Vertex origin;
geo::Vector dir;
public:
Ray();
Ray(geo::Vertex origin, geo::Vector dir);
~Ray();
geo::Vertex getOrigin();
geo::Vector getDirection();
void setOrigin(geo::Vertex origin);
void setDirection(geo::Vector dir);
};
LightModule.h:
#pragma once
#include "Polygon.h"
#include "Ray.h"
class LightModule
{
private:
//List of blocking Polygons
std::vector<geo::Polygon>* blockingPolygons;
std::vector<Ray> rays;
geo::Polygon bounds;
geo::Polygon visible;
/*geo::Polygon blocked;*/
//HitDetection Class later
geo::Vertex getIntersection(Ray r, geo::Edge* e);
geo::Vertex getClosestIntersection(Ray r, geo::Polygon *p);
public:
LightModule();
LightModule(std::vector<geo::Polygon>* blockingPolygons);
~LightModule();
//Set the Blocking Polygons
void setBlockingPolygons(std::vector<geo::Polygon>* blockingPolygons);
geo::Vertex callCI(Ray r, geo::Polygon* p);
geo::Vertex callI(Ray r, geo::Edge* e);
//Cast Rays towards Vertecies and store them in rays
void updateRays();
//Update Visibility Polygon
void updateVisible();
//Return Visibility Polygon
geo::Polygon* getVisible();
};
LightMModule.cpp:
#include "LightModule.h"
LightModule::LightModule()
{
rays.clear();
}
LightModule::LightModule(std::vector<geo::Polygon>* blockingPolygons)
{
this->blockingPolygons = blockingPolygons;
rays.clear();
}
LightModule::~LightModule()
{
}
void LightModule::setBlockingPolygons(std::vector<geo::Polygon>* blockingPolygons)
{
this->blockingPolygons = blockingPolygons;
}
//Test-cast a Ray (will follow mouse in the Test)
void LightModule::updateRays()
{
Ray r(geo::Vertex(geo::Vector(200, 100)), geo::Vector(-100, 0));
rays.push_back(r);
}
void LightModule::updateVisible()
{
}
//Both for Testing will later be part of a seperate class
geo::Vertex LightModule::callCI(Ray r, geo::Polygon *p)
{
return this->getClosestIntersection(r, p);
}
geo::Vertex LightModule::callI(Ray r, geo::Edge* e)
{
return this->getIntersection(r, e);
}
//TEST
geo::Vertex LightModule::getIntersection(Ray r, geo::Edge* e)
{
geo::Vertex v;
v.setIntersectVert(false);
float r_px = r.getOrigin().getPosition().getX();
float r_py = r.getOrigin().getPosition().getY();
float r_dx = r.getDirection().getX();
float r_dy = r.getDirection().getY();
float s_px = e->getOrigin().getPosition().getX();
float s_py = e->getOrigin().getPosition().getY();
float s_dx = e->getDirection().getX();
float s_dy = e->getDirection().getY();
float r_mag = sqrt(r_dx*r_dx + r_dy*r_dy);
float s_mag = sqrt(s_dx*s_dx + s_dy*s_dy);
if (r_dx / r_mag == s_dx / s_mag && r_dy / r_mag == s_dy / s_mag)
{
return v;
}
float T2 = (r_dx*(s_py - r_py) + r_dy*(r_px - s_px)) / (s_dx*r_dy - s_dy*r_dx);
float T1 = (s_px + s_dx*T2 - r_px) / r_dx;
if (T1 < 0 /*|| T1 > 1 For Lines*/)
{
return v;
}
if (T2 < 0 || T2 > 1)
{
return v;
}
v.setIntersectVert(true);
v.setPosition(geo::Vector(r_px + r_dx*T1, r_py + r_dy*T1));
return v;
}
geo::Vertex LightModule::getClosestIntersection(Ray r, geo::Polygon *p)
{
geo::Vertex v;
v.setIntersectVert(false);
geo::Vertex v_nearest(geo::Vector(0, 0));
v_nearest.setIntersectVert(false);
geo::Vector h1;
geo::Vector h2;
for (int i = 0; i < p->getEdges().size(); i++)
{
v = this->getIntersection(r, &p->getEdges().at(i));
h1.setX(v.getPosition().getX() - r.getOrigin().getPosition().getX());
h1.setY(v.getPosition().getY() - r.getOrigin().getPosition().getY());
h2.setX(v_nearest.getPosition().getX() - r.getOrigin().getPosition().getX());
h2.setY(v_nearest.getPosition().getY() - r.getOrigin().getPosition().getY());
if (i < 1)
v_nearest = v;
else if (v.isIntersectVert() == true && h1.getLength() < h2.getLength())
{
v_nearest = v;
}
}
return v_nearest;
}
For the Testing i create a Polygon a LightModule and call updateRays and then call the helper-Function callCI().
I know my code gets pretty messy when i have to cascade my getters and setters, ill have to fix that but for the Rest i hope everything is understandable and if not feel free to ask. And just to have mentioned it, I Test-draw my Objects with Vertex-Arrays but I don't need Graphical output of the intersection process, i just need the visible polygon.
Just to point out again: I need a faster way of finding the Intersection-Point between a Ray and a Polygon and as I didn't know if i did something wrong in my code I posted it all here so someone can maybe help me making my code more efficient or show me a different method to solve my problem.
Have a nice day and thank you for your answers :)
Paul
EDIT: Would it be meaningfully faster to first triangulate my polygons and then do a Ray-Triangle intersection Test?
I can't speak to the algorithm (which is possibly what you need) but some immediate thoughts on speeding up what you have.
First off you can define all your getters and setters inline (put them in the class in the header, not the separate source file) so the compiler can optimize the function calls away.
Then these changes might buy you a few frames:
// make sure your getters and setters are inline so the compiler
// can optimize them away
geo::Vertex LightModule::getClosestIntersection(Ray r, geo::Polygon* p)
{
geo::Vertex v;
v.setIntersectVert(false);
geo::Vector h1;
geo::Vector h2;
// cache these
Vector ray_position = r.getOrigin().getPosition();
geo::Vertex v_nearest(geo::Vector(0, 0));
v_nearest.setIntersectVert(false);
// cache size (don't dereference each time)
size_t size = p->getEdges().size();
// avoid acces violation
if(!size)
return v_nearest;
// preset item 0
v_nearest = this->getIntersection(r, &p->getEdges()[0]);
// start from 1 not 0
for(int i = 1; i < size; i++)
{
// don't use at() its slower
// v = this->getIntersection(r, &p->getEdges().at(i));
v = this->getIntersection(r, &p->getEdges()[i]);
// used cached ray position rather than call functions
h1.setX(v.getPosition().getX() - ray_position.getX());
h1.setY(v.getPosition().getY() - ray_position.getY());
h2.setX(v_nearest.getPosition().getX() - ray_position.getX());
h2.setY(v_nearest.getPosition().getY() - ray_position.getY());
// this if not needed because presetting item 0
//if(i < 1)
// v_nearest = v;
if(v.isIntersectVert() == true && h1.getLength() < h2.getLength())
{
v_nearest = v;
}
}
return v_nearest;
}
I removed one of the if statements by calculating the 0 item before the loop and starting the loop from 1, the rest is just caching a much used value and avoiding at() which is slower because it does bound-checking.

c++ Find all values of all objects in a class

I'm making a simple 2d platformer and I need to find all the values of all objects created, these objects would represent the in game collidables. So I would need all of the x/y co-ordinates, width and height so that I can check if any of them are colliding with the player.
Class Looks like:
class CollidableObject
{
public:
CollidableObject();
virtual ~CollidableObject();
int Height;
int Width;
DirectX::SimpleMath::Vector2 position;
bool collidable;
};
It's obviously a very simple class and I just need a way to find out if the player position collides with any of the collidable objects values, I don't need collision code just a way to get at all of the collidable objects values at once. Hope I've made it clear.
class CollisionPred(
public:
CollisionPred( Player p) : p_(p) {}
bool operator()(const ColiidableObject& o) {
// process object and return true if there is a collision, i.e:
return o.Height*o.Height + o.Width*o.Width > p_.distance;
}
private:
Player p_;
;
int main() {
//...
std::vector<CollidableObject> v(100);
std::vector<CollidableObject>::iterator it =
std::find_if(v.begin(), v.end(), CollisionPred());
//...
}
The simplest and yet, the most popular way of doing it is to just iterate through a collection of collidables to check if any collides with a player.
vector<CollidableObject> objects;
for(CollidableObject& obj: objects)
{
if (obj.position.x - obj.width < player.position.x + player.radius
&& obj.position.x + obj.width > player.position.x - player.radius
&& obj.position.y - obj.height < player.position.y + player.radius
&& obj.position.y + obj.height > player.position.y - player.radius
)
// collision happened
}