<commit_before>// This file is part of the AliceVision project.
// Copyright (c) 2016 AliceVision contributors.
// This Source Code Form is subject to the terms of the Mozilla Public License,
// v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.

#include "GeometricFilterMatrix_HGrowing.hpp"
#include "dependencies/vectorGraphics/svgDrawer.hpp"

namespace aliceVision {
namespace matchingImageCollection {

bool GeometricFilterMatrix_HGrowing::getMatches(const feature::EImageDescriberType &descType,
                                                const IndexT homographyId, matching::IndMatches &matches) const
{
  matches.clear();

  if (_HsAndMatchesPerDesc.find(descType) == _HsAndMatchesPerDesc.end())
    return false;
  if (homographyId > _HsAndMatchesPerDesc.at(descType).size() - 1)
    return false;

  matches = _HsAndMatchesPerDesc.at(descType).at(homographyId).second;

  return !matches.empty();

}

std::size_t GeometricFilterMatrix_HGrowing::getNbHomographies(const feature::EImageDescriberType &descType) const
{
  if (_HsAndMatchesPerDesc.find(descType) == _HsAndMatchesPerDesc.end())
    return 0;
  return _HsAndMatchesPerDesc.at(descType).size();
}

std::size_t GeometricFilterMatrix_HGrowing::getNbVerifiedMatches(const feature::EImageDescriberType &descType,
                                                                 const IndexT homographyId) const
{
  if (_HsAndMatchesPerDesc.find(descType) == _HsAndMatchesPerDesc.end())
    return 0;
  if (homographyId > _HsAndMatchesPerDesc.at(descType).size() - 1)
    return 0;

  return _HsAndMatchesPerDesc.at(descType).at(homographyId).second.size();
}

std::size_t GeometricFilterMatrix_HGrowing::getNbAllVerifiedMatches() const
{
  std::size_t counter = 0;
  for (const auto & HnMs : _HsAndMatchesPerDesc)
  {
    for (const std::pair<Mat3, matching::IndMatches> & HnM : HnMs.second)
    {
      counter += HnM.second.size();
    }
  }
  return counter;
}

bool growHomography(const std::vector<feature::SIOPointFeature> &featuresI,
                    const std::vector<feature::SIOPointFeature> &featuresJ,
                    const matching::IndMatches &matches,
                    const IndexT &seedMatchId,
                    std::set<IndexT> &planarMatchesIndices, Mat3 &transformation,
                    const GrowParameters& param)
{
  assert(seedMatchId <= matches.size());

  planarMatchesIndices.clear();
  transformation = Mat3::Identity();

  const matching::IndMatch & seedMatch = matches.at(seedMatchId);
  const feature::SIOPointFeature & seedFeatureI = featuresI.at(seedMatch._i);
  const feature::SIOPointFeature & seedFeatureJ = featuresJ.at(seedMatch._j);

  double currTolerance;

  for (IndexT iRefineStep = 0; iRefineStep < param._nbRefiningIterations; ++iRefineStep)
  {
    if (iRefineStep == 0)
    {
      computeSimilarity(seedFeatureI, seedFeatureJ, transformation);
      currTolerance = param._similarityTolerance;
    }
    else if (iRefineStep <= 4)
    {
      estimateAffinity(featuresI, featuresJ, matches, transformation, planarMatchesIndices);
      currTolerance = param._affinityTolerance;
    }
    else
    {
      estimateHomography(featuresI, featuresJ, matches, transformation, planarMatchesIndices);
      currTolerance = param._homographyTolerance;
    }

    findTransformationInliers(featuresI, featuresJ, matches, transformation, currTolerance, planarMatchesIndices);

    if (planarMatchesIndices.size() < param._minInliersToRefine)
      return false;

    // Note: the following statement is present in the MATLAB code but not implemented in YASM
//      if (planarMatchesIndices.size() >= param._maxFractionPlanarMatches * matches.size())
//        break;
  }
  return !transformation.isIdentity();
}

void filterMatchesByHGrowing(const std::vector<feature::SIOPointFeature>& siofeatures_I,
                             const std::vector<feature::SIOPointFeature>& siofeatures_J,
                             const matching::IndMatches& putativeMatches,
                             std::vector<std::pair<Mat3, matching::IndMatches>>& homographiesAndMatches,
                             matching::IndMatches& outGeometricInliers,
                             const HGrowingFilteringParam& param)
{

  using namespace aliceVision::feature;
  using namespace aliceVision::matching;

  IndMatches remainingMatches = putativeMatches;
  GeometricFilterMatrix_HGrowing dummy;

  for(IndexT iH = 0; iH < param._maxNbHomographies; ++iH)
  {
    std::set<IndexT> usedMatchesId, bestMatchesId;
    Mat3 bestHomography;

    // -- Estimate H using homography-growing approach
    #pragma omp parallel for // (huge optimization but modify results a little)
    for(int iMatch = 0; iMatch < remainingMatches.size(); ++iMatch)
    {
      // Growing a homography from one match ([F.Srajer, 2016] algo. 1, p. 20)
      // each match is used once only per homography estimation (increases computation time) [1st improvement ([F.Srajer, 2016] p. 20) ]
      if (usedMatchesId.find(iMatch) != usedMatchesId.end())
        continue;
      std::set<IndexT> planarMatchesId; // be careful: it contains the id. in the 'remainingMatches' vector not 'putativeMatches' vector.
      Mat3 homography;

      if (!growHomography(siofeatures_I,
                          siofeatures_J,
                          remainingMatches,
                          iMatch,
                          planarMatchesId,
                          homography,
                          param._growParam))
      {
        continue;
      }

      #pragma omp critical
      usedMatchesId.insert(planarMatchesId.begin(), planarMatchesId.end());

      if (planarMatchesId.size() > bestMatchesId.size())
      {
        #pragma omp critical
        {
          if(iH == 3) std::cout << "best iMatch" << iMatch << std::endl;
          bestMatchesId = planarMatchesId; // be careful: it contains the id. in the 'remainingMatches' vector not 'putativeMatches' vector.
          bestHomography = homography;
        }
      }
    } // 'iMatch'

    // -- Refine H using Ceres minimizer
    refineHomography(siofeatures_I, siofeatures_J, remainingMatches, bestHomography, bestMatchesId, param._growParam._homographyTolerance);

    // stop when the models get too small
    if (bestMatchesId.size() < param._minNbMatchesPerH)
      break;

    // Store validated results:
    {
      IndMatches matches;
      Mat3 H = bestHomography;
      for (IndexT id : bestMatchesId)
      {
        matches.push_back(remainingMatches.at(id));
      }
      homographiesAndMatches.emplace_back(H, matches);
    }

    // -- Update not used matches & Save geometrically verified matches
    for (IndexT id : bestMatchesId)
    {
      outGeometricInliers.push_back(remainingMatches.at(id));
    }

    // update remaining matches (/!\ Keep ordering)
    std::size_t cpt = 0;
    for (IndexT id : bestMatchesId)
    {
      remainingMatches.erase(remainingMatches.begin() + id - cpt);
      ++cpt;
    }

    // stop when the number of remaining matches is too small
    if (remainingMatches.size() < param._minNbMatchesPerH)
      break;

  } // 'iH'

}

void drawHomographyMatches(const std::string& outFilename,
                           const sfm::View & viewI,
                           const sfm::View & viewJ,
                           const std::vector<feature::SIOPointFeature>& siofeatures_I,
                           const std::vector<feature::SIOPointFeature>& siofeatures_J,
                           const std::vector<std::pair<Mat3, matching::IndMatches>>& homographiesAndMatches,
                           const matching::IndMatches& putativeMatches)
{
  const std::vector<std::string> colors{"red", "cyan", "purple", "green", "black", "brown", "blue", "pink", "grey"};

  svg::svgDrawer svgStream(viewI.getWidth() + viewJ.getWidth() , std::max(viewI.getHeight(), viewJ.getHeight()));

  const std::size_t offset{viewI.getWidth()};

  svgStream.drawImage(viewI.getImagePath(), viewI.getWidth(), viewI.getHeight());
  svgStream.drawImage(viewJ.getImagePath(), viewJ.getWidth(), viewJ.getHeight(), offset);

// draw little white dots representing putative matches
  for (const auto& match : putativeMatches)
  {
    const float radius{1.f};
    const float strokeSize{2.f};
    const feature::SIOPointFeature &fI = siofeatures_I.at(match._i);
    const feature::SIOPointFeature &fJ = siofeatures_J.at(match._j);
    const svg::svgStyle style = svg::svgStyle().stroke("white", strokeSize);

    svgStream.drawCircle(fI.x(), fI.y(), radius, style);
    svgStream.drawCircle(fJ.x() + offset, fJ.y(), radius, style);
  }

  for (const auto &currRes : homographiesAndMatches)
  {
    std::size_t iH{0};
    const auto &bestMatchesId = currRes.second;
    for (const auto &match : bestMatchesId)
    {
      const float radius{5.f};
      const float strokeSize{5.f};
      const feature::SIOPointFeature &fI = siofeatures_I.at(match._i);
      const feature::SIOPointFeature &fJ = siofeatures_J.at(match._j);
      // 0 < iH <= 8: colored; iH > 8  are white (not enough colors)
      std::string color = "grey";
      if (iH <= colors.size() - 1)
        color = colors.at(iH);
      const svg::svgStyle style = svg::svgStyle().stroke(color, strokeSize);

      svgStream.drawCircle(fI.x(), fI.y(), radius, style);
      svgStream.drawCircle(fJ.x() + offset, fJ.y(), radius, style);
      ++iH;
    }
  }

    std::ofstream svgFile(outFilename);
    if(!svgFile.is_open())
    {
      ALICEVISION_CERR("Unable to open file "+outFilename);
      return;
    }
    svgFile << svgStream.closeSvgFile().str();
    if(!svgFile.good())
    {
      ALICEVISION_CERR("Something wrong happened while writing file "+outFilename);
      return;
    }
    svgFile << svgStream.closeSvgFile().str();
    svgFile.close();

}

}
}<commit_msg>[matchingImageCollection] bugfix double write on svg file<commit_after>// This file is part of the AliceVision project.
// Copyright (c) 2016 AliceVision contributors.
// This Source Code Form is subject to the terms of the Mozilla Public License,
// v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.

#include "GeometricFilterMatrix_HGrowing.hpp"
#include "dependencies/vectorGraphics/svgDrawer.hpp"

