<commit_before>/*=========================================================================

  Program:   ORFEO Toolbox
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
  See OTBCopyright.txt for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#if defined(_MSC_VER)
#pragma warning ( disable : 4786 )
#endif

#ifdef __BORLANDC__
#define ITK_LEAN_AND_MEAN
#endif

//  Software Guide : BeginCommandLineArgs
//    INPUTS: {ROI_QB_MUL_1.png}
//    OUTPUTS: {MSFilteredOutput.tif}, {MSClusteredOutput.tif}, {MSLabelledOutput.tif}, {MSBoundariesOutput.tif}, {MSFilteredOutput-pretty.png}, {MSClusteredOutput-pretty.png}
//  7 30 20 1.0
//  Software Guide : EndCommandLineArgs

//  Software Guide : BeginLatex
//
//  This example demonstrates the use of the
//  \doxygen{otb}{MeanShiftVectorImageFilter} class which implements
//  filtering and clustering using the mean shift algorithm
//  \cite{Comaniciu2002}. For a given pixel, the mean shift will
//  build a set of neighboring pixels within a given spatial radius
//  and a color range. The spatial and color center of this set is
//  then computed and the algorithm iterates with this new spatial and
//  color center. The Mean Shift can be used for edge-preserving
//  smoothing, or for clustering.
//
//  Software Guide : EndLatex

#include "itkExceptionObject.h"
#include "otbVectorImage.h"
#include "otbImageFileReader.h"
#include "otbStreamingImageFileWriter.h"
#include "otbPrintableImageFilter.h"

//  Software Guide : BeginLatex
//
//  Two implementations for the filter exist, one for scalar images
//  (\doxygen{otb}{MeanShiftImageFilter}). And another one (the one
//  presented in this example) for vector images
//  (\doxygen{otb}{MeanShiftVectorImageFilter}). They have the same
//  interface, so they can be used in the same way. We start by
//  including the needed header file.
//
//  Software Guide : EndLatex

// Software Guide : BeginCodeSnippet
#include "otbMeanShiftVectorImageFilter.h"
// Software Guide : EndCodeSnippet
int main(int argc, char * argv[])
{
   if(argc != 12)
    {
      std::cerr<<"Usage: "<<argv[0]<<" infname filteredfname clusteredfname labeledclusteredfname clusterboundariesfname filteredPretty clusteredPretty spatialRadius rangeRadius minregionsize scale"<<std::endl;
      return EXIT_FAILURE;
    }

  const char *       infname                = argv[1];
  const char *       filteredfname          = argv[2];
  const char *       clusteredfname         = argv[3];
  const char *       labeledclusteredfname  = argv[4];
  const char *       clusterboundariesfname = argv[5];
  const char *       filteredPretty         = argv[6];
  const char *       clusteredPretty        = argv[7];
  const unsigned int spatialRadius          = atoi(argv[8]);
  const double       rangeRadius            = atof(argv[9]);
  const unsigned int minRegionSize          = atoi(argv[10]);
  const double       scale                  = atoi(argv[11]);

  //  Software Guide : BeginLatex
//
//  We start by the classical \code{typedef}s needed for reading and
//  writing the images. The EDISON code upon which OTB's
//  implementation is based, uses float pixel precision, so we choose
//  to work with a float pixel type.
//
//  Software Guide : EndLatex

// Software Guide : BeginCodeSnippet
  const unsigned int Dimension = 2;
  typedef float PixelType;
  typedef otb::VectorImage<PixelType,Dimension> ImageType;
  typedef otb::ImageFileReader<ImageType> ReaderType;
  typedef otb::StreamingImageFileWriter<ImageType> WriterType;
// Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
//
//  We can now define the type for the filter, and also the type for
//  the labeled output image, which is needed for the corresponding writer:
//
//  Software Guide : EndLatex

// Software Guide : BeginCodeSnippet
  typedef otb::MeanShiftVectorImageFilter<ImageType,ImageType> FilterType;
  typedef FilterType::LabeledOutputType LabeledImageType;
  typedef otb::StreamingImageFileWriter<LabeledImageType> LabeledWriterType;

  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
//
//  We instantiate the filter, the reader, and 4 writers (2 for the
//  filetered and clustered images and 2 more for the labeled and
//  boundaries images):
//
//  Software Guide : EndLatex

// Software Guide : BeginCodeSnippet
  FilterType::Pointer filter = FilterType::New();
  ReaderType::Pointer reader = ReaderType::New();
  WriterType::Pointer writer1 = WriterType::New();
  WriterType::Pointer writer2 = WriterType::New();
  LabeledWriterType::Pointer writer3 = LabeledWriterType::New();
  LabeledWriterType::Pointer writer4 = LabeledWriterType::New();

  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
//
//  We set the file names for the reader and the writers:
//
//  Software Guide : EndLatex

// Software Guide : BeginCodeSnippet
  reader->SetFileName(infname);
  writer1->SetFileName(filteredfname);
  writer2->SetFileName(clusteredfname);
  writer3->SetFileName(labeledclusteredfname);
  writer4->SetFileName(clusterboundariesfname);

  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
//
//  We can now set the parameters for the filter. There are 3 main
//  parameters: the spatial radius used for defining the neighborhood,
//  the range radius used for defining the interval in the color space
//  and the minimum size for the regions to be kept after clustering.
//
//  Software Guide : EndLatex

// Software Guide : BeginCodeSnippet
  filter->SetSpatialRadius(spatialRadius);
  filter->SetRangeRadius(rangeRadius);
  filter->SetMinimumRegionSize(minRegionSize);
  // Software Guide : EndCodeSnippet
  //  Software Guide : BeginLatex
//
//  OTB's implementation adds another parameter -- the scale -- which
//  allows to stretch the image before processing. This is useful when
//  pixel values are in the $[0-1]$ range.
//
//  Software Guide : EndLatex

// Software Guide : BeginCodeSnippet
  filter->SetScale(scale);
    // Software Guide : EndCodeSnippet
  //  Software Guide : BeginLatex
//
//  We can now plug the pipeline and run it.
//
//  Software Guide : EndLatex

// Software Guide : BeginCodeSnippet

  filter->SetInput(reader->GetOutput());
  writer1->SetInput(filter->GetOutput());
  writer2->SetInput(filter->GetClusteredOutput());
  writer3->SetInput(filter->GetLabeledClusteredOutput());
  writer4->SetInput(filter->GetClusterBoundariesOutput());

  writer1->Update();
  writer2->Update();
  writer3->Update();
  writer4->Update();
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  // Figure~\ref{fig:MeanShiftVectorImageFilter} shows the result of applying the mean shift
  // to a Quickbird image.
  // \begin{figure}
  // \center
  // \includegraphics[width=0.40\textwidth]{ROI_QB_MUL_1.eps}
  // \includegraphics[width=0.40\textwidth]{MSFilteredOutput-pretty.eps}
  // \includegraphics[width=0.40\textwidth]{MSClusteredOutput-pretty.eps}
  // \itkcaption[Mean Shift]{From top to bottom and left to right: Original image, image filtered by
  // mean shift and mean shift clustering.}
  // \label{fig:MeanShiftVectorImageFilter}
  // \end{figure}
  // Software Guide : EndLatex

  typedef otb::PrintableImageFilter< ImageType >   PrintableFilterType;
  PrintableFilterType::Pointer printableImageFilter = PrintableFilterType::New();

  printableImageFilter->SetChannel(1);
  printableImageFilter->SetChannel(2);
  printableImageFilter->SetChannel(3);

  typedef PrintableFilterType::OutputImageType OutputImageType;
  typedef otb::StreamingImageFileWriter< OutputImageType >
                                              PrettyWriterType;
  PrettyWriterType::Pointer prettyWriter = PrettyWriterType::New();

  printableImageFilter->SetInput( filter->GetOutput() );
  prettyWriter->SetFileName( filteredPretty );
  prettyWriter->SetInput( printableImageFilter->GetOutput() );
  prettyWriter->Update();

  printableImageFilter->SetInput( filter->GetClusteredOutput() );
  prettyWriter->SetFileName( clusteredPretty );
  prettyWriter->SetInput( printableImageFilter->GetOutput() );
  prettyWriter->Update();

  return EXIT_SUCCESS;
}

<commit_msg>DOC: typo corrected<commit_after>/*=========================================================================

  Program:   ORFEO Toolbox
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
  See OTBCopyright.txt for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#if defined(_MSC_VER)
#pragma warning ( disable : 4786 )
#endif

#ifdef __BORLANDC__
#define ITK_LEAN_AND_MEAN
#endif

//  Software Guide : BeginCommandLineArgs
//    INPUTS: {ROI_QB_MUL_1.png}
//    OUTPUTS: {MSFilteredOutput.tif}, {MSClusteredOutput.tif}, {MSLabeledOutput.tif}, {MSBoundariesOutput.tif}, {MSFilteredOutput-pretty.png}, {MSClusteredOutput-pretty.png}
//  7 30 20 1.0
//  Software Guide : EndCommandLineArgs

//  Software Guide : BeginLatex
//
//  This example demonstrates the use of the
//  \doxygen{otb}{MeanShiftVectorImageFilter} class which implements
//  filtering and clustering using the mean shift algorithm
//  \cite{Comaniciu2002}. For a given pixel, the mean shift will
//  build a set of neighboring pixels within a given spatial radius
//  and a color range. The spatial and color center of this set is
//  then computed and the algorithm iterates with this new spatial and
//  color center. The Mean Shift can be used for edge-preserving
//  smoothing, or for clustering.
//
//  Software Guide : EndLatex

#include "itkExceptionObject.h"
#include "otbVectorImage.h"
#include "otbImageFileReader.h"
#include "otbStreamingImageFileWriter.h"
#include "otbPrintableImageFilter.h"

//  Software Guide : BeginLatex
//
//  Two implementations for the filter exist, one for scalar images
//  (\doxygen{otb}{MeanShiftImageFilter}). And another one (the one
//  presented in this example) for vector images
//  (\doxygen{otb}{MeanShiftVectorImageFilter}). They have the same
//  interface, so they can be used in the same way. We start by
//  including the needed header file.
//
//  Software Guide : EndLatex

// Software Guide : BeginCodeSnippet
#include "otbMeanShiftVectorImageFilter.h"
// Software Guide : EndCodeSnippet
int main(int argc, char * argv[])
{
   if(argc != 12)
    {
      std::cerr<<"Usage: "<<argv[0]<<" infname filteredfname clusteredfname labeledclusteredfname clusterboundariesfname filteredPretty clusteredPretty spatialRadius rangeRadius minregionsize scale"<<std::endl;
      return EXIT_FAILURE;
    }

  const char *       infname                = argv[1];
  const char *       filteredfname          = argv[2];
  const char *       clusteredfname         = argv[3];
  const char *       labeledclusteredfname  = argv[4];
  const char *       clusterboundariesfname = argv[5];
  const char *       filteredPretty         = argv[6];
  const char *       clusteredPretty        = argv[7];
  const unsigned int spatialRadius          = atoi(argv[8]);
  const double       rangeRadius            = atof(argv[9]);
  const unsigned int minRegionSize          = atoi(argv[10]);
  const double       scale                  = atoi(argv[11]);

  //  Software Guide : BeginLatex
//
//  We start by the classical \code{typedef}s needed for reading and
//  writing the images. The EDISON code upon which OTB's
//  implementation is based, uses float pixel precision, so we choose
//  to work with a float pixel type.
//
//  Software Guide : EndLatex

// Software Guide : BeginCodeSnippet
  const unsigned int Dimension = 2;
  typedef float PixelType;
  typedef otb::VectorImage<PixelType,Dimension> ImageType;
  typedef otb::ImageFileReader<ImageType> ReaderType;
  typedef otb::StreamingImageFileWriter<ImageType> WriterType;
// Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
//
//  We can now define the type for the filter, and also the type for
//  the labeled output image, which is needed for the corresponding writer:
//
//  Software Guide : EndLatex

// Software Guide : BeginCodeSnippet
  typedef otb::MeanShiftVectorImageFilter<ImageType,ImageType> FilterType;
  typedef FilterType::LabeledOutputType LabeledImageType;
  typedef otb::StreamingImageFileWriter<LabeledImageType> LabeledWriterType;

  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
//
//  We instantiate the filter, the reader, and 4 writers (2 for the
//  filetered and clustered images and 2 more for the labeled and
//  boundaries images):
//
//  Software Guide : EndLatex

// Software Guide : BeginCodeSnippet
  FilterType::Pointer filter = FilterType::New();
  ReaderType::Pointer reader = ReaderType::New();
  WriterType::Pointer writer1 = WriterType::New();
  WriterType::Pointer writer2 = WriterType::New();
  LabeledWriterType::Pointer writer3 = LabeledWriterType::New();
  LabeledWriterType::Pointer writer4 = LabeledWriterType::New();

  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
//
//  We set the file names for the reader and the writers:
//
//  Software Guide : EndLatex

// Software Guide : BeginCodeSnippet
  reader->SetFileName(infname);
  writer1->SetFileName(filteredfname);
  writer2->SetFileName(clusteredfname);
  writer3->SetFileName(labeledclusteredfname);
  writer4->SetFileName(clusterboundariesfname);

  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
//
//  We can now set the parameters for the filter. There are 3 main
//  parameters: the spatial radius used for defining the neighborhood,
//  the range radius used for defining the interval in the color space
//  and the minimum size for the regions to be kept after clustering.
//
//  Software Guide : EndLatex

// Software Guide : BeginCodeSnippet
  filter->SetSpatialRadius(spatialRadius);
  filter->SetRangeRadius(rangeRadius);
  filter->SetMinimumRegionSize(minRegionSize);
  // Software Guide : EndCodeSnippet
  //  Software Guide : BeginLatex
//
//  OTB's implementation adds another parameter -- the scale -- which
//  allows to stretch the image before processing. This is useful when
//  pixel values are in the $[0-1]$ range.
//
//  Software Guide : EndLatex

// Software Guide : BeginCodeSnippet
  filter->SetScale(scale);
    // Software Guide : EndCodeSnippet
  //  Software Guide : BeginLatex
//
//  We can now plug the pipeline and run it.
//
//  Software Guide : EndLatex

// Software Guide : BeginCodeSnippet

  filter->SetInput(reader->GetOutput());
  writer1->SetInput(filter->GetOutput());
  writer2->SetInput(filter->GetClusteredOutput());
  writer3->SetInput(filter->GetLabeledClusteredOutput());
  writer4->SetInput(filter->GetClusterBoundariesOutput());

  writer1->Update();
  writer2->Update();
  writer3->Update();
  writer4->Update();
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  // Figure~\ref{fig:MeanShiftVectorImageFilter} shows the result of applying the mean shift
  // to a Quickbird image.
  // \begin{figure}
  // \center
  // \includegraphics[width=0.40\textwidth]{ROI_QB_MUL_1.eps}
  // \includegraphics[width=0.40\textwidth]{MSFilteredOutput-pretty.eps}
  // \includegraphics[width=0.40\textwidth]{MSClusteredOutput-pretty.eps}
  // \itkcaption[Mean Shift]{From top to bottom and left to right: Original image, image filtered by
  // mean shift and mean shift clustering.}
  // \label{fig:MeanShiftVectorImageFilter}
  // \end{figure}
  // Software Guide : EndLatex

  typedef otb::PrintableImageFilter< ImageType >   PrintableFilterType;
  PrintableFilterType::Pointer printableImageFilter = PrintableFilterType::New();

  printableImageFilter->SetChannel(1);
  printableImageFilter->SetChannel(2);
  printableImageFilter->SetChannel(3);

  typedef PrintableFilterType::OutputImageType OutputImageType;
  typedef otb::StreamingImageFileWriter< OutputImageType >
                                              PrettyWriterType;
  PrettyWriterType::Pointer prettyWriter = PrettyWriterType::New();

  printableImageFilter->SetInput( filter->GetOutput() );
  prettyWriter->SetFileName( filteredPretty );
  prettyWriter->SetInput( printableImageFilter->GetOutput() );
  prettyWriter->Update();

  printableImageFilter->SetInput( filter->GetClusteredOutput() );
  prettyWriter->SetFileName( clusteredPretty );
  prettyWriter->SetInput( printableImageFilter->GetOutput() );
  prettyWriter->Update();

  return EXIT_SUCCESS;
}

<|endoftext|>


<commit_before>// Copyright (c) 2018 Chris Ohk, Youngjoong Kim, SeungHyun Jeon

// We are making my contributions/submissions to this project solely in our
// personal capacity and are not conveying any rights to any intellectual
// property of any third parties.

#ifndef ROSETTASTONE_TORCH_GAME_TO_VEC_HPP
#define ROSETTASTONE_TORCH_GAME_TO_VEC_HPP

#include <Rosetta/Games/Game.hpp>

#include <torch/torch.h>

namespace RosettaTorch
{
using namespace RosettaStone;

//!
//! \brief ActionEncoder struct.
//!
//! This struct generates torch tensor from Game context.
//!
class GameToVec
{
 public:
    //! Constructs the embedding tables.
    GameToVec();

    //! Constructs the embedding tables with given \p seed
    // \param seed The seed used when the embedding table is generated.
    explicit GameToVec(std::size_t seed);

    //! Default virtual destructor.
    virtual ~GameToVec() = default;

    //! Generates torch tensor from the effects
    //! \param effects The card effects.
    //! \return The encoded torch tensor from \p effects.
    virtual torch::Tensor EffectsToTensor(std::vector<Effect> effects);

    //! Generates torch tensor from the tasks
    //! \param tasks The card tasks
    //! \return The encoded torch tensor from \p tasks.
    virtual torch::Tensor TasksToTensor(std::vector<ITask*> tasks);

    //! Generates torch tensor from the entity
    //! \param entity The card context.
    //! \return The encoded torch tensor from \p entity.
    virtual torch::Tensor CardToTensor(Entity* entity);

    //! Generates torch tensor from game context.
    //! \param game The game context.
    //! \return The encoded torch tensor from \p game.
    virtual torch::Tensor GenerateTensor(const Game& game);

    //! Gets Effect Embedding Table.
    //! \return The embedding table torch tensor.
    torch::nn::Embedding GetEffectEmbeddingTable();

    //! Gets Entity Type Embedding Table.
    //! \return The embedding table torch tensor.
    torch::nn::Embedding GetEntityTypeEmbeddingTable();

    //! Gets Task Id Embedding Table.
    //! \return The embedding table torch tensor.
    torch::nn::Embedding GetTaskIdEmbeddingTable();

    /////////////////////////////////////////////
    static constexpr size_t CLIP_CARD_NORM = 64;
    static constexpr size_t CLIP_EFFECT_NORM = 8;

    /////////////////////////////////////////////
    std::vector<GameTag> EffectGameTag = {
        GameTag::INVALID,  GameTag::ATK,       GameTag::HEALTH,
        GameTag::TAUNT,    GameTag::POISONOUS, GameTag::DIVINE_SHIELD,
        GameTag::WINDFURY, GameTag::STEALTH
    };
    std::vector<EffectOperator> EffectOperatorTag = { EffectOperator::ADD,
                                                      EffectOperator::MUL,
                                                      EffectOperator::SET,
                                                      EffectOperator::SUB };
    static constexpr std::size_t EffectVectorSize = 4;
    static constexpr std::size_t EffectGameTagSize = 8;
    static constexpr std::size_t EffectOperationTagSize = 4;
    static constexpr std::size_t EffectIndexSize =
        EffectGameTagSize * EffectOperationTagSize;

    static constexpr std::size_t AuraVectorSize = 5;

    static constexpr std::size_t EnchantVectorSize = 4;

    static constexpr std::size_t EntityTypeVectorSize = 4;
    static constexpr std::size_t EntityTypeIndexSize = 16;
    static constexpr std::size_t TaskIdVectorSize = 4;
    static constexpr std::size_t TaskIdIndexSize = 27;
    static constexpr std::size_t TaskVectorSize =
        EntityTypeVectorSize + TaskIdVectorSize;

    /////////////////////////////////////////////
    static constexpr std::size_t CardMetaSize = 3;
    static constexpr std::size_t AbilityVectorSize =
        AuraVectorSize + EnchantVectorSize + TaskVectorSize + TaskVectorSize;
    static constexpr std::size_t CardVectorSize =
        CardMetaSize + AbilityVectorSize;

    /////////////////////////////////////////////
    static constexpr std::size_t PlayerMetaSize = 3;
    static constexpr std::size_t GameVectorSize =
        PlayerMetaSize + (CardVectorSize * (HAND_SIZE + 2 * FIELD_SIZE));

 private:
    std::size_t m_seed;

    //! embedding table for the card
    torch::nn::Embedding m_effectEmbeddingTable = nullptr;
    torch::nn::Embedding m_entityTypeEmbeddingTable = nullptr;
    torch::nn::Embedding m_taskIDEmbeddingTable = nullptr;
};
}  // namespace RosettaTorch

#endif<commit_msg>fix: Add punctuations<commit_after>// Copyright (c) 2018 Chris Ohk, Youngjoong Kim, SeungHyun Jeon

// We are making my contributions/submissions to this project solely in our
// personal capacity and are not conveying any rights to any intellectual
// property of any third parties.

#ifndef ROSETTASTONE_TORCH_GAME_TO_VEC_HPP
#define ROSETTASTONE_TORCH_GAME_TO_VEC_HPP

#include <Rosetta/Games/Game.hpp>

#include <torch/torch.h>

namespace RosettaTorch
{
using namespace RosettaStone;

//!
//! \brief ActionEncoder struct.
//!
//! This struct generates torch tensor from Game context.
//!
class GameToVec
{
 public:
    //! Constructs the embedding tables.
    GameToVec();

    //! Constructs the embedding tables with given \p seed.
    //! \param seed The seed used when the embedding table is generated.
    explicit GameToVec(std::size_t seed);

    //! Default virtual destructor.
    virtual ~GameToVec() = default;

    //! Generates torch tensor from the effects.
    //! \param effects The card effects.
    //! \return The encoded torch tensor from \p effects.
    virtual torch::Tensor EffectsToTensor(std::vector<Effect> effects);

    //! Generates torch tensor from the tasks.
    //! \param tasks The card tasks.
    //! \return The encoded torch tensor from \p tasks.
    virtual torch::Tensor TasksToTensor(std::vector<ITask*> tasks);

    //! Generates torch tensor from the entity.
    //! \param entity The card context.
    //! \return The encoded torch tensor from \p entity.
    virtual torch::Tensor CardToTensor(Entity* entity);

    //! Generates torch tensor from game context.
    //! \param game The game context.
    //! \return The encoded torch tensor from \p game.
    virtual torch::Tensor GenerateTensor(const Game& game);

    //! Gets Effect Embedding Table.
    //! \return The embedding table torch tensor.
    torch::nn::Embedding GetEffectEmbeddingTable();

    //! Gets Entity Type Embedding Table.
    //! \return The embedding table torch tensor.
    torch::nn::Embedding GetEntityTypeEmbeddingTable();

    //! Gets Task Id Embedding Table.
    //! \return The embedding table torch tensor.
    torch::nn::Embedding GetTaskIdEmbeddingTable();

    /////////////////////////////////////////////
    static constexpr size_t CLIP_CARD_NORM = 64;
    static constexpr size_t CLIP_EFFECT_NORM = 8;

    /////////////////////////////////////////////
    std::vector<GameTag> EffectGameTag = {
        GameTag::INVALID,  GameTag::ATK,       GameTag::HEALTH,
        GameTag::TAUNT,    GameTag::POISONOUS, GameTag::DIVINE_SHIELD,
        GameTag::WINDFURY, GameTag::STEALTH
    };
    std::vector<EffectOperator> EffectOperatorTag = { EffectOperator::ADD,
                                                      EffectOperator::MUL,
                                                      EffectOperator::SET,
                                                      EffectOperator::SUB };
    static constexpr std::size_t EffectVectorSize = 4;
    static constexpr std::size_t EffectGameTagSize = 8;
    static constexpr std::size_t EffectOperationTagSize = 4;
    static constexpr std::size_t EffectIndexSize =
        EffectGameTagSize * EffectOperationTagSize;

    static constexpr std::size_t AuraVectorSize = 5;

    static constexpr std::size_t EnchantVectorSize = 4;

    static constexpr std::size_t EntityTypeVectorSize = 4;
    static constexpr std::size_t EntityTypeIndexSize = 16;
    static constexpr std::size_t TaskIdVectorSize = 4;
    static constexpr std::size_t TaskIdIndexSize = 27;
    static constexpr std::size_t TaskVectorSize =
        EntityTypeVectorSize + TaskIdVectorSize;

    /////////////////////////////////////////////
    static constexpr std::size_t CardMetaSize = 3;
    static constexpr std::size_t AbilityVectorSize =
        AuraVectorSize + EnchantVectorSize + TaskVectorSize + TaskVectorSize;
    static constexpr std::size_t CardVectorSize =
        CardMetaSize + AbilityVectorSize;

    /////////////////////////////////////////////
    static constexpr std::size_t PlayerMetaSize = 3;
    static constexpr std::size_t GameVectorSize =
        PlayerMetaSize + (CardVectorSize * (HAND_SIZE + 2 * FIELD_SIZE));

 private:
    std::size_t m_seed;

    //! embedding table for the card
    torch::nn::Embedding m_effectEmbeddingTable = nullptr;
    torch::nn::Embedding m_entityTypeEmbeddingTable = nullptr;
    torch::nn::Embedding m_taskIDEmbeddingTable = nullptr;
};
}  // namespace RosettaTorch

#endif<|endoftext|>


<commit_before>#include "cmm_socket.h"

struct csocket {
    int osfd;
    u_long cur_label;
    int connected;
};

csocket::csocket(int family, int type, int protocol)
{
    osfd = socket(family, type, protocol);
    if (osfd < 0) {
	/* out of file descriptors or memory at this point */
	throw osfd;
    }
    cur_label = 0;
    connected = 0;
}

