<commit_before>// __BEGIN_LICENSE__
//
// Copyright (C) 2006 United States Government as represented by the
// Administrator of the National Aeronautics and Space Administration
// (NASA).  All Rights Reserved.
//
// This software is distributed under the NASA Open Source Agreement
// (NOSA), version 1.3.  The NOSA has been approved by the Open Source
// Initiative.  See the file COPYING at the top of the distribution
// directory tree for the complete NOSA document.
//
// THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY
// KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT
// LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO
// SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR
// A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT
// THE SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT
// DOCUMENTATION, IF PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE.
//
// __END_LICENSE__

/// \file hdr_merge.cc
///
/// This is a simple example program that stitches a HDR stack into an
/// HDR image, performs tone-mapping, and saves several versions with
/// different post-processing applied for comparison.  Usually the
/// best image is produced by re-applying the camera response curves
/// and then gamma correcting.
///
/// You can specify the exposure spacing in the stack, however if EXIF
/// information is available the exposure ratios will be inferred
/// automatically.

#ifdef _MSC_VER
#pragma warning(disable:4244)
#pragma warning(disable:4267)
#pragma warning(disable:4996)
#endif

#include <boost/program_options.hpp>
namespace po = boost::program_options;

#include <vw/Image.h>
#include <vw/FileIO.h>
#include <vw/HDR.h>

#include <vector>
#include <string>

using namespace std;
using namespace vw;
using namespace vw::hdr;

int main( int argc, char *argv[] ) {
  try {
    std::vector<std::string> input_filenames;
    std::string output_filename, curve_file;
    float exposure_ratio = 0;

    po::options_description desc("Options");
    desc.add_options()
      ("help", "Display this help message")
      ("input-filenames", po::value<std::vector<std::string> >(&input_filenames), "Specify the input files")
      ("output-filename,o", po::value<std::string>(&output_filename)->default_value("hdr.exr"), "Specify the output filename")
      ("exposure-ratio,e", po::value<float>(&exposure_ratio), "Manually specified exposure ratio for the images (in units of f-stops).")
      ("save-curves,c", po::value<std::string>(&curve_file), "Write the curve lookup tables to a file on disk.")
      ("use-curves", po::value<std::string>(&curve_file), "Read the curve lookup tables to a file on disk.  These curves will be used instead of computing new curves.");

    po::positional_options_description p;
    p.add("input-filenames", -1);

    po::variables_map vm;
    po::store( po::command_line_parser( argc, argv ).options(desc).positional(p).run(), vm );
    po::notify( vm );

    if( vm.count("help") ) {
      std::cout << desc << std::endl;
      return 1;
    }

    if( vm.count("input-filenames") != 1 ) {
      std::cout << "Usage: " << argv[0] << " <input-filenames> [args]\n";
      std::cout << desc << std::endl;
      return 1;
    }

    // Process HDR stack using Exif tags.
    ImageView<PixelRGB<float> > hdr;

    // In the absense of EXIF data or if the user has provided an
    // explicit exposure ratio, we go with that value here.
       std::vector<double> brightness_values;
    if( vm.count("exposure-ratio") != 0 )
      brightness_values = brightness_values_from_exposure_ratio(exposure_ratio, input_filenames.size());
    else
      brightness_values = brightness_values_from_exif(input_filenames);

    // For debugging: (print out the brightness values
    //     for (int i = 0; i < brightness_values.size(); ++i)
    //       vw_out(0) << "BV: " << brightness_values[i] << "\n";

    vector<ImageViewRef<PixelRGB<float> > > images(input_filenames.size());
    for ( unsigned i=0; i < input_filenames.size(); ++i )
      images[i] = DiskImageView<PixelRGB<float> >(input_filenames[i]);

    // Compute the camera curves
    CameraCurveFn curves;
    if ( vm.count("use-curves") != 0 )
      curves = read_curves(curve_file);
    else {
      curves = camera_curves(images, brightness_values);

      // Write out the curves to disk as a tabulated file
      if ( vm.count("save-curves") != 0 ) {
        write_curves(curve_file, curves);
      }
    }

    // Create the HDR images and write the results to the file
    write_image(output_filename, HighDynamicRangeView<PixelRGB<float> > (images, curves, brightness_values) );

  } catch (vw::Exception &e) {
    std::cout << argv[0] << ": a Vision Workbench error occurred: \n\t" << e.what() << "\nExiting.\n\n";
    return 1;
  }
  return 0;
}
<commit_msg>Fixed some command line arguments to make them more clear...<commit_after>// __BEGIN_LICENSE__
//
// Copyright (C) 2006 United States Government as represented by the
// Administrator of the National Aeronautics and Space Administration
// (NASA).  All Rights Reserved.
//
// This software is distributed under the NASA Open Source Agreement
// (NOSA), version 1.3.  The NOSA has been approved by the Open Source
// Initiative.  See the file COPYING at the top of the distribution
// directory tree for the complete NOSA document.
//
// THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY
// KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT
// LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO
// SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR
// A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT
// THE SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT
// DOCUMENTATION, IF PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE.
//
// __END_LICENSE__

/// \file hdr_merge.cc
///
/// This is a simple example program that stitches a HDR stack into an
/// HDR image, performs tone-mapping, and saves several versions with
/// different post-processing applied for comparison.  Usually the
/// best image is produced by re-applying the camera response curves
/// and then gamma correcting.
///
/// You can specify the exposure spacing in the stack, however if EXIF
/// information is available the exposure ratios will be inferred
/// automatically.

#ifdef _MSC_VER
#pragma warning(disable:4244)
#pragma warning(disable:4267)
#pragma warning(disable:4996)
#endif

#include <boost/program_options.hpp>
namespace po = boost::program_options;

#include <vw/Image.h>
#include <vw/FileIO.h>
#include <vw/HDR.h>

#include <vector>
#include <string>

using namespace std;
using namespace vw;
using namespace vw::hdr;

int main( int argc, char *argv[] ) {
  try {
    std::vector<std::string> input_filenames;
    std::string output_filename, curve_file;
    float exposure_ratio = 0;

    po::options_description desc("Options");
    desc.add_options()
      ("help", "Display this help message")
      ("input-filenames,i", po::value<std::vector<std::string> >(&input_filenames), "Specify the input files")
      ("output-filename,o", po::value<std::string>(&output_filename)->default_value("merged_hdr_image.exr"), "Specify the output filename")
      ("exposure-ratio,e", po::value<float>(&exposure_ratio), "Manually specified exposure ratio for the images (e.g. for increasing power of 2 expoures, you would use a exposure-ratio of 2.0).")
      ("save-curves,c", po::value<std::string>(&curve_file), "Write the curve lookup tables to a file on disk.")
      ("use-curves,u", po::value<std::string>(&curve_file), "Read the curve lookup tables to a file on disk.  These curves will be used instead of computing new curves.");

    po::positional_options_description p;
    p.add("input-filenames", -1);

    po::variables_map vm;
    po::store( po::command_line_parser( argc, argv ).options(desc).positional(p).run(), vm );
    po::notify( vm );

    if( vm.count("help") ) {
      std::cout << desc << std::endl;
      return 1;
    }

    if( vm.count("input-filenames") != 1 ) {
      std::cout << "Usage: " << argv[0] << " <input-filenames> [args]\n";
      std::cout << desc << std::endl;
      return 1;
    }

    // Process HDR stack using Exif tags.
    ImageView<PixelRGB<float> > hdr;

    // In the absense of EXIF data or if the user has provided an
    // explicit exposure ratio, we go with that value here.
       std::vector<double> brightness_values;
    if( vm.count("exposure-ratio") != 0 )
      brightness_values = brightness_values_from_exposure_ratio(exposure_ratio, input_filenames.size());
    else
      brightness_values = brightness_values_from_exif(input_filenames);

    // For debugging: (print out the brightness values
    //     for (int i = 0; i < brightness_values.size(); ++i)
    //       vw_out(0) << "BV: " << brightness_values[i] << "\n";

    vector<ImageViewRef<PixelRGB<float> > > images(input_filenames.size());
    for ( unsigned i=0; i < input_filenames.size(); ++i )
      images[i] = DiskImageView<PixelRGB<float> >(input_filenames[i]);

    // Compute the camera curves
    CameraCurveFn curves;
    if ( vm.count("use-curves") != 0 )
      curves = read_curves(curve_file);
    else {
      curves = camera_curves(images, brightness_values);

      // Write out the curves to disk as a tabulated file
      if ( vm.count("save-curves") != 0 ) {
        write_curves(curve_file, curves);
      }
    }

    // Create the HDR images and write the results to the file
    write_image(output_filename, HighDynamicRangeView<PixelRGB<float> > (images, curves, brightness_values) );

  } catch (vw::Exception &e) {
    std::cout << argv[0] << ": a Vision Workbench error occurred: \n\t" << e.what() << "\nExiting.\n\n";
    return 1;
  }
  return 0;
}
<|endoftext|>


<commit_before>// Copyright (c) 2018 The Gulden developers
// Authored by: Willem de Jonge (willem@isnapp.nl)
// Distributed under the GULDEN software license, see the accompanying
// file COPYING

#include "spvscanner.h"
#include "../net_processing.h"
#include "../validation/validation.h"
#include "wallet.h"

#include <algorithm>

// Maximum number of requests pending. This number should be high enough so that
// the requests can be reasonably distributed over our peers.
const static int nMaxPendingRequests = 512;

// Seconds before oldest key to start scanning blocks.
const static int64_t startTimeGap = 3 * 3600;

CSPVScanner::CSPVScanner(CWallet& _wallet) :
    wallet(_wallet),
    startTime(0)
{
    LOCK(cs_main);

    CWalletDB walletdb(*wallet.dbw);
    CBlockLocator locator;
    if (!walletdb.ReadLastSPVBlockProcessed(locator))
    {
        // fixme: (SPV) start locator at approriate checkpoint
        locator = chainActive.GetLocatorPoW2(chainActive.Genesis());
    }

    lastProcessed = FindForkInGlobalIndex(headerChain, locator);
    requestTip = lastProcessed;
    startHeight = lastProcessed->nHeight;

    int64_t seedTime = wallet.nTimeFirstKey;

    startTime =  std::max(int64_t(0), seedTime - startTimeGap);

    LogPrint(BCLog::WALLET, "Using %s (height = %d) as last processed SPV block\n",
             lastProcessed->GetBlockHashPoW2().ToString(), lastProcessed->nHeight);

    RegisterValidationInterface(this);
}

CSPVScanner::~CSPVScanner()
{
    UnregisterValidationInterface(this);
}

void CSPVScanner::StartScan()
{
    RequestBlocks();
}

void CSPVScanner::RequestBlocks()
{
    LOCK2(cs_main, wallet.cs_wallet);

    // put lastProcessed and/or requestTip back on chain if forked
    while (!headerChain.Contains(requestTip)) {
        if (requestTip->nHeight > lastProcessed->nHeight) {
            CancelPriorityDownload(requestTip, std::bind(&CSPVScanner::ProcessPriorityRequest, this, std::placeholders::_1, std::placeholders::_2));
            requestTip = requestTip->pprev;
        }
        else { // so here requestTip == lastProcessed
            std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();
            if (!ReadBlockFromDisk(*pblock, lastProcessed, Params())) {
                wallet.BlockDisconnected(pblock);
            }
            else {
                // This block must be on disk, it was processed before.
                // So pruning has to keep at least as many blocks back as the longest fork we are willing to handle.
                assert(false);
            }
            UpdateLastProcessed(lastProcessed->pprev);
            requestTip = lastProcessed;
        }
    }

    // skip blocks that are before startTime
    const CBlockIndex* skip = lastProcessed;
    while (skip->GetBlockTime() < startTime && headerChain.Height() > skip->nHeight)
        skip = headerChain.Next(skip);
    if (skip != lastProcessed) {
        LogPrint(BCLog::WALLET, "Skipping %d old blocks for SPV scan, up to height %d\n", skip->nHeight - lastProcessed->nHeight, skip->nHeight);
        UpdateLastProcessed(skip);
        if (lastProcessed->nHeight > requestTip->nHeight) {
            requestTip = lastProcessed;
            startHeight = lastProcessed->nHeight;
        }
    }

    std::vector<const CBlockIndex*> blocksToRequest;

    // add requests for as long as nMaxPendingRequests is not reached and there are still heigher blocks in headerChain
    while (requestTip->nHeight - lastProcessed->nHeight < nMaxPendingRequests &&
           headerChain.Height() > requestTip->nHeight) {

        requestTip = headerChain.Next(requestTip);
        blocksToRequest.push_back(requestTip);
    }

    if (!blocksToRequest.empty()) {
        LogPrint(BCLog::WALLET, "Requesting %d blocks for SPV, up to height %d\n", blocksToRequest.size(), requestTip->nHeight);
        AddPriorityDownload(blocksToRequest, std::bind(&CSPVScanner::ProcessPriorityRequest, this, std::placeholders::_1, std::placeholders::_2));
    }
}

