<commit_before>#pragma once

#include "generator/osm2type.hpp"
#include "generator/xml_element.hpp"
#include "generator/feature_builder.hpp"
#include "generator/ways_merger.hpp"

#include "indexer/ftypes_matcher.hpp"
#include "indexer/feature_visibility.hpp"
#include "indexer/classificator.hpp"

#include "geometry/tree4d.hpp"

#include "base/string_utils.hpp"
#include "base/logging.hpp"
#include "base/stl_add.hpp"
#include "base/cache.hpp"

#include "std/unordered_set.hpp"
#include "std/list.hpp"

/// @param  TEmitter  Feature accumulating policy
/// @param  THolder   Nodes, ways, relations holder
template <class TEmitter, class THolder>
class SecondPassParser : public BaseOSMParser
{
  TEmitter & m_emitter;
  THolder & m_holder;

  bool GetPoint(uint64_t id, m2::PointD & pt) const
  {
    return m_holder.GetNode(id, pt.y, pt.x);
  }

  typedef vector<m2::PointD> pts_vec_t;
  typedef list<pts_vec_t> holes_list_t;

  class holes_accumulator
  {
    AreaWayMerger<THolder> m_merger;
    holes_list_t m_holes;

  public:
    holes_accumulator(SecondPassParser * pMain) : m_merger(pMain->m_holder) {}

    void operator() (uint64_t id)
    {
      m_merger.AddWay(id);
    }

    void operator() (pts_vec_t & v, vector<uint64_t> const &)
    {
      m_holes.push_back(pts_vec_t());
      m_holes.back().swap(v);
    }

    holes_list_t & GetHoles()
    {
      ASSERT ( m_holes.empty(), ("Can call only once") );
      m_merger.ForEachArea(*this, false);
      return m_holes;
    }
  };

  /// Find holes for way with 'id' in first relation.
  class multipolygon_holes_processor
  {
    uint64_t m_id;      ///< id of way to find it's holes
    holes_accumulator m_holes;

  public:
    multipolygon_holes_processor(uint64_t id, SecondPassParser * pMain)
      : m_id(id), m_holes(pMain)
    {
    }

    /// 1. relations process function
    bool operator() (uint64_t /*id*/, RelationElement const & e)
    {
      if (e.GetType() == "multipolygon")
      {
        string role;
        if (e.FindWay(m_id, role) && (role == "outer"))
        {
          e.ForEachWay(*this);
          // stop processing (??? assume that "outer way" exists in one relation only ???)
          return true;
        }
      }
      return false;
    }

    /// 2. "ways in relation" process function
    void operator() (uint64_t id, string const & role)
    {
      if (id != m_id && role == "inner")
        m_holes(id);
    }

    holes_list_t & GetHoles() { return m_holes.GetHoles(); }
  };

  /// Generated features should include parent relation tags to make
  /// full types matching and storing any additional info.
  class RelationTagsProcessor
  {
    uint64_t m_featureID;
    XMLElement * m_current;

    my::Cache<uint64_t, RelationElement> m_cache;

    bool IsAcceptBoundary(RelationElement const & e) const
    {
      string role;
      CHECK(e.FindWay(m_featureID, role), (m_featureID));

      // Do not accumulate boundary types (boundary=administrative) for inner polygons.
      // Example: Minsk city border (admin_level=8) is inner for Minsk area border (admin_level=4).
      return (role != "inner");
    }

    typedef unordered_set<string> NameKeysT;
    void GetNameKeys(NameKeysT & keys) const
    {
      for (auto const & p : m_current->childs)
        if (p.tagKey == XMLElement::ET_TAG)
        {
          if (strings::StartsWith(p.k, "name"))
            keys.insert(p.k);
        }
    }

    void Process(RelationElement const & e)
    {
      string const type = e.GetType();

      /// @todo Skip special relation types.
      if (type == "multipolygon" ||
          type == "route" ||
          type == "bridge" ||
          type == "restriction")
      {
        return;
      }

      bool const isWay = (m_current->tagKey == XMLElement::ET_WAY);
      bool const isBoundary = isWay && (type == "boundary") && IsAcceptBoundary(e);

      NameKeysT nameKeys;
      GetNameKeys(nameKeys);

      for (auto const & p : e.tags)
      {
        /// @todo Skip common key tags.
        if (p.first == "type" || p.first == "route")
          continue;

        /// Skip already existing "name" tags.
        if (nameKeys.count(p.first) != 0)
          continue;

        if (!isBoundary && p.first == "boundary")
          continue;

        if (isWay && p.first == "place")
          continue;

        m_current->AddKV(p.first, p.second);
      }
    }

  public:
    RelationTagsProcessor()
      : m_cache(14)
    {
    }

    void Reset(uint64_t fID, XMLElement * p)
    {
      m_featureID = fID;
      m_current = p;
    }

    template <class ReaderT> bool operator() (uint64_t id, ReaderT & reader)
    {
      bool exists = false;
      RelationElement & e = m_cache.Find(id, exists);
      if (!exists)
        CHECK(reader.Read(id, e), (id));

      Process(e);
      return false;
    }

  } m_relationsProcess;

  bool ParseType(XMLElement * p, FeatureParams & params)
  {
    // Get tags from parent relations.
    m_relationsProcess.Reset(p->id, p);

    if (p->tagKey == XMLElement::ET_NODE)
    {
      // additional process of nodes ONLY if there is no native types
      FeatureParams fp;
      ftype::GetNameAndType(p, fp);
      if (!ftype::IsValidTypes(fp))
        m_holder.ForEachRelationByNodeCached(p->id, m_relationsProcess);
    }
    else if (p->tagKey == XMLElement::ET_WAY)
    {
      // always make additional process of ways
      m_holder.ForEachRelationByWayCached(p->id, m_relationsProcess);
    }

    // Get params from element tags.
    ftype::GetNameAndType(p, params);
    params.FinishAddingTypes();
    return ftype::IsValidTypes(params);
  }

  typedef FeatureBuilder1 FeatureBuilderT;

  class multipolygons_emitter
  {
    SecondPassParser * m_pMain;
    FeatureParams const & m_params;
    holes_list_t & m_holes;
    uint64_t m_relID;

  public:
    multipolygons_emitter(SecondPassParser * pMain,
                          FeatureParams const & params,
                          holes_list_t & holes,
                          uint64_t relID)
      : m_pMain(pMain), m_params(params), m_holes(holes), m_relID(relID)
    {
    }

    void operator() (pts_vec_t const & pts, vector<uint64_t> const & ids)
    {
      FeatureBuilderT ft;

      for (size_t i = 0; i < ids.size(); ++i)
        ft.AddOsmId(osm::Id::Way(ids[i]));

      for (size_t i = 0; i < pts.size(); ++i)
        ft.AddPoint(pts[i]);

      ft.AddOsmId(osm::Id::Relation(m_relID));
      m_pMain->EmitArea(ft, m_params, [this] (FeatureBuilderT & ft)
      {
        ft.SetAreaAddHoles(m_holes);
      });
    }
  };

  uint32_t m_coastType;

  unique_ptr<FileWriter> m_addrWriter;
  bool NeedWriteAddress(FeatureParams const & params) const
  {
    return m_addrWriter && ftypes::IsBuildingChecker::Instance()(params.m_Types);
  }

  class Place
  {
    FeatureBuilderT m_ft;
    m2::PointD m_pt;
    uint32_t m_type;

    static constexpr double EQUAL_PLACE_SEARCH_RADIUS_M = 20000.0;

    bool IsPoint() const { return (m_ft.GetGeomType() == feature::GEOM_POINT); }

  public:
    Place(FeatureBuilderT const & ft, uint32_t type)
      : m_ft(ft), m_pt(ft.GetKeyPoint()), m_type(type)
    {
    }

    FeatureBuilderT const & GetFeature() const { return m_ft; }

    m2::RectD GetLimitRect() const
    {
      return MercatorBounds::RectByCenterXYAndSizeInMeters(m_pt, EQUAL_PLACE_SEARCH_RADIUS_M);
    }

    /// @name Always replace point features and leave area features.
    //@{
    bool IsEqual(Place const & r) const
    {
      return (m_type == r.m_type &&
              m_ft.GetName() == r.m_ft.GetName() &&
              (IsPoint() || r.IsPoint()) &&
              MercatorBounds::DistanceOnEarth(m_pt, r.m_pt) < EQUAL_PLACE_SEARCH_RADIUS_M);
    }

    bool NeedReplace(Place const & r) const
    {
      return (r.IsPoint() && (!IsPoint() || r.m_ft.GetRank() < m_ft.GetRank()));
    }
    //@}
  };

  m4::Tree<Place> m_places;

  void EmitFeatureBase(FeatureBuilderT & ft, FeatureParams const & params)
  {
    ft.SetParams(params);
    if (ft.PreSerialize())
    {
      string addr;
      if (NeedWriteAddress(params) && ft.FormatFullAddress(addr))
        m_addrWriter->Write(addr.c_str(), addr.size());

      static uint32_t const placeType = classif().GetTypeByPath({"place"});
      uint32_t const type = params.FindType(placeType, 1);

      if (type != ftype::GetEmptyValue() && !ft.GetName().empty())
      {
        m_places.ReplaceEqualInRect(Place(ft, type),
                                    bind(&Place::IsEqual, _1, _2),
                                    bind(&Place::NeedReplace, _1, _2));
      }
      else
        m_emitter(ft);
    }
  }

  /// @param[in]  params  Pass by value because it can be modified.
  //@{
  void EmitPoint(m2::PointD const & pt, FeatureParams params, osm::Id id)
  {
    if (feature::RemoveNoDrawableTypes(params.m_Types, feature::GEOM_POINT))
    {
      FeatureBuilderT ft;
      ft.SetCenter(pt);
      ft.SetOsmId(id);
      EmitFeatureBase(ft, params);
    }
  }

  void EmitLine(FeatureBuilderT & ft, FeatureParams params, bool isCoastLine)
  {
    if (isCoastLine || feature::RemoveNoDrawableTypes(params.m_Types, feature::GEOM_LINE))
    {
      ft.SetLinear(params.m_reverseGeometry);
      EmitFeatureBase(ft, params);
    }
  }

