Added SpaceGridIterator for SpaceSegment

This commit is contained in:
Michaël Lemaire 2015-10-15 20:01:08 +02:00
parent a91fa41f8f
commit 91cd564c59
8 changed files with 224 additions and 9 deletions

View file

@ -0,0 +1,5 @@
#include "SpaceGridIterator.h"
SpaceGridIterator::SpaceGridIterator()
{
}

View 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

View file

@ -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;
}

View file

@ -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;

View file

@ -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 {

View file

@ -15,6 +15,7 @@ namespace basics {
class Vector3;
class Matrix4;
class BoundingBox;
class SpaceGridIterator;
class SpaceSegment;
class Color;
class NoiseGenerator;

View 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);
}

View file

@ -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 \