void CSPVScanner::ProcessPriorityRequest(const std::shared_ptr<const CBlock> &block, const CBlockIndex *pindex)
{
    LOCK2(cs_main, wallet.cs_wallet);

    // if chainActive is up-to-date no SPV blocks need to be requested, we can update SPV to the activeChain
    if (chainActive.Tip() == headerChain.Tip()) {
        LogPrint(BCLog::WALLET, "chainActive is up-to-date, skipping SPV processing block %d\n", pindex->nHeight);
        if (lastProcessed != headerChain.Tip()) {
            UpdateLastProcessed(chainActive.Tip());
            requestTip = lastProcessed;
        }
    }

    // if this is the block we're waiting for process it and request new block(s)
    if (pindex->pprev == lastProcessed) {
        LogPrint(BCLog::WALLET, "SPV processing block %d\n", pindex->nHeight);

        // TODO handle mempool effects

        std::vector<CTransactionRef> vtxConflicted; // dummy for now
        wallet.BlockConnected(block, pindex, vtxConflicted);

        UpdateLastProcessed(pindex);

        RequestBlocks();

        uiInterface.NotifySPVProgress(startHeight, pindex->nHeight, headerChain.Height());
    }
}

void CSPVScanner::HeaderTipChanged(const CBlockIndex* pTip)
{
    RequestBlocks();
}

void CSPVScanner::UpdateLastProcessed(const CBlockIndex* pindex)
{
    lastProcessed = pindex;
    CWalletDB walletdb(*wallet.dbw);
    walletdb.WriteLastSPVBlockProcessed(headerChain.GetLocatorPoW2(lastProcessed));
}
<commit_msg>Minor refactoring to make use of const vars more clear<commit_after>// Copyright (c) 2018 The Gulden developers
// Authored by: Willem de Jonge (willem@isnapp.nl)
// Distributed under the GULDEN software license, see the accompanying
// file COPYING

#include "spvscanner.h"
#include "../net_processing.h"
#include "../validation/validation.h"
#include "wallet.h"

#include <algorithm>

// Maximum number of requests pending. This number should be high enough so that
// the requests can be reasonably distributed over our peers.
const int MAX_PENDING_REQUESTS = 512;

// Seconds before oldest key to start scanning blocks.
const int64_t START_TIME_GAP = 3 * 3600;

CSPVScanner::CSPVScanner(CWallet& _wallet) :
    wallet(_wallet),
    startTime(0)
{
    LOCK(cs_main);

    CWalletDB walletdb(*wallet.dbw);
    CBlockLocator locator;
    if (!walletdb.ReadLastSPVBlockProcessed(locator))
    {
        // fixme: (SPV) start locator at approriate checkpoint
        locator = chainActive.GetLocatorPoW2(chainActive.Genesis());
    }

    lastProcessed = FindForkInGlobalIndex(headerChain, locator);
    requestTip = lastProcessed;
    startHeight = lastProcessed->nHeight;

    int64_t seedTime = wallet.nTimeFirstKey;

    startTime =  std::max(int64_t(0), seedTime - START_TIME_GAP);

    LogPrint(BCLog::WALLET, "Using %s (height = %d) as last processed SPV block\n",
             lastProcessed->GetBlockHashPoW2().ToString(), lastProcessed->nHeight);

    RegisterValidationInterface(this);
}

CSPVScanner::~CSPVScanner()
{
    UnregisterValidationInterface(this);
}

void CSPVScanner::StartScan()
{
    RequestBlocks();
}

void CSPVScanner::RequestBlocks()
{
    LOCK2(cs_main, wallet.cs_wallet);

    // put lastProcessed and/or requestTip back on chain if forked
    while (!headerChain.Contains(requestTip)) {
        if (requestTip->nHeight > lastProcessed->nHeight) {
            CancelPriorityDownload(requestTip, std::bind(&CSPVScanner::ProcessPriorityRequest, this, std::placeholders::_1, std::placeholders::_2));
            requestTip = requestTip->pprev;
        }
        else { // so here requestTip == lastProcessed
            std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();
            if (!ReadBlockFromDisk(*pblock, lastProcessed, Params())) {
                wallet.BlockDisconnected(pblock);
            }
            else {
                // This block must be on disk, it was processed before.
                // So pruning has to keep at least as many blocks back as the longest fork we are willing to handle.
                assert(false);
            }
            UpdateLastProcessed(lastProcessed->pprev);
            requestTip = lastProcessed;
        }
    }

    // skip blocks that are before startTime
    const CBlockIndex* skip = lastProcessed;
    while (skip->GetBlockTime() < startTime && headerChain.Height() > skip->nHeight)
        skip = headerChain.Next(skip);
    if (skip != lastProcessed) {
        LogPrint(BCLog::WALLET, "Skipping %d old blocks for SPV scan, up to height %d\n", skip->nHeight - lastProcessed->nHeight, skip->nHeight);
        UpdateLastProcessed(skip);
        if (lastProcessed->nHeight > requestTip->nHeight) {
            requestTip = lastProcessed;
            startHeight = lastProcessed->nHeight;
        }
    }

    std::vector<const CBlockIndex*> blocksToRequest;

    // add requests for as long as nMaxPendingRequests is not reached and there are still heigher blocks in headerChain
    while (requestTip->nHeight - lastProcessed->nHeight < MAX_PENDING_REQUESTS &&
           headerChain.Height() > requestTip->nHeight) {

        requestTip = headerChain.Next(requestTip);
        blocksToRequest.push_back(requestTip);
    }

    if (!blocksToRequest.empty()) {
        LogPrint(BCLog::WALLET, "Requesting %d blocks for SPV, up to height %d\n", blocksToRequest.size(), requestTip->nHeight);
        AddPriorityDownload(blocksToRequest, std::bind(&CSPVScanner::ProcessPriorityRequest, this, std::placeholders::_1, std::placeholders::_2));
    }
}

void CSPVScanner::ProcessPriorityRequest(const std::shared_ptr<const CBlock> &block, const CBlockIndex *pindex)
{
    LOCK2(cs_main, wallet.cs_wallet);

    // if chainActive is up-to-date no SPV blocks need to be requested, we can update SPV to the activeChain
    if (chainActive.Tip() == headerChain.Tip()) {
        LogPrint(BCLog::WALLET, "chainActive is up-to-date, skipping SPV processing block %d\n", pindex->nHeight);
        if (lastProcessed != headerChain.Tip()) {
            UpdateLastProcessed(chainActive.Tip());
            requestTip = lastProcessed;
        }
    }

    // if this is the block we're waiting for process it and request new block(s)
    if (pindex->pprev == lastProcessed) {
        LogPrint(BCLog::WALLET, "SPV processing block %d\n", pindex->nHeight);

        // TODO handle mempool effects

        std::vector<CTransactionRef> vtxConflicted; // dummy for now
        wallet.BlockConnected(block, pindex, vtxConflicted);

        UpdateLastProcessed(pindex);

        RequestBlocks();

        uiInterface.NotifySPVProgress(startHeight, pindex->nHeight, headerChain.Height());
    }
}

void CSPVScanner::HeaderTipChanged(const CBlockIndex* pTip)
{
    RequestBlocks();
}

void CSPVScanner::UpdateLastProcessed(const CBlockIndex* pindex)
{
    lastProcessed = pindex;
    CWalletDB walletdb(*wallet.dbw);
    walletdb.WriteLastSPVBlockProcessed(headerChain.GetLocatorPoW2(lastProcessed));
}
<|endoftext|>


<commit_before>#include <sstream>
#include <assert.h>
#include <map>
#include <iostream>
#include "halGenome.h"
#include "halAlignment.h"
#include "halBottomSegmentIterator.h"
#include "halDNAIterator.h"
#include "halMetaData.h"
#include "halSegmentIterator.h"
#include "halSequenceIterator.h"
#include "halTopSegmentIterator.h"
using namespace std;

