<commit_before>#ifndef __MEMORY_ANALYSIS_HH_
#define __MEMORY_ANALYSIS_HH_

/* Wrapper for a datastructure analysis*/

#include "llvm/IR/Function.h"
#include "llvm/IR/Value.h"
#include "llvm/IR/Instructions.h"

#include "boost/tuple/tuple.hpp"

#include "crab_llvm/config.h"
#include <crab/cfg/Cfg.hpp>

#ifdef HAVE_DSA
#include "boost/range/algorithm/set_algorithm.hpp"
#include "dsa/DataStructure.h"
#include "dsa/DSGraph.h"
#include "dsa/DSNode.h"

namespace crab_llvm
{
  using namespace std;
  using namespace llvm;
  using namespace crab::cfg;

  class MemAnalysis
  {
    /*
     *  The goal of the memory analysis is to split the whole heap into
     *  disjoint arrays (i.e., contiguous sequence of bytes)
     *
     *  Each DSA node is translated into an array. A DSA node may not
     *  correspond directly to a llvm Value so we map DSA node to
     *  id's.
     */

   public:

    typedef int array_id_t; // if < 0 then error

   private:

    DataStructures*  m_dsa;
    TrackedPrecision m_tracklev;

    /// map from DSNode to ids
    DenseMap<const DSNode*, unsigned> m_node_ids;
    boost::unordered_map<unsigned, const DSNode*> m_rev_node_ids;

    /// reach - all reachable nodes from this function
    std::set<const DSNode*> m_reach;
    /// outReach - subset of reach that is only reachable from the
    ///            return node
    std::set<const DSNode*> m_retReach;

    // template<typename First, typename Second>
    // struct getSecond : public std::unary_function<pair<First,Second>, Second> {
    //   getSecond () { }
    //   Second operator () (const pair<First,Second> &p) const { return p.second; }
    // };

    // typedef boost::transform_iterator< getSecond<const DSNode*,unsigned>,
    //                                    typename DenseMap<const DSNode*,
    //                                                      unsigned>::iterator > iterator;

    array_id_t getId (const DSNode *n)
    {
      auto it = m_node_ids.find (n);
      if (it != m_node_ids.end ()) return it->second;
      unsigned id = m_node_ids.size ();
      m_node_ids[n] = id;
      m_rev_node_ids[id] = n;
      return id;
    }

    template <typename Set>
    void markReachableNodes (const DSNode *n, Set &set)
    {
      if (!n) return;

      assert (!n->isForwarding () && "Cannot mark a forwarded node");
      if (set.insert (n).second)
        for (auto &edg : boost::make_iterator_range (n->edge_begin (), n->edge_end ()))
          markReachableNodes (edg.second.getNode (), set);
    }

    template <typename Set>
    void inputReachableNodes (const DSCallSite &cs, DSGraph &dsg, Set &set)
    {
      markReachableNodes (cs.getVAVal().getNode (), set);
      if (cs.isIndirectCall ()) markReachableNodes (cs.getCalleeNode (), set);
      for (unsigned i = 0, e = cs.getNumPtrArgs (); i != e; ++i)
        markReachableNodes (cs.getPtrArg (i).getNode (), set);

      // globals
      DSScalarMap &sm = dsg.getScalarMap ();
      for (auto &gv : boost::make_iterator_range (sm.global_begin(), sm.global_end ()))
        markReachableNodes (sm[gv].getNode (), set);
    }

    template <typename Set>
    void retReachableNodes (const DSCallSite &cs, Set &set)
    {markReachableNodes (cs.getRetVal ().getNode (), set);}

    template <typename Set>
    void set_difference (Set &s1, Set &s2)
    {
      Set s3;
      boost::set_difference (s1, s2, std::inserter (s3, s3.end ()));
      std::swap (s3, s1);
    }

    template <typename Set>
    void set_union (Set &s1, Set &s2)
    {
      Set s3;
      boost::set_union (s1, s2, std::inserter (s3, s3.end ()));
      std::swap (s3, s1);
    }

    /// Computes DSNode reachable from the call arguments
    /// reach - all reachable nodes
    /// outReach - subset of reach that is only reachable from the return node
    template <typename Set1, typename Set2>
    void argReachableNodes (DSCallSite CS, DSGraph &dsg,
                            Set1 &reach, Set2 &outReach)
    {
      inputReachableNodes (CS, dsg, reach);
      retReachableNodes (CS, outReach);
      set_difference (outReach, reach);
      set_union (reach, outReach);
    }

    template <typename Set1, typename Set2>
    void argReachableNodes (Function&f, Set1 &reach, Set2 &outReach)
    {
      DSGraph *cdsg = m_dsa->getDSGraph (f);
      if (cdsg)
      {
        DSCallSite CCS = cdsg->getCallSiteForArguments (f);
        argReachableNodes (CCS, *cdsg, reach, outReach);
      }
    }

    // //! return begin iterator to node id's
    // iterator begin () {
    //     return boost::make_transform_iterator
    //         (m_node_ids.begin (),
    //          getSecond<const DSNode*,unsigned> ());
    // }

    // //! return end iterator to node id's
    // iterator end () {
    //     return boost::make_transform_iterator
    //         (m_node_ids.end (),
    //          getSecond<const DSNode*,unsigned> ());
    // }

   public:

    MemAnalysis ():  m_dsa (0), m_tracklev (INT) { }

    MemAnalysis (DataStructures * dsa,
                 TrackedPrecision tracklev):
        m_dsa (dsa), m_tracklev (tracklev) { }

    TrackedPrecision getTrackLevel () const { return m_tracklev; }

    //! return < 0 if no array associated with ptr is found
    array_id_t getArrayId (Function& f, Value* ptr)
    {
      if (!m_dsa) return -1;

      DSGraph* dsg = m_dsa->getDSGraph (f);
      if (!dsg) return -1;

      DSGraph* gDsg = dsg->getGlobalsGraph ();
      DSNode* n = dsg->getNodeForValue (ptr).getNode ();
      if (!n) n = gDsg->getNodeForValue (ptr).getNode ();

      if (!n) return -1;

      return getId (n);
    }

    //! return true if the array corresponds to a single memory cell.
    bool isSingleton (array_id_t array_id)
    {
      auto it = m_rev_node_ids.find (array_id);
      if (it == m_rev_node_ids.end ()) return false;

      return it->second->getUniqueScalar ();
    }

    // Return the set of ref, mod and new nodes such that mod nodes
    // are a subset of the ref nodes and the new nodes are disjoint
    // from mod nodes.
    boost::tuple< set<array_id_t>, set<array_id_t>, set<array_id_t> >
    getRefModNewArrays (Function& f) {
      std::set<const DSNode*> reach, retReach;
      argReachableNodes (f, reach, retReach);

      set<array_id_t> refs, mods, news;
      for (const DSNode* n : reach) {
        if (!n->isReadNode () && !n->isModifiedNode ())
          continue;

        if ((n->isReadNode () || n->isModifiedNode ()) && retReach.count (n) <= 0)
          refs.insert (getId (n));

        if (n->isModifiedNode () && retReach.count (n) <= 0)
          mods.insert (getId (n));

        if (n->isModifiedNode () && retReach.count (n))
          news.insert (getId (n));
      }
      return boost::make_tuple (refs, mods, news);
    }

    // Return the set of ref, mod and new nodes such that mod nodes
    // are a subset of the ref nodes and the new nodes are disjoint
    // from mod nodes.
    boost::tuple< set<array_id_t>, set<array_id_t>, set<array_id_t> >
    getRefModNewArrays (CallInst& I) {
      set<array_id_t> refs, mods, news;

      /// ignore inline assembly
      if (I.isInlineAsm ())
        return boost::make_tuple (refs, mods, news);

      DSGraph *dsg = m_dsa->getDSGraph (*(I.getParent ()->getParent ()));
      DSCallSite CS = dsg->getDSCallSiteForCallSite (CallSite (&I));

      if (!CS.isDirectCall ())
        return boost::make_tuple (refs, mods, news);

      if (!m_dsa->hasDSGraph (*CS.getCalleeFunc ()))
        return boost::make_tuple (refs, mods, news);

      const Function &CF = *CS.getCalleeFunc ();
      DSGraph *cdsg = m_dsa->getDSGraph (CF);
      if (!cdsg)
        return boost::make_tuple (refs, mods, news);

      // -- compute callee nodes reachable from arguments and returns
      DSCallSite CCS = cdsg->getCallSiteForArguments (CF);
      std::set<const DSNode*> reach;
      std::set<const DSNode*> retReach;
      argReachableNodes (CCS, *cdsg, reach, retReach);
      DSGraph::NodeMapTy nodeMap;
      dsg->computeCalleeCallerMapping (CS, CF, *cdsg, nodeMap);

      for (const DSNode* n : reach) {
        if (!n->isReadNode () && !n->isModifiedNode ())
          continue;

        if ((n->isReadNode () || n->isModifiedNode ()) && retReach.count (n) <= 0)
          refs.insert (getId (n));

        if (n->isModifiedNode () && retReach.count (n) <= 0)
          mods.insert (getId (n));

        if (n->isModifiedNode () && retReach.count (n))
          news.insert (getId (n));

      }
      // -- add the node of the lhs of the call site
      int ret = getArrayId (*(I.getParent ()->getParent ()), &I);
      if (ret >=0)
        mods.insert (ret);

      return boost::make_tuple (refs, mods, news);
    }

  };

} // end namespace
#else
namespace crab_llvm
{
  using namespace crab::cfg;
  struct MemAnalysis {
    typedef int array_id_t;
    TrackedPrecision m_tracklev;
    MemAnalysis (): m_tracklev (INT) { }
    TrackedPrecision getTrackLevel () const { return m_tracklev; }
    int getArrayId (llvm::Function&, llvm::Value*) { return -1; }
    bool isSingleton (int) { return false; }
    boost::tuple<set<int>,set<int>, set<int> >
    getRefModNewArrays (llvm::Function&) {
      return boost::make_tuple (set<int> (), set<int> (), set<int> ());
    }
    boost::tuple<set<int>,set<int>, set<int> >
    getRefModNewArrays (llvm::CallInst&) {
      return boost::make_tuple (set<int> (), set<int> (), set<int> ());
    }
  };
} // end namespace
#endif

#endif /*__MEMORY_ANALYSIS_HH_*/
<commit_msg>[NEW] memory abstraction: keep track only of arrays which are known, complete, and non-collapsed.<commit_after>#ifndef __MEMORY_ANALYSIS_HH_
#define __MEMORY_ANALYSIS_HH_

/* Wrapper for a datastructure analysis*/

#include "llvm/IR/Function.h"
#include "llvm/IR/Value.h"
#include "llvm/IR/Instructions.h"

#include "boost/tuple/tuple.hpp"

#include "crab_llvm/config.h"
#include <crab/cfg/Cfg.hpp>

#ifdef HAVE_DSA
#include "boost/range/algorithm/set_algorithm.hpp"
#include "dsa/DataStructure.h"
#include "dsa/DSGraph.h"
#include "dsa/DSNode.h"

namespace crab_llvm
{
  using namespace std;
  using namespace llvm;
  using namespace crab::cfg;

  class MemAnalysis
  {
    /*
     *  The goal of the memory analysis is to split the whole heap into
     *  disjoint arrays (i.e., contiguous sequence of bytes)
     *
     *  Each DSA node is translated into an array. A DSA node may not
     *  correspond directly to a llvm Value so we map DSA node to
     *  id's.
     */

