$extrastylesheet
Olena  User documentation 2.1
An Image Processing Platform
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
paragraph_set.hh
1 // Copyright (C) 2011, 2013 EPITA Research and Development Laboratory (LRDE)
2 //
3 // This file is part of Olena.
4 //
5 // Olena is free software: you can redistribute it and/or modify it under
6 // the terms of the GNU General Public License as published by the Free
7 // Software Foundation, version 2 of the License.
8 //
9 // Olena is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with Olena. If not, see <http://www.gnu.org/licenses/>.
16 //
17 // As a special exception, you may use this file as part of a free
18 // software project without restriction. Specifically, if other files
19 // instantiate templates or use macros or inline functions from this
20 // file, or you compile this file and link it with other files to produce
21 // an executable, this file does not by itself cause the resulting
22 // executable to be covered by the GNU General Public License. This
23 // exception does not however invalidate any other reasons why the
24 // executable file might be covered by the GNU General Public License.
25 
26 #ifndef SCRIBO_CORE_PARAGRAPH_SET_HH
27 # define SCRIBO_CORE_PARAGRAPH_SET_HH
28 
29 # include <mln/util/array.hh>
30 # include <mln/make/relabelfun.hh>
31 # include <mln/value/int_u16.hh>
32 # include <mln/core/concept/function.hh>
33 # include <scribo/core/line_links.hh>
34 # include <scribo/core/line_set.hh>
35 # include <scribo/core/paragraph_info.hh>
36 # include <scribo/core/stats.hh>
37 
38 # include <scribo/core/concept/serializable.hh>
39 # include <scribo/core/tag/paragraph.hh>
40 
41 namespace scribo
42 {
43 
45 
46  namespace internal
47  {
48 
50  template <typename L>
52  {
54  paragraph_set_data(const line_links<L>& llines, unsigned npars);
55 
57  line_set<L> lines_;
58  line_links<L> links_;
59  };
60 
61  } // end of namespace scribo::internal
62 
63 
70  template <typename L>
71  class paragraph_set : public Serializable<paragraph_set<L> >
72  {
74 
75  public:
76  paragraph_set();
78  paragraph_set(const line_links<L>& llinks, unsigned npars);
79 
80  unsigned nelements() const;
81 
82  paragraph_info<L>& operator()(const paragraph_id_t& i);
83  const paragraph_info<L>& operator()(const paragraph_id_t& i) const;
84 
85  bool is_valid() const;
86 
87  // Massively invalidate paragraphs.
88  template <typename F>
89  void invalidate(const Function_v2b<F>& f);
90 
91  const line_set<L>& lines() const;
92 
93  const line_links<L>& links() const;
94 
95  paragraph_set<L> duplicate() const;
96 
97  private:
99  };
100 
101 
102  template <typename L>
103  bool operator==(const paragraph_set<L>& lhs, const paragraph_set<L>& rhs);
104 
105  namespace make
106  {
107 
109  template <typename L>
111  paragraph(const line_links<L>& llinks,
112  const line_links<L>& rlinks);
113 
115  template <typename L>
117  paragraph(const scribo::line_set<L>& lines);
118 
119 
121  template <typename L>
123  paragraph(const line_links<L>& llinks);
124 
125 
126  } // end of namespace scribo::make
127 
128 
129 # ifndef MLN_INCLUDE_ONLY
130 
131  // paragraph_set_data<L> >
132 
133  namespace internal
134  {
135 
136  // data< paragraph_set<L> >
137 
138 
139  template <typename L>
140  inline
141  paragraph_set_data<L>::paragraph_set_data()
142  {
143  }
144 
145 
146  template <typename L>
147  inline
148  paragraph_set_data<L>::paragraph_set_data(const line_links<L>& llinks, unsigned npars)
149  : pars_(npars + 1, paragraph_info<L>(llinks)), links_(llinks)
150  {
151  lines_ = llinks.lines();
152  }
153 
154  } // end of namespace mln::internal
155 
156 
157  template <typename L>
158  paragraph_set<L>::paragraph_set()
159  : data_(0)
160  {
161  }
162 
163  template <typename L>
164  paragraph_set<L>::paragraph_set(internal::paragraph_set_data<L>* data)
165  {
166  data_ = data;
167  }
168 
169  template <typename L>
170  paragraph_set<L>::paragraph_set(const line_links<L>& llinks, unsigned npars)
171  {
172  data_ = new internal::paragraph_set_data<L>(llinks, npars);
173  }
174 
175  template <typename L>
176  unsigned
177  paragraph_set<L>::nelements() const
178  {
179  mln_precondition(data_ != 0);
180  return data_->pars_.nelements() - 1;
181  }
182 
183  template <typename L>
184  paragraph_info<L>&
185  paragraph_set<L>::operator()(const paragraph_id_t& i)
186  {
187  mln_precondition(data_ != 0);
188  return data_->pars_[i];
189  }
190 
191  template <typename L>
192  const paragraph_info<L>&
193  paragraph_set<L>::operator()(const paragraph_id_t& i) const
194  {
195  mln_precondition(data_ != 0);
196  return data_->pars_[i];
197  }
198 
199 
200  template <typename L>
201  bool
202  paragraph_set<L>::is_valid() const
203  {
204  return data_ && !data_->pars_.is_empty();
205  }
206 
207  template <typename L>
208  template <typename F>
209  void
210  paragraph_set<L>::invalidate(const Function_v2b<F>& f_)
211  {
212  const F& f = exact(f_);
213 
214  for_all_paragraphs(p, (*this))
215  if (!f(p))
216  (*this)(p).invalidate();
217  }
218 
219  template <typename L>
220  const line_set<L>&
221  paragraph_set<L>::lines() const
222  {
223  mln_precondition(data_ != 0);
224  return data_->lines_;
225  }
226 
227 
228  template <typename L>
229  const line_links<L>&
230  paragraph_set<L>::links() const
231  {
232  mln_precondition(data_ != 0);
233  return data_->links_;
234  }
235 
236 
237  template <typename L>
238  inline
239  paragraph_set<L>
241  {
242  paragraph_set<L> output;
243  output.data_ = new data_t();
244 
245  *(output.data_.ptr_) = *(data_.ptr_);
246  return output;
247  }
248 
249 
250  template <typename L>
251  bool operator==(const paragraph_set<L>& lhs, const paragraph_set<L>& rhs)
252  {
253  if (! (lhs.lines() == rhs.lines() && lhs.nelements() == rhs.nelements()))
254  {
255  return false;
256  }
257 
258  for_all_paragraphs(p, lhs)
259  if (!(lhs(p) == rhs(p)))
260  {
261  return false;
262  }
263 
264  return true;
265  }
266 
267 
268  namespace make
269  {
270 
271  namespace internal
272  {
273 
274  template <typename L>
275  inline
276  unsigned
277  find_root(line_links<L>& parent, unsigned x)
278  {
279  unsigned tmp_x = x;
280 
281  while (parent(tmp_x) != tmp_x)
282  tmp_x = parent(tmp_x);
283 
284  while (parent(x) != x)
285  {
286  const unsigned tmp = parent(x);
287  x = parent(x);
288  parent(tmp) = tmp_x;
289  }
290 
291  return x;
292  }
293 
294  template <typename L>
295  inline
296  void
297  set_root(line_links<L>& parent, unsigned x, const unsigned root)
298  {
299  while (parent(x) != x && parent(x) != root)
300  {
301  const unsigned tmp = parent(x);
302  x = parent(x);
303  parent(tmp) = root;
304  }
305 
306  parent(x) = root;
307  }
308 
309 
310  } // end of namespace scribo::make::internal
311 
312 
313  // FIXME: move that code into paragraph_set constructor?
314  template <typename L>
316  paragraph(const line_links<L>& llinks,
317  const line_links<L>& rlinks)
318  {
319  line_links<L> links = llinks.duplicate();
320 
321  for_all_links(l, links)
322  {
323  const line_id_t current_neighbor = llinks(l);
324  links(l) = internal::find_root(links, l);
325  const line_id_t root_index = links(l);
326 
327  for (unsigned j = 0; j < rlinks.nelements(); ++j)
328  {
329  if (l != j &&
330  current_neighbor != l &&
331  rlinks(j) == l)
332  internal::set_root(links, j, root_index);
333  }
334  }
335 
336  unsigned npars;
338  par_ids = mln::make::relabelfun(links.line_to_link(),
339  links.nelements() - 1, npars);
340  paragraph_set<L> parset(links, npars);
341 
342  const scribo::line_set<L>& lines = links.lines();
343  for_all_links(l, links)
344  if (links(l))
345  {
346  value::int_u16 par_id = par_ids(l);
347  parset(par_id).add_line(lines(l));
348  }
349 
350  for_all_paragraphs(p, parset)
351  {
352  paragraph_info<L>& current_par = parset(p);
353  stats< float > delta(current_par.nlines());
354 
355  // Update stats
356  current_par.force_stats_update();
357 
358  // Compute paragraph's delta baseline
359  const mln::util::array<line_id_t>& line_ids = current_par.line_ids();
360  const unsigned nelements = line_ids.nelements();
361 
362  for (unsigned i = 0; i < nelements; ++i)
363  {
364  const line_id_t& current_id = line_ids(i);
365 
366  if (llinks(current_id) != current_id)
367  {
368  const line_info<L>& current_line = lines(current_id);
369  const line_info<L>& left_line = lines(llinks(current_id));
370 
371  delta.take(left_line.baseline() - current_line.baseline());
372  }
373  }
374 
375  int median = delta.median();
376 
377  if (!median)
378  median = lines(current_par.line_ids()(0)).x_height();
379 
380  current_par.set_delta_baseline(median);
381  }
382 
383  return parset;
384  }
385 
386 
387  template <typename L>
389  paragraph(const line_links<L>& llinks)
390  {
391  line_links<L> links = llinks.duplicate();
392 
393  for_all_links(l, links)
394  links(l) = internal::find_root(links, l);
395 
396  unsigned npars;
397  mln::fun::i2v::array<unsigned>
398  par_ids = mln::make::relabelfun(links.line_to_link(),
399  links.nelements() - 1, npars);
400  paragraph_set<L> parset(links, npars);
401 
402  const scribo::line_set<L>& lines = links.lines();
403  for_all_links(l, links)
404  if (links(l))
405  {
406  value::int_u16 par_id = par_ids(l);
407  parset(par_id).add_line(lines(l));
408  }
409 
410  for_all_paragraphs(p, parset)
411  parset(p).force_stats_update();
412 
413  return parset;
414  }
415 
416  // FIXME: move that code into paragraph_set constructor?
417  template <typename L>
418  scribo::paragraph_set<L>
419  paragraph(const scribo::line_set<L>& lines)
420  {
421  line_links<L> links(lines);
422  links.init();
423 
424  unsigned npars;
426  par_ids = mln::make::relabelfun(links.line_to_link(),
427  links.nelements() - 1, npars);
428  paragraph_set<L> parset(links, npars);
429 
430  for_all_links(l, links)
431  if (links(l))
432  {
433  value::int_u16 par_id = par_ids(l);
434  parset(par_id).add_line(lines(l));
435  }
436 
437  for_all_paragraphs(p, parset)
438  parset(p).force_stats_update();
439 
440  return parset;
441  }
442 
443 
444 
445  } // end of namespace scribo::make
446 
447 
448 # endif // ! MLN_INCLUDE_ONLY
449 
450 } // end of namespace scribo
451 
452 #endif // ! SCRIBO_CORE_PARAGRAPH_SET_HH