namespace hal {
void Genome::copy(Genome *dest) const
{
  copyDimensions(dest);
  copySequence(dest);
  copyTopSegments(dest);
  copyBottomSegments(dest);
  copyMetadata(dest);
}

void Genome::copyDimensions(Genome *dest) const
{
  vector<Sequence::Info> dimensions;
  const Alignment *inAlignment = getAlignment();
  SequenceIteratorConstPtr seqIt = getSequenceIterator();
  SequenceIteratorConstPtr seqEndIt = getSequenceEndIterator();

  bool root = inAlignment->getParentName(getName()).empty();
  bool leaf = inAlignment->getChildNames(getName()).empty();

  for (; seqIt != seqEndIt; seqIt->toNext())
  {
    const Sequence* sequence = seqIt->getSequence();
    Sequence::Info info(sequence->getName(),
                        sequence->getSequenceLength(),
                        root ? 0 : sequence->getNumTopSegments(),
                        leaf ? 0 : sequence->getNumBottomSegments());
    dimensions.push_back(info);
  }
  dest->setDimensions(dimensions);
}

void Genome::copyTopDimensions(Genome *dest) const
{
  vector<Sequence::UpdateInfo> dimensions;
  SequenceIteratorConstPtr seqIt = getSequenceIterator();
  SequenceIteratorConstPtr seqEndIt = getSequenceEndIterator();
  for (; seqIt != seqEndIt; seqIt->toNext())
  {
    const Sequence* sequence = seqIt->getSequence();
    if (sequence->getSequenceLength() == 0 &&
        dest->getSequence(sequence->getName()) == NULL) {
      // progressiveCactus creates 0-length sequences in ancestors,
      // which are not usually extractable and aren't important
      continue;
    }
    Sequence::UpdateInfo info(sequence->getName(),
                              sequence->getNumTopSegments());
    dimensions.push_back(info);
  }
  dest->updateTopDimensions(dimensions);
}

void Genome::copyBottomDimensions(Genome *dest) const
{
  vector<Sequence::UpdateInfo> dimensions;
  SequenceIteratorConstPtr seqIt = getSequenceIterator();
  SequenceIteratorConstPtr seqEndIt = getSequenceEndIterator();

  for (; seqIt != seqEndIt; seqIt->toNext())
  {
    const Sequence* sequence = seqIt->getSequence();
    if (sequence->getSequenceLength() == 0 &&
        dest->getSequence(sequence->getName()) == NULL) {
      // progressiveCactus creates 0-length sequences in ancestors,
      // which are not usually extractable and aren't important
      continue;
    }
    Sequence::UpdateInfo info(sequence->getName(),
                              sequence->getNumBottomSegments());
    dimensions.push_back(info);
  }
  dest->updateBottomDimensions(dimensions);
}

void Genome::copyTopSegments(Genome *dest) const
{
  const Genome *inParent = getParent();
  const Genome *outParent = dest->getParent();

  TopSegmentIteratorConstPtr inTop = getTopSegmentIterator();
  TopSegmentIteratorPtr outTop = dest->getTopSegmentIterator();
  hal_size_t n = dest->getNumTopSegments();
  assert(n == 0 || n == getNumTopSegments());

  if (n == 0) {
    // Nothing to do if there are no top segments.
    return;
  }

  BottomSegmentIteratorConstPtr inParentBottomSegIt = inParent->getBottomSegmentIterator();
  BottomSegmentIteratorConstPtr outParentBottomSegIt = outParent->getBottomSegmentIterator();

  for (; (hal_size_t)inTop->getArrayIndex() < n; inTop->toRight(),
         outTop->toRight())
  {
    hal_index_t genomePos = inTop->getStartPosition();
    assert(genomePos != NULL_INDEX);
    string inSeqName = getSequenceBySite(genomePos)->getName();
    string outSeqName = dest->getSequenceBySite(genomePos)->getName();
    // if (inSeqName != outSeqName) {
    //   stringstream ss;
    //   ss << "When copying top segments from " << getName() << " to " << dest->getName() << ": sequence " << inSeqName << " != " << outSeqName << " at site " << genomePos;
    //   throw hal_exception(ss.str());
    // }

    outTop->setCoordinates(inTop->getStartPosition(), inTop->getLength());
    outTop->setParentIndex(inTop->getParentIndex());
    outTop->setParentReversed(inTop->getParentReversed());
    outTop->setBottomParseIndex(inTop->getBottomParseIndex());
    outTop->setNextParalogyIndex(inTop->getNextParalogyIndex());

    // Check that the sequences from the bottom segments we point to are the same. If not, correct the indices so that they are.
    if (inTop->getParentIndex() != NULL_INDEX) {
      inParentBottomSegIt->toParent(inTop);

      const Sequence *inParentSequence = inParentBottomSegIt->getSequence();

      const Sequence *outParentSequence = outParent->getSequence(inParentSequence->getName());

      hal_index_t inParentSegmentOffset = inTop->getParentIndex() - inParentSequence->getBottomSegmentArrayIndex();
      hal_index_t outParentSegmentIndex = inParentSegmentOffset + outParentSequence->getBottomSegmentArrayIndex();

      outTop->setParentIndex(outParentSegmentIndex);
    }
  }
}

void Genome::copyBottomSegments(Genome *dest) const
{
  assert(getNumBottomSegments() == dest->getNumBottomSegments());
  hal_size_t inNc = getNumChildren();
  hal_size_t outNc = dest->getNumChildren();
  // The child indices aren't consistent across files--make sure each bottom
  // segment points to the correct children
  vector<string> inChildNames;
  vector<string> outChildNames;
  for (hal_size_t inChild = 0; inChild < inNc; ++inChild)
  {
    inChildNames.push_back(getChild(inChild)->getName());
  }
  for (hal_size_t outChild = 0; outChild < outNc; ++outChild)
  {
    outChildNames.push_back(dest->getChild(outChild)->getName());
  }
  map<hal_size_t, hal_size_t> inChildToOutChild;
  for (hal_size_t inChild = 0; inChild < inNc; inChild++)
  {
    hal_size_t outChild;
    for (outChild = 0; outChild < outNc; outChild++)
    {
      if (inChildNames[inChild] == outChildNames[outChild])
      {
        inChildToOutChild[inChild] = outChild;
        break;
      }
    }
    if (outChild == outNc)
    {
      inChildToOutChild[inChild] = outNc;
    }
  }

  // Go through each sequence in this genome, find the matching
  // sequence in the dest genome, then copy over the segments for each
  // sequence.
  SequenceIteratorConstPtr seqIt = getSequenceIterator();
  SequenceIteratorConstPtr seqEndIt = getSequenceEndIterator();

  for (; seqIt != seqEndIt; seqIt->toNext())
  {
    const Sequence *inSeq = seqIt->getSequence();
    const Sequence *outSeq = dest->getSequence(inSeq->getName());
    BottomSegmentIteratorPtr inBot = inSeq->getBottomSegmentIterator();
    BottomSegmentIteratorPtr outBot = outSeq->getBottomSegmentIterator();

    cout << "DEBUG: inSeq name: " << inSeq->getName() << ", outSeq name: " << outSeq->getName() << endl;

    if (inSeq->getName() != outSeq->getName()) {
      // This check is important enough that it can't be an assert.
      stringstream ss;
      ss << "When copying bottom segments: segment #" << inBot->getArrayIndex() << " of source genome is from sequence " << inBot->getSequence()->getName() << ", but segment #" << outBot->getArrayIndex() << " is from sequence " << outBot->getSequence()->getName();
      throw hal_exception(ss.str());
    }

    if (inSeq->getNumBottomSegments() != outSeq->getNumBottomSegments()) {
      stringstream ss;
      ss << "When copying bottom segments: sequence " << inSeq->getName() << " has " << inSeq->getNumBottomSegments() << " in genome " << getName() << ", while it has " << outSeq->getNumBottomSegments() << " in genome " << dest->getName();
      throw hal_exception(ss.str());
    }

    hal_index_t inSegmentEnd = inSeq->getBottomSegmentArrayIndex() + inSeq->getNumBottomSegments();
    cout << "DEBUG: inSegmentStart: " << inSeq->getBottomSegmentArrayIndex() << " inSegmentEnd: " << inSegmentEnd << " num bottom segments: " << inSeq->getNumBottomSegments() << endl;
    for (; inBot->getArrayIndex() < inSegmentEnd; inBot->toRight(),
           outBot->toRight())
    {
      hal_index_t outStartPosition = inBot->getStartPosition() - inSeq->getStartPosition() + outSeq->getStartPosition();

      cout << "Decided on outStartPosition " << outStartPosition << " for seg index " << outBot->getArrayIndex() << " (src index " << inBot->getArrayIndex() << ")" << endl;

      if (dest->getSequenceBySite(outStartPosition) != outSeq) {
        stringstream ss;
        ss << "When copying bottom segments from " << getName() << " to " << dest->getName() << ": expected destination sequence " << outSeq->getName() << " for segment # " << inBot->getArrayIndex() << " but got " << dest->getSequenceBySite(outStartPosition)->getName();
        throw hal_exception(ss.str());
      }
      outBot->setCoordinates(outStartPosition, inBot->getLength());
      for(hal_size_t inChild = 0; inChild < inNc; inChild++) {
        hal_size_t outChild = inChildToOutChild[inChild];
        if (outChild != outNc) {
          outBot->setChildIndex(outChild, inBot->getChildIndex(inChild));
          cout << "genome " << getName() << ": Set child index " << inChild << " to " << inBot->getChildIndex(inChild) << endl;
          outBot->setChildReversed(outChild, inBot->getChildReversed(inChild));
        }
      }
      outBot->setTopParseIndex(inBot->getTopParseIndex());
    }
  }
}

void Genome::copySequence(Genome *dest) const
{
  DNAIteratorConstPtr inDna = getDNAIterator();
  DNAIteratorPtr outDna = dest->getDNAIterator();
  hal_size_t n = getSequenceLength();
  assert(n == dest->getSequenceLength());
  for (; (hal_size_t)inDna->getArrayIndex() < n; inDna->toRight(),
         outDna->toRight())
  {
    outDna->setChar(inDna->getChar());
  }
}

void Genome::copyMetadata(Genome *dest) const
{
  const map<string, string>& meta = getMetaData()->getMap();
  map<string, string>::const_iterator i = meta.begin();
  for (; i != meta.end(); ++i)
  {
    dest->getMetaData()->set(i->first, i->second);
  }
}

void Genome::fixParseInfo()
{
  if (getParent() == NULL || getNumChildren() == 0)
  {
    return;
  }

  // copied from CactusHalConverter::updateRootParseInfo() in
  // cactus2hal/src/cactusHalConverter.cpp
  BottomSegmentIteratorPtr bottomIterator =
    getBottomSegmentIterator();
  TopSegmentIteratorPtr topIterator = getTopSegmentIterator();
  BottomSegmentIteratorConstPtr bend = getBottomSegmentEndIterator();
  TopSegmentIteratorConstPtr tend = getTopSegmentEndIterator();
  int top = 0, bot = 0;
  while (bottomIterator != bend && topIterator != tend)
  {
    bool bright = false;
    bool tright = false;
    BottomSegment* bseg = bottomIterator->getBottomSegment();
    TopSegment* tseg = topIterator->getTopSegment();
    hal_index_t bstart = bseg->getStartPosition();
    hal_index_t bendidx = bstart + (hal_index_t)bseg->getLength();
    hal_index_t tstart = tseg->getStartPosition();
    hal_index_t tendidx = tstart + (hal_index_t)tseg->getLength();

    if (bstart >= tstart && bstart < tendidx)
    {
      bseg->setTopParseIndex(tseg->getArrayIndex());
    }
    if (bendidx <= tendidx || bstart == bendidx)
    {
      bright = true;
    }

    if (tstart >= bstart && tstart < bendidx)
    {
      tseg->setBottomParseIndex(bseg->getArrayIndex());
    }
    if (tendidx <= bendidx || tstart == tendidx)
    {
      tright = true;
    }

    assert(bright || tright);
    if (bright == true)
    {
      bot += 1;
      bottomIterator->toRight();
    }
    if (tright == true)
    {
      top += 1;
      topIterator->toRight();
    }
  }
}
} // namespace hal
<commit_msg>Adjust copyTopSegments/copyBottomSegments to work when seq order changed<commit_after>#include <sstream>
#include <assert.h>
#include <map>
#include <iostream>
#include "halGenome.h"
#include "halAlignment.h"
#include "halBottomSegmentIterator.h"
#include "halDNAIterator.h"
#include "halMetaData.h"
#include "halSegmentIterator.h"
#include "halSequenceIterator.h"
#include "halTopSegmentIterator.h"
using namespace std;

