<commit_before>/*******************************************************************************
 *
 * Generic implementation of non-relational domains.
 *
 * Author: Arnaud J. Venet (arnaud.j.venet@nasa.gov)
 *
 * Notices:
 *
 * Copyright (c) 2011 United States Government as represented by the
 * Administrator of the National Aeronautics and Space Administration.
 * All Rights Reserved.
 *
 * Disclaimers:
 *
 * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF
 * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED
 * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS,
 * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
 * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE
 * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO
 * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN
 * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS,
 * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS
 * RESULTING FROM USE OF THE SUBJECT SOFTWARE.  FURTHER, GOVERNMENT AGENCY
 * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE,
 * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS."
 *
 * Waiver and Indemnity:  RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST
 * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL
 * AS ANY PRIOR RECIPIENT.  IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS
 * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH
 * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM,
 * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD
 * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS,
 * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW.
 * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE,
 * UNILATERAL TERMINATION OF THIS AGREEMENT.
 *
 ******************************************************************************/

#pragma once

#include <crab/common/types.hpp>
#include <crab/domains/patricia_trees.hpp>
#include <boost/optional.hpp>

namespace ikos {

  template <typename Key, typename Value>
  class separate_domain {

  private:
    typedef patricia_tree<Key, Value> patricia_tree_t;
    typedef typename patricia_tree_t::unary_op_t unary_op_t;
    typedef typename patricia_tree_t::binary_op_t binary_op_t;
    typedef typename patricia_tree_t::partial_order_t partial_order_t;

  public:
    typedef separate_domain<Key, Value> separate_domain_t;
    typedef typename patricia_tree_t::iterator iterator;
    typedef Key key_type;
    typedef Value value_type;

  private:
    bool _is_bottom;
    patricia_tree_t _tree;

  public:

    class join_op: public binary_op_t {
      std::pair<bool, boost::optional<Value>> apply(Value x, Value y) {
        Value z = x.operator|(y);
        if (z.is_top()) {
          return {false, boost::optional<Value>()};
        } else {
          return {false, boost::optional<Value>(z)};
        }
      };

      bool default_is_absorbing() {
	return true;
      }
    }; // class join_op

    class widening_op: public binary_op_t {
      std::pair<bool, boost::optional<Value>> apply(Value x, Value y) {
        Value z = x.operator||(y);
        if (z.is_top()) {
          return {false, boost::optional<Value>()};
        } else {
          return {false, boost::optional<Value>(z)};
        }
      };

      bool default_is_absorbing() {
        return true;
      }

    }; // class widening_op

    template <typename Thresholds>
    class widening_thresholds_op: public binary_op_t {
      const Thresholds& m_ts;

     public:
      widening_thresholds_op (const Thresholds& ts): m_ts (ts) { }

      std::pair<bool, boost::optional<Value>> apply(Value x, Value y) {
        Value z = x.widening_thresholds(y, m_ts);
        if (z.is_top()) {
          return {false, boost::optional<Value>()};
        } else {
          return {false, boost::optional<Value>(z)};
        }
      };

      bool default_is_absorbing() {
        return true;
      }

    }; // class widening_thresholds_op

    class meet_op: public binary_op_t {
      std::pair<bool, boost::optional<Value>> apply(Value x, Value y) {
        Value z = x.operator&(y);
        if (z.is_bottom()) {
          return {true, boost::optional<Value>()};
        } else {
          return {false, boost::optional<Value>(z)};
        }
      };

      bool default_is_absorbing() {
        return false;
      }

    }; // class meet_op

    class narrowing_op: public binary_op_t {
      std::pair<bool, boost::optional<Value>> apply(Value x, Value y) {
        Value z = x.operator&&(y);
        if (z.is_bottom()) {
          return {true, boost::optional<Value>()};
        } else {
          return {false, boost::optional<Value>(z)};
        }
      };

      bool default_is_absorbing() {
        return false;
      }

    }; // class narrowing_op

    class domain_po: public partial_order_t {
      bool leq(Value x, Value y) {
        return x.operator<=(y);
      }

      bool default_is_top() {
        return true;
      }

    }; // class domain_po

   public:
    static separate_domain_t top() {
      return separate_domain_t();
    }

    static separate_domain_t bottom() {
      return separate_domain_t(false);
    }

   private:
    static patricia_tree_t apply_operation(binary_op_t& o,
					   patricia_tree_t t1,
					   patricia_tree_t t2,
					   bool& is_bottom) {
      is_bottom = t1.merge_with(t2, o);
      return t1;
    }

    separate_domain(patricia_tree_t t): _is_bottom(false), _tree(t) { }

    separate_domain(bool b): _is_bottom(!b) { }

  public:
    separate_domain(): _is_bottom(false) { }

    separate_domain(const separate_domain_t& e):
        _is_bottom(e._is_bottom), _tree(e._tree) { }

    separate_domain(const separate_domain_t&& e):
      _is_bottom(e._is_bottom), _tree(std::move(e._tree)) { }

    separate_domain_t& operator=(separate_domain_t e) {
      this->_is_bottom = e._is_bottom;
      this->_tree = e._tree;
      return *this;
    }

    iterator begin() const {
      if (this->is_bottom()) {
        CRAB_ERROR("Separate domain: trying to invoke iterator on bottom");
      } else {
        return this->_tree.begin();
      }
    }

    iterator end() const {
      if (this->is_bottom()) {
        CRAB_ERROR("Separate domain: trying to invoke iterator on bottom");
      } else {
        return this->_tree.end();
      }
    }

    bool is_bottom() const {
      return this->_is_bottom;
    }

    bool is_top() const {
      return (!this->is_bottom() && this->_tree.size() == 0);
    }

    bool operator<=(separate_domain_t e) {
      if (this->is_bottom()) {
        return true;
      } else if (e.is_bottom()) {
        return false;
      } else {
        domain_po po;
        return this->_tree.leq(e._tree, po);
      }
    }

    bool operator==(separate_domain_t e) {
      return (this->operator<=(e) && e.operator<=(*this));
    }

    // Join
    separate_domain_t operator|(separate_domain_t e) {
      if (this->is_bottom()) {
        return e;
      } else if(e.is_bottom()) {
        return *this;
      } else {
        join_op o;
	bool is_bottom;
	patricia_tree_t res = apply_operation(o, this->_tree, e._tree, is_bottom);
        return separate_domain_t(std::move(res));
      }
    }

    // Meet
    separate_domain_t operator&(separate_domain_t e) {
      if (this->is_bottom() || e.is_bottom()) {
        return this->bottom();
      } else {
	meet_op o;
	bool is_bottom;
	patricia_tree_t res = apply_operation(o, this->_tree, e._tree, is_bottom);
	if (is_bottom) {
	  return this->bottom();
	} else {
	  return separate_domain_t(std::move(res));
	}
      }
    }

    // Widening
    separate_domain_t operator||(separate_domain_t e) {
      if (this->is_bottom()) {
        return e;
      } else if(e.is_bottom()) {
        return *this;
      } else {
        widening_op o;
	bool is_bottom;
	patricia_tree_t res = apply_operation(o, this->_tree, e._tree, is_bottom);
	return separate_domain_t(std::move(res));
      }
    }

    // Widening with thresholds
    template<typename Thresholds>
    separate_domain_t widening_thresholds(separate_domain_t e, const Thresholds& ts) {
      if (this->is_bottom()) {
        return e;
      } else if(e.is_bottom()) {
        return *this;
      } else {
        widening_thresholds_op<Thresholds> o(ts);
	bool is_bottom;
	patricia_tree_t res = apply_operation(o, this->_tree, e._tree, is_bottom);
        return separate_domain_t(std::move(res));
      }
    }

    // Narrowing
    separate_domain_t operator&&(separate_domain_t e) {
      if (this->is_bottom() || e.is_bottom()) {
        return separate_domain_t(false);
      } else {
	narrowing_op o;
	bool is_bottom;
	patricia_tree_t res = apply_operation(o, this->_tree, e._tree, is_bottom);
	if (is_bottom) {
	  return this->bottom();
	} else {
	  return separate_domain_t(std::move(res));
	}
      }
    }

    void set(Key k, Value v) {
      if (!this->is_bottom()) {
        if (v.is_bottom()) {
          this->_is_bottom = true;
          this->_tree = patricia_tree_t();
        } else if (v.is_top()) {
          this->_tree.remove(k);
        } else {
          this->_tree.insert(k, v);
        }
      }
    }

    void set_to_bottom() {
      this->_is_bottom = true;
      this->_tree = patricia_tree_t();
    }

    separate_domain_t& operator-=(Key k) {
      if (!this->is_bottom()) {
        this->_tree.remove(k);
      }
      return *this;
    }

    Value operator[](Key k) const {
      if (this->is_bottom()) {
        return Value::bottom();
      } else {
        boost::optional<Value> v = this->_tree.lookup(k);
        if (v) {
          return *v;
        } else {
          return Value::top();
        }
      }
    }

    std::size_t size() const {
      if (is_bottom()) {
	return 0;
      } else if (is_top()) {
	CRAB_ERROR("separate_domains::size() is undefined if top");
      } else {
	return this->_tree.size();
      }
    }

    void write(crab::crab_os& o) const {
      if (this->is_bottom()) {
        o << "_|_";
      } else {
        o << "{";
        for (typename patricia_tree_t::iterator it = this->_tree.begin();
             it != this->_tree.end(); ) {
          Key k = it->first;
          k.write(o);
          o << " -> ";
          Value v = it->second;
          v.write(o);
          ++it;
          if (it != this->_tree.end()) {
            o << "; ";
	  }
        }
        o << "}";
      }
    }

    friend crab::crab_os& operator<<(crab::crab_os&o, const separate_domain<Key,Value>& d) {
      d.write(o);
      return o;
    }
  }; // class separate_domain

} // namespace ikos

<commit_msg>Add const to key parameter in separate_domains.hpp<commit_after>/*******************************************************************************
 *
 * Generic implementation of non-relational domains.
 *
 * Author: Arnaud J. Venet (arnaud.j.venet@nasa.gov)
 *
 * Notices:
 *
 * Copyright (c) 2011 United States Government as represented by the
 * Administrator of the National Aeronautics and Space Administration.
 * All Rights Reserved.
 *
 * Disclaimers:
 *
 * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF
 * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED
 * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS,
 * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
 * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE
 * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO
 * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN
 * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS,
 * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS
 * RESULTING FROM USE OF THE SUBJECT SOFTWARE.  FURTHER, GOVERNMENT AGENCY
 * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE,
 * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS."
 *
 * Waiver and Indemnity:  RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST
 * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL
 * AS ANY PRIOR RECIPIENT.  IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS
 * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH
 * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM,
 * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD
 * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS,
 * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW.
 * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE,
 * UNILATERAL TERMINATION OF THIS AGREEMENT.
 *
 ******************************************************************************/

#pragma once

#include <crab/common/types.hpp>
#include <crab/domains/patricia_trees.hpp>
#include <boost/optional.hpp>

namespace ikos {

  template <typename Key, typename Value>
  class separate_domain {

  private:
    typedef patricia_tree<Key, Value> patricia_tree_t;
    typedef typename patricia_tree_t::unary_op_t unary_op_t;
    typedef typename patricia_tree_t::binary_op_t binary_op_t;
    typedef typename patricia_tree_t::partial_order_t partial_order_t;

