Choreonoid  1.8
RangeLimiter.h
Go to the documentation of this file.
1 
5 #ifndef CNOID_UTIL_RANGE_LIMITER_H_INCLUDED
6 #define CNOID_UTIL_RANGE_LIMITER_H_INCLUDED
7 
8 #include <cmath>
9 #include <vector>
10 #include "exportdecl.h"
11 
12 namespace cnoid {
13 
15 {
16 public:
17  template <class TArray>
18  bool apply(TArray& valueSeq, double upperLimit, double lowerLimit, double limitGrad, double edgeGradRatio = 0.5);
19 
20 private:
21  double uL;
22  double lL;
23  double r;
24 
25  struct TSegment {
26  int begin;
27  int end;
28  double upper;
29  double lower;
30  double uc;
31  double lc;
32  bool isOver;
33  };
34 
35  std::vector<TSegment> segments;
36 
37  CNOID_EXPORT void calcCrossPoint(TSegment* seg);
38  CNOID_EXPORT TSegment* mergeSegment(TSegment* seg, TSegment* prevSeg);
39 
40  template <class TArray>
41  TSegment* finalizeSegment(TSegment* seg, int endFrame, TArray& valueSeq);
42 
43 };
44 
45 template <class TArray>
46 RangeLimiter::TSegment* RangeLimiter::finalizeSegment
47 (RangeLimiter::TSegment* seg, int endFrame, TArray& valueSeq)
48 {
49  seg->end = endFrame;
50  int backFrame = seg->begin - 1;
51  TSegment* prevSeg = &segments[segments.size() - 2];
52  while(backFrame >= 0){
53  if(backFrame < prevSeg->end){
54  return mergeSegment(seg, prevSeg);
55  }
56  double v = valueSeq[backFrame];
57  backFrame--;
58  if((v < seg->uc) && (v > seg->lc)){
59  break;
60  }
61  }
62 
63  backFrame++;
64  seg->begin = backFrame;
65 
66  return seg;
67 }
68 
69 template <class TArray>
71 (TArray& valueSeq, double upperLimit, double lowerLimit, double limitGrad, double edgeGradRatio)
72 {
73  r = limitGrad;
74  uL = upperLimit;
75  lL = lowerLimit;
76 
77  segments.clear();
78 
79  TSegment dummy;
80  dummy.isOver = false;
81  dummy.end = -1;
82  segments.push_back(dummy);
83 
84  segments.push_back(TSegment());
85 
86  TSegment* seg = &segments.back();
87 
88  seg->begin = 0;
89  seg->upper = uL;
90  seg->lower = lL;
91  seg->isOver = false;
92  calcCrossPoint(seg);
93 
94  int frame = 0;
95  int n = valueSeq.size();
96 
97  while(frame < n){
98  double v = valueSeq[frame];
99 
100  bool isOver = false;
101  if(v > seg->upper){
102  isOver = true;
103  seg->upper = v;
104  } else if(v < seg->lower){
105  isOver = true;
106  seg->lower = v;
107  }
108 
109  if(isOver){
110  calcCrossPoint(seg);
111  if(!seg->isOver){
112  seg->isOver = true;
113  seg->begin = frame;
114  }
115  } else if(seg->isOver) {
116  if((v < seg->uc) && (v > seg->lc)){
117  TSegment* finalized = finalizeSegment(seg, frame, valueSeq);
118 
119  if(finalized != seg){
120  seg = finalized;
121  continue;
122  } else {
123  TSegment nextSeg;
124  nextSeg.begin = finalized->end;
125  nextSeg.upper = uL;
126  nextSeg.lower = lL;
127  nextSeg.isOver = false;
128  calcCrossPoint(&nextSeg);
129  segments.push_back(nextSeg);
130  seg = &segments.back();
131  }
132  }
133  }
134  frame++;
135  }
136 
137  if(seg->isOver){
138  while(true) {
139  TSegment* finalized = finalizeSegment(seg, frame, valueSeq);
140  if(finalized == seg){
141  break;
142  }
143  seg = finalized;
144  }
145  } else {
146  segments.pop_back();
147  }
148 
149 
150  for(std::size_t i=1; i < segments.size(); i++){
151  TSegment& seg = segments[i];
152 
153  if(seg.isOver){
154 
155  double ua, ub;
156  if(seg.upper == uL){
157  ua = 0.0;
158  ub = 0.0;
159  } else {
160  double k = ((uL - seg.uc) / (seg.upper - seg.uc)) * edgeGradRatio;
161  double u = seg.upper - seg.uc;
162  double l = uL - seg.uc;
163  ub = ((1.0 - k) * u - 3.0 * (u - l)) / (u * u);
164  ua = (-2.0 * u * ub - 1.0 + k) / (3.0 * u * u);
165  }
166 
167  double la, lb;
168  if(seg.lower == lL){
169  la = 0.0;
170  lb = 0.0;
171  } else {
172  double k = ((lL - seg.lc) / (seg.lower - seg.lc)) * edgeGradRatio;
173  double u = seg.lower - seg.lc;
174  double l = lL - seg.lc;
175  lb = ((1.0 - k) * u - 3.0 * (u - l)) / (u * u);
176  la = (-2.0 * u * lb - 1.0 + k) / (3.0 * u * u);
177  }
178 
179 
180  for(int frame=seg.begin; frame < seg.end; frame++){
181  double v = valueSeq[frame];
182  if(v >= seg.uc){
183  double x = v - seg.uc;
184  valueSeq[frame] = ua * x*x*x + ub * x*x + x + seg.uc;
185  } else if(v <= seg.lc){
186  double x = v - seg.lc;
187  valueSeq[frame] = la * x*x*x + lb * x*x + x + seg.lc;
188  }
189  }
190  }
191  }
192 
193  return true;
194 }
195 }
196 
197 #endif
cnoid::RangeLimiter
Definition: RangeLimiter.h:14
cnoid
Definition: AbstractSceneLoader.h:11
cnoid::RangeLimiter::apply
bool apply(TArray &valueSeq, double upperLimit, double lowerLimit, double limitGrad, double edgeGradRatio=0.5)
Definition: RangeLimiter.h:71