  template <class MakeFnT>
  void EmitArea(FeatureBuilderT & ft, FeatureParams params, MakeFnT makeFn)
  {
    using namespace feature;

    // Ensure that we have closed area geometry.
    if (ft.IsGeometryClosed())
    {
      // Key point here is that IsDrawableLike and RemoveNoDrawableTypes
      // work a bit different for GEOM_AREA.

      if (IsDrawableLike(params.m_Types, GEOM_AREA))
      {
        // Make the area feature if it has unique area styles.
        VERIFY(RemoveNoDrawableTypes(params.m_Types, GEOM_AREA), (params));

        makeFn(ft);

        EmitFeatureBase(ft, params);
      }
      else
      {
        // Try to make the point feature if it has point styles.
        EmitPoint(ft.GetGeometryCenter(), params, ft.GetLastOsmId());
      }
    }
  }
  //@}

public:
  /// The main entry point for parsing process.
  virtual void EmitElement(XMLElement * p)
  {
    FeatureParams params;
    if (!ParseType(p, params))
      return;

    if (p->tagKey == XMLElement::ET_NODE)
    {
      m2::PointD pt;
      if (p->childs.empty() || !GetPoint(p->id, pt))
        return;

      EmitPoint(pt, params, osm::Id::Node(p->id));
    }
    else if (p->tagKey == XMLElement::ET_WAY)
    {
      FeatureBuilderT ft;

      // Parse geometry.
      for (auto const & e : p->childs)
      {
        if (e.tagKey == XMLElement::ET_ND)
        {
          m2::PointD pt;
          if (!GetPoint(e.ref, pt))
            return;

          ft.AddPoint(pt);
        }
      }

      if (ft.GetPointsCount() < 2)
        return;

      ft.SetOsmId(osm::Id::Way(p->id));
      bool isCoastLine = (m_coastType != 0 && params.IsTypeExist(m_coastType));

      EmitArea(ft, params, [&] (FeatureBuilderT & ft)
      {
        isCoastLine = false;  // emit coastline feature only once
        multipolygon_holes_processor processor(p->id, this);
        m_holder.ForEachRelationByWay(p->id, processor);
        ft.SetAreaAddHoles(processor.GetHoles());
      });

      EmitLine(ft, params, isCoastLine);
    }
    else if (p->tagKey == XMLElement::ET_RELATION)
    {
      {
        // 1. Check, if this is our processable relation. Here we process only polygon relations.
        size_t i = 0;
        size_t const count = p->childs.size();
        for (; i < count; ++i)
        {
          if (p->childs[i].tagKey == XMLElement::ET_TAG &&
              p->childs[i].k == "type" &&
              p->childs[i].v == "multipolygon")
          {
            break;
          }
        }
        if (i == count)
          return;
      }

      holes_accumulator holes(this);
      AreaWayMerger<THolder> outer(m_holder);

      // 3. Iterate ways to get 'outer' and 'inner' geometries
      for (auto const & e : p->childs)
      {
        if (e.tagKey == XMLElement::ET_MEMBER && e.type == "way")
        {
          if (e.role == "outer")
            outer.AddWay(e.ref);
          else if (e.role == "inner")
            holes(e.ref);
        }
      }

      multipolygons_emitter emitter(this, params, holes.GetHoles(), p->id);
      outer.ForEachArea(emitter, true);
    }
  }

public:
  SecondPassParser(TEmitter & emitter, THolder & holder,
                   uint32_t coastType, string const & addrFilePath)
    : m_emitter(emitter), m_holder(holder), m_coastType(coastType)
  {
    if (!addrFilePath.empty())
      m_addrWriter.reset(new FileWriter(addrFilePath));
  }

  void Finish()
  {
    m_places.ForEach([this] (Place const & p)
    {
      m_emitter(p.GetFeature());
    });
  }
};
<commit_msg>[generator] Better “place-XXX” filtering according to the classificator type.<commit_after>#pragma once

#include "generator/osm2type.hpp"
#include "generator/xml_element.hpp"
#include "generator/feature_builder.hpp"
#include "generator/ways_merger.hpp"

#include "indexer/ftypes_matcher.hpp"
#include "indexer/feature_visibility.hpp"
#include "indexer/classificator.hpp"

#include "geometry/tree4d.hpp"

#include "base/string_utils.hpp"
#include "base/logging.hpp"
#include "base/stl_add.hpp"
#include "base/cache.hpp"

#include "std/unordered_set.hpp"
#include "std/list.hpp"

/// @param  TEmitter  Feature accumulating policy
/// @param  THolder   Nodes, ways, relations holder
template <class TEmitter, class THolder>
class SecondPassParser : public BaseOSMParser
{
  TEmitter & m_emitter;
  THolder & m_holder;

  bool GetPoint(uint64_t id, m2::PointD & pt) const
  {
    return m_holder.GetNode(id, pt.y, pt.x);
  }

  typedef vector<m2::PointD> pts_vec_t;
  typedef list<pts_vec_t> holes_list_t;

  class holes_accumulator
  {
    AreaWayMerger<THolder> m_merger;
    holes_list_t m_holes;

  public:
    holes_accumulator(SecondPassParser * pMain) : m_merger(pMain->m_holder) {}

    void operator() (uint64_t id)
    {
      m_merger.AddWay(id);
    }

    void operator() (pts_vec_t & v, vector<uint64_t> const &)
    {
      m_holes.push_back(pts_vec_t());
      m_holes.back().swap(v);
    }

    holes_list_t & GetHoles()
    {
      ASSERT ( m_holes.empty(), ("Can call only once") );
      m_merger.ForEachArea(*this, false);
      return m_holes;
    }
  };

  /// Find holes for way with 'id' in first relation.
  class multipolygon_holes_processor
  {
    uint64_t m_id;      ///< id of way to find it's holes
    holes_accumulator m_holes;

  public:
    multipolygon_holes_processor(uint64_t id, SecondPassParser * pMain)
      : m_id(id), m_holes(pMain)
    {
    }

    /// 1. relations process function
    bool operator() (uint64_t /*id*/, RelationElement const & e)
    {
      if (e.GetType() == "multipolygon")
      {
        string role;
        if (e.FindWay(m_id, role) && (role == "outer"))
        {
          e.ForEachWay(*this);
          // stop processing (??? assume that "outer way" exists in one relation only ???)
          return true;
        }
      }
      return false;
    }

    /// 2. "ways in relation" process function
    void operator() (uint64_t id, string const & role)
    {
      if (id != m_id && role == "inner")
        m_holes(id);
    }

    holes_list_t & GetHoles() { return m_holes.GetHoles(); }
  };

  /// Generated features should include parent relation tags to make
  /// full types matching and storing any additional info.
  class RelationTagsProcessor
  {
    uint64_t m_featureID;
    XMLElement * m_current;

    my::Cache<uint64_t, RelationElement> m_cache;

    bool IsAcceptBoundary(RelationElement const & e) const
    {
      string role;
      CHECK(e.FindWay(m_featureID, role), (m_featureID));

      // Do not accumulate boundary types (boundary=administrative) for inner polygons.
      // Example: Minsk city border (admin_level=8) is inner for Minsk area border (admin_level=4).
      return (role != "inner");
    }

    typedef unordered_set<string> NameKeysT;
    void GetNameKeys(NameKeysT & keys) const
    {
      for (auto const & p : m_current->childs)
        if (p.tagKey == XMLElement::ET_TAG)
        {
          if (strings::StartsWith(p.k, "name"))
            keys.insert(p.k);
        }
    }

    void Process(RelationElement const & e)
    {
      string const type = e.GetType();

      /// @todo Skip special relation types.
      if (type == "multipolygon" ||
          type == "route" ||
          type == "bridge" ||
          type == "restriction")
      {
        return;
      }

      bool const isWay = (m_current->tagKey == XMLElement::ET_WAY);
      bool const isBoundary = isWay && (type == "boundary") && IsAcceptBoundary(e);

      NameKeysT nameKeys;
      GetNameKeys(nameKeys);

      for (auto const & p : e.tags)
      {
        /// @todo Skip common key tags.
        if (p.first == "type" || p.first == "route")
          continue;

        /// Skip already existing "name" tags.
        if (nameKeys.count(p.first) != 0)
          continue;

        if (!isBoundary && p.first == "boundary")
          continue;

        if (isWay && p.first == "place")
          continue;

        m_current->AddKV(p.first, p.second);
      }
    }

  public:
    RelationTagsProcessor()
      : m_cache(14)
    {
    }

    void Reset(uint64_t fID, XMLElement * p)
    {
      m_featureID = fID;
      m_current = p;
    }

    template <class ReaderT> bool operator() (uint64_t id, ReaderT & reader)
    {
      bool exists = false;
      RelationElement & e = m_cache.Find(id, exists);
      if (!exists)
        CHECK(reader.Read(id, e), (id));

      Process(e);
      return false;
    }

  } m_relationsProcess;

  bool ParseType(XMLElement * p, FeatureParams & params)
  {
    // Get tags from parent relations.
    m_relationsProcess.Reset(p->id, p);

    if (p->tagKey == XMLElement::ET_NODE)
    {
      // additional process of nodes ONLY if there is no native types
      FeatureParams fp;
      ftype::GetNameAndType(p, fp);
      if (!ftype::IsValidTypes(fp))
        m_holder.ForEachRelationByNodeCached(p->id, m_relationsProcess);
    }
    else if (p->tagKey == XMLElement::ET_WAY)
    {
      // always make additional process of ways
      m_holder.ForEachRelationByWayCached(p->id, m_relationsProcess);
    }

    // Get params from element tags.
    ftype::GetNameAndType(p, params);
    params.FinishAddingTypes();
    return ftype::IsValidTypes(params);
  }

  typedef FeatureBuilder1 FeatureBuilderT;

  class multipolygons_emitter
  {
    SecondPassParser * m_pMain;
    FeatureParams const & m_params;
    holes_list_t & m_holes;
    uint64_t m_relID;

  public:
    multipolygons_emitter(SecondPassParser * pMain,
                          FeatureParams const & params,
                          holes_list_t & holes,
                          uint64_t relID)
      : m_pMain(pMain), m_params(params), m_holes(holes), m_relID(relID)
    {
    }

    void operator() (pts_vec_t const & pts, vector<uint64_t> const & ids)
    {
      FeatureBuilderT ft;

      for (size_t i = 0; i < ids.size(); ++i)
        ft.AddOsmId(osm::Id::Way(ids[i]));

      for (size_t i = 0; i < pts.size(); ++i)
        ft.AddPoint(pts[i]);

      ft.AddOsmId(osm::Id::Relation(m_relID));
      m_pMain->EmitArea(ft, m_params, [this] (FeatureBuilderT & ft)
      {
        ft.SetAreaAddHoles(m_holes);
      });
    }
  };

  uint32_t m_coastType;

  unique_ptr<FileWriter> m_addrWriter;
  bool NeedWriteAddress(FeatureParams const & params) const
  {
    return m_addrWriter && ftypes::IsBuildingChecker::Instance()(params.m_Types);
  }

  class Place
  {
    FeatureBuilderT m_ft;
    m2::PointD m_pt;
    uint32_t m_type;

    static constexpr double EQUAL_PLACE_SEARCH_RADIUS_M = 20000.0;

    bool IsPoint() const { return (m_ft.GetGeomType() == feature::GEOM_POINT); }
    static bool IsEqualTypes(uint32_t t1, uint32_t t2)
    {
      // Use 2-arity places comparison for filtering.
      // ("place-city-capital-2" is equal to "place-city")
      ftype::TruncValue(t1, 2);
      ftype::TruncValue(t2, 2);
      return (t1 == t2);
    }

  public:
    Place(FeatureBuilderT const & ft, uint32_t type)
      : m_ft(ft), m_pt(ft.GetKeyPoint()), m_type(type)
    {
    }