namespace aliceVision {
namespace matchingImageCollection {

bool GeometricFilterMatrix_HGrowing::getMatches(const feature::EImageDescriberType &descType,
                                                const IndexT homographyId, matching::IndMatches &matches) const
{
  matches.clear();

  if (_HsAndMatchesPerDesc.find(descType) == _HsAndMatchesPerDesc.end())
    return false;
  if (homographyId > _HsAndMatchesPerDesc.at(descType).size() - 1)
    return false;

  matches = _HsAndMatchesPerDesc.at(descType).at(homographyId).second;

  return !matches.empty();

}

std::size_t GeometricFilterMatrix_HGrowing::getNbHomographies(const feature::EImageDescriberType &descType) const
{
  if (_HsAndMatchesPerDesc.find(descType) == _HsAndMatchesPerDesc.end())
    return 0;
  return _HsAndMatchesPerDesc.at(descType).size();
}

std::size_t GeometricFilterMatrix_HGrowing::getNbVerifiedMatches(const feature::EImageDescriberType &descType,
                                                                 const IndexT homographyId) const
{
  if (_HsAndMatchesPerDesc.find(descType) == _HsAndMatchesPerDesc.end())
    return 0;
  if (homographyId > _HsAndMatchesPerDesc.at(descType).size() - 1)
    return 0;

  return _HsAndMatchesPerDesc.at(descType).at(homographyId).second.size();
}

std::size_t GeometricFilterMatrix_HGrowing::getNbAllVerifiedMatches() const
{
  std::size_t counter = 0;
  for (const auto & HnMs : _HsAndMatchesPerDesc)
  {
    for (const std::pair<Mat3, matching::IndMatches> & HnM : HnMs.second)
    {
      counter += HnM.second.size();
    }
  }
  return counter;
}

bool growHomography(const std::vector<feature::SIOPointFeature> &featuresI,
                    const std::vector<feature::SIOPointFeature> &featuresJ,
                    const matching::IndMatches &matches,
                    const IndexT &seedMatchId,
                    std::set<IndexT> &planarMatchesIndices, Mat3 &transformation,
                    const GrowParameters& param)
{
  assert(seedMatchId <= matches.size());

  planarMatchesIndices.clear();
  transformation = Mat3::Identity();

  const matching::IndMatch & seedMatch = matches.at(seedMatchId);
  const feature::SIOPointFeature & seedFeatureI = featuresI.at(seedMatch._i);
  const feature::SIOPointFeature & seedFeatureJ = featuresJ.at(seedMatch._j);

  double currTolerance;

  for (IndexT iRefineStep = 0; iRefineStep < param._nbRefiningIterations; ++iRefineStep)
  {
    if (iRefineStep == 0)
    {
      computeSimilarity(seedFeatureI, seedFeatureJ, transformation);
      currTolerance = param._similarityTolerance;
    }
    else if (iRefineStep <= 4)
    {
      estimateAffinity(featuresI, featuresJ, matches, transformation, planarMatchesIndices);
      currTolerance = param._affinityTolerance;
    }
    else
    {
      estimateHomography(featuresI, featuresJ, matches, transformation, planarMatchesIndices);
      currTolerance = param._homographyTolerance;
    }

    findTransformationInliers(featuresI, featuresJ, matches, transformation, currTolerance, planarMatchesIndices);

    if (planarMatchesIndices.size() < param._minInliersToRefine)
      return false;

    // Note: the following statement is present in the MATLAB code but not implemented in YASM
//      if (planarMatchesIndices.size() >= param._maxFractionPlanarMatches * matches.size())
//        break;
  }
  return !transformation.isIdentity();
}

void filterMatchesByHGrowing(const std::vector<feature::SIOPointFeature>& siofeatures_I,
                             const std::vector<feature::SIOPointFeature>& siofeatures_J,
                             const matching::IndMatches& putativeMatches,
                             std::vector<std::pair<Mat3, matching::IndMatches>>& homographiesAndMatches,
                             matching::IndMatches& outGeometricInliers,
                             const HGrowingFilteringParam& param)
{

  using namespace aliceVision::feature;
  using namespace aliceVision::matching;

  IndMatches remainingMatches = putativeMatches;
  GeometricFilterMatrix_HGrowing dummy;

  for(IndexT iH = 0; iH < param._maxNbHomographies; ++iH)
  {
    std::set<IndexT> usedMatchesId, bestMatchesId;
    Mat3 bestHomography;

    // -- Estimate H using homography-growing approach
    #pragma omp parallel for // (huge optimization but modify results a little)
    for(int iMatch = 0; iMatch < remainingMatches.size(); ++iMatch)
    {
      // Growing a homography from one match ([F.Srajer, 2016] algo. 1, p. 20)
      // each match is used once only per homography estimation (increases computation time) [1st improvement ([F.Srajer, 2016] p. 20) ]
      if (usedMatchesId.find(iMatch) != usedMatchesId.end())
        continue;
      std::set<IndexT> planarMatchesId; // be careful: it contains the id. in the 'remainingMatches' vector not 'putativeMatches' vector.
      Mat3 homography;

      if (!growHomography(siofeatures_I,
                          siofeatures_J,
                          remainingMatches,
                          iMatch,
                          planarMatchesId,
                          homography,
                          param._growParam))
      {
        continue;
      }

      #pragma omp critical
      usedMatchesId.insert(planarMatchesId.begin(), planarMatchesId.end());

      if (planarMatchesId.size() > bestMatchesId.size())
      {
        #pragma omp critical
        {
          if(iH == 3) std::cout << "best iMatch" << iMatch << std::endl;
          bestMatchesId = planarMatchesId; // be careful: it contains the id. in the 'remainingMatches' vector not 'putativeMatches' vector.
          bestHomography = homography;
        }
      }
    } // 'iMatch'

    // -- Refine H using Ceres minimizer
    refineHomography(siofeatures_I, siofeatures_J, remainingMatches, bestHomography, bestMatchesId, param._growParam._homographyTolerance);

    // stop when the models get too small
    if (bestMatchesId.size() < param._minNbMatchesPerH)
      break;

    // Store validated results:
    {
      IndMatches matches;
      Mat3 H = bestHomography;
      for (IndexT id : bestMatchesId)
      {
        matches.push_back(remainingMatches.at(id));
      }
      homographiesAndMatches.emplace_back(H, matches);
    }

    // -- Update not used matches & Save geometrically verified matches
    for (IndexT id : bestMatchesId)
    {
      outGeometricInliers.push_back(remainingMatches.at(id));
    }

    // update remaining matches (/!\ Keep ordering)
    std::size_t cpt = 0;
    for (IndexT id : bestMatchesId)
    {
      remainingMatches.erase(remainingMatches.begin() + id - cpt);
      ++cpt;
    }

    // stop when the number of remaining matches is too small
    if (remainingMatches.size() < param._minNbMatchesPerH)
      break;

  } // 'iH'

}

void drawHomographyMatches(const std::string& outFilename,
                           const sfm::View & viewI,
                           const sfm::View & viewJ,
                           const std::vector<feature::SIOPointFeature>& siofeatures_I,
                           const std::vector<feature::SIOPointFeature>& siofeatures_J,
                           const std::vector<std::pair<Mat3, matching::IndMatches>>& homographiesAndMatches,
                           const matching::IndMatches& putativeMatches)
{
  const std::vector<std::string> colors{"red", "cyan", "purple", "green", "black", "brown", "blue", "pink", "grey"};

  svg::svgDrawer svgStream(viewI.getWidth() + viewJ.getWidth() , std::max(viewI.getHeight(), viewJ.getHeight()));

  const std::size_t offset{viewI.getWidth()};

  svgStream.drawImage(viewI.getImagePath(), viewI.getWidth(), viewI.getHeight());
  svgStream.drawImage(viewJ.getImagePath(), viewJ.getWidth(), viewJ.getHeight(), offset);

// draw little white dots representing putative matches
  for (const auto& match : putativeMatches)
  {
    const float radius{1.f};
    const float strokeSize{2.f};
    const feature::SIOPointFeature &fI = siofeatures_I.at(match._i);
    const feature::SIOPointFeature &fJ = siofeatures_J.at(match._j);
    const svg::svgStyle style = svg::svgStyle().stroke("white", strokeSize);

    svgStream.drawCircle(fI.x(), fI.y(), radius, style);
    svgStream.drawCircle(fJ.x() + offset, fJ.y(), radius, style);
  }

  for (const auto &currRes : homographiesAndMatches)
  {
    std::size_t iH{0};
    const auto &bestMatchesId = currRes.second;
    for (const auto &match : bestMatchesId)
    {
      const float radius{5.f};
      const float strokeSize{5.f};
      const feature::SIOPointFeature &fI = siofeatures_I.at(match._i);
      const feature::SIOPointFeature &fJ = siofeatures_J.at(match._j);
      // 0 < iH <= 8: colored; iH > 8  are white (not enough colors)
      std::string color = "grey";
      if (iH <= colors.size() - 1)
        color = colors.at(iH);
      const svg::svgStyle style = svg::svgStyle().stroke(color, strokeSize);

      svgStream.drawCircle(fI.x(), fI.y(), radius, style);
      svgStream.drawCircle(fJ.x() + offset, fJ.y(), radius, style);
      ++iH;
    }
  }

  std::ofstream svgFile(outFilename);
  if(!svgFile.is_open())
  {
    ALICEVISION_CERR("Unable to open file "+outFilename);
    return;
  }
  svgFile << svgStream.closeSvgFile().str();
  if(!svgFile.good())
  {
    ALICEVISION_CERR("Something wrong happened while writing file "+outFilename);
    return;
  }
  svgFile.close();

}

}
}<|endoftext|>


<commit_before>//@+leo-ver=5-thin
//@+node:gcross.20110520194631.1350: * @file contained.hpp
//@@language cplusplus

//@+<< License >>
//@+node:gcross.20110520194631.1352: ** << License >>
//@+at
// Copyright (c) 2011, Gregory Crosswhite
// 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.
//
// 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.
//@@c
//@-<< License >>

#ifndef HDFPP_CONTAINED_HPP
#define HDFPP_CONTAINED_HPP

//@+<< Includes >>
//@+node:gcross.20110520194631.1351: ** << Includes >>
#include "identified.hpp"
#include "location.hpp"
//@-<< Includes >>

namespace HDF {

//@+others
//@+node:gcross.20110520194631.1353: ** class Contained
//@+<< Forward declarations >>
//@+node:gcross.20110520211700.1488: *3* << Forward declarations >>
class File;
//@-<< Forward declarations >>

class Contained: public Identified, public virtual Locatable {
    //@+others
    //@+node:gcross.20110520194631.1357: *3* Constructors
    protected:

    Contained();
    Contained(File const& file, hid_t id, Identity::Closer const& closer);
    Contained(File const& file, Identity::Ptr const& self_identity);
    //@+node:gcross.20110520211700.1486: *3* Fields
    protected:

    File file;

    public:

    virtual File const& getFile() const;
    virtual Identity::Ptr const& getIdentity() const;
    //@-others
};
//@-others

}

#endif
//@-leo
<commit_msg>Removed a redundant forward declaration.<commit_after>//@+leo-ver=5-thin
//@+node:gcross.20110520194631.1350: * @file contained.hpp
//@@language cplusplus

//@+<< License >>
//@+node:gcross.20110520194631.1352: ** << License >>
//@+at
// Copyright (c) 2011, Gregory Crosswhite
// 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.
//
// 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.
//@@c
//@-<< License >>

#ifndef HDFPP_CONTAINED_HPP
#define HDFPP_CONTAINED_HPP

//@+<< Includes >>
//@+node:gcross.20110520194631.1351: ** << Includes >>
#include "identified.hpp"
#include "location.hpp"
//@-<< Includes >>

namespace HDF {

//@+others
//@+node:gcross.20110520194631.1353: ** class Contained
class Contained: public Identified, public virtual Locatable {
    //@+others
    //@+node:gcross.20110520194631.1357: *3* Constructors
    protected:

    Contained();
    Contained(File const& file, hid_t id, Identity::Closer const& closer);
    Contained(File const& file, Identity::Ptr const& self_identity);
    //@+node:gcross.20110520211700.1486: *3* Fields
    protected:

    File file;

    public:

    virtual File const& getFile() const;
    virtual Identity::Ptr const& getIdentity() const;
    //@-others
};
//@-others

}

#endif
//@-leo
<|endoftext|>


