[vspline] 49/72: added map.h, with new implementation of teating out-of-bounds coordinates I was never really happy with the code in mapping.h with it's function pointers and the mixup between mapping and splitting of coordinates. So now I thought out a different way of doing the task. I want bspline objects to now have const bcv's and have the coordinate pretreatment via specialized types. map.h now has the basis for doing this: there is a collection of 'gate' types which are derived from vspline::unary_functor and offer ways of 'treating' out-of-bounds coordinates, and there is a class 'mapper' which contains a set of such gate objects and can apply them to an nD coordinate. what's missing is the integration with class evaluator and the modifications to class bspline.

Kay F. Jahnke kfj-guest at moszumanska.debian.org
Sun Jul 2 09:02:42 UTC 2017


This is an automated email from the git hooks/post-receive script.

kfj-guest pushed a commit to branch master
in repository vspline.

commit a02e20f46f58b16b3caca24f9fc1c5e0498d9c78
Author: Kay F. Jahnke <kfjahnke at gmail.com>
Date:   Sat Apr 22 12:41:27 2017 +0200

    added map.h, with new implementation of teating out-of-bounds coordinates
    I was never really happy with the code in mapping.h with it's function pointers and
    the mixup between mapping and splitting of coordinates. So now I thought out a different
    way of doing the task. I want bspline objects to now have const bcv's and have the
    coordinate pretreatment via specialized types. map.h now has the basis for doing this:
    there is a collection of 'gate' types which are derived from vspline::unary_functor
    and offer ways of 'treating' out-of-bounds coordinates, and there is a class 'mapper'
    which contains a set of such gate objects and can apply them to an nD coordinate.
    what's missing is the integration with class evaluator and the modifications to
    class bspline.
---
 map.h     | 525 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 mapping.h |   7 +-
 2 files changed, 530 insertions(+), 2 deletions(-)