namespace hal {
void Genome::copy(Genome *dest) const
{
  copyDimensions(dest);
  copySequence(dest);
  copyTopSegments(dest);
  copyBottomSegments(dest);
  copyMetadata(dest);
}

void Genome::copyDimensions(Genome *dest) const
{
  vector<Sequence::Info> dimensions;
  const Alignment *inAlignment = getAlignment();
  SequenceIteratorConstPtr seqIt = getSequenceIterator();
  SequenceIteratorConstPtr seqEndIt = getSequenceEndIterator();

  bool root = inAlignment->getParentName(getName()).empty();
  bool leaf = inAlignment->getChildNames(getName()).empty();

  for (; seqIt != seqEndIt; seqIt->toNext())
  {
    const Sequence* sequence = seqIt->getSequence();
    Sequence::Info info(sequence->getName(),
                        sequence->getSequenceLength(),
                        root ? 0 : sequence->getNumTopSegments(),
                        leaf ? 0 : sequence->getNumBottomSegments());
    dimensions.push_back(info);
  }
  dest->setDimensions(dimensions);
}

void Genome::copyTopDimensions(Genome *dest) const
{
  vector<Sequence::UpdateInfo> dimensions;
  SequenceIteratorConstPtr seqIt = getSequenceIterator();
  SequenceIteratorConstPtr seqEndIt = getSequenceEndIterator();
  for (; seqIt != seqEndIt; seqIt->toNext())
  {
    const Sequence* sequence = seqIt->getSequence();
    if (sequence->getSequenceLength() == 0 &&
        dest->getSequence(sequence->getName()) == NULL) {
      // progressiveCactus creates 0-length sequences in ancestors,
      // which are not usually extractable and aren't important
      continue;
    }
    Sequence::UpdateInfo info(sequence->getName(),
                              sequence->getNumTopSegments());
    dimensions.push_back(info);
  }
  dest->updateTopDimensions(dimensions);
}

void Genome::copyBottomDimensions(Genome *dest) const
{
  vector<Sequence::UpdateInfo> dimensions;
  SequenceIteratorConstPtr seqIt = getSequenceIterator();
  SequenceIteratorConstPtr seqEndIt = getSequenceEndIterator();

  for (; seqIt != seqEndIt; seqIt->toNext())
  {
    const Sequence* sequence = seqIt->getSequence();
    if (sequence->getSequenceLength() == 0 &&
        dest->getSequence(sequence->getName()) == NULL) {
      // progressiveCactus creates 0-length sequences in ancestors,
      // which are not usually extractable and aren't important
      continue;
    }
    Sequence::UpdateInfo info(sequence->getName(),
                              sequence->getNumBottomSegments());
    dimensions.push_back(info);
  }
  dest->updateBottomDimensions(dimensions);
}

void Genome::copyTopSegments(Genome *dest) const
{
  const Genome *inParent = getParent();
  const Genome *outParent = dest->getParent();

  TopSegmentIteratorConstPtr inTop = getTopSegmentIterator();
  TopSegmentIteratorPtr outTop = dest->getTopSegmentIterator();
  hal_size_t n = dest->getNumTopSegments();
  assert(n == 0 || n == getNumTopSegments());

  if (n == 0) {
    // Nothing to do if there are no top segments.
    return;
  }

  BottomSegmentIteratorConstPtr inParentBottomSegIt = inParent->getBottomSegmentIterator();
  BottomSegmentIteratorConstPtr outParentBottomSegIt = outParent->getBottomSegmentIterator();

  // Go through each sequence in this genome, find the matching
  // sequence in the dest genome, then copy over the segments for each
  // sequence.
  SequenceIteratorConstPtr seqIt = getSequenceIterator();
  SequenceIteratorConstPtr seqEndIt = getSequenceEndIterator();

  for (; seqIt != seqEndIt; seqIt->toNext())
  {
    const Sequence *inSeq = seqIt->getSequence();
    const Sequence *outSeq = dest->getSequence(inSeq->getName());
    TopSegmentIteratorPtr inTop = inSeq->getTopSegmentIterator();
    TopSegmentIteratorPtr outTop = outSeq->getTopSegmentIterator();

    if (inSeq->getName() != outSeq->getName()) {
      stringstream ss;
      ss << "When copying top segments: segment #" << inTop->getArrayIndex() << " of source genome is from sequence " << inTop->getSequence()->getName() << ", but segment #" << outTop->getArrayIndex() << " is from sequence " << outTop->getSequence()->getName();
      throw hal_exception(ss.str());
    }

    if (inSeq->getNumTopSegments() != outSeq->getNumTopSegments()) {
      stringstream ss;
      ss << "When copying top segments: sequence " << inSeq->getName() << " has " << inSeq->getNumTopSegments() << " in genome " << getName() << ", while it has " << outSeq->getNumTopSegments() << " in genome " << dest->getName();
      throw hal_exception(ss.str());
    }

    hal_index_t inSegmentEnd = inSeq->getTopSegmentArrayIndex() + inSeq->getNumTopSegments();
    for (; (hal_size_t)inTop->getArrayIndex() < inSegmentEnd; inTop->toRight(),
             outTop->toRight())
    {
        hal_index_t outStartPosition = inTop->getStartPosition() - inSeq->getStartPosition() + outSeq->getStartPosition();
        outTop->setCoordinates(outStartPosition, inTop->getLength());
        outTop->setParentIndex(inTop->getParentIndex());
        outTop->setParentReversed(inTop->getParentReversed());
        outTop->setBottomParseIndex(inTop->getBottomParseIndex());
        // Figure out next paralogy index in new sequence order.
        hal_index_t inParalogyIndex = inTop->getNextParalogyIndex();
        hal_index_t outParalogyIndex;
        if (inParalogyIndex != NULL_INDEX) {
            TopSegmentIteratorPtr inParalogyIt = getTopSegmentIterator(inParalogyIndex);
            Sequence *inParalogySeq = inParalogyIt->getSequence();
            Sequence *outParalogySeq = dest->getSequence(inParalogySeq->getName());
            outParalogyIndex = inParalogyIndex - inParalogySeq->getTopSegmentArrayIndex() + outParalogySeq->getTopSegmentArrayIndex();
        } else {
            outParalogyIndex = NULL_INDEX;
        }
        outTop->setNextParalogyIndex(outParalogyIndex);

        // Check that the sequences from the bottom segments we point to are the same. If not, correct the indices so that they are.
        if (inTop->getParentIndex() != NULL_INDEX) {
            inParentBottomSegIt->toParent(inTop);

            const Sequence *inParentSequence = inParentBottomSegIt->getSequence();

            const Sequence *outParentSequence = outParent->getSequence(inParentSequence->getName());

            hal_index_t inParentSegmentOffset = inTop->getParentIndex() - inParentSequence->getBottomSegmentArrayIndex();
            hal_index_t outParentSegmentIndex = inParentSegmentOffset + outParentSequence->getBottomSegmentArrayIndex();

            outTop->setParentIndex(outParentSegmentIndex);
        } else {
            outTop->setParentIndex(NULL_INDEX);
        }
    }
  }
}

void Genome::copyBottomSegments(Genome *dest) const
{
  assert(getNumBottomSegments() == dest->getNumBottomSegments());
  hal_size_t inNc = getNumChildren();
  hal_size_t outNc = dest->getNumChildren();
  // The child indices aren't consistent across files--make sure each bottom
  // segment points to the correct children
  vector<string> inChildNames;
  vector<string> outChildNames;
  for (hal_size_t inChild = 0; inChild < inNc; ++inChild)
  {
    inChildNames.push_back(getChild(inChild)->getName());
  }
  for (hal_size_t outChild = 0; outChild < outNc; ++outChild)
  {
    outChildNames.push_back(dest->getChild(outChild)->getName());
  }
  map<hal_size_t, hal_size_t> inChildToOutChild;
  for (hal_size_t inChild = 0; inChild < inNc; inChild++)
  {
    hal_size_t outChild;
    for (outChild = 0; outChild < outNc; outChild++)
    {
      if (inChildNames[inChild] == outChildNames[outChild])
      {
        inChildToOutChild[inChild] = outChild;
        break;
      }
    }
    if (outChild == outNc)
    {
      inChildToOutChild[inChild] = outNc;
    }
  }

  // Go through each sequence in this genome, find the matching
  // sequence in the dest genome, then copy over the segments for each
  // sequence.
  SequenceIteratorConstPtr seqIt = getSequenceIterator();
  SequenceIteratorConstPtr seqEndIt = getSequenceEndIterator();

  for (; seqIt != seqEndIt; seqIt->toNext())
  {
    const Sequence *inSeq = seqIt->getSequence();
    const Sequence *outSeq = dest->getSequence(inSeq->getName());
    BottomSegmentIteratorPtr inBot = inSeq->getBottomSegmentIterator();
    BottomSegmentIteratorPtr outBot = outSeq->getBottomSegmentIterator();

    if (inSeq->getName() != outSeq->getName()) {
      // This check is important enough that it can't be an assert.
      stringstream ss;
      ss << "When copying bottom segments: segment #" << inBot->getArrayIndex() << " of source genome is from sequence " << inBot->getSequence()->getName() << ", but segment #" << outBot->getArrayIndex() << " is from sequence " << outBot->getSequence()->getName();
      throw hal_exception(ss.str());
    }

    if (inSeq->getNumBottomSegments() != outSeq->getNumBottomSegments()) {
      stringstream ss;
      ss << "When copying bottom segments: sequence " << inSeq->getName() << " has " << inSeq->getNumBottomSegments() << " in genome " << getName() << ", while it has " << outSeq->getNumBottomSegments() << " in genome " << dest->getName();
      throw hal_exception(ss.str());
    }

    hal_index_t inSegmentEnd = inSeq->getBottomSegmentArrayIndex() + inSeq->getNumBottomSegments();
    for (; inBot->getArrayIndex() < inSegmentEnd; inBot->toRight(),
           outBot->toRight())
    {
      hal_index_t outStartPosition = inBot->getStartPosition() - inSeq->getStartPosition() + outSeq->getStartPosition();

      if (dest->getSequenceBySite(outStartPosition) != outSeq) {
        stringstream ss;
        ss << "When copying bottom segments from " << getName() << " to " << dest->getName() << ": expected destination sequence " << outSeq->getName() << " for segment # " << inBot->getArrayIndex() << " but got " << dest->getSequenceBySite(outStartPosition)->getName();
        throw hal_exception(ss.str());
      }
      outBot->setCoordinates(outStartPosition, inBot->getLength());
      for(hal_size_t inChild = 0; inChild < inNc; inChild++) {
        hal_size_t outChild = inChildToOutChild[inChild];
        if (outChild != outNc) {
            // Adjust top segment we point to so that it points to the
            // same sequence, even if the sequence ordering has changed.
            hal_index_t childIndex = inBot->getChildIndex(inChild);
            Genome *outChildGenome = dest->getChild(outChild);
            if (childIndex != NULL_INDEX) {
                TopSegmentIteratorConstPtr inIt = getTopSegmentIterator();
                inIt->toChild(inBot, inChild);

                const Sequence *inChildSequence = inIt->getSequence();
                const Sequence *outChildSequence = outChildGenome->getSequence(inChildSequence->getName());

                hal_index_t inChildSegmentOffset = inIt->getArrayIndex() - inChildSequence->getTopSegmentArrayIndex();
                childIndex = inChildSegmentOffset + outChildSequence->getTopSegmentArrayIndex();
            }

            outBot->setChildIndex(outChild, childIndex);
            outBot->setChildReversed(outChild, inBot->getChildReversed(inChild));
        }
      }
      outBot->setTopParseIndex(inBot->getTopParseIndex());
    }
  }
}

void Genome::copySequence(Genome *dest) const
{
  DNAIteratorConstPtr inDna = getDNAIterator();
  DNAIteratorPtr outDna = dest->getDNAIterator();
  hal_size_t n = getSequenceLength();
  assert(n == dest->getSequenceLength());
  for (; (hal_size_t)inDna->getArrayIndex() < n; inDna->toRight(),
         outDna->toRight())
  {
    outDna->setChar(inDna->getChar());
  }
}

void Genome::copyMetadata(Genome *dest) const
{
  const map<string, string>& meta = getMetaData()->getMap();
  map<string, string>::const_iterator i = meta.begin();
  for (; i != meta.end(); ++i)
  {
    dest->getMetaData()->set(i->first, i->second);
  }
}

void Genome::fixParseInfo()
{
  if (getParent() == NULL || getNumChildren() == 0)
  {
    return;
  }

  // copied from CactusHalConverter::updateRootParseInfo() in
  // cactus2hal/src/cactusHalConverter.cpp
  BottomSegmentIteratorPtr bottomIterator =
    getBottomSegmentIterator();
  TopSegmentIteratorPtr topIterator = getTopSegmentIterator();
  BottomSegmentIteratorConstPtr bend = getBottomSegmentEndIterator();
  TopSegmentIteratorConstPtr tend = getTopSegmentEndIterator();
  int top = 0, bot = 0;
  while (bottomIterator != bend && topIterator != tend)
  {
    bool bright = false;
    bool tright = false;
    BottomSegment* bseg = bottomIterator->getBottomSegment();
    TopSegment* tseg = topIterator->getTopSegment();
    hal_index_t bstart = bseg->getStartPosition();
    hal_index_t bendidx = bstart + (hal_index_t)bseg->getLength();
    hal_index_t tstart = tseg->getStartPosition();
    hal_index_t tendidx = tstart + (hal_index_t)tseg->getLength();

    if (bstart >= tstart && bstart < tendidx)
    {
      bseg->setTopParseIndex(tseg->getArrayIndex());
    }
    if (bendidx <= tendidx || bstart == bendidx)
    {
      bright = true;
    }

    if (tstart >= bstart && tstart < bendidx)
    {
      tseg->setBottomParseIndex(bseg->getArrayIndex());
    }
    if (tendidx <= bendidx || tstart == tendidx)
    {
      tright = true;
    }

    assert(bright || tright);
    if (bright == true)
    {
      bot += 1;
      bottomIterator->toRight();
    }
    if (tright == true)
    {
      top += 1;
      topIterator->toRight();
    }
  }
}
} // namespace hal
<|endoftext|>


<commit_before><commit_msg>Revert "linux: use xmessage for the dialog used in LOG(FATAL)"<commit_after><|endoftext|>