csocket::~csocket()
{
    if (osfd > 0) {
	/* if it's a real open socket */
	close(osfd);
    }
}

CMMSocket::CMMSocket(int family, int type, int protocol)
{
    /* reserve a dummy OS file descriptor for this mc_socket. */
    sock = socket(family, type, protocol);
    if (sock < 0) {
	/* invalid params, or no more FDs/memory left. */
	throw sock; /* :-) */
    }

    sock_family = family;
    sock_type = type;
    sock_protocol = protocol;
    addr = NULL;
    addrlen = 0;

    label_down_cb = NULL;
    label_up_cb = NULL;
    cb_arg = NULL;

    /* TODO: read these from /proc instead of hard-coding them. */
    struct csocket *bg_sock = new struct csocket(family, type, protocol);
    struct csocket *ondemand_sock = new struct csocket(family, type, protocol);

    sock_color_hash[CONNMGR_LABEL_BACKGROUND] = bg_sock;
    sock_color_hash[CONNMGR_LABEL_ONDEMAND] = ondemand_sock;
    csocks.push_back(bg_sock);
    csocks.push_back(ondemand_sock);

    /* to illustrate how multiple labels can map to the same interface */
    sock_color_hash[CONNMGR_LABEL_RED] = bg_sock;
    sock_color_hash[CONNMGR_LABEL_BLUE] = ondemand_sock;

    non_blocking=0;
}