   public:

    typedef int array_id_t; // if < 0 then error

   private:

    DataStructures*  m_dsa;
    TrackedPrecision m_tracklev;

    /// map from DSNode to ids
    DenseMap<const DSNode*, unsigned> m_node_ids;
    boost::unordered_map<unsigned, const DSNode*> m_rev_node_ids;

    /// reach - all reachable nodes from this function
    std::set<const DSNode*> m_reach;
    /// outReach - subset of reach that is only reachable from the
    ///            return node
    std::set<const DSNode*> m_retReach;

    array_id_t getId (const DSNode *n) {
      auto it = m_node_ids.find (n);
      if (it != m_node_ids.end ()) return it->second;
      unsigned id = m_node_ids.size ();
      m_node_ids[n] = id;
      m_rev_node_ids[id] = n;
      return id;
    }

    template <typename Set>
    void markReachableNodes (const DSNode *n, Set &set) {
      if (!n) return;

      assert (!n->isForwarding () && "Cannot mark a forwarded node");
      if (set.insert (n).second)
        for (auto &edg : boost::make_iterator_range (n->edge_begin (), n->edge_end ()))
          markReachableNodes (edg.second.getNode (), set);
    }

    template <typename Set>
    void inputReachableNodes (const DSCallSite &cs, DSGraph &dsg, Set &set) {
      markReachableNodes (cs.getVAVal().getNode (), set);
      if (cs.isIndirectCall ()) markReachableNodes (cs.getCalleeNode (), set);
      for (unsigned i = 0, e = cs.getNumPtrArgs (); i != e; ++i)
        markReachableNodes (cs.getPtrArg (i).getNode (), set);

      // globals
      DSScalarMap &sm = dsg.getScalarMap ();
      for (auto &gv : boost::make_iterator_range (sm.global_begin(), sm.global_end ()))
        markReachableNodes (sm[gv].getNode (), set);
    }

    template <typename Set>
    void retReachableNodes (const DSCallSite &cs, Set &set)
    {markReachableNodes (cs.getRetVal ().getNode (), set);}

    template <typename Set>
    void set_difference (Set &s1, Set &s2) {
      Set s3;
      boost::set_difference (s1, s2, std::inserter (s3, s3.end ()));
      std::swap (s3, s1);
    }

    template <typename Set>
    void set_union (Set &s1, Set &s2) {
      Set s3;
      boost::set_union (s1, s2, std::inserter (s3, s3.end ()));
      std::swap (s3, s1);
    }

    /// Computes DSNode reachable from the call arguments
    /// reach - all reachable nodes
    /// outReach - subset of reach that is only reachable from the return node
    template <typename Set1, typename Set2>
    void argReachableNodes (DSCallSite CS, DSGraph &dsg,
                            Set1 &reach, Set2 &outReach) {
      inputReachableNodes (CS, dsg, reach);
      retReachableNodes (CS, outReach);
      set_difference (outReach, reach);
      set_union (reach, outReach);
    }

    template <typename Set1, typename Set2>
    void argReachableNodes (Function&f, Set1 &reach, Set2 &outReach) {
      DSGraph *cdsg = m_dsa->getDSGraph (f);
      if (cdsg) {
        DSCallSite CCS = cdsg->getCallSiteForArguments (f);
        argReachableNodes (CCS, *cdsg, reach, outReach);
      }
    }

    // - a node is complete if all its uses have been seen.
    // - a node is unknown if an integer is cast to a pointer or when
    //   unanalyzable address arithmetic is seen.
    // - a node is collapsed if all its uses have compatible type or
    //   compatible types but misaligned.
    bool isTrackable (const DSNode* n) const {
      return  (n->isCompleteNode () &&
               !n->isUnknownNode () &&
               !n->isCollapsedNode () &&
               (n->isAllocaNode () || n->isHeapNode () || n->isGlobalNode ()));
    }

   public:

    MemAnalysis ():  m_dsa (0), m_tracklev (INT) { }

    MemAnalysis (DataStructures * dsa,
                 TrackedPrecision tracklev):
        m_dsa (dsa), m_tracklev (tracklev) { }

    TrackedPrecision getTrackLevel () const { return m_tracklev; }

    //! return < 0 if no array associated with ptr is found
    array_id_t getArrayId (Function& f, Value* ptr)  {
      if (!m_dsa) return -1;

      DSGraph* dsg = m_dsa->getDSGraph (f);
      if (!dsg) return -1;

      DSGraph* gDsg = dsg->getGlobalsGraph ();
      DSNode* n = dsg->getNodeForValue (ptr).getNode ();
      if (!n) n = gDsg->getNodeForValue (ptr).getNode ();

      if (!n || !isTrackable (n)) return -1;

      return getId (n);
    }

    //! return true if the array corresponds to a single memory cell.
    bool isSingleton (array_id_t array_id) {
      auto it = m_rev_node_ids.find (array_id);
      if (it == m_rev_node_ids.end ()) return false;

      return it->second->getUniqueScalar ();
    }

    // Return the set of ref, mod and new nodes such that mod nodes
    // are a subset of the ref nodes and the new nodes are disjoint
    // from mod nodes.
    boost::tuple< set<array_id_t>, set<array_id_t>, set<array_id_t> >
    getRefModNewArrays (Function& f) {
      std::set<const DSNode*> reach, retReach;
      argReachableNodes (f, reach, retReach);

      set<array_id_t> refs, mods, news;
      for (const DSNode* n : reach) {

        if (!isTrackable (n))
          continue;

        if (!n->isReadNode () && !n->isModifiedNode ())
          continue;

        if ((n->isReadNode () || n->isModifiedNode ()) && retReach.count (n) <= 0)
          refs.insert (getId (n));

        if (n->isModifiedNode () && retReach.count (n) <= 0)
          mods.insert (getId (n));

        if (n->isModifiedNode () && retReach.count (n))
          news.insert (getId (n));
      }
      return boost::make_tuple (refs, mods, news);
    }

    // Return the set of ref, mod and new nodes such that mod nodes
    // are a subset of the ref nodes and the new nodes are disjoint
    // from mod nodes.
    boost::tuple< set<array_id_t>, set<array_id_t>, set<array_id_t> >
    getRefModNewArrays (CallInst& I) {
      set<array_id_t> refs, mods, news;

      /// ignore inline assembly
      if (I.isInlineAsm ())
        return boost::make_tuple (refs, mods, news);

      DSGraph *dsg = m_dsa->getDSGraph (*(I.getParent ()->getParent ()));
      DSCallSite CS = dsg->getDSCallSiteForCallSite (CallSite (&I));

      if (!CS.isDirectCall ())
        return boost::make_tuple (refs, mods, news);

      if (!m_dsa->hasDSGraph (*CS.getCalleeFunc ()))
        return boost::make_tuple (refs, mods, news);

      const Function &CF = *CS.getCalleeFunc ();
      DSGraph *cdsg = m_dsa->getDSGraph (CF);
      if (!cdsg)
        return boost::make_tuple (refs, mods, news);

      // -- compute callee nodes reachable from arguments and returns
      DSCallSite CCS = cdsg->getCallSiteForArguments (CF);
      std::set<const DSNode*> reach;
      std::set<const DSNode*> retReach;
      argReachableNodes (CCS, *cdsg, reach, retReach);
      DSGraph::NodeMapTy nodeMap;
      dsg->computeCalleeCallerMapping (CS, CF, *cdsg, nodeMap);

      for (const DSNode* n : reach) {

        if (!isTrackable (n))
          continue;

        if (!n->isReadNode () && !n->isModifiedNode ())
          continue;

        if ((n->isReadNode () || n->isModifiedNode ()) && retReach.count (n) <= 0)
          refs.insert (getId (n));

        if (n->isModifiedNode () && retReach.count (n) <= 0)
          mods.insert (getId (n));

        if (n->isModifiedNode () && retReach.count (n))
          news.insert (getId (n));

      }
      // -- add the node of the lhs of the call site
      int ret = getArrayId (*(I.getParent ()->getParent ()), &I);
      if (ret >=0)
        mods.insert (ret);

      return boost::make_tuple (refs, mods, news);
    }

  };

} // end namespace
#else

namespace crab_llvm
{
  using namespace crab::cfg;
  // Empty memory analysis
  struct MemAnalysis {
    typedef int array_id_t;
    TrackedPrecision m_tracklev;
    MemAnalysis (): m_tracklev (INT) { }
    TrackedPrecision getTrackLevel () const { return m_tracklev; }
    int getArrayId (llvm::Function&, llvm::Value*) { return -1; }
    bool isSingleton (int) { return false;}
    boost::tuple<set<int>,set<int>, set<int> >
    getRefModNewArrays (llvm::Function&) {
      return boost::make_tuple (set<int> (), set<int> (), set<int> ());
    }
    boost::tuple<set<int>,set<int>, set<int> >
    getRefModNewArrays (llvm::CallInst&) {
      return boost::make_tuple (set<int> (), set<int> (), set<int> ());
    }
  };
} // end namespace
#endif

#endif /*__MEMORY_ANALYSIS_HH_*/
<|endoftext|>


<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

#include "ReadableNativeMap.h"

using namespace facebook::jni;

namespace facebook {
namespace react {

void ReadableNativeMap::mapException(const std::exception &ex) {
  if (dynamic_cast<const folly::TypeError *>(&ex) != nullptr) {
    throwNewJavaException(
        exceptions::gUnexpectedNativeTypeExceptionClass, ex.what());
  }
}

void addDynamicToJArray(
    local_ref<JArrayClass<jobject>> jarray,
    jint index,
    const folly::dynamic &dyn) {
  switch (dyn.type()) {
    case folly::dynamic::Type::NULLT: {
      jarray->setElement(index, nullptr);
      break;
    }
    case folly::dynamic::Type::BOOL: {
      (*jarray)[index] = JBoolean::valueOf(dyn.getBool());
      break;
    }
    case folly::dynamic::Type::INT64: {
      (*jarray)[index] = JDouble::valueOf(dyn.getInt());
      break;
    }
    case folly::dynamic::Type::DOUBLE: {
      (*jarray)[index] = JDouble::valueOf(dyn.getDouble());
      break;
    }
    case folly::dynamic::Type::STRING: {
      (*jarray)[index] = make_jstring(dyn.getString());
      break;
    }
    case folly::dynamic::Type::OBJECT: {
      (*jarray)[index] = ReadableNativeMap::newObjectCxxArgs(dyn);
      break;
    }
    case folly::dynamic::Type::ARRAY: {
      (*jarray)[index] = ReadableNativeArray::newObjectCxxArgs(dyn);
      break;
    }
    default:
      jarray->setElement(index, nullptr);
      break;
  }
}

local_ref<JArrayClass<jstring>> ReadableNativeMap::importKeys() {
  keys_ = folly::dynamic::array();
  if (map_ == nullptr) {
    return JArrayClass<jstring>::newArray(0);
  }
  auto pairs = map_.items();
  for (auto &pair : pairs) {
    keys_.value().push_back(pair.first.asString());
  }
  jint size = keys_.value().size();
  auto jarray = JArrayClass<jstring>::newArray(size);
  for (jint ii = 0; ii < size; ii++) {
    (*jarray)[ii] = make_jstring(keys_.value()[ii].getString());
  }
  return jarray;
}

local_ref<JArrayClass<jobject>> ReadableNativeMap::importValues() {
  jint size = keys_.value().size();
  auto jarray = JArrayClass<jobject>::newArray(size);
  for (jint ii = 0; ii < size; ii++) {
    const std::string &key = keys_.value()[ii].getString();
    addDynamicToJArray(jarray, ii, map_.at(key));
  }
  return jarray;
}

local_ref<JArrayClass<jobject>> ReadableNativeMap::importTypes() {
  jint size = keys_.value().size();
  auto jarray = JArrayClass<jobject>::newArray(size);
  for (jint ii = 0; ii < size; ii++) {
    const std::string &key = keys_.value()[ii].getString();
    (*jarray)[ii] = ReadableType::getType(map_.at(key).type());
  }
  return jarray;
}

local_ref<ReadableNativeMap::jhybridobject>
ReadableNativeMap::createWithContents(folly::dynamic &&map) {
  if (map.isNull()) {
    return local_ref<jhybridobject>(nullptr);
  }

  if (!map.isObject()) {
    throwNewJavaException(
        exceptions::gUnexpectedNativeTypeExceptionClass,
        "expected Map, got a %s",
        map.typeName());
  }

  return newObjectCxxArgs(std::move(map));
}

void ReadableNativeMap::registerNatives() {
  registerHybrid({
      makeNativeMethod("importKeys", ReadableNativeMap::importKeys),
      makeNativeMethod("importValues", ReadableNativeMap::importValues),
      makeNativeMethod("importTypes", ReadableNativeMap::importTypes),
  });
}

} // namespace react
} // namespace facebook
<commit_msg>Micro-optimization in ReadableNativeMaps<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