<commit_before>/*****************************************************************************
 * cast.cpp: Chromecast sout module for vlc
 *****************************************************************************
 * Copyright © 2014-2015 VideoLAN
 *
 * Authors: Adrien Maglo <magsoft@videolan.org>
 *          Jean-Baptiste Kempf <jb@videolan.org>
 *          Steve Lhomme <robux4@videolabs.io>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include "chromecast.h"

#include <vlc_sout.h>

#include <cassert>

struct sout_stream_sys_t
{
    sout_stream_sys_t(intf_sys_t *intf, sout_stream_t *sout, bool has_video)
        : p_out(sout)
        , p_intf(intf)
        , b_has_video(has_video)
    {
        assert(p_intf != NULL);
    }

    ~sout_stream_sys_t()
    {
        sout_StreamChainDelete(p_out, p_out);
    }

    sout_stream_t * const p_out;
    intf_sys_t * const p_intf;
    const bool b_has_video;
};

#define SOUT_CFG_PREFIX "sout-chromecast-"

/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
static int Open(vlc_object_t *);
static void Close(vlc_object_t *);

static const char *const ppsz_sout_options[] = {
    "http-port", "mux", "mime", "video", NULL
};

/*****************************************************************************
 * Module descriptor
 *****************************************************************************/

#define HTTP_PORT_TEXT N_("HTTP port")
#define HTTP_PORT_LONGTEXT N_("This sets the HTTP port of the server " \
                              "used to stream the media to the Chromecast.")
#define HAS_VIDEO_TEXT N_("Video")
#define HAS_VIDEO_LONGTEXT N_("The Chromecast receiver can receive video.")
#define MUX_TEXT N_("Muxer")
#define MUX_LONGTEXT N_("This sets the muxer used to stream to the Chromecast.")
#define MIME_TEXT N_("MIME content type")
#define MIME_LONGTEXT N_("This sets the media MIME content type sent to the Chromecast.")

vlc_module_begin ()

    set_shortname(N_("Chromecast"))
    set_description(N_("Chromecast stream output"))
    set_capability("sout stream", 0)
    add_shortcut("chromecast")
    set_category(CAT_SOUT)
    set_subcategory(SUBCAT_SOUT_STREAM)
    set_callbacks(Open, Close)

    add_integer(SOUT_CFG_PREFIX "http-port", HTTP_PORT, HTTP_PORT_TEXT, HTTP_PORT_LONGTEXT, false)
    add_bool(SOUT_CFG_PREFIX "video", true, HAS_VIDEO_TEXT, HAS_VIDEO_LONGTEXT, false)
    add_string(SOUT_CFG_PREFIX "mux", "mp4stream", MUX_TEXT, MUX_LONGTEXT, false)
    add_string(SOUT_CFG_PREFIX "mime", "video/mp4", MIME_TEXT, MIME_LONGTEXT, false)

vlc_module_end ()

/*****************************************************************************
 * Sout callbacks
 *****************************************************************************/
static sout_stream_id_sys_t *Add(sout_stream_t *p_stream, const es_format_t *p_fmt)
{
    sout_stream_sys_t *p_sys = p_stream->p_sys;

    if (!p_sys->b_has_video)
    {
        if (p_fmt->i_cat != AUDIO_ES)
            return NULL;
    }
    return sout_StreamIdAdd(p_sys->p_out, p_fmt);
}

static void Del(sout_stream_t *p_stream, sout_stream_id_sys_t *id)
{
    sout_stream_sys_t *p_sys = p_stream->p_sys;

    sout_StreamIdDel(p_sys->p_out, id);
}

static int Send(sout_stream_t *p_stream, sout_stream_id_sys_t *id,
                block_t *p_buffer)
{
    sout_stream_sys_t *p_sys = p_stream->p_sys;

    return sout_StreamIdSend(p_sys->p_out, id, p_buffer);
}

static void Flush( sout_stream_t *p_stream, sout_stream_id_sys_t *id )
{
    sout_stream_sys_t *p_sys = p_stream->p_sys;

    sout_StreamFlush( p_sys->p_out, id );
}

static int Control(sout_stream_t *p_stream, int i_query, va_list args)
{
    sout_stream_sys_t *p_sys = p_stream->p_sys;

    if ( !p_sys->p_out->pf_control )
        return VLC_EGENERIC;

    return p_sys->p_out->pf_control( p_sys->p_out, i_query, args );
}

/*****************************************************************************
 * Open: connect to the Chromecast and initialize the sout
 *****************************************************************************/
static int Open(vlc_object_t *p_this)
{
    sout_stream_t *p_stream = reinterpret_cast<sout_stream_t*>(p_this);
    sout_stream_sys_t *p_sys = NULL;
    intf_sys_t *p_intf = NULL;
    char *psz_mux = NULL;
    char *psz_var_mime = NULL;
    sout_stream_t *p_sout = NULL;
    bool b_has_video = true;
    std::stringstream ss;

    config_ChainParse(p_stream, SOUT_CFG_PREFIX, ppsz_sout_options, p_stream->p_cfg);

    psz_mux = var_GetNonEmptyString(p_stream, SOUT_CFG_PREFIX "mux");
    if (psz_mux == NULL || !psz_mux[0])
    {
        goto error;
    }
    psz_var_mime = var_GetNonEmptyString(p_stream, SOUT_CFG_PREFIX "mime");
    if (psz_var_mime == NULL || !psz_var_mime[0])
        goto error;

    ss << "http{dst=:" << var_InheritInteger(p_stream, SOUT_CFG_PREFIX "http-port") << "/stream"
       << ",mux=" << psz_mux
       << ",access=http{mime=" << psz_var_mime << "}}";

    p_sout = sout_StreamChainNew( p_stream->p_sout, ss.str().c_str(), NULL, NULL);
    if (p_sout == NULL) {
        msg_Dbg(p_stream, "could not create sout chain:%s", ss.str().c_str());
        goto error;
    }

    b_has_video = var_GetBool(p_stream, SOUT_CFG_PREFIX "video");

    p_sys = new(std::nothrow) sout_stream_sys_t(p_intf, p_sout, b_has_video);
    if (unlikely(p_sys == NULL))
        goto error;

    // Set the sout callbacks.
    p_stream->pf_add     = Add;
    p_stream->pf_del     = Del;
    p_stream->pf_send    = Send;
    p_stream->pf_flush   = Flush;
    p_stream->pf_control = Control;

    p_stream->p_sys = p_sys;
    free(psz_mux);
    free(psz_var_mime);
    return VLC_SUCCESS;

error:
    sout_StreamChainDelete(p_sout, p_sout);
    free(psz_mux);
    free(psz_var_mime);
    delete p_sys;
    return VLC_EGENERIC;
}

/*****************************************************************************
 * Close: destroy interface
 *****************************************************************************/
static void Close(vlc_object_t *p_this)
{
    sout_stream_t *p_stream = reinterpret_cast<sout_stream_t*>(p_this);

    delete p_stream->p_sys;
}

<commit_msg>chromecast: var_GetNonEmptyString() cannot return a "" string<commit_after>/*****************************************************************************
 * cast.cpp: Chromecast sout module for vlc
 *****************************************************************************
 * Copyright © 2014-2015 VideoLAN
 *
 * Authors: Adrien Maglo <magsoft@videolan.org>
 *          Jean-Baptiste Kempf <jb@videolan.org>
 *          Steve Lhomme <robux4@videolabs.io>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include "chromecast.h"

#include <vlc_sout.h>

#include <cassert>

struct sout_stream_sys_t
{
    sout_stream_sys_t(intf_sys_t *intf, sout_stream_t *sout, bool has_video)
        : p_out(sout)
        , p_intf(intf)
        , b_has_video(has_video)
    {
        assert(p_intf != NULL);
    }

    ~sout_stream_sys_t()
    {
        sout_StreamChainDelete(p_out, p_out);
    }

    sout_stream_t * const p_out;
    intf_sys_t * const p_intf;
    const bool b_has_video;
};

#define SOUT_CFG_PREFIX "sout-chromecast-"

/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
static int Open(vlc_object_t *);
static void Close(vlc_object_t *);

static const char *const ppsz_sout_options[] = {
    "http-port", "mux", "mime", "video", NULL
};

/*****************************************************************************
 * Module descriptor
 *****************************************************************************/

#define HTTP_PORT_TEXT N_("HTTP port")
#define HTTP_PORT_LONGTEXT N_("This sets the HTTP port of the server " \
                              "used to stream the media to the Chromecast.")
#define HAS_VIDEO_TEXT N_("Video")
#define HAS_VIDEO_LONGTEXT N_("The Chromecast receiver can receive video.")
#define MUX_TEXT N_("Muxer")
#define MUX_LONGTEXT N_("This sets the muxer used to stream to the Chromecast.")
#define MIME_TEXT N_("MIME content type")
#define MIME_LONGTEXT N_("This sets the media MIME content type sent to the Chromecast.")

vlc_module_begin ()

    set_shortname(N_("Chromecast"))
    set_description(N_("Chromecast stream output"))
    set_capability("sout stream", 0)
    add_shortcut("chromecast")
    set_category(CAT_SOUT)
    set_subcategory(SUBCAT_SOUT_STREAM)
    set_callbacks(Open, Close)

    add_integer(SOUT_CFG_PREFIX "http-port", HTTP_PORT, HTTP_PORT_TEXT, HTTP_PORT_LONGTEXT, false)
    add_bool(SOUT_CFG_PREFIX "video", true, HAS_VIDEO_TEXT, HAS_VIDEO_LONGTEXT, false)
    add_string(SOUT_CFG_PREFIX "mux", "mp4stream", MUX_TEXT, MUX_LONGTEXT, false)
    add_string(SOUT_CFG_PREFIX "mime", "video/mp4", MIME_TEXT, MIME_LONGTEXT, false)

vlc_module_end ()

/*****************************************************************************
 * Sout callbacks
 *****************************************************************************/
static sout_stream_id_sys_t *Add(sout_stream_t *p_stream, const es_format_t *p_fmt)
{
    sout_stream_sys_t *p_sys = p_stream->p_sys;

    if (!p_sys->b_has_video)
    {
        if (p_fmt->i_cat != AUDIO_ES)
            return NULL;
    }
    return sout_StreamIdAdd(p_sys->p_out, p_fmt);
}

static void Del(sout_stream_t *p_stream, sout_stream_id_sys_t *id)
{
    sout_stream_sys_t *p_sys = p_stream->p_sys;

    sout_StreamIdDel(p_sys->p_out, id);
}

static int Send(sout_stream_t *p_stream, sout_stream_id_sys_t *id,
                block_t *p_buffer)
{
    sout_stream_sys_t *p_sys = p_stream->p_sys;

    return sout_StreamIdSend(p_sys->p_out, id, p_buffer);
}

static void Flush( sout_stream_t *p_stream, sout_stream_id_sys_t *id )
{
    sout_stream_sys_t *p_sys = p_stream->p_sys;

    sout_StreamFlush( p_sys->p_out, id );
}

static int Control(sout_stream_t *p_stream, int i_query, va_list args)
{
    sout_stream_sys_t *p_sys = p_stream->p_sys;

    if ( !p_sys->p_out->pf_control )
        return VLC_EGENERIC;

    return p_sys->p_out->pf_control( p_sys->p_out, i_query, args );
}

/*****************************************************************************
 * Open: connect to the Chromecast and initialize the sout
 *****************************************************************************/