<commit_before>/*  Copyright (c) MediaArea.net SARL. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license that can
 *  be found in the License.html file in the root of the source tree.
 */

//---------------------------------------------------------------------------
// Pre-compilation
#include "MediaInfo/PreComp.h"
#ifdef __BORLANDC__
    #pragma hdrstop
#endif
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
#include "MediaInfo/Setup.h"
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
#if defined(MEDIAINFO_NISO_YES)
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
#include "MediaInfo/Export/Export_Niso.h"
#include "MediaInfo/File__Analyse_Automatic.h"
#include "MediaInfo/OutputHelpers.h"
#include <ctime>

using namespace std;

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

namespace MediaInfoLib
{
//---------------------------------------------------------------------------
extern MediaInfo_Config Config;
//---------------------------------------------------------------------------

//***************************************************************************
// Constructor/Destructor
//***************************************************************************

//---------------------------------------------------------------------------
Export_Niso::Export_Niso ()
{
}

//---------------------------------------------------------------------------
Export_Niso::~Export_Niso ()
{
}

//***************************************************************************
// Helpers
//***************************************************************************
Node* Transform_Header()
{
    //Root node
    Node* Node_Header = new Node("mix:mix");
    Node_Header->Add_Attribute("xmlns:mix", "http://www.loc.gov/mix/v20");
    Node_Header->Add_Attribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
    Node_Header->Add_Attribute("xsi:schemaLocation", "http://www.loc.gov/mix/v20 http://www.loc.gov/standards/mix/mix20/mix20.xsd");

    return Node_Header;
}
//***************************************************************************
// Input
//***************************************************************************

//---------------------------------------------------------------------------
Ztring Export_Niso::Transform(MediaInfo_Internal &MI, Ztring ExternalMetadataValues, Ztring ExternalMetaDataConfig)
{
    bool UseExternalMetaData=(!ExternalMetaDataConfig.empty() && !ExternalMetadataValues.empty());

    Ztring ToReturn;
    for (size_t Pos=0; Pos<MI.Count_Get(Stream_Image); Pos++)
    {
        Node* Node_Root = Transform_Header();

        //Use external metadata
        if (UseExternalMetaData)
        {
            Ztring FileName;
            if (!MI.Get(Stream_General, 0, General_FileName).empty())
                FileName=MI.Get(Stream_General, 0, General_FileName);
            if (!MI.Get(Stream_General, 0, General_FileExtension).empty())
                FileName+=__T('.')+MI.Get(Stream_General, 0, General_FileExtension);
            if (FileName.empty())
            {
                MediaInfoLib::Config.Log_Send(0xC0, 0xFF, 0, "File name not found in external metadata file");
                delete Node_Root;
                return Ztring();
            }

            Node* Node_Extension=Node_Root->Add_Child("mix:Extension");

            if (ExternalMetaDataConfig.find(__T("<ebucore:ebuCoreMain"))<100)
            {
                //TODO: merge with EBUCore code
                //Current date/time is ISO format
                time_t Seconds = time(NULL);
                Ztring DateTime; DateTime.Date_From_Seconds_1970((int32u)Seconds);
                if (DateTime.size() >= 4 && DateTime[0] == __T('U') && DateTime[1] == __T('T') && DateTime[2] == __T('C') && DateTime[3] == __T(' '))
                {
                    DateTime.erase(0, 4);
                    DateTime += __T('Z');
                }
                Ztring Date = DateTime.substr(0, 10);
                Ztring Time = DateTime.substr(11);

                Node* Node_CoreMain = Node_Extension->Add_Child("ebucore:ebuCoreMain");
                Node_CoreMain->Add_Attribute("xmlns:dc", "http://purl.org/dc/elements/1.1/");
                {
                    Node_CoreMain->Add_Attribute("xmlns:ebucore", "urn:ebu:metadata-schema:ebucore");
                    Node_CoreMain->Add_Attribute("xmlns:xalan", "http://xml.apache.org/xalan");
                    Node_CoreMain->Add_Attribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
                    Node_CoreMain->Add_Attribute("xsi:schemaLocation", string("urn:ebu:metadata-schema:ebucore http") + string(MediaInfoLib::Config.Https_Get() ? "s" : "") + "://www.ebu.ch/metadata/schemas/EBUCore/20171009/ebucore.xsd");
                    Node_CoreMain->Add_Attribute("version", "1.8");
                    Node_CoreMain->Add_Attribute("writingLibraryName", "MediaInfoLib");
                    Node_CoreMain->Add_Attribute("writingLibraryVersion", MediaInfoLib::Config.Info_Version_Get().SubString(__T(" - v"), Ztring()));
                }
                Node_CoreMain->Add_Attribute("dateLastModified", Date);
                Node_CoreMain->Add_Attribute("timeLastModified", Time);

                Node_Extension = Node_CoreMain;
            }

            if (!ExternalMetadata(FileName, ExternalMetadataValues, ExternalMetaDataConfig, ZtringList(__T("mix:Extension;ebucore:ebuCoreMain")), __T(""), Node_Extension, NULL))
            {
                delete Node_Root;
                return Ztring();
            }
        }

        size_t Extension_Size=Node_Root->Childs.size();

        //BasicDigitalObjectInformation
        Node* Node_BasicDigitalObjectInformation = new Node("mix:BasicDigitalObjectInformation");

        //TODO: mix:byteOrder
        std::string CompressionScheme = MI.Get(Stream_Image, Pos, Image_Codec).To_UTF8();
        if (!CompressionScheme.empty())
            Node_BasicDigitalObjectInformation->Add_Child("mix:Compression")->Add_Child("mix:compressionScheme", CompressionScheme=="Raw"?std::string("Uncompressed"):CompressionScheme);

        if (!Node_BasicDigitalObjectInformation->Childs.empty())
            Node_Root->Childs.insert(Node_Root->Childs.end()-Extension_Size, Node_BasicDigitalObjectInformation);
        else
            delete Node_BasicDigitalObjectInformation;

        Node* Node_BasicImageInformation = new Node("mix:BasicImageInformation");
        Node* Node_BasicImageCharacteristics = new Node("mix:BasicImageCharacteristics");

        Node_BasicImageCharacteristics->Add_Child_IfNotEmpty(MI, Stream_Image, Pos, Image_Width, "mix:imageWidth");
        Node_BasicImageCharacteristics->Add_Child_IfNotEmpty(MI, Stream_Image, Pos, Image_Height, "mix:imageHeight");

        Node* Node_PhotometricInterpretation = new Node("mix:PhotometricInterpretation");

        Node_PhotometricInterpretation->Add_Child_IfNotEmpty(MI, Stream_Image, Pos, Image_ColorSpace, "mix:colorSpace");

        //TODO: mix:ReferenceBlackWhite

        if (!Node_PhotometricInterpretation->Childs.empty())
            Node_BasicImageCharacteristics->Childs.push_back(Node_PhotometricInterpretation);
        else
            delete Node_PhotometricInterpretation;

        if (!Node_BasicImageCharacteristics->Childs.empty())
            Node_BasicImageInformation->Childs.push_back(Node_BasicImageCharacteristics);
        else
            delete Node_BasicImageCharacteristics;

        if (!Node_BasicImageInformation->Childs.empty())
            Node_Root->Childs.insert(Node_Root->Childs.end()-Extension_Size, Node_BasicImageInformation);
        else
            delete Node_BasicImageInformation;

        //TODO: mix:ImageCaptureMetadata

        Node* Node_ImageAssessmentMetadata = new Node("mix:ImageAssessmentMetadata");
        //TODO: mix:SpatialMetrics

        Node* Node_ImageColorEncoding = new Node("mix:ImageColorEncoding");
        Node* Node_BitsPerSample = new Node("mix:BitsPerSample");

        size_t SamplesPerPixel = MI.Get(Stream_Image, Pos, Image_ColorSpace).length();
        for (size_t Pos2 = 0; Pos2<SamplesPerPixel; ++Pos2)
            Node_BitsPerSample->Add_Child_IfNotEmpty(MI, Stream_Image, Pos, Image_BitDepth, "mix:bitsPerSampleValue");

        if (!Node_BitsPerSample->Childs.empty())
        {
            Node_BitsPerSample->Add_Child("mix:bitsPerSampleUnit", std::string("integer"));
            Node_ImageColorEncoding->Childs.push_back(Node_BitsPerSample);
        }
        else
           delete Node_BitsPerSample;

        if (SamplesPerPixel)
            Node_ImageColorEncoding->Add_Child("mix:samplesPerPixel", Ztring().From_Number(SamplesPerPixel).To_UTF8());

        if (!Node_ImageColorEncoding->Childs.empty())
            Node_ImageAssessmentMetadata->Childs.push_back(Node_ImageColorEncoding);
        else
            delete Node_ImageColorEncoding;

        if (!Node_ImageAssessmentMetadata->Childs.empty())
            Node_Root->Childs.insert(Node_Root->Childs.end()-Extension_Size, Node_ImageAssessmentMetadata);
        else
            delete Node_ImageAssessmentMetadata;

        ToReturn+=Ztring().From_UTF8(To_XML(*Node_Root, 0, true, true).c_str());
    }

    if (ToReturn.empty())
        ToReturn+=Ztring().From_UTF8(To_XML(*Transform_Header(), 0, true, true).c_str())+=__T("\n");

    //Carriage return
    if (MediaInfoLib::Config.LineSeparator_Get()!=__T("\n"))
        ToReturn.FindAndReplace(__T("\n"), MediaInfoLib::Config.LineSeparator_Get(), 0, Ztring_Recursive);

    return ToReturn;
}

//***************************************************************************
//
//***************************************************************************

} //NameSpace

#endif
<commit_msg>+ NISO Z39.87 output: more elements supported<commit_after>/*  Copyright (c) MediaArea.net SARL. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license that can
 *  be found in the License.html file in the root of the source tree.
 */

//---------------------------------------------------------------------------
// Pre-compilation
#include "MediaInfo/PreComp.h"
#ifdef __BORLANDC__
    #pragma hdrstop
#endif
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
#include "MediaInfo/Setup.h"
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
#if defined(MEDIAINFO_NISO_YES)
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
#include "MediaInfo/Export/Export_Niso.h"
#include "MediaInfo/File__Analyse_Automatic.h"
#include "MediaInfo/OutputHelpers.h"
#include <ctime>

using namespace std;

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