#include "ReadableNativeMap.h"

using namespace facebook::jni;

namespace facebook {
namespace react {

void ReadableNativeMap::mapException(const std::exception &ex) {
  if (dynamic_cast<const folly::TypeError *>(&ex) != nullptr) {
    throwNewJavaException(
        exceptions::gUnexpectedNativeTypeExceptionClass, ex.what());
  }
}

void addDynamicToJArray(
    local_ref<JArrayClass<jobject>> jarray,
    jint index,
    const folly::dynamic &dyn) {
  switch (dyn.type()) {
    case folly::dynamic::Type::NULLT: {
      jarray->setElement(index, nullptr);
      break;
    }
    case folly::dynamic::Type::BOOL: {
      (*jarray)[index] = JBoolean::valueOf(dyn.getBool());
      break;
    }
    case folly::dynamic::Type::INT64: {
      (*jarray)[index] = JDouble::valueOf(dyn.getInt());
      break;
    }
    case folly::dynamic::Type::DOUBLE: {
      (*jarray)[index] = JDouble::valueOf(dyn.getDouble());
      break;
    }
    case folly::dynamic::Type::STRING: {
      (*jarray)[index] = make_jstring(dyn.getString());
      break;
    }
    case folly::dynamic::Type::OBJECT: {
      (*jarray)[index] = ReadableNativeMap::newObjectCxxArgs(dyn);
      break;
    }
    case folly::dynamic::Type::ARRAY: {
      (*jarray)[index] = ReadableNativeArray::newObjectCxxArgs(dyn);
      break;
    }
    default:
      jarray->setElement(index, nullptr);
      break;
  }
}

local_ref<JArrayClass<jstring>> ReadableNativeMap::importKeys() {
  keys_ = folly::dynamic::array();
  if (map_ == nullptr) {
    return JArrayClass<jstring>::newArray(0);
  }
  auto pairs = map_.items();
  jint size = map_.size();
  auto jarray = JArrayClass<jstring>::newArray(size);
  jint i = 0;
  for (auto &pair : pairs) {
    auto value = pair.first.asString();
    keys_.value().push_back(value);
    (*jarray)[i++] = make_jstring(value);
  }

  return jarray;
}

local_ref<JArrayClass<jobject>> ReadableNativeMap::importValues() {
  jint size = keys_.value().size();
  auto jarray = JArrayClass<jobject>::newArray(size);
  for (jint ii = 0; ii < size; ii++) {
    const std::string &key = keys_.value()[ii].getString();
    addDynamicToJArray(jarray, ii, map_.at(key));
  }
  return jarray;
}

local_ref<JArrayClass<jobject>> ReadableNativeMap::importTypes() {
  jint size = keys_.value().size();
  auto jarray = JArrayClass<jobject>::newArray(size);
  for (jint ii = 0; ii < size; ii++) {
    const std::string &key = keys_.value()[ii].getString();
    (*jarray)[ii] = ReadableType::getType(map_.at(key).type());
  }
  return jarray;
}

local_ref<ReadableNativeMap::jhybridobject>
ReadableNativeMap::createWithContents(folly::dynamic &&map) {
  if (map.isNull()) {
    return local_ref<jhybridobject>(nullptr);
  }

  if (!map.isObject()) {
    throwNewJavaException(
        exceptions::gUnexpectedNativeTypeExceptionClass,
        "expected Map, got a %s",
        map.typeName());
  }

  return newObjectCxxArgs(std::move(map));
}

void ReadableNativeMap::registerNatives() {
  registerHybrid({
      makeNativeMethod("importKeys", ReadableNativeMap::importKeys),
      makeNativeMethod("importValues", ReadableNativeMap::importValues),
      makeNativeMethod("importTypes", ReadableNativeMap::importTypes),
  });
}

} // namespace react
} // namespace facebook
<|endoftext|>


<commit_before>#include "cinder/app/AppBasic.h"
#include <list>
#include "cinder/params/Params.h"
#include "cinder/Font.h"
#include "cinder/Utilities.h"
#include "cinder/Rand.h"

#include <b2cinder/b2cinder.h>

using namespace ci;
using namespace ci::app;
using namespace ci::box2d;
using namespace std;

class BasicBox2DApp : public AppBasic {
 public:
	void mouseDrag( MouseEvent event );
	void mouseDown( MouseEvent event );
	void update();
	void prepareSettings(Settings* settings);
	void setup();
	void draw();

private:
	void addBox();

	Sandbox mSandbox;
	Font mFont;
};

void BasicBox2DApp::prepareSettings(Settings* settings)
{
	settings->setWindowSize(1024, 768);
	settings->setFrameRate(60.0f);
}

void BasicBox2DApp::setup()
{
	mSandbox.init();
	mSandbox.enableMouseInteraction(this);

	mFont = Font( "Hoefler Text", 12.0f );
}

void BasicBox2DApp::mouseDrag( MouseEvent event )
{
	if ( event.isAltDown() )
	{
		addBox();
	}
//	mSandbox.addBox( getMousePos(), Vec2f( Rand::randFloat(10.0f,40.0f), Rand::randFloat(10.0f,40.0f) ) );
}

void BasicBox2DApp::mouseDown( MouseEvent event )
{
	if( event.isAltDown() )
	{
		addBox();
	}

}

void BasicBox2DApp::update()
{
	mSandbox.update();
}

void BasicBox2DApp::addBox()
{
	BoxElement* b = new BoxElement( getMousePos(), Vec2f( Rand::randFloat(10.0f,40.0f), Rand::randFloat(10.0f,40.0f) ) );
	b->setColor( Color( CM_HSV, Rand::randFloat(0.0f,0.19f), 0.9f, 1.0f  ) );
	mSandbox.addElement(b);
}

void BasicBox2DApp::draw()
{
	gl::clear( Color::white() );
	gl::enableAlphaBlending();

	//draw all physics elements
	mSandbox.draw();
	//only draw the contact points in debug
	mSandbox.debugDraw(false, true);

	gl::drawString( "Framerate: " + toString(getAverageFps()), Vec2f( 10.0f, 10.0f ), Color::black(), mFont );
	gl::drawString( "Num bodies: " + toString(mSandbox.getBodyCount() ), Vec2f( 10.0f, 22.0f ), Color::black(), mFont );
	gl::drawString( "Num contacts: " + toString(mSandbox.getContactCount() ), Vec2f( 10.0f, 34.0f ), Color::black(), mFont );

//	params::InterfaceGl::draw();
}

// This line tells Cinder to actually create the application
CINDER_APP_BASIC( BasicBox2DApp, RendererGl )
<commit_msg>basic demo now adds boxes unless alt/option is held.<commit_after>#include "cinder/app/AppBasic.h"
#include <list>
#include "cinder/params/Params.h"
#include "cinder/Font.h"
#include "cinder/Utilities.h"
#include "cinder/Rand.h"

#include <b2cinder/b2cinder.h>

using namespace ci;
using namespace ci::app;
using namespace ci::box2d;
using namespace std;

class BasicBox2DApp : public AppBasic {
 public:
	void mouseDrag( MouseEvent event );
	void mouseDown( MouseEvent event );
	void update();
	void prepareSettings(Settings* settings);
	void setup();
	void draw();

private:
	void addBox();

	Sandbox mSandbox;
	Font mFont;
};

void BasicBox2DApp::prepareSettings(Settings* settings)
{
	settings->setWindowSize(1024, 768);
	settings->setFrameRate(60.0f);
}

void BasicBox2DApp::setup()
{
	mSandbox.init();
	mSandbox.enableMouseInteraction(this);

	mFont = Font( "Hoefler Text", 12.0f );
}

void BasicBox2DApp::mouseDrag( MouseEvent event )
{
	if ( !event.isAltDown() )
	{
		addBox();
	}
//	mSandbox.addBox( getMousePos(), Vec2f( Rand::randFloat(10.0f,40.0f), Rand::randFloat(10.0f,40.0f) ) );
}

void BasicBox2DApp::mouseDown( MouseEvent event )
{
	if( !event.isAltDown() )
	{
		addBox();
	}

}

void BasicBox2DApp::update()
{
	mSandbox.update();
}

void BasicBox2DApp::addBox()
{
	BoxElement* b = new BoxElement( getMousePos(), Vec2f( Rand::randFloat(10.0f,40.0f), Rand::randFloat(10.0f,40.0f) ) );
	b->setColor( Color( CM_HSV, Rand::randFloat(0.0f,0.19f), 0.9f, 1.0f  ) );
	mSandbox.addElement(b);
}

void BasicBox2DApp::draw()
{
	gl::clear( Color::white() );
	gl::enableAlphaBlending();

	//draw all physics elements
	mSandbox.draw();
	//only draw the contact points in debug
	mSandbox.debugDraw(false, true);

	gl::drawString( "Framerate: " + toString(getAverageFps()), Vec2f( 10.0f, 10.0f ), Color::black(), mFont );
	gl::drawString( "Num bodies: " + toString(mSandbox.getBodyCount() ), Vec2f( 10.0f, 22.0f ), Color::black(), mFont );
	gl::drawString( "Num contacts: " + toString(mSandbox.getContactCount() ), Vec2f( 10.0f, 34.0f ), Color::black(), mFont );

//	params::InterfaceGl::draw();
}

// This line tells Cinder to actually create the application
CINDER_APP_BASIC( BasicBox2DApp, RendererGl )
<|endoftext|>


<commit_before>#include "text_file.hpp"
#include "to_utf16.hpp"
#include "to_utf8.hpp"
#include "current_dir.hpp"
#include <fstream>

static std::string getFullFileName(std::string fileName)
{
    if (fileName.empty() || fileName[0] == L'/')
        return fileName;
    else
        return getCurrentDir() + '/' + fileName;
}

static std::string baseName(std::string fileName)
{
    auto p = fileName.rfind('/');
    if (p != std::string::npos)
        return std::string{ begin(fileName) + p + 1, end(fileName) };
    else
        return fileName;
}