    FeatureBuilderT const & GetFeature() const { return m_ft; }

    m2::RectD GetLimitRect() const
    {
      return MercatorBounds::RectByCenterXYAndSizeInMeters(m_pt, EQUAL_PLACE_SEARCH_RADIUS_M);
    }

    bool IsEqual(Place const & r) const
    {
      return (IsEqualTypes(m_type, r.m_type) &&
              m_ft.GetName() == r.m_ft.GetName() &&
              (IsPoint() || r.IsPoint()) &&
              MercatorBounds::DistanceOnEarth(m_pt, r.m_pt) < EQUAL_PLACE_SEARCH_RADIUS_M);
    }

    /// Check whether we need to replace place @r with place @this.
    bool IsBetterThan(Place const & r) const
    {
      // Area places has priority before point places.
      if (!r.IsPoint())
        return false;
      if (!IsPoint())
        return true;

      // Check types length.
      // ("place-city-capital-2" is better than "place-city").
      uint8_t const l1 = ftype::GetLevel(m_type);
      uint8_t const l2 = ftype::GetLevel(r.m_type);
      if (l1 != l2)
        return (l2 < l1);

      // Check ranks.
      return (r.m_ft.GetRank() < m_ft.GetRank());
    }
  };

  m4::Tree<Place> m_places;

  void EmitFeatureBase(FeatureBuilderT & ft, FeatureParams const & params)
  {
    ft.SetParams(params);
    if (ft.PreSerialize())
    {
      string addr;
      if (NeedWriteAddress(params) && ft.FormatFullAddress(addr))
        m_addrWriter->Write(addr.c_str(), addr.size());

      static uint32_t const placeType = classif().GetTypeByPath({"place"});
      uint32_t const type = params.FindType(placeType, 1);

      if (type != ftype::GetEmptyValue() && !ft.GetName().empty())
      {
        m_places.ReplaceEqualInRect(Place(ft, type),
                                    bind(&Place::IsEqual, _1, _2),
                                    bind(&Place::IsBetterThan, _1, _2));
      }
      else
        m_emitter(ft);
    }
  }

  /// @param[in]  params  Pass by value because it can be modified.
  //@{
  void EmitPoint(m2::PointD const & pt, FeatureParams params, osm::Id id)
  {
    if (feature::RemoveNoDrawableTypes(params.m_Types, feature::GEOM_POINT))
    {
      FeatureBuilderT ft;
      ft.SetCenter(pt);
      ft.SetOsmId(id);
      EmitFeatureBase(ft, params);
    }
  }

  void EmitLine(FeatureBuilderT & ft, FeatureParams params, bool isCoastLine)
  {
    if (isCoastLine || feature::RemoveNoDrawableTypes(params.m_Types, feature::GEOM_LINE))
    {
      ft.SetLinear(params.m_reverseGeometry);
      EmitFeatureBase(ft, params);
    }
  }

  template <class MakeFnT>
  void EmitArea(FeatureBuilderT & ft, FeatureParams params, MakeFnT makeFn)
  {
    using namespace feature;

    // Ensure that we have closed area geometry.
    if (ft.IsGeometryClosed())
    {
      // Key point here is that IsDrawableLike and RemoveNoDrawableTypes
      // work a bit different for GEOM_AREA.

      if (IsDrawableLike(params.m_Types, GEOM_AREA))
      {
        // Make the area feature if it has unique area styles.
        VERIFY(RemoveNoDrawableTypes(params.m_Types, GEOM_AREA), (params));

        makeFn(ft);

        EmitFeatureBase(ft, params);
      }
      else
      {
        // Try to make the point feature if it has point styles.
        EmitPoint(ft.GetGeometryCenter(), params, ft.GetLastOsmId());
      }
    }
  }
  //@}

public:
  /// The main entry point for parsing process.
  virtual void EmitElement(XMLElement * p)
  {
    FeatureParams params;
    if (!ParseType(p, params))
      return;

    if (p->tagKey == XMLElement::ET_NODE)
    {
      m2::PointD pt;
      if (p->childs.empty() || !GetPoint(p->id, pt))
        return;

      EmitPoint(pt, params, osm::Id::Node(p->id));
    }
    else if (p->tagKey == XMLElement::ET_WAY)
    {
      FeatureBuilderT ft;

      // Parse geometry.
      for (auto const & e : p->childs)
      {
        if (e.tagKey == XMLElement::ET_ND)
        {
          m2::PointD pt;
          if (!GetPoint(e.ref, pt))
            return;

          ft.AddPoint(pt);
        }
      }

      if (ft.GetPointsCount() < 2)
        return;

      ft.SetOsmId(osm::Id::Way(p->id));
      bool isCoastLine = (m_coastType != 0 && params.IsTypeExist(m_coastType));

      EmitArea(ft, params, [&] (FeatureBuilderT & ft)
      {
        isCoastLine = false;  // emit coastline feature only once
        multipolygon_holes_processor processor(p->id, this);
        m_holder.ForEachRelationByWay(p->id, processor);
        ft.SetAreaAddHoles(processor.GetHoles());
      });

      EmitLine(ft, params, isCoastLine);
    }
    else if (p->tagKey == XMLElement::ET_RELATION)
    {
      {
        // 1. Check, if this is our processable relation. Here we process only polygon relations.
        size_t i = 0;
        size_t const count = p->childs.size();
        for (; i < count; ++i)
        {
          if (p->childs[i].tagKey == XMLElement::ET_TAG &&
              p->childs[i].k == "type" &&
              p->childs[i].v == "multipolygon")
          {
            break;
          }
        }
        if (i == count)
          return;
      }

      holes_accumulator holes(this);
      AreaWayMerger<THolder> outer(m_holder);

      // 3. Iterate ways to get 'outer' and 'inner' geometries
      for (auto const & e : p->childs)
      {
        if (e.tagKey == XMLElement::ET_MEMBER && e.type == "way")
        {
          if (e.role == "outer")
            outer.AddWay(e.ref);
          else if (e.role == "inner")
            holes(e.ref);
        }
      }

      multipolygons_emitter emitter(this, params, holes.GetHoles(), p->id);
      outer.ForEachArea(emitter, true);
    }
  }

public:
  SecondPassParser(TEmitter & emitter, THolder & holder,
                   uint32_t coastType, string const & addrFilePath)
    : m_emitter(emitter), m_holder(holder), m_coastType(coastType)
  {
    if (!addrFilePath.empty())
      m_addrWriter.reset(new FileWriter(addrFilePath));
  }

  void Finish()
  {
    m_places.ForEach([this] (Place const & p)
    {
      m_emitter(p.GetFeature());
    });
  }
};
<|endoftext|>


<commit_before>#include "http/URLParser.hpp"
#include <cstring>

using std::string;

char hexToChar(char hex1, char hex2) {
    return (hex1 - '0') * 16 + (hex2 - '0');
}

bool decodeURLEntities(const char* in, size_t length, std::string& out) {
    out.clear();
    out.reserve(length);
    for (size_t i = 0; i < length; i++) {
        if (in[i] == '%') {
            if (i + 3 <= length) {
                int value = 0;
                out += hexToChar(in[i+1], in[i+2]);
                i += 2;
            } else {
                return false;
            }
        } else if (in[i] == '+') {
            out += ' ';
        } else {
            out += in[i];
        }
    }
    return true;
}

std::string decodeURLEntities(const char* in, size_t length) {
    std::string ret;
    if(!decodeURLEntities(in, length, ret)) {
        return ""; //On error
    }
    return ret;
}

bool decodeURLEntities(const std::string& in, std::string& out) {
    return decodeURLEntities(in.data(), in.size(), out);
}

void parseQueryPart(const char* query, std::map<std::string, std::string>& map) {
    //Skip '?' at the beginning, if any
    if(query[0] == '?') {
        query++;
    }

    while(true) {
        char* kvSeparator = strchr(query, '=');
        if(kvSeparator == nullptr) {
            //No separator -- no argument left
            //This branch won't execute for correct inputs
            break;
        }
        char* argSeparator = strchr(kvSeparator, '&');
        string key = decodeURLEntities(query, (kvSeparator - query));
        if(argSeparator == nullptr) {
            //last argument
            map[key] = decodeURLEntities(kvSeparator + 1, strlen(kvSeparator + 1));
            break;
        } else {
            map[key] = decodeURLEntities(kvSeparator + 1, argSeparator - kvSeparator - 1);
        }
        query = argSeparator + 1;
    }
}<commit_msg>Fix const char problems<commit_after>#include "http/URLParser.hpp"
#include <cstring>

using std::string;

char hexToChar(char hex1, char hex2) {
    return (hex1 - '0') * 16 + (hex2 - '0');
}

bool decodeURLEntities(const char* in, size_t length, std::string& out) {
    out.clear();
    out.reserve(length);
    for (size_t i = 0; i < length; i++) {
        if (in[i] == '%') {
            if (i + 3 <= length) {
                int value = 0;
                out += hexToChar(in[i+1], in[i+2]);
                i += 2;
            } else {
                return false;
            }
        } else if (in[i] == '+') {
            out += ' ';
        } else {
            out += in[i];
        }
    }
    return true;
}

std::string decodeURLEntities(const char* in, size_t length) {
    std::string ret;
    if(!decodeURLEntities(in, length, ret)) {
        return ""; //On error
    }
    return ret;
}

bool decodeURLEntities(const std::string& in, std::string& out) {
    return decodeURLEntities(in.data(), in.size(), out);
}

void parseQueryPart(const char* query, std::map<std::string, std::string>& map) {
    //Skip '?' at the beginning, if any
    if(query[0] == '?') {
        query++;
    }

    while(true) {
        const char* kvSeparator = strchr(query, '=');
        if(kvSeparator == nullptr) {
            //No separator -- no argument left
            //This branch won't execute for correct inputs
            break;
        }
        const char* argSeparator = strchr(kvSeparator, '&');
        string key = decodeURLEntities(query, (kvSeparator - query));
        if(argSeparator == nullptr) {
            //last argument
            map[key] = decodeURLEntities(kvSeparator + 1, strlen(kvSeparator + 1));
            break;
        } else {
            map[key] = decodeURLEntities(kvSeparator + 1, argSeparator - kvSeparator - 1);
        }
        query = argSeparator + 1;
    }
}<|endoftext|>


<commit_before>// Copyright 2016 AUV-IITK
#include <ros.h>
#include <Arduino.h>
#include <std_msgs/Int32.h>
#include <std_msgs/Float64.h>
#include <math.h>

#define pwmPinWest 3
#define pwmPinEast 2
#define directionPinWest1 30
#define directionPinWest2 31
#define directionPinEast1 33
#define directionPinEast2 32

#define pwmPinNorthSway 5
#define pwmPinSouthSway 4
#define directionPinNorthSway1 26
#define directionPinNorthSway2 27
#define directionPinSouthSway1 28
#define directionPinSouthSway2 29

#define pwmPinNorthUp 6
#define pwmPinSouthUp 7
#define directionPinNorthUp1 24
#define directionPinNorthUp2 25
#define directionPinSouthUp1 22
#define directionPinSouthUp2 23