CMMSocket::~CMMSocket()
{
    for (CSockList::iterator it = csocks.begin();
	 it != csocks.end(); it++) {
	struct csocket *victim = *it;
	delete victim;
    }

    free(addr);
    close(sock);
}

CMMSocketSerial::CMMSocketSerial()
{
    active_csock = NULL;
}
<commit_msg>Small changes; just syncing, really.<commit_after>#include "cmm_socket.h"

struct csocket {
    int osfd;
    u_long cur_label;
    int connected;
};

csocket::csocket(int family, int type, int protocol)
{
    osfd = socket(family, type, protocol);
    if (osfd < 0) {
	/* out of file descriptors or memory at this point */
	throw osfd;
    }
    cur_label = 0;
    connected = 0;
}

csocket::~csocket()
{
    if (osfd > 0) {
	/* if it's a real open socket */
	close(osfd);
    }
}

CMMSocket::CMMSocket(int family, int type, int protocol)
{
    /* reserve a dummy OS file descriptor for this mc_socket. */
    sock = socket(family, type, protocol);
    if (sock < 0) {
	/* invalid params, or no more FDs/memory left. */
	throw sock; /* :-) */
    }

    sock_family = family;
    sock_type = type;
    sock_protocol = protocol;
    addr = NULL;
    addrlen = 0;

    label_down_cb = NULL;
    label_up_cb = NULL;
    cb_arg = NULL;

    /* TODO: read these from /proc instead of hard-coding them. */
    struct csocket *bg_sock = new struct csocket(family, type, protocol);
    struct csocket *ondemand_sock = new struct csocket(family, type, protocol);

    sock_color_hash[CONNMGR_LABEL_BACKGROUND] = bg_sock;
    sock_color_hash[CONNMGR_LABEL_ONDEMAND] = ondemand_sock;
    csocks.push_back(bg_sock);
    csocks.push_back(ondemand_sock);

    /* to illustrate how multiple labels can map to the same interface */
    sock_color_hash[CONNMGR_LABEL_RED] = bg_sock;
    sock_color_hash[CONNMGR_LABEL_BLUE] = ondemand_sock;

    non_blocking=0;
}

CMMSocket::~CMMSocket()
{
    for (CSockList::iterator it = csocks.begin();
	 it != csocks.end(); it++) {
	struct csocket *victim = *it;
	delete victim;
    }

    free(addr);
    close(sock);
}

CMMSocketSerial::CMMSocketSerial()
{
    active_csock = NULL;
}

// XXX: in progress.
void
CMMSocketSerial::prepare(u_long label)
{
    CMMSockHash::const_accessor read_ac;
    CMMSockHash::accessor write_ac;

    struct cmm_sock *sk = NULL;
    if (!cmm_sock_hash.find(read_ac, sock)) {
	assert(0); /* already checked in caller */
    }

    sk = read_ac->second;
    assert(sk);

    struct csocket *csock = NULL;
    if (up_label) {
	csock = sk->sock_color_hash[up_label];
	if (!csock) {
	    /* caller specified an invalid label */
	    errno = EINVAL;
	    return CMM_FAILED;
	}
    } else {
	if (sk->active_csock) {
	    csock = sk->active_csock;
	    up_label = sk->active_csock->cur_label;
	} else {
	    /* no active csock, no label specified;
	     * just grab the first socket that exists and whose network
	     * is available */
	    for (CSockHash::iterator iter = sk->sock_color_hash.begin();
		 iter != sk->sock_color_hash.end(); iter++) {
		u_long label = iter->first;
		struct csocket *candidate = iter->second;
		if (candidate && scout_net_available(label)) {
		    csock = candidate;
		    up_label = label;
		}
	    }
	}
    }
    if (!csock) {
	errno = ENOTCONN;
	return CMM_FAILED;
    }

    if (!csock->connected) {
#ifdef CMM_TIMING
	struct timeval switch_start;
	struct timeval switch_end;
	struct timeval connect_start;
	struct timeval connect_end;
	struct timeval up_cb_start;
	struct timeval up_cb_end;
	struct timeval diff;

	timerclear(&connect_start);
	timerclear(&connect_end);
	timerclear(&up_cb_start);
	timerclear(&up_cb_end);

	TIME(switch_start);
#endif
	u_long down_label = 0;
	assert(csock->cur_label == 0); /* only for multiplexing */

	    if (sk->active_csock) {
		down_label = sk->active_csock->cur_label;
		read_ac.release();
		if (sk->label_down_cb) {
		    /* XXX: check return value? */
		    sk->label_down_cb(sock, sk->active_csock->cur_label,
				      sk->cb_arg);
		}

		if (!cmm_sock_hash.find(write_ac, sock)) {
		    assert(0);
		}
		assert(write_ac->second == sk);

		close(sk->active_csock->osfd);
		sk->active_csock->osfd = socket(sk->sock_family,
						sk->sock_type,
						sk->sock_protocol);
		sk->active_csock->cur_label = 0;
		sk->active_csock->connected = 0;
		sk->active_csock = NULL;

	    } else {
		read_ac.release();
		if (!cmm_sock_hash.find(write_ac, sock)) {
		    assert(0);
		}
		assert(write_ac->second == sk);
		assert(csock == sk->sock_color_hash[up_label]);
	    }

	set_all_sockopts(sk, csock->osfd);

	/* connect new socket with current label */
	set_socket_labels(csock->osfd, up_label);
	fprintf(stderr, "About to connect socket, label=%lu\n", up_label);

        write_ac.release();
        if (!cmm_sock_hash.find(read_ac, sock)) {
            assert(0);
        }
        assert(read_ac->second == sk);
        assert(csock == sk->sock_color_hash[up_label]);

#ifdef CMM_TIMING
	TIME(connect_start);
#endif
	int rc = connect(csock->osfd, sk->addr, sk->addrlen);
#ifdef CMM_TIMING
	TIME(connect_end);
#endif
        read_ac.release();
        if (!cmm_sock_hash.find(write_ac, sock)) {
          assert(0);
        }
        assert(write_ac->second == sk);
        assert(csock == sk->sock_color_hash[up_label]);

	if (rc < 0) {
	    if(errno==EINPROGRESS || errno==EWOULDBLOCK)
		//is this what we want for the 'send',
		//i.e wait until the sock is conn'ed.
		errno = EAGAIN;
	    else {
		perror("connect");
		close(csock->osfd);
		fprintf(stderr, "libcmm: error connecting new socket\n");
		/* we've previously checked, and the label should be
		 * available... so this failure is something else. */
		/* XXX: maybe check scout_label_available(up_label) again?
		 *      if it is not, return CMM_DEFERRED? */
		/* XXX: this may be a race; i'm not sure. */
#ifdef CMM_TIMING
		TIMEDIFF(connect_start, connect_end, diff);
		fprintf(timing_file, "connect() failed after %ld.%06ld seconds\n",
			diff.tv_sec, diff.tv_usec);
#endif
		return CMM_FAILED;
	    }
	}

	csock->cur_label = up_label;
	csock->connected = 1;
#ifdef IMPORT_RULES
	sk->connecting = 1;
#endif
	sk->active_csock = csock;
	write_ac.release();

	if (sk->label_up_cb) {
#ifdef CMM_TIMING
	    TIME(up_cb_start);
#endif
	    int rc = sk->label_up_cb(sk->sock, up_label, sk->cb_arg);
#ifdef CMM_TIMING
	    TIME(up_cb_end);
#endif
#ifdef IMPORT_RULES
	    if (cmm_sock_hash.find(write_ac, sock)) {
		assert(write_ac->second == sk);
		sk->connecting = 0;
		write_ac.release();
	    }
#endif

	    if (rc < 0) {
#ifdef CMM_TIMING
		TIMEDIFF(up_cb_start, up_cb_end, diff);
		fprintf(timing_file,
			"error: application-level up_cb failed"
			"after %ld.%06ld\n",
			diff.tv_sec, diff.tv_usec);
#endif
		fprintf(stderr, "error: application-level up_cb failed\n");

		if (rc == CMM_DEFERRED) {
		    return rc;
		} else {
		    CMMSockHash::accessor write_ac;
		    if (cmm_sock_hash.find(write_ac, sock)) {
			assert(write_ac->second == sk);
			assert(csock == sk->sock_color_hash[up_label]);

			close(csock->osfd);
			csock->osfd = socket(sk->sock_family,
					     sk->sock_type,
					     sk->sock_protocol);
			csock->cur_label = 0;
			csock->connected = 0;
			sk->active_csock = NULL;
		    } /* else: must have already been cmm_close()d */

		    return CMM_FAILED;
		}
	    }
	}
#ifdef CMM_TIMING
	TIME(switch_end);
	{
	    tbb::mutex::scoped_lock(timing_mutex);

	    if (timing_file) {
		TIMEDIFF(switch_start, switch_end, diff);
		struct timeval tmp = total_switch_time;
		timeradd(&tmp, &diff, &total_switch_time);
		if (down_label == CONNMGR_LABEL_BACKGROUND &&
		    up_label == CONNMGR_LABEL_ONDEMAND) {
		    num_switches_to_fg++;
		    tmp = total_switch_time_to_fg;
		    timeradd(&tmp, &diff, &total_switch_time_to_fg);
		} else if (down_label == CONNMGR_LABEL_ONDEMAND &&
			   up_label == CONNMGR_LABEL_BACKGROUND) {
		    num_switches_to_bg++;
		    tmp = total_switch_time_to_bg;
		    timeradd(&tmp, &diff, &total_switch_time_to_bg);
		}

		fprintf(timing_file, "Switch %d at %ld.%06ld: %ld.%06ld; from %s to %s; ",
			++num_switches,
			switch_start.tv_sec, switch_start.tv_usec,
			diff.tv_sec, diff.tv_usec,
			label_str(down_label), label_str(up_label));
		if (connect_start.tv_sec > 0) {
		    TIMEDIFF(connect_start, connect_end, diff);
		    fprintf(timing_file, "connect(): %ld.%06ld; ",
			    diff.tv_sec, diff.tv_usec);
		    struct timeval tmp = total_time_in_connect;
		    timeradd(&tmp, &diff, &total_time_in_connect);
		}
		if (up_cb_start.tv_sec > 0) {
		    TIMEDIFF(up_cb_start, up_cb_end, diff);
		    fprintf(timing_file, "up_cb(): %ld.%06ld",
			    diff.tv_sec, diff.tv_usec);
		    struct timeval tmp = total_time_in_up_cb;
		    timeradd(&tmp, &diff, &total_time_in_up_cb);
		}
		fprintf(timing_file, "\n");
	    }
	}
#endif
    }

    return 0;
}
<|endoftext|>