TextFile::TextFile(std::string fileName):
    fileName_(getFullFileName(fileName))
{
    if (!fileName.empty())
        setName(toUtf16(baseName(fileName)));
    else
        setName(L"Untitled");

    std::ifstream f(fileName_);
    if (f.is_open())
        while (!f.eof())
        {
            std::string line;
            std::getline(f, line);
            buffer_.push_back(toUtf16(line));
        }
    else
        buffer_.push_back(L"");
}

std::string TextFile::fileName() const
{
    return fileName_;
}

void TextFile::save()
{
    if (!fileName_.empty())
        saveAs(fileName_);
}

void TextFile::saveAs(std::string fileName)
{
    fileName_ = fileName;
    setName(toUtf16(baseName(fileName)));
    std::ofstream f(fileName_);
    for (const auto &l: buffer_)
        f << toUtf8(l) << std::endl;
    clearModified();
}
<commit_msg>Fix bug when the application adds the empty line to the end of the file after saving<commit_after>#include "text_file.hpp"
#include "to_utf16.hpp"
#include "to_utf8.hpp"
#include "current_dir.hpp"
#include <fstream>

static std::string getFullFileName(std::string fileName)
{
    if (fileName.empty() || fileName[0] == L'/')
        return fileName;
    else
        return getCurrentDir() + '/' + fileName;
}

static std::string baseName(std::string fileName)
{
    auto p = fileName.rfind('/');
    if (p != std::string::npos)
        return std::string{ begin(fileName) + p + 1, end(fileName) };
    else
        return fileName;
}

TextFile::TextFile(std::string fileName):
    fileName_(getFullFileName(fileName))
{
    if (!fileName.empty())
        setName(toUtf16(baseName(fileName)));
    else
        setName(L"Untitled");

    std::ifstream f(fileName_);
    if (f.is_open())
        while (!f.eof())
        {
            std::string line;
            std::getline(f, line);
            buffer_.push_back(toUtf16(line));
        }
    else
        buffer_.push_back(L"");
}

std::string TextFile::fileName() const
{
    return fileName_;
}

void TextFile::save()
{
    if (!fileName_.empty())
        saveAs(fileName_);
}

void TextFile::saveAs(std::string fileName)
{
    fileName_ = fileName;
    setName(toUtf16(baseName(fileName)));
    std::ofstream f(fileName_);
    bool first = true;
    for (const auto &l: buffer_)
    {
        if (first)
            first = false;
        else
            f << std::endl;
        f << toUtf8(l);
    }
    clearModified();
}
<|endoftext|>


<commit_before>/**
 * @file   TimePointTest.cpp
 * @brief  TimePoint class tester.
 * @author zer0
 * @date   2017-04-12
 */

#include <gtest/gtest.h>
#include <libtbag/time/TimePoint.hpp>

#include <thread>

using namespace libtbag;
using namespace libtbag::time;

TEST(TimePointTest, Default)
{
    TimePoint tp;
    ASSERT_EQ(1970, tp.year());
    ASSERT_EQ(   1, tp.month());
    ASSERT_EQ(   1, tp.day());
    ASSERT_EQ(   0, tp.hours());
    ASSERT_EQ(   0, tp.minutes());
    ASSERT_EQ(   0, tp.seconds());
    ASSERT_EQ(   0, tp.millisec());
    ASSERT_EQ(   0, tp.microsec());
}

TEST(TimePointTest, Constructor)
{
    auto now  = std::chrono::system_clock::now();
    auto diff = std::chrono::microseconds(1);

    TimePoint::Rep  now_rep =  now.time_since_epoch().count();
    TimePoint::Rep diff_rep = diff.count();

    TimePoint tp1;
    TimePoint tp2(now);
    TimePoint tp3(now, diff);
    TimePoint tp4(now_rep);
    TimePoint tp5(now_rep, diff_rep);
    TimePoint tp6(1970, 1, 1, 0, 0, 0, 0, 0);

    TimePoint tp7 = tp1;
    TimePoint tp8 = std::move(TimePoint(1970, 1, 1, 0, 0, 0, 0, 0, 0));

    ASSERT_EQ(0, tp8.getMicrosecTimeSinceEpoch());
    ASSERT_EQ(tp1, tp7);
    ASSERT_EQ(tp2, tp3);
    ASSERT_EQ(tp4, tp5);
}

TEST(TimePointTest, Swap)
{
    TimePoint tp1 = TimePoint::now();
    auto g1 = tp1.getTimeSinceEpoch();
    auto l1 = tp1.getLocalTimeSinceEpoch();

    std::this_thread::sleep_for(std::chrono::microseconds(1));

    TimePoint tp2 = TimePoint::now();
    auto g2 = tp2.getTimeSinceEpoch();
    auto l2 = tp2.getLocalTimeSinceEpoch();

    ASSERT_NE(g1, g2);
    ASSERT_NE(l1, l2);

    std::swap(tp1, tp2);
    ASSERT_EQ(g1, tp2.getTimeSinceEpoch());
    ASSERT_EQ(l1, tp2.getLocalTimeSinceEpoch());
    ASSERT_EQ(g2, tp1.getTimeSinceEpoch());
    ASSERT_EQ(l2, tp1.getLocalTimeSinceEpoch());
}

TEST(TimePointTest, Operators)
{
    using namespace std::chrono;

    TimePoint tp1;
    TimePoint tp2(1970, 1, 1, 0, 0, 0, 0, 0);
    ASSERT_EQ(tp1, tp2);

    ASSERT_EQ(TimePoint::SystemDuration(0), tp1.getTimeSinceEpoch());
    ASSERT_EQ(TimePoint::SystemDuration(0), tp2.getTimeSinceEpoch());

    tp1 += TimePoint::SystemDuration(1);
    tp2 += TimePoint::SystemDuration(1);
    ASSERT_EQ(tp1, tp2);

    ASSERT_EQ(TimePoint::SystemDuration(1), tp1.getTimeSinceEpoch());
    ASSERT_EQ(TimePoint::SystemDuration(1), tp2.getTimeSinceEpoch());

    tp1 = tp1 - TimePoint::SystemDuration(1);
    tp2 = tp2 - TimePoint::SystemDuration(1);

    ASSERT_EQ(TimePoint::SystemDuration(0), tp1.getTimeSinceEpoch());
    ASSERT_EQ(TimePoint::SystemDuration(0), tp2.getTimeSinceEpoch());

    tp1 = TimePoint::SystemDuration(0);
    tp2 = TimePoint::SystemDuration(1);

    ASSERT_LT(tp1, tp2);
    ASSERT_LE(tp1, tp2);
    ASSERT_GT(tp2, tp1);
    ASSERT_GE(tp2, tp1);
    ASSERT_NE(tp1, tp2);
}

TEST(TimePointTest, DateTime)
{
    TimePoint tp1(2017, 4, 5, 3, 28, 27, 100, 99);
    ASSERT_EQ(2017, tp1.year());
    ASSERT_EQ(   4, tp1.month());
    ASSERT_EQ(   5, tp1.day());
    ASSERT_EQ(   3, tp1.hours());
    ASSERT_EQ(  28, tp1.minutes());
    ASSERT_EQ(  27, tp1.seconds());
    ASSERT_EQ( 100, tp1.millisec());
    ASSERT_EQ(  99, tp1.microsec());

    TimePoint tp3 = TimePoint::now();
    TimePoint tp4(tp3.year(), tp3.month(), tp3.day(), tp3.hours(), tp3.minutes(), tp3.seconds(), tp3.millisec(), tp3.microsec());

    std::cout << "TP3 Long String: " << tp3.toLongString() << std::endl;
    std::cout << "TP4 Long String: " << tp4.toLongString() << std::endl;
    ASSERT_EQ(tp3, tp4);
}

TEST(TimePointTest, TimeBeforeEpoch)
{
    //TimePoint tp2(100, 1, 1, 0, 0, 1, 0, 1);
    //ASSERT_EQ(100, tp2.year());
    //ASSERT_EQ(  1, tp2.month());
    //ASSERT_EQ(  1, tp2.day());
    //ASSERT_EQ(  0, tp2.hours());
    //ASSERT_EQ(  0, tp2.minutes());
    //ASSERT_EQ(  1, tp2.seconds());
    //ASSERT_EQ(  0, tp2.millisec());
    //ASSERT_EQ(  1, tp2.microsec());
}

<commit_msg>Fixed nanoseconds error in TestPointTest.DateTime tester.<commit_after>/**
 * @file   TimePointTest.cpp
 * @brief  TimePoint class tester.
 * @author zer0
 * @date   2017-04-12
 */

#include <gtest/gtest.h>
#include <libtbag/time/TimePoint.hpp>

#include <thread>

using namespace libtbag;
using namespace libtbag::time;

TEST(TimePointTest, Default)
{
    TimePoint tp;
    ASSERT_EQ(1970, tp.year());
    ASSERT_EQ(   1, tp.month());
    ASSERT_EQ(   1, tp.day());
    ASSERT_EQ(   0, tp.hours());
    ASSERT_EQ(   0, tp.minutes());
    ASSERT_EQ(   0, tp.seconds());
    ASSERT_EQ(   0, tp.millisec());
    ASSERT_EQ(   0, tp.microsec());
}

TEST(TimePointTest, Constructor)
{
    auto now  = std::chrono::system_clock::now();
    auto diff = std::chrono::microseconds(1);

    TimePoint::Rep  now_rep =  now.time_since_epoch().count();
    TimePoint::Rep diff_rep = diff.count();

    TimePoint tp1;
    TimePoint tp2(now);
    TimePoint tp3(now, diff);
    TimePoint tp4(now_rep);
    TimePoint tp5(now_rep, diff_rep);
    TimePoint tp6(1970, 1, 1, 0, 0, 0, 0, 0);

    TimePoint tp7 = tp1;
    TimePoint tp8 = std::move(TimePoint(1970, 1, 1, 0, 0, 0, 0, 0, 0));

    ASSERT_EQ(0, tp8.getMicrosecTimeSinceEpoch());
    ASSERT_EQ(tp1, tp7);
    ASSERT_EQ(tp2, tp3);
    ASSERT_EQ(tp4, tp5);
}

TEST(TimePointTest, Swap)
{
    TimePoint tp1 = TimePoint::now();
    auto g1 = tp1.getTimeSinceEpoch();
    auto l1 = tp1.getLocalTimeSinceEpoch();

    std::this_thread::sleep_for(std::chrono::microseconds(1));

    TimePoint tp2 = TimePoint::now();
    auto g2 = tp2.getTimeSinceEpoch();
    auto l2 = tp2.getLocalTimeSinceEpoch();

    ASSERT_NE(g1, g2);
    ASSERT_NE(l1, l2);

    std::swap(tp1, tp2);
    ASSERT_EQ(g1, tp2.getTimeSinceEpoch());
    ASSERT_EQ(l1, tp2.getLocalTimeSinceEpoch());
    ASSERT_EQ(g2, tp1.getTimeSinceEpoch());
    ASSERT_EQ(l2, tp1.getLocalTimeSinceEpoch());
}