  public:
    typedef separate_domain<Key, Value> separate_domain_t;
    typedef typename patricia_tree_t::iterator iterator;
    typedef Key key_type;
    typedef Value value_type;

  private:
    bool _is_bottom;
    patricia_tree_t _tree;

  public:

    class join_op: public binary_op_t {
      std::pair<bool, boost::optional<Value>> apply(Value x, Value y) {
        Value z = x.operator|(y);
        if (z.is_top()) {
          return {false, boost::optional<Value>()};
        } else {
          return {false, boost::optional<Value>(z)};
        }
      };

      bool default_is_absorbing() {
	return true;
      }
    }; // class join_op

    class widening_op: public binary_op_t {
      std::pair<bool, boost::optional<Value>> apply(Value x, Value y) {
        Value z = x.operator||(y);
        if (z.is_top()) {
          return {false, boost::optional<Value>()};
        } else {
          return {false, boost::optional<Value>(z)};
        }
      };

      bool default_is_absorbing() {
        return true;
      }

    }; // class widening_op

    template <typename Thresholds>
    class widening_thresholds_op: public binary_op_t {
      const Thresholds& m_ts;

     public:
      widening_thresholds_op (const Thresholds& ts): m_ts (ts) { }

      std::pair<bool, boost::optional<Value>> apply(Value x, Value y) {
        Value z = x.widening_thresholds(y, m_ts);
        if (z.is_top()) {
          return {false, boost::optional<Value>()};
        } else {
          return {false, boost::optional<Value>(z)};
        }
      };

      bool default_is_absorbing() {
        return true;
      }

    }; // class widening_thresholds_op

    class meet_op: public binary_op_t {
      std::pair<bool, boost::optional<Value>> apply(Value x, Value y) {
        Value z = x.operator&(y);
        if (z.is_bottom()) {
          return {true, boost::optional<Value>()};
        } else {
          return {false, boost::optional<Value>(z)};
        }
      };

      bool default_is_absorbing() {
        return false;
      }

    }; // class meet_op

    class narrowing_op: public binary_op_t {
      std::pair<bool, boost::optional<Value>> apply(Value x, Value y) {
        Value z = x.operator&&(y);
        if (z.is_bottom()) {
          return {true, boost::optional<Value>()};
        } else {
          return {false, boost::optional<Value>(z)};
        }
      };

      bool default_is_absorbing() {
        return false;
      }

    }; // class narrowing_op

    class domain_po: public partial_order_t {
      bool leq(Value x, Value y) {
        return x.operator<=(y);
      }

      bool default_is_top() {
        return true;
      }

    }; // class domain_po

   public:
    static separate_domain_t top() {
      return separate_domain_t();
    }

    static separate_domain_t bottom() {
      return separate_domain_t(false);
    }

   private:
    static patricia_tree_t apply_operation(binary_op_t& o,
					   patricia_tree_t t1,
					   patricia_tree_t t2,
					   bool& is_bottom) {
      is_bottom = t1.merge_with(t2, o);
      return t1;
    }

    separate_domain(patricia_tree_t t): _is_bottom(false), _tree(t) { }

    separate_domain(bool b): _is_bottom(!b) { }

  public:
    separate_domain(): _is_bottom(false) { }

    separate_domain(const separate_domain_t& e):
        _is_bottom(e._is_bottom), _tree(e._tree) { }

    separate_domain(const separate_domain_t&& e):
      _is_bottom(e._is_bottom), _tree(std::move(e._tree)) { }

    separate_domain_t& operator=(separate_domain_t e) {
      this->_is_bottom = e._is_bottom;
      this->_tree = e._tree;
      return *this;
    }

    iterator begin() const {
      if (this->is_bottom()) {
        CRAB_ERROR("Separate domain: trying to invoke iterator on bottom");
      } else {
        return this->_tree.begin();
      }
    }

    iterator end() const {
      if (this->is_bottom()) {
        CRAB_ERROR("Separate domain: trying to invoke iterator on bottom");
      } else {
        return this->_tree.end();
      }
    }

    bool is_bottom() const {
      return this->_is_bottom;
    }

    bool is_top() const {
      return (!this->is_bottom() && this->_tree.size() == 0);
    }

    bool operator<=(separate_domain_t e) {
      if (this->is_bottom()) {
        return true;
      } else if (e.is_bottom()) {
        return false;
      } else {
        domain_po po;
        return this->_tree.leq(e._tree, po);
      }
    }

    bool operator==(separate_domain_t e) {
      return (this->operator<=(e) && e.operator<=(*this));
    }

    // Join
    separate_domain_t operator|(separate_domain_t e) {
      if (this->is_bottom()) {
        return e;
      } else if(e.is_bottom()) {
        return *this;
      } else {
        join_op o;
	bool is_bottom;
	patricia_tree_t res = apply_operation(o, this->_tree, e._tree, is_bottom);
        return separate_domain_t(std::move(res));
      }
    }

    // Meet
    separate_domain_t operator&(separate_domain_t e) {
      if (this->is_bottom() || e.is_bottom()) {
        return this->bottom();
      } else {
	meet_op o;
	bool is_bottom;
	patricia_tree_t res = apply_operation(o, this->_tree, e._tree, is_bottom);
	if (is_bottom) {
	  return this->bottom();
	} else {
	  return separate_domain_t(std::move(res));
	}
      }
    }

    // Widening
    separate_domain_t operator||(separate_domain_t e) {
      if (this->is_bottom()) {
        return e;
      } else if(e.is_bottom()) {
        return *this;
      } else {
        widening_op o;
	bool is_bottom;
	patricia_tree_t res = apply_operation(o, this->_tree, e._tree, is_bottom);
	return separate_domain_t(std::move(res));
      }
    }

    // Widening with thresholds
    template<typename Thresholds>
    separate_domain_t widening_thresholds(separate_domain_t e, const Thresholds& ts) {
      if (this->is_bottom()) {
        return e;
      } else if(e.is_bottom()) {
        return *this;
      } else {
        widening_thresholds_op<Thresholds> o(ts);
	bool is_bottom;
	patricia_tree_t res = apply_operation(o, this->_tree, e._tree, is_bottom);
        return separate_domain_t(std::move(res));
      }
    }

    // Narrowing
    separate_domain_t operator&&(separate_domain_t e) {
      if (this->is_bottom() || e.is_bottom()) {
        return separate_domain_t(false);
      } else {
	narrowing_op o;
	bool is_bottom;
	patricia_tree_t res = apply_operation(o, this->_tree, e._tree, is_bottom);
	if (is_bottom) {
	  return this->bottom();
	} else {
	  return separate_domain_t(std::move(res));
	}
      }
    }

    void set(Key k, Value v) {
      if (!this->is_bottom()) {
        if (v.is_bottom()) {
          this->_is_bottom = true;
          this->_tree = patricia_tree_t();
        } else if (v.is_top()) {
          this->_tree.remove(k);
        } else {
          this->_tree.insert(k, v);
        }
      }
    }

    void set_to_bottom() {
      this->_is_bottom = true;
      this->_tree = patricia_tree_t();
    }

    separate_domain_t& operator-=(const Key &k) {
      if (!this->is_bottom()) {
        this->_tree.remove(k);
      }
      return *this;
    }

    Value operator[](const Key& k) const {
      if (this->is_bottom()) {
        return Value::bottom();
      } else {
        boost::optional<Value> v = this->_tree.lookup(k);
        if (v) {
          return *v;
        } else {
          return Value::top();
        }
      }
    }

    std::size_t size() const {
      if (is_bottom()) {
	return 0;
      } else if (is_top()) {
	CRAB_ERROR("separate_domains::size() is undefined if top");
      } else {
	return this->_tree.size();
      }
    }

    void write(crab::crab_os& o) const {
      if (this->is_bottom()) {
        o << "_|_";
      } else {
        o << "{";
        for (typename patricia_tree_t::iterator it = this->_tree.begin();
             it != this->_tree.end(); ) {
          Key k = it->first;
          k.write(o);
          o << " -> ";
          Value v = it->second;
          v.write(o);
          ++it;
          if (it != this->_tree.end()) {
            o << "; ";
	  }
        }
        o << "}";
      }
    }

    friend crab::crab_os& operator<<(crab::crab_os&o, const separate_domain<Key,Value>& d) {
      d.write(o);
      return o;
    }
  }; // class separate_domain

} // namespace ikos

<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: scrwnd.cxx,v $
 *
 *  $Revision: 1.11 $
 *
 *  last change: $Author: ihi $ $Date: 2007-06-06 14:21:49 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, 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
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_vcl.hxx"

#include <math.h>
#include <limits.h>

#ifndef _TOOLS_TIME_HXX
#include <tools/time.hxx>
#endif
#include <tools/debug.hxx>

#ifndef _SV_SVIDS_HRC
#include <svids.hrc>
#endif
#ifndef _SV_SVDATA_HXX
#include <svdata.hxx>
#endif
#ifndef _VCL_TIMER_HXX
#include <timer.hxx>
#endif
#ifndef _VCL_EVENT_HXX
#include <event.hxx>
#endif
#ifndef _VCL_SCRWND_HXX
#include <scrwnd.hxx>
#endif

// -----------
// - Defines -
// -----------

#define WHEEL_WIDTH     25
#define WHEEL_RADIUS    ((WHEEL_WIDTH) >> 1 )
#define MAX_TIME        300
#define MIN_TIME        20
#define DEF_TIMEOUT     50

// -------------------
// - ImplWheelWindow -
// -------------------

ImplWheelWindow::ImplWheelWindow( Window* pParent ) :
            FloatingWindow  ( pParent, 0 ),
            mnRepaintTime   ( 1UL ),
            mnTimeout       ( DEF_TIMEOUT ),
            mnWheelMode     ( WHEELMODE_NONE ),
            mnActDist       ( 0UL ),
            mnActDeltaX     ( 0L ),
            mnActDeltaY     ( 0L )
{
    // we need a parent
    DBG_ASSERT( pParent, "ImplWheelWindow::ImplWheelWindow(): Parent not set!" );

    const Size      aSize( pParent->GetOutputSizePixel() );
    const USHORT    nFlags = ImplGetSVData()->maWinData.mnAutoScrollFlags;
    const BOOL      bHorz = ( nFlags & AUTOSCROLL_HORZ ) != 0;
    const BOOL      bVert = ( nFlags & AUTOSCROLL_VERT ) != 0;

    // calculate maximum speed distance
    mnMaxWidth = (ULONG) ( 0.4 * hypot( (double) aSize.Width(), aSize.Height() ) );

    // create wheel window
    SetTitleType( FLOATWIN_TITLE_NONE );
    ImplCreateImageList();
    ResMgr* pResMgr = ImplGetResMgr();
    Bitmap aBmp;
    if( pResMgr )
        aBmp = Bitmap( ResId( SV_RESID_BITMAP_SCROLLMSK, *pResMgr ) );
    ImplSetRegion( aBmp );

    // set wheel mode
    if( bHorz && bVert )
        ImplSetWheelMode( WHEELMODE_VH );
    else if( bHorz )
        ImplSetWheelMode( WHEELMODE_H );
    else
        ImplSetWheelMode( WHEELMODE_V );

    // init timer
    mpTimer = new Timer;
    mpTimer->SetTimeoutHdl( LINK( this, ImplWheelWindow, ImplScrollHdl ) );
    mpTimer->SetTimeout( mnTimeout );
    mpTimer->Start();

    CaptureMouse();
}