#define analogPinPressureSensor A0

const float c092 = 506.22;
const float s092 = -2.65;
const float c093 = 448.62;
const float s093 = -2.92;
const float c099 = 397.65;   // reference as their graph is at lowest
const float s099 = -2.71;  // reference as their graph is at lowest
const float c113 = 539.85;
const float s113 = -3.38;
const float c117 = 441.32;
const float s117 = -3.03;
const float c122 = 547.39;
const float s122 = -2.93;

float k092 = 0;
float k093 = 0;
float k099 = 0;
float k113 = 0;
float k117 = 0;
float k122 = 0;

int count, sum;
bool isMovingForward = true;
float v;
std_msgs::Float64 voltage;
ros::NodeHandle nh;

int NormalizePWM(int pwm)
{
  return pwm * 53 / 255 + 147;
}

int NormalizeUpwardPWM(int pwm)
{
  return pwm * 73 / 255 + 147;
}

int btd092(int pwm)
{
  pwm = NormalizePWM(pwm);
  if (pwm <= 147)
  {
    return 0;
  }
  pwm = (c099 + k092 + s099 * pwm - c092) / (s092);
  return pwm;
}

int btd093(int pwm)
{
  pwm = NormalizeUpwardPWM(pwm);
  if (pwm <= 147)
  {
    return 0;
  }
  pwm = (c099 + k093 + s099 * pwm - c093) / (s093);
  return pwm;
}

int btd099(int pwm)
{
  pwm = NormalizePWM(pwm);
  if (pwm <= 147)
  {
    return 0;
  }
  return pwm;
}

int btd113(int pwm)
{
  pwm = NormalizePWM(pwm);
  if (pwm <= 147)
  {
    return 0;
  }
  pwm = (c099 + k113 + s099 * pwm - c113) / (s113);
  return pwm;
}

int btd117(int pwm)
{
  pwm = NormalizeUpwardPWM(pwm);
  if (pwm <= 147)
  {
    return 0;
  }
  pwm = (c099 + k117 + s099 * pwm - c117) / (s117);
  return pwm;
}

int btd122(int pwm)
{
  pwm = NormalizePWM(pwm);
  if (pwm <= 147)
  {
    return 0;
  }
  pwm = (c099 + k122 + s099 * pwm - c122) / (s122);
  return pwm;
}

void thrusterNorthUp(int pwm, int isUpward)
{
  pwm = abs(pwm);
  pwm = btd117(pwm);
  analogWrite(pwmPinNorthUp, 255 - pwm);
  if (isUpward)
  {
    digitalWrite(directionPinNorthUp1, HIGH);
    digitalWrite(directionPinNorthUp2, LOW);
  }
  else
  {
    digitalWrite(directionPinNorthUp1, LOW);
    digitalWrite(directionPinNorthUp2, HIGH);
  }
}

void thrusterSouthUp(int pwm, int isUpward)
{
  pwm = abs(pwm);
  pwm = btd093(pwm);
  analogWrite(pwmPinSouthUp, 255 - pwm);
  if (isUpward)
  {
    digitalWrite(directionPinSouthUp1, HIGH);
    digitalWrite(directionPinSouthUp2, LOW);
  }
  else
  {
    digitalWrite(directionPinSouthUp1, LOW);
    digitalWrite(directionPinSouthUp2, HIGH);
  }
}

void thrusterNorthSway(int pwm, int isRight)
{
  pwm = abs(pwm);
  pwm = btd113(pwm);
  analogWrite(pwmPinNorthSway, 255 - pwm);
  if (isRight)
  {
    digitalWrite(directionPinNorthSway1, HIGH);
    digitalWrite(directionPinNorthSway2, LOW);
  }
  else
  {
    digitalWrite(directionPinNorthSway1, LOW);
    digitalWrite(directionPinNorthSway2, HIGH);
  }
}

void thrusterSouthSway(int pwm, int isRight)
{
  pwm = abs(pwm);
  pwm = btd122(pwm);
  analogWrite(pwmPinSouthSway, 255 - pwm);
  if (isRight)
  {
    digitalWrite(directionPinSouthSway1, HIGH);
    digitalWrite(directionPinSouthSway2, LOW);
  }
  else
  {
    digitalWrite(directionPinSouthSway1, LOW);
    digitalWrite(directionPinSouthSway2, HIGH);
  }
}

void thrusterEast(int pwm, int isForward)
{
  pwm = abs(pwm);
  pwm = btd092(pwm);
  analogWrite(pwmPinEast, 255 - pwm);
  if (isForward)
  {
    digitalWrite(directionPinEast1, HIGH);
    digitalWrite(directionPinEast2, LOW);
  }
  else
  {
    digitalWrite(directionPinEast1, LOW);
    digitalWrite(directionPinEast2, HIGH);
  }
}

void thrusterWest(int pwm, int isForward)
{
  pwm = abs(pwm);
  pwm = btd099(pwm);
  analogWrite(pwmPinWest, 255 - pwm);
  if (isForward)
  {
    digitalWrite(directionPinWest1, HIGH);
    digitalWrite(directionPinWest2, LOW);
  }
  else
  {
    digitalWrite(directionPinWest1, LOW);
    digitalWrite(directionPinWest2, HIGH);
  }
}

void PWMCbForward(const std_msgs::Int32& msg)
{
  if (msg.data > 0)
  {
    thrusterEast(msg.data, true);
    thrusterWest(msg.data, true);
  }
  else
  {
    thrusterEast(msg.data, false);
    thrusterWest(msg.data, false);
  }
  isMovingForward = true;
}

void PWMCbSideward(const std_msgs::Int32& msg)
{
  if (msg.data > 0)
  {
    thrusterNorthSway(msg.data, true);
    thrusterSouthSway(msg.data, true);
  }
  else
  {
    thrusterNorthSway(msg.data, false);
    thrusterSouthSway(msg.data, false);
  }
  isMovingForward = false;
}

void PWMCbUpward(const std_msgs::Int32& msg)
{
  if (msg.data > 0)
  {
    thrusterNorthUp(msg.data, true);
    thrusterSouthUp(msg.data, true);
  }
  else
  {
    thrusterNorthUp(msg.data, false);
    thrusterSouthUp(msg.data, false);
  }
}

void PWMCbTurn(const std_msgs::Int32& msg)
{
  if (!isMovingForward)
  {
    if (msg.data > 0)
    {
      thrusterEast(msg.data, true);
      thrusterWest(msg.data, false);
    }
    else
    {
      thrusterEast(msg.data, false);
      thrusterWest(msg.data, true);
    }
  }
  else
  {
    if (msg.data > 0)
    {
      thrusterNorthSway(msg.data, false);
      thrusterSouthSway(msg.data, true);
    }
    else
    {
      thrusterNorthSway(msg.data, true);
      thrusterSouthSway(msg.data, false);
    }
  }
}

void thrust092(const std_msgs::Float64& msg)
{
  k092 = msg.data;
}

void thrust093(const std_msgs::Float64& msg)
{
  k093 = msg.data;
}

void thrust099(const std_msgs::Float64& msg)
{
  k099 = msg.data;
}

void thrust113(const std_msgs::Float64& msg)
{
  k113 = msg.data;
}

void thrust117(const std_msgs::Float64& msg)
{
  k117 = msg.data;
}

void thrust122(const std_msgs::Float64& msg)
{
  k122 = msg.data;
}

ros::Subscriber<std_msgs::Int32> subPwmForward("/pwm/forward", &PWMCbForward);
ros::Subscriber<std_msgs::Int32> subPwmSideward("/pwm/sideward", &PWMCbSideward);
ros::Subscriber<std_msgs::Int32> subPwmUpward("/pwm/upward", &PWMCbUpward);
ros::Subscriber<std_msgs::Int32> subPwmTurn("/pwm/turn", &PWMCbTurn);
ros::Publisher ps_voltage("/varun/sensors/pressure_sensor/depth", &voltage);

ros::Subscriber<std_msgs::Float64> thruster092("/thrust/092", &thrust092);
ros::Subscriber<std_msgs::Float64> thruster093("/thrust/093", &thrust093);
ros::Subscriber<std_msgs::Float64> thruster099("/thrust/099", &thrust099);
ros::Subscriber<std_msgs::Float64> thruster113("/thrust/113", &thrust113);
ros::Subscriber<std_msgs::Float64> thruster117("/thrust/117", &thrust117);
ros::Subscriber<std_msgs::Float64> thruster122("/thrust/122", &thrust122);

void setup()
{
  nh.initNode();

  pinMode(pwmPinEast, OUTPUT);
  pinMode(directionPinEast1, OUTPUT);
  pinMode(directionPinEast2, OUTPUT);
  pinMode(pwmPinWest, OUTPUT);
  pinMode(directionPinWest1, OUTPUT);
  pinMode(directionPinWest2, OUTPUT);

  pinMode(directionPinSouthSway1, OUTPUT);
  pinMode(directionPinSouthSway2, OUTPUT);
  pinMode(pwmPinNorthSway, OUTPUT);
  pinMode(directionPinNorthSway2, OUTPUT);
  pinMode(pwmPinSouthSway, OUTPUT);
  pinMode(directionPinNorthSway1, OUTPUT);

  pinMode(directionPinSouthUp1, OUTPUT);
  pinMode(directionPinSouthUp2, OUTPUT);
  pinMode(pwmPinNorthUp, OUTPUT);
  pinMode(directionPinNorthUp2, OUTPUT);
  pinMode(pwmPinSouthUp, OUTPUT);
  pinMode(directionPinNorthUp1, OUTPUT);

  nh.subscribe(subPwmForward);
  nh.subscribe(subPwmSideward);
  nh.subscribe(subPwmUpward);
  nh.subscribe(subPwmTurn);
  nh.advertise(ps_voltage);
  Serial.begin(57600);
  std_msgs::Int32 msg;
  msg.data = 0;
  PWMCbForward(msg);
  PWMCbSideward(msg);
  PWMCbUpward(msg);
  PWMCbTurn(msg);
  count = 0;
  sum = 0;

  nh.subscribe(thruster092);
  nh.subscribe(thruster093);
  nh.subscribe(thruster099);
  nh.subscribe(thruster113);
  nh.subscribe(thruster117);
  nh.subscribe(thruster122);
}

void loop()
{
  if (count == 100)
  {
    sum /= count;
    voltage.data = -sum;  // negative because convention is to take upward direction as positive
    ps_voltage.publish(&voltage);
    sum = 0;
    count = 0;
  }
  else
  {
    v = analogRead(analogPinPressureSensor);
    sum += v;
    count++;
    delay(1);
  }
  nh.spinOnce();
}
<commit_msg>made anticlockwise positive<commit_after>// Copyright 2016 AUV-IITK
#include <ros.h>
#include <Arduino.h>
#include <std_msgs/Int32.h>
#include <std_msgs/Float64.h>
#include <math.h>

#define pwmPinWest 3
#define pwmPinEast 2
#define directionPinWest1 30
#define directionPinWest2 31
#define directionPinEast1 33
#define directionPinEast2 32

