28#ifndef OZZ_ANIMATION_OFFLINE_DECIMATE_H_
29#define OZZ_ANIMATION_OFFLINE_DECIMATE_H_
31#ifndef OZZ_INCLUDE_PRIVATE_HEADER
32#error "This header is private, it cannot be included from public headers."
35#include "ozz/base/containers/stack.h"
36#include "ozz/base/containers/vector.h"
53template <
typename _Track,
typename _Adapter>
54void Decimate(
const _Track& _src,
const _Adapter& _adapter,
float _tolerance,
57 if (_src.size() < 2) {
63 typedef std::pair<size_t, size_t> Segment;
64 ozz::stack<Segment> segments;
67 ozz::vector<bool> included(_src.size(),
false);
70 segments.push(Segment(0, _src.size() - 1));
72 included[_src.size() - 1] =
true;
75 while (!segments.empty()) {
77 const Segment segment = segments.top();
82 size_t candidate = segment.first;
83 typename _Track::const_reference left = _src[segment.first];
84 typename _Track::const_reference right = _src[segment.second];
85 for (
size_t i = segment.first + 1; i < segment.second; ++i) {
86 assert(!included[i] &&
"Included points should be processed once only.");
87 typename _Track::const_reference test = _src[i];
88 if (!_adapter.Decimable(test)) {
92 const float distance =
93 _adapter.Distance(_adapter.Lerp(left, right, test), test);
94 if (distance > _tolerance && distance > max) {
103 if (candidate != segment.first) {
104 included[candidate] =
true;
105 if (candidate - segment.first > 1) {
106 segments.push(Segment(segment.first, candidate));
108 if (segment.second - candidate > 1) {
109 segments.push(Segment(candidate, segment.second));
116 for (
size_t i = 0; i < _src.size(); ++i) {
118 _dest->push_back(_src[i]);
123 if (_dest->size() > 1) {
124 typename _Track::const_iterator end = _dest->end();
125 typename _Track::const_reference last = *(--end);
126 typename _Track::const_reference penultimate = *(--end);
127 const float distance = _adapter.Distance(penultimate, last);
128 if (_adapter.Decimable(last) && distance <= _tolerance) {