Added SpaceGridIterator for SpaceSegment
This commit is contained in:
parent
a91fa41f8f
commit
91cd564c59
8 changed files with 224 additions and 9 deletions
5
src/basics/SpaceGridIterator.cpp
Normal file
5
src/basics/SpaceGridIterator.cpp
Normal file
|
@ -0,0 +1,5 @@
|
|||
#include "SpaceGridIterator.h"
|
||||
|
||||
SpaceGridIterator::SpaceGridIterator()
|
||||
{
|
||||
}
|
30
src/basics/SpaceGridIterator.h
Normal file
30
src/basics/SpaceGridIterator.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
#ifndef SPACEGRIDITERATOR_H
|
||||
#define SPACEGRIDITERATOR_H
|
||||
|
||||
#include "basics_global.h"
|
||||
|
||||
namespace paysages {
|
||||
namespace basics {
|
||||
|
||||
/**
|
||||
* Iterator delegate that can receive sequential grid coordinates.
|
||||
*
|
||||
* This may be useful for ray marching algorithms for example.
|
||||
*/
|
||||
class BASICSSHARED_EXPORT SpaceGridIterator
|
||||
{
|
||||
public:
|
||||
SpaceGridIterator();
|
||||
|
||||
/**
|
||||
* Abstract method to implement to receive grid coordinates.
|
||||
*
|
||||
* Return false to interrupt the iteration, true to continue.
|
||||
*/
|
||||
virtual bool onCell(int x, int y, int z) = 0;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // SPACEGRIDITERATOR_H
|
|
@ -1,5 +1,8 @@
|
|||
#include "SpaceSegment.h"
|
||||
|
||||
#include <climits>
|
||||
#include "SpaceGridIterator.h"
|
||||
|
||||
SpaceSegment::SpaceSegment(const Vector3& start, const Vector3& end):
|
||||
start(start), end(end)
|
||||
{
|
||||
|
@ -54,3 +57,81 @@ bool SpaceSegment::intersectYInterval(double ymin, double ymax)
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
SpaceSegment SpaceSegment::projectedOnXPlane(double x) const
|
||||
{
|
||||
return SpaceSegment(Vector3(x, start.y, start.z), Vector3(x, end.y, end.z));
|
||||
}
|
||||
|
||||
SpaceSegment SpaceSegment::projectedOnYPlane(double y) const
|
||||
{
|
||||
return SpaceSegment(Vector3(start.x, y, start.z), Vector3(end.x, y, end.z));
|
||||
}
|
||||
|
||||
SpaceSegment SpaceSegment::projectedOnZPlane(double z) const
|
||||
{
|
||||
return SpaceSegment(Vector3(start.x, start.y, z), Vector3(end.x, end.y, z));
|
||||
}
|
||||
|
||||
SpaceSegment SpaceSegment::scaled(double factor) const
|
||||
{
|
||||
return SpaceSegment(start.scale(factor), end.scale(factor));
|
||||
}
|
||||
|
||||
bool SpaceSegment::iterateOnGrid(SpaceGridIterator &delegate)
|
||||
{
|
||||
Vector3 diff = end.sub(start);
|
||||
|
||||
int stepX = diff.x < 0.0 ? -1 : 1;
|
||||
int stepY = diff.y < 0.0 ? -1 : 1;
|
||||
int stepZ = diff.z < 0.0 ? -1 : 1;
|
||||
int X = (int)floor(start.x);
|
||||
int Y = (int)floor(start.y);
|
||||
int Z = (int)floor(start.z);
|
||||
int limitX = (int)floor(end.x) + stepX;
|
||||
int limitY = (int)floor(end.y) + stepY;
|
||||
int limitZ = (int)floor(end.z) + stepZ;
|
||||
double tDeltaX = diff.x == 0.0 ? 0.0 : 1.0 / fabs(diff.x);
|
||||
double tDeltaY = diff.y == 0.0 ? 0.0 : 1.0 / fabs(diff.y);
|
||||
double tDeltaZ = diff.z == 0.0 ? 0.0 : 1.0 / fabs(diff.z);
|
||||
double tMaxX = diff.x == 0.0 ? INFINITY : ((double)(X + (stepX > 0 ? 1 : 0)) - start.x) / diff.x;
|
||||
double tMaxY = diff.y == 0.0 ? INFINITY : ((double)(Y + (stepY > 0 ? 1 : 0)) - start.y) / diff.y;
|
||||
double tMaxZ = diff.z == 0.0 ? INFINITY : ((double)(Z + (stepZ > 0 ? 1 : 0)) - start.z) / diff.z;
|
||||
|
||||
do
|
||||
{
|
||||
if (not delegate.onCell(X, Y, Z))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tMaxX < tMaxY)
|
||||
{
|
||||
if (tMaxX < tMaxZ)
|
||||
{
|
||||
X = X + stepX;
|
||||
tMaxX = tMaxX + tDeltaX;
|
||||
}
|
||||
else
|
||||
{
|
||||
Z = Z + stepZ;
|
||||
tMaxZ = tMaxZ + tDeltaZ;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(tMaxY < tMaxZ)
|
||||
{
|
||||
Y = Y + stepY;
|
||||
tMaxY = tMaxY + tDeltaY;
|
||||
}
|
||||
else
|
||||
{
|
||||
Z= Z + stepZ;
|
||||
tMaxZ = tMaxZ + tDeltaZ;
|
||||
}
|
||||
}
|
||||
} while (X != limitX and Y != limitY and Z != limitZ);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
namespace paysages {
|
||||
namespace basics {
|
||||
|
||||
/*!
|
||||
* \brief A segment in 3D space (mainly useful for rays).
|
||||
/**
|
||||
* A delimited segment in 3D space (mainly useful for rays).
|
||||
*/
|
||||
class BASICSSHARED_EXPORT SpaceSegment
|
||||
{
|
||||
|
@ -17,19 +17,53 @@ public:
|
|||
SpaceSegment(const Vector3& start, const Vector3& end);
|
||||
SpaceSegment(): SpaceSegment(Vector3(), Vector3()) {}
|
||||
|
||||
inline Vector3 getStart() const {return start;}
|
||||
inline Vector3 getEnd() const {return end;}
|
||||
inline const Vector3 &getStart() const {return start;}
|
||||
inline const Vector3 &getEnd() const {return end;}
|
||||
inline Vector3 getDirection() const {return end.sub(start);}
|
||||
inline double getLength() const {return end.sub(start).getNorm();}
|
||||
|
||||
inline double getXDiff() const {return end.x - start.x;}
|
||||
inline double getYDiff() const {return end.y - start.y;}
|
||||
inline double getZDiff() const {return end.z - start.z;}
|
||||
|
||||
/*!
|
||||
* \brief Keep only the intersection with a slice orthogonal to the Y axis.
|
||||
* \return true if a segment remains
|
||||
/**
|
||||
* Keep only the intersection with a slice orthogonal to the Y axis.
|
||||
*
|
||||
* Return true if a segment remains.
|
||||
*/
|
||||
bool intersectYInterval(double ymin, double ymax);
|
||||
|
||||
/**
|
||||
* Return a version of this segment, projected on a X plane.
|
||||
*/
|
||||
SpaceSegment projectedOnXPlane(double x=0.0) const;
|
||||
/**
|
||||
* Return a version of this segment, projected on a Y plane.
|
||||
*/
|
||||
SpaceSegment projectedOnYPlane(double y=0.0) const;
|
||||
/**
|
||||
* Return a version of this segment, projected on a Z plane.
|
||||
*/
|
||||
SpaceSegment projectedOnZPlane(double z=0.0) const;
|
||||
|
||||
/**
|
||||
* Return a scaled version of this segment.
|
||||
*
|
||||
* Pay attention, scaling is done from the coordinates origin (0,0,0), not the segment center.
|
||||
*/
|
||||
SpaceSegment scaled(double factor) const;
|
||||
|
||||
/**
|
||||
* Iterate inside a virtual grid.
|
||||
*
|
||||
* The space is considered as cut into 1.0-sized cubic cells,
|
||||
* and the delegate will be called with coordinates of the cells
|
||||
* traversed by this segment.
|
||||
*
|
||||
* Return false if the iteration was aborted by the delegate, true otherwise.
|
||||
*/
|
||||
bool iterateOnGrid(SpaceGridIterator &delegate);
|
||||
|
||||
private:
|
||||
Vector3 start;
|
||||
Vector3 end;
|
||||
|
|
|
@ -33,7 +33,8 @@ SOURCES += \
|
|||
Texture3D.cpp \
|
||||
Texture4D.cpp \
|
||||
NoiseState.cpp \
|
||||
FractalNoise.cpp
|
||||
FractalNoise.cpp \
|
||||
SpaceGridIterator.cpp
|
||||
|
||||
HEADERS +=\
|
||||
basics_global.h \
|
||||
|
@ -54,7 +55,8 @@ HEADERS +=\
|
|||
Texture3D.h \
|
||||
Texture4D.h \
|
||||
NoiseState.h \
|
||||
FractalNoise.h
|
||||
FractalNoise.h \
|
||||
SpaceGridIterator.h
|
||||
|
||||
unix:!symbian {
|
||||
maemo5 {
|
||||
|
|
|
@ -15,6 +15,7 @@ namespace basics {
|
|||
class Vector3;
|
||||
class Matrix4;
|
||||
class BoundingBox;
|
||||
class SpaceGridIterator;
|
||||
class SpaceSegment;
|
||||
class Color;
|
||||
class NoiseGenerator;
|
||||
|
|
61
src/tests/SpaceSegment_Test.cpp
Normal file
61
src/tests/SpaceSegment_Test.cpp
Normal file
|
@ -0,0 +1,61 @@
|
|||
#include "BaseTestCase.h"
|
||||
|
||||
#include "SpaceSegment.h"
|
||||
#include "SpaceGridIterator.h"
|
||||
|
||||
class CollectGridIterator: public SpaceGridIterator
|
||||
{
|
||||
public:
|
||||
std::vector<Vector3> locations;
|
||||
protected:
|
||||
virtual bool onCell(int x, int y, int z) override
|
||||
{
|
||||
locations.push_back(Vector3(x, y, z));
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
TEST(SpaceSegment, iterateOnGrid)
|
||||
{
|
||||
CollectGridIterator it;
|
||||
SpaceSegment segment(Vector3(0.5, 1.5, 0.0), Vector3(2.5, 0.5, 0.0));
|
||||
segment.iterateOnGrid(it);
|
||||
|
||||
ASSERT_EQ(4, it.locations.size());
|
||||
EXPECT_VECTOR3_COORDS(it.locations[0], 0.0, 1.0, 0.0);
|
||||
EXPECT_VECTOR3_COORDS(it.locations[1], 1.0, 1.0, 0.0);
|
||||
EXPECT_VECTOR3_COORDS(it.locations[2], 1.0, 0.0, 0.0);
|
||||
EXPECT_VECTOR3_COORDS(it.locations[3], 2.0, 0.0, 0.0);
|
||||
}
|
||||
|
||||
TEST(SpaceSegment, iterateOnGrid_Corner)
|
||||
{
|
||||
CollectGridIterator it;
|
||||
SpaceSegment segment(Vector3(0.5, 0.5, 0.5), Vector3(2.5, 2.5, 2.5));
|
||||
segment.iterateOnGrid(it);
|
||||
|
||||
ASSERT_EQ(7, it.locations.size());
|
||||
EXPECT_VECTOR3_COORDS(it.locations[0], 0.0, 0.0, 0.0);
|
||||
EXPECT_VECTOR3_COORDS(it.locations[3], 1.0, 1.0, 1.0);
|
||||
EXPECT_VECTOR3_COORDS(it.locations[6], 2.0, 2.0, 2.0);
|
||||
}
|
||||
|
||||
TEST(SpaceSegment, iterateOnGrid_OneCell)
|
||||
{
|
||||
CollectGridIterator it;
|
||||
SpaceSegment segment(Vector3(8.1, 8.2, 8.9), Vector3(8.9, 8.3, 8.6));
|
||||
segment.iterateOnGrid(it);
|
||||
|
||||
ASSERT_EQ(1, it.locations.size());
|
||||
EXPECT_VECTOR3_COORDS(it.locations[0], 8.0, 8.0, 8.0);
|
||||
}
|
||||
|
||||
TEST(SpaceSegment, iterateOnGrid_Negative)
|
||||
{
|
||||
CollectGridIterator it;
|
||||
SpaceSegment segment(Vector3(-8.1, -8.2, -8.9), Vector3(-8.9, -8.3, -8.6));
|
||||
segment.iterateOnGrid(it);
|
||||
|
||||
ASSERT_EQ(1, it.locations.size());
|
||||
EXPECT_VECTOR3_COORDS(it.locations[0], -9.0, -9.0, -9.0);
|
||||
}
|
|
@ -18,6 +18,7 @@ SOURCES += main.cpp \
|
|||
FluidMediumManager_Test.cpp \
|
||||
VertexArray_Test.cpp \
|
||||
FractalNoise_Test.cpp \
|
||||
SpaceSegment_Test.cpp \
|
||||
Canvas_Test.cpp \
|
||||
CanvasPortion_Test.cpp \
|
||||
CanvasPreview_Test.cpp \
|
||||
|
|
Loading…
Reference in a new issue