<commit_before>// Copyright (c) 2012, 2013 Pierre MOULON.

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#include "openMVG/matching_image_collection/Pair_Builder.hpp"
#include "testing/testing.h"

#include <iostream>
using namespace std;

using namespace openMVG;

// Check pairs follow a weak ordering pair.first < pair.second
bool checkPairOrder(const PairsT & pairs)
{
  for (PairsT::const_iterator iterP = pairs.begin(); iterP != pairs.end();
    ++iterP)
  {
    if (iterP->first >= iterP->second)
      return false;
  }
  return true;
}

TEST(matching_image_collection, exhaustivePairs)
{
  PairsT pairSet = exhaustivePairs(0);
  EXPECT_EQ( 0, pairSet.size());

  pairSet = exhaustivePairs(4);
  EXPECT_TRUE( checkPairOrder(pairSet) );
  EXPECT_EQ( 6, pairSet.size());
  EXPECT_TRUE( pairSet.find(std::make_pair(0,1)) != pairSet.end() );
  EXPECT_TRUE( pairSet.find(std::make_pair(0,2)) != pairSet.end() );
  EXPECT_TRUE( pairSet.find(std::make_pair(0,3)) != pairSet.end() );
  EXPECT_TRUE( pairSet.find(std::make_pair(1,2)) != pairSet.end() );
  EXPECT_TRUE( pairSet.find(std::make_pair(1,3)) != pairSet.end() );
  EXPECT_TRUE( pairSet.find(std::make_pair(2,3)) != pairSet.end() );
}

TEST(matching_image_collection, contiguousWithOverlap)
{
  PairsT pairSet = exhaustivePairs(0);
  EXPECT_EQ( 0, pairSet.size());

  pairSet = contiguousWithOverlap(4,1);
  EXPECT_TRUE( checkPairOrder(pairSet) );
  EXPECT_EQ( 3, pairSet.size());
  EXPECT_TRUE( pairSet.find(std::make_pair(0,1)) != pairSet.end() );
  EXPECT_TRUE( pairSet.find(std::make_pair(1,2)) != pairSet.end() );
  EXPECT_TRUE( pairSet.find(std::make_pair(2,3)) != pairSet.end() );
}

TEST(matching_image_collection, IO)
{
  PairsT pairSetGT;
  pairSetGT.insert( std::make_pair(0,2) );
  pairSetGT.insert( std::make_pair(2,4) );

  EXPECT_TRUE( savePairs("pairsT_IO.txt", pairSetGT));

  PairsT loaded_Pairs;
  EXPECT_TRUE( loadPairs("pairsT_IO.txt", loaded_Pairs));
  EXPECT_TRUE( loaded_Pairs == pairSetGT);
}

/* ************************************************************************* */
int main() { TestResult tr; return TestRegistry::runAllTests(tr);}
/* ************************************************************************* */
<commit_msg>fix test compilation. #4<commit_after>// Copyright (c) 2012, 2013 Pierre MOULON.

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#include "openMVG/matching_image_collection/Pair_Builder.hpp"
#include "testing/testing.h"

#include <iostream>
using namespace std;

using namespace openMVG;

// Check pairs follow a weak ordering pair.first < pair.second
bool checkPairOrder(const PairsT & pairs)
{
  for (PairsT::const_iterator iterP = pairs.begin(); iterP != pairs.end();
    ++iterP)
  {
    if (iterP->first >= iterP->second)
      return false;
  }
  return true;
}

TEST(matching_image_collection, exhaustivePairs)
{
  PairsT pairSet = exhaustivePairs(0);
  EXPECT_EQ( 0, pairSet.size());

  pairSet = exhaustivePairs(4);
  EXPECT_TRUE( checkPairOrder(pairSet) );
  EXPECT_EQ( 6, pairSet.size());
  EXPECT_TRUE( pairSet.find(std::make_pair(0,1)) != pairSet.end() );
  EXPECT_TRUE( pairSet.find(std::make_pair(0,2)) != pairSet.end() );
  EXPECT_TRUE( pairSet.find(std::make_pair(0,3)) != pairSet.end() );
  EXPECT_TRUE( pairSet.find(std::make_pair(1,2)) != pairSet.end() );
  EXPECT_TRUE( pairSet.find(std::make_pair(1,3)) != pairSet.end() );
  EXPECT_TRUE( pairSet.find(std::make_pair(2,3)) != pairSet.end() );
}

TEST(matching_image_collection, contiguousWithOverlap)
{
  PairsT pairSet = exhaustivePairs(0);
  EXPECT_EQ( 0, pairSet.size());

  pairSet = contiguousWithOverlap(4,1);
  EXPECT_TRUE( checkPairOrder(pairSet) );
  EXPECT_EQ( 3, pairSet.size());
  EXPECT_TRUE( pairSet.find(std::make_pair(0,1)) != pairSet.end() );
  EXPECT_TRUE( pairSet.find(std::make_pair(1,2)) != pairSet.end() );
  EXPECT_TRUE( pairSet.find(std::make_pair(2,3)) != pairSet.end() );
}

TEST(matching_image_collection, IO)
{
  PairsT pairSetGT;
  pairSetGT.insert( std::make_pair(0,2) );
  pairSetGT.insert( std::make_pair(2,4) );

  EXPECT_TRUE( savePairs("pairsT_IO.txt", pairSetGT));

  PairsT loaded_Pairs;
  EXPECT_TRUE( loadPairs(pairSetGT.size(), "pairsT_IO.txt", loaded_Pairs));
  EXPECT_TRUE( loaded_Pairs == pairSetGT);
}

/* ************************************************************************* */
int main() { TestResult tr; return TestRegistry::runAllTests(tr);}
/* ************************************************************************* */
<|endoftext|>


<commit_before>/*
    This file is part of KMail.

    Copyright (c) 2004 Cornelius Schumacher <schumacher@kde.org>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

    As a special exception, permission is given to link this program
    with any edition of Qt, and distribute the resulting executable,
    without including the source code for Qt in the source distribution.
*/

#include "recipientseditor.h"

#include "recipientspicker.h"
#include "kwindowpositioner.h"

#include <kdebug.h>
#include <kinputdialog.h>
#include <klocale.h>

#include <qlayout.h>
#include <qlabel.h>
#include <qscrollview.h>
#include <qcombobox.h>
#include <qhbox.h>
#include <qtimer.h>
#include <qpushbutton.h>

Recipient::Recipient( const QString &email, Recipient::Type type )
  : mEmail( email ), mType( type )
{
}

void Recipient::setType( Type type )
{
  mType = type;
}

Recipient::Type Recipient::type() const
{
  return mType;
}

void Recipient::setEmail( const QString &email )
{
  mEmail = email;
}

QString Recipient::email() const
{
  return mEmail;
}

bool Recipient::isEmpty() const
{
  return mEmail.isEmpty();
}

int Recipient::typeToId( Recipient::Type type )
{
  return static_cast<int>( type );
}

Recipient::Type Recipient::idToType( int id )
{
  return static_cast<Type>( id );
}

QString Recipient::typeLabel() const
{
  return typeLabel( mType );
}

QString Recipient::typeLabel( Recipient::Type type )
{
  switch( type ) {
    case To:
      return i18n("To");
    case Cc:
      return i18n("CC");
    case Bcc:
      return i18n("BCC");
    case ReplyTo:
      return i18n("Reply To");
  }

  return i18n("<Undefined RecipientType>");
}

QStringList Recipient::allTypeLabels()
{
  QStringList types;
  types.append( typeLabel( To ) );
  types.append( typeLabel( Cc ) );
  types.append( typeLabel( Bcc ) );
  types.append( typeLabel( ReplyTo ) );
  return types;
}

void RecipientLineEdit::keyPressEvent( QKeyEvent *ev )
{
  if ( ev->key() == Key_Backspace  &&  text().isEmpty() )
  {
      ev->accept();
      emit deleteMe();
  }
  else
    KMLineEdit::keyPressEvent( ev );

}

RecipientLine::RecipientLine( QWidget *parent )
  : QWidget( parent ), mIsEmpty( true )
{
  QBoxLayout *topLayout = new QHBoxLayout( this );

  QStringList recipientTypes = Recipient::allTypeLabels();

  mCombo = new QComboBox( this );
  mCombo->insertStringList( recipientTypes );
  topLayout->addWidget( mCombo );

  mEdit = new RecipientLineEdit( this );
  topLayout->addWidget( mEdit );
  connect( mEdit, SIGNAL( returnPressed() ), SLOT( slotReturnPressed() ) );
  connect( mEdit, SIGNAL( deleteMe() ), SLOT( slotPropagateDeletion() ) );
  connect( mEdit, SIGNAL( textChanged( const QString & ) ),
    SLOT( checkEmptyState( const QString & ) ) );
  connect( mEdit, SIGNAL( focusUp() ), SLOT( slotFocusUp() ) );
  connect( mEdit, SIGNAL( focusDown() ), SLOT( slotFocusDown() ) );

  kdDebug() << "HEIGHT: " << mEdit->minimumSizeHint().height() << endl;

  mCombo->setFixedHeight( mEdit->minimumSizeHint().height() );
}