namespace MediaInfoLib
{
//---------------------------------------------------------------------------
extern MediaInfo_Config Config;
//---------------------------------------------------------------------------

//***************************************************************************
// Constructor/Destructor
//***************************************************************************

//---------------------------------------------------------------------------
Export_Niso::Export_Niso ()
{
}

//---------------------------------------------------------------------------
Export_Niso::~Export_Niso ()
{
}

//***************************************************************************
// Helpers
//***************************************************************************
Node* Transform_Header()
{
    //Root node
    Node* Node_Header = new Node("mix:mix");
    Node_Header->Add_Attribute("xmlns:mix", "http://www.loc.gov/mix/v20");
    Node_Header->Add_Attribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
    Node_Header->Add_Attribute("xsi:schemaLocation", "http://www.loc.gov/mix/v20 http://www.loc.gov/standards/mix/mix20/mix20.xsd");

    return Node_Header;
}
//***************************************************************************
// Input
//***************************************************************************

//---------------------------------------------------------------------------
Ztring Export_Niso::Transform(MediaInfo_Internal &MI, Ztring ExternalMetadataValues, Ztring ExternalMetaDataConfig)
{
    bool UseExternalMetaData=(!ExternalMetaDataConfig.empty() && !ExternalMetadataValues.empty());

    Ztring ToReturn;
    for (size_t Pos=0; Pos<MI.Count_Get(Stream_Image); Pos++)
    {
        Node* Node_Root = Transform_Header();

        //Use external metadata
        if (UseExternalMetaData)
        {
            Ztring FileName;
            if (!MI.Get(Stream_General, 0, General_FileName).empty())
                FileName=MI.Get(Stream_General, 0, General_FileName);
            if (!MI.Get(Stream_General, 0, General_FileExtension).empty())
                FileName+=__T('.')+MI.Get(Stream_General, 0, General_FileExtension);
            if (FileName.empty())
            {
                MediaInfoLib::Config.Log_Send(0xC0, 0xFF, 0, "File name not found in external metadata file");
                delete Node_Root;
                return Ztring();
            }

            Node* Node_Extension=Node_Root->Add_Child("mix:Extension");

            if (ExternalMetaDataConfig.find(__T("<ebucore:ebuCoreMain"))<100)
            {
                //TODO: merge with EBUCore code
                //Current date/time is ISO format
                time_t Seconds = time(NULL);
                Ztring DateTime; DateTime.Date_From_Seconds_1970((int32u)Seconds);
                if (DateTime.size() >= 4 && DateTime[0] == __T('U') && DateTime[1] == __T('T') && DateTime[2] == __T('C') && DateTime[3] == __T(' '))
                {
                    DateTime.erase(0, 4);
                    DateTime += __T('Z');
                }
                Ztring Date = DateTime.substr(0, 10);
                Ztring Time = DateTime.substr(11);

                Node* Node_CoreMain = Node_Extension->Add_Child("ebucore:ebuCoreMain");
                Node_CoreMain->Add_Attribute("xmlns:dc", "http://purl.org/dc/elements/1.1/");
                {
                    Node_CoreMain->Add_Attribute("xmlns:ebucore", "urn:ebu:metadata-schema:ebucore");
                    Node_CoreMain->Add_Attribute("xmlns:xalan", "http://xml.apache.org/xalan");
                    Node_CoreMain->Add_Attribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
                    Node_CoreMain->Add_Attribute("xsi:schemaLocation", string("urn:ebu:metadata-schema:ebucore http") + string(MediaInfoLib::Config.Https_Get() ? "s" : "") + "://www.ebu.ch/metadata/schemas/EBUCore/20171009/ebucore.xsd");
                    Node_CoreMain->Add_Attribute("version", "1.8");
                    Node_CoreMain->Add_Attribute("writingLibraryName", "MediaInfoLib");
                    Node_CoreMain->Add_Attribute("writingLibraryVersion", MediaInfoLib::Config.Info_Version_Get().SubString(__T(" - v"), Ztring()));
                }
                Node_CoreMain->Add_Attribute("dateLastModified", Date);
                Node_CoreMain->Add_Attribute("timeLastModified", Time);

                Node_Extension = Node_CoreMain;
            }

            if (!ExternalMetadata(FileName, ExternalMetadataValues, ExternalMetaDataConfig, ZtringList(__T("mix:Extension;ebucore:ebuCoreMain")), __T(""), Node_Extension, NULL))
            {
                delete Node_Root;
                return Ztring();
            }
        }

        size_t Extension_Size=Node_Root->Childs.size();

        //BasicDigitalObjectInformation
        Node* Node_BasicDigitalObjectInformation = new Node("mix:BasicDigitalObjectInformation");
        Node_BasicDigitalObjectInformation->Add_Child("mix:ObjectIdentifier")->Add_Child("mix:objectIdentifierType", string("MediaInfo"));

        std::string byteOrder = MI.Get(Stream_Image, Pos, Image_Format_Settings_Endianness).To_UTF8();
        if (!byteOrder.empty())
            Node_BasicDigitalObjectInformation->Add_Child("mix:byteOrder", byteOrder=="Little"?std::string("little endian"):(byteOrder=="Big"?std::string("big endian"): byteOrder));

        std::string CompressionScheme = MI.Get(Stream_Image, Pos, Image_Format).To_UTF8();
        if (!CompressionScheme.empty())
            Node_BasicDigitalObjectInformation->Add_Child("mix:Compression")->Add_Child("mix:compressionScheme", CompressionScheme=="Raw"?std::string("Uncompressed"):CompressionScheme);

        if (!Node_BasicDigitalObjectInformation->Childs.empty())
            Node_Root->Childs.insert(Node_Root->Childs.end()-Extension_Size, Node_BasicDigitalObjectInformation);
        else
            delete Node_BasicDigitalObjectInformation;

        Node* Node_BasicImageInformation = new Node("mix:BasicImageInformation");
        Node* Node_BasicImageCharacteristics = new Node("mix:BasicImageCharacteristics");

        Node_BasicImageCharacteristics->Add_Child_IfNotEmpty(MI, Stream_Image, Pos, Image_Width, "mix:imageWidth");
        Node_BasicImageCharacteristics->Add_Child_IfNotEmpty(MI, Stream_Image, Pos, Image_Height, "mix:imageHeight");

        Node* Node_PhotometricInterpretation = new Node("mix:PhotometricInterpretation");

        Node_PhotometricInterpretation->Add_Child_IfNotEmpty(MI, Stream_Image, Pos, Image_ColorSpace, "mix:colorSpace");

        //ReferenceBlackWhite
        std::string ColorSpace = MI.Get(Stream_Image, Pos, Image_ColorSpace).To_UTF8();
        if (!ColorSpace.empty())
        {
            Node* ReferenceBlackWhite = Node_PhotometricInterpretation->Add_Child("mix:ReferenceBlackWhite");
            for (size_t i = 0; i < ColorSpace.size(); i++)
            {
                Node* Component = ReferenceBlackWhite->Add_Child("mix:Component");
                Component->Add_Child("mix:componentPhotometricInterpretation", string(1, ColorSpace[i]));
                Node* footroom = Component->Add_Child("mix:footroom");
                footroom->Add_Child("mix:numerator", Ztring::ToZtring(0));
                int8u BitDepth=MI.Get(Stream_Image, Pos, Image_BitDepth).To_int8u();
                if (BitDepth)
                {
                    Node* headroom = Component->Add_Child("mix:headroom");
                    headroom->Add_Child("mix:numerator", Ztring::ToZtring((1<<BitDepth)-1));
                }
            }
        }

        if (!Node_PhotometricInterpretation->Childs.empty())
            Node_BasicImageCharacteristics->Childs.push_back(Node_PhotometricInterpretation);
        else
            delete Node_PhotometricInterpretation;

        if (!Node_BasicImageCharacteristics->Childs.empty())
            Node_BasicImageInformation->Childs.push_back(Node_BasicImageCharacteristics);
        else
            delete Node_BasicImageCharacteristics;

        if (!Node_BasicImageInformation->Childs.empty())
            Node_Root->Childs.insert(Node_Root->Childs.end()-Extension_Size, Node_BasicImageInformation);
        else
            delete Node_BasicImageInformation;

        //ImageCaptureMetadata
        std::string Make = MI.Get(Stream_General, 0, General_Encoded_Application_CompanyName).To_UTF8();
        std::string Model = MI.Get(Stream_General, 0, General_Encoded_Library_Name).To_UTF8();
        std::string Software = MI.Get(Stream_General, 0, General_Encoded_Application_Name).To_UTF8();
        std::string Encoded_Date = MI.Get(Stream_Image, Pos, Image_Encoded_Date).To_UTF8();
        if (!Make.empty() || !Model.empty() || !Software.empty() || !Encoded_Date.empty())
        {
            Node* Node_ImageCaptureMetadata = new Node("mix:ImageCaptureMetadata");
            Node_Root->Childs.insert(Node_Root->Childs.end() - Extension_Size, Node_ImageCaptureMetadata);

            if (!Encoded_Date.empty())
            {
                if (Encoded_Date.size()>4 && Encoded_Date[4]==':')
                    Encoded_Date[4]='-';
                if (Encoded_Date.size()>7 && Encoded_Date[7]==':')
                    Encoded_Date[7]='-';
                if (Encoded_Date.size()>10 && Encoded_Date[10]==' ')
                    Encoded_Date[10]='T';
                Node* Node_GeneralCaptureInformation = Node_ImageCaptureMetadata->Add_Child("mix:GeneralCaptureInformation");
                Node_GeneralCaptureInformation->Add_Child("mix:dateTimeCreated", Encoded_Date);
            }

            if (!Make.empty() || !Model.empty() || !Software.empty() )
            {
                Node* Node_ScannerCapture = Node_ImageCaptureMetadata->Add_Child("mix:ScannerCapture");
                if (!Make.empty())
                    Node_ScannerCapture->Add_Child("mix:scannerManufacturer", Make);
                if (!Model.empty())
                    Node_ScannerCapture->Add_Child("mix:ScannerModel")->Add_Child("mix:scannerModelName", Model);
                if (!Software.empty())
                    Node_ScannerCapture->Add_Child("mix:ScanningSystemSoftware")->Add_Child("mix:scanningSoftwareName", Software);
            }
        }

        Node* Node_ImageAssessmentMetadata = new Node("mix:ImageAssessmentMetadata");

        //SpatialMetrics
        string samplingFrequencyUnit=MI.Get(Stream_Image, Pos, __T("Density_Unit")).To_UTF8();
        string xSamplingFrequency=MI.Get(Stream_Image, Pos, __T("Density_X")).To_UTF8();
        string ySamplingFrequency=MI.Get(Stream_Image, Pos, __T("Density_Y")).To_UTF8();
        if (!xSamplingFrequency.empty() || !ySamplingFrequency.empty())
        {
            Node* Node_SpatialMetrics = Node_ImageAssessmentMetadata->Add_Child("mix:SpatialMetrics");

            if (samplingFrequencyUnit.empty())
                Node_SpatialMetrics->Add_Child("mix:samplingFrequencyUnit", string("no absolute unit of measurement"));
            else if (samplingFrequencyUnit=="dpi")
                Node_SpatialMetrics->Add_Child("mix:samplingFrequencyUnit", string("in."));
            else if (samplingFrequencyUnit=="dpcm")
                Node_SpatialMetrics->Add_Child("mix:samplingFrequencyUnit", string("cm"));

            if (!xSamplingFrequency.empty())
                Node_SpatialMetrics->Add_Child("mix:xSamplingFrequency")->Add_Child("mix:numerator", xSamplingFrequency);

            if (!ySamplingFrequency.empty())
                Node_SpatialMetrics->Add_Child("mix:ySamplingFrequency")->Add_Child("mix:numerator", ySamplingFrequency);
        }

        Node* Node_ImageColorEncoding = new Node("mix:ImageColorEncoding");
        Node* Node_BitsPerSample = new Node("mix:BitsPerSample");

        size_t SamplesPerPixel = MI.Get(Stream_Image, Pos, Image_ColorSpace).length();
        for (size_t Pos2 = 0; Pos2<SamplesPerPixel; ++Pos2)
            Node_BitsPerSample->Add_Child_IfNotEmpty(MI, Stream_Image, Pos, Image_BitDepth, "mix:bitsPerSampleValue");

        if (!Node_BitsPerSample->Childs.empty())
        {
            Node_BitsPerSample->Add_Child("mix:bitsPerSampleUnit", std::string("integer"));
            Node_ImageColorEncoding->Childs.push_back(Node_BitsPerSample);
        }
        else
           delete Node_BitsPerSample;

        if (SamplesPerPixel)
            Node_ImageColorEncoding->Add_Child("mix:samplesPerPixel", Ztring().From_Number(SamplesPerPixel).To_UTF8());

        if (!Node_ImageColorEncoding->Childs.empty())
            Node_ImageAssessmentMetadata->Childs.push_back(Node_ImageColorEncoding);
        else
            delete Node_ImageColorEncoding;

        if (!Node_ImageAssessmentMetadata->Childs.empty())
            Node_Root->Childs.insert(Node_Root->Childs.end()-Extension_Size, Node_ImageAssessmentMetadata);
        else
            delete Node_ImageAssessmentMetadata;

        ToReturn+=Ztring().From_UTF8(To_XML(*Node_Root, 0, true, true).c_str());
    }

    if (ToReturn.empty())
        ToReturn+=Ztring().From_UTF8(To_XML(*Transform_Header(), 0, true, true).c_str())+=__T("\n");

    //Carriage return
    if (MediaInfoLib::Config.LineSeparator_Get()!=__T("\n"))
        ToReturn.FindAndReplace(__T("\n"), MediaInfoLib::Config.LineSeparator_Get(), 0, Ztring_Recursive);

    return ToReturn;
}

//***************************************************************************
//
//***************************************************************************

} //NameSpace

