std::deque<Vector> FlowMath::computeStreamlineEuler(const Flow& flow, const Vector& r0, const float length, const float stepwidth, int* const startIndex, const tgt::vec2& thresholds) { // N: number of partitions // const float h = fabsf(stepwidth); float fn = ceilf(fabsf(length) / h); const unsigned int N = (length != 0.0f) ? static_cast<unsigned int>(fn) : 0; Vector r(r0), r_(r0); std::deque<Vector> points; points.push_back(r0); int indexR0 = 0; bool lookupPos = true; // integrate along the streamline in positive direction? bool lookupNeg = true; // integrate along the streamline in negative direction? bool useThresholds = (thresholds != tgt::vec2::zero); for (unsigned int i = 0; ((N == 0) || (i < N)) ; ++i) { if (lookupPos == true) { const Vector& v = flow.lookupFlow(r); if (useThresholds == true) { float magnitude = tgt::length(v); if ((magnitude < thresholds.x) || (magnitude > thresholds.y)) { lookupPos = false; break; } } if (v != Vector::zero) { r += normalize(v) * h; lookupPos = flow.isInsideBoundings(r); if (r == points.back()) // in case of no progress on streamline in this direction... lookupPos = false; else if (lookupPos == true) points.push_back(r); } else lookupPos = false; } if (lookupNeg == true) { const Vector& v = flow.lookupFlow(r_); if (useThresholds == true) { float magnitude = tgt::length(v); if ((magnitude < thresholds.x) || (magnitude > thresholds.y)) { lookupNeg = false; break; } } if (v != Vector::zero) { r_ -= normalize(v) * h; lookupNeg = flow.isInsideBoundings(r_); if (r_ == points.front()) // in case of no progress on streamline in this direction... lookupNeg = false; else if (lookupNeg == true) { points.push_front(r_); ++indexR0; } } else lookupNeg = false; } if ((lookupPos == false) && (lookupNeg == false)) break; } // for ( ; ; ++i) if (startIndex != 0) *startIndex = indexR0; return points; }
std::deque<Vector> FlowMath::computeStreamlineRungeKutta(const Flow& flow, const Vector& r0, const float length, const float stepwidth, int* const startIndex, const tgt::vec2& thresholds) { // N: number of partitions // const float h = fabsf(stepwidth); float fn = ceilf(fabsf(length) / h); const unsigned int N = (length != 0.0f) ? static_cast<unsigned int>(fn) : 0; Vector r(r0), r_(r0); Vector k1(0.0f), k2(0.0f), k3(0.0f), k4(0.0f); Vector k1_(0.0f), k2_(0.0f), k3_(0.0f), k4_(0.0f); std::deque<Vector> points; // points on streamline in positive direction points.push_back(r0); // avoid that one of the deque is empty int indexR0 = 0; // position of r0 within deque bool lookupPos = true; // integrate along the streamline in positive direction? bool lookupNeg = true; // integrate along the streamline in negative direction? bool useThresholds = (thresholds != tgt::vec2::zero); for (unsigned int i = 0; ((N == 0) || (i < N)); ++i) { if (lookupPos == true) { const Vector& v = flow.lookupFlow(r); if (useThresholds == true) { float magnitude = tgt::length(v); if ((magnitude < thresholds.x) || (magnitude > thresholds.y)) { lookupPos = false; break; } } if (v != Vector::zero) { k1 = normalize(v) * h; k2 = normalize( flow.lookupFlow(r + (k1 / 2.0f)) ) * h; k3 = normalize( flow.lookupFlow(r + (k2 / 2.0f)) ) * h; k4 = normalize( flow.lookupFlow(r + k3) ) * h; r += ((k1 / 6.0f) + (k2 / 3.0f) + (k3 / 3.0f) + (k4 / 6.0f)); lookupPos = flow.isInsideBoundings(r); if (r == points.back()) // in case of no progress on streamline in this direction... lookupPos = false; else if (lookupPos == true) points.push_back(r); } else lookupPos = false; } if (lookupNeg == true) { const Vector& v = flow.lookupFlow(r_); if (useThresholds == true) { float magnitude = tgt::length(v); if ((magnitude < thresholds.x) || (magnitude > thresholds.y)) { lookupNeg = false; break; } } if (v != Vector::zero) { k1_ = normalize(v) * h; k2_ = normalize( flow.lookupFlow(r_ - (k1_ / 2.0f)) ) * h; k3_ = normalize( flow.lookupFlow(r_ - (k2_ / 2.0f)) ) * h; k4_ = normalize( flow.lookupFlow(r_ - k3_) ) * h; r_ -= ((k1_ / 6.0f) + (k2_ / 3.0f) + (k3_ / 3.0f) + (k4_ / 6.0f)); lookupNeg = flow.isInsideBoundings(r_); if (r_ == points.front()) // in case of no progress on streamline in this direction... lookupNeg = false; else if (lookupNeg == true) { points.push_front(r_); ++indexR0; } } else lookupNeg = false; } if ((lookupPos == false) && (lookupNeg == false)) break; } // for (; ; ++i) if (startIndex != 0) *startIndex = indexR0; return points; }