// ------------------------------------------------------------------------

ImplWheelWindow::~ImplWheelWindow()
{
    ImplStop();
    delete mpTimer;
}

// ------------------------------------------------------------------------

void ImplWheelWindow::ImplStop()
{
    ReleaseMouse();
    mpTimer->Stop();
    Show(FALSE);
}

// ------------------------------------------------------------------------

void ImplWheelWindow::ImplSetRegion( const Bitmap& rRegionBmp )
{
    Point           aPos( GetPointerPosPixel() );
    const Size      aSize( rRegionBmp.GetSizePixel() );
    Point           aPoint;
    const Rectangle aRect( aPoint, aSize );

    maCenter = maLastMousePos = aPos;
    aPos.X() -= aSize.Width() >> 1;
    aPos.Y() -= aSize.Height() >> 1;

    SetPosSizePixel( aPos, aSize );
    SetWindowRegionPixel( rRegionBmp.CreateRegion( COL_BLACK, aRect ) );
}

// ------------------------------------------------------------------------

void ImplWheelWindow::ImplCreateImageList()
{
    ResMgr* pResMgr = ImplGetResMgr();
    if( pResMgr )
        maImgList.InsertFromHorizontalBitmap
            ( ResId( SV_RESID_BITMAP_SCROLLBMP, *pResMgr ), 6, NULL );
}

// ------------------------------------------------------------------------

void ImplWheelWindow::ImplSetWheelMode( ULONG nWheelMode )
{
    if( nWheelMode != mnWheelMode )
    {
        mnWheelMode = nWheelMode;

        if( WHEELMODE_NONE == mnWheelMode )
        {
            if( IsVisible() )
                Hide();
        }
        else
        {
            if( !IsVisible() )
                Show();

            ImplDrawWheel();
        }
    }
}

// ------------------------------------------------------------------------

void ImplWheelWindow::ImplDrawWheel()
{
    USHORT nId;

    switch( mnWheelMode )
    {
        case( WHEELMODE_VH ):       nId = 1; break;
        case( WHEELMODE_V    ):     nId = 2; break;
        case( WHEELMODE_H    ):     nId = 3; break;
        case( WHEELMODE_SCROLL_VH ):nId = 4; break;
        case( WHEELMODE_SCROLL_V ): nId = 5; break;
        case( WHEELMODE_SCROLL_H ): nId = 6; break;
        default:                    nId = 0; break;
    }

    if( nId )
        DrawImage( Point(), maImgList.GetImage( nId ) );
}

// ------------------------------------------------------------------------

void ImplWheelWindow::ImplRecalcScrollValues()
{
    if( mnActDist < WHEEL_RADIUS )
    {
        mnActDeltaX = mnActDeltaY = 0L;
        mnTimeout = DEF_TIMEOUT;
    }
    else
    {
        ULONG nCurTime;

        // calc current time
        if( mnMaxWidth )
        {
            const double fExp = ( (double) mnActDist / mnMaxWidth ) * log10( (double) MAX_TIME / MIN_TIME );
            nCurTime = (ULONG) ( MAX_TIME / pow( 10., fExp ) );
        }
        else
            nCurTime = MAX_TIME;

        if( !nCurTime )
            nCurTime = 1UL;

        if( mnRepaintTime <= nCurTime )
            mnTimeout = nCurTime - mnRepaintTime;
        else
        {
            long nMult = mnRepaintTime / nCurTime;

            if( !( mnRepaintTime % nCurTime ) )
                mnTimeout = 0UL;
            else
                mnTimeout = ++nMult * nCurTime - mnRepaintTime;

            double fValX = (double) mnActDeltaX * nMult;
            double fValY = (double) mnActDeltaY * nMult;

            if( fValX > LONG_MAX )
                mnActDeltaX = LONG_MAX;
            else if( fValX < LONG_MIN )
                mnActDeltaX = LONG_MIN;
            else
                mnActDeltaX = (long) fValX;

            if( fValY > LONG_MAX )
                mnActDeltaY = LONG_MAX;
            else if( fValY < LONG_MIN )
                mnActDeltaY = LONG_MIN;
            else
                mnActDeltaY = (long) fValY;
        }
    }
}

// ------------------------------------------------------------------------

PointerStyle ImplWheelWindow::ImplGetMousePointer( long nDistX, long nDistY )
{
    PointerStyle    eStyle;
    const USHORT    nFlags = ImplGetSVData()->maWinData.mnAutoScrollFlags;
    const BOOL      bHorz = ( nFlags & AUTOSCROLL_HORZ ) != 0;
    const BOOL      bVert = ( nFlags & AUTOSCROLL_VERT ) != 0;

    if( bHorz || bVert )
    {
        if( mnActDist < WHEEL_RADIUS )
        {
            if( bHorz && bVert )
                eStyle = POINTER_AUTOSCROLL_NSWE;
            else if( bHorz )
                eStyle = POINTER_AUTOSCROLL_WE;
            else
                eStyle = POINTER_AUTOSCROLL_NS;
        }
        else
        {
            double fAngle = atan2( (double) -nDistY, nDistX ) / F_PI180;

            if( fAngle < 0.0 )
                fAngle += 360.;

            if( bHorz && bVert )
            {
                if( fAngle >= 22.5 && fAngle <= 67.5 )
                    eStyle = POINTER_AUTOSCROLL_NE;
                else if( fAngle >= 67.5 && fAngle <= 112.5 )
                    eStyle = POINTER_AUTOSCROLL_N;
                else if( fAngle >= 112.5 && fAngle <= 157.5 )
                    eStyle = POINTER_AUTOSCROLL_NW;
                else if( fAngle >= 157.5 && fAngle <= 202.5 )
                    eStyle = POINTER_AUTOSCROLL_W;
                else if( fAngle >= 202.5 && fAngle <= 247.5 )
                    eStyle = POINTER_AUTOSCROLL_SW;
                else if( fAngle >= 247.5 && fAngle <= 292.5 )
                    eStyle = POINTER_AUTOSCROLL_S;
                else if( fAngle >= 292.5 && fAngle <= 337.5 )
                    eStyle = POINTER_AUTOSCROLL_SE;
                else
                    eStyle = POINTER_AUTOSCROLL_E;
            }
            else if( bHorz )
            {
                if( fAngle >= 270. || fAngle <= 90. )
                    eStyle = POINTER_AUTOSCROLL_E;
                else
                    eStyle = POINTER_AUTOSCROLL_W;
            }
            else
            {
                if( fAngle >= 0. && fAngle <= 180. )
                    eStyle = POINTER_AUTOSCROLL_N;
                else
                    eStyle = POINTER_AUTOSCROLL_S;
            }
        }
    }
    else
        eStyle = POINTER_ARROW;

    return eStyle;
}

// ------------------------------------------------------------------------

void ImplWheelWindow::Paint( const Rectangle& )
{
    ImplDrawWheel();
}

// ------------------------------------------------------------------------

void ImplWheelWindow::MouseMove( const MouseEvent& rMEvt )
{
    FloatingWindow::MouseMove( rMEvt );

    const Point aMousePos( OutputToScreenPixel( rMEvt.GetPosPixel() ) );
    const long  nDistX = aMousePos.X() - maCenter.X();
    const long  nDistY = aMousePos.Y() - maCenter.Y();

    mnActDist = (ULONG) hypot( (double) nDistX, nDistY );

    const PointerStyle  eActStyle = ImplGetMousePointer( nDistX, nDistY );
    const USHORT        nFlags = ImplGetSVData()->maWinData.mnAutoScrollFlags;
    const BOOL          bHorz = ( nFlags & AUTOSCROLL_HORZ ) != 0;
    const BOOL          bVert = ( nFlags & AUTOSCROLL_VERT ) != 0;
    const BOOL          bOuter = mnActDist > WHEEL_RADIUS;

    if( bOuter && ( maLastMousePos != aMousePos ) )
    {
        switch( eActStyle )
        {
            case( POINTER_AUTOSCROLL_N ):   mnActDeltaX = +0L, mnActDeltaY = +1L; break;
            case( POINTER_AUTOSCROLL_S ):   mnActDeltaX = +0L, mnActDeltaY = -1L; break;
            case( POINTER_AUTOSCROLL_W ):   mnActDeltaX = +1L, mnActDeltaY = +0L; break;
            case( POINTER_AUTOSCROLL_E ):   mnActDeltaX = -1L, mnActDeltaY = +0L; break;
            case( POINTER_AUTOSCROLL_NW ):  mnActDeltaX = +1L, mnActDeltaY = +1L; break;
            case( POINTER_AUTOSCROLL_NE ):  mnActDeltaX = -1L, mnActDeltaY = +1L; break;
            case( POINTER_AUTOSCROLL_SW ):  mnActDeltaX = +1L, mnActDeltaY = -1L; break;
            case( POINTER_AUTOSCROLL_SE ):  mnActDeltaX = -1L, mnActDeltaY = -1L; break;

            default:
            break;
        }
    }

    ImplRecalcScrollValues();
    maLastMousePos = aMousePos;
    SetPointer( eActStyle );

    if( bHorz && bVert )
        ImplSetWheelMode( bOuter ? WHEELMODE_SCROLL_VH : WHEELMODE_VH );
    else if( bHorz )
        ImplSetWheelMode( bOuter ? WHEELMODE_SCROLL_H : WHEELMODE_H );
    else
        ImplSetWheelMode( bOuter ? WHEELMODE_SCROLL_V : WHEELMODE_V );
}

// ------------------------------------------------------------------------

void ImplWheelWindow::MouseButtonUp( const MouseEvent& rMEvt )
{
    if( mnActDist > WHEEL_RADIUS )
        GetParent()->EndAutoScroll();
    else
        FloatingWindow::MouseButtonUp( rMEvt );
}

// ------------------------------------------------------------------------

IMPL_LINK( ImplWheelWindow, ImplScrollHdl, Timer*, EMPTYARG )
{
    if ( mnActDeltaX || mnActDeltaY )
    {
        Window*             pWindow = GetParent();
        const Point         aMousePos( pWindow->OutputToScreenPixel( pWindow->GetPointerPosPixel() ) );
        Point               aCmdMousePos( pWindow->ImplFrameToOutput( aMousePos ) );
        CommandScrollData   aScrollData( mnActDeltaX, mnActDeltaY );
        CommandEvent        aCEvt( aCmdMousePos, COMMAND_AUTOSCROLL, TRUE, &aScrollData );
        NotifyEvent         aNCmdEvt( EVENT_COMMAND, pWindow, &aCEvt );

        if ( !ImplCallPreNotify( aNCmdEvt ) )
        {
            const ULONG nTime = Time::GetSystemTicks();
            ImplDelData aDel( this );
            pWindow->Command( aCEvt );
            if( aDel.IsDead() )
                return 0;
            mnRepaintTime = Max( Time::GetSystemTicks() - nTime, 1UL );
            ImplRecalcScrollValues();
        }
    }

    if ( mnTimeout != mpTimer->GetTimeout() )
        mpTimer->SetTimeout( mnTimeout );
    mpTimer->Start();

    return 0L;
}
<commit_msg>INTEGRATION: CWS vgbugs07 (1.10.38); FILE MERGED 2007/06/04 13:29:48 vg 1.10.38.1: #i76605# Remove -I .../inc/module hack introduced by hedaburemove01<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: scrwnd.cxx,v $
 *
 *  $Revision: 1.12 $
 *
 *  last change: $Author: hr $ $Date: 2007-06-27 20:32:51 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, 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
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_vcl.hxx"