#endif
<|endoftext|>


<commit_before>//
// Copyright (c) 2017-2020 the rbfx project.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

#include <Urho3D/Graphics/Camera.h>
#include <Urho3D/Scene/Node.h>
#include <Urho3D/Core/CoreEvents.h>
#include <Urho3D/Input/Input.h>
#include <Urho3D/UI/UI.h>
#include <Urho3D/Scene/Scene.h>
#include <Urho3D/Graphics/Octree.h>
#include <Urho3D/Graphics/Graphics.h>
#include <Urho3D/Graphics/GraphicsEvents.h>
#include <Urho3D/Graphics/AnimatedModel.h>
#include <Urho3D/Graphics/DebugRenderer.h>
#include <Urho3D/IO/Log.h>
#include <Urho3D/SystemUI/SystemUI.h>
#include <Urho3D/Graphics/Light.h>
#include <ImGui/imgui_internal.h>
#include <ImGuizmo/ImGuizmo.h>
#include "Gizmo.h"

namespace Urho3D
{

Gizmo::Gizmo(Context* context) : Object(context)
{
}

Gizmo::~Gizmo()
{
    UnsubscribeFromAllEvents();
}

bool Gizmo::Manipulate(const Camera* camera, Node* node)
{
    ea::vector<WeakPtr<Node>> nodes;
    nodes.push_back(WeakPtr<Node>(node));
    return Manipulate(camera, nodes);
}

bool Gizmo::IsActive() const
{
    return ImGuizmo::IsUsing();
}

bool Gizmo::Manipulate(const Camera* camera, const ea::vector<WeakPtr<Node>>& nodes)
{
    if (nodes.empty())
        return false;

    ImGuizmo::SetOrthographic(camera->IsOrthographic());

    if (!IsActive())
    {
        if (nodes.size() > 1)
        {
            // Find center point of all nodes
            // It is not clear what should be rotation and scale of center point for multiselection, therefore we limit
            // multiselection operations to world space (see above).
            Vector3 center;
            auto count = GetSelectionCenter(center, nodes);
            if (count == 0)
                return false;
            currentOrigin_.SetTranslation(center);
        }
        else if (!nodes.front().Expired())
            currentOrigin_ = nodes.front()->GetTransform().ToMatrix4();
    }

    // Enums are compatible.
    auto operation = static_cast<ImGuizmo::OPERATION>(operation_);
    ImGuizmo::MODE mode = ImGuizmo::WORLD;
    // Scaling only works in local space. Multiselections only work in world space.
    if (transformSpace_ == TS_LOCAL)
        mode = ImGuizmo::LOCAL;
    else if (transformSpace_ == TS_WORLD)
        mode = ImGuizmo::WORLD;

    // Scaling is always done in local space even for multiselections.
    if (operation_ == GIZMOOP_SCALE)
        mode = ImGuizmo::LOCAL;
        // Any other operations on multiselections are done in world space.
    else if (nodes.size() > 1)
        mode = ImGuizmo::WORLD;

    Matrix4 view = camera->GetView().ToMatrix4().Transpose();
    Matrix4 proj = camera->GetProjection().Transpose();
    Matrix4 tran = currentOrigin_.Transpose();
    Matrix4 delta;

    ImGuiWindow* window = ui::GetCurrentWindow();
    ImGuizmo::SetRect(window->Pos.x, window->Pos.y, window->Size.x, window->Size.y);
    ImGuizmo::Manipulate(&view.m00_, &proj.m00_, operation, mode, &tran.m00_, &delta.m00_, nullptr);

    if (IsActive())
    {
        if (!wasActive_)
        {
            // Just started modifying nodes.
            for (const auto& node: nodes)
                initialTransforms_[node] = node->GetTransform();
        }

        wasActive_ = true;
        tran = tran.Transpose();
        delta = delta.Transpose();

        currentOrigin_ = Matrix4(tran);

        for (const auto& node: nodes)
        {
            if (node == nullptr)
            {
                URHO3D_LOGERROR("Gizmo received null pointer of node.");
                continue;
            }

            if (operation_ == GIZMOOP_SCALE)
            {
                // A workaround for ImGuizmo bug where delta matrix returns absolute scale value.
                if (!nodeScaleStart_.contains(node))
                    nodeScaleStart_[node] = node->GetScale();
                node->SetScale(nodeScaleStart_[node] * delta.Scale());
            }
            else
            {
                // Delta matrix is always in world-space.
                if (operation_ == GIZMOOP_ROTATE)
                    node->RotateAround(currentOrigin_.Translation(), -delta.Rotation(), TS_WORLD);
                else
                    node->Translate(delta.Translation(), TS_WORLD);
            }
        }

        return true;
    }
    else
    {
        if (wasActive_)
        {
            // Just finished modifying nodes.
            using namespace GizmoNodeModified;
            for (const auto& node: nodes)
            {
                if (node.Expired())
                {
                    URHO3D_LOGWARNINGF("Node expired while manipulating it with gizmo.");
                    continue;
                }

                auto it = initialTransforms_.find(node.Get());
                if (it == initialTransforms_.end())
                {
                    URHO3D_LOGWARNINGF("Gizmo has no record of initial node transform. List of transformed nodes "
                        "changed mid-manipulation?");
                    continue;
                }

                SendEvent(E_GIZMONODEMODIFIED, P_NODE, node.Get(), P_OLDTRANSFORM, it->second,
                    P_NEWTRANSFORM, node->GetTransform());
            }
        }
        wasActive_ = false;
        initialTransforms_.clear();
        if (operation_ == GIZMOOP_SCALE && !nodeScaleStart_.empty())
            nodeScaleStart_.clear();
    }
    return false;
}

bool Gizmo::ManipulateSelection(const Camera* camera)
{
    ImGuizmo::SetDrawlist();

    // Remove expired selections
    for (auto it = nodeSelection_.begin(); it != nodeSelection_.end();)
    {
        if (it->Expired())
            it = nodeSelection_.erase(it);
        else
            ++it;
    }

    return Manipulate(camera, nodeSelection_);
}

void Gizmo::RenderUI()
{
    ui::TextUnformatted("Op:");
    ui::SameLine(60);

    if (ui::RadioButton("Tr", GetOperation() == GIZMOOP_TRANSLATE))
        SetOperation(GIZMOOP_TRANSLATE);
    ui::SameLine();
    if (ui::RadioButton("Rot", GetOperation() == GIZMOOP_ROTATE))
        SetOperation(GIZMOOP_ROTATE);
    ui::SameLine();
    if (ui::RadioButton("Scl", GetOperation() == GIZMOOP_SCALE))
        SetOperation(GIZMOOP_SCALE);

    ui::TextUnformatted("Space:");
    ui::SameLine(60);
    if (ui::RadioButton("World", GetTransformSpace() == TS_WORLD))
        SetTransformSpace(TS_WORLD);
    ui::SameLine();
    if (ui::RadioButton("Local", GetTransformSpace() == TS_LOCAL))
        SetTransformSpace(TS_LOCAL);
}

bool Gizmo::Select(Node* node)
{
    WeakPtr<Node> weakNode(node);
    if (nodeSelection_.contains(weakNode))
        return false;
    nodeSelection_.push_back(weakNode);
    SendEvent(E_GIZMOSELECTIONCHANGED);
    return true;
}

bool Gizmo::Select(ea::vector<Node*> nodes)
{
    bool selectedAny = false;
    for (auto* node : nodes)
    {
        WeakPtr<Node> weakNode(node);
        if (!nodeSelection_.contains(weakNode))
        {
            nodeSelection_.push_back(weakNode);
            selectedAny = true;
        }
    }
    if (selectedAny)
        SendEvent(E_GIZMOSELECTIONCHANGED);

    return selectedAny;
}

bool Gizmo::Unselect(Node* node)
{
    WeakPtr<Node> weakNode(node);
    if (!nodeSelection_.contains(weakNode))
        return false;
    nodeSelection_.erase_first(weakNode);
    SendEvent(E_GIZMOSELECTIONCHANGED);
    return true;
}

void Gizmo::ToggleSelection(Node* node)
{
    if (IsSelected(node))
        Unselect(node);
    else
        Select(node);
}

bool Gizmo::UnselectAll()
{
    if (nodeSelection_.empty())
        return false;
    nodeSelection_.clear();
    SendEvent(E_GIZMOSELECTIONCHANGED);
    return true;
}

bool Gizmo::IsSelected(Node* node) const
{
    WeakPtr<Node> pNode(node);
    return nodeSelection_.contains(pNode);
}

const int Gizmo::GetSelectionCenter(Vector3& outCenter, const ea::vector<WeakPtr<Node>>& nodes) const
{
    outCenter = Vector3::ZERO;
    auto count = 0;
    for (const auto& node: nodes)
    {
        if (node.Expired() || node->GetType() == Scene::GetTypeStatic())
            continue;
        outCenter += node->GetWorldPosition();
        count++;
    }

    if (count != 0)
        outCenter /= count;
    return count;
}

const int Gizmo::GetSelectionCenter(Vector3& outCenter) const
{
    int ret = GetSelectionCenter(outCenter, GetSelection());
    return ret;
}

}
<commit_msg>Editor: Fix gizmo rendered in the wrong position. Fixes #177.<commit_after>//
// Copyright (c) 2017-2020 the rbfx project.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

#include <Urho3D/Graphics/Camera.h>
#include <Urho3D/Scene/Node.h>
#include <Urho3D/Core/CoreEvents.h>
#include <Urho3D/Input/Input.h>
#include <Urho3D/UI/UI.h>
#include <Urho3D/Scene/Scene.h>
#include <Urho3D/Graphics/Octree.h>
#include <Urho3D/Graphics/Graphics.h>
#include <Urho3D/Graphics/GraphicsEvents.h>
#include <Urho3D/Graphics/AnimatedModel.h>
#include <Urho3D/Graphics/DebugRenderer.h>
#include <Urho3D/IO/Log.h>
#include <Urho3D/SystemUI/SystemUI.h>
#include <Urho3D/Graphics/Light.h>
#include <ImGui/imgui_internal.h>
#include <ImGuizmo/ImGuizmo.h>
#include "Gizmo.h"