void RecipientLine::slotFocusUp()
{
  emit upPressed( this );
}

void RecipientLine::slotFocusDown()
{
  emit downPressed( this );
}

void RecipientLine::checkEmptyState( const QString &text )
{
  if ( text.isEmpty() != mIsEmpty ) {
    mIsEmpty = text.isEmpty();
    emit emptyChanged();
  }
}

void RecipientLine::setRecipient( const Recipient &rec )
{
  mEdit->setText( rec.email() );
  mCombo->setCurrentItem( Recipient::typeToId( rec.type() ) );
}

void RecipientLine::setRecipient( const QString &email )
{
  setRecipient( Recipient( email ) );
}

Recipient RecipientLine::recipient() const
{
  return Recipient( mEdit->text(),
    Recipient::idToType( mCombo->currentItem() ) );
}

void RecipientLine::activate()
{
  mEdit->setFocus();
}

bool RecipientLine::isActive()
{
  return mEdit->hasFocus();
}

bool RecipientLine::isEmpty()
{
  return mEdit->text().isEmpty();
}

void RecipientLine::slotReturnPressed()
{
  emit returnPressed( this );
}

void RecipientLine::slotPropagateDeletion()
{
  emit deleteLine( this );
}

void RecipientLine::keyPressEvent( QKeyEvent *ev )
{
  if ( ev->key() == Key_Up ) {
    emit upPressed( this );
  } else if ( ev->key() == Key_Down ) {
    emit downPressed( this );
  }
}

RecipientsView::RecipientsView( QWidget *parent )
  : QScrollView( parent )
{
  setHScrollBarMode( AlwaysOff );
  setLineWidth( 0 );

  addLine();
}

RecipientLine *RecipientsView::activeLine()
{
  return mLines.last();
}

RecipientLine *RecipientsView::emptyLine()
{
  RecipientLine *line;
  for( line = mLines.first(); line; line = mLines.next() ) {
    if ( line->isEmpty() ) return line;
  }

  return 0;
}

RecipientLine *RecipientsView::addLine()
{
  kdDebug() << "RecipientsView::addLine()" << endl;

  RecipientLine *line = new RecipientLine( viewport() );
  addChild( line, 0, mLines.count() * mLineHeight );
  line->show();
  connect( line, SIGNAL( returnPressed( RecipientLine * ) ),
    SLOT( slotReturnPressed( RecipientLine * ) ) );
  connect( line, SIGNAL( upPressed( RecipientLine * ) ),
    SLOT( slotUpPressed( RecipientLine * ) ) );
  connect( line, SIGNAL( downPressed( RecipientLine * ) ),
    SLOT( slotDownPressed( RecipientLine * ) ) );
  connect( line, SIGNAL( deleteLine( RecipientLine * ) ),
    SLOT( slotDecideLineDeletion( RecipientLine * ) ) );
  connect( line, SIGNAL( emptyChanged() ), SLOT( calculateTotal() ) );

  mLines.append( line );

  mLineHeight = line->minimumSizeHint().height();

  line->resize( viewport()->width(), mLineHeight );

  resizeContents( viewport()->width(), mLines.count() * mLineHeight );

  if ( mLines.count() < 6 ) {
    setFixedHeight( mLineHeight * mLines.count() );
  }

  calculateTotal();

  ensureVisible( 0, mLines.count() * mLineHeight );

  return line;
}

void RecipientsView::calculateTotal()
{
  int count = 0;

  RecipientLine *line;
  for( line = mLines.first(); line; line = mLines.next() ) {
    if ( !line->isEmpty() ) ++count;
  }

  emit totalChanged( count, mLines.count() );
}

void RecipientsView::slotReturnPressed( RecipientLine *line )
{
  if ( !line->recipient().isEmpty() ) {
    RecipientLine *empty = emptyLine();
    if ( !empty ) empty = addLine();
    activateLine( empty );
  }
}

void RecipientsView::slotDownPressed( RecipientLine *line )
{
  int pos = mLines.find( line );
  if ( pos >= (int)mLines.count() - 1 ) {
    emit focusDown();
  } else if ( pos >= 0 ) {
    activateLine( mLines.at( pos + 1 ) );
  }
}

void RecipientsView::slotUpPressed( RecipientLine *line )
{
  int pos = mLines.find( line );
  if ( pos > 0 ) {
    activateLine( mLines.at( pos - 1 ) );
  } else {
    emit focusUp();
  }
}

void RecipientsView::slotDecideLineDeletion( RecipientLine *line )
{
  if ( mLines.first() != line ) {
    mCurDelLine = line;
    QTimer::singleShot( 0, this, SLOT( slotDeleteDueLine( ) ) );
  }
}

void RecipientsView::slotDeleteDueLine()
{
   RecipientLine *line = mCurDelLine;
   int pos = mLines.find( line );

   mLines.at( pos-1 )->activate();
   mLines.remove( line );
   removeChild( line );
   delete line;

   for( uint i = pos; i < mLines.count(); ++i ) {
     RecipientLine *line = mLines.at( i );
     moveChild( line, childX( line ), childY( line ) - mLineHeight );
   }

   setFixedHeight( mLines.count() * mLineHeight );
}

void RecipientsView::activateLine( RecipientLine *line )
{
  line->activate();
  ensureVisible( 0, childY( line ) );
}

void RecipientsView::viewportResizeEvent ( QResizeEvent *ev )
{
  kdDebug() << "RESIZE " << ev->size() << endl;

  for( uint i = 0; i < mLines.count(); ++i ) {
    mLines.at( i )->resize( ev->size().width(), mLineHeight );
  }
}

QSize RecipientsView::sizeHint() const
{
  return QSize( 200, mLineHeight * mLines.count() );
}

QSize RecipientsView::minimumSizeHint() const
{
  int height;

  uint numLines = 5;

  if ( mLines.count() < numLines ) height = mLineHeight * mLines.count();
  else height = mLineHeight * numLines;

  return QSize( 200, height );
}

Recipient::List RecipientsView::recipients() const
{
  Recipient::List recipients;

  QPtrListIterator<RecipientLine> it( mLines );
  RecipientLine *line;
  while( ( line = it.current() ) ) {
    if ( !line->recipient().isEmpty() ) {
      recipients.append( line->recipient() );
    }

    ++it;
  }

  return recipients;
}

void RecipientsView::setFocus()
{
  if ( mLines.last()->isActive() ) setFocusBottom();
  else setFocusTop();
}

void RecipientsView::setFocusTop()
{
  RecipientLine *line = mLines.first();
  if ( line ) line->activate();
  else kdWarning() << "No first" << endl;
}

void RecipientsView::setFocusBottom()
{
  RecipientLine *line = mLines.last();
  if ( line ) line->activate();
  else  kdWarning() << "No last" << endl;
}

SideWidget::SideWidget( RecipientsView *view, QWidget *parent )
  : QWidget( parent ), mView( view ), mRecipientPicker( 0 )
{
  QBoxLayout *topLayout = new QVBoxLayout( this );

  mTotalLabel = new QLabel( this );
  mTotalLabel->setAlignment( AlignCenter );
  topLayout->addWidget( mTotalLabel, 1 );
  mTotalLabel->hide();

  QPushButton *button = new QPushButton( "&Select...", this );
  topLayout->addWidget( button );
  connect( button, SIGNAL( clicked() ), SLOT( pickRecipient() ) );

  initRecipientPicker();
}

void SideWidget::initRecipientPicker()
{
  if ( mRecipientPicker ) return;

  mRecipientPicker = new RecipientsPicker( 0 );
  connect( mRecipientPicker, SIGNAL( pickedRecipient( const QString & ) ),
    SIGNAL( pickedRecipient( const QString & ) ) );

  mPickerPositioner = new KWindowPositioner( this, mRecipientPicker );
}

void SideWidget::setTotal( int recipients, int lines )
{
#if 0
  kdDebug() << "SideWidget::setTotal() recipients: " << recipients <<
    "  lines: " << lines << endl;
#endif

  mTotalLabel->setText( i18n("1 recipient","%n recipients", recipients ) );
  if ( lines > 1 ) mTotalLabel->show();
  else mTotalLabel->hide();
}

void SideWidget::pickRecipient()
{
#if 0
  QString rec = KInputDialog::getText( "Pick Recipient",
    "Email address of recipient" );
  if ( !rec.isEmpty() ) emit pickedRecipient( rec );
#else
  mRecipientPicker->setRecipients( mView->recipients() );
  mRecipientPicker->show();
  mRecipientPicker->raise();
  mPickerPositioner->reposition();
#endif
}

RecipientsEditor::RecipientsEditor( QWidget *parent )
  : QWidget( parent )
{
  QBoxLayout *topLayout = new QHBoxLayout( this );
  topLayout->setSpacing( KDialog::spacingHint() );

  mRecipientsView = new RecipientsView( this );
  topLayout->addWidget( mRecipientsView );
  connect( mRecipientsView, SIGNAL( focusUp() ), SIGNAL( focusUp() ) );
  connect( mRecipientsView, SIGNAL( focusDown() ), SIGNAL( focusDown() ) );

  SideWidget *side = new SideWidget( mRecipientsView, this );
  topLayout->addWidget( side );
  connect( side, SIGNAL( pickedRecipient( const QString & ) ),
    SLOT( slotPickedRecipient( const QString & ) ) );

  connect( mRecipientsView, SIGNAL( totalChanged( int, int ) ),
    side, SLOT( setTotal( int, int ) ) );
}

void RecipientsEditor::slotPickedRecipient( const QString &rec )
{
  RecipientLine *line = mRecipientsView->activeLine();
  line->setRecipient( rec );

  mRecipientsView->addLine()->activate();
}

Recipient::List RecipientsEditor::recipients() const
{
  return mRecipientsView->recipients();
}

void RecipientsEditor::setRecipientString( const QString &str,
  Recipient::Type type )
{
  clear();

  QStringList r = QStringList::split( ",", str );
  QStringList::ConstIterator it;
  for( it = r.begin(); it != r.end(); ++it ) {
    RecipientLine *line = mRecipientsView->emptyLine();
    if ( !line ) line = mRecipientsView->addLine();
    line->setRecipient( Recipient( *it, type ) );
  }
}

QString RecipientsEditor::recipientString( Recipient::Type type )
{
  kdDebug() << "recipientString() " << Recipient::typeLabel( type ) << endl;

  QString str;

  Recipient::List recipients = mRecipientsView->recipients();
  Recipient::List::ConstIterator it;
  for( it = recipients.begin(); it != recipients.end(); ++it ) {
    if ( (*it).type() == type ) {
      if ( !str.isEmpty() ) str += ", ";
      str.append( (*it).email() );
    }
  }

  return str;
}

void RecipientsEditor::clear()
{
}

void RecipientsEditor::setFocus()
{
  mRecipientsView->setFocus();
}

void RecipientsEditor::setFocusTop()
{
  mRecipientsView->setFocusTop();
}

void RecipientsEditor::setFocusBottom()
{
  mRecipientsView->setFocusBottom();
}

#include "recipientseditor.moc"
<commit_msg>When asked about indentation, the great CORNELIUS said:  "And the number of the counting shall be 2.  Neither shall you count to 4 or 8 nor shalt you count to 1, unless you thenceforth proceedeth to 2". And the PIM hackers were happy and there was much rejoice..<commit_after>/*
    This file is part of KMail.

    Copyright (c) 2004 Cornelius Schumacher <schumacher@kde.org>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

    As a special exception, permission is given to link this program
    with any edition of Qt, and distribute the resulting executable,
    without including the source code for Qt in the source distribution.
*/