static int Open(vlc_object_t *p_this)
{
    sout_stream_t *p_stream = reinterpret_cast<sout_stream_t*>(p_this);
    sout_stream_sys_t *p_sys = NULL;
    intf_sys_t *p_intf = NULL;
    char *psz_mux = NULL;
    char *psz_var_mime = NULL;
    sout_stream_t *p_sout = NULL;
    bool b_has_video = true;
    std::stringstream ss;

    config_ChainParse(p_stream, SOUT_CFG_PREFIX, ppsz_sout_options, p_stream->p_cfg);

    psz_mux = var_GetNonEmptyString(p_stream, SOUT_CFG_PREFIX "mux");
    if (psz_mux == NULL)
    {
        goto error;
    }
    psz_var_mime = var_GetNonEmptyString(p_stream, SOUT_CFG_PREFIX "mime");
    if (psz_var_mime == NULL)
        goto error;

    ss << "http{dst=:" << var_InheritInteger(p_stream, SOUT_CFG_PREFIX "http-port") << "/stream"
       << ",mux=" << psz_mux
       << ",access=http{mime=" << psz_var_mime << "}}";

    p_sout = sout_StreamChainNew( p_stream->p_sout, ss.str().c_str(), NULL, NULL);
    if (p_sout == NULL) {
        msg_Dbg(p_stream, "could not create sout chain:%s", ss.str().c_str());
        goto error;
    }

    b_has_video = var_GetBool(p_stream, SOUT_CFG_PREFIX "video");

    p_sys = new(std::nothrow) sout_stream_sys_t(p_intf, p_sout, b_has_video);
    if (unlikely(p_sys == NULL))
        goto error;

    // Set the sout callbacks.
    p_stream->pf_add     = Add;
    p_stream->pf_del     = Del;
    p_stream->pf_send    = Send;
    p_stream->pf_flush   = Flush;
    p_stream->pf_control = Control;

    p_stream->p_sys = p_sys;
    free(psz_mux);
    free(psz_var_mime);
    return VLC_SUCCESS;

error:
    sout_StreamChainDelete(p_sout, p_sout);
    free(psz_mux);
    free(psz_var_mime);
    delete p_sys;
    return VLC_EGENERIC;
}

/*****************************************************************************
 * Close: destroy interface
 *****************************************************************************/
static void Close(vlc_object_t *p_this)
{
    sout_stream_t *p_stream = reinterpret_cast<sout_stream_t*>(p_this);

    delete p_stream->p_sys;
}

<|endoftext|>


<commit_before>#include "player.h"

#include "common/log.h"

#define PLAYER_CAPSULE_HEIGHT 1.8f
#define PLAYER_CAPSULE_RADIUS 0.25f

// 75 kg mass person
#define PLAYER_MASS 75.0f

namespace redc
{
  Player_Controller::Player_Controller() : inited_(false), ghost_(),
                                           shape_(PLAYER_CAPSULE_RADIUS,
                                                  PLAYER_CAPSULE_HEIGHT),
                                           jump_velocity_() {}

  // They are expected to add the action to the dynamics world and then this
  // will be called, then we init then we start
  void Player_Controller::updateAction(btCollisionWorld* world, btScalar dt)
  {
    if(!inited_)
    {
      // Initialize velocity and impulse to zero
      jump_velocity_.setZero();

      last_normal_.setZero();

      // Set it to a unit vector going straight upwards
      last_normal_.setY(1.0f);

      // Player state
      state = Player_State::Grounded;

      // Transform
      btTransform trans;
      trans.setIdentity();
      trans.setOrigin(btVector3(0.0f, 4.5f, 0.0f));
      ghost_.setWorldTransform(trans);

      // Shape
      ghost_.setCollisionShape(&shape_);

      // Flags
      ghost_.setCollisionFlags(ghost_.getCollisionFlags() |
                               btCollisionObject::CF_KINEMATIC_OBJECT);
      ghost_.setActivationState(DISABLE_DEACTIVATION);

      // Ghost callback, this updates any ghost object with any and all objects
      // it collides with so later on we can collision dispatching on only those
      // pairs (and get contacts back, etc).

      // **Important:** Add this before adding the ghost object, otherwise the
      // ghost object will not get notified and dispatching collisions of the
      // ghost object will literally ignore all collisions with the world. This
      // actually bit me in the butt before these two statements were
      // re-ordered. Interesting because even though the objects were actually
      // colliding, the (pair caching) ghost object was not dispatching the
      // ghost-map collisions.
      world->getPairCache()->setInternalGhostPairCallback(&ghost_cb_);

      // Add to world
      world->addCollisionObject(&ghost_);

      inited_ = true;
      return;
    }

    // Current world transform
    auto xform = ghost_.getWorldTransform();
    // Current position
    auto pos = xform.getOrigin();

    // Updates the ghost object. Suffixed with an underscore so we know it's
    // private... to this function.
    auto update_ghost_transform_ = [&]()
    {
      xform.setOrigin(pos);
      ghost_.setWorldTransform(xform);
    };

    // ===
    // Ray tracing floor-collision handling
    // ===
    {
      // First trace a ray from the player to the near-ground. If we hit
      // something we should consider the player on the ground, that means we no
      // longer have to apply gravity, for example.

      // How far should the ray extend past the bottom of the ghost object.
      constexpr float shoe_size = 0.7f;

      auto start_pos = pos;
      start_pos.setY(pos.getY() - PLAYER_CAPSULE_HEIGHT / 2.0f);

      auto end_pos = pos;
      end_pos.setY(start_pos.getY() - shoe_size);

      // Redundancy whhyyyyy
      btCollisionWorld::ClosestRayResultCallback ground_ray(start_pos, end_pos);
      world->rayTest(start_pos, end_pos, ground_ray);

      if(ground_ray.hasHit())
      {
        // What is the player doing?

        // Notes:

        // This section used to reset the player's y position to the ray
        // intersection point, the issue is that it would interfere with the
        // penetration recovery and cause a constant switch from the player
        // being grounded to being registered as jumping. The ray trace ended up
        // locking it too close to the ground and then the recover would push it
        // up too far such that next frame we switched to jumping, etc.

        // Anyways it works better now because we still use the player state to
        // decide whether or not to apply gravity but we don't accidentally move
        // the player and cause strange unexpected changes. The penetration
        // recovery works well enough that it can handle moving the player above
        // the floor just fine. After that, as long as gravity isn't applied the
        // player remains stable.

        // One issue that I'm seeing now that due to a large value for
        // shoe_size, the player can get stuck low down in the range of
        // allowable heights and then a jump becomes ineffective because even
        // after that one tick of movement the player is still in the allowable
        // range, which means the player is immediately considered to be on the
        // ground. Of course, currently that means velocity is not applied.
        if(state == Player_State::Jumping) state = Player_State::Grounded;

        last_normal_ = ground_ray.m_hitNormalWorld;
      }

      // No ground?
      else
      {
        state = Player_State::Jumping;
      }

      update_ghost_transform_();
    }

    // ===
    // Handle input
    // ===

    {
      btVector3 local_dpos;
      local_dpos.setZero();

      if(input_ref_->forward)
      {
        local_dpos.setX(-1.0f);
      }
      if(input_ref_->backward)
      {
        local_dpos.setX(+1.0f);
      }
      if(input_ref_->strafe_left)
      {
        local_dpos.setZ(+1.0f);
      }
      if(input_ref_->strafe_right)
      {
        local_dpos.setZ(-1.0f);
      }

      if(input_ref_->jump && state == Player_State::Grounded)
      {
        jump_velocity_ = btVector3(0.0f, 6.0f, 0.0f);
        state = Player_State::Jumping;
      }

      auto active_normal = last_normal_;
      if(state == Player_State::Jumping)
      {
        active_normal.setZero();
        active_normal.setY(1.0f);
      }

      if(FLT_EPSILON < btFabs(local_dpos.length()))
      {
        auto movement = btMatrix3x3(xform.getRotation()) * local_dpos;
        pos += movement.cross(active_normal) * btScalar(0.1f);
      }

      update_ghost_transform_();
    }

    // ===
    // Apply gravity to the velocity if necessary
    // ===

    // When we are in the air, adjust the velocity change due to gravity.
    if(state == Player_State::Jumping)
    {
      // Adjust the air velocity of the player
      jump_velocity_ += btVector3(0.0f, -9.81f, 0.0f) * dt;
    }
    else
    {
      jump_velocity_.setZero();
    }

    // ===
    // Integrate the velocity
    // ===
    if(state != Player_State::Grounded)
    {
      pos += jump_velocity_ * dt;
      update_ghost_transform_();
    }

    // ===
    // Recover the player from any intersection with the map
    //
    // Inspired very heavily by the btKinematicCharacterController.
    // See http://bulletphysics.org/Bullet/BulletFull/btKinematicCharacterController_8cpp_source.html
    // for reference, license, etc.
    // ===

    // Here we must refresh the overlapping paircache as the penetrating
    // movement itself or the previous recovery iteration might have used
    // setWorldTransform and pushed us into an object that is not in the
    // previous cache contents from the last timestep, as will happen if we are
    // pushed into a new AABB overlap. Unhandled this means the next convex
    // sweep gets stuck.

    // Do this by calling the broadphase's setAabb with the moved AABB, this
    // will update the broadphase paircache and the ghostobject's internal
    // paircache at the same time. /BW
    btVector3 minAabb, maxAabb;
    shape_.getAabb(ghost_.getWorldTransform(), minAabb, maxAabb);
    world->getBroadphase()->setAabb(ghost_.getBroadphaseHandle(),
                                    minAabb, maxAabb, world->getDispatcher());

    // Added Notes:

    // The ghost object already knows what it's colliding with but doesn't have
    // any collision manifolds (lists of intersecting points between a pair of
    // objects). Basically, the ghost pair cache and the world pair cache are
    // kept mostly up to date thanks to the btGhostPairCallback set in the
    // world's pair cache above, but the pair objects (and algorithm impl.,
    // which store the collision manifold) are actually different, even if the
    // objects that the pair consists of (or more specifically broadphase
    // proxies) are the same. As a result, we can't pass the world pair cache to
    // do the processing because it will only generate contact points for the
    // pairs of objects in the world. As a result, the contact points (or
    // manifold) will not be accessible from the ghost pair cache, (whose
    // contact points have not been calculated).
    auto ghost_cache = ghost_.getOverlappingPairCache();
    world->getDispatcher()->dispatchAllCollisionPairs(ghost_cache,
                                                      world->getDispatchInfo(),
                                                      world->getDispatcher());

    bool penetration = false;

    for (int i = 0; i < ghost_cache->getNumOverlappingPairs(); i++)
    {
      btManifoldArray manifolds;

      btBroadphasePair* pair = &ghost_cache->getOverlappingPairArray()[i];

      btCollisionObject* obj0 = static_cast<btCollisionObject*>(
              pair->m_pProxy0->m_clientObject);
      btCollisionObject* obj1 = static_cast<btCollisionObject*>(
              pair->m_pProxy1->m_clientObject);

      // Both objects must not have collision response.
      if ((obj0 && !obj0->hasContactResponse()) ||
          (obj1 && !obj1->hasContactResponse()))
      {
        continue;
      }

      if (pair->m_algorithm)
      {
        pair->m_algorithm->getAllContactManifolds(manifolds);
      }

      for (int j = 0; j < manifolds.size(); j++)
      {
        btPersistentManifold* manifold = manifolds[j];
        btScalar sign =
          manifold->getBody0() == &ghost_ ? btScalar(-1.0) : btScalar(1.0);

        for (int p = 0; p < manifold->getNumContacts(); p++)
        {
          const btManifoldPoint& pt = manifold->getContactPoint(p);

          btScalar dist = pt.getDistance();

          if (dist < 0.0)
          {
            // Added notes:

            // This solution of pushing the character away from objects is okay
            // but it is not really practical when the player is standing still
            // The character often glitches around and it's only that measly
            // multiplication by 0.2 that keeps the whole thing somewhat decent
            // and smooth. The smoothing does work against walls though, so this
            // should be considered this codes most important reason for being
            // here. Floor collision, jumping, stepping, etc should all probably
            // be done with a raytrace and a state machine, etc.

            pos += pt.m_normalWorldOnB * sign * dist;
            penetration = true;
          }
        }
      }
    }

    if(penetration) update_ghost_transform_();
  }

  void Player_Controller::apply_delta_yaw(double yaw)
  {
    auto xform = ghost_.getWorldTransform();
    auto rot = xform.getRotation();
    rot *= btQuaternion(-yaw, 0.0f, 0.0f);
    xform.setRotation(rot);
    ghost_.setWorldTransform(xform);
  }
  void Player_Controller::apply_delta_pitch(double pitch)
  {
    // We don't care about pitch as of now from a physics standpoint
    /*
    auto xform = ghost_.getWorldTransform();
    auto rot = xform.getRotation();
    rot *= btQuaternion(0.0f, pitch, 0.0f);
    ghost_.setWorldTransform(xform);
    */
  }
}
<commit_msg>Simplify impl. of walking perpendicular to floor<commit_after>#include "player.h"

