bool Downsampler::operator() (const Streamline<>& in, Streamline<>& out) const { out.clear(); out.index = in.index; out.weight = in.weight; if (ratio <= 1 || in.empty()) return false; if (in.size() == 1) return true; out.push_back (in.front()); const size_t midpoint = in.size()/2; size_t index = (((midpoint - 1) % ratio) + 1); while (index < in.size() - 1) { out.push_back (in[index]); index += ratio; } out.push_back (in.back()); return true; }
bool FixedNumPoints::operator() (const Streamline<>& in, Streamline<>& out) const { // Perform an explicit calculation of streamline length // From this, derive the spline position of each sample assert (in.size() > 1); out.clear(); out.index = in.index; out.weight = in.weight; value_type length = 0.0; vector<value_type> steps; for (size_t i = 1; i != in.size(); ++i) { const value_type dist = (in[i] - in[i-1]).norm(); length += dist; steps.push_back (dist); } steps.push_back (value_type(0)); Math::Hermite<value_type> interp (hermite_tension); Streamline<> temp (in); const size_t s = temp.size(); temp.insert (temp.begin(), temp[0] + (temp[0] - temp[ 1 ])); temp.push_back ( temp[s] + (temp[s] - temp[s-1])); value_type cumulative_length = value_type(0); size_t input_index = 0; for (size_t output_index = 0; output_index != num_points; ++output_index) { const value_type target_length = length * output_index / value_type(num_points-1); while (input_index < s && (cumulative_length + steps[input_index] < target_length)) cumulative_length += steps[input_index++]; if (input_index == s) { out.push_back (temp[s]); break; } const value_type mu = (target_length - cumulative_length) / steps[input_index]; interp.set (mu); out.push_back (interp.value (temp[input_index], temp[input_index+1], temp[input_index+2], temp[input_index+3])); } return true; }
bool Worker::operator() (Streamline<>& in, Streamline<>& out) const { out.clear(); out.index = in.index; out.weight = in.weight; if (!thresholds (in)) { // Want to test thresholds before wasting time on resampling if (inverse) in.swap (out); return true; } // Assign to ROIs if (properties.include.size() || properties.exclude.size()) { include_visited.assign (properties.include.size(), false); if (ends_only) { for (size_t i = 0; i != 2; ++i) { const Eigen::Vector3f& p (i ? in.back() : in.front()); properties.include.contains (p, include_visited); if (properties.exclude.contains (p)) { if (inverse) in.swap (out); return true; } } } else { for (const auto& p : in) { properties.include.contains (p, include_visited); if (properties.exclude.contains (p)) { if (inverse) in.swap (out); return true; } } } // Make sure all of the include regions were visited for (const auto& i : include_visited) { if (!i) { if (inverse) in.swap (out); return true; } } } if (properties.mask.size()) { // Split tck into separate tracks based on the mask vector<vector<Eigen::Vector3f>> cropped_tracks; vector<Eigen::Vector3f> temp; for (const auto& p : in) { const bool contains = properties.mask.contains (p); if (contains == inverse) { if (temp.size() >= 2) cropped_tracks.push_back (temp); temp.clear(); } else { temp.push_back (p); } } if (temp.size() >= 2) cropped_tracks.push_back (temp); if (cropped_tracks.empty()) return true; if (cropped_tracks.size() == 1) { cropped_tracks[0].swap (out); return true; } // Stitch back together in preparation for sending down queue as a single track out.push_back ({ NaN, NaN, NaN }); for (const auto& i : cropped_tracks) { for (const auto& p : i) out.push_back (p); out.push_back ({ NaN, NaN, NaN }); } return true; } else { if (!inverse) in.swap (out); return true; } }