#include "recipientseditor.h"

#include "recipientspicker.h"
#include "kwindowpositioner.h"

#include <kdebug.h>
#include <kinputdialog.h>
#include <klocale.h>

#include <qlayout.h>
#include <qlabel.h>
#include <qscrollview.h>
#include <qcombobox.h>
#include <qhbox.h>
#include <qtimer.h>
#include <qpushbutton.h>

Recipient::Recipient( const QString &email, Recipient::Type type )
  : mEmail( email ), mType( type )
{
}

void Recipient::setType( Type type )
{
  mType = type;
}

Recipient::Type Recipient::type() const
{
  return mType;
}

void Recipient::setEmail( const QString &email )
{
  mEmail = email;
}

QString Recipient::email() const
{
  return mEmail;
}

bool Recipient::isEmpty() const
{
  return mEmail.isEmpty();
}

int Recipient::typeToId( Recipient::Type type )
{
  return static_cast<int>( type );
}

Recipient::Type Recipient::idToType( int id )
{
  return static_cast<Type>( id );
}

QString Recipient::typeLabel() const
{
  return typeLabel( mType );
}

QString Recipient::typeLabel( Recipient::Type type )
{
  switch( type ) {
    case To:
      return i18n("To");
    case Cc:
      return i18n("CC");
    case Bcc:
      return i18n("BCC");
    case ReplyTo:
      return i18n("Reply To");
  }

  return i18n("<Undefined RecipientType>");
}

QStringList Recipient::allTypeLabels()
{
  QStringList types;
  types.append( typeLabel( To ) );
  types.append( typeLabel( Cc ) );
  types.append( typeLabel( Bcc ) );
  types.append( typeLabel( ReplyTo ) );
  return types;
}

void RecipientLineEdit::keyPressEvent( QKeyEvent *ev )
{
  if ( ev->key() == Key_Backspace  &&  text().isEmpty() )
  {
    ev->accept();
    emit deleteMe();
  }
  else
    KMLineEdit::keyPressEvent( ev );

}

RecipientLine::RecipientLine( QWidget *parent )
  : QWidget( parent ), mIsEmpty( true )
{
  QBoxLayout *topLayout = new QHBoxLayout( this );

  QStringList recipientTypes = Recipient::allTypeLabels();

  mCombo = new QComboBox( this );
  mCombo->insertStringList( recipientTypes );
  topLayout->addWidget( mCombo );

  mEdit = new RecipientLineEdit( this );
  topLayout->addWidget( mEdit );
  connect( mEdit, SIGNAL( returnPressed() ), SLOT( slotReturnPressed() ) );
  connect( mEdit, SIGNAL( deleteMe() ), SLOT( slotPropagateDeletion() ) );
  connect( mEdit, SIGNAL( textChanged( const QString & ) ),
    SLOT( checkEmptyState( const QString & ) ) );
  connect( mEdit, SIGNAL( focusUp() ), SLOT( slotFocusUp() ) );
  connect( mEdit, SIGNAL( focusDown() ), SLOT( slotFocusDown() ) );

  kdDebug() << "HEIGHT: " << mEdit->minimumSizeHint().height() << endl;

  mCombo->setFixedHeight( mEdit->minimumSizeHint().height() );
}

void RecipientLine::slotFocusUp()
{
  emit upPressed( this );
}

void RecipientLine::slotFocusDown()
{
  emit downPressed( this );
}

void RecipientLine::checkEmptyState( const QString &text )
{
  if ( text.isEmpty() != mIsEmpty ) {
    mIsEmpty = text.isEmpty();
    emit emptyChanged();
  }
}

void RecipientLine::setRecipient( const Recipient &rec )
{
  mEdit->setText( rec.email() );
  mCombo->setCurrentItem( Recipient::typeToId( rec.type() ) );
}

void RecipientLine::setRecipient( const QString &email )
{
  setRecipient( Recipient( email ) );
}

Recipient RecipientLine::recipient() const
{
  return Recipient( mEdit->text(),
    Recipient::idToType( mCombo->currentItem() ) );
}

void RecipientLine::activate()
{
  mEdit->setFocus();
}

bool RecipientLine::isActive()
{
  return mEdit->hasFocus();
}

bool RecipientLine::isEmpty()
{
  return mEdit->text().isEmpty();
}

void RecipientLine::slotReturnPressed()
{
  emit returnPressed( this );
}

void RecipientLine::slotPropagateDeletion()
{
  emit deleteLine( this );
}

void RecipientLine::keyPressEvent( QKeyEvent *ev )
{
  if ( ev->key() == Key_Up ) {
    emit upPressed( this );
  } else if ( ev->key() == Key_Down ) {
    emit downPressed( this );
  }
}

RecipientsView::RecipientsView( QWidget *parent )
  : QScrollView( parent )
{
  setHScrollBarMode( AlwaysOff );
  setLineWidth( 0 );

  addLine();
}

RecipientLine *RecipientsView::activeLine()
{
  return mLines.last();
}

RecipientLine *RecipientsView::emptyLine()
{
  RecipientLine *line;
  for( line = mLines.first(); line; line = mLines.next() ) {
    if ( line->isEmpty() ) return line;
  }

  return 0;
}

RecipientLine *RecipientsView::addLine()
{
  kdDebug() << "RecipientsView::addLine()" << endl;

  RecipientLine *line = new RecipientLine( viewport() );
  addChild( line, 0, mLines.count() * mLineHeight );
  line->show();
  connect( line, SIGNAL( returnPressed( RecipientLine * ) ),
    SLOT( slotReturnPressed( RecipientLine * ) ) );
  connect( line, SIGNAL( upPressed( RecipientLine * ) ),
    SLOT( slotUpPressed( RecipientLine * ) ) );
  connect( line, SIGNAL( downPressed( RecipientLine * ) ),
    SLOT( slotDownPressed( RecipientLine * ) ) );
  connect( line, SIGNAL( deleteLine( RecipientLine * ) ),
    SLOT( slotDecideLineDeletion( RecipientLine * ) ) );
  connect( line, SIGNAL( emptyChanged() ), SLOT( calculateTotal() ) );

  mLines.append( line );

  mLineHeight = line->minimumSizeHint().height();

  line->resize( viewport()->width(), mLineHeight );

  resizeContents( viewport()->width(), mLines.count() * mLineHeight );

  if ( mLines.count() < 6 ) {
    setFixedHeight( mLineHeight * mLines.count() );
  }

  calculateTotal();

  ensureVisible( 0, mLines.count() * mLineHeight );

  return line;
}

void RecipientsView::calculateTotal()
{
  int count = 0;

  RecipientLine *line;
  for( line = mLines.first(); line; line = mLines.next() ) {
    if ( !line->isEmpty() ) ++count;
  }

  emit totalChanged( count, mLines.count() );
}

void RecipientsView::slotReturnPressed( RecipientLine *line )
{
  if ( !line->recipient().isEmpty() ) {
    RecipientLine *empty = emptyLine();
    if ( !empty ) empty = addLine();
    activateLine( empty );
  }
}

void RecipientsView::slotDownPressed( RecipientLine *line )
{
  int pos = mLines.find( line );
  if ( pos >= (int)mLines.count() - 1 ) {
    emit focusDown();
  } else if ( pos >= 0 ) {
    activateLine( mLines.at( pos + 1 ) );
  }
}

void RecipientsView::slotUpPressed( RecipientLine *line )
{
  int pos = mLines.find( line );
  if ( pos > 0 ) {
    activateLine( mLines.at( pos - 1 ) );
  } else {
    emit focusUp();
  }
}

void RecipientsView::slotDecideLineDeletion( RecipientLine *line )
{
  if ( mLines.first() != line ) {
    mCurDelLine = line;
    QTimer::singleShot( 0, this, SLOT( slotDeleteDueLine( ) ) );
  }
}

void RecipientsView::slotDeleteDueLine()
{
   RecipientLine *line = mCurDelLine;
   int pos = mLines.find( line );

   mLines.at( pos-1 )->activate();
   mLines.remove( line );
   removeChild( line );
   delete line;

   for( uint i = pos; i < mLines.count(); ++i ) {
     RecipientLine *line = mLines.at( i );
     moveChild( line, childX( line ), childY( line ) - mLineHeight );
   }

   setFixedHeight( mLines.count() * mLineHeight );
}

void RecipientsView::activateLine( RecipientLine *line )
{
  line->activate();
  ensureVisible( 0, childY( line ) );
}

void RecipientsView::viewportResizeEvent ( QResizeEvent *ev )
{
  kdDebug() << "RESIZE " << ev->size() << endl;

  for( uint i = 0; i < mLines.count(); ++i ) {
    mLines.at( i )->resize( ev->size().width(), mLineHeight );
  }
}

QSize RecipientsView::sizeHint() const
{
  return QSize( 200, mLineHeight * mLines.count() );
}

QSize RecipientsView::minimumSizeHint() const
{
  int height;

  uint numLines = 5;

  if ( mLines.count() < numLines ) height = mLineHeight * mLines.count();
  else height = mLineHeight * numLines;

  return QSize( 200, height );
}

Recipient::List RecipientsView::recipients() const
{
  Recipient::List recipients;

  QPtrListIterator<RecipientLine> it( mLines );
  RecipientLine *line;
  while( ( line = it.current() ) ) {
    if ( !line->recipient().isEmpty() ) {
      recipients.append( line->recipient() );
    }

    ++it;
  }

  return recipients;
}

void RecipientsView::setFocus()
{
  if ( mLines.last()->isActive() ) setFocusBottom();
  else setFocusTop();
}

void RecipientsView::setFocusTop()
{
  RecipientLine *line = mLines.first();
  if ( line ) line->activate();
  else kdWarning() << "No first" << endl;
}

void RecipientsView::setFocusBottom()
{
  RecipientLine *line = mLines.last();
  if ( line ) line->activate();
  else  kdWarning() << "No last" << endl;
}

SideWidget::SideWidget( RecipientsView *view, QWidget *parent )
  : QWidget( parent ), mView( view ), mRecipientPicker( 0 )
{
  QBoxLayout *topLayout = new QVBoxLayout( this );

  mTotalLabel = new QLabel( this );
  mTotalLabel->setAlignment( AlignCenter );
  topLayout->addWidget( mTotalLabel, 1 );
  mTotalLabel->hide();

  QPushButton *button = new QPushButton( "&Select...", this );
  topLayout->addWidget( button );
  connect( button, SIGNAL( clicked() ), SLOT( pickRecipient() ) );

  initRecipientPicker();
}

void SideWidget::initRecipientPicker()
{
  if ( mRecipientPicker ) return;

  mRecipientPicker = new RecipientsPicker( 0 );
  connect( mRecipientPicker, SIGNAL( pickedRecipient( const QString & ) ),
    SIGNAL( pickedRecipient( const QString & ) ) );

  mPickerPositioner = new KWindowPositioner( this, mRecipientPicker );
}

void SideWidget::setTotal( int recipients, int lines )
{
#if 0
  kdDebug() << "SideWidget::setTotal() recipients: " << recipients <<
    "  lines: " << lines << endl;
#endif

  mTotalLabel->setText( i18n("1 recipient","%n recipients", recipients ) );
  if ( lines > 1 ) mTotalLabel->show();
  else mTotalLabel->hide();
}

void SideWidget::pickRecipient()
{
#if 0
  QString rec = KInputDialog::getText( "Pick Recipient",
    "Email address of recipient" );
  if ( !rec.isEmpty() ) emit pickedRecipient( rec );
#else
  mRecipientPicker->setRecipients( mView->recipients() );
  mRecipientPicker->show();
  mRecipientPicker->raise();
  mPickerPositioner->reposition();
#endif
}