namespace Urho3D
{

Gizmo::Gizmo(Context* context) : Object(context)
{
}

Gizmo::~Gizmo()
{
    UnsubscribeFromAllEvents();
}

bool Gizmo::Manipulate(const Camera* camera, Node* node)
{
    ea::vector<WeakPtr<Node>> nodes;
    nodes.push_back(WeakPtr<Node>(node));
    return Manipulate(camera, nodes);
}

bool Gizmo::IsActive() const
{
    return ImGuizmo::IsUsing();
}

bool Gizmo::Manipulate(const Camera* camera, const ea::vector<WeakPtr<Node>>& nodes)
{
    if (nodes.empty())
        return false;

    ImGuizmo::SetOrthographic(camera->IsOrthographic());

    if (!IsActive())
    {
        if (nodes.size() > 1)
        {
            // Find center point of all nodes
            // It is not clear what should be rotation and scale of center point for multiselection, therefore we limit
            // multiselection operations to world space (see above).
            Vector3 center;
            auto count = GetSelectionCenter(center, nodes);
            if (count == 0)
                return false;
            currentOrigin_.SetTranslation(center);
        }
        else if (!nodes.front().Expired())
            currentOrigin_ = nodes.front()->GetWorldTransform().ToMatrix4();
    }

    // Enums are compatible.
    auto operation = static_cast<ImGuizmo::OPERATION>(operation_);
    ImGuizmo::MODE mode = ImGuizmo::WORLD;
    // Scaling only works in local space. Multiselections only work in world space.
    if (transformSpace_ == TS_LOCAL)
        mode = ImGuizmo::LOCAL;
    else if (transformSpace_ == TS_WORLD)
        mode = ImGuizmo::WORLD;

    // Scaling is always done in local space even for multiselections.
    if (operation_ == GIZMOOP_SCALE)
        mode = ImGuizmo::LOCAL;
        // Any other operations on multiselections are done in world space.
    else if (nodes.size() > 1)
        mode = ImGuizmo::WORLD;

    Matrix4 view = camera->GetView().ToMatrix4().Transpose();
    Matrix4 proj = camera->GetProjection().Transpose();
    Matrix4 tran = currentOrigin_.Transpose();
    Matrix4 delta;

    ImGuiWindow* window = ui::GetCurrentWindow();
    ImGuizmo::SetRect(window->Pos.x, window->Pos.y, window->Size.x, window->Size.y);
    ImGuizmo::Manipulate(&view.m00_, &proj.m00_, operation, mode, &tran.m00_, &delta.m00_, nullptr);

    if (IsActive())
    {
        if (!wasActive_)
        {
            // Just started modifying nodes.
            for (const auto& node: nodes)
                initialTransforms_[node] = node->GetTransform();
        }

        wasActive_ = true;
        tran = tran.Transpose();
        delta = delta.Transpose();

        currentOrigin_ = Matrix4(tran);

        for (const auto& node: nodes)
        {
            if (node == nullptr)
            {
                URHO3D_LOGERROR("Gizmo received null pointer of node.");
                continue;
            }

            if (operation_ == GIZMOOP_SCALE)
            {
                // A workaround for ImGuizmo bug where delta matrix returns absolute scale value.
                if (!nodeScaleStart_.contains(node))
                    nodeScaleStart_[node] = node->GetScale();
                node->SetScale(nodeScaleStart_[node] * delta.Scale());
            }
            else
            {
                // Delta matrix is always in world-space.
                if (operation_ == GIZMOOP_ROTATE)
                    node->RotateAround(currentOrigin_.Translation(), -delta.Rotation(), TS_WORLD);
                else
                    node->Translate(delta.Translation(), TS_WORLD);
            }
        }

        return true;
    }
    else
    {
        if (wasActive_)
        {
            // Just finished modifying nodes.
            using namespace GizmoNodeModified;
            for (const auto& node: nodes)
            {
                if (node.Expired())
                {
                    URHO3D_LOGWARNINGF("Node expired while manipulating it with gizmo.");
                    continue;
                }

                auto it = initialTransforms_.find(node.Get());
                if (it == initialTransforms_.end())
                {
                    URHO3D_LOGWARNINGF("Gizmo has no record of initial node transform. List of transformed nodes "
                        "changed mid-manipulation?");
                    continue;
                }

                SendEvent(E_GIZMONODEMODIFIED, P_NODE, node.Get(), P_OLDTRANSFORM, it->second,
                    P_NEWTRANSFORM, node->GetTransform());
            }
        }
        wasActive_ = false;
        initialTransforms_.clear();
        if (operation_ == GIZMOOP_SCALE && !nodeScaleStart_.empty())
            nodeScaleStart_.clear();
    }
    return false;
}

bool Gizmo::ManipulateSelection(const Camera* camera)
{
    ImGuizmo::SetDrawlist();

    // Remove expired selections
    for (auto it = nodeSelection_.begin(); it != nodeSelection_.end();)
    {
        if (it->Expired())
            it = nodeSelection_.erase(it);
        else
            ++it;
    }

    return Manipulate(camera, nodeSelection_);
}

void Gizmo::RenderUI()
{
    ui::TextUnformatted("Op:");
    ui::SameLine(60);

    if (ui::RadioButton("Tr", GetOperation() == GIZMOOP_TRANSLATE))
        SetOperation(GIZMOOP_TRANSLATE);
    ui::SameLine();
    if (ui::RadioButton("Rot", GetOperation() == GIZMOOP_ROTATE))
        SetOperation(GIZMOOP_ROTATE);
    ui::SameLine();
    if (ui::RadioButton("Scl", GetOperation() == GIZMOOP_SCALE))
        SetOperation(GIZMOOP_SCALE);

    ui::TextUnformatted("Space:");
    ui::SameLine(60);
    if (ui::RadioButton("World", GetTransformSpace() == TS_WORLD))
        SetTransformSpace(TS_WORLD);
    ui::SameLine();
    if (ui::RadioButton("Local", GetTransformSpace() == TS_LOCAL))
        SetTransformSpace(TS_LOCAL);
}

bool Gizmo::Select(Node* node)
{
    WeakPtr<Node> weakNode(node);
    if (nodeSelection_.contains(weakNode))
        return false;
    nodeSelection_.push_back(weakNode);
    SendEvent(E_GIZMOSELECTIONCHANGED);
    return true;
}

bool Gizmo::Select(ea::vector<Node*> nodes)
{
    bool selectedAny = false;
    for (auto* node : nodes)
    {
        WeakPtr<Node> weakNode(node);
        if (!nodeSelection_.contains(weakNode))
        {
            nodeSelection_.push_back(weakNode);
            selectedAny = true;
        }
    }
    if (selectedAny)
        SendEvent(E_GIZMOSELECTIONCHANGED);

    return selectedAny;
}

bool Gizmo::Unselect(Node* node)
{
    WeakPtr<Node> weakNode(node);
    if (!nodeSelection_.contains(weakNode))
        return false;
    nodeSelection_.erase_first(weakNode);
    SendEvent(E_GIZMOSELECTIONCHANGED);
    return true;
}

void Gizmo::ToggleSelection(Node* node)
{
    if (IsSelected(node))
        Unselect(node);
    else
        Select(node);
}

bool Gizmo::UnselectAll()
{
    if (nodeSelection_.empty())
        return false;
    nodeSelection_.clear();
    SendEvent(E_GIZMOSELECTIONCHANGED);
    return true;
}

bool Gizmo::IsSelected(Node* node) const
{
    WeakPtr<Node> pNode(node);
    return nodeSelection_.contains(pNode);
}

const int Gizmo::GetSelectionCenter(Vector3& outCenter, const ea::vector<WeakPtr<Node>>& nodes) const
{
    outCenter = Vector3::ZERO;
    auto count = 0;
    for (const auto& node: nodes)
    {
        if (node.Expired() || node->GetType() == Scene::GetTypeStatic())
            continue;
        outCenter += node->GetWorldPosition();
        count++;
    }

    if (count != 0)
        outCenter /= count;
    return count;
}

const int Gizmo::GetSelectionCenter(Vector3& outCenter) const
{
    int ret = GetSelectionCenter(outCenter, GetSelection());
    return ret;
}

}
<|endoftext|>


<commit_before>//Includes all the headers necessary to use the most common public pieces of the ROS system.
#include <ros/ros.h>
//Include some useful constants for image encoding. Refer to: http://www.ros.org/doc/api/sensor_msgs/html/namespacesensor__msgs_1_1image__encodings.html for more info.
#include <sensor_msgs/image_encodings.h>
#include <sensor_msgs/LaserScan.h>
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <string>
#include <math.h>
#include <dirent.h>
#include <iomanip>
#include <ctime>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
#include <unistd.h>
#include "icarus_rover_rc/Definitions.h"
#include "icarus_rover_rc/ICARUS_Probe_Status.h"
#include "icarus_rover_rc/ICARUS_Probe_Command.h"

using namespace std;

int Extended_Switch = 0;
int Retracted_Switch = 0;
int Forward_Timeout = 0;
int Reverse_Timeout = 0;
int Recharge_Command = RECHARGE_WAIT;
double forward_timer = 0.0;
double reverse_timer = 0.0;