#define pwmPinNorthSway 5
#define pwmPinSouthSway 4
#define directionPinNorthSway1 26
#define directionPinNorthSway2 27
#define directionPinSouthSway1 28
#define directionPinSouthSway2 29

#define pwmPinNorthUp 6
#define pwmPinSouthUp 7
#define directionPinNorthUp1 24
#define directionPinNorthUp2 25
#define directionPinSouthUp1 22
#define directionPinSouthUp2 23

#define analogPinPressureSensor A0

const float c092 = 506.22;
const float s092 = -2.65;
const float c093 = 448.62;
const float s093 = -2.92;
const float c099 = 397.65;   // reference as their graph is at lowest
const float s099 = -2.71;  // reference as their graph is at lowest
const float c113 = 539.85;
const float s113 = -3.38;
const float c117 = 441.32;
const float s117 = -3.03;
const float c122 = 547.39;
const float s122 = -2.93;

float k092 = 0;
float k093 = 0;
float k099 = 0;
float k113 = 0;
float k117 = 0;
float k122 = 0;

int count, sum;
bool isMovingForward = true;
float v;
std_msgs::Float64 voltage;
ros::NodeHandle nh;

int NormalizePWM(int pwm)
{
  return pwm * 53 / 255 + 147;
}

int NormalizeUpwardPWM(int pwm)
{
  return pwm * 73 / 255 + 147;
}

int btd092(int pwm)
{
  pwm = NormalizePWM(pwm);
  if (pwm <= 147)
  {
    return 0;
  }
  pwm = (c099 + k092 + s099 * pwm - c092) / (s092);
  return pwm;
}

int btd093(int pwm)
{
  pwm = NormalizeUpwardPWM(pwm);
  if (pwm <= 147)
  {
    return 0;
  }
  pwm = (c099 + k093 + s099 * pwm - c093) / (s093);
  return pwm;
}

int btd099(int pwm)
{
  pwm = NormalizePWM(pwm);
  if (pwm <= 147)
  {
    return 0;
  }
  return pwm;
}

int btd113(int pwm)
{
  pwm = NormalizePWM(pwm);
  if (pwm <= 147)
  {
    return 0;
  }
  pwm = (c099 + k113 + s099 * pwm - c113) / (s113);
  return pwm;
}

int btd117(int pwm)
{
  pwm = NormalizeUpwardPWM(pwm);
  if (pwm <= 147)
  {
    return 0;
  }
  pwm = (c099 + k117 + s099 * pwm - c117) / (s117);
  return pwm;
}

int btd122(int pwm)
{
  pwm = NormalizePWM(pwm);
  if (pwm <= 147)
  {
    return 0;
  }
  pwm = (c099 + k122 + s099 * pwm - c122) / (s122);
  return pwm;
}

void thrusterNorthUp(int pwm, int isUpward)
{
  pwm = abs(pwm);
  pwm = btd117(pwm);
  analogWrite(pwmPinNorthUp, 255 - pwm);
  if (isUpward)
  {
    digitalWrite(directionPinNorthUp1, HIGH);
    digitalWrite(directionPinNorthUp2, LOW);
  }
  else
  {
    digitalWrite(directionPinNorthUp1, LOW);
    digitalWrite(directionPinNorthUp2, HIGH);
  }
}

void thrusterSouthUp(int pwm, int isUpward)
{
  pwm = abs(pwm);
  pwm = btd093(pwm);
  analogWrite(pwmPinSouthUp, 255 - pwm);
  if (isUpward)
  {
    digitalWrite(directionPinSouthUp1, HIGH);
    digitalWrite(directionPinSouthUp2, LOW);
  }
  else
  {
    digitalWrite(directionPinSouthUp1, LOW);
    digitalWrite(directionPinSouthUp2, HIGH);
  }
}

void thrusterNorthSway(int pwm, int isRight)
{
  pwm = abs(pwm);
  pwm = btd113(pwm);
  analogWrite(pwmPinNorthSway, 255 - pwm);
  if (isRight)
  {
    digitalWrite(directionPinNorthSway1, HIGH);
    digitalWrite(directionPinNorthSway2, LOW);
  }
  else
  {
    digitalWrite(directionPinNorthSway1, LOW);
    digitalWrite(directionPinNorthSway2, HIGH);
  }
}

void thrusterSouthSway(int pwm, int isRight)
{
  pwm = abs(pwm);
  pwm = btd122(pwm);
  analogWrite(pwmPinSouthSway, 255 - pwm);
  if (isRight)
  {
    digitalWrite(directionPinSouthSway1, HIGH);
    digitalWrite(directionPinSouthSway2, LOW);
  }
  else
  {
    digitalWrite(directionPinSouthSway1, LOW);
    digitalWrite(directionPinSouthSway2, HIGH);
  }
}

void thrusterEast(int pwm, int isForward)
{
  pwm = abs(pwm);
  pwm = btd092(pwm);
  analogWrite(pwmPinEast, 255 - pwm);
  if (isForward)
  {
    digitalWrite(directionPinEast1, HIGH);
    digitalWrite(directionPinEast2, LOW);
  }
  else
  {
    digitalWrite(directionPinEast1, LOW);
    digitalWrite(directionPinEast2, HIGH);
  }
}

void thrusterWest(int pwm, int isForward)
{
  pwm = abs(pwm);
  pwm = btd099(pwm);
  analogWrite(pwmPinWest, 255 - pwm);
  if (isForward)
  {
    digitalWrite(directionPinWest1, HIGH);
    digitalWrite(directionPinWest2, LOW);
  }
  else
  {
    digitalWrite(directionPinWest1, LOW);
    digitalWrite(directionPinWest2, HIGH);
  }
}

void PWMCbForward(const std_msgs::Int32& msg)
{
  if (msg.data > 0)
  {
    thrusterEast(msg.data, true);
    thrusterWest(msg.data, true);
  }
  else
  {
    thrusterEast(msg.data, false);
    thrusterWest(msg.data, false);
  }
  isMovingForward = true;
}

void PWMCbSideward(const std_msgs::Int32& msg)
{
  if (msg.data > 0)
  {
    thrusterNorthSway(msg.data, true);
    thrusterSouthSway(msg.data, true);
  }
  else
  {
    thrusterNorthSway(msg.data, false);
    thrusterSouthSway(msg.data, false);
  }
  isMovingForward = false;
}

void PWMCbUpward(const std_msgs::Int32& msg)
{
  if (msg.data > 0)
  {
    thrusterNorthUp(msg.data, true);
    thrusterSouthUp(msg.data, true);
  }
  else
  {
    thrusterNorthUp(msg.data, false);
    thrusterSouthUp(msg.data, false);
  }
}

void PWMCbTurn(const std_msgs::Int32& msg)
{
  if (!isMovingForward)
  {
    if (msg.data < 0)
    {
      thrusterEast(msg.data, true);
      thrusterWest(msg.data, false);
    }
    else
    {
      thrusterEast(msg.data, false);
      thrusterWest(msg.data, true);
    }
  }
  else
  {
    if (msg.data > 0)
    {
      thrusterNorthSway(msg.data, false);
      thrusterSouthSway(msg.data, true);
    }
    else
    {
      thrusterNorthSway(msg.data, true);
      thrusterSouthSway(msg.data, false);
    }
  }
}

void thrust092(const std_msgs::Float64& msg)
{
  k092 = msg.data;
}

void thrust093(const std_msgs::Float64& msg)
{
  k093 = msg.data;
}

void thrust099(const std_msgs::Float64& msg)
{
  k099 = msg.data;
}

void thrust113(const std_msgs::Float64& msg)
{
  k113 = msg.data;
}

void thrust117(const std_msgs::Float64& msg)
{
  k117 = msg.data;
}

void thrust122(const std_msgs::Float64& msg)
{
  k122 = msg.data;
}

ros::Subscriber<std_msgs::Int32> subPwmForward("/pwm/forward", &PWMCbForward);
ros::Subscriber<std_msgs::Int32> subPwmSideward("/pwm/sideward", &PWMCbSideward);
ros::Subscriber<std_msgs::Int32> subPwmUpward("/pwm/upward", &PWMCbUpward);
ros::Subscriber<std_msgs::Int32> subPwmTurn("/pwm/turn", &PWMCbTurn);
ros::Publisher ps_voltage("/varun/sensors/pressure_sensor/depth", &voltage);

ros::Subscriber<std_msgs::Float64> thruster092("/thrust/092", &thrust092);
ros::Subscriber<std_msgs::Float64> thruster093("/thrust/093", &thrust093);
ros::Subscriber<std_msgs::Float64> thruster099("/thrust/099", &thrust099);
ros::Subscriber<std_msgs::Float64> thruster113("/thrust/113", &thrust113);
ros::Subscriber<std_msgs::Float64> thruster117("/thrust/117", &thrust117);
ros::Subscriber<std_msgs::Float64> thruster122("/thrust/122", &thrust122);

void setup()
{
  nh.initNode();

  pinMode(pwmPinEast, OUTPUT);
  pinMode(directionPinEast1, OUTPUT);
  pinMode(directionPinEast2, OUTPUT);
  pinMode(pwmPinWest, OUTPUT);
  pinMode(directionPinWest1, OUTPUT);
  pinMode(directionPinWest2, OUTPUT);

  pinMode(directionPinSouthSway1, OUTPUT);
  pinMode(directionPinSouthSway2, OUTPUT);
  pinMode(pwmPinNorthSway, OUTPUT);
  pinMode(directionPinNorthSway2, OUTPUT);
  pinMode(pwmPinSouthSway, OUTPUT);
  pinMode(directionPinNorthSway1, OUTPUT);

  pinMode(directionPinSouthUp1, OUTPUT);
  pinMode(directionPinSouthUp2, OUTPUT);
  pinMode(pwmPinNorthUp, OUTPUT);
  pinMode(directionPinNorthUp2, OUTPUT);
  pinMode(pwmPinSouthUp, OUTPUT);
  pinMode(directionPinNorthUp1, OUTPUT);

  nh.subscribe(subPwmForward);
  nh.subscribe(subPwmSideward);
  nh.subscribe(subPwmUpward);
  nh.subscribe(subPwmTurn);
  nh.advertise(ps_voltage);
  Serial.begin(57600);
  std_msgs::Int32 msg;
  msg.data = 0;
  PWMCbForward(msg);
  PWMCbSideward(msg);
  PWMCbUpward(msg);
  PWMCbTurn(msg);
  count = 0;
  sum = 0;

  nh.subscribe(thruster092);
  nh.subscribe(thruster093);
  nh.subscribe(thruster099);
  nh.subscribe(thruster113);
  nh.subscribe(thruster117);
  nh.subscribe(thruster122);
}

void loop()
{
  if (count == 100)
  {
    sum /= count;
    voltage.data = -sum;  // negative because convention is to take upward direction as positive
    ps_voltage.publish(&voltage);
    sum = 0;
    count = 0;
  }
  else
  {
    v = analogRead(analogPinPressureSensor);
    sum += v;
    count++;
    delay(1);
  }
  nh.spinOnce();
}
<|endoftext|>


