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

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
}

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

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.

proper way to store objects in a std vector

Let me explain my problem bit by bit.
This is a 2D game.
I have there simple class.
the first one is a Point class:
class Point {
public:
double x;
double y;
Point(double x, double y)
{
this->x = x;
this->y = y;
};
};
The second one is a class indicating a Edge :
class Edge {
public:
Point startPoint;
Point endPoint;
Edge(Point startPoint, Point endPoint)
{
this->startPoint = startPoint;
this->endPoint = endPoint;
};
};
And then a class indicating a angle point:
class AnglePoint {
public:
Point point;
Edge prevEdge;
Edge nextEdge;
AnglePoint(Point point,
Edge prevEdge,
Edge nextEdge)
{
this->point = point;
this->prevEdge = prevEdge;
this->nextEdge = nextEdge;
};
};
Then I have a std::vector to store the Edge objects I generated:
std::vector<std::vector<Edge>> polyEdgeArray;
And Here is how I initialize the polyEdgeArray:
polyEdgeArray.clear();
for (int i = 0; i < N; i ++) {
std::vector<Edge> edgeArray;
for (int j = 0; j < M; j ++) {
Point s = Point(x, x);
Point e = Point(x, x);
edgeArray.push_back(Edge(s, e));
}
polyEdgeArray.push_back(edgeArray);
}
And I have another vector to hold all the AnglePoint objects:
std::vector<AnglePoint> anglePointArray;
And here is how I initialize the anglePointArray:
for (int i = 0, l = (int)polyEdgeArray.size(); i < l; i ++) {
std::vector<Edge> edgeArray = polyEdgeArray[i];
for (int j = 0, ll = (int)edgeArray.size(); j < ll; j ++) {
Edge edge = edgeArray[j];
Edge preEdge = (j == 0 ? edgeArray[ll - 1] : edgeArray[j - 1]);
Edge nextEdge = (j == ll - 1 ? edgeArray[0] : edgeArray[j + 1]);
addEndPointAnglePoint(edge.startPoint, edge, preEdge, nextEdge);
}
}
void addEndPointAnglePoint(Point& point,
Edge& edge,
Edge& prevEdge,
Edge& nextEdge)
{
AnglePoint anglePoint = AnglePoint(point, prevEdge, nextEdge);
anglePointArray.push_back(anglePoint);
}
And then, here is the background of my game, the number of the polyEdgeArray and anglePointArray will be quite large, say 100000.
And, the polyEdgeArray and anglePointArray will be regenerated / recalculated per frame.
The code above works fine in my game but I am not sure if they are efficient enough.
Based on the information above I have several questions here:
a. For the class Edge, the params in construct is :
Point xxx
will it be better if I change it to :
Point* xxx or `Point& xxx`
b. Similarly about the std::vector<Edge>, should I change it to:
std::vector<Edge*>
c. In my case, which way is the better solution -- to save all the objects without the new operator or with the new operator as pointer.
Any advice will be appreciated, thanks :)
Before you go trying to optimise code because "not sure if they are efficient enough", do measurement to be sure there is a confirmed need. Few things are worse drains on developer time than premature optimisation.
On a quick look though ....
Simplifying the initialisation of polyEdgeArray is simple, assuming you are actually initialising all the points for all the edges using the same value of x.
Point p(x,x);
std::vector<std::vector<Edge>> polyEdgeArray(N, std::vector<Edge>(M, Edge(p,p)));
will do exactly the same thing.
If your code is different (e.g. x is not fixed throughout your loops) however, there are a number of algorithms (in standard header <algorithm>) for initialising a range, or setting the value for all elements in a range using a function. These algorithms are templated, so "value" can mean "instance of appropriate class".
Although I haven't checked if standard algorithms will be usable for initialising your anglePointArray, I suggest you do.
At worst, using standard algorithms - if they are applicable, of course - will make your code easier to understand, therefore easier to get right, and easier to maintain. And there is a fair chance that implementers of the standard library will do a better job of optimising the standard algorithms than you'll be able to achieve in your code to do the same thing.

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.