#include <math.h>
#include <limits.h>

#ifndef _TOOLS_TIME_HXX
#include <tools/time.hxx>
#endif
#include <tools/debug.hxx>

#ifndef _SV_SVIDS_HRC
#include <svids.hrc>
#endif
#ifndef _SV_SVDATA_HXX
#include <vcl/svdata.hxx>
#endif
#ifndef _VCL_TIMER_HXX
#include <vcl/timer.hxx>
#endif
#ifndef _VCL_EVENT_HXX
#include <vcl/event.hxx>
#endif
#ifndef _VCL_SCRWND_HXX
#include <scrwnd.hxx>
#endif

// -----------
// - Defines -
// -----------

#define WHEEL_WIDTH     25
#define WHEEL_RADIUS    ((WHEEL_WIDTH) >> 1 )
#define MAX_TIME        300
#define MIN_TIME        20
#define DEF_TIMEOUT     50

// -------------------
// - ImplWheelWindow -
// -------------------

ImplWheelWindow::ImplWheelWindow( Window* pParent ) :
            FloatingWindow  ( pParent, 0 ),
            mnRepaintTime   ( 1UL ),
            mnTimeout       ( DEF_TIMEOUT ),
            mnWheelMode     ( WHEELMODE_NONE ),
            mnActDist       ( 0UL ),
            mnActDeltaX     ( 0L ),
            mnActDeltaY     ( 0L )
{
    // we need a parent
    DBG_ASSERT( pParent, "ImplWheelWindow::ImplWheelWindow(): Parent not set!" );

    const Size      aSize( pParent->GetOutputSizePixel() );
    const USHORT    nFlags = ImplGetSVData()->maWinData.mnAutoScrollFlags;
    const BOOL      bHorz = ( nFlags & AUTOSCROLL_HORZ ) != 0;
    const BOOL      bVert = ( nFlags & AUTOSCROLL_VERT ) != 0;

    // calculate maximum speed distance
    mnMaxWidth = (ULONG) ( 0.4 * hypot( (double) aSize.Width(), aSize.Height() ) );

    // create wheel window
    SetTitleType( FLOATWIN_TITLE_NONE );
    ImplCreateImageList();
    ResMgr* pResMgr = ImplGetResMgr();
    Bitmap aBmp;
    if( pResMgr )
        aBmp = Bitmap( ResId( SV_RESID_BITMAP_SCROLLMSK, *pResMgr ) );
    ImplSetRegion( aBmp );

    // set wheel mode
    if( bHorz && bVert )
        ImplSetWheelMode( WHEELMODE_VH );
    else if( bHorz )
        ImplSetWheelMode( WHEELMODE_H );
    else
        ImplSetWheelMode( WHEELMODE_V );

    // init timer
    mpTimer = new Timer;
    mpTimer->SetTimeoutHdl( LINK( this, ImplWheelWindow, ImplScrollHdl ) );
    mpTimer->SetTimeout( mnTimeout );
    mpTimer->Start();

    CaptureMouse();
}

// ------------------------------------------------------------------------

ImplWheelWindow::~ImplWheelWindow()
{
    ImplStop();
    delete mpTimer;
}

// ------------------------------------------------------------------------

void ImplWheelWindow::ImplStop()
{
    ReleaseMouse();
    mpTimer->Stop();
    Show(FALSE);
}

// ------------------------------------------------------------------------

void ImplWheelWindow::ImplSetRegion( const Bitmap& rRegionBmp )
{
    Point           aPos( GetPointerPosPixel() );
    const Size      aSize( rRegionBmp.GetSizePixel() );
    Point           aPoint;
    const Rectangle aRect( aPoint, aSize );

    maCenter = maLastMousePos = aPos;
    aPos.X() -= aSize.Width() >> 1;
    aPos.Y() -= aSize.Height() >> 1;

    SetPosSizePixel( aPos, aSize );
    SetWindowRegionPixel( rRegionBmp.CreateRegion( COL_BLACK, aRect ) );
}

// ------------------------------------------------------------------------

void ImplWheelWindow::ImplCreateImageList()
{
    ResMgr* pResMgr = ImplGetResMgr();
    if( pResMgr )
        maImgList.InsertFromHorizontalBitmap
            ( ResId( SV_RESID_BITMAP_SCROLLBMP, *pResMgr ), 6, NULL );
}

// ------------------------------------------------------------------------

void ImplWheelWindow::ImplSetWheelMode( ULONG nWheelMode )
{
    if( nWheelMode != mnWheelMode )
    {
        mnWheelMode = nWheelMode;

        if( WHEELMODE_NONE == mnWheelMode )
        {
            if( IsVisible() )
                Hide();
        }
        else
        {
            if( !IsVisible() )
                Show();

            ImplDrawWheel();
        }
    }
}

// ------------------------------------------------------------------------

void ImplWheelWindow::ImplDrawWheel()
{
    USHORT nId;

    switch( mnWheelMode )
    {
        case( WHEELMODE_VH ):       nId = 1; break;
        case( WHEELMODE_V    ):     nId = 2; break;
        case( WHEELMODE_H    ):     nId = 3; break;
        case( WHEELMODE_SCROLL_VH ):nId = 4; break;
        case( WHEELMODE_SCROLL_V ): nId = 5; break;
        case( WHEELMODE_SCROLL_H ): nId = 6; break;
        default:                    nId = 0; break;
    }

    if( nId )
        DrawImage( Point(), maImgList.GetImage( nId ) );
}

// ------------------------------------------------------------------------

void ImplWheelWindow::ImplRecalcScrollValues()
{
    if( mnActDist < WHEEL_RADIUS )
    {
        mnActDeltaX = mnActDeltaY = 0L;
        mnTimeout = DEF_TIMEOUT;
    }
    else
    {
        ULONG nCurTime;

        // calc current time
        if( mnMaxWidth )
        {
            const double fExp = ( (double) mnActDist / mnMaxWidth ) * log10( (double) MAX_TIME / MIN_TIME );
            nCurTime = (ULONG) ( MAX_TIME / pow( 10., fExp ) );
        }
        else
            nCurTime = MAX_TIME;

        if( !nCurTime )
            nCurTime = 1UL;

        if( mnRepaintTime <= nCurTime )
            mnTimeout = nCurTime - mnRepaintTime;
        else
        {
            long nMult = mnRepaintTime / nCurTime;

            if( !( mnRepaintTime % nCurTime ) )
                mnTimeout = 0UL;
            else
                mnTimeout = ++nMult * nCurTime - mnRepaintTime;

            double fValX = (double) mnActDeltaX * nMult;
            double fValY = (double) mnActDeltaY * nMult;

            if( fValX > LONG_MAX )
                mnActDeltaX = LONG_MAX;
            else if( fValX < LONG_MIN )
                mnActDeltaX = LONG_MIN;
            else
                mnActDeltaX = (long) fValX;

            if( fValY > LONG_MAX )
                mnActDeltaY = LONG_MAX;
            else if( fValY < LONG_MIN )
                mnActDeltaY = LONG_MIN;
            else
                mnActDeltaY = (long) fValY;
        }
    }
}

// ------------------------------------------------------------------------

PointerStyle ImplWheelWindow::ImplGetMousePointer( long nDistX, long nDistY )
{
    PointerStyle    eStyle;
    const USHORT    nFlags = ImplGetSVData()->maWinData.mnAutoScrollFlags;
    const BOOL      bHorz = ( nFlags & AUTOSCROLL_HORZ ) != 0;
    const BOOL      bVert = ( nFlags & AUTOSCROLL_VERT ) != 0;

    if( bHorz || bVert )
    {
        if( mnActDist < WHEEL_RADIUS )
        {
            if( bHorz && bVert )
                eStyle = POINTER_AUTOSCROLL_NSWE;
            else if( bHorz )
                eStyle = POINTER_AUTOSCROLL_WE;
            else
                eStyle = POINTER_AUTOSCROLL_NS;
        }
        else
        {
            double fAngle = atan2( (double) -nDistY, nDistX ) / F_PI180;

            if( fAngle < 0.0 )
                fAngle += 360.;

            if( bHorz && bVert )
            {
                if( fAngle >= 22.5 && fAngle <= 67.5 )
                    eStyle = POINTER_AUTOSCROLL_NE;
                else if( fAngle >= 67.5 && fAngle <= 112.5 )
                    eStyle = POINTER_AUTOSCROLL_N;
                else if( fAngle >= 112.5 && fAngle <= 157.5 )
                    eStyle = POINTER_AUTOSCROLL_NW;
                else if( fAngle >= 157.5 && fAngle <= 202.5 )
                    eStyle = POINTER_AUTOSCROLL_W;
                else if( fAngle >= 202.5 && fAngle <= 247.5 )
                    eStyle = POINTER_AUTOSCROLL_SW;
                else if( fAngle >= 247.5 && fAngle <= 292.5 )
                    eStyle = POINTER_AUTOSCROLL_S;
                else if( fAngle >= 292.5 && fAngle <= 337.5 )
                    eStyle = POINTER_AUTOSCROLL_SE;
                else
                    eStyle = POINTER_AUTOSCROLL_E;
            }
            else if( bHorz )
            {
                if( fAngle >= 270. || fAngle <= 90. )
                    eStyle = POINTER_AUTOSCROLL_E;
                else
                    eStyle = POINTER_AUTOSCROLL_W;
            }
            else
            {
                if( fAngle >= 0. && fAngle <= 180. )
                    eStyle = POINTER_AUTOSCROLL_N;
                else
                    eStyle = POINTER_AUTOSCROLL_S;
            }
        }
    }
    else
        eStyle = POINTER_ARROW;

    return eStyle;
}

// ------------------------------------------------------------------------

void ImplWheelWindow::Paint( const Rectangle& )
{
    ImplDrawWheel();
}

// ------------------------------------------------------------------------

void ImplWheelWindow::MouseMove( const MouseEvent& rMEvt )
{
    FloatingWindow::MouseMove( rMEvt );

    const Point aMousePos( OutputToScreenPixel( rMEvt.GetPosPixel() ) );
    const long  nDistX = aMousePos.X() - maCenter.X();
    const long  nDistY = aMousePos.Y() - maCenter.Y();

    mnActDist = (ULONG) hypot( (double) nDistX, nDistY );

    const PointerStyle  eActStyle = ImplGetMousePointer( nDistX, nDistY );
    const USHORT        nFlags = ImplGetSVData()->maWinData.mnAutoScrollFlags;
    const BOOL          bHorz = ( nFlags & AUTOSCROLL_HORZ ) != 0;
    const BOOL          bVert = ( nFlags & AUTOSCROLL_VERT ) != 0;
    const BOOL          bOuter = mnActDist > WHEEL_RADIUS;

    if( bOuter && ( maLastMousePos != aMousePos ) )
    {
        switch( eActStyle )
        {
            case( POINTER_AUTOSCROLL_N ):   mnActDeltaX = +0L, mnActDeltaY = +1L; break;
            case( POINTER_AUTOSCROLL_S ):   mnActDeltaX = +0L, mnActDeltaY = -1L; break;
            case( POINTER_AUTOSCROLL_W ):   mnActDeltaX = +1L, mnActDeltaY = +0L; break;
            case( POINTER_AUTOSCROLL_E ):   mnActDeltaX = -1L, mnActDeltaY = +0L; break;
            case( POINTER_AUTOSCROLL_NW ):  mnActDeltaX = +1L, mnActDeltaY = +1L; break;
            case( POINTER_AUTOSCROLL_NE ):  mnActDeltaX = -1L, mnActDeltaY = +1L; break;
            case( POINTER_AUTOSCROLL_SW ):  mnActDeltaX = +1L, mnActDeltaY = -1L; break;
            case( POINTER_AUTOSCROLL_SE ):  mnActDeltaX = -1L, mnActDeltaY = -1L; break;

            default:
            break;
        }
    }

    ImplRecalcScrollValues();
    maLastMousePos = aMousePos;
    SetPointer( eActStyle );

    if( bHorz && bVert )
        ImplSetWheelMode( bOuter ? WHEELMODE_SCROLL_VH : WHEELMODE_VH );
    else if( bHorz )
        ImplSetWheelMode( bOuter ? WHEELMODE_SCROLL_H : WHEELMODE_H );
    else
        ImplSetWheelMode( bOuter ? WHEELMODE_SCROLL_V : WHEELMODE_V );
}