diff --git a/map.h b/map.h
new file mode 100644
index 0000000..cb8437c
--- /dev/null
+++ b/map.h
@@ -0,0 +1,525 @@
+/************************************************************************/
+/*                                                                      */
+/*    vspline - a set of generic tools for creation and evaluation      */
+/*              of uniform b-splines                                    */
+/*                                                                      */
+/*            Copyright 2015 - 2017 by Kay F. Jahnke                    */
+/*                                                                      */
+/*    The git repository for this software is at                        */
+/*                                                                      */
+/*    https://bitbucket.org/kfj/vspline                                 */
+/*                                                                      */
+/*    Please direct questions, bug reports, and contributions to        */
+/*                                                                      */
+/*    kfjahnke+vspline at gmail.com                                        */
+/*                                                                      */
+/*    Permission is hereby granted, free of charge, to any person       */
+/*    obtaining a copy of this software and associated documentation    */
+/*    files (the "Software"), to deal in the Software without           */
+/*    restriction, including without limitation the rights to use,      */
+/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
+/*    sell copies of the Software, and to permit persons to whom the    */
+/*    Software is furnished to do so, subject to the following          */
+/*    conditions:                                                       */
+/*                                                                      */
+/*    The above copyright notice and this permission notice shall be    */
+/*    included in all copies or substantial portions of the             */
+/*    Software.                                                         */
+/*                                                                      */
+/*    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND    */
+/*    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES   */
+/*    OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND          */
+/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
+/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
+/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
+/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
+/*                                                                      */
+/************************************************************************/
+
+/*! \file map.h
+
+    \brief code to handle out-of-bounds coordinates.
+    
+    Incoming coordinates may not be inside the range which can be evaluated
+    by the spline. There is no one correct way of dealing with out-of-bounds
+    coordinates, so we provide a few common ways of do it, and also offer
+    the users a way to provide their own handling.
+    
+    The basic type handling the operation is 'gate_type', which 'treats'
+    a single value or single simdized type. For nD coordinates, we use a
+    set of these gate_type objects, one for each component, and each of
+    a distinct type specific to the axis the component belongs to.
+    
+    Application of the gates is via a 'mapper' object, which contains
+    the gate_types and applies them to the components in turn.
+    
+    The final mapper object is a functor which converts an arbitrary incoming
+    coordinate into an in-range coordinate (or, for REJECT mode, throws an
+    out_of_bounds exception).
+    
+    We provide code to pass coordinates through unmodified, to
+    reject out-of-bounds values, to clamp them, set them to a fixed value,
+    'unmirror' on the bounds or to 'unperiodize'. Finally there is a version
+    taking two std::functions, one for single values and one for simdized types,
+    which applies the appropriate functor to incoming coordinates.
+*/
+
+#ifndef VSPLINE_MAP_H
+#define VSPLINE_MAP_H
+
+#include <vspline/unary_functor.h>
+#include <vspline/mapping.h>
+#include <vigra/tinyvector.hxx>
+
+namespace vspline
+{
+/// unspecialized gate_type. only classes specialized by 'mode'
+/// actually do any work.
+
+template < typename rc_type ,
+           vspline::bc_code mode ,
+           int vsize >
+struct gate_type
+{
+} ;
+
+/// specializations for the supported mapping modes
+
+/// the most basic gate passes it's input to it's output unmodified.
+/// Like all gate_types, this gate_type inherits from a vspline::unary_functor,
+/// with input and output types equal. this specialization needs no
+/// constructor, since it's independent of a range.
+
+template < typename _rc_type ,
+           int _vsize >
+struct gate_type < _rc_type , vspline::RAW , _vsize >
+: public vspline::unary_functor < _rc_type , _rc_type , _vsize >
+{
+  typedef _rc_type rc_type ;
+  
+  // pull in vspline::unary_functor's type system
+
+  typedef vspline::unary_functor < rc_type ,
+                                   rc_type ,
+                                   _vsize > base_type ;
+                                   
+  using_unary_functor_types(base_type) ;
+  
+  // implement vspline::unary_functor's two pure virtual methods:
+
+  void eval ( const in_type & c ,
+                    out_type & result ) const
+  {
+    result = c ;
+  }
+  
+  void eval ( const in_v & c ,
+                    out_v & result ) const
+  {
+    result = c ;
+  }
+
+} ;
+
+/// gate with REJECT throws vspline::out_of_bounds for invalid coordinates
+
+template < typename _rc_type ,
+           int _vsize >
+struct gate_type < _rc_type , vspline::REJECT , _vsize >
+: public vspline::unary_functor < _rc_type , _rc_type , _vsize >
+{
+  typedef _rc_type rc_type ;
+  typedef vspline::unary_functor < rc_type , rc_type , _vsize > base_type ;
+  using_unary_functor_types(base_type) ;
+  
+  const rc_type lower ;
+  const rc_type upper ;
+  
+  // the constructor pulls in the bounds
+
+  gate_type ( rc_type _lower ,
+              rc_type _upper )
+  : lower ( _lower ) ,
+    upper ( _upper )
+  { } ;
+
+  void eval ( const in_type & c ,
+                    out_type & result ) const
+  {
+    if ( c < lower || c > upper )
+      throw vspline::out_of_bounds() ;
+    result = c ;
+  }
+  
+  void eval ( const in_v & c ,
+                    out_v & result ) const
+  {
+    if ( any_of ( ( c[0] < lower ) | ( c[0] > upper ) ) )
+      throw vspline::out_of_bounds() ;
+    result = c ;
+  }
+
+} ;
+
+/// gate with LIMIT clamps out-of-bounds values
+
+template < typename _rc_type ,
+           int _vsize >
+struct gate_type < _rc_type , vspline::LIMIT , _vsize >
+: public vspline::unary_functor < _rc_type , _rc_type , _vsize >
+{
+  typedef _rc_type rc_type ;
+  typedef vspline::unary_functor < rc_type , rc_type , _vsize > base_type ;
+  using_unary_functor_types(base_type) ;
+  
+  const rc_type lower ;
+  const rc_type upper ;
+  
+  gate_type ( rc_type _lower ,
+              rc_type _upper )
+  : lower ( _lower ) ,
+    upper ( _upper )
+  { } ;
+
+  void eval ( const in_type & c ,
+                    out_type & result ) const
+  {
+    if ( c < lower )
+      result = lower ;
+    else if ( c > upper )
+      result = upper ;
+    else
+      result = c ;
+  }
+  
+  void eval ( const in_v & c ,
+                    out_v & result ) const
+  {
+    out_ele_v cc = c[0] ;
+    cc ( cc < lower ) = lower ;
+    cc ( cc > upper ) = upper ;
+    result[0] = cc ;
+  }
+
+} ;
+
+/// constant gate assigns 'fix' to out-of-bounds coordinates
+
+template < typename _rc_type ,
+           int _vsize >
+struct gate_type < _rc_type , vspline::CONSTANT , _vsize >
+: public vspline::unary_functor < _rc_type , _rc_type , _vsize >
+{
+  typedef _rc_type rc_type ;
+  typedef vspline::unary_functor < rc_type , rc_type , _vsize > base_type ;
+  using_unary_functor_types(base_type) ;
+  
+  const rc_type lower ;
+  const rc_type upper ;
+  const rc_type fix ;
+  
+  gate_type ( rc_type _lower ,
+              rc_type _upper ,
+              rc_type _fix
+            )
+  : lower ( _lower ) ,
+    upper ( _upper ) ,
+    fix ( _fix )
+  { } ;
+
+  void eval ( const in_type & c ,
+                    out_type & result ) const
+  {
+    if ( c < lower )
+      result = fix ;
+    else if ( c > upper )
+      result = fix ;
+    else
+      result = c ;
+  }
+  
+  void eval ( const in_v & c ,
+                    out_v & result ) const
+  {
+    out_ele_v cc = c[0] ;
+    cc ( cc < lower ) = fix ;
+    cc ( cc > upper ) = fix ;
+    result[0] = cc ;
+  }
+
+} ;
+
+/// gate with mirror moves coordinates into the range. It places the
+/// result value so that mirroring it on both lower and upper (which
+/// produces an infinite number of mirror images) will produce one
+/// mirror image coinciding with the input.
+
+template < typename _rc_type ,
+           int _vsize >
+struct gate_type < _rc_type , vspline::MIRROR , _vsize >
+: public vspline::unary_functor < _rc_type , _rc_type , _vsize >
+{
+  typedef _rc_type rc_type ;
+  typedef vspline::unary_functor < rc_type , rc_type , _vsize > base_type ;
+  using_unary_functor_types(base_type) ;
+  
+  const rc_type lower ;
+  const rc_type upper ;
+  
+  gate_type ( rc_type _lower ,
+              rc_type _upper )
+  : lower ( _lower ) ,
+    upper ( _upper )
+  { } ;
+
+  void eval ( const in_type & c ,
+                    out_type & result ) const
+  {
+    in_type cc = c ;
+    if ( cc < lower )
+      cc = 2 * lower - cc ;
+    if ( cc > upper )
+    {
+      cc -= lower ;
+      cc = std::fmod ( cc , 2 * ( upper - lower ) ) ;
+      cc += lower ;
+      if ( cc > upper )
+        cc = 2 * upper - cc ;
+    }
+    result = cc ;
+  }
+  
+  void eval ( const in_v & c ,
+                    out_v & result ) const
+  {
+    out_ele_v cc ;
+    
+    cc = c[0] - lower ;
+    auto w = upper - lower ;
+
+    cc = abs ( cc ) ;                   // left mirror, v is now >= 0
+
+    if ( any_of ( cc > w ) )
+    {
+      cc = v_fmod ( cc , 2 * w ) ;        // map to one full period
+      cc -= w ;                     // ccenter
+      cc = abs ( cc ) ;                     // map to half period
+      cc = w - cc ;                  // flip
+    }
+    
+    result[0] = cc + lower ;
+  }
+
+} ;
+
+template < typename _rc_type ,
+           int _vsize >
+struct gate_type < _rc_type , vspline::PERIODIC , _vsize >
+: public vspline::unary_functor < _rc_type , _rc_type , _vsize >
+{
+  typedef _rc_type rc_type ;
+  typedef vspline::unary_functor < rc_type , rc_type , _vsize > base_type ;
+  using_unary_functor_types(base_type) ;
+  
+  const rc_type lower ;
+  const rc_type upper ;
+  
+  gate_type ( rc_type _lower ,
+              rc_type _upper )
+  : lower ( _lower ) ,
+    upper ( _upper )
+  { } ;
+
+  void eval ( const in_type & c ,
+                    out_type & result ) const
+  {
+    in_type cc = c - lower ;
+    auto w = upper - lower ;
+    
+    if ( cc < 0 )
+      cc = w + fmod ( cc , w ) ;
+    else if ( cc >= w )
+      cc = fmod ( cc , w ) ;
+    result = cc + lower ;
+  }
+  
+  void eval ( const in_v & c ,
+                    out_v & result ) const
+  {
+    out_ele_v cc ;
+    
+    cc = c[0] - lower ;
+    auto w = upper - lower ;
+
+    if ( any_of ( ( cc < 0 ) | ( cc >= w ) ) )
+    {
+      cc = v_fmod ( cc , w ) ;
+      cc ( cc < 0 ) += w ;
+    }
+    
+    result[0] = cc + lower ;
+  }
+
+} ;
+
+/// currently abusing GUESS to delegate to a pair of std::functions
+/// this allows user code to introduce arbitrary gate functions when
+/// the provided ready-made ones aren't sufficient.
+
+template < typename _rc_type ,
+           int _vsize >
+struct gate_type < _rc_type , vspline::GUESS , _vsize >
+: public vspline::unary_functor < _rc_type , _rc_type , _vsize >
+{
+  typedef _rc_type rc_type ;
+  typedef vspline::unary_functor < rc_type , rc_type , _vsize > base_type ;
+  using_unary_functor_types(base_type) ;
+  
+  typedef std::function < out_type ( in_type ) > func_type ;
+  typedef std::function < out_ele_v ( in_ele_v ) > vfunc_type ;
+  
+  const func_type f ;
+  const vfunc_type vf ;
+  
+  gate_type ( func_type _f , vfunc_type _vf )
+  : f ( _f ) , vf ( _vf )
+  { } ;
+
+  void eval ( const in_type & c ,
+                    out_type & result ) const
+  {
+    result = f ( c ) ;
+  }
+  
+  void eval ( const in_v & c ,
+                    out_v & result ) const
+  {
+    result[0] = vf ( c[0] ) ;
+  }
+
+} ;
+
+// /// struct mapper1 applies a gate to it's incoming coordinate,
+// /// then splits it according to it's splitting mode
+// 
+// template < typename _gate_type ,
+//            typename _ic_type ,
+//            vspline::bc_code mode >
+// struct mapper1
+// {
+// } ;
+// 
+// /// simple raw mapping (should be one of two, for odd and even)
+// 
+// template < typename _gate_type , typename _ic_type >
+// struct mapper1 < _gate_type , _ic_type , vspline::RAW >
+// {
+//   typedef _gate_type gate_type ;
+//   typedef _ic_type ic_type ;
+// 
+//   typedef typename gate_type::out_ele_type rc_type ;
+//   typedef typename gate_type::out_ele_v rc_v ;
+//   typedef typename vspline::vector_traits
+//                     < _ic_type , gate_type::vsize > :: type ic_v ;
+//   
+//   const gate_type & gate ;
+//   
+//   mapper1 ( const gate_type & _gate )
+//   : gate ( _gate )
+//   { } ;
+// 
+//   // we need two overloads for map(), one for single values, one for SIMD types
+// 
+//   virtual void map ( const rc_type& in ,
+//                      ic_type & out_i ,
+//                      rc_type & out_r ) const
+//   {
+//     rc_type gated ;
+//     rc_type fi ;
+//     gate.eval ( in , gated ) ;
+//     out_r = std::modf ( gated , &fi ) ;
+//     out_i = fi ;
+//   }
+// 
+//   virtual void map ( const rc_v& in ,
+//                      ic_v & out_i ,
+//                      rc_v & out_r ) const
+//   {
+//     rc_v gated ;
+//     rc_v fi ;
+//     gate.eval ( in , gated ) ;
+//     out_r = vspline::v_modf ( gated , &fi ) ;
+//     out_i = fi ;
+//   }
+// 
+// } ;
+
+/// finally we define class mapper which is initialized with a set of
+/// gate objects (of arbitrary type) which are applied to each component
+/// of an incoming nD coordinate in turn.
+/// The trickery with the variadic template argument list is necessary,
+/// because we want to be able to combine arbitrary gate types, which
+/// have distinct types to make them as efficient as possible.
+
+template < class ... Types >  // types of the 1D mappers
+struct mapper
+{
+  // we infer the dimensionality from the number of 1D mapper types
+  enum { dimension = sizeof...(Types) } ;
+  
+  // we want to hold the 1D mappers in a tuple
+  typedef std::tuple < Types... > mvec_type ;
+  
+  // mvec holds the 1D gate objects passed to the constructor
+  const mvec_type mvec ;
+  
+  mapper ( Types ... args )
+  : mvec ( args... )
+  { } ;
+  
+  // to handle the application of the 1D gates, we use a recursive
+  // helper type which applies the 1D gate for a specific axis and
+  // then recurses to the next axis until axis 0 is reached.
+
+  template < int level , typename nd_rc_type >
+  struct _map
+  { 
+    void operator() ( const mvec_type & mvec ,
+                      const nd_rc_type & in ,
+                      nd_rc_type & out ) const
+    {
+      std::get<level>(mvec).eval ( in[level] , out[level] ) ;
+      _map < level - 1 , nd_rc_type >() ( mvec , in , out ) ;
+    }
+  } ;
+  
+  // at level 0 the recursion ends
+  
+  template < typename nd_rc_type >
+  struct _map < 0 , nd_rc_type >
+  { 
+    void operator() ( const mvec_type & mvec ,
+                      const nd_rc_type & in ,
+                      nd_rc_type & out ) const
+    {
+      std::get<0>(mvec).eval ( in[0] , out[0] ) ;
+    }
+  } ;
+  
+  // finally, the implementation of struct mapper's map() method is
+  // simple: we delegate to a _map object for the highest axis.
+  // note how this code will handle singular and vectorized coordinates
+  // alike; the gate object can handle either.
+  
+  template < typename nd_rc_type >
+  void operator() ( const nd_rc_type & in ,
+                    nd_rc_type & out )
+  {
+    _map < dimension - 1 , nd_rc_type >() ( mvec , in , out ) ;
+  }
+} ;
+
+} ; // namespace vspline
+
+#endif // #ifndef VSPLINE_MAP_H
diff --git a/mapping.h b/mapping.h
index 073bd74..aeb3e7b 100644
--- a/mapping.h
+++ b/mapping.h
@@ -270,7 +270,7 @@ public:
 /// All remaining mappings in this file are safe insofar as out-of-bounds incoming coordinates
 /// will either result in an exception or be handled in a way specific to the mapping.
 ///