TEST(TimePointTest, Operators)
{
    using namespace std::chrono;

    TimePoint tp1;
    TimePoint tp2(1970, 1, 1, 0, 0, 0, 0, 0);
    ASSERT_EQ(tp1, tp2);

    ASSERT_EQ(TimePoint::SystemDuration(0), tp1.getTimeSinceEpoch());
    ASSERT_EQ(TimePoint::SystemDuration(0), tp2.getTimeSinceEpoch());

    tp1 += TimePoint::SystemDuration(1);
    tp2 += TimePoint::SystemDuration(1);
    ASSERT_EQ(tp1, tp2);

    ASSERT_EQ(TimePoint::SystemDuration(1), tp1.getTimeSinceEpoch());
    ASSERT_EQ(TimePoint::SystemDuration(1), tp2.getTimeSinceEpoch());

    tp1 = tp1 - TimePoint::SystemDuration(1);
    tp2 = tp2 - TimePoint::SystemDuration(1);

    ASSERT_EQ(TimePoint::SystemDuration(0), tp1.getTimeSinceEpoch());
    ASSERT_EQ(TimePoint::SystemDuration(0), tp2.getTimeSinceEpoch());

    tp1 = TimePoint::SystemDuration(0);
    tp2 = TimePoint::SystemDuration(1);

    ASSERT_LT(tp1, tp2);
    ASSERT_LE(tp1, tp2);
    ASSERT_GT(tp2, tp1);
    ASSERT_GE(tp2, tp1);
    ASSERT_NE(tp1, tp2);
}

TEST(TimePointTest, DateTime)
{
    TimePoint tp1(2017, 4, 5, 3, 28, 27, 100, 99);
    ASSERT_EQ(2017, tp1.year());
    ASSERT_EQ(   4, tp1.month());
    ASSERT_EQ(   5, tp1.day());
    ASSERT_EQ(   3, tp1.hours());
    ASSERT_EQ(  28, tp1.minutes());
    ASSERT_EQ(  27, tp1.seconds());
    ASSERT_EQ( 100, tp1.millisec());
    ASSERT_EQ(  99, tp1.microsec());

    TimePoint tp3 = TimePoint::now();
    TimePoint tp4(tp3.year(), tp3.month(), tp3.day(), tp3.hours(), tp3.minutes(), tp3.seconds(), tp3.millisec(), tp3.microsec(), tp3.nanosec());

    std::cout << "TP3 Long String: " << tp3.toLongString() << std::endl;
    std::cout << "TP4 Long String: " << tp4.toLongString() << std::endl;
    ASSERT_EQ(tp3, tp4);
}

TEST(TimePointTest, TimeBeforeEpoch)
{
    //TimePoint tp2(100, 1, 1, 0, 0, 1, 0, 1);
    //ASSERT_EQ(100, tp2.year());
    //ASSERT_EQ(  1, tp2.month());
    //ASSERT_EQ(  1, tp2.day());
    //ASSERT_EQ(  0, tp2.hours());
    //ASSERT_EQ(  0, tp2.minutes());
    //ASSERT_EQ(  1, tp2.seconds());
    //ASSERT_EQ(  0, tp2.millisec());
    //ASSERT_EQ(  1, tp2.microsec());
}

<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: b2dcubicbezier.cxx,v $
 *
 *  $Revision: 1.9 $
 *
 *  last change: $Author: rt $ $Date: 2004-12-13 08:47:52 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 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
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _BGFX_CURVE_B2DCUBICBEZIER_HXX
#include <basegfx/curve/b2dcubicbezier.hxx>
#endif

#ifndef _BGFX_VECTOR_B2DVECTOR_HXX
#include <basegfx/vector/b2dvector.hxx>
#endif

#ifndef _BGFX_POLYGON_B2DPOLYGON_HXX
#include <basegfx/polygon/b2dpolygon.hxx>
#endif

#ifndef _BGFX_NUMERIC_FTOOLS_HXX
#include <basegfx/numeric/ftools.hxx>
#endif

// #i37443#
#define FACTOR_FOR_UNSHARPEN    (1.6)
#ifdef DBG_UTIL
static double fMultFactUnsharpen = FACTOR_FOR_UNSHARPEN;
#endif

//////////////////////////////////////////////////////////////////////////////

namespace basegfx
{
    namespace
    {
        void ImpSubDiv(
            const B2DPoint& rfPA,           // start point
            const B2DPoint& rfEA,           // edge on A
            const B2DPoint& rfEB,           // edge on B
            const B2DPoint& rfPB,           // end point
            B2DPolygon& rTarget,            // target polygon
            double fAngleBound,             // angle bound in [0.0 .. 2PI]
            bool bAddLastPoint,             // should last point be added?
            bool bAllowUnsharpen,           // #i37443# allow the criteria to get unsharp in recursions
            sal_uInt16 nMaxRecursionDepth)  // endless loop protection
        {
            if(nMaxRecursionDepth)
            {
                // do angle test
                const B2DVector aLeft(rfEA - rfPA);
                const B2DVector aRight(rfEB - rfPB);
                const double fCurrentAngle(aLeft.angle(aRight));

                if(fabs(fCurrentAngle) > (F_PI - fAngleBound))
                {
                    // end recursion
                    nMaxRecursionDepth = 0;
                }
                else
                {
                    if(bAllowUnsharpen)
                    {
                        // #i37443# unsharpen criteria
#ifdef DBG_UTIL
                        fAngleBound *= fMultFactUnsharpen;
#else
                        fAngleBound *= FACTOR_FOR_UNSHARPEN;
#endif
                    }
                }
            }

            if(nMaxRecursionDepth)
            {
                // divide at 0.5
                const B2DPoint aS1L(average(rfPA, rfEA));
                const B2DPoint aS1C(average(rfEA, rfEB));
                const B2DPoint aS1R(average(rfEB, rfPB));
                const B2DPoint aS2L(average(aS1L, aS1C));
                const B2DPoint aS2R(average(aS1C, aS1R));
                const B2DPoint aS3C(average(aS2L, aS2R));

                // left recursion
                ImpSubDiv(rfPA, aS1L, aS2L, aS3C, rTarget, fAngleBound,
                    bAddLastPoint, bAllowUnsharpen, nMaxRecursionDepth - 1);

                // right recursion
                ImpSubDiv(aS3C, aS2R, aS1R, rfPB, rTarget, fAngleBound,
                    bAddLastPoint, bAllowUnsharpen, nMaxRecursionDepth - 1);
            }
            else
            {
                // add points
                rTarget.append(rfPA);

                if(bAddLastPoint)
                {
                    rTarget.append(rfPB);
                }
            }
        }

        void ImpSubDivStart(
            const B2DPoint& rfPA,           // start point
            const B2DPoint& rfEA,           // edge on A
            const B2DPoint& rfEB,           // edge on B
            const B2DPoint& rfPB,           // end point
            B2DPolygon& rTarget,            // target polygon
            const double& rfAngleBound,     // angle bound in [0.0 .. 2PI]
            bool bAddLastPoint,             // should last point be added?
            bool bAllowUnsharpen)           // #i37443# allow the criteria to get unsharp in recursions
        {
            sal_uInt16 nMaxRecursionDepth(8);
            const B2DVector aLeft(rfEA - rfPA);
            const B2DVector aRight(rfEB - rfPB);
            bool bLeftEqualZero(aLeft.equalZero());
            bool bRightEqualZero(aRight.equalZero());
            bool bAllParallel(false);

            if(bLeftEqualZero && bRightEqualZero)
            {
                nMaxRecursionDepth = 0;
            }
            else
            {
                const B2DVector aBase(rfPB - rfPA);
                const bool bBaseEqualZero(aLeft.equalZero());

                if(!bBaseEqualZero)
                {
                    const bool bLeftParallel(bLeftEqualZero ? true : areParallel(aLeft, aBase));
                    const bool bRightParallel(bRightEqualZero ? true : areParallel(aRight, aBase));

                    if(bLeftParallel && bRightParallel)
                    {
                        bAllParallel = true;

                        if(!bLeftEqualZero)
                        {
                            double fFactor;

                            if(fabs(aBase.getX()) > fabs(aBase.getY()))
                            {
                                fFactor = aLeft.getX() / aBase.getX();
                            }
                            else
                            {
                                fFactor = aLeft.getY() / aBase.getY();
                            }

                            if(fFactor >= 0.0 && fFactor <= 1.0)
                            {
                                bLeftEqualZero = true;
                            }
                        }

                        if(!bRightEqualZero)
                        {
                            double fFactor;

                            if(fabs(aBase.getX()) > fabs(aBase.getY()))
                            {
                                fFactor = aRight.getX() / -aBase.getX();
                            }
                            else
                            {
                                fFactor = aRight.getY() / -aBase.getY();
                            }

                            if(fFactor >= 0.0 && fFactor <= 1.0)
                            {
                                bRightEqualZero = true;
                            }
                        }

                        if(bLeftEqualZero && bRightEqualZero)
                        {
                            nMaxRecursionDepth = 0;
                        }
                    }
                }
            }

            if(nMaxRecursionDepth)
            {
                // divide at 0.5 ad test both edges for angle criteria
                const B2DPoint aS1L(average(rfPA, rfEA));
                const B2DPoint aS1C(average(rfEA, rfEB));
                const B2DPoint aS1R(average(rfEB, rfPB));
                const B2DPoint aS2L(average(aS1L, aS1C));
                const B2DPoint aS2R(average(aS1C, aS1R));
                const B2DPoint aS3C(average(aS2L, aS2R));

                // test left
                bool bAngleIsSmallerLeft(bAllParallel && bLeftEqualZero);
                if(!bAngleIsSmallerLeft)
                {
                    const B2DVector aLeftLeft(aS1L - rfPA);
                    const B2DVector aRightLeft(aS2L - aS3C);
                    const double fCurrentAngleLeft(aLeftLeft.angle(aRightLeft));
                    bAngleIsSmallerLeft = (fabs(fCurrentAngleLeft) > (F_PI - rfAngleBound));
                }

                // test right
                bool bAngleIsSmallerRight(bAllParallel && bRightEqualZero);
                if(!bAngleIsSmallerRight)
                {
                    const B2DVector aLeftRight(aS2R - aS3C);
                    const B2DVector aRightRight(aS1R - rfPB);
                    const double fCurrentAngleRight(aLeftRight.angle(aRightRight));
                    bAngleIsSmallerRight = (fabs(fCurrentAngleRight) > (F_PI - rfAngleBound));
                }

                if(bAngleIsSmallerLeft && bAngleIsSmallerRight)
                {
                    // no recursion necessary at all
                    nMaxRecursionDepth = 0;
                }
                else
                {
                    // left
                    if(bAngleIsSmallerLeft)
                    {
                        rTarget.append(rfPA);
                        if(bAddLastPoint)
                        {
                            rTarget.append(aS3C);
                        }
                    }
                    else
                    {
                        ImpSubDiv(rfPA, aS1L, aS2L, aS3C, rTarget, rfAngleBound,
                            bAddLastPoint, bAllowUnsharpen, nMaxRecursionDepth);
                    }

                    // right
                    if(bAngleIsSmallerRight)
                    {
                        rTarget.append(aS3C);
                        if(bAddLastPoint)
                        {
                            rTarget.append(rfPB);
                        }
                    }
                    else
                    {
                        ImpSubDiv(aS3C, aS2R, aS1R, rfPB, rTarget, rfAngleBound,
                            bAddLastPoint, bAllowUnsharpen, nMaxRecursionDepth);
                    }
                }
            }

            if(!nMaxRecursionDepth)
            {
                rTarget.append(rfPA);
                if(bAddLastPoint)
                {
                    rTarget.append(rfPB);
                }
            }
        }
    } // end of anonymous namespace
} // end of namespace basegfx

//////////////////////////////////////////////////////////////////////////////