RecipientsEditor::RecipientsEditor( QWidget *parent )
  : QWidget( parent )
{
  QBoxLayout *topLayout = new QHBoxLayout( this );
  topLayout->setSpacing( KDialog::spacingHint() );

  mRecipientsView = new RecipientsView( this );
  topLayout->addWidget( mRecipientsView );
  connect( mRecipientsView, SIGNAL( focusUp() ), SIGNAL( focusUp() ) );
  connect( mRecipientsView, SIGNAL( focusDown() ), SIGNAL( focusDown() ) );

  SideWidget *side = new SideWidget( mRecipientsView, this );
  topLayout->addWidget( side );
  connect( side, SIGNAL( pickedRecipient( const QString & ) ),
    SLOT( slotPickedRecipient( const QString & ) ) );

  connect( mRecipientsView, SIGNAL( totalChanged( int, int ) ),
    side, SLOT( setTotal( int, int ) ) );
}

void RecipientsEditor::slotPickedRecipient( const QString &rec )
{
  RecipientLine *line = mRecipientsView->activeLine();
  line->setRecipient( rec );

  mRecipientsView->addLine()->activate();
}

Recipient::List RecipientsEditor::recipients() const
{
  return mRecipientsView->recipients();
}

void RecipientsEditor::setRecipientString( const QString &str,
  Recipient::Type type )
{
  clear();

  QStringList r = QStringList::split( ",", str );
  QStringList::ConstIterator it;
  for( it = r.begin(); it != r.end(); ++it ) {
    RecipientLine *line = mRecipientsView->emptyLine();
    if ( !line ) line = mRecipientsView->addLine();
    line->setRecipient( Recipient( *it, type ) );
  }
}

QString RecipientsEditor::recipientString( Recipient::Type type )
{
  kdDebug() << "recipientString() " << Recipient::typeLabel( type ) << endl;

  QString str;

  Recipient::List recipients = mRecipientsView->recipients();
  Recipient::List::ConstIterator it;
  for( it = recipients.begin(); it != recipients.end(); ++it ) {
    if ( (*it).type() == type ) {
      if ( !str.isEmpty() ) str += ", ";
      str.append( (*it).email() );
    }
  }

  return str;
}

void RecipientsEditor::clear()
{
}

void RecipientsEditor::setFocus()
{
  mRecipientsView->setFocus();
}

void RecipientsEditor::setFocusTop()
{
  mRecipientsView->setFocusTop();
}

void RecipientsEditor::setFocusBottom()
{
  mRecipientsView->setFocusBottom();
}

#include "recipientseditor.moc"
<|endoftext|>


<commit_before>#pragma once

#include "openMVG/robust_estimation/rand_sampling.hpp"
#include "openMVG/robust_estimation/robust_estimator_ACRansac.hpp"
#include "openMVG/robust_estimation/robust_ransac_tools.hpp"
#include <limits>
#include <numeric>
#include <iostream>
#include <vector>
#include <iterator>

namespace openMVG {
namespace robust{

//*****************************************************
template<typename Kernel, typename Scorer>
double iterativeReweightedLeastSquares(const Kernel &kernel,
                                     const Scorer &scorer,
                                     typename Kernel::Model &best_model,
                                     std::vector<std::size_t> &inliers,
                                     double mtheta = std::sqrt(2),
                                     std::size_t numIter = 4)
{
  const std::size_t total_samples = kernel.NumSamples();
  const std::size_t min_samples = Kernel::MINIMUM_LSSAMPLES;
  double theta = scorer.getThreshold();
  // used in the iterations to update (reduce) the threshold value
  const double deltaTetha = (mtheta*theta - theta) / (numIter-1);

  std::vector<std::size_t> all_samples(total_samples);
  std::iota(all_samples.begin(), all_samples.end(), 0);

  // find inliers from best model with threshold theta
  inliers.clear();
  scorer.Score(kernel, best_model, all_samples, &inliers, theta);

  if(inliers.size() < min_samples)
  {
    inliers.clear();
    std::cerr << "[IRLS] returning cause inliers.size() < min_samples" << std::endl;
    return std::numeric_limits<double>::infinity();
  }

  // LS model from the above inliers
  std::vector<typename Kernel::Model> models;
  kernel.FitLS(inliers, &models);
  assert(models.size()==1);   // LS fitting must always return 1 model

  // change threshold for refinement
  theta *= mtheta;

  // iterative refinement
  for(std::size_t i = 0; i < numIter; ++i)
  {
    // find inliers on the best-so-far model
    // @todo maybe inliers instead of all samples to save some computation
    inliers.clear();
    scorer.Score(kernel, models[0], all_samples, &inliers, theta);

    if(inliers.size() < min_samples)
    {
      inliers.clear();
      std::cerr << "[IRLS] returning cause inliers.size() < min_samples" << std::endl;
      return std::numeric_limits<double>::infinity();
    }
//    std::cout << "[IRLS] #" << i
//            << " theta: " << theta
//            << " num inliers: " << inliers.size() << std::endl;

    // compute the weights for the inliers
    std::vector<double> weights;
    kernel.computeWeights(models[0], inliers, weights);

    // LS with weights on inliers
    models.clear();
    kernel.FitLS(inliers, &models, &weights);
    if(models.size() != 1)   // LS fitting must always return 1 model
    {
      std::cerr << "[IRLS] found "<< models.size() << " models, aborting..." << std::endl;
      return std::numeric_limits<double>::infinity();
    }

    // update the threshold
    theta -= deltaTetha;
  }

  assert(models.size()==1);
  best_model = models[0];
  inliers.clear();
  const double score = scorer.Score(kernel, best_model, all_samples, &inliers, theta);
  std::cout << "[IRLS] returning with num inliers: " << inliers.size()
          << " and score " << score << std::endl;
  return score;
}

template<typename Kernel, typename Scorer>
double localOptimization(const Kernel &kernel,
                       const Scorer &scorer,
                       typename Kernel::Model &bestModel,
                       std::vector<std::size_t> &bestInliers,
                       double mtheta = std::sqrt(2),
                       std::size_t numRep = 10,
                       std::size_t minSampleSize = 10)
{
  const std::size_t total_samples = kernel.NumSamples();
  const std::size_t min_samples = Kernel::MINIMUM_LSSAMPLES;
  assert((total_samples > min_samples) &&
          "[localOptimization] not enough data to estimate the model!");

  const double theta = scorer.getThreshold();

  std::vector<std::size_t> all_samples(total_samples);
  std::iota(all_samples.begin(), all_samples.end(), 0);

  std::size_t debugInit = 0;
  if(!bestInliers.empty())
  {
    debugInit = bestInliers.size();
    bestInliers.clear();
  }
  double bestScore = scorer.Score(kernel, bestModel, all_samples, &bestInliers, theta);
  if(debugInit != 0) assert(debugInit == bestInliers.size());

  // so far this is the best model
  std::size_t bestNumInliers = bestInliers.size();
  std::cout << "[localOptim] so far best num inliers: " << bestNumInliers << std::endl;
  std::cout << "[localOptim] so far best model:\n" << bestModel << std::endl;
  std::cout << "[localOptim] so far best score: " << bestScore << std::endl;

  // find inliers from best model with larger threshold t*m over all the samples
  std::vector<std::size_t> inliersBase;
  scorer.Score(kernel, bestModel, all_samples, &inliersBase, theta*mtheta);
  assert((inliersBase.size() > min_samples) &&
          "[localOptimization] not enough data in inliersBase to estimate the model!");

  // LS model from the above inliers
  std::vector<typename Kernel::Model> models;
  kernel.FitLS(inliersBase, &models);
  assert(models.size()==1);   // LS fitting must always return 1 model

  // find inliers with t again over all the samples
  inliersBase.clear();
  scorer.Score(kernel, models[0], all_samples, &inliersBase, theta);

  // sample of size sampleSize from the last best inliers
  const std::size_t sampleSize = std::min(minSampleSize, inliersBase.size()/2);
  if(sampleSize <= Kernel::MINIMUM_LSSAMPLES)
  {
    std::cout << "breaking cause sampleSize is " << sampleSize << std::endl;
    return bestScore;
  }

  // do numRep resampling + iterative LS
  for(std::size_t i = 0; i < numRep; ++i)
  {
    std::vector<std::size_t> sample;
    UniformSample(sampleSize, inliersBase, &sample);
    assert(sampleSize > Kernel::MINIMUM_LSSAMPLES);
    assert(sample.size() > Kernel::MINIMUM_LSSAMPLES);

    // LS estimation from the sample
    models.clear();
    kernel.FitLS(sample, &models);
    assert(models.size()==1);   // LS fitting must always return 1 model

    // IRLS
    std::vector<std::size_t> inliers;
    const double score = iterativeReweightedLeastSquares(kernel, scorer, models[0], inliers);

    // store new best model if it is the case
    if((inliers.size() > bestNumInliers) ||
       ((inliers.size() == bestNumInliers) && (score < bestScore)))
    {
      bestNumInliers = inliers.size();
      bestScore = score;
      bestModel = models[0];
      bestInliers.swap(inliers);
      std::cout << "[localOptim] new best num inliers: " << bestNumInliers << std::endl;
    }
  }
  return bestScore;
}

//@todo make visible parameters for the optimization step
template<typename Kernel, typename Scorer>
typename Kernel::Model LO_RANSAC(
  const Kernel &kernel,
  const Scorer &scorer,
  std::vector<std::size_t> *best_inliers = NULL,
  double *best_score = NULL,
  bool bVerbose = true,
  double outliers_probability = 1e-2)
{
  assert(outliers_probability < 1.0);
  assert(outliers_probability > 0.0);
  std::size_t iteration = 0;
  const std::size_t min_samples = Kernel::MINIMUM_SAMPLES;
  const std::size_t total_samples = kernel.NumSamples();

  std::size_t max_iterations = 100;
  const std::size_t really_max_iterations = 4096;

  std::size_t bestNumInliers = 0;
  double bestInlierRatio = 0.0;
  typename Kernel::Model bestModel;

  // Test if we have sufficient points for the kernel.
  if (total_samples < min_samples)
  {
    if (best_inliers) {
      best_inliers->resize(0);
    }
    return bestModel;
  }

  // In this robust estimator, the scorer always works on all the data points
  // at once. So precompute the list ahead of time [0,..,total_samples].
  std::vector<std::size_t> all_samples(total_samples);
  std::iota(all_samples.begin(), all_samples.end(), 0);

  std::vector<std::size_t> sample;
  for(iteration = 0; iteration < max_iterations; ++iteration)
  {
    UniformSample(min_samples, total_samples, &sample);

    std::vector<typename Kernel::Model> models;
    kernel.Fit(sample, &models);

    // Compute the inlier list for each fit.
    for(std::size_t i = 0; i < models.size(); ++i)
    {
      std::vector<std::size_t> inliers;
      double score = scorer.Score(kernel, models[i], all_samples, &inliers);
      std::cout << "sample=";
      std::sort(sample.begin(), sample.end());
      std::copy(sample.begin(), sample.end(),
                    std::ostream_iterator<std::size_t>(std::cout, ","));
      std::cout << "\nmodel " << i
              << " e: " << score << std::endl;

      if (bestNumInliers <= inliers.size())
      {
        bestModel = models[i];
        //** LOCAL OPTIMIZATION
        std::cout << "Before Optim: num inliers: " << inliers.size()
                << " score: " << score
                << " Kernel::MINIMUM_LSSAMPLES: " << Kernel::MINIMUM_LSSAMPLES
                << std::endl;

        std::cout << "Model:\n" << bestModel << std::endl;

        if(inliers.size() > Kernel::MINIMUM_LSSAMPLES)
        {
          score = localOptimization(kernel, scorer, bestModel, inliers);
        }
        std::cout << "After Optim: num inliers: " << inliers.size()
                << " score: " << score << std::endl;
        std::cout << "Model:\n" << bestModel << std::endl;

        bestNumInliers = inliers.size();
        bestInlierRatio = inliers.size() / double(total_samples);

        if (best_inliers)
        {
          best_inliers->swap(inliers);
        }

        if(bVerbose)
        {
          std::cout << " inliers=" << bestNumInliers << "/" << total_samples
                    << " (iter=" << iteration
                    << " ,i=" << i;
          std::cout << ",sample=";
          std::copy(sample.begin(), sample.end(),
                    std::ostream_iterator<std::size_t>(std::cout, ","));
          std::cout << ")";
        }
        if (bestInlierRatio)
        {
          max_iterations = IterationsRequired(min_samples,
                                              outliers_probability,
                                              bestInlierRatio);
          // safeguard to not get stuck in a big number of iterations
          max_iterations = std::min(max_iterations, really_max_iterations);
          if(bVerbose)
            std::cout << " New max_iteration: " << max_iterations << std::endl;
        }
      }
    }
  }
  if (best_score)
    *best_score = bestNumInliers;

  if(bestNumInliers)
    kernel.Unnormalize(&bestModel);

  return bestModel;
}

} // namespace robust
} // namespace openMVG<commit_msg>[robust] using clear instead of resize<commit_after>#pragma once

