Fix 1947076: Infinite error message loop on split tangents.
[synfig.git] / synfig-studio / trunk / src / synfigapp / timegather.cpp
1 /* === S Y N F I G ========================================================= */
2 /*!     \file timegather.cpp
3 **      \brief Time Gather File
4 **
5 **      $Id$
6 **
7 **      \legal
8 **      Copyright (c) 2004 Adrian Bentley
9 **      Copyright (c) 2007 Chris Moore
10 **
11 **      This package is free software; you can redistribute it and/or
12 **      modify it under the terms of the GNU General Public License as
13 **      published by the Free Software Foundation; either version 2 of
14 **      the License, or (at your option) any later version.
15 **
16 **      This package is distributed in the hope that it will be useful,
17 **      but WITHOUT ANY WARRANTY; without even the implied warranty of
18 **      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 **      General Public License for more details.
20 **      \endlegal
21 */
22 /* ========================================================================= */
23
24 /* === H E A D E R S ======================================================= */
25
26 #ifdef USING_PCH
27 #       include "pch.h"
28 #else
29 #ifdef HAVE_CONFIG_H
30 #       include <config.h>
31 #endif
32
33 #include "timegather.h"
34 #include "value_desc.h"
35
36 #include <synfig/layer_pastecanvas.h>
37
38 #include "general.h"
39
40 #endif
41
42 /* === U S I N G =========================================================== */
43
44 using namespace std;
45 using namespace etl;
46 using namespace synfig;
47 using namespace synfigapp;
48
49 /* === M A C R O S ========================================================= */
50
51 /* === G L O B A L S ======================================================= */
52
53 /* === P R O C E D U R E S ================================================= */
54
55 /* === M E T H O D S ======================================================= */
56
57 /* === E N T R Y P O I N T ================================================= */
58
59 //! Definitions for build a list of accurate valuenode references
60
61 void synfigapp::timepoints_ref::insert(synfig::ValueNode_Animated::Handle v, synfig::Waypoint w)
62 {
63         ValueBaseTimeInfo       vt;
64         vt.val = v;
65
66         waytracker::iterator i = waypointbiglist.find(vt);
67
68         if(i != waypointbiglist.end())
69         {
70                 i->waypoints.insert(w);
71         }else
72         {
73                 vt.waypoints.insert(w);
74                 waypointbiglist.insert(vt);
75         }
76 }
77
78 void synfigapp::timepoints_ref::insert(synfigapp::ValueDesc v, synfig::Activepoint a)
79 {
80         ActiveTimeInfo  vt;
81         vt.val = v;
82
83         acttracker::iterator i = actpointbiglist.find(vt);
84
85         if(i != actpointbiglist.end())
86         {
87                 i->activepoints.insert(a);
88                 /*{ //if it fails...
89                         synfig::info("!!!!For some reason it wasn't able to insert the activepoint in the list (%s,%.4lg)",
90                                                         a.state?"true":"false", (double)a.time);
91                 }*/
92         }else
93         {
94                 vt.activepoints.insert(a);
95                 actpointbiglist.insert(vt);
96                 //synfig::info("Insert new activept list for valdesc");
97         }
98 }
99
100 //recursion functions
101 void synfigapp::recurse_canvas(synfig::Canvas::Handle h, const std::set<Time> &tlist,
102                                                                 timepoints_ref &vals, synfig::Time time_offset)
103 {
104
105         //synfig::info("Canvas...\n Recurse through layers");
106         // iterate through the layers
107
108         synfig::Canvas::iterator i = h->begin(), end = h->end();
109
110         for(; i != end; ++i)
111         {
112                 const Node::time_set &tset = (*i)->get_times();
113                 if(check_intersect(tset.begin(),tset.end(),tlist.begin(),tlist.end(),time_offset))
114                 {
115                         recurse_layer(*i,tlist,vals,time_offset);
116                 }
117         }
118 }
119
120 void synfigapp::recurse_layer(synfig::Layer::Handle h, const std::set<Time> &tlist,
121                                                                 timepoints_ref &vals, synfig::Time time_offset)
122 {
123         // iterate through the layers
124         //check for special case of paste canvas
125         etl::handle<synfig::Layer_PasteCanvas> p = etl::handle<synfig::Layer_PasteCanvas>::cast_dynamic(h);
126
127         //synfig::info("Layer...");
128
129         if(p)
130         {
131                 //synfig::info("We are a paste canvas so go into that");
132                 //recurse into the canvas
133                 const synfig::Node::time_set &tset = p->get_sub_canvas()->get_times();
134                 synfig::Time subcanvas_time_offset(time_offset + p->get_time_offset());
135
136                 if(check_intersect(tset.begin(),tset.end(),tlist.begin(),tlist.end(),subcanvas_time_offset))
137                         recurse_canvas(p->get_sub_canvas(),tlist,vals,subcanvas_time_offset);
138         }
139
140         //check all the valuenodes regardless...
141         //synfig::info("Recurse all valuenodes");
142         synfig::Layer::DynamicParamList::const_iterator         i = h->dynamic_param_list().begin(),
143                                                                                                         end = h->dynamic_param_list().end();
144         for(; i != end; ++i)
145         {
146                 const synfig::Node::time_set &tset = i->second->get_times();
147
148                 if(check_intersect(tset.begin(),tset.end(),tlist.begin(),tlist.end(),time_offset))
149                 {
150                         recurse_valuedesc(ValueDesc(h,i->first),tlist,vals,time_offset);
151                 }
152         }
153 }
154
155 template < typename IT, typename CMP >
156 static bool sorted(IT i,IT end, const CMP &cmp = CMP())
157 {
158         if(i == end) return true;
159
160         for(IT last = i++; i != end; last = i++)
161         {
162                 if(!cmp(*last,*i))
163                         return false;
164         }
165
166         return true;
167 }
168
169 void synfigapp::recurse_valuedesc(synfigapp::ValueDesc h, const std::set<Time> &tlist,
170                                                                 timepoints_ref &vals, synfig::Time time_offset)
171 {
172         //special cases for Animated, DynamicList, and Linkable
173
174         //synfig::info("ValueBasenode... %p, %s", h.get_value_node().get(),typeid(*h.get_value_node()).name());
175
176
177         //animated case
178         {
179                 synfig::ValueNode_Animated::Handle p = synfig::ValueNode_Animated::Handle::cast_dynamic(h.get_value_node());
180
181                 if(p)
182                 {
183                         //loop through and determine which waypoint we will need to reference
184                         const synfig::WaypointList &w = p->waypoint_list();
185
186                         synfig::WaypointList::const_iterator i = w.begin(),
187                                                                                                 end = w.end();
188
189                         std::set<Time>::const_iterator          j = tlist.begin(),
190                                                                                                 jend = tlist.end();
191                         for(; i != end && j != jend;)
192                         {
193                                 //synfig::info("tpair t(%.3f) = %.3f", (float)*j, (float)(i->get_time()));
194
195                                 if((*j+time_offset).is_equal(i->get_time()))
196                                 {
197                                         vals.insert(p,*i);
198                                         ++i,++j;
199                                 }else if(*i < *j+time_offset)
200                                 {
201                                         ++i;
202                                 }else ++j;
203                         }
204                         return;
205                 }
206         }
207
208         //parent dynamiclist case - just for active points for that object...
209         if(h.parent_is_value_node())
210         {
211                 synfig::ValueNode_DynamicList::Handle p = synfig::ValueNode_DynamicList::Handle::cast_dynamic(h.get_parent_value_node());
212
213                 if(p)
214                 {
215                         int index = h.get_index();
216
217                         //check all the active points in each list...
218                         const synfig::ActivepointList &a = p->list[index].timing_info;
219
220                         //synfig::info("Our parent = dynamic list, searching in %d activepts",a.size());
221
222                         std::set<Time>::const_iterator                  i = tlist.begin(),
223                                                                                                         end = tlist.end();
224
225                         synfig::ActivepointList::const_iterator         j = a.begin(),
226                                                                                                         jend = a.end();
227
228                         for(; j != jend && i != end;)
229                         {
230                                 double it = *i+time_offset;
231                                 double jt = j->get_time();
232                                 double diff = (double)(it - jt);
233
234                                 //synfig::info("\ttpair match(%.4lg) - %.4lg (diff = %lg",it,jt,diff);
235
236                                 //
237                                 if(abs(diff) < (double)Time::epsilon())
238                                 {
239                                         //synfig::info("\tActivepoint to add being referenced (%x,%s,%.4lg)",
240                                         //                              (int)j->get_uid(),j->state?"true":"false", (double)j->time);
241                                         vals.insert(ValueDesc(p,index),*j);
242                                         ++i,++j;
243                                 }else if(it < jt)
244                                 {
245                                         ++i;
246                                         //synfig::info("\tIncrementing time");
247                                 }
248                                 else
249                                 {
250                                         ++j;
251                                         //synfig::info("\tIncrementing actpt");
252                                 }
253                         }
254                 }
255         }
256
257         //dynamiclist case - we must still make sure that we read from the list entries the time values
258         //                                              because just the linked valuenodes will not do that
259         {
260                 synfig::ValueNode_DynamicList::Handle p = synfig::ValueNode_DynamicList::Handle::cast_dynamic(h.get_value_node());
261
262                 if(p)
263                 {
264                         //synfig::info("Process dynamic list valuenode");
265                         int index = 0;
266
267                         std::vector<synfig::ValueNode_DynamicList::ListEntry>::const_iterator
268                                                         i = p->list.begin(),
269                                                         end = p->list.end();
270
271                         for(; i != end; ++i, ++index)
272                         {
273                                 const Node::time_set &tset = i->get_times();
274
275                                 if(check_intersect(tset.begin(),tset.end(),tlist.begin(),tlist.end(),time_offset))
276                                 {
277                                         recurse_valuedesc(ValueDesc(p,index),tlist,vals,time_offset);
278                                 }
279                         }
280                         return;
281                 }
282         }
283
284         //the linkable case...
285         {
286                 etl::handle<synfig::LinkableValueNode> p = etl::handle<synfig::LinkableValueNode>::cast_dynamic(h.get_value_node());
287
288                 if(p)
289                 {
290                         //synfig::info("Process Linkable ValueBasenode");
291                         int i = 0, size = p->link_count();
292
293                         for(; i < size; ++i)
294                         {
295                                 ValueNode::Handle v = p->get_link(i);
296                                 const Node::time_set &tset = v->get_times();
297
298                                 if(check_intersect(tset.begin(),tset.end(),tlist.begin(),tlist.end(),time_offset))
299                                 {
300                                         recurse_valuedesc(ValueDesc(p,i),tlist,vals,time_offset);
301                                 }
302                         }
303                 }
304         }
305 }