// ------------------------------------------------------------------------

void ImplWheelWindow::MouseButtonUp( const MouseEvent& rMEvt )
{
    if( mnActDist > WHEEL_RADIUS )
        GetParent()->EndAutoScroll();
    else
        FloatingWindow::MouseButtonUp( rMEvt );
}

// ------------------------------------------------------------------------

IMPL_LINK( ImplWheelWindow, ImplScrollHdl, Timer*, EMPTYARG )
{
    if ( mnActDeltaX || mnActDeltaY )
    {
        Window*             pWindow = GetParent();
        const Point         aMousePos( pWindow->OutputToScreenPixel( pWindow->GetPointerPosPixel() ) );
        Point               aCmdMousePos( pWindow->ImplFrameToOutput( aMousePos ) );
        CommandScrollData   aScrollData( mnActDeltaX, mnActDeltaY );
        CommandEvent        aCEvt( aCmdMousePos, COMMAND_AUTOSCROLL, TRUE, &aScrollData );
        NotifyEvent         aNCmdEvt( EVENT_COMMAND, pWindow, &aCEvt );

        if ( !ImplCallPreNotify( aNCmdEvt ) )
        {
            const ULONG nTime = Time::GetSystemTicks();
            ImplDelData aDel( this );
            pWindow->Command( aCEvt );
            if( aDel.IsDead() )
                return 0;
            mnRepaintTime = Max( Time::GetSystemTicks() - nTime, 1UL );
            ImplRecalcScrollValues();
        }
    }

    if ( mnTimeout != mpTimer->GetTimeout() )
        mpTimer->SetTimeout( mnTimeout );
    mpTimer->Start();

    return 0L;
}
<|endoftext|>


<commit_before>/** @file
    @brief Produces a distortion polynomial and partial display description
           from a table of display locations to angle inputs.

    @date 2019

    @author
    Russ Taylor working through ReliaSolve.com for ValitXR.
*/

// Copyright 2019 ValityXR.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Standard includes
#include <string>
#include <iostream>
#include <iomanip>
#include <fstream>
#include <cmath>
#include <vector>
#include <stdlib.h> // For exit()

// Local includes
#include "types.h"

// Global constants and variables
static bool g_verbose = false;
static double MY_PI = (4.0*atan(1.0));

// Forward declarations
static int testAlgorithms();

static void writePolynomial(std::ostream &s, std::vector<double> const &poly)
{
  s << "[";
  for (size_t i = 0; i < poly.size(); i++) {
    if (i == 0) { s << " "; }
    else { s << ","; }
    s << std::setprecision(4) << poly[i];
  }
}

/// @brief Evaluate the coefficients with both radius and vector in meters.
/// @return Angle in Radians associated with radial point.
static double evaluateAngleRadians(double r, std::vector<double> const &coefs)
{
  double ret = 0;
  for (size_t i = 0; i < coefs.size(); i++) {
    ret += coefs[i] * pow(r, 1 + 2 * i);
  }
  return atan(ret);
}

/// @brief Determine the OSVR equivalent FOV for an axis.
/// @param left Left side of the display (or Bottom) (at depth)
/// @param right Right side of the display (or Top) (at depth)
/// @param depth Perpendicular distance to the screen
static double computeFOVDegrees(double left, double right, double depth)
{
  // Find half of the width of the axis, because we need to compute
  // the FOV as if we were centered.
  double halfWidth = fabs((right - left) / 2);

  // Find twice the angle to that point at the specified depth
  double rad = 2 * atan2(halfWidth, depth);

  // Convert to Radians
  return 180 / MY_PI * rad;
}

void Usage(std::string name)
{
  std::cerr << "Usage: " << name
    << " [-eye right|left] (default is right)"
    << " [-depth_meters D] (default is 2.0)"
    << " [-verbose] (default is not)"
    << " display_size"
    << " C1 [C3 [C5 [...]]"
    << std::endl
    << "  This program solves for the polynomial distortion correction that will correct for" << std::endl
    << "the screen-to-angle mapping described in the coefficients.  The first-order term C1" << std::endl
    << "must be specified, and other higher odd-numbered terms may also be specified (C3, C5, ...)" << std::endl
    << "The coefficents are from the equation tan(theta) = C1*r + C3*r^3 + C5*r^5 + ..." << std::endl
    << "  The input r for the mapping is in millimeters." << std::endl
    << "  The output of the mapping is the tangent of the angle towards the visible point" << std::endl
    << "  The size of the display is specified in millimeters and must be the." << std::endl
    << "same for both width and height until the code is generalized." << std::endl
    << std::endl;
  exit(1);
}

int main(int argc, char *argv[])
{
  // Parse the command line
  std::vector<std::string> inputFileNames;
  bool useRightEye = true;
  double left, right, bottom, top;
  std::vector<double> coeffs;
  double depth = 2.0;
  int realParams = 0;
  for (int i = 1; i < argc; i++) {
    if (std::string("-verbose") == argv[i]) {
      g_verbose = true;
    } else if (std::string("-depth_meters") == argv[i]) {
      if (++i >= argc) { Usage(argv[0]); }
      depth = atof(argv[i]);
    } else if (std::string("-eye") == argv[i]) {
      if (++i >= argc) { Usage(argv[0]); }
      std::string eye = argv[i];
      if (eye == "left") {
        useRightEye = false;
      } else if (eye == "right") {
        useRightEye = true;
      } else {
        std::cerr << "Bad value for -eye: " << eye << ", expected left or right" << std::endl;
        Usage(argv[0]);
      }
    } else if ((argv[i][0] == '-') && (atof(argv[i]) == 0.0)) {
      Usage(argv[0]);
    } else switch (++realParams) {
    case 1:
      right = top = atof(argv[i])/2;
      left = bottom = -right;
      break;
    default:
      // We got another coefficient, so put it onto the list after scaling it.
      coeffs.push_back(atof(argv[i]));
    }
  }
  if (realParams < 5) { Usage(argv[0]); }

  //====================================================================
  // Ensure that our parameters are not more general than we can handle.

  //====================================================================
  // Run our algorithm test to make sure things are working properly.
  int ret;
  if ((ret = testAlgorithms()) != 0) {
    std::cerr << "Error testing basic algorithms, code " << ret << std::endl;
    return 100;
  }

  //====================================================================
  // The output screens and polynomial.
  ScreenDescription leftScreen, rightScreen;
  std::vector<double> polynomial;

  //====================================================================
  // Compute left and right screen boundaries that are mirror images
  // of each other.
  // Compute the boundaries of the screen based on the depth and the maximum
  // angles in +/- X and Y projected to that distance.  These need to be
  // projected from the display space into the distance that the screen
  // lies at.
  double leftAngle = evaluateAngleRadians(left, coeffs);
  double rightAngle = evaluateAngleRadians(right, coeffs);
  double topAngle = evaluateAngleRadians(top, coeffs);
  double bottomAngle = evaluateAngleRadians(bottom, coeffs);
  if (g_verbose) {
    std::cout << "leftAngle (degrees): " << leftAngle * 180 / MY_PI << std::endl;
    std::cout << "rightAngle (degrees): " << rightAngle * 180 / MY_PI << std::endl;
    std::cout << "bottomAngle (degrees): " << bottomAngle * 180 / MY_PI << std::endl;
    std::cout << "topAngle (degrees): " << topAngle * 180 / MY_PI << std::endl;
  }
  double leftScreenLeft, leftScreenRight, leftScreenBottom, leftScreenTop;
  double rightScreenLeft, rightScreenRight, rightScreenBottom, rightScreenTop;
  rightScreenBottom = leftScreenBottom = depth * tan(bottomAngle);
  rightScreenTop = leftScreenTop = depth * tan(topAngle);
  if (useRightEye) {
    rightScreenLeft = depth * tan(leftAngle);
    rightScreenRight = depth * tan(rightAngle);

    leftScreenLeft = -depth * tan(rightAngle);
    leftScreenRight = -depth * tan(leftAngle);
  } else {
    leftScreenLeft = depth * tan(leftAngle);
    leftScreenRight = depth * tan(rightAngle);

    rightScreenLeft = -depth * tan(rightAngle);
    rightScreenRight = -depth * tan(leftAngle);
  }
  if (g_verbose) {
    std::cout << "rightScreenLeft: " << rightScreenLeft << std::endl;
    std::cout << "rightScreenRight: " << rightScreenRight << std::endl;
    std::cout << "rightScreenBottom: " << rightScreenBottom << std::endl;
    std::cout << "rightScreenTop: " << rightScreenTop << std::endl;
  }

  //====================================================================
  // Convert the screen boundaries into the OSVR description format.
  leftScreen.xCOP = (0 - leftScreenLeft) / (leftScreenRight - leftScreenLeft);
  leftScreen.yCOP = (0 - leftScreenBottom) / (leftScreenTop - leftScreenBottom);
  leftScreen.overlapPercent = 100; /// @todo Consider generalizing
  leftScreen.hFOVDegrees = computeFOVDegrees(leftScreenLeft, leftScreenRight, depth);
  leftScreen.vFOVDegrees = computeFOVDegrees(leftScreenBottom, leftScreenTop, depth);

  rightScreen.xCOP = (0 - rightScreenLeft) / (rightScreenRight - rightScreenLeft);
  rightScreen.yCOP = (0 - rightScreenBottom) / (rightScreenTop - rightScreenBottom);
  rightScreen.overlapPercent = 100; /// @todo Consider generalizing
  rightScreen.hFOVDegrees = computeFOVDegrees(rightScreenLeft, rightScreenRight, depth);
  rightScreen.vFOVDegrees = computeFOVDegrees(rightScreenBottom, rightScreenTop, depth);

  if (g_verbose) {
    std::cout << "hFOV (degrees): " << rightScreen.hFOVDegrees << std::endl;
    std::cout << "vFOV (degrees): " << rightScreen.vFOVDegrees << std::endl;
  }

  //====================================================================
  // Compute a polynomial that will map from the linear, rendered canonical
  // image to the correct location that matches that viewing angle when seen
  // through HMD lens.  It will leave points at the center of projection
  // at the same location and should map a point at the furthest location on
  // the same vertical or horizontal screen to the same location (if the
  // screen is centered, this will be points on the horizontal and vertical
  // centers of the edges).

  // The coefficients provide a mapping from radial distance in millimeters
  // away from the center of projection to the tangent of the angle at which
  // the point will appear.  OSVR wants a polynomial that moves points from
  // an initial location in a space to an offset location in that same space.
  //   The tangent space is scaled differently than the pixel space, so we
  // need to transform the coefficients so that they are not.
  //   We are free to choose either space (or another one entirely), so long
  // as the distance metrics match.
  //   We choose to scale the input space to match the output tangent space
  // in a manner that will map the furthest input pixel to the furthest tangent,
  // which means that we need to convert the input units to tangent space by
  // multiplying them by tangent_range/mm_range.
  //   This basically means that we need to scale the polynomial coefficients
  // by this inverse of this factor raised to the power that they are applying
  // so that they will do the conversion for us.
  double units = (left - right) / (tan(leftAngle) - tan(rightAngle));

  // This means that the coefficients are providing us the correct mapping,
  // but we need to convert them into the appropriate distance scale an put
  // them into the appropriate coefficients.  The appropriate coefficients
  // are the 1st, 3rd, and so forth.  We skip all even coefficients.
  // Always push back 0 for the 0th-order term.
  polynomial.push_back(0);
  for (size_t i = 0; i < coeffs.size(); i++) {
    // Zero all even terms.  We already zeroed the 0th-order term
    if (i > 0) { polynomial.push_back(0); }
    // Scale by the units conversion.
    polynomial.push_back(coeffs[i] * pow(units,1 + 2 * i));
  }
  // Set the distance units to twice the distance from the center of
  // the display to the farthest direction so that the point at the center
  // of the furthest edge will map to itself.  This is in the tangent
  // space.
  // (For the square case, this is just twice the right edge.)
  double distance_scale = 2*tan(rightAngle);

  /// @todo Generalize for non-square, non-centered displays.  In that
  // case, we want the farthest edge from the center to map to itself and
  // the other edges will overfill to some extent.

  // Determine the longest distance from the center of projection to an
  // edge in millimeters.
  /*
  double maxEdge = fabs(left);
  maxEdge = std::max(maxEdge, fabs(right));
  maxEdge = std::max(maxEdge, fabs(bottom));
  maxEdge = std::max(maxEdge, fabs(top));
  */

  //====================================================================
  // Construct Json screen description.
  // We do this by hand rather than using JsonCPP because we want
  // to control the printed precision of the numbers to avoid making
  // a huge file.
  std::cout << "{" << std::endl;
  std::cout << " \"display\": {" << std::endl;
  std::cout << "  \"hmd\": {" << std::endl;

  std::cout << "   \"field_of_view\": {" << std::endl;
  std::cout << "    \"monocular_horizontal\": "
    << rightScreen.hFOVDegrees
    << "," << std::endl;
  std::cout << "    \"monocular_vertical\": "
    << rightScreen.vFOVDegrees
    << "," << std::endl;
  std::cout << "    \"overlap_percent\": "
    << rightScreen.overlapPercent
    << "," << std::endl;
  std::cout << "    \"pitch_tilt\": 0" << std::endl;
  std::cout << "   }," << std::endl; // field_of_view

  std::cout << "   \"distortion\": {" << std::endl;
  std::cout << "     \"distance_scale_x\": " << distance_scale << "," << std::endl;
  std::cout << "     \"distance_scale_y\": " << distance_scale << "," << std::endl;
  std::cout << "     \"polynomial_coeffs_red\": ";
    writePolynomial(std::cout, polynomial);
  std::cout << " ]," << std::endl;
  std::cout << "     \"polynomial_coeffs_green\": ";
  writePolynomial(std::cout, polynomial);
  std::cout << " ]," << std::endl;
  std::cout << "     \"polynomial_coeffs_blue\": ";
  writePolynomial(std::cout, polynomial);
  std::cout << " ]" << std::endl;
  std::cout << "   }," << std::endl; // distortion

  std::cout << "   \"eyes\": [" << std::endl;
  std::cout << "    {" << std::endl;
  std::cout << "     \"center_proj_x\": "
    << leftScreen.xCOP
    << "," << std::endl;
  std::cout << "     \"center_proj_y\": "
    << leftScreen.yCOP
    << "," << std::endl;
  std::cout << "     \"rotate_180\": 0" << std::endl;
  std::cout << "    }," << std::endl;
  std::cout << "    {" << std::endl;
  std::cout << "     \"center_proj_x\": "
    << rightScreen.xCOP
    << "," << std::endl;
  std::cout << "     \"center_proj_y\": "
    << rightScreen.yCOP
    << "," << std::endl;
  std::cout << "     \"rotate_180\": 0" << std::endl;
  std::cout << "    }" << std::endl;
  std::cout << "   ]" << std::endl; // eyes

  std::cout << "  }" << std::endl;  // hmd
  std::cout << " }" << std::endl;   // display
  std::cout << "}" << std::endl;    // Closes outer object

  return 0;
}