namespace basegfx
{
    B2DCubicBezier::B2DCubicBezier(const B2DCubicBezier& rBezier)
    :   maStartPoint(rBezier.maStartPoint),
        maEndPoint(rBezier.maEndPoint),
        maControlPointA(rBezier.maControlPointA),
        maControlPointB(rBezier.maControlPointB)
    {
    }

    B2DCubicBezier::B2DCubicBezier()
    {
    }

    B2DCubicBezier::B2DCubicBezier(const B2DPoint& rStart, const B2DPoint& rEnd)
    :   maStartPoint(rStart),
        maEndPoint(rEnd),
        maControlPointA(rStart),
        maControlPointB(rEnd)
    {
    }

    B2DCubicBezier::B2DCubicBezier(const B2DPoint& rStart, const B2DPoint& rControlPointA,
        const B2DPoint& rControlPointB, const B2DPoint& rEnd)
    :   maStartPoint(rStart),
        maEndPoint(rEnd),
        maControlPointA(rControlPointA),
        maControlPointB(rControlPointB)
    {
    }

    B2DCubicBezier::~B2DCubicBezier()
    {
    }

    // assignment operator
    B2DCubicBezier& B2DCubicBezier::operator=(const B2DCubicBezier& rBezier)
    {
        maStartPoint = rBezier.maStartPoint;
        maEndPoint = rBezier.maEndPoint;
        maControlPointA = rBezier.maControlPointA;
        maControlPointB = rBezier.maControlPointB;

        return *this;
    }

    // compare operators
    bool B2DCubicBezier::operator==(const B2DCubicBezier& rBezier) const
    {
        return (
            maStartPoint == rBezier.maStartPoint
            && maEndPoint == rBezier.maEndPoint
            && maControlPointA == rBezier.maControlPointA
            && maControlPointB == rBezier.maControlPointB
        );
    }

    bool B2DCubicBezier::operator!=(const B2DCubicBezier& rBezier) const
    {
        return (
            maStartPoint != rBezier.maStartPoint
            || maEndPoint != rBezier.maEndPoint
            || maControlPointA != rBezier.maControlPointA
            || maControlPointB != rBezier.maControlPointB
        );
    }

    // test if vectors are used
    bool B2DCubicBezier::isBezier() const
    {
        if(maControlPointA != maStartPoint || maControlPointB != maEndPoint)
        {
            return true;
        }

        return false;
    }

    void B2DCubicBezier::testAndSolveTrivialBezier()
    {
        // TODO
    }

    double B2DCubicBezier::getEdgeLength() const
    {
        const B2DVector aEdge(maEndPoint - maStartPoint);
        return aEdge.getLength();
    }

    double B2DCubicBezier::getControlPolygonLength() const
    {
        const B2DVector aVectorA(maControlPointA - maStartPoint);
        const B2DVector aVectorB(maEndPoint - maControlPointB);
        const B2DVector aTop(maControlPointB - maControlPointA);
        return (aVectorA.getLength() + aVectorB.getLength() + aTop.getLength());
    }

    void B2DCubicBezier::adaptiveSubdivideByAngle(B2DPolygon& rTarget, double fAngleBound,
        bool bAddLastPoint, bool bAllowUnsharpen) const
    {
        // use support method #i37443# and allow unsharpen the criteria
        ImpSubDivStart(maStartPoint, maControlPointA, maControlPointB, maEndPoint,
            rTarget, fAngleBound * F_PI180, bAddLastPoint, bAllowUnsharpen);
    }

    // #i37443# adaptive subdivide by nCount subdivisions
    void B2DCubicBezier::adaptiveSubdivideByCount(B2DPolygon& rTarget, sal_uInt32 nCount, bool bAddLastPoint) const
    {
        rTarget.append(maStartPoint);

        if(nCount)
        {
            for(sal_uInt32 a(0L); a < nCount; a++)
            {
                const double fPos(double(a + 1L) / double(nCount + 1L));
                const B2DPoint aS1L(interpolate(maStartPoint, maControlPointA, fPos));
                const B2DPoint aS1C(interpolate(maControlPointA, maControlPointB, fPos));
                const B2DPoint aS1R(interpolate(maControlPointB, maEndPoint, fPos));
                const B2DPoint aS2L(interpolate(aS1L, aS1C, fPos));
                const B2DPoint aS2R(interpolate(aS1C, aS1R, fPos));
                const B2DPoint aS3C(interpolate(aS2L, aS2R, fPos));
                rTarget.append(aS3C);
            }
        }

        if(bAddLastPoint)
        {
            rTarget.append(maEndPoint);
        }
    }
} // end of namespace basegfx

// eof
<commit_msg>INTEGRATION: CWS ooo19126 (1.9.26); FILE MERGED 2005/09/05 17:38:33 rt 1.9.26.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: b2dcubicbezier.cxx,v $
 *
 *  $Revision: 1.10 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-07 20:40:27 $
 *
 *  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
 *
 ************************************************************************/

#ifndef _BGFX_CURVE_B2DCUBICBEZIER_HXX
#include <basegfx/curve/b2dcubicbezier.hxx>
#endif

#ifndef _BGFX_VECTOR_B2DVECTOR_HXX
#include <basegfx/vector/b2dvector.hxx>
#endif

#ifndef _BGFX_POLYGON_B2DPOLYGON_HXX
#include <basegfx/polygon/b2dpolygon.hxx>
#endif

#ifndef _BGFX_NUMERIC_FTOOLS_HXX
#include <basegfx/numeric/ftools.hxx>
#endif

// #i37443#
#define FACTOR_FOR_UNSHARPEN    (1.6)
#ifdef DBG_UTIL
static double fMultFactUnsharpen = FACTOR_FOR_UNSHARPEN;
#endif

//////////////////////////////////////////////////////////////////////////////

namespace basegfx
{
    namespace
    {
        void ImpSubDiv(
            const B2DPoint& rfPA,           // start point
            const B2DPoint& rfEA,           // edge on A
            const B2DPoint& rfEB,           // edge on B
            const B2DPoint& rfPB,           // end point
            B2DPolygon& rTarget,            // target polygon
            double fAngleBound,             // angle bound in [0.0 .. 2PI]
            bool bAddLastPoint,             // should last point be added?
            bool bAllowUnsharpen,           // #i37443# allow the criteria to get unsharp in recursions
            sal_uInt16 nMaxRecursionDepth)  // endless loop protection
        {
            if(nMaxRecursionDepth)
            {
                // do angle test
                const B2DVector aLeft(rfEA - rfPA);
                const B2DVector aRight(rfEB - rfPB);
                const double fCurrentAngle(aLeft.angle(aRight));

                if(fabs(fCurrentAngle) > (F_PI - fAngleBound))
                {
                    // end recursion
                    nMaxRecursionDepth = 0;
                }
                else
                {
                    if(bAllowUnsharpen)
                    {
                        // #i37443# unsharpen criteria
#ifdef DBG_UTIL
                        fAngleBound *= fMultFactUnsharpen;
#else
                        fAngleBound *= FACTOR_FOR_UNSHARPEN;
#endif
                    }
                }
            }

            if(nMaxRecursionDepth)
            {
                // divide at 0.5
                const B2DPoint aS1L(average(rfPA, rfEA));
                const B2DPoint aS1C(average(rfEA, rfEB));
                const B2DPoint aS1R(average(rfEB, rfPB));
                const B2DPoint aS2L(average(aS1L, aS1C));
                const B2DPoint aS2R(average(aS1C, aS1R));
                const B2DPoint aS3C(average(aS2L, aS2R));

                // left recursion
                ImpSubDiv(rfPA, aS1L, aS2L, aS3C, rTarget, fAngleBound,
                    bAddLastPoint, bAllowUnsharpen, nMaxRecursionDepth - 1);

                // right recursion
                ImpSubDiv(aS3C, aS2R, aS1R, rfPB, rTarget, fAngleBound,
                    bAddLastPoint, bAllowUnsharpen, nMaxRecursionDepth - 1);
            }
            else
            {
                // add points
                rTarget.append(rfPA);

                if(bAddLastPoint)
                {
                    rTarget.append(rfPB);
                }
            }
        }

        void ImpSubDivStart(
            const B2DPoint& rfPA,           // start point
            const B2DPoint& rfEA,           // edge on A
            const B2DPoint& rfEB,           // edge on B
            const B2DPoint& rfPB,           // end point
            B2DPolygon& rTarget,            // target polygon
            const double& rfAngleBound,     // angle bound in [0.0 .. 2PI]
            bool bAddLastPoint,             // should last point be added?
            bool bAllowUnsharpen)           // #i37443# allow the criteria to get unsharp in recursions
        {
            sal_uInt16 nMaxRecursionDepth(8);
            const B2DVector aLeft(rfEA - rfPA);
            const B2DVector aRight(rfEB - rfPB);
            bool bLeftEqualZero(aLeft.equalZero());
            bool bRightEqualZero(aRight.equalZero());
            bool bAllParallel(false);

            if(bLeftEqualZero && bRightEqualZero)
            {
                nMaxRecursionDepth = 0;
            }
            else
            {
                const B2DVector aBase(rfPB - rfPA);
                const bool bBaseEqualZero(aLeft.equalZero());

                if(!bBaseEqualZero)
                {
                    const bool bLeftParallel(bLeftEqualZero ? true : areParallel(aLeft, aBase));
                    const bool bRightParallel(bRightEqualZero ? true : areParallel(aRight, aBase));

                    if(bLeftParallel && bRightParallel)
                    {
                        bAllParallel = true;

                        if(!bLeftEqualZero)
                        {
                            double fFactor;

                            if(fabs(aBase.getX()) > fabs(aBase.getY()))
                            {
                                fFactor = aLeft.getX() / aBase.getX();
                            }
                            else
                            {
                                fFactor = aLeft.getY() / aBase.getY();
                            }

                            if(fFactor >= 0.0 && fFactor <= 1.0)
                            {
                                bLeftEqualZero = true;
                            }
                        }

                        if(!bRightEqualZero)
                        {
                            double fFactor;

                            if(fabs(aBase.getX()) > fabs(aBase.getY()))
                            {
                                fFactor = aRight.getX() / -aBase.getX();
                            }
                            else
                            {
                                fFactor = aRight.getY() / -aBase.getY();
                            }

                            if(fFactor >= 0.0 && fFactor <= 1.0)
                            {
                                bRightEqualZero = true;
                            }
                        }

                        if(bLeftEqualZero && bRightEqualZero)
                        {
                            nMaxRecursionDepth = 0;
                        }
                    }
                }
            }

            if(nMaxRecursionDepth)
            {
                // divide at 0.5 ad test both edges for angle criteria
                const B2DPoint aS1L(average(rfPA, rfEA));
                const B2DPoint aS1C(average(rfEA, rfEB));
                const B2DPoint aS1R(average(rfEB, rfPB));
                const B2DPoint aS2L(average(aS1L, aS1C));
                const B2DPoint aS2R(average(aS1C, aS1R));
                const B2DPoint aS3C(average(aS2L, aS2R));

                // test left
                bool bAngleIsSmallerLeft(bAllParallel && bLeftEqualZero);
                if(!bAngleIsSmallerLeft)
                {
                    const B2DVector aLeftLeft(aS1L - rfPA);
                    const B2DVector aRightLeft(aS2L - aS3C);
                    const double fCurrentAngleLeft(aLeftLeft.angle(aRightLeft));
                    bAngleIsSmallerLeft = (fabs(fCurrentAngleLeft) > (F_PI - rfAngleBound));
                }

                // test right
                bool bAngleIsSmallerRight(bAllParallel && bRightEqualZero);
                if(!bAngleIsSmallerRight)
                {
                    const B2DVector aLeftRight(aS2R - aS3C);
                    const B2DVector aRightRight(aS1R - rfPB);
                    const double fCurrentAngleRight(aLeftRight.angle(aRightRight));
                    bAngleIsSmallerRight = (fabs(fCurrentAngleRight) > (F_PI - rfAngleBound));
                }

                if(bAngleIsSmallerLeft && bAngleIsSmallerRight)
                {
                    // no recursion necessary at all
                    nMaxRecursionDepth = 0;
                }
                else
                {
                    // left
                    if(bAngleIsSmallerLeft)
                    {
                        rTarget.append(rfPA);
                        if(bAddLastPoint)
                        {
                            rTarget.append(aS3C);
                        }
                    }
                    else
                    {
                        ImpSubDiv(rfPA, aS1L, aS2L, aS3C, rTarget, rfAngleBound,
                            bAddLastPoint, bAllowUnsharpen, nMaxRecursionDepth);
                    }

                    // right
                    if(bAngleIsSmallerRight)
                    {
                        rTarget.append(aS3C);
                        if(bAddLastPoint)
                        {
                            rTarget.append(rfPB);
                        }
                    }
                    else
                    {
                        ImpSubDiv(aS3C, aS2R, aS1R, rfPB, rTarget, rfAngleBound,
                            bAddLastPoint, bAllowUnsharpen, nMaxRecursionDepth);
                    }
                }
            }

            if(!nMaxRecursionDepth)
            {
                rTarget.append(rfPA);
                if(bAddLastPoint)
                {
                    rTarget.append(rfPB);
                }
            }
        }
    } // end of anonymous namespace
} // end of namespace basegfx

