https://svn.lrde.epita.fr/svn/oln/trunk/milena
Index: ChangeLog
from Thierry Geraud <thierry.geraud(a)lrde.epita.fr>
Make some image types share data.
New stuff.
* mln/core/internal/image_base.hh (data_): New.
* mln/core/internal/image_morpher.hh (has_data): New.
* mln/core/internal/image_primary.hh: New.
* mln/core/clone.hh: New.
* mln/core/window.hh: Add check.
Split client image structure and image data.
* mln/pw/image.hh,
* mln/core/cast_image.hh,
* mln/core/sub_image.hh,
* mln/core/image1d_b.hh,
* mln/core/image2d_b.hh,
* mln/core/image3d_b.hh (data_): New.
Update.
Clean-up.
* mln/core/internal/tracked_ptr.hh: Rename as...
* mln/util/tracked_ptr.hh: ...this.
(util): Add.
* mln/core/internal/image_adaptor.hh,
* mln/core/internal/image_value_morpher.hh (has_data),
* mln/core/image1d_b_data.hh,
* mln/core/image2d_b_data.hh,
* mln/core/image3d_b_data.hh: Remove; obsolete.
core/cast_image.hh | 62 ++++++++----
core/clone.hh | 86 ++++++++++++++++
core/image1d_b.hh | 180 ++++++++++++++++++-----------------
core/image2d_b.hh | 164 +++++++++++++++++++++++--------
core/image3d_b.hh | 175 ++++++++++++++++++++--------------
core/internal/image_base.hh | 30 +++++
core/internal/image_morpher.hh | 27 +++--
core/internal/image_primary.hh | 72 ++++++++++++++
core/internal/image_value_morpher.hh | 9 -
core/sub_image.hh | 72 ++++++++------
core/window.hh | 2
pw/image.hh | 89 ++++++++---------
util/tracked_ptr.hh | 21 +++-
13 files changed, 671 insertions(+), 318 deletions(-)
Index: mln/pw/image.hh
--- mln/pw/image.hh (revision 1149)
+++ mln/pw/image.hh (working copy)
@@ -33,9 +33,8 @@
* \brief Definition of an image class FIXME
*/
-# include <mln/core/internal/image_base.hh>
+# include <mln/core/internal/image_primary.hh>
# include <mln/core/concept/function.hh>
-# include <mln/core/internal/tracked_ptr.hh>
# include <mln/value/set.hh>
@@ -52,51 +51,39 @@
*/
template <typename F, typename S>
pw::image<F,S>
-
operator | (const Function_p2v<F>& f, const Point_Set<S>& ps);
- namespace pw
+ namespace internal
{
- /*! \brief data structure for pw::image
- *
- */
+ /// Data structure for mln::pw::image
template <typename F, typename S>
- struct image_data
+ struct data_< mln::pw::image<F,S> >
{
- public:
- image_data(const Function_p2v<F>& f, const Point_Set<S>& ps);
+ data_(const F& f, const S& ps);
F f_;
S pset_;
};
- template <typename F, typename S>
- image_data<F, S>::image_data(const Function_p2v<F>& f, const
Point_Set<S>& ps)
- : f_(exact(f)),
- pset_(exact(ps))
+ } // end of namespace mln::internal
+
+
+
+ namespace pw
{
- }
/*! \brief FIXME
*
*/
template <typename F, typename S>
- class image : public internal::image_base_< S, image<F,S> >
+ struct image : public internal::image_primary_< S, image<F,S> >
{
- typedef internal::image_base_< S, image<F,S> > super_;
- public:
-
-
/// Skeleton.
typedef image< tag::function<F>, tag::pset<S> > skeleton;
- // From super class.
- typedef mln_psite(super_) psite;
-
-
/// Value associated type.
typedef mln_result(F) value;
@@ -110,31 +97,27 @@
typedef mln::value::set<mln_result(F)> vset;
- /// Constructor.
- image(const Function_p2v<F>& f, const Point_Set<S>& ps);
+ /// Constructor without argument.
image();
+ /// Constructor.
+ image(const Function_p2v<F>& f, const Point_Set<S>& ps);
- /// Test if this image has been initialized.
- bool has_data() const;
/// Test if a pixel value is accessible at \p p.
- bool owns_(const psite& p) const;
+ bool owns_(const mln_psite(S)& p) const;
/// Give the definition domain.
const S& domain() const;
/// Read-only access of pixel value at point site \p p.
- mln_result(F) operator()(const psite& p) const;
+ mln_result(F) operator()(const mln_psite(S)& p) const;
/// Read-write access is present but disabled.
- void operator()(const psite&);
+ void operator()(const mln_psite(S)&);
/// Give the set of values of the image.
const vset& values() const;
-
- protected:
- tracked_ptr< image_data<F, S> > data_;
};
} // end of namespace mln::pw
@@ -143,6 +126,8 @@
# ifndef MLN_INCLUDE_ONLY
+ // Operator.
+
template <typename F, typename S>
pw::image<F,S>
operator | (const Function_p2v<F>& f, const Point_Set<S>& ps)
@@ -151,50 +136,60 @@
return tmp;
}
- namespace pw
+ // internal::data_< pw::image<F,S> >
+
+ namespace internal
{
template <typename F, typename S>
- image<F,S>::image()
+ data_< pw::image<F,S> >::data_(const F& f, const S& ps)
+ : f_(f),
+ pset_(ps)
{
}
+ }
+
+ // pw::image<F,S>
+
+ namespace pw
+ {
+
template <typename F, typename S>
- image<F,S>::image(const Function_p2v<F>& f, const
Point_Set<S>& ps)
+ image<F,S>::image()
{
- data_ = new image_data<F, S>(f, ps);
}
template <typename F, typename S>
- bool image<F,S>::has_data() const
+ image<F,S>::image(const Function_p2v<F>& f, const
Point_Set<S>& ps)
{
- return true;
+ this->data_ = new internal::data_< pw::image<F,S> >(exact(f),
exact(ps));
}
template <typename F, typename S>
- bool image<F,S>::owns_(const psite& p) const
+ bool image<F,S>::owns_(const mln_psite(S)& p) const
{
- return data_->pset_.has(p);
+ return this->data_->pset_.has(p);
}
template <typename F, typename S>
const S&
image<F,S>::domain() const
{
- return data_->pset_;
+ return this->data_->pset_;
}
template <typename F, typename S>
mln_result(F)
- image<F,S>::operator()(const psite& p) const
+ image<F,S>::operator()(const mln_psite(S)& p) const
{
- mln_precondition(data_->pset_.has(p));
- return data_->f_(p);
+ mln_precondition(this->data_->pset_.has(p));
+ return this->data_->f_(p);
}
template <typename F, typename S>
void
- image<F,S>::operator()(const psite&)
+ image<F,S>::operator()(const mln_psite(S)&)
{
mln_invariant(0); // FIXME: Turn into a compile-time error...
}
Index: mln/core/window.hh
--- mln/core/window.hh (revision 1149)
+++ mln/core/window.hh (working copy)
@@ -41,6 +41,7 @@
# include <mln/convert/to_dpoint.hh>
# include <mln/geom/sym.hh>
+# include <mln/metal/is_a.hh>
namespace mln
@@ -116,6 +117,7 @@
template <typename D>
window<D>::window()
{
+ mln::metal::is_a<D, Dpoint>::check();
}
template <typename D>
Index: mln/core/internal/image_primary.hh
--- mln/core/internal/image_primary.hh (revision 0)
+++ mln/core/internal/image_primary.hh (revision 0)
@@ -0,0 +1,72 @@
+// Copyright (C) 2007 EPITA Research and Development Laboratory
+//
+// This file is part of the Olena Library. This library is free
+// software; you can redistribute it and/or modify it under the terms
+// of the GNU General Public License version 2 as published by the
+// Free Software Foundation.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this library; see the file COPYING. If not, write to
+// the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+// Boston, MA 02111-1307, USA.
+//
+// As a special exception, you may use this file as part of a free
+// software library without restriction. Specifically, if other files
+// instantiate templates or use macros or inline functions from this
+// file, or you compile this file and link it with other files to
+// produce an executable, this file does not by itself cause the
+// resulting executable to be covered by the GNU General Public
+// License. This exception does not however invalidate any other
+// reasons why the executable file might be covered by the GNU General
+// Public License.
+
+#ifndef MLN_CORE_INTERNAL_IMAGE_PRIMARY_HH
+# define MLN_CORE_INTERNAL_IMAGE_PRIMARY_HH
+
+/*! \file mln/core/internal/image_primary.hh
+ *
+ * \brief Definition of a base class for primary images.
+ */
+
+# include <mln/core/internal/image_base.hh>
+
+
+namespace mln
+{
+
+ namespace internal
+ {
+
+
+ /*! \brief A base class for primary images.
+ *
+ * \internal
+ */
+ template <typename S, typename E>
+ struct image_primary_ : public image_base_<S, E>
+ {
+ protected:
+ image_primary_();
+ };
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+ template <typename S, typename E>
+ image_primary_<S,E>::image_primary_()
+ {
+ }
+
+# endif // ! MLN_INCLUDE_ONLY
+
+ } // end of namespace mln::internal
+
+} // end of namespace mln
+
+
+#endif // ! MLN_CORE_INTERNAL_IMAGE_PRIMARY_HH
Index: mln/core/internal/image_value_morpher.hh
--- mln/core/internal/image_value_morpher.hh (revision 1149)
+++ mln/core/internal/image_value_morpher.hh (working copy)
@@ -57,8 +57,6 @@
const mln_pset(I)& domain() const;
bool owns_(const mln_psite(I)& p) const;
- bool has_data() const; // Default impl.
-
protected:
image_value_morpher_();
};
@@ -87,13 +85,6 @@
return this->delegatee_()->owns_(p);
}
- template <typename I, typename E>
- bool
- image_value_morpher_<I,E>::has_data() const
- {
- return this->delegatee_() != 0 && this->delegatee_()->has_data();
- }
-
# endif // ! MLN_INCLUDE_ONLY
} // end of namespace mln::internal
Index: mln/core/internal/image_base.hh
--- mln/core/internal/image_base.hh (revision 1149)
+++ mln/core/internal/image_base.hh (working copy)
@@ -35,11 +35,27 @@
# include <mln/core/concept/image.hh>
# include <mln/core/grids.hh>
+# include <mln/util/tracked_ptr.hh>
namespace mln
{
+
+
+ namespace internal
+ {
+
+ /// Class of image internal data.
+ template <typename I>
+ struct data_;
+
+ // FIXME: Say more about it!
+
+ } // end of namespace mln::internal
+
+
+
namespace internal
{
@@ -132,8 +148,15 @@
/// Give the number of points of the image domain.
std::size_t npoints() const;
+ /// Test if this image has been initialized; default impl.
+ bool has_data() const;
+
+ // FIXME: Add void init_data(..);
+
protected:
image_base_();
+
+ util::tracked_ptr< internal::data_<E> > data_;
};
@@ -146,6 +169,13 @@
template <typename S, typename E>
bool
+ image_base_<S,E>::has_data() const
+ {
+ return data_ != 0;
+ }
+
+ template <typename S, typename E>
+ bool
image_base_<S,E>::has(const psite& p) const
{
mln_precondition(exact(this)->has_data());
Index: mln/core/internal/image_morpher.hh
--- mln/core/internal/image_morpher.hh (revision 1149)
+++ mln/core/internal/image_morpher.hh (working copy)
@@ -56,18 +56,22 @@
typedef I delegatee;
- /// Return the delegatee_ pointer.
+ /// Return the delegatee_ pointer; default code.
mlc_const(I)* delegatee_() const;
- /// Return the delegatee_ pointer (non-const version).
+ /// Return the delegatee_ pointer (non-const version); default code.
I* delegatee_();
- /// Convertion to the underlying (morphed) image.
- operator I() const; // FIXME: Dangerous?
-
- /// Default for has_data is "delegatee has data".
+ /* \brief Test if this image has been initialized; default impl.
+ *
+ * This default impl is stronger than the one inherited from
+ * image_base_.
+ */
bool has_data() const;
+ /// Convertion to the underlying (morphed) image.
+ operator I() const; // FIXME: Very dangerous? Remove?
+
protected:
image_morpher_();
};
@@ -84,21 +88,20 @@
mlc_const(I)*
image_morpher_<I,S,E>::delegatee_() const
{
- return exact(this)->impl_delegatee_();
+ return this->data_ = 0 ? 0 : & this->data_->ima_;
}
template <typename I, typename S, typename E>
I*
image_morpher_<I,S,E>::delegatee_()
{
- return exact(this)->impl_delegatee_();
+ return this->data_ = 0 ? 0 : & this->data_->ima_;
}
template <typename I, typename S, typename E>
image_morpher_<I,S,E>::operator I() const
{
mln_precondition(exact(this)->has_data());
- mln_precondition(this->delegatee_() != 0); // FIXME: Redundant?
return * this->delegatee_();
}
@@ -106,8 +109,10 @@
bool
image_morpher_<I,S,E>::has_data() const
{
- mln_precondition(this->delegatee_() != 0); // FIXME: Redundant?
- return this->delegatee_()->has_data();
+ return
+ this->data != 0 &&
+ this->delegatee_() != 0 &&
+ this->delegatee_()->has_data();
}
# endif // ! MLN_INCLUDE_ONLY
Index: mln/core/image2d_b.hh
--- mln/core/image2d_b.hh (revision 1149)
+++ mln/core/image2d_b.hh (working copy)
@@ -33,18 +33,14 @@
* \brief Definition of the basic mln::image2d_b class.
*/
-# include <mln/core/internal/image_base.hh>
+# include <mln/core/internal/image_primary.hh>
# include <mln/core/box2d.hh>
# include <mln/border/thickness.hh>
# include <mln/value/set.hh>
# include <mln/fun/i2v/all.hh>
-
# include <mln/core/line_piter.hh>
-# include <mln/core/internal/tracked_ptr.hh>
-# include <mln/core/image2d_b_data.hh>
-
// FIXME:
// # include <mln/core/pixter2d_b.hh>
@@ -58,6 +54,32 @@
template <typename T> struct image2d_b;
+
+ namespace internal
+ {
+
+ template <typename T>
+ struct data_< image2d_b<T> >
+ {
+ data_(const box2d& b, unsigned bdr);
+ ~data_();
+
+ T* buffer_;
+ T** array_;
+
+ box2d b_; // theoretical box
+ unsigned bdr_;
+ box2d vb_; // virtual box, i.e., box including the virtual border
+
+ void update_vb_();
+ void allocate_();
+ void deallocate_();
+ };
+
+ } // end of namespace mln::internal
+
+
+
namespace trait
{
@@ -78,7 +100,7 @@
* thickness around data.
*/
template <typename T>
- struct image2d_b : public internal::image_base_< box2d, image2d_b<T> >
+ struct image2d_b : public internal::image_primary_< box2d, image2d_b<T> >
{
// Warning: just to make effective types appear in Doxygen:
typedef box2d pset;
@@ -142,20 +164,18 @@
/// Initialize an empty image.
template <typename I>
- void init_with(const Image<I>& other)
+ void init_with(const Image<I>& other) // FIXME: Remove this soon obsolete
code!
{
- mln_precondition(data_ = 0);
+ mln_precondition(this->data_ = 0);
mln_precondition(exact(other).has_data());
- data_ = new image2d_b_data<T>(exact(other).bbox()); // FIXME: border?
+ this->data_ = new internal::data_< image2d_b<T>
>(exact(other).bbox(),
+ exact(other).border());
}
/// Test if \p p is valid.
bool owns_(const point2d& p) const;
- /// Test if this image has been initialized.
- bool has_data() const;
-
/// Give the set of values of the image.
const vset& values() const;
@@ -204,8 +224,6 @@
private:
- tracked_ptr< image2d_b_data<T> > data_;
-
typedef internal::image_base_< box2d, image2d_b<T> > super;
};
@@ -213,17 +231,86 @@
# ifndef MLN_INCLUDE_ONLY
- // ctors
+
+ // internal::data_< image2d_b<T> >
+
+ namespace internal
+ {
+
+ template <typename T>
+ data_< image2d_b<T> >::data_(const box2d& b, unsigned bdr)
+ : buffer_(0),
+ array_ (0),
+ b_ (b),
+ bdr_ (bdr)
+ {
+ allocate_();
+ }
+
+ template <typename T>
+ data_< image2d_b<T> >::~data_()
+ {
+ deallocate_();
+ }
+
+ template <typename T>
+ void
+ data_< image2d_b<T> >::update_vb_()
+ {
+ vb_.pmin() = b_.pmin() - dpoint2d(all(bdr_));
+ vb_.pmax() = b_.pmax() + dpoint2d(all(bdr_));
+ }
+
+ template <typename T>
+ void
+ data_< image2d_b<T> >::allocate_()
+ {
+ update_vb_();
+ unsigned
+ nr = vb_.len(0),
+ nc = vb_.len(1);
+ buffer_ = new T[nr * nc];
+ array_ = new T*[nr];
+ T* buf = buffer_ - vb_.pmin().col();
+ for (unsigned i = 0; i < nr; ++i)
+ {
+ array_[i] = buf;
+ buf += nc;
+ }
+ array_ -= vb_.pmin().row();
+ mln_postcondition(vb_.len(0) = b_.len(0) + 2 * bdr_);
+ mln_postcondition(vb_.len(1) = b_.len(1) + 2 * bdr_);
+ }
+
+ template <typename T>
+ void
+ data_< image2d_b<T> >::deallocate_()
+ {
+ if (buffer_)
+ {
+ delete[] buffer_;
+ buffer_ = 0;
+ }
+ if (array_)
+ {
+ array_ += vb_.pmin().row();
+ delete[] array_;
+ array_ = 0;
+ }
+ }
+
+ } // end of namespace mln::internal
+
+
+ // image2d_b<T>
template <typename T>
image2d_b<T>::image2d_b()
- : data_(0)
{
}
template <typename T>
image2d_b<T>::image2d_b(int nrows, int ncols, unsigned bdr)
- : data_(0)
{
init_with(nrows, ncols, bdr);
}
@@ -233,7 +320,7 @@
image2d_b<T>::init_with(int nrows, int ncols, unsigned bdr)
{
mln_precondition(! this->has_data());
- data_ = new image2d_b_data<T>(make::box2d(nrows, ncols), bdr);
+ this->data_ = new internal::data_< image2d_b<T> >(make::box2d(nrows,
ncols), bdr);
}
template <typename T>
@@ -247,13 +334,11 @@
image2d_b<T>::init_with(const box2d& b, unsigned bdr)
{
mln_precondition(! this->has_data());
- data_ = new image2d_b_data<T>(b, bdr);
+ this->data_ = new internal::data_< image2d_b<T> >(b, bdr);
}
template <typename T>
image2d_b<T>::image2d_b(const image2d_b<T>& rhs)
- : super(rhs),
- data_(rhs.data_)
{
}
@@ -274,13 +359,6 @@
// methods
template <typename T>
- bool
- image2d_b<T>::has_data() const
- {
- return data_ != 0;
- }
-
- template <typename T>
const typename image2d_b<T>::vset&
image2d_b<T>::values() const
{
@@ -292,7 +370,7 @@
image2d_b<T>::domain() const
{
mln_precondition(this->has_data());
- return data_->b_;
+ return this->data_->b_;
}
template <typename T>
@@ -300,7 +378,7 @@
image2d_b<T>::border() const
{
mln_precondition(this->has_data());
- return data_->bdr_;
+ return this->data_->bdr_;
}
template <typename T>
@@ -308,7 +386,7 @@
image2d_b<T>::ncells() const
{
mln_precondition(this->has_data());
- return data_->vb_.npoints();
+ return this->data_->vb_.npoints();
}
template <typename T>
@@ -316,7 +394,7 @@
image2d_b<T>::owns_(const point2d& p) const
{
mln_precondition(this->has_data());
- return data_->vb_.has(p);
+ return this->data_->vb_.has(p);
}
template <typename T>
@@ -324,7 +402,7 @@
image2d_b<T>::operator()(const point2d& p) const
{
mln_precondition(this->owns_(p));
- return data_->array_[p.row()][p.col()];
+ return this->data_->array_[p.row()][p.col()];
}
template <typename T>
@@ -332,7 +410,7 @@
image2d_b<T>::operator()(const point2d& p)
{
mln_precondition(this->owns_(p));
- return data_->array_[p.row()][p.col()];
+ return this->data_->array_[p.row()][p.col()];
}
template <typename T>
@@ -340,7 +418,7 @@
image2d_b<T>::operator[](unsigned o) const
{
mln_precondition(o < ncells());
- return *(data_->buffer_ + o);
+ return *(this->data_->buffer_ + o);
}
template <typename T>
@@ -348,7 +426,7 @@
image2d_b<T>::operator[](unsigned o)
{
mln_precondition(o < ncells());
- return *(data_->buffer_ + o);
+ return *(this->data_->buffer_ + o);
}
template <typename T>
@@ -356,7 +434,7 @@
image2d_b<T>::at(int row, int col) const
{
mln_precondition(this->owns_(make::point2d(row, col)));
- return data_->array_[row][col];
+ return this->data_->array_[row][col];
}
template <typename T>
@@ -364,7 +442,7 @@
image2d_b<T>::at(int row, int col)
{
mln_precondition(this->owns_(make::point2d(row, col)));
- return data_->array_[row][col];
+ return this->data_->array_[row][col];
}
template <typename T>
@@ -377,7 +455,7 @@
image2d_b<T>::buffer() const
{
mln_precondition(this->has_data());
- return data_->buffer_;
+ return this->data_->buffer_;
}
template <typename T>
@@ -385,7 +463,7 @@
image2d_b<T>::buffer()
{
mln_precondition(this->has_data());
- return data_->buffer_;
+ return this->data_->buffer_;
}
template <typename T>
@@ -393,7 +471,7 @@
image2d_b<T>::offset(const dpoint2d& dp) const
{
mln_precondition(this->has_data());
- int o = dp[0] * data_->vb_.len(1) + dp[1];
+ int o = dp[0] * this->data_->vb_.len(1) + dp[1];
return o;
}
@@ -402,8 +480,8 @@
image2d_b<T>::point_at_offset(unsigned o) const
{
mln_precondition(o < ncells());
- point2d p = make::point2d(o / data_->vb_.len(1) + data_->vb_.min_row(),
- o % data_->vb_.len(1) + data_->vb_.min_col());
+ point2d p = make::point2d(o / this->data_->vb_.len(1) +
this->data_->vb_.min_row(),
+ o % this->data_->vb_.len(1) + this->data_->vb_.min_col());
mln_postcondition(& this->operator()(p) = this->data_->buffer_ + o);
return p;
}
Index: mln/core/cast_image.hh
--- mln/core/cast_image.hh (revision 1149)
+++ mln/core/cast_image.hh (working copy)
@@ -31,6 +31,8 @@
/*! \file mln/core/cast_image.hh
*
* \brief Definition of an image class FIXME
+ *
+ * \todo Rename as cast_image (without '_')!
*/
# include <mln/core/internal/image_value_morpher.hh>
@@ -41,14 +43,30 @@
namespace mln
{
+ // Fwd decl.
+ template <typename T, typename I> class cast_image_;
+
+
+ namespace internal
+ {
+
+ template <typename T, typename I>
+ struct data_< cast_image_<T,I> >
+ {
+ data_(const I& ima);
+ const I& ima_;
+ };
+
+ } // end of namespace mln::internal
+
+
+
/*! \brief FIXME
*
*/
template <typename T, typename I>
- class cast_image_ : public internal::image_value_morpher_< I, cast_image_<T,I>
>
+ struct cast_image_ : public internal::image_value_morpher_< I,
cast_image_<T,I> >
{
- public:
-
/// Value associated type.
typedef T value;
@@ -78,12 +96,6 @@
/// Give the set of values of the image.
const vset& values() const;
-
- /// Access to delegatee pointer.
- const I* impl_delegatee_() const;
-
- protected:
- const I& ima_;
};
@@ -101,26 +113,43 @@
# ifndef MLN_INCLUDE_ONLY
+
+ // internal::data_< cast_image_<T,I> >
+
+ namespace internal
+ {
+
+ template <typename T, typename I>
+ data_< cast_image_<T,I> >::data_(const I& ima)
+ : ima_(ima)
+ {
+ }
+
+ } // end of namespace mln::internal
+
+
+ // cast_image_<T,I>
+
template <typename T, typename I>
cast_image_<T,I>::cast_image_(const Image<I>& ima)
- : ima_(exact(ima))
{
mln_precondition(exact(ima).has_data());
+ this->data_ = new internal::data_< cast_image_<T,I> >(exact(ima));
}
template <typename T, typename I>
T
cast_image_<T,I>::operator()(const mln_psite(I)& p) const
{
- mln_precondition(ima_.owns_(p));
- return mln::value::cast<T>( ima_(p) );
+ mln_precondition(this->data_->ima_.owns_(p));
+ return mln::value::cast<T>( this->data_->ima_(p) );
}
template <typename T, typename I>
T
cast_image_<T,I>::operator()(const mln_psite(I)& p)
{
- return mln::value::cast<T>( ima_(p) );
+ return mln::value::cast<T>( this->data_->ima_(p) );
}
template <typename T, typename I>
@@ -130,13 +159,6 @@
return vset::the();
}
- template <typename T, typename I>
- const I*
- cast_image_<T,I>::impl_delegatee_() const
- {
- return & ima_;
- }
-
# endif // ! MLN_INCLUDE_ONLY
} // end of namespace mln
Index: mln/core/sub_image.hh
--- mln/core/sub_image.hh (revision 1149)
+++ mln/core/sub_image.hh (working copy)
@@ -34,29 +34,43 @@
namespace mln
{
- // FIXME: Doc!
+
+ // Fwd decl.
+ template <typename I, typename S> class sub_image;
+
+
+ namespace internal
+ {
template <typename I, typename S>
- class sub_image : public internal::image_domain_morpher_< I, S, sub_image<I,S>
>
+ struct data_< sub_image<I,S> >
{
- public:
+ data_(I& ima, const S& pset);
+
+ I& ima_;
+ const S& pset_;
+ };
+
+ } // end of namespace mln::internal
+
+
+ // FIXME: Doc!
+
+ template <typename I, typename S>
+ struct sub_image : public internal::image_domain_morpher_< I, S,
sub_image<I,S> >
+ {
/// Skeleton.
typedef sub_image< tag::image<I>, tag::pset<S> > skeleton;
+ /// Constructor.
sub_image(I& ima, const S& pset);
+ /// Give the definition domain.
const S& domain() const;
/// Const promotion via convertion.
operator sub_image<const I, S>() const;
-
- mlc_const(I)* impl_delegatee_() const;
- I* impl_delegatee_();
-
- protected:
- I& ima_;
- const S& pset_;
};
@@ -71,42 +85,46 @@
# ifndef MLN_INCLUDE_ONLY
+ // internal::data_< sub_image<I,S> >
+
+ namespace internal
+ {
+
template <typename I, typename S>
- sub_image<I,S>::sub_image(I& ima, const S& pset)
+ data_< sub_image<I,S> >::data_(I& ima, const S& pset)
: ima_(ima),
pset_(pset)
{
}
- template <typename I, typename S>
- const S&
- sub_image<I,S>::domain() const
- {
- return pset_;
- }
+ } // end of namespace mln::internal
+
+
+ // sub_image<I,S>
template <typename I, typename S>
- sub_image<I,S>::operator sub_image<const I, S>() const
+ sub_image<I,S>::sub_image(I& ima, const S& pset)
{
- sub_image<const I, S> tmp(this->adaptee_, this->pset_);
- return tmp;
+ this->data_ = new internal::data_< sub_image<I,S> >(ima, pset);
}
template <typename I, typename S>
- mlc_const(I)*
- sub_image<I,S>::impl_delegatee_() const
+ const S&
+ sub_image<I,S>::domain() const
{
- return & ima_;
+ return this->data_->pset_;
}
template <typename I, typename S>
- I*
- sub_image<I,S>::impl_delegatee_()
+ sub_image<I,S>::operator sub_image<const I, S>() const
{
- return & ima_;
+ sub_image<const I, S> tmp(this->data_->ima_,
+ this->data_->pset_);
+ return tmp;
}
- // operator
+
+ // Operators.
template <typename I, typename S>
sub_image<const I, S>
Index: mln/core/clone.hh
--- mln/core/clone.hh (revision 0)
+++ mln/core/clone.hh (revision 0)
@@ -0,0 +1,86 @@
+// Copyright (C) 2007 EPITA Research and Development Laboratory
+//
+// This file is part of the Olena Library. This library is free
+// software; you can redistribute it and/or modify it under the terms
+// of the GNU General Public License version 2 as published by the
+// Free Software Foundation.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this library; see the file COPYING. If not, write to
+// the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+// Boston, MA 02111-1307, USA.
+//
+// As a special exception, you may use this file as part of a free
+// software library without restriction. Specifically, if other files
+// instantiate templates or use macros or inline functions from this
+// file, or you compile this file and link it with other files to
+// produce an executable, this file does not by itself cause the
+// resulting executable to be covered by the GNU General Public
+// License. This exception does not however invalidate any other
+// reasons why the executable file might be covered by the GNU General
+// Public License.
+
+#ifndef MLN_CORE_CLONE_HH
+# define MLN_CORE_CLONE_HH
+
+/*! \file mln/core/clone.hh
+ *
+ * \brief Clone an image, that is, get an effective copy.
+ */
+
+# include <mln/core/concept/image.hh>
+
+
+namespace mln
+{
+
+ /*! Clone the image \p ima with the values of the image \p data.
+ *
+ * \param[in,out] ima The image to be cloneed.
+ * \param[in] data The image.
+ *
+ * \warning The definition domain of \p ima has to be included in
+ * the one of \p data.
+ *
+ * \pre \p ima.domain <= \p data.domain.
+ *
+ * \todo Use memcpy when possible.
+ */
+ template <typename I>
+ mln_concrete(I) clone(const Image<I>& ima);
+
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+ namespace impl
+ {
+
+ template <typename I>
+ void clone_(mln_concrete(I)& result, const Image<I>& ima)
+ {
+ std::cerr << "oops" << std::endl; // FIXME: Fake code.
+ }
+
+ } // end of namespace mln::impl
+
+
+ template <typename I>
+ mln_concrete(I) clone(const Image<I>& ima)
+ {
+ mln_concrete(I) tmp;
+ impl::clone_(ima, tmp);
+ return tmp;
+ }
+
+# endif // ! MLN_INCLUDE_ONLY
+
+} // end of namespace mln
+
+
+#endif // ! MLN_CORE_CLONE_HH
Index: mln/core/image1d_b.hh
--- mln/core/image1d_b.hh (revision 1149)
+++ mln/core/image1d_b.hh (working copy)
@@ -33,7 +33,7 @@
* \brief Definition of the basic mln::image1d_b class.
*/
-# include <mln/core/internal/image_base.hh>
+# include <mln/core/internal/image_primary.hh>
# include <mln/core/box1d.hh>
# include <mln/border/thickness.hh>
@@ -42,9 +42,6 @@
# include <mln/core/line_piter.hh>
-# include <mln/core/internal/tracked_ptr.hh>
-# include <mln/core/image1d_b_data.hh>
-
// FIXME:
// # include <mln/core/pixter1d_b.hh>
@@ -71,14 +68,40 @@
+ namespace internal
+ {
+
+ /// Data structure for mln::image1d_b<T>.
+ template <typename T>
+ struct data_< image1d_b<T> >
+ {
+ data_(const box1d& b, unsigned bdr);
+ ~data_();
+
+ T* buffer_;
+ T* array_;
+
+ box1d b_; // theoretical box
+ unsigned bdr_;
+ box1d vb_; // virtual box, i.e., box including the virtual border
+
+ void update_vb_();
+ void allocate_();
+ void deallocate_();
+ };
+
+ } // end of namespace mln::internal
+
+
+
/*! \brief Basic 1D image class.
*
* The parameter \c T is the type of pixel values. This image class
* stores data in memory and has a virtual border with constant
- * thickness around data.
+ * thickness before and after data.
*/
template <typename T>
- struct image1d_b : public internal::image_base_< box1d, image1d_b<T> >
+ struct image1d_b : public internal::image_primary_< box1d, image1d_b<T> >
{
// Warning: just to make effective types appear in Doxygen:
typedef box1d pset;
@@ -112,26 +135,13 @@
/// Constructor without argument.
image1d_b();
- /// Constructor with the numbers of indexes and the
- /// border thickness.
- image1d_b(int ninds, unsigned bdr = border::thickness);
+ /// Constructor with the number of indices and the border
+ /// thickness.
+ image1d_b(unsigned ninds, unsigned bdr = border::thickness);
- /// Constructor with a box and the border thickness (default is
- /// 3).
+ /// Constructor with a box and the border thickness.
image1d_b(const box1d& b, unsigned bdr = border::thickness);
- /// Copy constructor.
- image1d_b(const image1d_b<T>& rhs);
-
- /// Assignment operator.
- image1d_b& operator=(const image1d_b<T>& rhs);
-
- /// Destructor.
- ~image1d_b();
-
-
- /// Initialize an empty image.
- void init_with(int ninds, unsigned bdr = border::thickness);
/// Initialize an empty image.
void init_with(const box1d& b, unsigned bdr = border::thickness);
@@ -140,9 +150,6 @@
/// Test if \p p is valid.
bool owns_(const point1d& p) const;
- /// Test if this image has been initialized.
- bool has_data() const;
-
/// Give the set of values of the image.
const vset& values() const;
@@ -187,85 +194,93 @@
/// Give a hook to the value buffer.
T* buffer();
-
-
- private:
-
- tracked_ptr< image1d_b_data<T> > data_;
-
- typedef internal::image_base_< box1d, image1d_b<T> > super;
};
# ifndef MLN_INCLUDE_ONLY
- // ctors
+ // internal::data_< image1d_b<T> >
+
+ namespace internal
+ {
template <typename T>
- image1d_b<T>::image1d_b()
- : data_(0)
+ data_< image1d_b<T> >::data_(const box1d& b, unsigned bdr)
+ : buffer_(0),
+ array_ (0),
+ b_ (b),
+ bdr_ (bdr)
{
+ allocate_();
}
template <typename T>
- image1d_b<T>::image1d_b(int ninds, unsigned bdr)
- : data_(0)
+ data_< image1d_b<T> >::~data_()
{
- init_with(ninds, bdr);
+ deallocate_();
}
template <typename T>
void
- image1d_b<T>::init_with(int ninds, unsigned bdr)
+ data_< image1d_b<T> >::update_vb_()
{
- mln_precondition(! this->has_data());
- data_ = new image1d_b_data<T>(make::box1d(ninds), bdr);
+ vb_.pmin() = b_.pmin() - dpoint1d(all(bdr_));
+ vb_.pmax() = b_.pmax() + dpoint1d(all(bdr_));
}
template <typename T>
- image1d_b<T>::image1d_b(const box1d& b, unsigned bdr)
- : data_(0)
+ void
+ data_< image1d_b<T> >::allocate_()
{
- init_with(b, bdr);
+ update_vb_();
+ unsigned
+ ni = vb_.len(0);
+ buffer_ = new T[ni];
+ array_ = buffer_ - vb_.pmin().ind();
+ mln_postcondition(vb_.len(0) = b_.len(0) + 2 * bdr_);
}
template <typename T>
void
- image1d_b<T>::init_with(const box1d& b, unsigned bdr)
+ data_< image1d_b<T> >::deallocate_()
{
- mln_precondition(! this->has_data());
- data_ = new image1d_b_data<T>(b, bdr);
+ if (buffer_)
+ {
+ delete[] buffer_;
+ buffer_ = 0;
+ }
}
+ } // end of namespace mln::internal
+
+
+ // image1d_b<T>
+
template <typename T>
- image1d_b<T>::image1d_b(const image1d_b<T>& rhs)
- : super(rhs),
- data_(rhs.data_)
+ image1d_b<T>::image1d_b()
{
}
- // assignment
-
template <typename T>
- image1d_b<T>&
- image1d_b<T>::operator=(const image1d_b<T>& rhs)
+ image1d_b<T>::image1d_b(const box1d& b, unsigned bdr)
{
- mln_precondition(rhs.has_data());
- if (& rhs = this)
- return *this;
-
- this->data_ = rhs.data_;
- return *this;
+ init_with(b, bdr);
}
- // methods
+ template <typename T>
+ image1d_b<T>::image1d_b(unsigned ninds, unsigned bdr)
+ {
+ mln_precondition(ninds != 0);
+ init_with(make::box1d(ninds), bdr);
+ }
template <typename T>
- bool
- image1d_b<T>::has_data() const
+ void
+ image1d_b<T>::init_with(const box1d& b, unsigned bdr)
{
- return data_ != 0;
+ mln_precondition(! this->has_data());
+ this->data_ = new internal::data_< image1d_b<T> >(b, bdr);
}
template <typename T>
@@ -280,7 +295,7 @@
image1d_b<T>::domain() const
{
mln_precondition(this->has_data());
- return data_->b_;
+ return this->data_->b_;
}
template <typename T>
@@ -288,7 +303,7 @@
image1d_b<T>::border() const
{
mln_precondition(this->has_data());
- return data_->bdr_;
+ return this->data_->bdr_;
}
template <typename T>
@@ -296,19 +311,15 @@
image1d_b<T>::ncells() const
{
mln_precondition(this->has_data());
- return data_->vb_.npoints();
+ return this->data_->vb_.npoints();
}
template <typename T>
bool
image1d_b<T>::owns_(const point1d& p) const
{
- if (! data_->vb_.has(p))
- {
- std::cout << " p = " << p << std::endl;
- }
mln_precondition(this->has_data());
- return data_->vb_.has(p);
+ return this->data_->vb_.has(p);
}
template <typename T>
@@ -316,7 +327,7 @@
image1d_b<T>::operator()(const point1d& p) const
{
mln_precondition(this->owns_(p));
- return data_->array_[p.ind()];
+ return this->data_->array_[p.ind()];
}
template <typename T>
@@ -324,7 +335,7 @@
image1d_b<T>::operator()(const point1d& p)
{
mln_precondition(this->owns_(p));
- return data_->array_[p.ind()];
+ return this->data_->array_[p.ind()];
}
template <typename T>
@@ -332,7 +343,7 @@
image1d_b<T>::operator[](unsigned o) const
{
mln_precondition(o < ncells());
- return *(data_->buffer_ + o);
+ return *(this->data_->buffer_ + o);
}
template <typename T>
@@ -340,7 +351,7 @@
image1d_b<T>::operator[](unsigned o)
{
mln_precondition(o < ncells());
- return *(data_->buffer_ + o);
+ return *(this->data_->buffer_ + o);
}
template <typename T>
@@ -348,7 +359,7 @@
image1d_b<T>::at(int ind) const
{
mln_precondition(this->owns_(make::point1d(ind)));
- return data_->array_[ind];
+ return this->data_->array_[ind];
}
template <typename T>
@@ -356,12 +367,7 @@
image1d_b<T>::at(int ind)
{
mln_precondition(this->owns_(make::point1d(ind)));
- return data_->array_[ind];
- }
-
- template <typename T>
- image1d_b<T>::~image1d_b()
- {
+ return this->data_->array_[ind];
}
template <typename T>
@@ -369,7 +375,7 @@
image1d_b<T>::buffer() const
{
mln_precondition(this->has_data());
- return data_->buffer_;
+ return this->data_->buffer_;
}
template <typename T>
@@ -377,7 +383,7 @@
image1d_b<T>::buffer()
{
mln_precondition(this->has_data());
- return data_->buffer_;
+ return this->data_->buffer_;
}
template <typename T>
@@ -394,7 +400,7 @@
image1d_b<T>::point_at_offset(unsigned o) const
{
mln_precondition(o < ncells());
- point1d p = make::point1d(o + data_->vb_.min_ind());
+ point1d p = make::point1d(o + this->data_->vb_.min_ind());
mln_postcondition(& this->operator()(p) = this->data_->buffer_ + o);
return p;
}
Index: mln/core/image3d_b.hh
--- mln/core/image3d_b.hh (revision 1149)
+++ mln/core/image3d_b.hh (working copy)
@@ -33,7 +33,7 @@
* \brief Definition of the basic mln::image3d_b class.
*/
-# include <mln/core/internal/image_base.hh>
+# include <mln/core/internal/image_primary.hh>
# include <mln/core/box3d.hh>
# include <mln/border/thickness.hh>
@@ -42,9 +42,6 @@
# include <mln/core/line_piter.hh>
-# include <mln/core/internal/tracked_ptr.hh>
-# include <mln/core/image3d_b_data.hh>
-
// FIXME:
// # include <mln/core/pixter3d_b.hh>
@@ -70,6 +67,31 @@
} // end of mln::trait
+ namespace internal
+ {
+
+ template <typename T>
+ struct data_< image3d_b<T> >
+ {
+ data_(const box3d& b, unsigned bdr);
+ ~data_();
+
+ T* buffer_;
+ T*** array_;
+
+ box3d b_; // theoretical box
+ unsigned bdr_;
+ box3d vb_; // virtual box, i.e., box including the virtual border
+
+ void update_vb_();
+ void allocate_();
+ void deallocate_();
+
+ };
+
+ } // end of namespace mln::internal
+
+
/*! \brief Basic 3D image class.
*
@@ -78,7 +100,7 @@
* thickness around data.
*/
template <typename T>
- struct image3d_b : public internal::image_base_< box3d, image3d_b<T> >
+ struct image3d_b : public internal::image_primary_< box3d, image3d_b<T> >
{
// Warning: just to make effective types appear in Doxygen:
typedef box3d pset;
@@ -112,37 +134,22 @@
/// Constructor without argument.
image3d_b();
- /// Constructor with the numbers of indexes and the
- /// border thickness.
- image3d_b(int nslis, int nrows, int ncols, unsigned bdr = border::thickness);
-
/// Constructor with a box and the border thickness (default is
/// 3).
image3d_b(const box3d& b, unsigned bdr = border::thickness);
- /// Copy constructor.
- image3d_b(const image3d_b<T>& rhs);
-
- /// Assignment operator.
- image3d_b& operator=(const image3d_b<T>& rhs);
-
- /// Destructor.
- ~image3d_b();
+ /// Constructor with the numbers of indexes and the
+ /// border thickness.
+ image3d_b(int nslis, int nrows, int ncols, unsigned bdr = border::thickness);
/// Initialize an empty image.
- void init_with(int nslis, int nrows, int ncols, unsigned bdr = border::thickness);
-
- /// Initialize an empty image.
void init_with(const box3d& b, unsigned bdr = border::thickness);
/// Test if \p p is valid.
bool owns_(const point3d& p) const;
- /// Test if this image has been initialized.
- bool has_data() const;
-
/// Give the set of values of the image.
const vset& values() const;
@@ -187,86 +194,121 @@
/// Give a hook to the value buffer.
T* buffer();
-
-
- private:
-
- tracked_ptr< image3d_b_data<T> > data_;
-
- typedef internal::image_base_< box3d, image3d_b<T> > super;
};
# ifndef MLN_INCLUDE_ONLY
- // ctors
+ // internal::data_< image3d_b<T> >
+
+ namespace internal
+ {
template <typename T>
- image3d_b<T>::image3d_b()
- : data_(0)
+ data_< image3d_b<T> >::data_(const box3d& b, unsigned bdr)
+ : buffer_(0),
+ array_ (0),
+ b_ (b),
+ bdr_ (bdr)
{
- data_->bdr_ = border::thickness; // default value in ctors.
+ allocate_();
}
template <typename T>
- image3d_b<T>::image3d_b(int nslis, int nrows, int ncols, unsigned bdr)
- : data_(0)
+ data_< image3d_b<T> >::~data_()
{
- init_with(nslis, nrows, ncols, bdr);
+ deallocate_();
}
template <typename T>
void
- image3d_b<T>::init_with(int nslis, int nrows, int ncols, unsigned bdr)
+ data_< image3d_b<T> >::update_vb_()
{
- mln_precondition(! this->has_data());
- data_ = new image3d_b_data<T>(make::box3d(nslis, nrows, ncols), bdr);
+ vb_.pmin() = b_.pmin() - dpoint3d(all(bdr_));
+ vb_.pmax() = b_.pmax() + dpoint3d(all(bdr_));
}
template <typename T>
- image3d_b<T>::image3d_b(const box3d& b, unsigned bdr)
- : data_(0)
+ void
+ data_< image3d_b<T> >::allocate_()
{
- init_with(b, bdr);
+ update_vb_();
+ unsigned
+ ns = vb_.len(0),
+ nr = vb_.len(1),
+ nc = vb_.len(2);
+ buffer_ = new T[nr * nc * ns];
+ array_ = new T**[ns];
+ T* buf = buffer_ - vb_.pmin().col();
+ for (unsigned i = 0; i < ns; ++i)
+ {
+ T** tmp = new T*[nr];
+ array_[i] = tmp;
+ for (unsigned j = 0; j < nr; ++j)
+ {
+ array_[i][j] = buf;
+ buf += nc;
+ }
+ array_[i] -= vb_.pmin().row();
+ }
+ array_ -= vb_.pmin().sli();
+ mln_postcondition(vb_.len(0) = b_.len(0) + 2 * bdr_);
}
template <typename T>
void
- image3d_b<T>::init_with(const box3d& b, unsigned bdr)
+ data_< image3d_b<T> >::deallocate_()
{
- mln_precondition(! this->has_data());
- data_ = new image3d_b_data<T>(b, bdr);
+ if (buffer_)
+ {
+ delete[] buffer_;
+ buffer_ = 0;
}
-
- template <typename T>
- image3d_b<T>::image3d_b(const image3d_b<T>& rhs)
- : super(rhs),
- data_(rhs.data_)
+ for (typename point3d::coord i = vb_.pmin().sli(); i <= vb_.pmax().sli(); ++i)
+ {
+ if (array_[i])
+ {
+ array_[i] += vb_.pmin().row();
+ delete[] array_[i];
+ array_[i] = 0;
+ }
+ }
+ if (array_)
{
+ array_ += vb_.pmin().sli();
+ delete[] array_;
+ array_ = 0;
}
+ }
+
+ } // end of namespace mln::internal
- // assignment
+ // image3d_b<T>
template <typename T>
- image3d_b<T>&
- image3d_b<T>::operator=(const image3d_b<T>& rhs)
+ image3d_b<T>::image3d_b()
{
- mln_precondition(rhs.has_data());
- if (& rhs = this)
- return *this;
+ }
- this->data_ = rhs.data_;
- return *this;
+ template <typename T>
+ image3d_b<T>::image3d_b(const box3d& b, unsigned bdr)
+ {
+ init_with(b, bdr);
}
- // methods
+ template <typename T>
+ image3d_b<T>::image3d_b(int nslis, int nrows, int ncols, unsigned bdr)
+ {
+ init_with(make::box3d(nslis, nrows, ncols), bdr);
+ }
template <typename T>
- bool
- image3d_b<T>::has_data() const
+ void
+ image3d_b<T>::init_with(const box3d& b, unsigned bdr)
{
- return data_ != 0;
+ mln_precondition(! this->has_data());
+ this->data_ = new internal::data_< image3d_b<T> >(b, bdr);
}
template <typename T>
@@ -357,11 +399,6 @@
}
template <typename T>
- image3d_b<T>::~image3d_b()
- {
- }
-
- template <typename T>
const T*
image3d_b<T>::buffer() const
{
@@ -398,8 +435,6 @@
return p;
}
-
-
# endif // ! MLN_INCLUDE_ONLY
} // end of namespace mln
Index: mln/util/tracked_ptr.hh
--- mln/util/tracked_ptr.hh (revision 1147)
+++ mln/util/tracked_ptr.hh (working copy)
@@ -25,8 +25,15 @@
// reasons why the executable file might be covered by the GNU General
// Public License.
-#ifndef MLN_CORE_INTERNAL_TRACKED_PTR_HH
-# define MLN_CORE_INTERNAL_TRACKED_PTR_HH
+#ifndef MLN_UTIL_TRACKED_PTR_HH
+# define MLN_UTIL_TRACKED_PTR_HH
+
+/*! \file mln/util/tracked_ptr.hh
+ *
+ * \brief Definition of a smart pointer for shared data with tracking.
+ *
+ * \todo Split defs from decls.
+ */
# include <set>
# include <iostream>
@@ -34,9 +41,13 @@
# include <mln/core/contract.hh>
+
namespace mln
{
+ namespace util
+ {
+
template <typename T>
struct tracked_ptr
{
@@ -273,9 +284,11 @@
}
-# endif
+# endif // ! MLN_INCLUDE_ONLY
+
+ } // end of namespace mln::util
} // end of namespace mln
-#endif // ! MLN_CORE_INTERNAL_TRACKED_PTR_HH
+#endif // ! MLN_UTIL_TRACKED_PTR_HH