-/// the next mapping mode is LIMIT. Here any out-of-bounds coordinates are set to the
+/// the next mapping mode is LIMIT. Here any out-of-bounds coordinates are clamped to the
 /// nearest valid value.
 
 template < typename ic_t , typename rc_t , int vsize = 1 >
@@ -923,6 +923,9 @@ public:
 /// coordinates, which is used in the roundtrip test, will produce the expected result.
 /// So, the left point of reflection as at -0.5, the right point of reflection at M - 0.5.
 
+// TODO I think this is wrong, the initial application of odd_mapping_mirror
+// can't have an effect
+
 template < typename ic_t , typename rc_t , int vsize = 1 >
 class odd_mapping_reflect
 {
@@ -1133,7 +1136,7 @@ map_func pick_mapping ( bc_code bc ,        ///< mapping mode
         /// as we could with periodic or mirror bcs.
         /// nevertheless we want to perform the usual transformations to real indices which
         /// correspond to data *inside* the defined range. What we do outside the defined range
-        /// is arbitrary, so here I repeat the value at the bounds ad infinitum.
+        /// is arbitrary, so here I clamp value at the bounds.
         return odd_mapping_limit < ic_t , rc_t , vsize > ( M ) ;
         break ;
       }

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/vspline.git



More information about the debian-science-commits mailing list