#include "openMVG/robust_estimation/rand_sampling.hpp"
#include "openMVG/robust_estimation/robust_estimator_ACRansac.hpp"
#include "openMVG/robust_estimation/robust_ransac_tools.hpp"
#include <limits>
#include <numeric>
#include <iostream>
#include <vector>
#include <iterator>

namespace openMVG {
namespace robust{

//*****************************************************
template<typename Kernel, typename Scorer>
double iterativeReweightedLeastSquares(const Kernel &kernel,
                                     const Scorer &scorer,
                                     typename Kernel::Model &best_model,
                                     std::vector<std::size_t> &inliers,
                                     double mtheta = std::sqrt(2),
                                     std::size_t numIter = 4)
{
  const std::size_t total_samples = kernel.NumSamples();
  const std::size_t min_samples = Kernel::MINIMUM_LSSAMPLES;
  double theta = scorer.getThreshold();
  // used in the iterations to update (reduce) the threshold value
  const double deltaTetha = (mtheta*theta - theta) / (numIter-1);

  std::vector<std::size_t> all_samples(total_samples);
  std::iota(all_samples.begin(), all_samples.end(), 0);

  // find inliers from best model with threshold theta
  inliers.clear();
  scorer.Score(kernel, best_model, all_samples, &inliers, theta);

  if(inliers.size() < min_samples)
  {
    inliers.clear();
    std::cerr << "[IRLS] returning cause inliers.size() < min_samples" << std::endl;
    return std::numeric_limits<double>::infinity();
  }

  // LS model from the above inliers
  std::vector<typename Kernel::Model> models;
  kernel.FitLS(inliers, &models);
  assert(models.size()==1);   // LS fitting must always return 1 model

  // change threshold for refinement
  theta *= mtheta;

  // iterative refinement
  for(std::size_t i = 0; i < numIter; ++i)
  {
    // find inliers on the best-so-far model
    // @todo maybe inliers instead of all samples to save some computation
    inliers.clear();
    scorer.Score(kernel, models[0], all_samples, &inliers, theta);

    if(inliers.size() < min_samples)
    {
      inliers.clear();
      std::cerr << "[IRLS] returning cause inliers.size() < min_samples" << std::endl;
      return std::numeric_limits<double>::infinity();
    }
//    std::cout << "[IRLS] #" << i
//            << " theta: " << theta
//            << " num inliers: " << inliers.size() << std::endl;

    // compute the weights for the inliers
    std::vector<double> weights;
    kernel.computeWeights(models[0], inliers, weights);

    // LS with weights on inliers
    models.clear();
    kernel.FitLS(inliers, &models, &weights);
    if(models.size() != 1)   // LS fitting must always return 1 model
    {
      std::cerr << "[IRLS] found "<< models.size() << " models, aborting..." << std::endl;
      return std::numeric_limits<double>::infinity();
    }

    // update the threshold
    theta -= deltaTetha;
  }

  assert(models.size()==1);
  best_model = models[0];
  inliers.clear();
  const double score = scorer.Score(kernel, best_model, all_samples, &inliers, theta);
  std::cout << "[IRLS] returning with num inliers: " << inliers.size()
          << " and score " << score << std::endl;
  return score;
}

template<typename Kernel, typename Scorer>
double localOptimization(const Kernel &kernel,
                       const Scorer &scorer,
                       typename Kernel::Model &bestModel,
                       std::vector<std::size_t> &bestInliers,
                       double mtheta = std::sqrt(2),
                       std::size_t numRep = 10,
                       std::size_t minSampleSize = 10)
{
  const std::size_t total_samples = kernel.NumSamples();
  const std::size_t min_samples = Kernel::MINIMUM_LSSAMPLES;
  assert((total_samples > min_samples) &&
          "[localOptimization] not enough data to estimate the model!");

  const double theta = scorer.getThreshold();

  std::vector<std::size_t> all_samples(total_samples);
  std::iota(all_samples.begin(), all_samples.end(), 0);

  std::size_t debugInit = 0;
  if(!bestInliers.empty())
  {
    debugInit = bestInliers.size();
    bestInliers.clear();
  }
  double bestScore = scorer.Score(kernel, bestModel, all_samples, &bestInliers, theta);
  if(debugInit != 0) assert(debugInit == bestInliers.size());

  // so far this is the best model
  std::size_t bestNumInliers = bestInliers.size();
  std::cout << "[localOptim] so far best num inliers: " << bestNumInliers << std::endl;
  std::cout << "[localOptim] so far best model:\n" << bestModel << std::endl;
  std::cout << "[localOptim] so far best score: " << bestScore << std::endl;

  // find inliers from best model with larger threshold t*m over all the samples
  std::vector<std::size_t> inliersBase;
  scorer.Score(kernel, bestModel, all_samples, &inliersBase, theta*mtheta);
  assert((inliersBase.size() > min_samples) &&
          "[localOptimization] not enough data in inliersBase to estimate the model!");

  // LS model from the above inliers
  std::vector<typename Kernel::Model> models;
  kernel.FitLS(inliersBase, &models);
  assert(models.size()==1);   // LS fitting must always return 1 model

  // find inliers with t again over all the samples
  inliersBase.clear();
  scorer.Score(kernel, models[0], all_samples, &inliersBase, theta);

  // sample of size sampleSize from the last best inliers
  const std::size_t sampleSize = std::min(minSampleSize, inliersBase.size()/2);
  if(sampleSize <= Kernel::MINIMUM_LSSAMPLES)
  {
    std::cout << "breaking cause sampleSize is " << sampleSize << std::endl;
    return bestScore;
  }

  // do numRep resampling + iterative LS
  for(std::size_t i = 0; i < numRep; ++i)
  {
    std::vector<std::size_t> sample;
    UniformSample(sampleSize, inliersBase, &sample);
    assert(sampleSize > Kernel::MINIMUM_LSSAMPLES);
    assert(sample.size() > Kernel::MINIMUM_LSSAMPLES);

    // LS estimation from the sample
    models.clear();
    kernel.FitLS(sample, &models);
    assert(models.size()==1);   // LS fitting must always return 1 model

    // IRLS
    std::vector<std::size_t> inliers;
    const double score = iterativeReweightedLeastSquares(kernel, scorer, models[0], inliers);

    // store new best model if it is the case
    if((inliers.size() > bestNumInliers) ||
       ((inliers.size() == bestNumInliers) && (score < bestScore)))
    {
      bestNumInliers = inliers.size();
      bestScore = score;
      bestModel = models[0];
      bestInliers.swap(inliers);
      std::cout << "[localOptim] new best num inliers: " << bestNumInliers << std::endl;
    }
  }
  return bestScore;
}

//@todo make visible parameters for the optimization step
template<typename Kernel, typename Scorer>
typename Kernel::Model LO_RANSAC(
  const Kernel &kernel,
  const Scorer &scorer,
  std::vector<std::size_t> *best_inliers = NULL,
  double *best_score = NULL,
  bool bVerbose = true,
  double outliers_probability = 1e-2)
{
  assert(outliers_probability < 1.0);
  assert(outliers_probability > 0.0);
  std::size_t iteration = 0;
  const std::size_t min_samples = Kernel::MINIMUM_SAMPLES;
  const std::size_t total_samples = kernel.NumSamples();

  std::size_t max_iterations = 100;
  const std::size_t really_max_iterations = 4096;

  std::size_t bestNumInliers = 0;
  double bestInlierRatio = 0.0;
  typename Kernel::Model bestModel;

  // Test if we have sufficient points for the kernel.
  if (total_samples < min_samples)
  {
    if (best_inliers) {
      best_inliers->clear();
    }
    return bestModel;
  }

  // In this robust estimator, the scorer always works on all the data points
  // at once. So precompute the list ahead of time [0,..,total_samples].
  std::vector<std::size_t> all_samples(total_samples);
  std::iota(all_samples.begin(), all_samples.end(), 0);

  std::vector<std::size_t> sample;
  for(iteration = 0; iteration < max_iterations; ++iteration)
  {
    UniformSample(min_samples, total_samples, &sample);

    std::vector<typename Kernel::Model> models;
    kernel.Fit(sample, &models);

    // Compute the inlier list for each fit.
    for(std::size_t i = 0; i < models.size(); ++i)
    {
      std::vector<std::size_t> inliers;
      double score = scorer.Score(kernel, models[i], all_samples, &inliers);
      std::cout << "sample=";
      std::sort(sample.begin(), sample.end());
      std::copy(sample.begin(), sample.end(),
                    std::ostream_iterator<std::size_t>(std::cout, ","));
      std::cout << "\nmodel " << i
              << " e: " << score << std::endl;

      if (bestNumInliers <= inliers.size())
      {
        bestModel = models[i];
        //** LOCAL OPTIMIZATION
        std::cout << "Before Optim: num inliers: " << inliers.size()
                << " score: " << score
                << " Kernel::MINIMUM_LSSAMPLES: " << Kernel::MINIMUM_LSSAMPLES
                << std::endl;

        std::cout << "Model:\n" << bestModel << std::endl;

        if(inliers.size() > Kernel::MINIMUM_LSSAMPLES)
        {
          score = localOptimization(kernel, scorer, bestModel, inliers);
        }
        std::cout << "After Optim: num inliers: " << inliers.size()
                << " score: " << score << std::endl;
        std::cout << "Model:\n" << bestModel << std::endl;

        bestNumInliers = inliers.size();
        bestInlierRatio = inliers.size() / double(total_samples);

        if (best_inliers)
        {
          best_inliers->swap(inliers);
        }

        if(bVerbose)
        {
          std::cout << " inliers=" << bestNumInliers << "/" << total_samples
                    << " (iter=" << iteration
                    << " ,i=" << i;
          std::cout << ",sample=";
          std::copy(sample.begin(), sample.end(),
                    std::ostream_iterator<std::size_t>(std::cout, ","));
          std::cout << ")";
        }
        if (bestInlierRatio)
        {
          max_iterations = IterationsRequired(min_samples,
                                              outliers_probability,
                                              bestInlierRatio);
          // safeguard to not get stuck in a big number of iterations
          max_iterations = std::min(max_iterations, really_max_iterations);
          if(bVerbose)
            std::cout << " New max_iteration: " << max_iterations << std::endl;
        }
      }
    }
  }
  if (best_score)
    *best_score = bestNumInliers;

  if(bestNumInliers)
    kernel.Unnormalize(&bestModel);

  return bestModel;
}

} // namespace robust
} // namespace openMVG<|endoftext|>