//////////////////////////////////////////////////////////////////////////////

namespace basegfx
{
    B2DCubicBezier::B2DCubicBezier(const B2DCubicBezier& rBezier)
    :   maStartPoint(rBezier.maStartPoint),
        maEndPoint(rBezier.maEndPoint),
        maControlPointA(rBezier.maControlPointA),
        maControlPointB(rBezier.maControlPointB)
    {
    }

    B2DCubicBezier::B2DCubicBezier()
    {
    }

    B2DCubicBezier::B2DCubicBezier(const B2DPoint& rStart, const B2DPoint& rEnd)
    :   maStartPoint(rStart),
        maEndPoint(rEnd),
        maControlPointA(rStart),
        maControlPointB(rEnd)
    {
    }

    B2DCubicBezier::B2DCubicBezier(const B2DPoint& rStart, const B2DPoint& rControlPointA,
        const B2DPoint& rControlPointB, const B2DPoint& rEnd)
    :   maStartPoint(rStart),
        maEndPoint(rEnd),
        maControlPointA(rControlPointA),
        maControlPointB(rControlPointB)
    {
    }

    B2DCubicBezier::~B2DCubicBezier()
    {
    }

    // assignment operator
    B2DCubicBezier& B2DCubicBezier::operator=(const B2DCubicBezier& rBezier)
    {
        maStartPoint = rBezier.maStartPoint;
        maEndPoint = rBezier.maEndPoint;
        maControlPointA = rBezier.maControlPointA;
        maControlPointB = rBezier.maControlPointB;

        return *this;
    }

    // compare operators
    bool B2DCubicBezier::operator==(const B2DCubicBezier& rBezier) const
    {
        return (
            maStartPoint == rBezier.maStartPoint
            && maEndPoint == rBezier.maEndPoint
            && maControlPointA == rBezier.maControlPointA
            && maControlPointB == rBezier.maControlPointB
        );
    }

    bool B2DCubicBezier::operator!=(const B2DCubicBezier& rBezier) const
    {
        return (
            maStartPoint != rBezier.maStartPoint
            || maEndPoint != rBezier.maEndPoint
            || maControlPointA != rBezier.maControlPointA
            || maControlPointB != rBezier.maControlPointB
        );
    }

    // test if vectors are used
    bool B2DCubicBezier::isBezier() const
    {
        if(maControlPointA != maStartPoint || maControlPointB != maEndPoint)
        {
            return true;
        }

        return false;
    }

    void B2DCubicBezier::testAndSolveTrivialBezier()
    {
        // TODO
    }

    double B2DCubicBezier::getEdgeLength() const
    {
        const B2DVector aEdge(maEndPoint - maStartPoint);
        return aEdge.getLength();
    }

    double B2DCubicBezier::getControlPolygonLength() const
    {
        const B2DVector aVectorA(maControlPointA - maStartPoint);
        const B2DVector aVectorB(maEndPoint - maControlPointB);
        const B2DVector aTop(maControlPointB - maControlPointA);
        return (aVectorA.getLength() + aVectorB.getLength() + aTop.getLength());
    }

    void B2DCubicBezier::adaptiveSubdivideByAngle(B2DPolygon& rTarget, double fAngleBound,
        bool bAddLastPoint, bool bAllowUnsharpen) const
    {
        // use support method #i37443# and allow unsharpen the criteria
        ImpSubDivStart(maStartPoint, maControlPointA, maControlPointB, maEndPoint,
            rTarget, fAngleBound * F_PI180, bAddLastPoint, bAllowUnsharpen);
    }

    // #i37443# adaptive subdivide by nCount subdivisions
    void B2DCubicBezier::adaptiveSubdivideByCount(B2DPolygon& rTarget, sal_uInt32 nCount, bool bAddLastPoint) const
    {
        rTarget.append(maStartPoint);

        if(nCount)
        {
            for(sal_uInt32 a(0L); a < nCount; a++)
            {
                const double fPos(double(a + 1L) / double(nCount + 1L));
                const B2DPoint aS1L(interpolate(maStartPoint, maControlPointA, fPos));
                const B2DPoint aS1C(interpolate(maControlPointA, maControlPointB, fPos));
                const B2DPoint aS1R(interpolate(maControlPointB, maEndPoint, fPos));
                const B2DPoint aS2L(interpolate(aS1L, aS1C, fPos));
                const B2DPoint aS2R(interpolate(aS1C, aS1R, fPos));
                const B2DPoint aS3C(interpolate(aS2L, aS2R, fPos));
                rTarget.append(aS3C);
            }
        }

        if(bAddLastPoint)
        {
            rTarget.append(maEndPoint);
        }
    }
} // end of namespace basegfx

// eof
<|endoftext|>


<commit_before><commit_msg>Fix flipped sign in BoundingBox::contains().<commit_after><|endoftext|>


<commit_before>/*
 * Copyright (c) 2014 Tobias Klauser
 *
 * 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.
 */

#ifndef __BINSEARCH_CLOSEST_HPP__
#define __BINSEARCH_CLOSEST_HPP__

#include <vector>

/** Binary search for the closest value in a vector.
 *
 * This function assumes the vector to be sorted. If the value is outside
 * the range of the vector, it is clamped accordingly. If several elements
 * in the vector are equally close, the first one is returned.
 *
 * @param vec
 *   The sorted vector to search.
 * @param val
 *   Scalar value for which to search the closest element in the vector.
 * @return
 *   Index of the element in the vector that is closest to val or -1 if the
 *   vector contains no elements.
 */
template<typename T>
ssize_t binsearch_closest(const std::vector<T> vec, T val)
{
	// empty vector
	if (vec.size() < 1)
	    return -1;

	// clamp value to range of vector
	if (val < vec.at(0))
		return 0;
	if (val > vec.at(vec.size() - 1))
		return vec.size() - 1;

	size_t imin = 0;
	size_t  imax = vec.size() - 1;
	while (imax - imin > 1) {
		// determine midpoint, prevent integer overflow
		size_t imid = imin + ((imax - imin) / 2);
		if (vec.at(imid) >= val)
			imax = imid;
		else
			imin = imid;
	}

	if (imax - imin == 1 && std::abs(vec.at(imax) - val) < std::abs(vec.at(imin) - val))
		imin = imax;

	return (ssize_t)imin;
}

#endif /* __BINSEARCH_CLOSEST_HPP__ */
<commit_msg>binsearch_closest: Fix spacing<commit_after>/*
 * Copyright (c) 2014 Tobias Klauser
 *
 * 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.
 */

#ifndef __BINSEARCH_CLOSEST_HPP__
#define __BINSEARCH_CLOSEST_HPP__

#include <vector>

/** Binary search for the closest value in a vector.
 *
 * This function assumes the vector to be sorted. If the value is outside
 * the range of the vector, it is clamped accordingly. If several elements
 * in the vector are equally close, the first one is returned.
 *
 * @param vec
 *   The sorted vector to search.
 * @param val
 *   Scalar value for which to search the closest element in the vector.
 * @return
 *   Index of the element in the vector that is closest to val or -1 if the
 *   vector contains no elements.
 */
template<typename T>
ssize_t binsearch_closest(const std::vector<T> vec, T val)
{
	// empty vector
	if (vec.size() < 1)
	    return -1;

	// clamp value to range of vector
	if (val < vec.at(0))
		return 0;
	if (val > vec.at(vec.size() - 1))
		return vec.size() - 1;

	size_t imin = 0;
	size_t imax = vec.size() - 1;
	while (imax - imin > 1) {
		// determine midpoint, prevent integer overflow
		size_t imid = imin + ((imax - imin) / 2);
		if (vec.at(imid) >= val)
			imax = imid;
		else
			imin = imid;
	}

	if (imax - imin == 1 && std::abs(vec.at(imax) - val) < std::abs(vec.at(imin) - val))
		imin = imax;

	return (ssize_t)imin;
}

#endif /* __BINSEARCH_CLOSEST_HPP__ */
<|endoftext|>


<commit_before>#include "time_grid.h"

Time_grid::Time_grid( Config &conf )
{
    check_correctness_of_related_config_fields( conf );
    get_values_from_config( conf );
    init_total_nodes();
    shrink_time_step_size_if_necessary( conf );
    shrink_time_save_step_if_necessary( conf );
    set_current_time_and_node();
}

Time_grid::Time_grid( hid_t h5_time_grid_group )
{
    herr_t status;
    status = H5LTget_attribute_double( h5_time_grid_group, "./",
				    "total_time", &total_time ); hdf5_status_check( status );
    status = H5LTget_attribute_double( h5_time_grid_group, "./",
				       "current_time", &current_time ); hdf5_status_check( status );
    status = H5LTget_attribute_double( h5_time_grid_group, "./",
				       "time_step_size", &time_step_size ); hdf5_status_check( status );
    status = H5LTget_attribute_double( h5_time_grid_group, "./",
				       "time_save_step", &time_save_step ); hdf5_status_check( status );
    status = H5LTget_attribute_int( h5_time_grid_group, "./",
				    "total_nodes", &total_nodes ); hdf5_status_check( status );
    status = H5LTget_attribute_int( h5_time_grid_group, "./",
				    "current_node", &current_node ); hdf5_status_check( status );
    status = H5LTget_attribute_int( h5_time_grid_group, "./",
				    "node_to_save", &node_to_save ); hdf5_status_check( status );

    status = H5Gclose(h5_time_grid_group); hdf5_status_check( status );
}

void Time_grid::check_correctness_of_related_config_fields( Config &conf )
{
    total_time_gt_zero( conf );
    time_step_size_gt_zero_le_total_time( conf );
    time_save_step_ge_time_step_size( conf );
}