static bool small(double d)
{
  return fabs(d) <= 1e-5;
}

static int testAlgorithms()
{
  if (g_verbose) {
    std::cerr << "=================== Starting testAlgorithms()" << std::endl;
  }

  // @todo
  std::cerr << "Warning: Test not yet implemented" << std::endl;

  if (g_verbose) {
    std::cerr << "=================== Successfully finished testAlgorithms()" << std::endl;
  }
  return 0;
}
<commit_msg>Making function emit closing brace along with opening brace.<commit_after>/** @file
    @brief Produces a distortion polynomial and partial display description
           from a table of display locations to angle inputs.

    @date 2019

    @author
    Russ Taylor working through ReliaSolve.com for ValitXR.
*/

// Copyright 2019 ValityXR.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Standard includes
#include <string>
#include <iostream>
#include <iomanip>
#include <fstream>
#include <cmath>
#include <vector>
#include <stdlib.h> // For exit()

// Local includes
#include "types.h"

// Global constants and variables
static bool g_verbose = false;
static double MY_PI = (4.0*atan(1.0));

// Forward declarations
static int testAlgorithms();

static void writePolynomial(std::ostream &s, std::vector<double> const &poly)
{
  s << "[";
  for (size_t i = 0; i < poly.size(); i++) {
    if (i == 0) { s << " "; }
    else { s << ","; }
    s << std::setprecision(4) << poly[i];
  }
  std::cout << " ]";
}

/// @brief Evaluate the coefficients with both radius and vector in meters.
/// @return Angle in Radians associated with radial point.
static double evaluateAngleRadians(double r, std::vector<double> const &coefs)
{
  double ret = 0;
  for (size_t i = 0; i < coefs.size(); i++) {
    ret += coefs[i] * pow(r, 1 + 2 * i);
  }
  return atan(ret);
}

/// @brief Determine the OSVR equivalent FOV for an axis.
/// @param left Left side of the display (or Bottom) (at depth)
/// @param right Right side of the display (or Top) (at depth)
/// @param depth Perpendicular distance to the screen
static double computeFOVDegrees(double left, double right, double depth)
{
  // Find half of the width of the axis, because we need to compute
  // the FOV as if we were centered.
  double halfWidth = fabs((right - left) / 2);

  // Find twice the angle to that point at the specified depth
  double rad = 2 * atan2(halfWidth, depth);

  // Convert to Radians
  return 180 / MY_PI * rad;
}

void Usage(std::string name)
{
  std::cerr << "Usage: " << name
    << " [-eye right|left] (default is right)"
    << " [-depth_meters D] (default is 2.0)"
    << " [-verbose] (default is not)"
    << " display_size"
    << " C1 [C3 [C5 [...]]"
    << std::endl
    << "  This program solves for the polynomial distortion correction that will correct for" << std::endl
    << "the screen-to-angle mapping described in the coefficients.  The first-order term C1" << std::endl
    << "must be specified, and other higher odd-numbered terms may also be specified (C3, C5, ...)" << std::endl
    << "The coefficents are from the equation tan(theta) = C1*r + C3*r^3 + C5*r^5 + ..." << std::endl
    << "  The input r for the mapping is in millimeters." << std::endl
    << "  The output of the mapping is the tangent of the angle towards the visible point" << std::endl
    << "  The size of the display is specified in millimeters and must be the." << std::endl
    << "same for both width and height until the code is generalized." << std::endl
    << std::endl;
  exit(1);
}

