00001 #ifndef STREAMLINES_H
00002 #define STREAMLINES_H
00003
00004 #include "flowvis_data.h"
00005
00006 #include <vector>
00007 #include <list>
00008 #include <cassert>
00009
00011 struct vec2 {
00012 float x;
00013 float y;
00014
00016 vec2() {}
00018 vec2(float x, float y) : x(x), y(y) {}
00019 };
00020
00022 inline vec2 rotate90(const vec2 &v)
00023 { return vec2(-v.y, v.x); }
00024
00026 inline const float dot(const vec2 &lhs, const vec2 &rhs)
00027 { return lhs.x * rhs.x + lhs.y * rhs.y; }
00028
00030 inline const vec2 operator*(const vec2 &v, float f)
00031 { return vec2(v.x * f, v.y * f); }
00032
00034 inline const vec2 operator+(const vec2 &lhs, const vec2 &rhs)
00035 { return vec2(lhs.x + rhs.x, lhs.y + rhs.y); }
00036
00038 inline const vec2 operator-(const vec2 &lhs, const vec2 &rhs)
00039 { return vec2(lhs.x - rhs.x, lhs.y - rhs.y); }
00040
00042 inline const float length(const vec2 &vec)
00043 { return sqrt(vec.x*vec.x + vec.y*vec.y); }
00044 struct SamplePoint {
00045 vec2 pos;
00046 vec2 dir;
00047 float thickness;
00048 float rotation;
00049
00051 SamplePoint()
00052 : thickness(0.0f)
00053 {
00054 }
00055
00057 SamplePoint(const vec2 &pos, const vec2 &dir, const float &thickness = 1.0f)
00058 : pos(pos), dir(dir), thickness(thickness)
00059 {
00060 float pi = 3.14159265f;
00061
00062 vec2 basic(0, 1);
00063
00064 float radians = acos(dot(basic, dir) / (length(basic) * length(dir)));
00065
00066 if(dir.x < 0)
00067 {
00068 radians = (2 * pi) - radians;
00069 }
00070
00071 radians += (pi / 4);
00072
00073 if(radians >= (2 * pi))
00074 radians -= (2 * pi);
00075
00076 rotation = radians;
00077 }
00078 };
00079
00081 struct SL_Rectangle {
00084 float left, bottom;
00085 float right, top;
00087
00089 SL_Rectangle() {}
00090
00092 SL_Rectangle(float left, float bottom, float right, float top)
00093 : left(left)
00094 , bottom(bottom)
00095 , right(right)
00096 , top(top)
00097 {}
00098
00100 float GetWidth() const
00101 { return right - left; }
00102
00104 float GetHeight() const
00105 { return top - bottom; }
00106 };
00107
00108 namespace detail
00109 {
00111 template <typename T>
00112 class Array2d {
00113 private:
00115
00116 int sizex;
00117 int sizey;
00119
00121 std::vector<T> data;
00122
00123 public:
00125 Array2d(int dimx, int dimy)
00126 : sizex(dimx)
00127 , sizey(dimy)
00128 , data(dimx * dimy)
00129 {}
00130
00132 const T& operator()(int x, int y) const
00133 {
00134 assert(0 <= x && x < sizex);
00135 assert(0 <= y && y < sizey);
00136 return data[x + y * sizex];
00137 }
00138
00140 T& operator()(int x, int y)
00141 {
00142 assert(0 <= x && x < sizex);
00143 assert(0 <= y && y < sizey);
00144 return data[x + y * sizex];
00145 }
00146
00148 const int GetSizeX() const
00149 { return sizex; }
00150
00152 const int GetSizeY() const
00153 { return sizey; }
00154
00156 const std::vector<T>& GetData() const
00157 { return data; }
00158 };
00159 }
00160
00162 typedef std::vector<SamplePoint> Streamline;
00163
00165 class VelocityFunctor
00166 {
00167 public:
00169 VelocityFunctor(FlowVisData *data)
00170 : m_data(data)
00171 {
00172 }
00173
00175 ~VelocityFunctor()
00176 {
00177 }
00178
00180 vec2 operator() (const vec2 &pos)
00181 {
00182 vec3 erg = !(m_data->GetVelocityAt(pos.x, pos.y));
00183
00184 return rotate90(vec2(erg[1], erg[0]));
00185 }
00186
00187 private:
00189 FlowVisData *m_data;
00190 };
00191
00193 enum SLIterAlg{
00195 ITER_RK,
00196
00198 ITER_EULER
00199 };
00200
00202 class StreamlineGenerator {
00203 public:
00206
00207 typedef VelocityFunctor VelocityFunc;
00208
00209 private:
00211 SL_Rectangle domain;
00212
00215 float dsep;
00216 float dtest;
00217
00218 float stepsize;
00219 float stepsize_half;
00220
00221 int maxiter;
00223
00225 SLIterAlg inter_type;
00226
00228 VelocityFunc v;
00229
00231 std::vector<Streamline> streamlines;
00232
00234 size_t grid_add_delay;
00235
00237 detail::Array2d<std::list<vec2> > grid;
00238
00240 std::list<vec2> point_queue;
00241
00242 private:
00243
00245 bool IsOutsideBounds(const vec2 &v) const
00246 {
00252 return !(domain.left <= v.x && v.x <= domain.right
00253 && domain.bottom <= v.y && v.y <= domain.top);
00254 }
00255
00257 void ComputeCellPosition(const vec2 &v, int &cx, int &cy) const
00258 {
00259 cx = (v.x - domain.left) / dsep;
00260 cy = (v.y - domain.bottom) / dsep;
00261 }
00262
00264 void BeginTraceLine();
00265
00267 void EndTraceLine();
00268
00270 float GetMinDistance(const vec2 &v) const;
00271
00273 void PutIntoGrid(const vec2 &v);
00274
00277 void DelayedPutIntoGrid(const vec2 &v);
00278
00280 void TraceLine(const vec2 &startpos, Streamline &sline);
00281
00283 void TraceAndStore(const vec2 &v, Streamline &sl);
00284
00286 float ComputeThickness(float mindist)
00287 { return mindist < dsep ? (mindist - dtest) / (dsep - dtest) : 1.0f; }
00288
00290 bool InterpolateTo(vec2 &position, bool forward);
00291
00292 public:
00294 StreamlineGenerator(
00295 const SL_Rectangle &domain,
00296 float dsep,
00297 float dtest,
00298 float stepsize,
00299 int maxiter,
00300 VelocityFunc v,
00301 SLIterAlg inter_type
00302 );
00303
00305 const std::vector<Streamline>& GetStreamlines() const
00306 { return streamlines; }
00307 };
00308
00309
00310 #endif