void Time_grid::get_values_from_config( Config &conf )
{
    total_time = conf.time_config_part.total_time;
    time_step_size = conf.time_config_part.time_step_size;
    time_save_step = conf.time_config_part.time_save_step;
}

void Time_grid::init_total_nodes()
{
    total_nodes = ceil( total_time / time_step_size ) + 1;
}

void Time_grid::shrink_time_step_size_if_necessary( Config &conf )
{
    time_step_size = total_time / ( total_nodes - 1 );
    if ( time_step_size != conf.time_config_part.time_step_size ) {
	std::cout.precision(3);
	std::cout << "Time step was shrinked to " << time_step_size
		  << " from " << conf.time_config_part.time_step_size
		  << " to fit round number of cells."
		  << std::endl;
    }
}

void Time_grid::shrink_time_save_step_if_necessary( Config &conf )
{
    time_save_step = ( (int)( time_save_step / time_step_size ) ) * time_step_size;
    if ( time_save_step != conf.time_config_part.time_save_step ) {
	std::cout.precision(3);
	std::cout << "Time save step was shrinked to " << time_save_step
		  << " from " << conf.time_config_part.time_save_step
		  << " to be a multiple of time step."
		  << std::endl;
    }
    node_to_save = (int) ( time_save_step / time_step_size );
}

void Time_grid::set_current_time_and_node()
{
    current_time = 0.0;
    current_node = 0;
}

void Time_grid::update_to_next_step()
{
    current_node++;
    current_time += time_step_size;
}

void Time_grid::print( )
{
    std::cout << "### Time grid:" << std::endl;
    std::cout << "Total time = " << total_time << std::endl;
    std::cout << "Current time = " << current_time << std::endl;
    std::cout << "Time step size = " << time_step_size << std::endl;
    std::cout << "Time save step = " << time_save_step << std::endl;
    std::cout << "Total nodes = " << total_nodes << std::endl;
    std::cout << "Current node = " << current_node << std::endl;
    std::cout << "Node to save = " << node_to_save << std::endl;
    return;
}

void Time_grid::write_to_file( hid_t hdf5_file_id )
{
    hid_t group_id;
    herr_t status;
    int single_element = 1;
    std::string hdf5_groupname = "/Time_grid";
    group_id = H5Gcreate( hdf5_file_id, hdf5_groupname.c_str(),
			  H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); hdf5_status_check( group_id );

    status = H5LTset_attribute_double( hdf5_file_id, hdf5_groupname.c_str(),
				       "total_time", &total_time, single_element ); hdf5_status_check( status );
    status = H5LTset_attribute_double( hdf5_file_id, hdf5_groupname.c_str(),
				       "current_time", &current_time, single_element ); hdf5_status_check( status );
    status = H5LTset_attribute_double( hdf5_file_id, hdf5_groupname.c_str(),
				       "time_step_size", &time_step_size, single_element ); hdf5_status_check( status );
    status = H5LTset_attribute_double( hdf5_file_id, hdf5_groupname.c_str(),
				       "time_save_step", &time_save_step, single_element ); hdf5_status_check( status );
    status = H5LTset_attribute_int( hdf5_file_id, hdf5_groupname.c_str(),
				    "total_nodes", &total_nodes, single_element ); hdf5_status_check( status );
    status = H5LTset_attribute_int( hdf5_file_id, hdf5_groupname.c_str(),
				    "current_node", &current_node, single_element ); hdf5_status_check( status );
    status = H5LTset_attribute_int( hdf5_file_id, hdf5_groupname.c_str(),
				    "node_to_save", &node_to_save, single_element ); hdf5_status_check( status );

    status = H5Gclose(group_id); hdf5_status_check( status );
    return;
}

void Time_grid::hdf5_status_check( herr_t status )
{
    if( status < 0 ){
	std::cout << "Something went wrong while writing Time_grid group. Aborting."
		  << std::endl;
	exit( EXIT_FAILURE );
    }
}

void Time_grid::total_time_gt_zero( Config &conf )
{
    check_and_exit_if_not(
	conf.time_config_part.total_time >= 0,
	"total_time < 0" );
}

void Time_grid::time_step_size_gt_zero_le_total_time( Config &conf )
{
    check_and_exit_if_not(
	( conf.time_config_part.time_step_size > 0 ) &&
	( conf.time_config_part.time_step_size <= conf.time_config_part.total_time ),
	"time_step_size <= 0 or time_step_size > total_time" );
    return;
}

void Time_grid::time_save_step_ge_time_step_size( Config &conf )
{
    check_and_exit_if_not(
	conf.time_config_part.time_save_step >= conf.time_config_part.time_step_size,
	"time_save_step < time_step_size" );
    return;
}

void Time_grid::check_and_exit_if_not( const bool &should_be, const std::string &message )
{
    if( !should_be ){
	std::cout << "Error: " + message << std::endl;
	exit( EXIT_FAILURE );
    }
    return;
}
<commit_msg>./Time_grid -> ./TimeGrid in h5<commit_after>#include "time_grid.h"

Time_grid::Time_grid( Config &conf )
{
    check_correctness_of_related_config_fields( conf );
    get_values_from_config( conf );
    init_total_nodes();
    shrink_time_step_size_if_necessary( conf );
    shrink_time_save_step_if_necessary( conf );
    set_current_time_and_node();
}

Time_grid::Time_grid( hid_t h5_time_grid_group )
{
    herr_t status;
    status = H5LTget_attribute_double( h5_time_grid_group, "./",
				    "total_time", &total_time ); hdf5_status_check( status );
    status = H5LTget_attribute_double( h5_time_grid_group, "./",
				       "current_time", &current_time ); hdf5_status_check( status );
    status = H5LTget_attribute_double( h5_time_grid_group, "./",
				       "time_step_size", &time_step_size ); hdf5_status_check( status );
    status = H5LTget_attribute_double( h5_time_grid_group, "./",
				       "time_save_step", &time_save_step ); hdf5_status_check( status );
    status = H5LTget_attribute_int( h5_time_grid_group, "./",
				    "total_nodes", &total_nodes ); hdf5_status_check( status );
    status = H5LTget_attribute_int( h5_time_grid_group, "./",
				    "current_node", &current_node ); hdf5_status_check( status );
    status = H5LTget_attribute_int( h5_time_grid_group, "./",
				    "node_to_save", &node_to_save ); hdf5_status_check( status );

    status = H5Gclose(h5_time_grid_group); hdf5_status_check( status );
}

void Time_grid::check_correctness_of_related_config_fields( Config &conf )
{
    total_time_gt_zero( conf );
    time_step_size_gt_zero_le_total_time( conf );
    time_save_step_ge_time_step_size( conf );
}

void Time_grid::get_values_from_config( Config &conf )
{
    total_time = conf.time_config_part.total_time;
    time_step_size = conf.time_config_part.time_step_size;
    time_save_step = conf.time_config_part.time_save_step;
}

void Time_grid::init_total_nodes()
{
    total_nodes = ceil( total_time / time_step_size ) + 1;
}

void Time_grid::shrink_time_step_size_if_necessary( Config &conf )
{
    time_step_size = total_time / ( total_nodes - 1 );
    if ( time_step_size != conf.time_config_part.time_step_size ) {
	std::cout.precision(3);
	std::cout << "Time step was shrinked to " << time_step_size
		  << " from " << conf.time_config_part.time_step_size
		  << " to fit round number of cells."
		  << std::endl;
    }
}

void Time_grid::shrink_time_save_step_if_necessary( Config &conf )
{
    time_save_step = ( (int)( time_save_step / time_step_size ) ) * time_step_size;
    if ( time_save_step != conf.time_config_part.time_save_step ) {
	std::cout.precision(3);
	std::cout << "Time save step was shrinked to " << time_save_step
		  << " from " << conf.time_config_part.time_save_step
		  << " to be a multiple of time step."
		  << std::endl;
    }
    node_to_save = (int) ( time_save_step / time_step_size );
}

void Time_grid::set_current_time_and_node()
{
    current_time = 0.0;
    current_node = 0;
}

void Time_grid::update_to_next_step()
{
    current_node++;
    current_time += time_step_size;
}

void Time_grid::print( )
{
    std::cout << "### Time grid:" << std::endl;
    std::cout << "Total time = " << total_time << std::endl;
    std::cout << "Current time = " << current_time << std::endl;
    std::cout << "Time step size = " << time_step_size << std::endl;
    std::cout << "Time save step = " << time_save_step << std::endl;
    std::cout << "Total nodes = " << total_nodes << std::endl;
    std::cout << "Current node = " << current_node << std::endl;
    std::cout << "Node to save = " << node_to_save << std::endl;
    return;
}

void Time_grid::write_to_file( hid_t hdf5_file_id )
{
    hid_t group_id;
    herr_t status;
    int single_element = 1;
    std::string hdf5_groupname = "/TimeGrid";
    group_id = H5Gcreate( hdf5_file_id, hdf5_groupname.c_str(),
			  H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); hdf5_status_check( group_id );

    status = H5LTset_attribute_double( hdf5_file_id, hdf5_groupname.c_str(),
				       "total_time", &total_time, single_element ); hdf5_status_check( status );
    status = H5LTset_attribute_double( hdf5_file_id, hdf5_groupname.c_str(),
				       "current_time", &current_time, single_element ); hdf5_status_check( status );
    status = H5LTset_attribute_double( hdf5_file_id, hdf5_groupname.c_str(),
				       "time_step_size", &time_step_size, single_element ); hdf5_status_check( status );
    status = H5LTset_attribute_double( hdf5_file_id, hdf5_groupname.c_str(),
				       "time_save_step", &time_save_step, single_element ); hdf5_status_check( status );
    status = H5LTset_attribute_int( hdf5_file_id, hdf5_groupname.c_str(),
				    "total_nodes", &total_nodes, single_element ); hdf5_status_check( status );
    status = H5LTset_attribute_int( hdf5_file_id, hdf5_groupname.c_str(),
				    "current_node", &current_node, single_element ); hdf5_status_check( status );
    status = H5LTset_attribute_int( hdf5_file_id, hdf5_groupname.c_str(),
				    "node_to_save", &node_to_save, single_element ); hdf5_status_check( status );

    status = H5Gclose(group_id); hdf5_status_check( status );
    return;
}

void Time_grid::hdf5_status_check( herr_t status )
{
    if( status < 0 ){
	std::cout << "Something went wrong while writing Time_grid group. Aborting."
		  << std::endl;
	exit( EXIT_FAILURE );
    }
}

void Time_grid::total_time_gt_zero( Config &conf )
{
    check_and_exit_if_not(
	conf.time_config_part.total_time >= 0,
	"total_time < 0" );
}

void Time_grid::time_step_size_gt_zero_le_total_time( Config &conf )
{
    check_and_exit_if_not(
	( conf.time_config_part.time_step_size > 0 ) &&
	( conf.time_config_part.time_step_size <= conf.time_config_part.total_time ),
	"time_step_size <= 0 or time_step_size > total_time" );
    return;
}

void Time_grid::time_save_step_ge_time_step_size( Config &conf )
{
    check_and_exit_if_not(
	conf.time_config_part.time_save_step >= conf.time_config_part.time_step_size,
	"time_save_step < time_step_size" );
    return;
}

void Time_grid::check_and_exit_if_not( const bool &should_be, const std::string &message )
{
    if( !should_be ){
	std::cout << "Error: " + message << std::endl;
	exit( EXIT_FAILURE );
    }
    return;
}
<|endoftext|>