#include "common/log.h"

#define PLAYER_CAPSULE_HEIGHT 1.8f
#define PLAYER_CAPSULE_RADIUS 0.25f

// 75 kg mass person
#define PLAYER_MASS 75.0f

namespace redc
{
  Player_Controller::Player_Controller() : inited_(false), ghost_(),
                                           shape_(PLAYER_CAPSULE_RADIUS,
                                                  PLAYER_CAPSULE_HEIGHT),
                                           jump_velocity_() {}

  // They are expected to add the action to the dynamics world and then this
  // will be called, then we init then we start
  void Player_Controller::updateAction(btCollisionWorld* world, btScalar dt)
  {
    if(!inited_)
    {
      // Initialize velocity and impulse to zero
      jump_velocity_.setZero();

      last_normal_.setZero();

      // Set it to a unit vector going straight upwards
      last_normal_.setY(1.0f);

      // Player state
      state = Player_State::Grounded;

      // Transform
      btTransform trans;
      trans.setIdentity();
      trans.setOrigin(btVector3(0.0f, 4.5f, 0.0f));
      ghost_.setWorldTransform(trans);

      // Shape
      ghost_.setCollisionShape(&shape_);

      // Flags
      ghost_.setCollisionFlags(ghost_.getCollisionFlags() |
                               btCollisionObject::CF_KINEMATIC_OBJECT);
      ghost_.setActivationState(DISABLE_DEACTIVATION);

      // Ghost callback, this updates any ghost object with any and all objects
      // it collides with so later on we can collision dispatching on only those
      // pairs (and get contacts back, etc).

      // **Important:** Add this before adding the ghost object, otherwise the
      // ghost object will not get notified and dispatching collisions of the
      // ghost object will literally ignore all collisions with the world. This
      // actually bit me in the butt before these two statements were
      // re-ordered. Interesting because even though the objects were actually
      // colliding, the (pair caching) ghost object was not dispatching the
      // ghost-map collisions.
      world->getPairCache()->setInternalGhostPairCallback(&ghost_cb_);

      // Add to world
      world->addCollisionObject(&ghost_);

      inited_ = true;
      return;
    }

    // Current world transform
    auto xform = ghost_.getWorldTransform();
    // Current position
    auto pos = xform.getOrigin();

    // Updates the ghost object. Suffixed with an underscore so we know it's
    // private... to this function.
    auto update_ghost_transform_ = [&]()
    {
      xform.setOrigin(pos);
      ghost_.setWorldTransform(xform);
    };

    // ===
    // Ray tracing floor-collision handling
    // ===
    {
      // First trace a ray from the player to the near-ground. If we hit
      // something we should consider the player on the ground, that means we no
      // longer have to apply gravity, for example.

      // How far should the ray extend past the bottom of the ghost object.
      constexpr float shoe_size = 0.7f;

      auto start_pos = pos;
      start_pos.setY(pos.getY() - PLAYER_CAPSULE_HEIGHT / 2.0f);

      auto end_pos = pos;
      end_pos.setY(start_pos.getY() - shoe_size);

      // Redundancy whhyyyyy
      btCollisionWorld::ClosestRayResultCallback ground_ray(start_pos, end_pos);
      world->rayTest(start_pos, end_pos, ground_ray);

      if(ground_ray.hasHit())
      {
        // What is the player doing?

        // Notes:

        // This section used to reset the player's y position to the ray
        // intersection point, the issue is that it would interfere with the
        // penetration recovery and cause a constant switch from the player
        // being grounded to being registered as jumping. The ray trace ended up
        // locking it too close to the ground and then the recover would push it
        // up too far such that next frame we switched to jumping, etc.

        // Anyways it works better now because we still use the player state to
        // decide whether or not to apply gravity but we don't accidentally move
        // the player and cause strange unexpected changes. The penetration
        // recovery works well enough that it can handle moving the player above
        // the floor just fine. After that, as long as gravity isn't applied the
        // player remains stable.

        // One issue that I'm seeing now that due to a large value for
        // shoe_size, the player can get stuck low down in the range of
        // allowable heights and then a jump becomes ineffective because even
        // after that one tick of movement the player is still in the allowable
        // range, which means the player is immediately considered to be on the
        // ground. Of course, currently that means velocity is not applied.
        if(state == Player_State::Jumping) state = Player_State::Grounded;

        last_normal_ = ground_ray.m_hitNormalWorld;
      }

      // No ground?
      else
      {
        state = Player_State::Jumping;
      }

      update_ghost_transform_();
    }

    // ===
    // Handle input
    // ===

    {
      btVector3 local_dpos;
      local_dpos.setZero();

      if(input_ref_->forward)
      {
        local_dpos.setZ(-1.0f);
      }
      if(input_ref_->backward)
      {
        local_dpos.setZ(+1.0f);
      }
      if(input_ref_->strafe_left)
      {
        local_dpos.setX(-1.0f);
      }
      if(input_ref_->strafe_right)
      {
        local_dpos.setX(+1.0f);
      }

      if(input_ref_->jump && state == Player_State::Grounded)
      {
        jump_velocity_ = btVector3(0.0f, 6.0f, 0.0f);
        state = Player_State::Jumping;
      }

      auto active_normal = last_normal_;
      if(state == Player_State::Jumping)
      {
        active_normal.setZero();
        active_normal.setY(1.0f);
      }

      if(FLT_EPSILON < btFabs(local_dpos.length()))
      {
        // We only really care about the direction in the x and z direction.
        // The y direction we will find ourselves such that the final movement
        // is perpendicular to the surface normal.
        auto movement = btMatrix3x3(xform.getRotation()) * local_dpos;

        // We want our final movement vector to be perpendicular to the normal
        // but it also has to be the same x and z value of the movement we
        // calculated before.
        auto partial_dot = active_normal.getX() * movement.getX() +
                           active_normal.getZ() * movement.getZ();
        // Use the fact that movement dot normal should be zero
        // 0 = partial_dot + new_movement_y * active_normal.getY();
        // -partial_dot / active_normal.getY() = new_movement_y;
        movement.setY(-partial_dot / active_normal.getY());
        pos += movement.normalize() * btScalar(.1f);
      }

      update_ghost_transform_();
    }

    // ===
    // Apply gravity to the velocity if necessary
    // ===

    // When we are in the air, adjust the velocity change due to gravity.
    if(state == Player_State::Jumping)
    {
      // Adjust the air velocity of the player
      jump_velocity_ += btVector3(0.0f, -9.81f, 0.0f) * dt;
    }
    else
    {
      jump_velocity_.setZero();
    }

    // ===
    // Integrate the velocity
    // ===
    if(state != Player_State::Grounded)
    {
      pos += jump_velocity_ * dt;
      update_ghost_transform_();
    }

    // ===
    // Recover the player from any intersection with the map
    //
    // Inspired very heavily by the btKinematicCharacterController.
    // See http://bulletphysics.org/Bullet/BulletFull/btKinematicCharacterController_8cpp_source.html
    // for reference, license, etc.
    // ===

    // Here we must refresh the overlapping paircache as the penetrating
    // movement itself or the previous recovery iteration might have used
    // setWorldTransform and pushed us into an object that is not in the
    // previous cache contents from the last timestep, as will happen if we are
    // pushed into a new AABB overlap. Unhandled this means the next convex
    // sweep gets stuck.

    // Do this by calling the broadphase's setAabb with the moved AABB, this
    // will update the broadphase paircache and the ghostobject's internal
    // paircache at the same time. /BW
    btVector3 minAabb, maxAabb;
    shape_.getAabb(ghost_.getWorldTransform(), minAabb, maxAabb);
    world->getBroadphase()->setAabb(ghost_.getBroadphaseHandle(),
                                    minAabb, maxAabb, world->getDispatcher());

    // Added Notes:

    // The ghost object already knows what it's colliding with but doesn't have
    // any collision manifolds (lists of intersecting points between a pair of
    // objects). Basically, the ghost pair cache and the world pair cache are
    // kept mostly up to date thanks to the btGhostPairCallback set in the
    // world's pair cache above, but the pair objects (and algorithm impl.,
    // which store the collision manifold) are actually different, even if the
    // objects that the pair consists of (or more specifically broadphase
    // proxies) are the same. As a result, we can't pass the world pair cache to
    // do the processing because it will only generate contact points for the
    // pairs of objects in the world. As a result, the contact points (or
    // manifold) will not be accessible from the ghost pair cache, (whose
    // contact points have not been calculated).
    auto ghost_cache = ghost_.getOverlappingPairCache();
    world->getDispatcher()->dispatchAllCollisionPairs(ghost_cache,
                                                      world->getDispatchInfo(),
                                                      world->getDispatcher());

    bool penetration = false;

    for (int i = 0; i < ghost_cache->getNumOverlappingPairs(); i++)
    {
      btManifoldArray manifolds;

      btBroadphasePair* pair = &ghost_cache->getOverlappingPairArray()[i];

      btCollisionObject* obj0 = static_cast<btCollisionObject*>(
              pair->m_pProxy0->m_clientObject);
      btCollisionObject* obj1 = static_cast<btCollisionObject*>(
              pair->m_pProxy1->m_clientObject);

      // Both objects must not have collision response.
      if ((obj0 && !obj0->hasContactResponse()) ||
          (obj1 && !obj1->hasContactResponse()))
      {
        continue;
      }

      if (pair->m_algorithm)
      {
        pair->m_algorithm->getAllContactManifolds(manifolds);
      }

      for (int j = 0; j < manifolds.size(); j++)
      {
        btPersistentManifold* manifold = manifolds[j];
        btScalar sign =
          manifold->getBody0() == &ghost_ ? btScalar(-1.0) : btScalar(1.0);

        for (int p = 0; p < manifold->getNumContacts(); p++)
        {
          const btManifoldPoint& pt = manifold->getContactPoint(p);

          btScalar dist = pt.getDistance();

          if (dist < 0.0)
          {
            // Added notes:

            // This solution of pushing the character away from objects is okay
            // but it is not really practical when the player is standing still
            // The character often glitches around and it's only that measly
            // multiplication by 0.2 that keeps the whole thing somewhat decent
            // and smooth. The smoothing does work against walls though, so this
            // should be considered this codes most important reason for being
            // here. Floor collision, jumping, stepping, etc should all probably
            // be done with a raytrace and a state machine, etc.

            pos += pt.m_normalWorldOnB * sign * dist;
            penetration = true;
          }
        }
      }
    }

    if(penetration) update_ghost_transform_();
  }

  void Player_Controller::apply_delta_yaw(double yaw)
  {
    auto xform = ghost_.getWorldTransform();
    auto rot = xform.getRotation();
    rot *= btQuaternion(-yaw, 0.0f, 0.0f);
    xform.setRotation(rot);
    ghost_.setWorldTransform(xform);
  }
  void Player_Controller::apply_delta_pitch(double pitch)
  {
    // We don't care about pitch as of now from a physics standpoint
    /*
    auto xform = ghost_.getWorldTransform();
    auto rot = xform.getRotation();
    rot *= btQuaternion(0.0f, pitch, 0.0f);
    ghost_.setWorldTransform(xform);
    */
  }
}
<|endoftext|>


<commit_before>/*
 * This file is part of oauth2 plugin
 *
 * Copyright (C) 2010 Nokia Corporation.
 * Copyright (C) 2012 Canonical Ltd.
 *
 * Contact: Alberto Mardegan <alberto.mardegan@canonical.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * version 2.1 as published by the Free Software Foundation.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 */

#include "common.h"
#include "oauth1plugin.h"
#include "oauth2plugin.h"
#include "plugin.h"

#include <QNetworkAccessManager>
#include <QNetworkProxy>

