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 "SpaceSegment.h"
|
||||||
|
|
||||||
|
#include <climits>
|
||||||
|
#include "SpaceGridIterator.h"
|
||||||
|
|
||||||
SpaceSegment::SpaceSegment(const Vector3& start, const Vector3& end):
|
SpaceSegment::SpaceSegment(const Vector3& start, const Vector3& end):
|
||||||
start(start), end(end)
|
start(start), end(end)
|
||||||
{
|
{
|
||||||
|
@ -54,3 +57,81 @@ bool SpaceSegment::intersectYInterval(double ymin, double ymax)
|
||||||
|
|
||||||
return true;
|
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 paysages {
|
||||||
namespace basics {
|
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
|
class BASICSSHARED_EXPORT SpaceSegment
|
||||||
{
|
{
|
||||||
|
@ -17,19 +17,53 @@ public:
|
||||||
SpaceSegment(const Vector3& start, const Vector3& end);
|
SpaceSegment(const Vector3& start, const Vector3& end);
|
||||||
SpaceSegment(): SpaceSegment(Vector3(), Vector3()) {}
|
SpaceSegment(): SpaceSegment(Vector3(), Vector3()) {}
|
||||||
|
|
||||||
inline Vector3 getStart() const {return start;}
|
inline const Vector3 &getStart() const {return start;}
|
||||||
inline Vector3 getEnd() const {return end;}
|
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 getXDiff() const {return end.x - start.x;}
|
||||||
inline double getYDiff() const {return end.y - start.y;}
|
inline double getYDiff() const {return end.y - start.y;}
|
||||||
inline double getZDiff() const {return end.z - start.z;}
|
inline double getZDiff() const {return end.z - start.z;}
|
||||||
|
|
||||||
/*!
|
/**
|
||||||
* \brief Keep only the intersection with a slice orthogonal to the Y axis.
|
* Keep only the intersection with a slice orthogonal to the Y axis.
|
||||||
* \return true if a segment remains
|
*
|
||||||
|
* Return true if a segment remains.
|
||||||
*/
|
*/
|
||||||
bool intersectYInterval(double ymin, double ymax);
|
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:
|
private:
|
||||||
Vector3 start;
|
Vector3 start;
|
||||||
Vector3 end;
|
Vector3 end;
|
||||||
|
|
|
@ -33,7 +33,8 @@ SOURCES += \
|
||||||
Texture3D.cpp \
|
Texture3D.cpp \
|
||||||
Texture4D.cpp \
|
Texture4D.cpp \
|
||||||
NoiseState.cpp \
|
NoiseState.cpp \
|
||||||
FractalNoise.cpp
|
FractalNoise.cpp \
|
||||||
|
SpaceGridIterator.cpp
|
||||||
|
|
||||||
HEADERS +=\
|
HEADERS +=\
|
||||||
basics_global.h \
|
basics_global.h \
|
||||||
|
@ -54,7 +55,8 @@ HEADERS +=\
|
||||||
Texture3D.h \
|
Texture3D.h \
|
||||||
Texture4D.h \
|
Texture4D.h \
|
||||||
NoiseState.h \
|
NoiseState.h \
|
||||||
FractalNoise.h
|
FractalNoise.h \
|
||||||
|
SpaceGridIterator.h
|
||||||
|
|
||||||
unix:!symbian {
|
unix:!symbian {
|
||||||
maemo5 {
|
maemo5 {
|
||||||
|
|
|
@ -15,6 +15,7 @@ namespace basics {
|
||||||
class Vector3;
|
class Vector3;
|
||||||
class Matrix4;
|
class Matrix4;
|
||||||
class BoundingBox;
|
class BoundingBox;
|
||||||
|
class SpaceGridIterator;
|
||||||
class SpaceSegment;
|
class SpaceSegment;
|
||||||
class Color;
|
class Color;
|
||||||
class NoiseGenerator;
|
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 \
|
FluidMediumManager_Test.cpp \
|
||||||
VertexArray_Test.cpp \
|
VertexArray_Test.cpp \
|
||||||
FractalNoise_Test.cpp \
|
FractalNoise_Test.cpp \
|
||||||
|
SpaceSegment_Test.cpp \
|
||||||
Canvas_Test.cpp \
|
Canvas_Test.cpp \
|
||||||
CanvasPortion_Test.cpp \
|
CanvasPortion_Test.cpp \
|
||||||
CanvasPreview_Test.cpp \
|
CanvasPreview_Test.cpp \
|
||||||
|
|
Loading…
Reference in a new issue