string MC_Device = "";
int Baud_Rate = -1;
int Probe_State = PROBE_RETRACTED;
int Probe_Error = NO_ERROR;
double dtime = 0.0;
int temp1;
void ICARUS_Probe_Command_Callback(const icarus_rover_rc::ICARUS_Probe_Command::ConstPtr& msg)  //Process ICARUS Probe Command Message
{
  //ROS_INFO("I heard: [%s]", msg->data.c_str());
  Recharge_Command = 0;//msg.Charge_Command;

}
void Recharge_FSM(double dtime)
{
  switch (Probe_State)
  {
    case PROBE_MOVING_FORWARD:
      forward_timer += dtime;
      if (Extended_Switch == true)
      {
        Probe_State = PROBE_EXTENDED;
        Probe_Error = NO_ERROR;
      }
      //servoWrite(WINCH_MOTOR_PIN, WINCH_MOTOR_FORWARD);
      break;
    case PROBE_MOVING_REVERSE:
      reverse_timer += dtime;
      if (Retracted_Switch == true)
      {
        Probe_State = PROBE_RETRACTED;
      }
      //servoWrite(WINCH_MOTOR_PIN,WINCH_MOTOR_REVERSE);
      break;
    case PROBE_EXTENDED:
      forward_timer = 0.0;
      reverse_timer = 0.0;
      if (Recharge_Command == RECHARGE_STOP)
      {
        Probe_State = PROBE_MOVING_REVERSE;
      }
      //servoWrite(WINCH_MOTOR_PIN,WINCH_MOTOR_NEUTRAL);
      break;
    case PROBE_RETRACTED:
      forward_timer = 0.0;
      reverse_timer = 0.0;
      if (Recharge_Command == RECHARGE_START)
      {
        Probe_State = PROBE_MOVING_FORWARD;
        Probe_Error = NO_ERROR;
      }
      //servoWrite(WINCH_MOTOR_PIN,WINCH_MOTOR_NEUTRAL);
      break;
    default:
      //servoWrite(WINCH_MOTOR_PIN,WINCH_MOTOR_NEUTRAL);
      break;
  }
  if (forward_timer > FORWARD_TIME_LIMIT){ Probe_Error = EXTENSION_ERROR; }
  if (reverse_timer > REVERSE_TIME_LIMIT){ Probe_State = RETRACTION_ERROR; }
}
int main(int argc, char **argv)
{
  int INITIALIZED = 0;
  ros::init(argc, argv, "Motion_Controller");
  ros::NodeHandle nh;
  //nh.getParam("target_count",target_count);
  nh.getParam("mc_device",MC_Device);
  nh.getParam("baudrate",Baud_Rate);
  int mc_device;
  struct termios oldtio,newtio;
	int res;

  mc_device= open(MC_Device.c_str(),O_RDWR | O_NOCTTY );

  if (mc_device  == -1)
  {
    ROS_INFO("ERROR: UNABLE TO OPEN SERIAL PORT.");
  }
  else
  {
    if(1)
    {
      INITIALIZED = 1;
      tcgetattr(mc_device,&oldtio);
	    bzero(&newtio, sizeof(newtio));
	    newtio.c_cflag = B115200 | CS8 | CLOCAL | CREAD;
      //newtio.c_cflag &= ~(IXON | IXOFF | IXANY);
	    newtio.c_iflag = IGNPAR;
	    newtio.c_oflag = 0;
	    newtio.c_lflag = 0;
	    newtio.c_cc[VTIME]    = 1;
	    newtio.c_cc[VMIN]     = 5;
                  // 0.5 seconds read timeout

	    tcflush(mc_device, TCIFLUSH);
	    tcsetattr(mc_device,TCSANOW,&newtio);
    }
    else
    {
struct termios tty;
struct termios tty_old;
memset (&tty, 0, sizeof tty);

/* Error Handling */
if ( tcgetattr ( mc_device, &tty ) != 0 ) {
   std::cout << "Error " << errno << " from tcgetattr: " << strerror(errno) << std::endl;
}

/* Save old tty parameters */
tty_old = tty;

/* Set Baud Rate */
cfsetospeed (&tty, (speed_t)B9600);
cfsetispeed (&tty, (speed_t)B9600);

/* Setting other Port Stuff */
tty.c_cflag     &=  ~PARENB;            // Make 8n1
tty.c_cflag     &=  ~CSTOPB;
tty.c_cflag     &=  ~CSIZE;
tty.c_cflag     |=  CS8;

tty.c_cflag     &=  ~CRTSCTS;           // no flow control
tty.c_cc[VMIN]   =  1;                  // read doesn't block
tty.c_cc[VTIME]  =  5;                  // 0.5 seconds read timeout
tty.c_cflag     |=  CREAD | CLOCAL;     // turn on READ & ignore ctrl lines

/* Make raw */
cfmakeraw(&tty);

/* Flush Port, then applies attributes */
tcflush( mc_device, TCIFLUSH );
if ( tcsetattr ( mc_device, TCSANOW, &tty ) != 0) {
   std::cout << "Error " << errno << " from tcsetattr" << std::endl;
}}
}

  ros::Subscriber Sub_ICARUS_Probe_Command_Callback = nh.subscribe("ICARUS_Probe_Command", 1000, ICARUS_Probe_Command_Callback);
  ros::Publisher Pub_ICARUS_Probe_Status = nh.advertise<icarus_rover_rc::ICARUS_Probe_Status>("ICARUS_Probe_Status", 1000);
  ros::Publisher Pub_ICARUS_Sonar_Scan = nh.advertise<sensor_msgs::LaserScan>("ICARUS_Sonar_Scan",1000);
  ros::Rate loop_rate(100);
	std::clock_t    start;
  ::icarus_rover_rc::ICARUS_Probe_Status Probe_Status;
  sensor_msgs::LaserScan Sonar_Scan;
	//LaserScan Sonar_Scan;
  temp1 = 0;
	while( ros::ok() && INITIALIZED)
	{

	  start = std::clock();
	  ros::spinOnce();
	  loop_rate.sleep();

	  try
	  {
	    int wr;
      temp1++;
      if (temp1 > 180) { temp1 = 0; }

      char cmd[255];
      memset(cmd,'\0',sizeof cmd);
      sprintf(cmd,"$NAV,%d,%d,*\r\n",temp1,180-temp1);
      wr = write(mc_device,cmd,sizeof(cmd)-1);
      char buf = '\0';
      char response[255];
      int spot = 0;

      memset(response,'\0',sizeof response);
      //res = read(mc_device,&buf,1);
      //printf("x%c",buf);

      do
      {

        res = read(mc_device,&buf,1);
        sprintf(&response[spot],"%c",buf);
        spot += res;
      } while(buf != '*' && res > 0);
      printf("%s",response);

/*
int n = 0,
    spot = 0;
char buf = '\0';

char response[255];
memset(response, '\0', sizeof response);

do {
   n = read( mc_device, &buf, 1 );
   if (n > 0) { printf("%c",buf); }
   sprintf( &response[spot], "%c", buf );
   spot += n;
} while( buf != '\r' && n > 0);
if (n < 0) {
   //std::cout << "Error reading: " << strerror(errno) << std::endl;
}
else if (n == 0) {
    std::cout << "Read nothing!" << std::endl;
}
else {
    std::cout << "Response: " << response << std::endl;
}*/
	    dtime = (std::clock() - start) / (double)(CLOCKS_PER_SEC /1);
      /*if (digitalRead(EXTENDED_SWITCH_PIN)==0)
      {
        Extended_Switch = true;
      }
      else
      {
        Extended_Switch = false;
      }
      if (digitalRead(RETRACTED_SWITCH_PIN)==0)
      {
        Retracted_Switch = true;
      }
      else
      {
        Retracted_Switch = false;
      }*/

      //Recharge_FSM(dtime);
      Probe_Status.header.stamp = ros::Time::now();
      Probe_Status.header.frame_id = "Probe_Status";
      Probe_Status.Probe_State = Probe_State;
      Probe_Status.Extended_Switch = Extended_Switch;
      Probe_Status.Retracted_Switch = Retracted_Switch;
      Probe_Status.Probe_Error = Probe_Error;

      Sonar_Scan.header.stamp = ros::Time::now();

      Pub_ICARUS_Sonar_Scan.publish(Sonar_Scan);
	    Pub_ICARUS_Probe_Status.publish(Probe_Status);
	  }
	  catch(const std::exception& ex)
	  {
	    ROS_INFO("ERROR:%s",ex.what());
      close(mc_device);
	  }
  }
  close(mc_device);

}
<commit_msg>Added code for better message parsing, and POS message reception.  Started working on Subscribing to ROS Joy topic.<commit_after>//Includes all the headers necessary to use the most common public pieces of the ROS system.
#include <ros/ros.h>
//Include some useful constants for image encoding. Refer to: http://www.ros.org/doc/api/sensor_msgs/html/namespacesensor__msgs_1_1image__encodings.html for more info.
#include <sensor_msgs/image_encodings.h>
#include <sensor_msgs/Joy.h>
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <string>
#include <math.h>
#include <dirent.h>
#include <iomanip>
#include <ctime>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
#include <unistd.h>
#include "icarus_rover_rc/Definitions.h"
#include "icarus_rover_rc/ICARUS_Probe_Status.h"
#include "icarus_rover_rc/ICARUS_Probe_Command.h"

using namespace std;

int Extended_Switch = 0;
int Retracted_Switch = 0;
int Forward_Timeout = 0;
int Reverse_Timeout = 0;
int Recharge_Command = RECHARGE_WAIT;
double forward_timer = 0.0;
double reverse_timer = 0.0;

//Communication Variables
int token_index = 0;
string MC_Device = "";
int Baud_Rate = -1;
int in_message_started = 0;
int in_message_completed = 0;

//Position Variables
double Pose_X;
double Pose_Y;
double Heading;

//Motion Variables
float Steer_Command;
float Drive_Command;

//Other Variables
int Probe_State = PROBE_RETRACTED;
int Probe_Error = NO_ERROR;
double dtime = 0.0;
int temp1;