using namespace SignOn;
using namespace OAuth2PluginNS;

namespace OAuth2PluginNS {
SIGNON_DECL_AUTH_PLUGIN(Plugin)
} //namespace OAuth2PluginNS

Plugin::Plugin(QObject *parent):
    AuthPluginInterface(parent),
    impl(0),
    m_networkAccessManager(new QNetworkAccessManager(this))
{
    TRACE();
}

Plugin::~Plugin()
{
    TRACE();
    delete impl;
    impl = 0;
}

QString Plugin::type() const
{
    TRACE();
    return QString("oauth2");
}

QStringList Plugin::mechanisms() const
{
    TRACE();
    return OAuth1Plugin::mechanisms() +
        OAuth2Plugin::mechanisms();
}

void Plugin::cancel()
{
    TRACE();
    if (impl != 0) impl->cancel();
}

void Plugin::process(const SignOn::SessionData &inData,
                           const QString &mechanism)
{
    if (impl != 0) delete impl;

    if (OAuth1Plugin::mechanisms().contains(mechanism)) {
        impl = new OAuth1Plugin(this);
    } else if (OAuth2Plugin::mechanisms().contains(mechanism)) {
        impl = new OAuth2Plugin(this);
    } else {
        emit error(Error(Error::MechanismNotAvailable));
        return;
    }

    QNetworkProxy networkProxy = QNetworkProxy::applicationProxy();
    // Override proxy, if given in the parameters
    QString proxy = inData.NetworkProxy();
    if (!proxy.isEmpty()) {
        QUrl proxyUrl(proxy);
        if (!proxyUrl.host().isEmpty()) {
            networkProxy = QNetworkProxy(QNetworkProxy::HttpProxy,
                                         proxyUrl.host(),
                                         proxyUrl.port(),
                                         proxyUrl.userName(),
                                         proxyUrl.password());
            TRACE() << proxyUrl.host() << ":" <<  proxyUrl.port();
        }
    }

    m_networkAccessManager->setProxy(networkProxy);
    impl->setNetworkAccessManager(m_networkAccessManager);

    // Forward the signals from the implementation
    connect(impl, SIGNAL(result(const SignOn::SessionData &)),
            SIGNAL(result(const SignOn::SessionData &)));
    connect(impl, SIGNAL(store(const SignOn::SessionData &)),
            SIGNAL(store(const SignOn::SessionData &)));
    connect(impl, SIGNAL(error(const SignOn::Error &)),
            SIGNAL(error(const SignOn::Error &)));
    connect(impl, SIGNAL(userActionRequired(const SignOn::UiSessionData &)),
            SIGNAL(userActionRequired(const SignOn::UiSessionData &)));
    connect(impl, SIGNAL(refreshed(const SignOn::UiSessionData &)),
            SIGNAL(refreshed(const SignOn::UiSessionData &)));
    connect(impl, SIGNAL(statusChanged(const AuthPluginState, const QString&)),
            SIGNAL(statusChanged(const AuthPluginState, const QString&)));

    impl->process(inData, mechanism);
}

void Plugin::userActionFinished(const SignOn::UiSessionData &data)
{
    TRACE();
    if (impl != 0) impl->userActionFinished(data);
}

void Plugin::refresh(const SignOn::UiSessionData &data)
{
    TRACE();
    if (impl != 0) impl->refresh(data);
}
<commit_msg>Delay instantiation of QNetworkAccessManager<commit_after>/*
 * This file is part of oauth2 plugin
 *
 * Copyright (C) 2010 Nokia Corporation.
 * Copyright (C) 2012 Canonical Ltd.
 *
 * Contact: Alberto Mardegan <alberto.mardegan@canonical.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * version 2.1 as published by the Free Software Foundation.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 */

#include "common.h"
#include "oauth1plugin.h"
#include "oauth2plugin.h"
#include "plugin.h"

#include <QNetworkAccessManager>
#include <QNetworkProxy>

using namespace SignOn;
using namespace OAuth2PluginNS;

namespace OAuth2PluginNS {
SIGNON_DECL_AUTH_PLUGIN(Plugin)
} //namespace OAuth2PluginNS

Plugin::Plugin(QObject *parent):
    AuthPluginInterface(parent),
    impl(0),
    m_networkAccessManager(0)
{
    TRACE();
}

Plugin::~Plugin()
{
    TRACE();
    delete impl;
    impl = 0;
}

QString Plugin::type() const
{
    TRACE();
    return QString("oauth2");
}

QStringList Plugin::mechanisms() const
{
    TRACE();
    return OAuth1Plugin::mechanisms() +
        OAuth2Plugin::mechanisms();
}

void Plugin::cancel()
{
    TRACE();
    if (impl != 0) impl->cancel();
}

void Plugin::process(const SignOn::SessionData &inData,
                           const QString &mechanism)
{
    if (impl != 0) delete impl;

    if (!m_networkAccessManager) {
        m_networkAccessManager = new QNetworkAccessManager(this);
    }

    if (OAuth1Plugin::mechanisms().contains(mechanism)) {
        impl = new OAuth1Plugin(this);
    } else if (OAuth2Plugin::mechanisms().contains(mechanism)) {
        impl = new OAuth2Plugin(this);
    } else {
        emit error(Error(Error::MechanismNotAvailable));
        return;
    }

    QNetworkProxy networkProxy = QNetworkProxy::applicationProxy();
    // Override proxy, if given in the parameters
    QString proxy = inData.NetworkProxy();
    if (!proxy.isEmpty()) {
        QUrl proxyUrl(proxy);
        if (!proxyUrl.host().isEmpty()) {
            networkProxy = QNetworkProxy(QNetworkProxy::HttpProxy,
                                         proxyUrl.host(),
                                         proxyUrl.port(),
                                         proxyUrl.userName(),
                                         proxyUrl.password());
            TRACE() << proxyUrl.host() << ":" <<  proxyUrl.port();
        }
    }

    m_networkAccessManager->setProxy(networkProxy);
    impl->setNetworkAccessManager(m_networkAccessManager);

    // Forward the signals from the implementation
    connect(impl, SIGNAL(result(const SignOn::SessionData &)),
            SIGNAL(result(const SignOn::SessionData &)));
    connect(impl, SIGNAL(store(const SignOn::SessionData &)),
            SIGNAL(store(const SignOn::SessionData &)));
    connect(impl, SIGNAL(error(const SignOn::Error &)),
            SIGNAL(error(const SignOn::Error &)));
    connect(impl, SIGNAL(userActionRequired(const SignOn::UiSessionData &)),
            SIGNAL(userActionRequired(const SignOn::UiSessionData &)));
    connect(impl, SIGNAL(refreshed(const SignOn::UiSessionData &)),
            SIGNAL(refreshed(const SignOn::UiSessionData &)));
    connect(impl, SIGNAL(statusChanged(const AuthPluginState, const QString&)),
            SIGNAL(statusChanged(const AuthPluginState, const QString&)));

    impl->process(inData, mechanism);
}

void Plugin::userActionFinished(const SignOn::UiSessionData &data)
{
    TRACE();
    if (impl != 0) impl->userActionFinished(data);
}

void Plugin::refresh(const SignOn::UiSessionData &data)
{
    TRACE();
    if (impl != 0) impl->refresh(data);
}
<|endoftext|>


<commit_before>/******************************************************************************
 *
 * File:         wordclass.cpp  (Formerly wordclass.c)
 * Description:  Word classifier
 * Author:       Mark Seaman, OCR Technology
 *
 * (c) Copyright 1990, Hewlett-Packard Company.
 ** 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.
 *
 *****************************************************************************/
/*----------------------------------------------------------------------
          I N C L U D E S
----------------------------------------------------------------------*/

#include "blamer.h"  // for blamer_bundle
#include "params.h"  // for BoolParam
#include "render.h"  // for display_blob, blob_window, wordrec_blob_pause
#include "wordrec.h" // for Wordrec

class BLOB_CHOICE_LIST;

struct TBLOB;

// Include automatically generated configuration file if running autoconf.
#ifdef HAVE_CONFIG_H
#  include "config_auto.h"
#endif

/*----------------------------------------------------------------------
          F u n c t i o n s
----------------------------------------------------------------------*/
namespace tesseract {
/**
 * @name classify_blob
 *
 * Classify the this blob if it is not already recorded in the match
 * table. Attempt to recognize this blob as a character. The recognition
 * rating for this blob will be stored as a part of the blob. This value
 * will also be returned to the caller.
 * @param blob Current blob
 * @param string The string to display in ScrollView
 * @param color The colour to use when displayed with ScrollView
 */
BLOB_CHOICE_LIST *Wordrec::classify_blob(TBLOB *blob, const char *string, ScrollView::Color color,
                                         BlamerBundle *blamer_bundle) {
#ifndef GRAPHICS_DISABLED
  if (wordrec_display_all_blobs) {
    display_blob(blob, color);
  }
#endif
  // TODO(rays) collapse with call_matcher and move all to wordrec.cpp.
  BLOB_CHOICE_LIST *choices = call_matcher(blob);
  // If a blob with the same bounding box as one of the truth character
  // bounding boxes is not classified as the corresponding truth character
  // blame character classifier for incorrect answer.
  if (blamer_bundle != nullptr) {
    blamer_bundle->BlameClassifier(getDict().getUnicharset(), blob->bounding_box(), *choices,
                                   wordrec_debug_blamer);
  }
#ifndef GRAPHICS_DISABLED
  if (classify_debug_level && string) {
    print_ratings_list(string, choices, getDict().getUnicharset());
  }

  if (wordrec_blob_pause) {
    blob_window->Wait();
  }
#endif

  return choices;
}

} // namespace tesseract
<commit_msg>Remove unused fwd.<commit_after>/******************************************************************************
 *
 * File:         wordclass.cpp  (Formerly wordclass.c)
 * Description:  Word classifier
 * Author:       Mark Seaman, OCR Technology
 *
 * (c) Copyright 1990, Hewlett-Packard Company.
 ** 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.
 *
 *****************************************************************************/
/*----------------------------------------------------------------------
          I N C L U D E S
----------------------------------------------------------------------*/

#include "blamer.h"  // for blamer_bundle
#include "params.h"  // for BoolParam
#include "render.h"  // for display_blob, blob_window, wordrec_blob_pause
#include "wordrec.h" // for Wordrec

struct TBLOB;

// Include automatically generated configuration file if running autoconf.
#ifdef HAVE_CONFIG_H
#  include "config_auto.h"
#endif

/*----------------------------------------------------------------------
          F u n c t i o n s
----------------------------------------------------------------------*/
namespace tesseract {
/**
 * @name classify_blob
 *
 * Classify the this blob if it is not already recorded in the match
 * table. Attempt to recognize this blob as a character. The recognition
 * rating for this blob will be stored as a part of the blob. This value
 * will also be returned to the caller.
 * @param blob Current blob
 * @param string The string to display in ScrollView
 * @param color The colour to use when displayed with ScrollView
 */
BLOB_CHOICE_LIST *Wordrec::classify_blob(TBLOB *blob, const char *string, ScrollView::Color color,
                                         BlamerBundle *blamer_bundle) {
#ifndef GRAPHICS_DISABLED
  if (wordrec_display_all_blobs) {
    display_blob(blob, color);
  }
#endif
  // TODO(rays) collapse with call_matcher and move all to wordrec.cpp.
  BLOB_CHOICE_LIST *choices = call_matcher(blob);
  // If a blob with the same bounding box as one of the truth character
  // bounding boxes is not classified as the corresponding truth character
  // blame character classifier for incorrect answer.
  if (blamer_bundle != nullptr) {
    blamer_bundle->BlameClassifier(getDict().getUnicharset(), blob->bounding_box(), *choices,
                                   wordrec_debug_blamer);
  }
#ifndef GRAPHICS_DISABLED
  if (classify_debug_level && string) {
    print_ratings_list(string, choices, getDict().getUnicharset());
  }

  if (wordrec_blob_pause) {
    blob_window->Wait();
  }
#endif

  return choices;
}

} // namespace tesseract
<|endoftext|>