<commit_before>/*
 *            Copyright 2009-2018 The VOTCA Development Team
 *                       (http://www.votca.org)
 *
 *      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.
 *
 */

#include <set>
#include <vector>
#include <exception>
#include <votca/tools/edge.h>
#include <votca/tools/edgecontainer.h>
#include <algorithm>

using namespace votca::tools;
using namespace std;

EdgeContainer::EdgeContainer(Edge ed) { addEdge(ed); }

EdgeContainer::EdgeContainer(vector<Edge> eds) {
  for (auto ed : eds) {
    addEdge(ed);
  }
}

int EdgeContainer::getMaxDegree(void) const{
  int max = 0;
  for(auto const& it : adj_list_) {
    if(it.second.size()>static_cast<size_t>(max)) {
      max = static_cast<int>(it.second.size());
    }
  }
  return max;
}

int EdgeContainer::getDegree(const int vert) const{
  if(!adj_list_.count(vert)) throw invalid_argument("vertex is not defined");
  return static_cast<int>(adj_list_.at(vert).size());
}

vector<int> EdgeContainer::getVerticesDegree(int degree) const{
  vector<int> verts;
  for(auto v_list : adj_list_){
    if(static_cast<int>(v_list.second.size())==degree){
      verts.push_back(v_list.first);
    }
  }
  return verts;
}

bool EdgeContainer::edgeExist(Edge ed) {
  return (find(adj_list_[ed.getV1()].begin(), adj_list_[ed.getV1()].end(),
               ed.getV2()) != adj_list_[ed.getV1()].end());
}

bool EdgeContainer::vertexExist(int vert) { return adj_list_.count(vert); }

void EdgeContainer::addEdge(Edge ed) {
  adj_list_[ed.getV1()].insert(ed.getV2());
  adj_list_[ed.getV2()].insert(ed.getV1());
  return;
}

vector<int> EdgeContainer::getVertices() {
  vector<int> vertices;
  for (auto const& it : adj_list_) vertices.push_back(it.first);
  return vertices;
}

vector<int> EdgeContainer::getNeighVertices(int vert) {
  vector<int> neigh_verts;
  for (auto const& neigh_vert : adj_list_[vert]) {
    neigh_verts.push_back(neigh_vert);
  }
  return neigh_verts;
}

vector<Edge> EdgeContainer::getNeighEdges(int vert) {
  vector<Edge> neigh_edges;
  for (auto const& neigh_vert : adj_list_[vert]) {
    neigh_edges.push_back(Edge(vert, neigh_vert));
  }
  return neigh_edges;
}

vector<Edge> EdgeContainer::getEdges() {
  set<Edge> edgs;
  for (auto const& it : adj_list_) {
    for (auto const& vert : it.second) edgs.insert(Edge(it.first, vert));
  }
  vector<Edge> vec_edgs(edgs.begin(), edgs.end());
  return vec_edgs;
}
<commit_msg>Added output functionality for edge container<commit_after>/*
 *            Copyright 2009-2018 The VOTCA Development Team
 *                       (http://www.votca.org)
 *
 *      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.
 *
 */

#include <set>
#include <vector>
#include <exception>
#include <votca/tools/edge.h>
#include <votca/tools/edgecontainer.h>
#include <algorithm>

namespace votca {
  namespace tools {

using namespace std;

EdgeContainer::EdgeContainer(Edge ed) { addEdge(ed); }

EdgeContainer::EdgeContainer(vector<Edge> eds) {
  for (auto ed : eds) {
    addEdge(ed);
  }
}

int EdgeContainer::getMaxDegree(void) const{
  int max = 0;
  for(auto const& it : adj_list_) {
    if(it.second.size()>static_cast<size_t>(max)) {
      max = static_cast<int>(it.second.size());
    }
  }
  return max;
}

int EdgeContainer::getDegree(const int vert) const{
  if(!adj_list_.count(vert)) throw invalid_argument("vertex is not defined");
  return static_cast<int>(adj_list_.at(vert).size());
}

vector<int> EdgeContainer::getVerticesDegree(int degree) const{
  vector<int> verts;
  for(auto v_list : adj_list_){
    if(static_cast<int>(v_list.second.size())==degree){
      verts.push_back(v_list.first);
    }
  }
  return verts;
}

bool EdgeContainer::edgeExist(Edge ed) {
  return (find(adj_list_[ed.getV1()].begin(), adj_list_[ed.getV1()].end(),
               ed.getV2()) != adj_list_[ed.getV1()].end());
}

bool EdgeContainer::vertexExist(int vert) { return adj_list_.count(vert); }

void EdgeContainer::addEdge(Edge ed) {
  adj_list_[ed.getV1()].insert(ed.getV2());
  adj_list_[ed.getV2()].insert(ed.getV1());
  return;
}

vector<int> EdgeContainer::getVertices() {
  vector<int> vertices;
  for (auto const& it : adj_list_) vertices.push_back(it.first);
  return vertices;
}

vector<int> EdgeContainer::getNeighVertices(int vert) {
  vector<int> neigh_verts;
  for (auto const& neigh_vert : adj_list_[vert]) {
    neigh_verts.push_back(neigh_vert);
  }
  return neigh_verts;
}

vector<Edge> EdgeContainer::getNeighEdges(int vert) {
  vector<Edge> neigh_edges;
  for (auto const& neigh_vert : adj_list_[vert]) {
    neigh_edges.push_back(Edge(vert, neigh_vert));
  }
  return neigh_edges;
}

vector<Edge> EdgeContainer::getEdges() {
  set<Edge> edgs;
  for (auto const& it : adj_list_) {
    for (auto const& vert : it.second) edgs.insert(Edge(it.first, vert));
  }
  vector<Edge> vec_edgs(edgs.begin(), edgs.end());
  return vec_edgs;
}

ostream& operator<<(ostream& os, const EdgeContainer edgecontainer){
  edges = edgecontainer.getEdges();
  for(auto edge : edges){
    os << edge << endl;
  }
  return os;
}

}
}
<|endoftext|>


<commit_before>/*

 Copyright (c) 2013, Ford Motor Company
 All rights reserved.

 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are met:

 Redistributions of source code must retain the above copyright notice, this
 list of conditions and the following disclaimer.

 Redistributions in binary form must reproduce the above copyright notice,
 this list of conditions and the following
 disclaimer in the documentation and/or other materials provided with the
 distribution.

 Neither the name of the Ford Motor Company nor the names of its contributors
 may be used to endorse or promote products derived from this software
 without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGE.
 */

#include "application_manager/commands/mobile/unsubscribe_vehicle_data_request.h"
#include "application_manager/commands/command_impl.h"
#include "application_manager/application_manager_impl.h"
#include "application_manager/application_impl.h"
#include "application_manager/message_helper.h"
#include "interfaces/MOBILE_API.h"
#include "interfaces/HMI_API.h"
#include "application_manager/smart_object_keys.h"

