snark
PointMap.h
1 // This file is part of snark, a generic and flexible library
2 // for robotics research.
3 //
4 // Copyright (C) 2011 The University of Sydney
5 //
6 // snark is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 3 of the License, or (at your option) any later version.
10 //
11 // snark is distributed in the hope that it will be useful, but WITHOUT ANY
12 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
14 // for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with snark. If not, see <http://www.gnu.org/licenses/>.
18 
19 #ifndef SNARK_GRAPHICS_APPLICATIONS_LABELPOINTS_POINTMAP_H_
20 #define SNARK_GRAPHICS_APPLICATIONS_LABELPOINTS_POINTMAP_H_
21 
22 #include <map>
23 #include <sstream>
24 #include <string>
25 #include <boost/optional.hpp>
26 #include <boost/static_assert.hpp>
27 #include <comma/math/compare.h>
28 
29 namespace snark {
30 
31 namespace impl {
32 
33 template< typename K, typename T, std::size_t D, typename Compare = std::less< T > >
34 struct MultidimensionalMapimpl : public std::map< K, MultidimensionalMapimpl< K, T, D - 1, Compare >, Compare >
35 {
36  typedef MultidimensionalMapimpl< K, T, D - 1, Compare > Basevalue_type;
37  typedef std::map< K, Basevalue_type, Compare > Base;
38 
39  template < typename P >
40  std::vector< T* > find( const P& p )
41  {
42  typename Base::iterator it = this->Base::find( p[ p.size() - D ] );
43  if( it == this->Base::end() ) { return std::vector< T* >(); }
44  return it->second.find( p );
45  }
46 
47  template < typename P >
48  void erase( const P& p )
49  {
50  typename Base::iterator it = this->Base::find( p[ p.size() - D ] );
51  if( it == this->Base::end() ) { return; }
52  it->second.erase( p );
53  if( it->second.empty() ) { this->Base::erase( it ); }
54  }
55 
56  template < typename P >
57  void insert( const P& p, const T& t ) { this->Base::operator[]( p[ p.size() - D ] ).insert( p, t ); }
58 
59  template < typename P >
60  void find( MultidimensionalMapimpl& m, const P& lower, const P& upper ) const
61  {
62  typename Base::const_iterator i = this->Base::lower_bound( lower[ lower.size() - D ] );
63  typename Base::const_iterator j = this->Base::upper_bound( upper[ upper.size() - D ] );
64  for( ; i != j; ++i )
65  {
66  i->second.find( m[ i->first ], lower, upper );
67  if( m[ i->first ].empty() ) { m.MultidimensionalMapimpl::Base::erase( i->first ); } // quick and dirty, fix later
68  }
69  }
70 
71  std::size_t size() const
72  {
73  std::size_t s = 0;
74  for( typename Base::const_iterator i = this->Base::begin(); i != this->Base::end(); ++i ) { s += i->second.size(); }
75  return s;
76  }
77 
78  struct Enumerator // too lame to be called iterator
79  {
80  void operator++()
81  {
82  if( it == map->end() ) { return; }
83  if( en.it != en.map->end() ) { ++en; if( en.it != en.map->end() ) { return; } }
84  ++it;
85  if( it == map->end() ) { return; }
86  it->second.setBegin( en );
87  }
88  template < typename P >
89  void get( P& key, T*& value )
90  {
91  if( it == map->end() ) { value = NULL; return; }
92  key[ key.size() - D ] = it->first;
93  en.get( key, value );
94  }
95  typename Base::iterator it;
96  typename Basevalue_type::Enumerator en;
97  MultidimensionalMapimpl* map;
98  };
99 
100  void setBegin( Enumerator& e )
101  {
102  e.map = const_cast< MultidimensionalMapimpl* >( this );
103  e.it = e.map->Base::begin();
104  if( e.it != this->Base::end() ) { e.it->second.setBegin( e.en ); }
105  }
106 
107  void toString( std::ostringstream& oss, const std::string& indent = "" ) const
108  {
109  oss << indent << "[" << D << "]: size = " << this->Base::size() << ":" << std::endl;
110  for( typename Base::const_iterator it = this->Base::begin(); it != this->Base::end(); ++it )
111  {
112  oss << indent << " " << it->first << ":" << std::endl;
113  it->second.toString( oss, indent + " " );
114  }
115  }
116 };
117 
118 template< typename K, typename T, typename Compare >
119 struct MultidimensionalMapimpl< K, T, 1, Compare > : public std::multimap< K, T, Compare > // public std::multimap< K, T, Compare >
120 {
121  typedef std::multimap< K, T, Compare > Base; // typedef std::multimap< K, T, Compare > Base;
122 
123  template < typename P >
124  std::vector< T* > find( const P& p )
125  {
126  std::vector< T* > v;
127  typename Base::iterator it = this->Base::lower_bound( p[ p.size() - 1 ] );
128  typename Base::iterator upper = this->Base::upper_bound( p[ p.size() - 1 ] );
129  for( ; it != this->Base::end() && it != upper; ++it ) { v.push_back( &it->second ); }
130  return v;
131  }
132 
133  template < typename P >
134  void erase( const P& p ) { this->Base::erase( p[ p.size() - 1 ] ); }
135 
136  template < typename P >
137  void insert( const P& p, const T& t ) { this->Base::insert( std::make_pair( p[ p.size() - 1 ], t ) ); }
138 
139  template < typename P >
140  void find( MultidimensionalMapimpl& m, const P& lower, const P& upper ) const
141  {
142  if( comma::math::less( upper[ lower.size() - 1 ], lower[ lower.size() - 1 ] ) ) { return; }
143  typename Base::const_iterator l = this->Base::lower_bound( lower[ lower.size() - 1 ] );
144  typename Base::const_iterator u = this->Base::upper_bound( upper[ upper.size() - 1 ] );
145  if( l == this->Base::end() && u == this->Base::end() ) { return; }
146  m.Base::insert( l, u );
147  }
148 
149  struct Enumerator // too lame to be called iterator
150  {
151  void operator++() { if( it != map->end() ) { ++it; } }
152  template < typename P >
153  void get( P& key, T*& value )
154  {
155  if( it == map->end() ) { value = NULL; return; }
156  key[ key.size() - 1 ] = it->first;
157  value = &it->second;
158  }
159  typename Base::iterator it;
160  MultidimensionalMapimpl* map;
161  };
162 
163  void setBegin( Enumerator& e ) { e.map = const_cast< MultidimensionalMapimpl* >( this ); e.it = e.map->Base::begin(); }
164 
165  void toString( std::ostringstream& oss, const std::string& indent ) const
166  {
167  for( typename Base::const_iterator it = this->Base::begin(); it != this->Base::end(); ++it )
168  {
169  oss << indent << it->first << ":" << it->second << std::endl;
170  }
171  }
172 };
173 
174 template < typename T > struct Less { bool operator()( const T& s, const T& t ) const { return comma::math::less( s, t ); } };
175 
176 } // namespace impl {
177 
178 template< typename P, typename T >
179 struct PointMap : public impl::MultidimensionalMapimpl< typename P::Scalar, T, P::RowsAtCompileTime, impl::Less< typename P::Scalar > >
180 {
181  typedef typename impl::MultidimensionalMapimpl< typename P::Scalar, T, P::RowsAtCompileTime, impl::Less< typename P::Scalar > > Base;
182 
183  //const T* find( const P& p ) const { return const_cast< PointMap* >( this )->Base::find( p ); }
184  //T* find( const P& p ) { return Base::find( p ); }
185  //std::vector< const T* > find( const P& p ) const { return const_cast< PointMap* >( this )->Base::find( p ); }
186  // a nasty hack violating constness: fix! well, later...
187  std::vector< T* > find( const P& p ) const { return const_cast< PointMap* >( this )->Base::find( p ); }
188  std::vector< T* > find( const P& p ) { return Base::find( p ); }
189  void insert( const P& p, const T& t ) { Base::insert( p, t ); }
190  void insert( const PointMap& m ) { for( PointMap::ConstEnumerator en = m.begin(); !en.end(); ++en ) { Base::insert( en.key(), en.value() ); } }
191  void erase( const P& p ) { return Base::erase( p ); }
192  void erase( const PointMap& m ) { for( PointMap::ConstEnumerator en = m.begin(); !en.end(); ++en ) { Base::erase( en.key() ); } }
193  PointMap find( const P& lower, const P& upper ) const { PointMap m; Base::find( m, lower, upper ); return m; }
194  std::size_t size() const { return Base::size(); }
195 
196  class ConstEnumerator // quick and dirty; too lame to be called iterator
197  {
198  public:
199  ConstEnumerator& operator++() { ++m_enum; m_enum.get( m_key, m_value ); return *this; }
200  bool end() const { return m_value == NULL; }
201  const P& key() const { return m_key; }
202  //T& value() { return *m_value; }
203  const T& value() const { return *m_value; }
204 
205  protected:
206  friend struct PointMap;
207  P m_key;
208  T* m_value;
209  typename PointMap::Base::Enumerator m_enum;
210  };
211 
212  class Enumerator : public ConstEnumerator // quick and dirty; too lame to be called iterator
213  {
214  public:
215  T& value() { return *this->m_value; }
216  };
217 
218  ConstEnumerator begin() const { ConstEnumerator e; const_cast< PointMap* >( this )->Base::setBegin( e.m_enum ); e.m_enum.get( e.m_key, e.m_value ); return e; }
219  Enumerator begin() { Enumerator e; this->Base::setBegin( e.m_enum ); e.m_enum.get( e.m_key, e.m_value ); return e; }
220 
221  std::string toString() const // quick and dirty; for testing
222  {
223  std::ostringstream oss;
224  this->Base::toString( oss );
225  return oss.str();
226  }
227 };
228 
229 } // namespace snark {
230 
231 #endif // SNARK_GRAPHICS_APPLICATIONS_LABELPOINTS_POINTMAP_H_
232