int main(int argc, char *argv[])
{
  // Parse the command line
  std::vector<std::string> inputFileNames;
  bool useRightEye = true;
  double left, right, bottom, top;
  std::vector<double> coeffs;
  double depth = 2.0;
  int realParams = 0;
  for (int i = 1; i < argc; i++) {
    if (std::string("-verbose") == argv[i]) {
      g_verbose = true;
    } else if (std::string("-depth_meters") == argv[i]) {
      if (++i >= argc) { Usage(argv[0]); }
      depth = atof(argv[i]);
    } else if (std::string("-eye") == argv[i]) {
      if (++i >= argc) { Usage(argv[0]); }
      std::string eye = argv[i];
      if (eye == "left") {
        useRightEye = false;
      } else if (eye == "right") {
        useRightEye = true;
      } else {
        std::cerr << "Bad value for -eye: " << eye << ", expected left or right" << std::endl;
        Usage(argv[0]);
      }
    } else if ((argv[i][0] == '-') && (atof(argv[i]) == 0.0)) {
      Usage(argv[0]);
    } else switch (++realParams) {
    case 1:
      right = top = atof(argv[i])/2;
      left = bottom = -right;
      break;
    default:
      // We got another coefficient, so put it onto the list after scaling it.
      coeffs.push_back(atof(argv[i]));
    }
  }
  if (realParams < 5) { Usage(argv[0]); }

  //====================================================================
  // Ensure that our parameters are not more general than we can handle.

  //====================================================================
  // Run our algorithm test to make sure things are working properly.
  int ret;
  if ((ret = testAlgorithms()) != 0) {
    std::cerr << "Error testing basic algorithms, code " << ret << std::endl;
    return 100;
  }

  //====================================================================
  // The output screens and polynomial.
  ScreenDescription leftScreen, rightScreen;
  std::vector<double> polynomial;

  //====================================================================
  // Compute left and right screen boundaries that are mirror images
  // of each other.
  // Compute the boundaries of the screen based on the depth and the maximum
  // angles in +/- X and Y projected to that distance.  These need to be
  // projected from the display space into the distance that the screen
  // lies at.
  double leftAngle = evaluateAngleRadians(left, coeffs);
  double rightAngle = evaluateAngleRadians(right, coeffs);
  double topAngle = evaluateAngleRadians(top, coeffs);
  double bottomAngle = evaluateAngleRadians(bottom, coeffs);
  if (g_verbose) {
    std::cout << "leftAngle (degrees): " << leftAngle * 180 / MY_PI << std::endl;
    std::cout << "rightAngle (degrees): " << rightAngle * 180 / MY_PI << std::endl;
    std::cout << "bottomAngle (degrees): " << bottomAngle * 180 / MY_PI << std::endl;
    std::cout << "topAngle (degrees): " << topAngle * 180 / MY_PI << std::endl;
  }
  double leftScreenLeft, leftScreenRight, leftScreenBottom, leftScreenTop;
  double rightScreenLeft, rightScreenRight, rightScreenBottom, rightScreenTop;
  rightScreenBottom = leftScreenBottom = depth * tan(bottomAngle);
  rightScreenTop = leftScreenTop = depth * tan(topAngle);
  if (useRightEye) {
    rightScreenLeft = depth * tan(leftAngle);
    rightScreenRight = depth * tan(rightAngle);

    leftScreenLeft = -depth * tan(rightAngle);
    leftScreenRight = -depth * tan(leftAngle);
  } else {
    leftScreenLeft = depth * tan(leftAngle);
    leftScreenRight = depth * tan(rightAngle);

    rightScreenLeft = -depth * tan(rightAngle);
    rightScreenRight = -depth * tan(leftAngle);
  }
  if (g_verbose) {
    std::cout << "rightScreenLeft: " << rightScreenLeft << std::endl;
    std::cout << "rightScreenRight: " << rightScreenRight << std::endl;
    std::cout << "rightScreenBottom: " << rightScreenBottom << std::endl;
    std::cout << "rightScreenTop: " << rightScreenTop << std::endl;
  }

  //====================================================================
  // Convert the screen boundaries into the OSVR description format.
  leftScreen.xCOP = (0 - leftScreenLeft) / (leftScreenRight - leftScreenLeft);
  leftScreen.yCOP = (0 - leftScreenBottom) / (leftScreenTop - leftScreenBottom);
  leftScreen.overlapPercent = 100; /// @todo Consider generalizing
  leftScreen.hFOVDegrees = computeFOVDegrees(leftScreenLeft, leftScreenRight, depth);
  leftScreen.vFOVDegrees = computeFOVDegrees(leftScreenBottom, leftScreenTop, depth);

  rightScreen.xCOP = (0 - rightScreenLeft) / (rightScreenRight - rightScreenLeft);
  rightScreen.yCOP = (0 - rightScreenBottom) / (rightScreenTop - rightScreenBottom);
  rightScreen.overlapPercent = 100; /// @todo Consider generalizing
  rightScreen.hFOVDegrees = computeFOVDegrees(rightScreenLeft, rightScreenRight, depth);
  rightScreen.vFOVDegrees = computeFOVDegrees(rightScreenBottom, rightScreenTop, depth);

  if (g_verbose) {
    std::cout << "hFOV (degrees): " << rightScreen.hFOVDegrees << std::endl;
    std::cout << "vFOV (degrees): " << rightScreen.vFOVDegrees << std::endl;
  }

  //====================================================================
  // Compute a polynomial that will map from the linear, rendered canonical
  // image to the correct location that matches that viewing angle when seen
  // through HMD lens.  It will leave points at the center of projection
  // at the same location and should map a point at the furthest location on
  // the same vertical or horizontal screen to the same location (if the
  // screen is centered, this will be points on the horizontal and vertical
  // centers of the edges).

  // The coefficients provide a mapping from radial distance in millimeters
  // away from the center of projection to the tangent of the angle at which
  // the point will appear.  OSVR wants a polynomial that moves points from
  // an initial location in a space to an offset location in that same space.
  //   The tangent space is scaled differently than the pixel space, so we
  // need to transform the coefficients so that they are not.
  //   We are free to choose either space (or another one entirely), so long
  // as the distance metrics match.
  //   We choose to scale the input space to match the output tangent space
  // in a manner that will map the furthest input pixel to the furthest tangent,
  // which means that we need to convert the input units to tangent space by
  // multiplying them by tangent_range/mm_range.
  //   This basically means that we need to scale the polynomial coefficients
  // by this inverse of this factor raised to the power that they are applying
  // so that they will do the conversion for us.
  double units = (left - right) / (tan(leftAngle) - tan(rightAngle));

  // This means that the coefficients are providing us the correct mapping,
  // but we need to convert them into the appropriate distance scale an put
  // them into the appropriate coefficients.  The appropriate coefficients
  // are the 1st, 3rd, and so forth.  We skip all even coefficients.
  // Always push back 0 for the 0th-order term.
  polynomial.push_back(0);
  for (size_t i = 0; i < coeffs.size(); i++) {
    // Zero all even terms.  We already zeroed the 0th-order term
    if (i > 0) { polynomial.push_back(0); }
    // Scale by the units conversion.
    polynomial.push_back(coeffs[i] * pow(units,1 + 2 * i));
  }
  // Set the distance units to twice the distance from the center of
  // the display to the farthest direction so that the point at the center
  // of the furthest edge will map to itself.  This is in the tangent
  // space.
  // (For the square case, this is just twice the right edge.)
  double distance_scale = 2*tan(rightAngle);

  /// @todo Generalize for non-square, non-centered displays.  In that
  // case, we want the farthest edge from the center to map to itself and
  // the other edges will overfill to some extent.

  // Determine the longest distance from the center of projection to an
  // edge in millimeters.
  /*
  double maxEdge = fabs(left);
  maxEdge = std::max(maxEdge, fabs(right));
  maxEdge = std::max(maxEdge, fabs(bottom));
  maxEdge = std::max(maxEdge, fabs(top));
  */

  //====================================================================
  // Construct Json screen description.
  // We do this by hand rather than using JsonCPP because we want
  // to control the printed precision of the numbers to avoid making
  // a huge file.
  std::cout << "{" << std::endl;
  std::cout << " \"display\": {" << std::endl;
  std::cout << "  \"hmd\": {" << std::endl;

  std::cout << "   \"field_of_view\": {" << std::endl;
  std::cout << "    \"monocular_horizontal\": "
    << rightScreen.hFOVDegrees
    << "," << std::endl;
  std::cout << "    \"monocular_vertical\": "
    << rightScreen.vFOVDegrees
    << "," << std::endl;
  std::cout << "    \"overlap_percent\": "
    << rightScreen.overlapPercent
    << "," << std::endl;
  std::cout << "    \"pitch_tilt\": 0" << std::endl;
  std::cout << "   }," << std::endl; // field_of_view

  std::cout << "   \"distortion\": {" << std::endl;
  std::cout << "     \"distance_scale_x\": " << distance_scale << "," << std::endl;
  std::cout << "     \"distance_scale_y\": " << distance_scale << "," << std::endl;
  std::cout << "     \"polynomial_coeffs_red\": ";
    writePolynomial(std::cout, polynomial);
  std::cout << "," << std::endl;
  std::cout << "     \"polynomial_coeffs_green\": ";
  writePolynomial(std::cout, polynomial);
  std::cout << "," << std::endl;
  std::cout << "     \"polynomial_coeffs_blue\": ";
  writePolynomial(std::cout, polynomial);
  std::cout << std::endl;
  std::cout << "   }," << std::endl; // distortion

  std::cout << "   \"eyes\": [" << std::endl;
  std::cout << "    {" << std::endl;
  std::cout << "     \"center_proj_x\": "
    << leftScreen.xCOP
    << "," << std::endl;
  std::cout << "     \"center_proj_y\": "
    << leftScreen.yCOP
    << "," << std::endl;
  std::cout << "     \"rotate_180\": 0" << std::endl;
  std::cout << "    }," << std::endl;
  std::cout << "    {" << std::endl;
  std::cout << "     \"center_proj_x\": "
    << rightScreen.xCOP
    << "," << std::endl;
  std::cout << "     \"center_proj_y\": "
    << rightScreen.yCOP
    << "," << std::endl;
  std::cout << "     \"rotate_180\": 0" << std::endl;
  std::cout << "    }" << std::endl;
  std::cout << "   ]" << std::endl; // eyes

  std::cout << "  }" << std::endl;  // hmd
  std::cout << " }" << std::endl;   // display
  std::cout << "}" << std::endl;    // Closes outer object

  return 0;
}

static bool small(double d)
{
  return fabs(d) <= 1e-5;
}

static int testAlgorithms()
{
  if (g_verbose) {
    std::cerr << "=================== Starting testAlgorithms()" << std::endl;
  }

  // @todo
  std::cerr << "Warning: Test not yet implemented" << std::endl;

  if (g_verbose) {
    std::cerr << "=================== Successfully finished testAlgorithms()" << std::endl;
  }
  return 0;
}
<|endoftext|>


<commit_before>// vim:ts=2:sw=2:expandtab:autoindent:filetype=cpp:
/*
The MIT License

Copyright (c) 2008, 2009 Flusspferd contributors (see "CONTRIBUTORS" or
                                       http://flusspferd.org/contributors.txt)

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.
*/

#ifndef FLUSSPFERD_NATIVE_OBJECT_BASE_HPP
#define FLUSSPFERD_NATIVE_OBJECT_BASE_HPP

#include "object.hpp"
#include "convert.hpp"
#include "function_adapter.hpp"
#include <boost/scoped_ptr.hpp>
#include <boost/noncopyable.hpp>
#include <boost/function.hpp>
#include <boost/type_traits/is_base_of.hpp>
#include <boost/type_traits/is_member_function_pointer.hpp>
#include <boost/any.hpp>
#include <memory>
#include <functional>

namespace flusspferd {

#ifndef IN_DOXYGEN
struct call_context;
class tracer;

namespace detail {
  object create_native_object(object const &proto);
  object create_native_enumerable_object(object const &proto);
}
#endif

/**
 * Native object base.
 *
 * @ingroup classes
 */
class native_object_base : public object, private boost::noncopyable {
public:
  /// Destructor.
  virtual ~native_object_base() = 0;

  /**
   * Explicitly return the associated object.
   *
   * @return The associated object.
   */
  object get_object() {
    return *static_cast<object*>(this);
  }

  /**
   * Get the native object associated with a Javascript object.
   *
   * @return A reference to the object.
   */
  static native_object_base &get_native(object const &o);

public:
  /**
   * Associate with an object if there is no association yet.
   *
   * Do not use directly.
   *
   * @param o The object to associate with.
   */
  void load_into(object const &o);

protected:
  /**
   * Constructor.
   *
   * Immediately associates with object @p o.
   *
   * Do not use with arbitrary objects.
   *
   * @param o The object to associate with.
   */
  native_object_base(object const &o);

protected:
  /**
   * Virtual method invoked whenever the object is called as if it were a
   * function.
   *
   * Default implementation: throw an exception.
   *
   * @param x The call context.
   */
  virtual void self_call(call_context &x);

  /**
   * Virtual method invoked whenever the object has to be traced.
   *
   * Default implementation: stub.
   *
   * For each value that is an otherwise unreachable member of the object and
   * that should be protected from garbage collection, call @c trc("x", x).
   * The string "x" does not need to be unique, it's used for debugging
   * purposes only.
   *
   * @code
flusspferd::value v;

...

void trace(flusspferd::tracer &trc) {
    trc("v", v);
}
   @endcode
   *
   * @param trc The tracer to be used.
   *
   * @see @ref gc
   */
  virtual void trace(tracer &trc);

protected:
  /**
   * Possible property access methods. Can be combined by bitwise or.
   */
  enum property_access {
    /**
     * The property access uses the @c . or @c [] operator:
     * @c obj.id or @c obj[id], not @c id.
     */
    property_qualified = 1,

    /**
     * The property appears on the left-hand side of an assignment.
     */
    property_assigning = 2,

    /**
     * The property is being used in code like "if (o.p) ...",
     * or a similar idiom where the apparent purpose of the property access is
     * to detect whether the property exists.
     */
    property_detecting = 4,

    /**
     * The property is being declared in a var, const, or function declaration.
     */
    property_declaring = 8,

    /**
     * class name used when constructing. (???)
     */
    property_classname = 16
  };

  /**
   * Virtual method invoked when a property is not found on an object.
   *
   * Default implementation: stub that returns @c false.
   *
   * It can be used to implement lazy properties.
   *
   * If possible, @p id will be an integer, or a string otherwise.
   *
   * @param id The property name / index.
   * @param access Information about the kind of property access. A combination
   *           of #property_access values.
   */
  virtual bool property_resolve(value const &id, unsigned access);