void ICARUS_Probe_Command_Callback(const icarus_rover_rc::ICARUS_Probe_Command::ConstPtr& msg)  //Process ICARUS Probe Command Message
{
  //ROS_INFO("I heard: [%s]", msg->data.c_str());
  Recharge_Command = 0;//msg.Charge_Command;

}
void ICARUS_Rover_Control_Callback(const sensor_msgs::Joy::ConstPtr& joy)
{
  Steer_Command = joy->axes[0];
  Drive_Command = joy->axes[1];

}
void Recharge_FSM(double dtime)
{
  switch (Probe_State)
  {
    case PROBE_MOVING_FORWARD:
      forward_timer += dtime;
      if (Extended_Switch == true)
      {
        Probe_State = PROBE_EXTENDED;
        Probe_Error = NO_ERROR;
      }
      //servoWrite(WINCH_MOTOR_PIN, WINCH_MOTOR_FORWARD);
      break;
    case PROBE_MOVING_REVERSE:
      reverse_timer += dtime;
      if (Retracted_Switch == true)
      {
        Probe_State = PROBE_RETRACTED;
      }
      //servoWrite(WINCH_MOTOR_PIN,WINCH_MOTOR_REVERSE);
      break;
    case PROBE_EXTENDED:
      forward_timer = 0.0;
      reverse_timer = 0.0;
      if (Recharge_Command == RECHARGE_STOP)
      {
        Probe_State = PROBE_MOVING_REVERSE;
      }
      //servoWrite(WINCH_MOTOR_PIN,WINCH_MOTOR_NEUTRAL);
      break;
    case PROBE_RETRACTED:
      forward_timer = 0.0;
      reverse_timer = 0.0;
      if (Recharge_Command == RECHARGE_START)
      {
        Probe_State = PROBE_MOVING_FORWARD;
        Probe_Error = NO_ERROR;
      }
      //servoWrite(WINCH_MOTOR_PIN,WINCH_MOTOR_NEUTRAL);
      break;
    default:
      //servoWrite(WINCH_MOTOR_PIN,WINCH_MOTOR_NEUTRAL);
      break;
  }
  if (forward_timer > FORWARD_TIME_LIMIT){ Probe_Error = EXTENSION_ERROR; }
  if (reverse_timer > REVERSE_TIME_LIMIT){ Probe_State = RETRACTION_ERROR; }
}
int main(int argc, char **argv)
{
  int INITIALIZED = 0;
  ros::init(argc, argv, "Motion_Controller");
  ros::NodeHandle nh;
  //nh.getParam("target_count",target_count);
  nh.getParam("mc_device",MC_Device);
  nh.getParam("baudrate",Baud_Rate);
  int mc_device;
  struct termios oldtio,newtio;
	int res;

  mc_device= open(MC_Device.c_str(),O_RDWR | O_NOCTTY );

  if (mc_device  == -1)
  {
    ROS_INFO("ERROR: UNABLE TO OPEN SERIAL PORT.");
  }
  else
  {
    if(1)
    {
      INITIALIZED = 1;
      tcgetattr(mc_device,&oldtio);
	    bzero(&newtio, sizeof(newtio));
	    newtio.c_cflag = B115200 | CS8 | CLOCAL | CREAD;
      //newtio.c_cflag &= ~(IXON | IXOFF | IXANY);
	    newtio.c_iflag = IGNPAR;
	    newtio.c_oflag = 0;
	    newtio.c_lflag = 0;
	    newtio.c_cc[VTIME]    = 1;
	    newtio.c_cc[VMIN]     = 5;
                  // 0.5 seconds read timeout

	    tcflush(mc_device, TCIFLUSH);
	    tcsetattr(mc_device,TCSANOW,&newtio);
    }
    else
    {
struct termios tty;
struct termios tty_old;
memset (&tty, 0, sizeof tty);

/* Error Handling */
if ( tcgetattr ( mc_device, &tty ) != 0 ) {
   std::cout << "Error " << errno << " from tcgetattr: " << strerror(errno) << std::endl;
}

/* Save old tty parameters */
tty_old = tty;

/* Set Baud Rate */
cfsetospeed (&tty, (speed_t)B9600);
cfsetispeed (&tty, (speed_t)B9600);

/* Setting other Port Stuff */
tty.c_cflag     &=  ~PARENB;            // Make 8n1
tty.c_cflag     &=  ~CSTOPB;
tty.c_cflag     &=  ~CSIZE;
tty.c_cflag     |=  CS8;

tty.c_cflag     &=  ~CRTSCTS;           // no flow control
tty.c_cc[VMIN]   =  1;                  // read doesn't block
tty.c_cc[VTIME]  =  5;                  // 0.5 seconds read timeout
tty.c_cflag     |=  CREAD | CLOCAL;     // turn on READ & ignore ctrl lines

/* Make raw */
cfmakeraw(&tty);

/* Flush Port, then applies attributes */
tcflush( mc_device, TCIFLUSH );
if ( tcsetattr ( mc_device, TCSANOW, &tty ) != 0) {
   std::cout << "Error " << errno << " from tcsetattr" << std::endl;
}}
}

  ros::Subscriber Sub_ICARUS_Probe_Command_Callback = nh.subscribe("ICARUS_Probe_Command", 1000, ICARUS_Probe_Command_Callback);
  ros::Publisher Pub_ICARUS_Probe_Status = nh.advertise<icarus_rover_rc::ICARUS_Probe_Status>("ICARUS_Probe_Status", 1000);
  ros::Subscriber Pub_Rover_Control = nh.subscribe<sensor_msgs::Joy>("ICARUS_Rover_Control",1000,ICARUS_Rover_Control_Callback);
  ros::Rate loop_rate(100);
	std::clock_t    start;
  ::icarus_rover_rc::ICARUS_Probe_Status Probe_Status;

  temp1 = 0;
	while( ros::ok() && INITIALIZED)
	{

	  start = std::clock();
	  ros::spinOnce();
	  loop_rate.sleep();

	  try
	  {
	    int wr;
      temp1++;
      if (temp1 > 180) { temp1 = 0; }

      char cmd[255];
      memset(cmd,'\0',sizeof cmd);
      sprintf(cmd,"$NAV,%d,%d,*\r\n",(int)Steer_Command,(int)Drive_Command);
      printf("%s",cmd);
      wr = write(mc_device,cmd,sizeof(cmd)-1);
      char buf = '\0';
      char response[255];
      int spot = 0;

      memset(response,'\0',sizeof response);
      //res = read(mc_device,&buf,1);
      //printf("x%c",buf);

      do
      {

        res = read(mc_device,&buf,1);
        if (buf == '$')
        {
          in_message_started = 1;
          in_message_completed = 0;
        }
        if(in_message_started == 1)
        {
          sprintf(&response[spot],"%c",buf);
          spot += res;
        }
      } while(buf != '*' && res > 0);
      in_message_started = 0;
      in_message_completed = 1;
      string in_message(response);
      if (in_message.compare(0,4,"$POS") == 0)
      {
        istringstream ss(in_message);
        string token;
        token_index = 0;
        while(getline(ss,token,',')) {
          std::string::size_type sz;
          if(token_index == 1) { Pose_X = atof(token.c_str()); }
          if(token_index == 2) { Pose_Y = atof(token.c_str()); }
          if(token_index == 3) { Heading = atof(token.c_str()); }
          token_index++;
        }
        //cout << setprecision(8) << "X: " << Pose_X << " Y: " << Pose_Y << " Heading: " << Heading << " Len: " << spot << endl;
      }
/*
int n = 0,
    spot = 0;
char buf = '\0';

char response[255];
memset(response, '\0', sizeof response);

do {
   n = read( mc_device, &buf, 1 );
   if (n > 0) { printf("%c",buf); }
   sprintf( &response[spot], "%c", buf );
   spot += n;
} while( buf != '\r' && n > 0);
if (n < 0) {
   //std::cout << "Error reading: " << strerror(errno) << std::endl;
}
else if (n == 0) {
    std::cout << "Read nothing!" << std::endl;
}
else {
    std::cout << "Response: " << response << std::endl;
}*/
	    dtime = (std::clock() - start) / (double)(CLOCKS_PER_SEC /1);
      /*if (digitalRead(EXTENDED_SWITCH_PIN)==0)
      {
        Extended_Switch = true;
      }
      else
      {
        Extended_Switch = false;
      }
      if (digitalRead(RETRACTED_SWITCH_PIN)==0)
      {
        Retracted_Switch = true;
      }
      else
      {
        Retracted_Switch = false;
      }*/

      //Recharge_FSM(dtime);
      Probe_Status.header.stamp = ros::Time::now();
      Probe_Status.header.frame_id = "Probe_Status";
      Probe_Status.Probe_State = Probe_State;
      Probe_Status.Extended_Switch = Extended_Switch;
      Probe_Status.Retracted_Switch = Retracted_Switch;
      Probe_Status.Probe_Error = Probe_Error;

	    Pub_ICARUS_Probe_Status.publish(Probe_Status);
	  }
	  catch(const std::exception& ex)
	  {
	    ROS_INFO("ERROR:%s",ex.what());
      close(mc_device);
	  }
  }
  close(mc_device);

}
<|endoftext|>


<commit_before>/*************************************************************************
> File Name: PlayMinion.cpp
> Project Name: Hearthstonepp
> Author: Young-Joong Kim
> Purpose: Implement PlayMinion, Summon Minion and Process PowerTasks
> Created Time: 2018/07/21
> Copyright (c) 2018, Young-Joong Kim
*************************************************************************/
#include <Tasks/BasicTasks/ModifyMana.h>
#include <Tasks/BasicTasks/PlayMinion.h>
#include <Tasks/PowerTask.h>

#include <algorithm>

namespace Hearthstonepp::BasicTasks
{
PlayMinionTask::PlayMinionTask(TaskAgent& agent, Entity* entity)
    : m_entity(entity), m_requirement(TaskID::SELECT_POSITION, agent)
{
    // Do Nothing
}

TaskID PlayMinionTask::GetTaskID() const
{
    return TaskID::PLAY_MINION;
}

MetaData PlayMinionTask::Impl(Player& player1, Player& player2) const
{
    TaskMeta meta;
    // Get Position Response from GameInterface
    m_requirement.Interact(player1.id, meta);

    using RequireTaskMeta = FlatData::ResponsePlayMinion;
    const auto& buffer = meta.GetConstBuffer();
    auto req = flatbuffers::GetRoot<RequireTaskMeta>(buffer.get());

    if (req == nullptr)
    {
        return MetaData::PLAY_MINION_FLATBUFFER_NULLPTR;
    }

    BYTE position = req->position();

    // Field Position Verification
    if (position > player1.field.size())
    {
        return MetaData::PLAY_MINION_POSITION_OUT_OF_RANGE;
    }

    // Character Casting Verification
    auto character = dynamic_cast<Character*>(m_entity);
    if (character == nullptr)
    {
        return MetaData::PLAY_MINION_CANNOT_CONVERT_ENTITY;
    }

    // Summon
    player1.field.insert(player1.field.begin() + position, character);

    // Summoned minion can't attack right turn
    player1.attacked.emplace_back(character);

    BYTE cost = static_cast<BYTE>(m_entity->card->cost);
    MetaData modified = ModifyManaTask(NumMode::SUB, ManaMode::EXIST, cost)
                            .Run(player1, player2);

    // Process PowerTasks
    if (m_entity->card->power != nullptr)
    {
        for (auto& power : m_entity->card->power->powerTask)
        {
            PowerTask::ProcessPower(player1, player2, power);
        }
    }

    if (modified == MetaData::MODIFY_MANA_SUCCESS)
    {
        return MetaData::PLAY_MINION_SUCCESS;
    }
    else
    {
        return MetaData::PLAY_MINION_MODIFY_MANA_FAIL;
    }
}
}  // namespace Hearthstonepp::BasicTasks<commit_msg>[ci skip] Consider minions that has 'CHARGE' mechanic<commit_after>/*************************************************************************
> File Name: PlayMinion.cpp
> Project Name: Hearthstonepp
> Author: Young-Joong Kim
> Purpose: Implement PlayMinion, Summon Minion and Process PowerTasks
> Created Time: 2018/07/21
> Copyright (c) 2018, Young-Joong Kim
*************************************************************************/
#include <Tasks/BasicTasks/ModifyMana.h>
#include <Tasks/BasicTasks/PlayMinion.h>
#include <Tasks/PowerTask.h>

#include <algorithm>

namespace Hearthstonepp::BasicTasks
{
PlayMinionTask::PlayMinionTask(TaskAgent& agent, Entity* entity)
    : m_entity(entity), m_requirement(TaskID::SELECT_POSITION, agent)
{
    // Do Nothing
}

TaskID PlayMinionTask::GetTaskID() const
{
    return TaskID::PLAY_MINION;
}

MetaData PlayMinionTask::Impl(Player& player1, Player& player2) const
{
    TaskMeta meta;
    // Get Position Response from GameInterface
    m_requirement.Interact(player1.id, meta);

    using RequireTaskMeta = FlatData::ResponsePlayMinion;
    const auto& buffer = meta.GetConstBuffer();
    auto req = flatbuffers::GetRoot<RequireTaskMeta>(buffer.get());

    if (req == nullptr)
    {
        return MetaData::PLAY_MINION_FLATBUFFER_NULLPTR;
    }

    BYTE position = req->position();

    // Field Position Verification
    if (position > player1.field.size())
    {
        return MetaData::PLAY_MINION_POSITION_OUT_OF_RANGE;
    }

    // Character Casting Verification
    auto character = dynamic_cast<Character*>(m_entity);
    if (character == nullptr)
    {
        return MetaData::PLAY_MINION_CANNOT_CONVERT_ENTITY;
    }

    // Summon
    player1.field.insert(player1.field.begin() + position, character);

    // Summoned minion can't attack right turn
    if (std::find(m_entity->card->mechanics.begin(),
                  m_entity->card->mechanics.end(),
        +GameTag::CHARGE) == m_entity->card->mechanics.end())
    {
        player1.attacked.emplace_back(character);
    }

    BYTE cost = static_cast<BYTE>(m_entity->card->cost);
    MetaData modified = ModifyManaTask(NumMode::SUB, ManaMode::EXIST, cost)
                            .Run(player1, player2);

    // Process PowerTasks
    if (m_entity->card->power != nullptr)
    {
        for (auto& power : m_entity->card->power->powerTask)
        {
            PowerTask::ProcessPower(player1, player2, power);
        }
    }

    if (modified == MetaData::MODIFY_MANA_SUCCESS)
    {
        return MetaData::PLAY_MINION_SUCCESS;
    }
    else
    {
        return MetaData::PLAY_MINION_MODIFY_MANA_FAIL;
    }
}
}  // namespace Hearthstonepp::BasicTasks<|endoftext|>