namespace application_manager {
namespace commands {

UnsubscribeVehicleDataRequest::UnsubscribeVehicleDataRequest(
    const MessageSharedPtr& message)
    : CommandRequestImpl(message) {
}

UnsubscribeVehicleDataRequest::~UnsubscribeVehicleDataRequest() {
}

#ifdef HMI_DBUS_API
namespace {
  struct Subrequest {
    hmi_apis::FunctionID::eType func_id;
    const char* str;
  };
  Subrequest subrequests[] = {
    { hmi_apis::FunctionID::VehicleInfo_UnsubscribeGps, strings::gps},
    { hmi_apis::FunctionID::VehicleInfo_UnsubscribeSpeed, strings::speed},
    { hmi_apis::FunctionID::VehicleInfo_UnsubscribeRpm, strings::rpm},
    { hmi_apis::FunctionID::VehicleInfo_UnsubscribeFuelLevel, strings::fuel_level},
    { hmi_apis::FunctionID::VehicleInfo_UnsubscribeFuelLevel_State, strings::fuel_level_state},
    { hmi_apis::FunctionID::VehicleInfo_UnsubscribeInstantFuelConsumption, strings::instant_fuel_consumption},
    { hmi_apis::FunctionID::VehicleInfo_UnsubscribeExternalTemperature, strings::external_temp},
    { hmi_apis::FunctionID::VehicleInfo_UnsubscribeVin, strings::vin},
    { hmi_apis::FunctionID::VehicleInfo_UnsubscribePrndl, strings::prndl},
    { hmi_apis::FunctionID::VehicleInfo_UnsubscribeTirePressure, strings::tire_pressure},
    { hmi_apis::FunctionID::VehicleInfo_UnsubscribeOdometer, strings::odometer},
    { hmi_apis::FunctionID::VehicleInfo_UnsubscribeBeltStatus, strings::belt_status},
    { hmi_apis::FunctionID::VehicleInfo_UnsubscribeBodyInformation, strings::body_information},
    { hmi_apis::FunctionID::VehicleInfo_UnsubscribeDeviceStatus, strings::device_status},
    { hmi_apis::FunctionID::VehicleInfo_UnsubscribeDriverBraking, strings::driver_braking},
    { hmi_apis::FunctionID::VehicleInfo_UnsubscribeWiperStatus, strings::wiper_status},
    { hmi_apis::FunctionID::VehicleInfo_UnsubscribeHeadLampStatus, strings::head_lamp_status},
    { hmi_apis::FunctionID::VehicleInfo_UnsubscribeEngineTorque, strings::engine_torque},
    { hmi_apis::FunctionID::VehicleInfo_UnsubscribeAccPedalPosition, strings::acc_pedal_pos},
    { hmi_apis::FunctionID::VehicleInfo_UnsubscribeSteeringWheelAngle, strings::steering_wheel_angle},
    { hmi_apis::FunctionID::VehicleInfo_UnsubscribeECallInfo, strings::e_call_info},
    { hmi_apis::FunctionID::VehicleInfo_UnsubscribeAirbagStatus, strings::airbag_status},
    { hmi_apis::FunctionID::VehicleInfo_UnsubscribeEmergencyEvent, strings::emergency_event},
    { hmi_apis::FunctionID::VehicleInfo_UnsubscribeClusterModeStatus, strings::cluster_mode_status},
    { hmi_apis::FunctionID::VehicleInfo_UnsubscribeMyKey, strings::my_key},
  };
}
#endif // #ifdef HMI_DBUS_API

void UnsubscribeVehicleDataRequest::Run() {
  LOG4CXX_AUTO_TRACE(logger_);

  ApplicationSharedPtr app = ApplicationManagerImpl::instance()->application(
      CommandRequestImpl::connection_key());

  if (!app) {
    LOG4CXX_ERROR(logger_, "NULL pointer");
    SendResponse(false, mobile_apis::Result::APPLICATION_NOT_REGISTERED);
    return;
  }

  // counter for items to subscribe
  int32_t items_to_unsubscribe = 0;
  // counter for subscribed items by application
  int32_t unsubscribed_items = 0;

  const VehicleData& vehicle_data = MessageHelper::vehicle_data();
  VehicleData::const_iterator it = vehicle_data.begin();

  smart_objects::SmartObject msg_params = smart_objects::SmartObject(
      smart_objects::SmartType_Map);

  smart_objects::SmartObject response_params = smart_objects::SmartObject(
      smart_objects::SmartType_Map);

  msg_params[strings::app_id] = app->app_id();

  for (; vehicle_data.end() != it; ++it) {
    std::string key_name = it->first;
    if ((*message_)[strings::msg_params].keyExists(key_name)) {
      bool is_key_enabled = (*message_)[strings::msg_params][key_name].asBool();
      if (is_key_enabled) {
        ++items_to_unsubscribe;
        msg_params[key_name] = is_key_enabled;

        VehicleDataType key_type = it->second;
        if (app->UnsubscribeFromIVI(static_cast<uint32_t>(key_type))) {
          ++unsubscribed_items;
        } else {
          response_params[key_name][strings::data_type] = key_type;
          response_params[key_name][strings::result_code] =
              mobile_apis::VehicleDataResultCode::VDRC_DATA_NOT_SUBSCRIBED;
        }
      }
    }
  }

  if (0 == items_to_unsubscribe) {
    if (HasDisallowedParams()) {
      SendResponse(false, mobile_apis::Result::DISALLOWED);
    } else {
      SendResponse(false, mobile_apis::Result::INVALID_DATA,
                   "No data in the request.");
    }
    return;
  } else if (0 == unsubscribed_items) {
    SendResponse(false, mobile_apis::Result::IGNORED,
                 "Was not subscribed on any VehicleData.", &response_params);
    return;
  }

#ifdef HMI_DBUS_API
  //Generate list of subrequests
  for (size_t i = 0; i < sizeof(subrequests) / sizeof(subrequests[0]); ++i) {
    const Subrequest& sr = subrequests[i];
    if (true == (*message_)[strings::msg_params].keyExists(sr.str)
        && true == (*message_)[strings::msg_params][sr.str].asBool()) {
      HmiRequest hmi_request;
      hmi_request.str = sr.str;
      hmi_request.func_id = sr.func_id;
      hmi_request.complete = false;
      hmi_requests_.push_back(hmi_request);
    }
  }
  LOG4CXX_INFO(logger_,
               hmi_requests_.size() << " requests are going to be sent to HMI");

  //Send subrequests
  for (HmiRequests::const_iterator it = hmi_requests_.begin();
      it != hmi_requests_.end(); ++it)
    SendHMIRequest(it->func_id, &msg_params, true);
#else
  SendHMIRequest(hmi_apis::FunctionID::VehicleInfo_UnsubscribeVehicleData,
      &msg_params, true);
#endif // #ifdef HMI_DBUS_API
}

void UnsubscribeVehicleDataRequest::on_event(const event_engine::Event& event) {
  LOG4CXX_AUTO_TRACE(logger_);

  const smart_objects::SmartObject& message = event.smart_object();

#ifdef HMI_DBUS_API
  for (HmiRequests::iterator it = hmi_requests_.begin();
      it != hmi_requests_.end(); ++it) {
    HmiRequest & hmi_request = *it;
    if (hmi_request.func_id == event.id()) {
      hmi_request.status =
          static_cast<hmi_apis::Common_Result::eType>(message[strings::params][hmi_response::code]
              .asInt());
      if (hmi_apis::Common_Result::SUCCESS == hmi_request.status)
        hmi_request.value = message[strings::msg_params][hmi_request.str];
      hmi_request.complete = true;
      break;
    }
  }
  bool all_complete = true;
  bool any_arg_success = false;
  mobile_api::Result::eType status = mobile_api::Result::eType::SUCCESS;
  for (HmiRequests::const_iterator it = hmi_requests_.begin();
      it != hmi_requests_.end(); ++it) {
    if (!it->complete) {
      all_complete = false;
      break;
    }
    if (hmi_apis::Common_Result::SUCCESS != it->status) {
      if (mobile_api::Result::SUCCESS == status) {
        status = static_cast<mobile_apis::Result::eType>(it->status);
      } else if (status
          != static_cast<mobile_apis::Result::eType>(it->status)) {
        status = mobile_api::Result::eType::GENERIC_ERROR;
      } LOG4CXX_TRACE(logger_, "Status from HMI: " << it->status <<
          ", so response status become " << status);
    } else {
      any_arg_success = true;
    }
  }
 if (all_complete) {
    smart_objects::SmartObject response_params(smart_objects::SmartType_Map);
    if (any_arg_success) {
      for (HmiRequests::const_iterator it = hmi_requests_.begin();
          it != hmi_requests_.end(); ++it) {
        response_params[it->str] = it->value;
      }
    }

    LOG4CXX_INFO(logger_, "All HMI requests are complete");
    if (true == any_arg_success) {
      SetAllowedToTerminate(false);
    }
    SendResponse(any_arg_success, status, NULL, &response_params);
    if (true == any_arg_success) {
      UpdateHash();
    }
#else
  hmi_apis::Common_Result::eType hmi_result =
      static_cast<hmi_apis::Common_Result::eType>(
          message[strings::params][hmi_response::code].asInt());

  bool result =
      hmi_result == hmi_apis::Common_Result::SUCCESS;

  mobile_apis::Result::eType result_code =
      hmi_result == hmi_apis::Common_Result::SUCCESS
      ? mobile_apis::Result::SUCCESS
      : static_cast<mobile_apis::Result::eType>(
          message[strings::params][hmi_response::code].asInt());

  const char* return_info = NULL;

  if (result) {
    if (IsAnythingAlreadyUnsubscribed(message[strings::msg_params])) {
      result_code = mobile_apis::Result::IGNORED;
      return_info =
          std::string("Some provided VehicleData was not subscribed.").c_str();
    }
  }

  if (true == result) {
    SetAllowedToTerminate(false);
  }
  SendResponse(result, result_code, return_info,
               &(message[strings::msg_params]));
  if (true == result) {
    UpdateHash();
  }
#endif // #ifdef HMI_DBUS_API
}

bool UnsubscribeVehicleDataRequest::IsAnythingAlreadyUnsubscribed(
                           const smart_objects::SmartObject& msg_params) const {
  LOG4CXX_INFO(logger_, "IsAnythingAlreadyUnsubscribed");

  const VehicleData& vehicle_data = MessageHelper::vehicle_data();
  VehicleData::const_iterator it = vehicle_data.begin();

  for (; vehicle_data.end() != it; ++it) {
    if (msg_params.keyExists(it->first)) {
      if (msg_params[it->first][strings::result_code].asInt() ==
        hmi_apis::Common_VehicleDataResultCode::VDRC_DATA_NOT_SUBSCRIBED) {
        return true;
      }
    }
  }

  return false;
}

void UnsubscribeVehicleDataRequest::UpdateHash() const {
  LOG4CXX_AUTO_TRACE(logger_);
  ApplicationSharedPtr application =
      ApplicationManagerImpl::instance()->application(connection_key());
  if (application) {
    application->UpdateHash();
  } else {
    LOG4CXX_ERROR(logger_, "NULL pointer");
  }
  ApplicationManagerImpl::instance()->TerminateRequest(connection_key(),
                                                       correlation_id());
}

}  // namespace commands
}  // namespace application_manager
<commit_msg>Fixed comments after review<commit_after>/*

 Copyright (c) 2013, Ford Motor Company
 All rights reserved.

 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are met:

 Redistributions of source code must retain the above copyright notice, this
 list of conditions and the following disclaimer.

 Redistributions in binary form must reproduce the above copyright notice,
 this list of conditions and the following
 disclaimer in the documentation and/or other materials provided with the
 distribution.

 Neither the name of the Ford Motor Company nor the names of its contributors
 may be used to endorse or promote products derived from this software
 without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGE.
 */

#include "application_manager/commands/mobile/unsubscribe_vehicle_data_request.h"
#include "application_manager/commands/command_impl.h"
#include "application_manager/application_manager_impl.h"
#include "application_manager/application_impl.h"
#include "application_manager/message_helper.h"
#include "interfaces/MOBILE_API.h"
#include "interfaces/HMI_API.h"
#include "application_manager/smart_object_keys.h"

namespace application_manager {
namespace commands {

UnsubscribeVehicleDataRequest::UnsubscribeVehicleDataRequest(
    const MessageSharedPtr& message)
    : CommandRequestImpl(message) {
}

UnsubscribeVehicleDataRequest::~UnsubscribeVehicleDataRequest() {
}

#ifdef HMI_DBUS_API
namespace {
  struct Subrequest {
    hmi_apis::FunctionID::eType func_id;
    const char* str;
  };
  Subrequest subrequests[] = {
    { hmi_apis::FunctionID::VehicleInfo_UnsubscribeGps, strings::gps},
    { hmi_apis::FunctionID::VehicleInfo_UnsubscribeSpeed, strings::speed},
    { hmi_apis::FunctionID::VehicleInfo_UnsubscribeRpm, strings::rpm},
    { hmi_apis::FunctionID::VehicleInfo_UnsubscribeFuelLevel, strings::fuel_level},
    { hmi_apis::FunctionID::VehicleInfo_UnsubscribeFuelLevel_State, strings::fuel_level_state},
    { hmi_apis::FunctionID::VehicleInfo_UnsubscribeInstantFuelConsumption, strings::instant_fuel_consumption},
    { hmi_apis::FunctionID::VehicleInfo_UnsubscribeExternalTemperature, strings::external_temp},
    { hmi_apis::FunctionID::VehicleInfo_UnsubscribeVin, strings::vin},
    { hmi_apis::FunctionID::VehicleInfo_UnsubscribePrndl, strings::prndl},
    { hmi_apis::FunctionID::VehicleInfo_UnsubscribeTirePressure, strings::tire_pressure},
    { hmi_apis::FunctionID::VehicleInfo_UnsubscribeOdometer, strings::odometer},
    { hmi_apis::FunctionID::VehicleInfo_UnsubscribeBeltStatus, strings::belt_status},
    { hmi_apis::FunctionID::VehicleInfo_UnsubscribeBodyInformation, strings::body_information},
    { hmi_apis::FunctionID::VehicleInfo_UnsubscribeDeviceStatus, strings::device_status},
    { hmi_apis::FunctionID::VehicleInfo_UnsubscribeDriverBraking, strings::driver_braking},
    { hmi_apis::FunctionID::VehicleInfo_UnsubscribeWiperStatus, strings::wiper_status},
    { hmi_apis::FunctionID::VehicleInfo_UnsubscribeHeadLampStatus, strings::head_lamp_status},
    { hmi_apis::FunctionID::VehicleInfo_UnsubscribeEngineTorque, strings::engine_torque},
    { hmi_apis::FunctionID::VehicleInfo_UnsubscribeAccPedalPosition, strings::acc_pedal_pos},
    { hmi_apis::FunctionID::VehicleInfo_UnsubscribeSteeringWheelAngle, strings::steering_wheel_angle},
    { hmi_apis::FunctionID::VehicleInfo_UnsubscribeECallInfo, strings::e_call_info},
    { hmi_apis::FunctionID::VehicleInfo_UnsubscribeAirbagStatus, strings::airbag_status},
    { hmi_apis::FunctionID::VehicleInfo_UnsubscribeEmergencyEvent, strings::emergency_event},
    { hmi_apis::FunctionID::VehicleInfo_UnsubscribeClusterModeStatus, strings::cluster_mode_status},
    { hmi_apis::FunctionID::VehicleInfo_UnsubscribeMyKey, strings::my_key},
  };
}
#endif // #ifdef HMI_DBUS_API

void UnsubscribeVehicleDataRequest::Run() {
  LOG4CXX_AUTO_TRACE(logger_);

  ApplicationSharedPtr app = ApplicationManagerImpl::instance()->application(
      CommandRequestImpl::connection_key());

  if (!app) {
    LOG4CXX_ERROR(logger_, "NULL pointer");
    SendResponse(false, mobile_apis::Result::APPLICATION_NOT_REGISTERED);
    return;
  }

  // counter for items to subscribe
  int32_t items_to_unsubscribe = 0;
  // counter for subscribed items by application
  int32_t unsubscribed_items = 0;

  const VehicleData& vehicle_data = MessageHelper::vehicle_data();
  VehicleData::const_iterator it = vehicle_data.begin();

  smart_objects::SmartObject msg_params = smart_objects::SmartObject(
      smart_objects::SmartType_Map);

  smart_objects::SmartObject response_params = smart_objects::SmartObject(
      smart_objects::SmartType_Map);

  msg_params[strings::app_id] = app->app_id();

  for (; vehicle_data.end() != it; ++it) {
    std::string key_name = it->first;
    if ((*message_)[strings::msg_params].keyExists(key_name)) {
      bool is_key_enabled = (*message_)[strings::msg_params][key_name].asBool();
      if (is_key_enabled) {
        ++items_to_unsubscribe;
        msg_params[key_name] = is_key_enabled;

        VehicleDataType key_type = it->second;
        if (app->UnsubscribeFromIVI(static_cast<uint32_t>(key_type))) {
          ++unsubscribed_items;
        } else {
          response_params[key_name][strings::data_type] = key_type;
          response_params[key_name][strings::result_code] =
              mobile_apis::VehicleDataResultCode::VDRC_DATA_NOT_SUBSCRIBED;
        }
      }
    }
  }

  if (0 == items_to_unsubscribe) {
    if (HasDisallowedParams()) {
      SendResponse(false, mobile_apis::Result::DISALLOWED);
    } else {
      SendResponse(false, mobile_apis::Result::INVALID_DATA,
                   "No data in the request.");
    }
    return;
  } else if (0 == unsubscribed_items) {
    SendResponse(false, mobile_apis::Result::IGNORED,
                 "Was not subscribed on any VehicleData.", &response_params);
    return;
  }

#ifdef HMI_DBUS_API
  //Generate list of subrequests
  for (size_t i = 0; i < sizeof(subrequests) / sizeof(subrequests[0]); ++i) {
    const Subrequest& sr = subrequests[i];
    if (true == (*message_)[strings::msg_params].keyExists(sr.str)
        && true == (*message_)[strings::msg_params][sr.str].asBool()) {
      HmiRequest hmi_request;
      hmi_request.str = sr.str;
      hmi_request.func_id = sr.func_id;
      hmi_request.complete = false;
      hmi_requests_.push_back(hmi_request);
    }
  }
  LOG4CXX_INFO(logger_,
               hmi_requests_.size() << " requests are going to be sent to HMI");

  //Send subrequests
  for (HmiRequests::const_iterator it = hmi_requests_.begin();
      it != hmi_requests_.end(); ++it)
    SendHMIRequest(it->func_id, &msg_params, true);
#else
  SendHMIRequest(hmi_apis::FunctionID::VehicleInfo_UnsubscribeVehicleData,
      &msg_params, true);
#endif // #ifdef HMI_DBUS_API
}

void UnsubscribeVehicleDataRequest::on_event(const event_engine::Event& event) {
  LOG4CXX_AUTO_TRACE(logger_);

  const smart_objects::SmartObject& message = event.smart_object();

#ifdef HMI_DBUS_API
  for (HmiRequests::iterator it = hmi_requests_.begin();
      it != hmi_requests_.end(); ++it) {
    HmiRequest & hmi_request = *it;
    if (hmi_request.func_id == event.id()) {
      hmi_request.status =
          static_cast<hmi_apis::Common_Result::eType>(message[strings::params][hmi_response::code]
              .asInt());
      if (hmi_apis::Common_Result::SUCCESS == hmi_request.status)
        hmi_request.value = message[strings::msg_params][hmi_request.str];
      hmi_request.complete = true;
      break;
    }
  }
  bool all_complete = true;
  bool any_arg_success = false;
  mobile_api::Result::eType status = mobile_api::Result::eType::SUCCESS;
  for (HmiRequests::const_iterator it = hmi_requests_.begin();
      it != hmi_requests_.end(); ++it) {
    if (!it->complete) {
      all_complete = false;
      break;
    }
    if (hmi_apis::Common_Result::SUCCESS != it->status) {
      if (mobile_api::Result::SUCCESS == status) {
        status = static_cast<mobile_apis::Result::eType>(it->status);
      } else if (status
          != static_cast<mobile_apis::Result::eType>(it->status)) {
        status = mobile_api::Result::eType::GENERIC_ERROR;
      } LOG4CXX_TRACE(logger_, "Status from HMI: " << it->status <<
          ", so response status become " << status);
    } else {
      any_arg_success = true;
    }
  }
 if (all_complete) {
    smart_objects::SmartObject response_params(smart_objects::SmartType_Map);
    if (any_arg_success) {
      for (HmiRequests::const_iterator it = hmi_requests_.begin();
          it != hmi_requests_.end(); ++it) {
        response_params[it->str] = it->value;
      }
    }

    LOG4CXX_INFO(logger_, "All HMI requests are complete");
    if (true == any_arg_success) {
      SetAllowedToTerminate(false);
    }
    SendResponse(any_arg_success, status, NULL, &response_params);
    if (true == any_arg_success) {
      UpdateHash();
    }
#else
  hmi_apis::Common_Result::eType hmi_result =
      static_cast<hmi_apis::Common_Result::eType>(
          message[strings::params][hmi_response::code].asInt());

  bool result =
      hmi_result == hmi_apis::Common_Result::SUCCESS;

  mobile_apis::Result::eType result_code =
      hmi_result == hmi_apis::Common_Result::SUCCESS
      ? mobile_apis::Result::SUCCESS
      : static_cast<mobile_apis::Result::eType>(
          message[strings::params][hmi_response::code].asInt());

  const char* return_info = NULL;

  if (result) {
    if (IsAnythingAlreadyUnsubscribed(message[strings::msg_params])) {
      result_code = mobile_apis::Result::IGNORED;
      return_info =
          std::string("Some provided VehicleData was not subscribed.").c_str();
    }
  }

  if (true == result) {
    SetAllowedToTerminate(false);
  }
  SendResponse(result, result_code, return_info,
               &(message[strings::msg_params]));
  if (true == result) {
    UpdateHash();
  }
#endif // #ifdef HMI_DBUS_API
}

bool UnsubscribeVehicleDataRequest::IsAnythingAlreadyUnsubscribed(
                           const smart_objects::SmartObject& msg_params) const {
  LOG4CXX_INFO(logger_, "IsAnythingAlreadyUnsubscribed");

  const VehicleData& vehicle_data = MessageHelper::vehicle_data();
  VehicleData::const_iterator it = vehicle_data.begin();

  for (; vehicle_data.end() != it; ++it) {
    if (msg_params.keyExists(it->first)) {
      if (msg_params[it->first][strings::result_code].asInt() ==
        hmi_apis::Common_VehicleDataResultCode::VDRC_DATA_NOT_SUBSCRIBED) {
        return true;
      }
    }
  }

  return false;
}

void UnsubscribeVehicleDataRequest::UpdateHash() const {
  LOG4CXX_AUTO_TRACE(logger_);
  ApplicationSharedPtr application =
      ApplicationManagerImpl::instance()->application(connection_key());
  if (application) {
    application->UpdateHash();
  } else {
    LOG4CXX_ERROR(logger_, "Application with connection_key = "<<connection_key()
                  <<"doesn't exists");
  }
  ApplicationManagerImpl::instance()->TerminateRequest(connection_key(),
                                                       correlation_id());
}

}  // namespace commands
}  // namespace application_manager
<|endoftext|>


<commit_before>#include "videosourcefactory.h"

namespace gg
{

VideoSourceFactory VideoSourceFactory::_factory_singleton;

VideoSourceFactory::VideoSourceFactory()
{
    for (size_t i = 0; i < NUM_DEVICES; i++)
        _devices[i] = nullptr;
}

VideoSourceFactory::~VideoSourceFactory()
{
    free_device(DVI2PCIeDuo_DVI);
    free_device(DVI2PCIeDuo_SDI);
}

VideoSourceFactory & VideoSourceFactory::get_instance()
{
    return _factory_singleton;
}

IVideoSource * VideoSourceFactory::get_device(Device device,
                                              ColourSpace colour)
{
    // TODO
}

void VideoSourceFactory::free_device(Device device)
{
    if (_devices[(int) device] != nullptr)
        delete _devices[(int) device];
    _devices[(int) device] = nullptr;
}

}
<commit_msg>Issue #121: amended free_device with device check as in Factory::disconnect<commit_after>#include "videosourcefactory.h"

namespace gg
{

VideoSourceFactory VideoSourceFactory::_factory_singleton;

VideoSourceFactory::VideoSourceFactory()
{
    for (size_t i = 0; i < NUM_DEVICES; i++)
        _devices[i] = nullptr;
}

VideoSourceFactory::~VideoSourceFactory()
{
    free_device(DVI2PCIeDuo_DVI);
    free_device(DVI2PCIeDuo_SDI);
}

VideoSourceFactory & VideoSourceFactory::get_instance()
{
    return _factory_singleton;
}

IVideoSource * VideoSourceFactory::get_device(Device device,
                                              ColourSpace colour)
{
    // TODO
    if (_devices[(int) device] == nullptr)
    {
        _devices[(int) device] = new DummyVideoSource;
        _device_colours[(int) device] = colour;
    }
    else if (_device_colours[(int) device] != colour)
        throw DeviceAlreadyConnected(
                "Device already connected using another colour space"
        );
    return _devices[(int) device];
}

void VideoSourceFactory::free_device(Device device)
{
    switch (device)
    {
    case DVI2PCIeDuo_DVI:
    case DVI2PCIeDuo_SDI:
        break; // everything up to here is recognised
    default:
        std::string msg;
        msg.append("Device ")
           .append(std::to_string(device))
           .append(" not recognised");
        throw DeviceNotFound(msg);
    }

    if (_devices[(int) device] != nullptr)
        delete _devices[(int) device];
    _devices[(int) device] = nullptr;
}

}
<|endoftext|>