NCBI C++ ToolKit
layered_layout_policy.cpp
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* $Id: layered_layout_policy.cpp 47479 2023-05-02 13:24:02Z ucko $
2  * ===========================================================================
3  *
4  * PUBLIC DOMAIN NOTICE
5  * National Center for Biotechnology Information
6  *
7  * This software/database is a "United States Government Work" under the
8  * terms of the United States Copyright Act. It was written as part of
9  * the author's official duties as a United States Government employee and
10  * thus cannot be copyrighted. This software/database is freely available
11  * to the public for use. The National Library of Medicine and the U.S.
12  * Government have not placed any restriction on its use or reproduction.
13  *
14  * Although all reasonable efforts have been taken to ensure the accuracy
15  * and reliability of the software and data, the NLM and the U.S.
16  * Government do not and cannot warrant the performance or results that
17  * may be obtained by using this software or data. The NLM and the U.S.
18  * Government disclaim all warranties, express or implied, including
19  * warranties of performance, merchantability or fitness for any particular
20  * purpose.
21  *
22  * Please cite the author in any work or product based on this material.
23  *
24  * ===========================================================================
25  *
26  * Authors: Liangshou Wu
27  *
28  * File Description:
29  *
30  */
31 
32 #include <ncbi_pch.hpp>
33 #include <corelib/ncbiutil.hpp>
39 
41 
42 static const size_t kMaxObjectNum = 1000;
43 static const int kVertScreenPixel = 400;
44 static const size_t kMinRowPerGroup = 20;
45 
46 ///////////////////////////////////////////////////////////////////////////////
47 /// CLayeredLayout
48 ///////////////////////////////////////////////////////////////////////////////
49 
50 /// special sort by glyph range.
51 /// abosolute less comparison, no overlapping allowed
53 {
54  bool operator()(const CRef<CSeqGlyph>& obj1,
55  const CRef<CSeqGlyph>& obj2) const
56  {
57  //return (obj1->GetRange().GetToOpen() < obj2->GetRange().GetFrom());
58  return (obj1->GetRange() < obj2->GetRange() &&
59  obj1->GetRange().GetTo() < obj2->GetRange().GetFrom());
60  }
61 };
62 
63 /// special sort by glyph geometry size.
64 /// abosolute less comparison, no overlapping allowed
66 {
67  bool operator()(const CRef<CSeqGlyph>& obj1,
68  const CRef<CSeqGlyph>& obj2) const
69  {
70  return obj1->GetRight() < obj2->GetLeft();
71  }
72 };
73 
74 
75 /// a dummy concreate glyph class for layout purpose.
76 class CDummyGlyph : public CSeqGlyph
77 {
78 public:
80  {
81  }
82 
83  void SetRange(const TSeqRange& range)
84  {
85  m_Range = range;
86  }
87 
89  {
90  SetLeft(r.GetFrom());
91  SetWidth(r.GetLength());
92  }
93 
94  /// access the position of this object.
95  TSeqRange GetRange(void) const
96  {
97  return m_Range;
98  }
99 
100 protected:
101  virtual void x_Draw() const {};
102  virtual void x_UpdateBoundingBox() {};
103 
104 private:
106 };
107 
108 
110 {
111  CLayoutGroup::TObjectList& objs(group.GetChildren());
112  size_t obj_num = objs.size();
113  // By default, the objects are sorted by size to promote larger-size
114  // objects to the top. Layout algorithm sorted by object size is
115  // more expensive than the one sorted by object position. When the
116  // object number reaches a predefined limit, we swith the layout
117  // algorithm to the cheaper one.
118  // Note: when there is a maximal row/height constraint, we relax the
119  // maximal object limit (double it) to reduce the chance of overlapping
120  // the larger objects into the last row.
121  if (obj_num < kMaxObjectNum ||
122  (m_MaxRow > 0 && obj_num < kMaxObjectNum * 2)) {
123  x_LayerBySize(group, bound);
124  } else {
125  x_LayerByPos(group, bound);
126  }
127 }
128 
129 
131 {
132 
133  TLayout layout;
134 
135  // If there is a constraint on the maximum row/height of layout,
136  // we simply squeeze the unfit objects to the last row.
137  TLayoutRow last_row;
138 
139  CLayoutGroup::TObjectList& objs(group.GetChildren());
140  if (m_Sorter) {
141  objs.sort(m_Sorter);
142  } else if (!m_Sorted ) {
144  }
145 
146  SGlyphSorter func;
147 
148  CDummyGlyph* range_holder = new CDummyGlyph;
149  CRef<CSeqGlyph> ref_obj(range_holder);
150 
151  TObjectList::const_iterator iter = objs.begin();
152  TObjectList::const_iterator end (objs.end());
153  for ( ; iter != end; ++iter) {
154  CRef<CSeqGlyph> ref(*iter);
155  TModelRange intersect_range(ref->GetLeft() - m_MinDist, ref->GetRight() + m_MinDist);
156  range_holder->SetSize(intersect_range);
157  bool inserted = false;
158  if (!layout.empty()) {
159  auto l_iter = layout.begin();
160  auto l_iter_end = layout.end();
161  if (m_FillEmptySpaces == false) {
162  l_iter = l_iter_end;
163  --l_iter;
164  }
165  for (; l_iter != l_iter_end; ++l_iter) {
166  bool intersects = false;
167  TLayoutRow::iterator row_iter = std::lower_bound(l_iter->begin(), l_iter->end(), ref_obj, func); /* NCBI_FAKE_WARNING: WorkShop */
168  if (row_iter != l_iter->end()) {
169  TModelRange total_range((*row_iter)->GetLeft(), (*row_iter)->GetRight());
170  intersects = intersect_range.IntersectingWith(total_range);
171  }
172  if ( !intersects ) {
173  inserted = true;
174  l_iter->insert(row_iter, ref);
175  ref->SetRowNum(layout.size());
176  break;
177  }
178  }
179  }
180 
181  if ( !inserted ) {
182  if (m_MaxRow < 1 || (int)(layout.size()) < m_MaxRow - 1) {
183  TLayoutRow row;
184  row.push_back(ref);
185  layout.push_back(row);
186  ref->SetRowNum(layout.size());
187  } else {
188  last_row.push_back(ref);
189  }
190  }
191  }
192 
193  if ( !last_row.empty()) {
194  layout.push_back(last_row);
195  auto row_num = layout.size();
196  for (auto& o : last_row) {
197  o->SetRowNum(row_num);
198  }
199  }
200 
201  TModelUnit obj_h = 1.0;
202  if ( !objs.empty() ) {
203  obj_h = objs.front()->GetHeight();
204  }
205  size_t row_num = kVertScreenPixel / (obj_h + m_VertSpace);
206  row_num = max(kMinRowPerGroup, row_num);
207  if (layout.size() > row_num && m_LimitRowPerGroup && m_MaxRow < 1) {
208  x_SeparateObjects(group, layout, bound, row_num, m_VertSpace);
209  } else {
210  x_SetObjectPos(layout, bound);
211  }
212 }
213 
214 
216 {
217  typedef vector<TModelUnit> TRows;
218 
219  TRows rows;
220  TLayout layout;
221 
222  // for cases where there is a max row number limit,
223  // we want to pack all unfit objects to the last row.
224  TLayoutRow last_row;
225  CLayoutGroup::TObjectList& objs(group.GetChildren());
226 
227  if (m_Sorter) {
228  objs.sort(m_Sorter);
229  } else if (!m_Sorted ) {
231  }
232 
233  NON_CONST_ITERATE (TObjectList, iter, objs) {
234  CSeqGlyph* glyph = *iter;
235  TModelRange range(glyph->GetLeft() - m_MinDist, glyph->GetRight());
236  size_t curr = 0;
237  if (!rows.empty()) {
238  if (m_FillEmptySpaces == false)
239  curr = rows.size() - 1;
240  for (; curr < rows.size(); ++curr) {
241  if (rows[curr] < range.GetFrom()) {
242  break;
243  }
244  }
245  }
246 
247  if (curr < rows.size()) {
248  layout[curr].push_back(*iter);
249  (*iter)->SetRowNum(curr);
250  rows[curr] = range.GetTo();
251  } else {
252  if (m_MaxRow < 1 || (int)(layout.size()) < m_MaxRow - 1) {
253  rows.push_back(range.GetTo());
254  TLayoutRow row;
255  row.push_back(*iter);
256  layout.push_back(row);
257  (*iter)->SetRowNum(layout.size());
258 
259  } else {
260  last_row.push_back(*iter);
261  }
262  }
263  }
264 
265  if ( !last_row.empty()) {
266  layout.push_back(last_row);
267  auto row_num = layout.size();
268  for (auto& o : last_row) {
269  o->SetRowNum(row_num);
270  }
271  }
272 
273  TModelUnit obj_h = 1.0;
274  if ( !objs.empty() ) {
275  obj_h = objs.front()->GetHeight();
276  }
277  size_t row_num = kVertScreenPixel / (obj_h + m_VertSpace);
278  row_num = max(kMinRowPerGroup, row_num);
279  if (layout.size() > row_num && m_LimitRowPerGroup && m_MaxRow < 1) {
280  x_SeparateObjects(group, layout, bound, row_num, m_VertSpace);
281  } else {
282  x_SetObjectPos(layout, bound);
283  }
284 }
285 
286 
288 {
289  bound.m_Height = 0.0;
290  bound.m_Width = 0.0;
291  bound.m_X = DBL_MAX;
292  TModelUnit max_h = 0.0;
293  TModelUnit right = 0.0;
294  int total_row = static_cast<int>(layout.size());
295  for (int row = 0; row < total_row; ++row) {
296  TLayoutRow& curr_row = layout[row];
297  bound.m_Height += m_VertSpace;
298  // if the last row contains packed inlined objects with side label,
299  // we need to make sure only labels that can fit will be shown.
300  if (row == total_row - 1 && m_MaxRow > 0 &&
301  m_MaxRow == total_row && curr_row.front()->HasSideLabel()) {
302  CInlineLayout in_layout;
303  in_layout.SetTopMargin(0);
304  TObjectList objs;
305  SBoundingBox r_bound;
306  std::copy(curr_row.begin(), curr_row.end(), std::back_inserter(objs));
307  in_layout.BuildLayout(objs, r_bound);
308 
309  max_h = r_bound.m_Height;
310  bound.m_X = min(bound.m_X, r_bound.m_X);
311  right = max(right, r_bound.m_X + r_bound.m_Width);
312  NON_CONST_ITERATE (TLayoutRow, iter, curr_row) {
313  (*iter)->SetTop(bound.m_Height);
314  }
315  } else {
316  NON_CONST_ITERATE (TLayoutRow, iter, curr_row) {
317  (*iter)->SetTop(bound.m_Height);
318  max_h = max(max_h, (*iter)->GetHeight());
319  bound.m_X = min(bound.m_X, (*iter)->GetLeft());
320  right = max(right, (*iter)->GetRight());
321  }
322  }
323  bound.m_Height += max_h;
324  max_h = 0.0;
325  }
326  bound.m_Width = right - bound.m_X;
327 }
328 
329 
a dummy concreate glyph class for layout purpose.
virtual void x_UpdateBoundingBox()
Update the bounding box assuming children's sizes are fixed if any.
void SetSize(TModelRange r)
virtual void x_Draw() const
The default renderer for this layout object.
TSeqRange GetRange(void) const
access the position of this object.
void SetRange(const TSeqRange &range)
CInlineLayout is the anther simple layout policy that put a list of glyphs in a single line horizonta...
virtual void BuildLayout(CLayoutGroup &group, SBoundingBox &bound) const
CInlineLayout.
void x_LayerBySize(CLayoutGroup &group, SBoundingBox &bound) const
build the layered layout in favor of object size.
virtual void BuildLayout(CLayoutGroup &group, SBoundingBox &bound) const
Build layout for a list of layout objects.
bool m_Sorted
layout object already in sorted order.
int m_MaxRow
Maximal number of rows allowed.
bool m_FillEmptySpaces
< default: true, if possible insert new features in between otherwise only add them to the end of the...
virtual void x_SetObjectPos(TLayout &layout, SBoundingBox &bound) const
Set the objects' position (Y), and update the bounding box of the group (of all objects).
TSeqPos m_MinDist
The minimum distance we permit two items to be within, horizontally.
void x_LayerByPos(CLayoutGroup &group, SBoundingBox &bound) const
build the layered layout in favor of object seq position.
CLayoutGroup is a container of CSeqGlyphs (layout objects).
const TObjectList & GetChildren() const
CLayoutGroup inline methods.
ILayoutPolicy::TObjectList TObjectList
class CSeqGlyph defines an interface that wraps a rectilinear abstract object.
Definition: seq_glyph.hpp:82
void SetRowNum(size_t cur_row)
Definition: seq_glyph.hpp:280
virtual TModelUnit GetRight() const
Definition: seq_glyph.hpp:603
virtual void SetWidth(TModelUnit w)
Definition: seq_glyph.hpp:646
virtual TSeqRange GetRange(void) const
get the total range of this object.
Definition: seq_glyph.hpp:513
virtual void SetLeft(TModelUnit l)
Definition: seq_glyph.hpp:654
virtual TModelUnit GetLeft() const
Definition: seq_glyph.hpp:595
vector< TLayoutRow > TLayout
void x_SeparateObjects(CLayoutGroup &group, TLayout &layout, SBoundingBox &bound, size_t group_size, int vert_space) const
Separate objects into multiple sub-groups.
list< CRef< CSeqGlyph > > TObjectList
vector< CRef< CSeqGlyph > > TLayoutRow
#define NON_CONST_ITERATE(Type, Var, Cont)
Non constant version of ITERATE macro.
Definition: ncbimisc.hpp:822
GLdouble TModelUnit
Definition: gltypes.hpp:48
bool IntersectingWith(const TThisType &r) const
Definition: range.hpp:331
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:103
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
TTo GetTo(void) const
Get the To member data.
Definition: Range_.hpp:269
TFrom GetFrom(void) const
Get the From member data.
Definition: Range_.hpp:222
static const size_t kMinRowPerGroup
static const size_t kMaxObjectNum
static const int kVertScreenPixel
range(_Ty, _Ty) -> range< _Ty >
Useful/utility classes and methods.
T max(T x_, T y_)
T bound(T x_, T xlo_, T xhi_)
T min(T x_, T y_)
double r(size_t dimension_, const Int4 *score_, const double *prob_, double theta_)
void copy(Njn::Matrix< S > *matrix_, const Njn::Matrix< T > &matrix0_)
Definition: njn_matrix.hpp:613
static bool s_CompareCRefs(const CRef< CSeqGlyph > &ref_obj1, const CRef< CSeqGlyph > &ref_obj2)
Definition: seq_glyph.hpp:421
static bool s_CompareCRefs(const CRef< CSeqGlyph > &ref_obj1, const CRef< CSeqGlyph > &ref_obj2)
Definition: seq_glyph.hpp:467
bool operator()(const CRef< CSeqGlyph > &obj1, const CRef< CSeqGlyph > &obj2) const
special sort by glyph geometry size.
bool operator()(const CRef< CSeqGlyph > &obj1, const CRef< CSeqGlyph > &obj2) const
Modified on Sun Mar 03 03:16:08 2024 by modify_doxy.py rev. 669887