  /**
   * Virtual method invoked to start enumerating properties.
   *
   * Will be called only if class_info::custom_enumerate is activated.
   *
   * Default implementation: return boost::any().
   *
   * @param[out] num_properties The number of properties, if that can be
   *                computed in advance. Otherwise should be set to zero.
   *                Pre-initialized to zero.
   * @return An opaque iterator for use by #enumerate_next.
   */
  virtual boost::any enumerate_start(int &num_properties);

  /**
   * Virtual method invoked to advance the enumeration and pull out the next
   * property name / index.
   *
   * Default implementation: return @c value().
   *
   * Should return @c value() (@c undefined) to stop the enumeration.
   *
   * @param[in,out] iter The opaque iterator.
   * @return The next property name / index.
   */
  virtual value enumerate_next(boost::any &iter);

  /**
   * Possible modes for native_object_base::property_op.
   */
  enum property_mode {
    /**
     * Used just before a new property is added to an object.
     */
    property_add = 0,

    /**
     * Used during most property deletions, even when the object has no property
     * with the given name / index.
     *
     * Will not be used for permanent properties.
     */
    property_delete = -1,

    /**
     * Used as the default getter for new properties or for non-existing
     * properties.
     */
    property_get = 1,

    /**
     * Used as the default setter for new properties.
     */
    property_set = 2
  };

  /**
   * Virtual method invoked for property addition, deletion, read access and
   * write access.
   *
   * Default implementation: stub.
   *
   * @param mode The reason for invocation.
   * @param id The property name / index.
   * @param[in,out] data The old/new value of the property.
   *
   * @see property_mode
   */
  virtual void property_op(property_mode mode, value const &id, value &data);

private:
#ifndef IN_DOXYGEN
  static object do_create_object(object const &proto);
  static object do_create_enumerable_object(object const &proto);

  friend object detail::create_native_object(object const &proto);
  friend object detail::create_native_enumerable_object(object const &proto);

private:
  class impl;
  boost::scoped_ptr<impl> p;

  friend class impl;
#endif
};

template<typename T>
T &cast_to_derived(native_object_base &o) {
  T *ptr = dynamic_cast<T*>(&o);
  if (!ptr)
    throw exception("Could not convert native object to derived type");
  return *ptr;
}

template<typename T>
T &get_native(object const &o) {
  return cast_to_derived<T>(native_object_base::get_native(o));
}

template<typename T>
bool is_derived(native_object_base &o) {
  return dynamic_cast<T*>(&o);
}

/**
 * Checks if @p o is a @p T.
 *
 * @param o object to check
 * @see get_native
 * @ingroup classes
 */
template<typename T>
bool is_native(object const &o) {
  return is_derived<T>(native_object_base::get_native(o));
}

template<typename T>
struct detail::convert_ptr<T, native_object_base> {
  struct to_value {
    value perform(T *ptr) {
      if (!ptr)
        return object();
      return *static_cast<object const *>(ptr);
    }
  };

  struct from_value {
    T *perform(value const &v) {
      if (!v.is_object())
        throw exception("Value is no object");
      return &native_object_base::get_native(v.get_object());
    }
  };
};

namespace detail {

template<typename T, typename O>
struct convert_ptr<
  T, O,
  typename boost::enable_if<
    typename boost::is_base_of<native_object_base, O>::type
  >::type
>
{
  typedef typename convert_ptr<T, native_object_base>::to_value to_value;

  struct from_value {
    typename convert_ptr<native_object_base>::from_value base;

    T *perform(value const &v) {
      return &dynamic_cast<T&>(*base.perform(v));
    }
  };
};

}

}

#endif
<commit_msg>docs: Example usage of is_native<T>(o)<commit_after>// vim:ts=2:sw=2:expandtab:autoindent:filetype=cpp:
/*
The MIT License

Copyright (c) 2008, 2009 Flusspferd contributors (see "CONTRIBUTORS" or
                                       http://flusspferd.org/contributors.txt)

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.
*/

#ifndef FLUSSPFERD_NATIVE_OBJECT_BASE_HPP
#define FLUSSPFERD_NATIVE_OBJECT_BASE_HPP

#include "object.hpp"
#include "convert.hpp"
#include "function_adapter.hpp"
#include <boost/scoped_ptr.hpp>
#include <boost/noncopyable.hpp>
#include <boost/function.hpp>
#include <boost/type_traits/is_base_of.hpp>
#include <boost/type_traits/is_member_function_pointer.hpp>
#include <boost/any.hpp>
#include <memory>
#include <functional>

namespace flusspferd {

#ifndef IN_DOXYGEN
struct call_context;
class tracer;

namespace detail {
  object create_native_object(object const &proto);
  object create_native_enumerable_object(object const &proto);
}
#endif

/**
 * Native object base.
 *
 * @ingroup classes
 */
class native_object_base : public object, private boost::noncopyable {
public:
  /// Destructor.
  virtual ~native_object_base() = 0;

  /**
   * Explicitly return the associated object.
   *
   * @return The associated object.
   */
  object get_object() {
    return *static_cast<object*>(this);
  }

  /**
   * Get the native object associated with a Javascript object.
   *
   * @return A reference to the object.
   */
  static native_object_base &get_native(object const &o);

public:
  /**
   * Associate with an object if there is no association yet.
   *
   * Do not use directly.
   *
   * @param o The object to associate with.
   */
  void load_into(object const &o);

protected:
  /**
   * Constructor.
   *
   * Immediately associates with object @p o.
   *
   * Do not use with arbitrary objects.
   *
   * @param o The object to associate with.
   */
  native_object_base(object const &o);

protected:
  /**
   * Virtual method invoked whenever the object is called as if it were a
   * function.
   *
   * Default implementation: throw an exception.
   *
   * @param x The call context.
   */
  virtual void self_call(call_context &x);

  /**
   * Virtual method invoked whenever the object has to be traced.
   *
   * Default implementation: stub.
   *
   * For each value that is an otherwise unreachable member of the object and
   * that should be protected from garbage collection, call @c trc("x", x).
   * The string "x" does not need to be unique, it's used for debugging
   * purposes only.
   *
   * @code
flusspferd::value v;

...

void trace(flusspferd::tracer &trc) {
    trc("v", v);
}
   @endcode
   *
   * @param trc The tracer to be used.
   *
   * @see @ref gc
   */
  virtual void trace(tracer &trc);

protected:
  /**
   * Possible property access methods. Can be combined by bitwise or.
   */
  enum property_access {
    /**
     * The property access uses the @c . or @c [] operator:
     * @c obj.id or @c obj[id], not @c id.
     */
    property_qualified = 1,

    /**
     * The property appears on the left-hand side of an assignment.
     */
    property_assigning = 2,

    /**
     * The property is being used in code like "if (o.p) ...",
     * or a similar idiom where the apparent purpose of the property access is
     * to detect whether the property exists.
     */
    property_detecting = 4,

    /**
     * The property is being declared in a var, const, or function declaration.
     */
    property_declaring = 8,

    /**
     * class name used when constructing. (???)
     */
    property_classname = 16
  };

  /**
   * Virtual method invoked when a property is not found on an object.
   *
   * Default implementation: stub that returns @c false.
   *
   * It can be used to implement lazy properties.
   *
   * If possible, @p id will be an integer, or a string otherwise.
   *
   * @param id The property name / index.
   * @param access Information about the kind of property access. A combination
   *           of #property_access values.
   */
  virtual bool property_resolve(value const &id, unsigned access);

  /**
   * Virtual method invoked to start enumerating properties.
   *
   * Will be called only if class_info::custom_enumerate is activated.
   *
   * Default implementation: return boost::any().
   *
   * @param[out] num_properties The number of properties, if that can be
   *                computed in advance. Otherwise should be set to zero.
   *                Pre-initialized to zero.
   * @return An opaque iterator for use by #enumerate_next.
   */
  virtual boost::any enumerate_start(int &num_properties);

  /**
   * Virtual method invoked to advance the enumeration and pull out the next
   * property name / index.
   *
   * Default implementation: return @c value().
   *
   * Should return @c value() (@c undefined) to stop the enumeration.
   *
   * @param[in,out] iter The opaque iterator.
   * @return The next property name / index.
   */
  virtual value enumerate_next(boost::any &iter);

  /**
   * Possible modes for native_object_base::property_op.
   */
  enum property_mode {
    /**
     * Used just before a new property is added to an object.
     */
    property_add = 0,

    /**
     * Used during most property deletions, even when the object has no property
     * with the given name / index.
     *
     * Will not be used for permanent properties.
     */
    property_delete = -1,

    /**
     * Used as the default getter for new properties or for non-existing
     * properties.
     */
    property_get = 1,

    /**
     * Used as the default setter for new properties.
     */
    property_set = 2
  };

  /**
   * Virtual method invoked for property addition, deletion, read access and
   * write access.
   *
   * Default implementation: stub.
   *
   * @param mode The reason for invocation.
   * @param id The property name / index.
   * @param[in,out] data The old/new value of the property.
   *
   * @see property_mode
   */
  virtual void property_op(property_mode mode, value const &id, value &data);

private:
#ifndef IN_DOXYGEN
  static object do_create_object(object const &proto);
  static object do_create_enumerable_object(object const &proto);

  friend object detail::create_native_object(object const &proto);
  friend object detail::create_native_enumerable_object(object const &proto);

private:
  class impl;
  boost::scoped_ptr<impl> p;

  friend class impl;
#endif
};

template<typename T>
T &cast_to_derived(native_object_base &o) {
  T *ptr = dynamic_cast<T*>(&o);
  if (!ptr)
    throw exception("Could not convert native object to derived type");
  return *ptr;
}

template<typename T>
T &get_native(object const &o) {
  return cast_to_derived<T>(native_object_base::get_native(o));
}

template<typename T>
bool is_derived(native_object_base &o) {
  return dynamic_cast<T*>(&o);
}

/**
 * Checks if @p o is a native object of class @p T.
 *
 * @code
flusspferd::object o = v.get_object();
if (flusspferd::is_native<flusspferd::binary>(o) {
  flusspferd::binary b = flusspferd::get_native<flusspferd::binary>(o);
}
@endcode
 *
 * @param o object to check
 * @see get_native
 * @ingroup classes
 */
template<typename T>
bool is_native(object const &o) {
  return is_derived<T>(native_object_base::get_native(o));
}

template<typename T>
struct detail::convert_ptr<T, native_object_base> {
  struct to_value {
    value perform(T *ptr) {
      if (!ptr)
        return object();
      return *static_cast<object const *>(ptr);
    }
  };

  struct from_value {
    T *perform(value const &v) {
      if (!v.is_object())
        throw exception("Value is no object");
      return &native_object_base::get_native(v.get_object());
    }
  };
};

namespace detail {

template<typename T, typename O>
struct convert_ptr<
  T, O,
  typename boost::enable_if<
    typename boost::is_base_of<native_object_base, O>::type
  >::type
>
{
  typedef typename convert_ptr<T, native_object_base>::to_value to_value;

  struct from_value {
    typename convert_ptr<native_object_base>::from_value base;

    T *perform(value const &v) {
      return &dynamic_cast<T&>(*base.perform(v));
    }
  };
};

}

}

#endif
<|endoftext|>