synfig-core  1.0.3
valueoperations.h
Go to the documentation of this file.
1 /* === S Y N F I G ========================================================= */
21 /* ========================================================================= */
22 
23 /* === S T A R T =========================================================== */
24 
25 #ifndef __SYNFIG_VALUEOPERATIONS_H
26 #define __SYNFIG_VALUEOPERATIONS_H
27 
28 /* === H E A D E R S ======================================================= */
29 
30 #include "value.h"
31 #include "transformation.h"
32 #include <vector>
33 
34 /* === M A C R O S ========================================================= */
35 
36 /* === T Y P E D E F S ===================================================== */
37 
38 /* === C L A S S E S & S T R U C T S ======================================= */
39 
40 namespace synfig {
41 
42 namespace types_namespace { class TypeWeightedValueBase; }
43 
48 {
49 private:
51  ValueVector() { }
52 
53 public:
54  static bool check_type(Type &type) {
55  return type == type_bline_point
56  || type == type_matrix
57  || type == type_transformation
58  || type == type_vector;
59  }
60 
61  static bool check_type(const ValueBase &value)
62  { return check_type(value.get_type()); }
63 
64  static Vector get_vector(const ValueBase &value) {
65  Type &type(value.get_type());
66  if (type == type_bline_point)
67  return value.get(BLinePoint()).get_vertex();
68  else
69  if (type == type_matrix)
70  return value.get(Matrix()).get_transformed(Vector(0, 0));
71  else
72  if (type == type_transformation)
73  return value.get(Transformation()).transform(Vector(0,0));
74  else
75  if (type == type_vector)
76  return value.get(Vector());
77  return Vector(0, 0);
78  }
79 };
80 
81 
86 {
87 private:
90 
91 public:
92  static bool check_type(Type &type) {
93  return type == type_angle
94  || type == type_bline_point
95  || type == type_matrix
96  || type == type_segment
97  || type == type_transformation
98  || type == type_vector
99  || type == type_width_point;
100  }
101 
102  static bool check_type(const ValueBase &value)
103  { return check_type(value.get_type()); }
104 
105  static ValueBase transform(const Transformation &transformation, const ValueBase &value) {
106  Type &type(value.get_type());
107  if (type == type_angle)
108  return value.get(Angle()) + transformation.angle;
109  else
110  if (type == type_bline_point)
111  {
112  BLinePoint bp(value.get(BLinePoint()));
113  bp.set_vertex( transformation.transform(bp.get_vertex()) );
114  bp.set_tangent1( transformation.transform(bp.get_tangent1(), false) );
115  bp.set_tangent2( transformation.transform(bp.get_tangent2(), false) );
116  return bp;
117  }
118  else
119  if (type == type_matrix)
120  return transformation.transform(value.get(Matrix()));
121  else
122  if (type == type_segment)
123  {
124  Segment s(value.get(Segment()));
125  s.p1 = transformation.transform(s.p1);
126  s.t1 = transformation.transform(s.t1, false);
127  s.p2 = transformation.transform(s.p2);
128  s.t2 = transformation.transform(s.t2, false);
129  return s;
130  }
131  else
132  if (type == type_transformation)
133  return transformation.transform(value.get(Transformation()));
134  else
135  if (type == type_vector)
136  return transformation.transform(value.get(Vector()));
137  else
138  if (type == type_width_point)
139  {
140  WidthPoint wp(value.get(WidthPoint()));
141  wp.set_width( wp.get_width()*transformation.scale[1] );
142  return wp;
143  }
144  return value;
145  }
146 
147  static ValueBase back_transform(const Transformation &transformation, const ValueBase &value)
148  { return transform(transformation.get_back_transformation(), value); }
149 };
150 
155 {
156 private:
158  ValueAverage() { }
159 
160  static types_namespace::TypeWeightedValueBase *allowed_types[];
161 
162 public:
164  static Type& convert_to_weighted_type(Type &type);
165  static Type& get_type_from_weighted(Type& type);
166 
167  static bool check_weighted_type(Type& type);
168  static bool check_type(Type& type)
169  { return get_weighted_type_for(type) != NULL; }
170  static bool check_type(const ValueBase &value)
171  { return check_type(value.get_type()); }
172 
173  static ValueBase add(const ValueBase &value_a, const ValueBase &value_b, const ValueBase &default_value)
174  {
175  if (value_a.get_type() != value_b.get_type()) return default_value;
176 
177  Type &type(value_a.get_type());
178  if (type == type_real)
179  return value_a.get(Real()) + value_b.get(Real());
180  else
181  if (type == type_bline_point)
182  {
183  BLinePoint res(value_a.get(BLinePoint()));
184  const BLinePoint &b = value_b.get(BLinePoint());
185  res.set_vertex( res.get_vertex() + b.get_vertex() );
186  res.set_tangent1( res.get_tangent1() + b.get_tangent1() );
187  res.set_tangent2( res.get_tangent2() + b.get_tangent2() );
188  return res;
189  }
190  else
191  if (type == type_matrix)
192  return value_a.get(Matrix()) + value_b.get(Matrix());
193  else
194  if (type == type_segment)
195  {
196  Segment res(value_a.get(Segment()));
197  const Segment &b = value_b.get(Segment());
198  res.p1 += b.p1;
199  res.t1 += b.t1;
200  res.p2 += b.p2;
201  res.t2 += b.t2;
202  return res;
203  }
204  else
205  if (type == type_transformation)
206  return Transformation(
207  value_a.get(Transformation()).get_matrix()
208  + value_b.get(Transformation()).get_matrix() );
209  else
210  if (type == type_vector)
211  return value_a.get(Vector()) + value_b.get(Vector());
212  else
213  if (type == type_width_point)
214  {
215  WidthPoint res(value_a.get(WidthPoint()));
216  const WidthPoint &b = value_b.get(WidthPoint());
217  res.set_width( res.get_width() + b.get_width() );
218  return res;
219  }
220 
221  return default_value;
222  }
223 
224  static ValueBase add(const ValueBase &value_a, const ValueBase &value_b)
225  { return add(value_a, value_b, value_a); }
226 
227  static ValueBase multiply(const ValueBase &value, Real amplifier)
228  {
229  Type &type(value.get_type());
230  if (type == type_real)
231  return value.get(Real()) * amplifier;
232  else
233  if (type == type_bline_point)
234  {
235  BLinePoint res(value.get(BLinePoint()));
236  res.set_vertex( res.get_vertex() * amplifier );
237  res.set_tangent1( res.get_tangent1() * amplifier );
238  res.set_tangent2( res.get_tangent2() * amplifier );
239  return res;
240  }
241  else
242  if (type == type_matrix)
243  return value.get(Matrix()) * amplifier;
244  else
245  if (type == type_segment)
246  {
247  Segment res(value.get(Segment()));
248  res.p1 *= amplifier;
249  res.t1 *= amplifier;
250  res.p2 *= amplifier;
251  res.t2 *= amplifier;
252  return res;
253  }
254  else
255  if (type == type_transformation)
256  return Transformation( value.get(Transformation()).get_matrix() * amplifier );
257  else
258  if (type == type_vector)
259  return value.get(Vector()) * amplifier;
260  else
261  if (type == type_width_point)
262  {
263  WidthPoint res(value.get(WidthPoint()));
264  res.set_width( res.get_width() * amplifier );
265  return res;
266  }
267 
268  return value;
269  }
270 
271  // iterators should provide following operations:
272  // comparison i == j, increment ++i, indirection *i, copy constructor i(j)
273  template<typename ConstIterator, typename ConstWeightIterator>
275  ConstIterator begin,
276  ConstIterator end,
277  ConstWeightIterator weight_begin,
278  ConstWeightIterator weight_end,
279  const ValueBase &default_value = ValueBase() )
280  {
281  if (begin == end) return ValueBase();
282 
283  // check values
284  int count = 0;
285  Type &type = (*begin).get_type();
286  if (!check_type(type)) return ValueBase();
287  for(ConstIterator i(begin); !(i == end); ++i, ++count)
288  if ((*i).get_type() != type) return ValueBase();
289 
290  // check weights
291  bool weights = !(weight_begin == weight_end);
292  Real summary_weight = 0.0;
293  int weights_count = 0;
294  if (weights)
295  for(ConstWeightIterator i(weight_begin); !(i == weight_end) && weights_count < count; ++i, ++weights_count)
296  summary_weight += *i;
297  if (weights_count < count || summary_weight == 0.0) weights = false;
298  if (!weights) summary_weight = (Real)count;
299  Real amplifier = 1.0/summary_weight;
300 
301  // process
302  ValueBase summary;
303  if (weights)
304  {
305  // weighted
306  ConstWeightIterator j(weight_begin);
307  ConstIterator i(begin);
308  summary = multiply(*i, (*j) * amplifier);
309  for(++i, ++j; !(i == end); ++i, ++j)
310  summary = add(summary, multiply(*i, (*j) * amplifier), ValueBase());
311  }
312  else
313  {
314  // simple
315  ConstIterator i(begin);
316  summary = multiply(*i, amplifier);
317  for(++i; !(i == end); ++i)
318  summary = add(summary, multiply(*i, amplifier), ValueBase());
319  }
320 
321  return summary.get_type() == type_nil ? default_value : summary;
322  }
323 
324  template<typename ConstIterator>
325  static ValueBase average_generic(ConstIterator begin, ConstIterator end, const ValueBase &default_value = ValueBase())
326  { return average_generic(begin, end, (Real*)NULL, (Real*)NULL, default_value); }
327 
328  static ValueBase average(const ValueBase &list, const ValueBase &weights, const ValueBase &default_value)
329  {
330  if (list.get_type() != type_list) return default_value;
331 
332  const std::vector<ValueBase> &list_vector = list.get_list();
333  if (weights.get_type() == type_list)
334  {
335  std::vector<Real> weights_vector_real;
336  weights_vector_real.reserve(weights.get_list().size());
337  const std::vector<ValueBase> &weights_vector = weights.get_list();
338  for(std::vector<ValueBase>::const_iterator i = weights_vector.begin(); i != weights_vector.end(); ++i)
339  if (i->get_type() == type_real)
340  weights_vector_real.push_back(i->get(Real())); else break;
341  if (weights_vector.size() >= list_vector.size())
342  return average_generic(
343  list_vector.begin(), list_vector.end(),
344  weights_vector_real.begin(), weights_vector_real.end(),
345  default_value );
346  }
347  return average_generic(list_vector.begin(), list_vector.end(), default_value);
348  }
349 
350  static ValueBase average(const ValueBase &list, const ValueBase &weights)
351  { return average(list, weights, ValueBase()); }
352  static ValueBase average(const ValueBase &list)
353  { return average(list, ValueBase()); }
354 
355  static ValueBase average_weighted(const ValueBase &weighted_list, const ValueBase &default_value);
356  static ValueBase average_weighted(const ValueBase &weighted_list)
357  { return average_weighted(weighted_list, ValueBase()); }
358 
359 
360  // iterators should provide following operations:
361  // comparison i == j, increment ++i, indirection *i, copy constructor i(j)
362  template<typename Iterator, typename ConstWeightIterator>
364  Iterator begin,
365  Iterator end,
366  ConstWeightIterator weight_begin,
367  ConstWeightIterator weight_end,
368  const ValueBase &value )
369  {
370  if (begin == end) return;
371 
372  // check values
373  int count = 0;
374  Type &type = (*begin).get_type();
375  if (!check_type(type)) return;
376  for(Iterator i(begin); !(i == end); ++i, ++count)
377  if ((*i).get_type() != type) return;
378 
379  // find difference
380  ValueBase previous_value = average_generic(begin, end, weight_begin, weight_end);
381  ValueBase difference = add(value, multiply(previous_value, -1.0));
382 
383  // simple
384  for(Iterator i(begin); !(i == end); ++i)
385  *i = add(*i, difference);
386  }
387 
388  template<typename Iterator>
389  static void set_average_value_generic(Iterator begin, Iterator end, const ValueBase &value)
390  { set_average_value_generic(begin, end, (Real*)NULL, (Real*)NULL, value); }
391 
392  static void set_average_value(ValueBase &list, const ValueBase &weights, const ValueBase &value)
393  {
394  if (list.get_type() != type_list) return;
395 
396  std::vector<ValueBase> list_vector = list.get_list();
397  if (weights.get_type() == type_list)
398  {
399  std::vector<Real> weights_vector_real;
400  weights_vector_real.reserve(weights.get_list().size());
401  const std::vector<ValueBase> &weights_vector = weights.get_list();
402  for(std::vector<ValueBase>::const_iterator i = weights_vector.begin(); i != weights_vector.end(); ++i)
403  if (i->get_type() == type_real)
404  weights_vector_real.push_back(i->get(Real())); else break;
405  if (weights_vector.size() >= list_vector.size())
406  {
408  list_vector.begin(), list_vector.end(),
409  weights_vector_real.begin(), weights_vector_real.end(),
410  value );
411  return;
412  }
413  }
414  set_average_value_generic(list_vector.begin(), list_vector.end(), value);
415  list = list_vector;
416  }
417 
418  static void set_average_value(ValueBase &list, const ValueBase &value)
419  { return set_average_value(list, ValueBase(), value); }
420 
421  static void set_average_value_weighted(ValueBase &weighted_list, const ValueBase &value);
422 };
423 
424 }; // END of namespace synfig
425 
426 /* === E N D =============================================================== */
427 
428 #endif