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

#include "watchman/Serde.h"
#include <gtest/gtest.h>

namespace {
using namespace watchman;

template <typename T>
struct HasField : public serde::Object {
  T field;

  template <typename X>
  void map(X& x) {
    x("field", field);
  }
};

TEST(SerdeTest, map_boolean) {
  HasField<bool> s;
  s.field = false;

  auto o = serde::encode(s);
  EXPECT_EQ(JSON_OBJECT, o.type());
  EXPECT_EQ(1, o.object().size());
  auto field = o.object().at("field");
  EXPECT_EQ(false, field.asBool());

  s.field = true;
  o = serde::encode(s);
  field = o.object().at("field");
  EXPECT_EQ(true, field.asBool());
}

template <typename T>
void roundtrip(const T& value) {
  HasField<T> s;
  s.field = value;

  auto result = serde::decode<HasField<T>>(serde::encode(s));
  EXPECT_EQ(result.field, value);
}

TEST(SerdeTest, integer_roundtrip) {
  roundtrip<bool>(false);
  roundtrip<bool>(true);

  roundtrip<char>(100);
  roundtrip<signed char>(100);
  roundtrip<unsigned char>(100);
  roundtrip<signed short>(100);
  roundtrip<unsigned short>(100);
  roundtrip<signed int>(100);
  roundtrip<unsigned int>(100);
  roundtrip<signed long>(100);
  roundtrip<unsigned long>(100);
  roundtrip<signed long long>(100);
  roundtrip<unsigned long long>(100);

  roundtrip<int8_t>(100);
  roundtrip<uint8_t>(100);
  roundtrip<int16_t>(100);
  roundtrip<uint16_t>(100);
  roundtrip<int32_t>(100);
  roundtrip<uint32_t>(100);
  roundtrip<int64_t>(100);
  roundtrip<uint64_t>(100);
}

TEST(SerdeTest, array_roundtrip) {
  roundtrip<std::vector<int>>(std::vector<int>{10, 20, -30});
}

TEST(SerdeTest, map_roundtrip) {
  roundtrip<std::map<w_string, bool>>(
      std::map<w_string, bool>{{"foo", false}, {"bar", true}});
}

TEST(SerdeTest, missing_keys_are_okay) {
  {
    auto decoded = serde::decode<HasField<int>>(json_object());
    EXPECT_EQ(0, decoded.field);
  }

  {
    auto decoded = serde::decode<HasField<std::string>>(json_object());
    EXPECT_EQ("", decoded.field);
  }
}

struct RequiredField : serde::Object {
  std::string str;

  template <typename X>
  void map(X& x) {
    x.required("str", str);
  }
};

TEST(SerdeTest, required_keys_are_necessary) {
  EXPECT_THROW(serde::decode<RequiredField>(json_object()), serde::MissingKey);

  auto decoded = serde::decode<RequiredField>(
      json_object({{"str", typed_string_to_json("value")}}));
  EXPECT_EQ("value", decoded.str);

  auto encoded = serde::encode(decoded);
  EXPECT_EQ(JSON_OBJECT, encoded.type());
  EXPECT_EQ(1, encoded.object().size());
  auto str = encoded.object().at("str");
  EXPECT_EQ(JSON_STRING, str.type());
  EXPECT_EQ("value", str.asString());
}

struct Base : serde::Object {
  std::string version;

  template <typename X>
  void map(X& x) {
    x("version", version);
  }
};

struct Derived : Base {
  bool yes;
  int count;

  template <typename X>
  void map(X& x) {
    Base::map(x);
    x("yes", yes);
    x("count", count);
  }
};

TEST(SerdeTest, base_class) {
  Derived d;
  d.version = "ver 15";
  d.yes = true;
  d.count = -45;

  auto o = serde::encode(d);
  auto& encoded = o.object();
  EXPECT_EQ(3, encoded.size());

  auto version = encoded.at("version");
  EXPECT_EQ(JSON_STRING, version.type());
  EXPECT_EQ("ver 15", version.asString());

  auto yes = encoded.at("yes");
  EXPECT_EQ(JSON_TRUE, yes.type());

  auto count = encoded.at("count");
  EXPECT_EQ(JSON_INTEGER, count.type());
}

struct OptionalMembers : serde::Object {
  std::optional<bool> set;
  std::optional<bool> unset;

  template <typename X>
  void map(X& x) {
    x("set", set);
    x.skip_if_default("unset", unset);
  }
};

TEST(SerdeTest, optional_field) {
  OptionalMembers members;

  {
    auto o = serde::encode(members);
    auto& encoded = o.object();
    EXPECT_EQ(1, encoded.size());
    EXPECT_EQ(JSON_NULL, encoded.at("set").type());

    OptionalMembers decoded = serde::decode<OptionalMembers>(o);
    EXPECT_EQ(members.set, decoded.set);
    EXPECT_EQ(members.unset, decoded.unset);
  }

  {
    members.set = true;
    members.unset = false;

    auto o = serde::encode(members);
    auto& encoded = o.object();
    EXPECT_EQ(2, encoded.size());
    EXPECT_EQ(JSON_TRUE, encoded.at("set").type());
    EXPECT_EQ(JSON_FALSE, encoded.at("unset").type());

    OptionalMembers decoded = serde::decode<OptionalMembers>(o);
    EXPECT_EQ(members.set, decoded.set);
    EXPECT_EQ(members.unset, decoded.unset);
  }
}

using TupleArray = serde::Array<1, int, bool>;

TEST(SerdeTest, arrays_as_tuples) {
  TupleArray ta;

  {
    // Encoding a tuple only emits the required and non-default elements.
    auto o = serde::encode(ta);
    EXPECT_EQ(JSON_ARRAY, o.type());
    auto& array = o.array();
    EXPECT_EQ(1, array.size());

    auto parsed = serde::decode<TupleArray>(o);
    EXPECT_EQ(0, std::get<0>(parsed));
    EXPECT_EQ(false, std::get<1>(parsed));
  }

  std::get<0>(ta) = 10;
  std::get<1>(ta) = true;

  {
    // Non-default elements are all emitted.
    auto o = serde::encode(ta);
    EXPECT_EQ(JSON_ARRAY, o.type());
    auto& array = o.array();
    EXPECT_EQ(2, array.size());

    auto parsed = serde::decode<TupleArray>(o);
    EXPECT_EQ(10, std::get<0>(parsed));
    EXPECT_EQ(true, std::get<1>(parsed));
  }
}

TEST(SerdeTest, longer_arrays_are_not_rejected) {
  auto j = json_array(
      {json_integer(10), json_false(), typed_string_to_json("hello world")});
  auto ta = serde::decode<TupleArray>(j);
  EXPECT_EQ(10, std::get<0>(ta));
  EXPECT_EQ(false, std::get<1>(ta));
}

struct SkippedThings : serde::Object {
  int x = 10;
  int y = 5;

  template <typename X>
  void map(X& m) {
    m.skip_if("x", x, [](const auto& x) { return x == 10; });
    m.skip_if("y", y, [](const auto& y) { return y == 5; });
  }
};

using MultipleOptionals = serde::Array<0, int, int, int>;

TEST(SerdeTest, non_defaults_after_defaults_are_encoded) {
  auto json = serde::encode(MultipleOptionals{{0, 0, 10}});
  EXPECT_EQ(JSON_ARRAY, json.type());
  auto& arr = json.array();
  EXPECT_EQ(3, arr.size());
  EXPECT_EQ(0, arr[0].asInt());
  EXPECT_EQ(0, arr[1].asInt());
  EXPECT_EQ(10, arr[2].asInt());

  json = serde::encode(MultipleOptionals{{0, 0, 0}});
  EXPECT_EQ(JSON_ARRAY, json.type());
  EXPECT_EQ(0, json.array().size());
}

TEST(SerdeTest, skip_if) {
  SkippedThings s;

  {
    auto o = serde::encode(s);
    EXPECT_EQ(JSON_OBJECT, o.type());
    EXPECT_EQ(0, o.object().size());

    auto decoded = serde::decode<SkippedThings>(o);
    EXPECT_EQ(0, decoded.x);
    EXPECT_EQ(0, decoded.y);
  }

  s.x = 0;
  s.y = 0;

  {
    auto o = serde::encode(s);
    EXPECT_EQ(JSON_OBJECT, o.type());
    auto& map = o.object();
    EXPECT_EQ(0, map.at("x").asInt());
    EXPECT_EQ(0, map.at("y").asInt());

    auto decoded = serde::decode<SkippedThings>(o);
    EXPECT_EQ(0, decoded.x);
    EXPECT_EQ(0, decoded.y);
  }

  s.x = 100;
  s.y = 5;

  {
    auto o = serde::encode(s);
    EXPECT_EQ(JSON_OBJECT, o.type());
    auto& map = o.object();
    EXPECT_EQ(1, map.size());
    EXPECT_EQ(100, map.at("x").asInt());

    auto decoded = serde::decode<SkippedThings>(o);
    EXPECT_EQ(100, decoded.x);
    // This is a bit strange, but unset keys in a JSON object always produce
    // default-initialized fields. Therefore, this is 0, not 5.
    EXPECT_EQ(0, decoded.y);
  }
}

} // namespace
<commit_msg>test: do not include <gtest/gtest.h> directly<commit_after>/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

#include "watchman/Serde.h"
#include <folly/portability/GTest.h>

namespace {
using namespace watchman;

template <typename T>
struct HasField : public serde::Object {
  T field;

  template <typename X>
  void map(X& x) {
    x("field", field);
  }
};

TEST(SerdeTest, map_boolean) {
  HasField<bool> s;
  s.field = false;

  auto o = serde::encode(s);
  EXPECT_EQ(JSON_OBJECT, o.type());
  EXPECT_EQ(1, o.object().size());
  auto field = o.object().at("field");
  EXPECT_EQ(false, field.asBool());

  s.field = true;
  o = serde::encode(s);
  field = o.object().at("field");
  EXPECT_EQ(true, field.asBool());
}

template <typename T>
void roundtrip(const T& value) {
  HasField<T> s;
  s.field = value;

  auto result = serde::decode<HasField<T>>(serde::encode(s));
  EXPECT_EQ(result.field, value);
}

TEST(SerdeTest, integer_roundtrip) {
  roundtrip<bool>(false);
  roundtrip<bool>(true);

  roundtrip<char>(100);
  roundtrip<signed char>(100);
  roundtrip<unsigned char>(100);
  roundtrip<signed short>(100);
  roundtrip<unsigned short>(100);
  roundtrip<signed int>(100);
  roundtrip<unsigned int>(100);
  roundtrip<signed long>(100);
  roundtrip<unsigned long>(100);
  roundtrip<signed long long>(100);
  roundtrip<unsigned long long>(100);

  roundtrip<int8_t>(100);
  roundtrip<uint8_t>(100);
  roundtrip<int16_t>(100);
  roundtrip<uint16_t>(100);
  roundtrip<int32_t>(100);
  roundtrip<uint32_t>(100);
  roundtrip<int64_t>(100);
  roundtrip<uint64_t>(100);
}

TEST(SerdeTest, array_roundtrip) {
  roundtrip<std::vector<int>>(std::vector<int>{10, 20, -30});
}

TEST(SerdeTest, map_roundtrip) {
  roundtrip<std::map<w_string, bool>>(
      std::map<w_string, bool>{{"foo", false}, {"bar", true}});
}

TEST(SerdeTest, missing_keys_are_okay) {
  {
    auto decoded = serde::decode<HasField<int>>(json_object());
    EXPECT_EQ(0, decoded.field);
  }

  {
    auto decoded = serde::decode<HasField<std::string>>(json_object());
    EXPECT_EQ("", decoded.field);
  }
}

struct RequiredField : serde::Object {
  std::string str;

  template <typename X>
  void map(X& x) {
    x.required("str", str);
  }
};

TEST(SerdeTest, required_keys_are_necessary) {
  EXPECT_THROW(serde::decode<RequiredField>(json_object()), serde::MissingKey);

  auto decoded = serde::decode<RequiredField>(
      json_object({{"str", typed_string_to_json("value")}}));
  EXPECT_EQ("value", decoded.str);

  auto encoded = serde::encode(decoded);
  EXPECT_EQ(JSON_OBJECT, encoded.type());
  EXPECT_EQ(1, encoded.object().size());
  auto str = encoded.object().at("str");
  EXPECT_EQ(JSON_STRING, str.type());
  EXPECT_EQ("value", str.asString());
}

struct Base : serde::Object {
  std::string version;

  template <typename X>
  void map(X& x) {
    x("version", version);
  }
};

struct Derived : Base {
  bool yes;
  int count;

  template <typename X>
  void map(X& x) {
    Base::map(x);
    x("yes", yes);
    x("count", count);
  }
};

TEST(SerdeTest, base_class) {
  Derived d;
  d.version = "ver 15";
  d.yes = true;
  d.count = -45;

  auto o = serde::encode(d);
  auto& encoded = o.object();
  EXPECT_EQ(3, encoded.size());

  auto version = encoded.at("version");
  EXPECT_EQ(JSON_STRING, version.type());
  EXPECT_EQ("ver 15", version.asString());

  auto yes = encoded.at("yes");
  EXPECT_EQ(JSON_TRUE, yes.type());

  auto count = encoded.at("count");
  EXPECT_EQ(JSON_INTEGER, count.type());
}

struct OptionalMembers : serde::Object {
  std::optional<bool> set;
  std::optional<bool> unset;

  template <typename X>
  void map(X& x) {
    x("set", set);
    x.skip_if_default("unset", unset);
  }
};

TEST(SerdeTest, optional_field) {
  OptionalMembers members;

  {
    auto o = serde::encode(members);
    auto& encoded = o.object();
    EXPECT_EQ(1, encoded.size());
    EXPECT_EQ(JSON_NULL, encoded.at("set").type());

    OptionalMembers decoded = serde::decode<OptionalMembers>(o);
    EXPECT_EQ(members.set, decoded.set);
    EXPECT_EQ(members.unset, decoded.unset);
  }

  {
    members.set = true;
    members.unset = false;

    auto o = serde::encode(members);
    auto& encoded = o.object();
    EXPECT_EQ(2, encoded.size());
    EXPECT_EQ(JSON_TRUE, encoded.at("set").type());
    EXPECT_EQ(JSON_FALSE, encoded.at("unset").type());

    OptionalMembers decoded = serde::decode<OptionalMembers>(o);
    EXPECT_EQ(members.set, decoded.set);
    EXPECT_EQ(members.unset, decoded.unset);
  }
}

using TupleArray = serde::Array<1, int, bool>;

TEST(SerdeTest, arrays_as_tuples) {
  TupleArray ta;

  {
    // Encoding a tuple only emits the required and non-default elements.
    auto o = serde::encode(ta);
    EXPECT_EQ(JSON_ARRAY, o.type());
    auto& array = o.array();
    EXPECT_EQ(1, array.size());

    auto parsed = serde::decode<TupleArray>(o);
    EXPECT_EQ(0, std::get<0>(parsed));
    EXPECT_EQ(false, std::get<1>(parsed));
  }

  std::get<0>(ta) = 10;
  std::get<1>(ta) = true;

  {
    // Non-default elements are all emitted.
    auto o = serde::encode(ta);
    EXPECT_EQ(JSON_ARRAY, o.type());
    auto& array = o.array();
    EXPECT_EQ(2, array.size());

    auto parsed = serde::decode<TupleArray>(o);
    EXPECT_EQ(10, std::get<0>(parsed));
    EXPECT_EQ(true, std::get<1>(parsed));
  }
}

TEST(SerdeTest, longer_arrays_are_not_rejected) {
  auto j = json_array(
      {json_integer(10), json_false(), typed_string_to_json("hello world")});
  auto ta = serde::decode<TupleArray>(j);
  EXPECT_EQ(10, std::get<0>(ta));
  EXPECT_EQ(false, std::get<1>(ta));
}

struct SkippedThings : serde::Object {
  int x = 10;
  int y = 5;

  template <typename X>
  void map(X& m) {
    m.skip_if("x", x, [](const auto& x) { return x == 10; });
    m.skip_if("y", y, [](const auto& y) { return y == 5; });
  }
};

using MultipleOptionals = serde::Array<0, int, int, int>;

TEST(SerdeTest, non_defaults_after_defaults_are_encoded) {
  auto json = serde::encode(MultipleOptionals{{0, 0, 10}});
  EXPECT_EQ(JSON_ARRAY, json.type());
  auto& arr = json.array();
  EXPECT_EQ(3, arr.size());
  EXPECT_EQ(0, arr[0].asInt());
  EXPECT_EQ(0, arr[1].asInt());
  EXPECT_EQ(10, arr[2].asInt());

  json = serde::encode(MultipleOptionals{{0, 0, 0}});
  EXPECT_EQ(JSON_ARRAY, json.type());
  EXPECT_EQ(0, json.array().size());
}

TEST(SerdeTest, skip_if) {
  SkippedThings s;

  {
    auto o = serde::encode(s);
    EXPECT_EQ(JSON_OBJECT, o.type());
    EXPECT_EQ(0, o.object().size());

    auto decoded = serde::decode<SkippedThings>(o);
    EXPECT_EQ(0, decoded.x);
    EXPECT_EQ(0, decoded.y);
  }

  s.x = 0;
  s.y = 0;

  {
    auto o = serde::encode(s);
    EXPECT_EQ(JSON_OBJECT, o.type());
    auto& map = o.object();
    EXPECT_EQ(0, map.at("x").asInt());
    EXPECT_EQ(0, map.at("y").asInt());

    auto decoded = serde::decode<SkippedThings>(o);
    EXPECT_EQ(0, decoded.x);
    EXPECT_EQ(0, decoded.y);
  }

  s.x = 100;
  s.y = 5;

  {
    auto o = serde::encode(s);
    EXPECT_EQ(JSON_OBJECT, o.type());
    auto& map = o.object();
    EXPECT_EQ(1, map.size());
    EXPECT_EQ(100, map.at("x").asInt());

    auto decoded = serde::decode<SkippedThings>(o);
    EXPECT_EQ(100, decoded.x);
    // This is a bit strange, but unset keys in a JSON object always produce
    // default-initialized fields. Therefore, this is 0, not 5.
    EXPECT_EQ(0, decoded.y);
  }
}

} // namespace
<|endoftext|>


<commit_before>/*-------------traverse.cpp---------------------------------------------------//
*
* Purpose: This file tests multiple ways to traverse a tree
*
*-----------------------------------------------------------------------------*/

#include <iostream>
#include <stack>
#include <queue>

struct node{
    node *parent;
    node **children;
    int num_children;
    int ID;
};

// Function to create simple tree
void create_tree(node* &root, int num_row, int num_child);

// Function to do a depth-first search recursively
void DFS_recursive(node* &root);

// Function to do a depth-first search with a stack
void DFS_stack();

// Function to do a breadth-first search with a queue
void BFS_queue();

int main(){

    // Creating tree
    node *root;
    create_tree(root, 3, 3);
    std::cout << "Tree created!" << '\n';
    DFS_recursive(root);

}

// Function to create simple tree
void create_tree(node* &root, int num_row, int num_child){
    root = new node;
    root->ID = num_row;
    root->num_children = num_child;
    root->children = (node**)malloc(sizeof(node)*num_child);
    if (num_row > 0){
        for (int i = 0; i < num_child; ++i){
            create_tree(root->children[i], num_row - 1, num_child);
        }
    }
}

// Function to do a depth-first search recursively
void DFS_recursive(node* &root){
    if (!root){return;}
    std::cout << root->ID << '\n';
    for (int i = 0; i < root->num_children; ++i){
        DFS_recursive(root->children[i]);
    }
}
<commit_msg>changed a malloc to new<commit_after>/*-------------traverse.cpp---------------------------------------------------//
*
* Purpose: This file tests multiple ways to traverse a tree
*
*-----------------------------------------------------------------------------*/

#include <iostream>
#include <stack>
#include <queue>

struct node{
    node *parent;
    node **children;
    int num_children;
    int ID;
};

// Function to create simple tree
void create_tree(node* &root, int num_row, int num_child);

// Function to do a depth-first search recursively
void DFS_recursive(node* &root);

// Function to do a depth-first search with a stack
void DFS_stack();

// Function to do a breadth-first search with a queue
void BFS_queue();

int main(){

    // Creating tree
    node *root;
    create_tree(root, 3, 3);
    std::cout << "Tree created!" << '\n';
    DFS_recursive(root);

}

// Function to create simple tree
void create_tree(node* &root, int num_row, int num_child){
    root = new node;
    root->ID = num_row;
    root->num_children = num_child;
    root->children = new node*[num_child];
    if (num_row > 0){
        for (int i = 0; i < num_child; ++i){
            create_tree(root->children[i], num_row - 1, num_child);
        }
    }
}

// Function to do a depth-first search recursively
void DFS_recursive(node* &root){
    if (!root){return;}
    std::cout << root->ID << '\n';
    for (int i = 0; i < root->num_children; ++i){
        DFS_recursive(root->children[i]);
    }
}
<|endoftext|>


<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.

 =========================================================================*/
#include "otbWrapperApplication.h"
#include "otbWrapperApplicationFactory.h"

#include "itkVectorIndexSelectionCastImageFilter.h"
#include "otbGenericRSResampleImageFilter.h"
#include "otbBCOInterpolateImageFunction.h"
#include "otbSimpleRcsPanSharpeningFusionImageFilter.h"
#include "itkFixedArray.h"

// Elevation handler
#include "otbWrapperElevationParametersHandler.h"

namespace otb
{
namespace Wrapper
{

class BundleToPerfectSensor : public Application
{
public:
  /** Standard class typedefs. */
  typedef BundleToPerfectSensor         Self;
  typedef Application                   Superclass;
  typedef itk::SmartPointer<Self>       Pointer;
  typedef itk::SmartPointer<const Self> ConstPointer;

  /** Standard macro */
  itkNewMacro(Self);

  itkTypeMacro(BundleToPerfectSensor, otb::Application);

private:

  void DoInit()
  {
    SetName("BundleToPerfectSensor");
    SetDescription("Perform P+XS pansharpening");

    // Documentation
    SetDocName("Bundle to perfect sensor");
    SetDocLongDescription("This application performs P+XS pansharpening.");
    SetDocLimitations("None");
    SetDocAuthors("OTB-Team");
    SetDocSeeAlso(" ");

    AddDocTag(Tags::Geometry);
    AddDocTag(Tags::Pansharpening);

    AddParameter(ParameterType_InputImage,   "inp",   "Input PAN Image");
    SetParameterDescription("inp"," Input panchromatic image.");
    AddParameter(ParameterType_InputImage,   "inxs",  "Input XS Image");
    SetParameterDescription("inxs"," Input XS image.");

    // Elevation
    ElevationParametersHandler::AddElevationParameters(this, "elev");

    AddParameter(ParameterType_Float,        "lms",   "Spacing of the deformation field");
    SetParameterDescription("lms"," Spacing of the deformation field. Default is 10 times the PAN image spacing.");
    AddParameter(ParameterType_OutputImage,  "out",   "Output image");
    SetParameterDescription("out"," Output image.");
    AddRAMParameter();

    MandatoryOff("lms");

    // Doc example parameter settings
    SetDocExampleParameterValue("inp", "QB_Toulouse_Ortho_PAN.tif");
    SetDocExampleParameterValue("inxs", "QB_Toulouse_Ortho_XS.tif");
    SetDocExampleParameterValue("out", "BundleToPerfectSensor.png uchar");

  }

  void DoUpdateParameters()
  {
    // Nothing to do here : all parameters are independent
  }

  void DoExecute()
  {
    FloatVectorImageType* panchroV = GetParameterImage("inp");
    if ( panchroV->GetNumberOfComponentsPerPixel() != 1 )
      {
      itkExceptionMacro(<< "The panchromatic image must be a single channel image")
      }

    // Transform the PAN image to otb::Image
    typedef otb::Image<FloatVectorImageType::InternalPixelType> FloatImageType;
    typedef itk::VectorIndexSelectionCastImageFilter<FloatVectorImageType, FloatImageType> VectorIndexSelectionCastImageFilterType;

    VectorIndexSelectionCastImageFilterType::Pointer channelSelect = VectorIndexSelectionCastImageFilterType::New();
    m_Ref.push_back(channelSelect.GetPointer());
    channelSelect->SetIndex(0);
    channelSelect->SetInput(panchroV);
    channelSelect->UpdateOutputInformation();
    FloatImageType::Pointer panchro = channelSelect->GetOutput();

    FloatVectorImageType* xs = GetParameterImage("inxs");

    typedef otb::BCOInterpolateImageFunction<FloatVectorImageType> InterpolatorType;
    typedef otb::GenericRSResampleImageFilter<FloatVectorImageType, FloatVectorImageType>  ResamplerType;
    typedef otb::SimpleRcsPanSharpeningFusionImageFilter<FloatImageType, FloatVectorImageType, FloatVectorImageType> FusionFilterType;

    // Resample filter
    ResamplerType::Pointer    resampler = ResamplerType::New();
    m_Ref.push_back(resampler.GetPointer());

    InterpolatorType::Pointer interpolator = InterpolatorType::New();
    resampler->SetInterpolator(interpolator);

    // Setup the DEM Handler
    otb::Wrapper::ElevationParametersHandler::SetupDEMHandlerFromElevationParameters(this,"elev");

    // Set up output image informations
    FloatVectorImageType::SpacingType spacing = panchro->GetSpacing();
    FloatVectorImageType::IndexType   start = panchro->GetLargestPossibleRegion().GetIndex();
    FloatVectorImageType::SizeType    size = panchro->GetLargestPossibleRegion().GetSize();
    FloatVectorImageType::PointType   origin = panchro->GetOrigin();

    if(IsParameterEnabled("lms") && HasValue("lms"))
      {
      double defScalarSpacing = GetParameterFloat("lms");
      otbAppLogINFO(<< "Generating coarse deformation field (spacing="<<defScalarSpacing<<")" << std::endl);
      FloatVectorImageType::SpacingType defSpacing;

      defSpacing[0] = defScalarSpacing;
      defSpacing[1] = defScalarSpacing;

      resampler->SetDisplacementFieldSpacing(defSpacing);
      }
    else
      {
      FloatVectorImageType::SpacingType defSpacing;
      defSpacing[0]=10*spacing[0];
      defSpacing[1]=10*spacing[1];
      resampler->SetDisplacementFieldSpacing(defSpacing);
      }

    FloatVectorImageType::PixelType defaultValue;
    itk::NumericTraits<FloatVectorImageType::PixelType>::SetLength(defaultValue, xs->GetNumberOfComponentsPerPixel());

    resampler->SetInput(xs);
    resampler->SetOutputOrigin(origin);
    resampler->SetOutputSpacing(spacing);
    resampler->SetOutputSize(size);
    resampler->SetOutputStartIndex(start);
    resampler->SetOutputKeywordList(panchro->GetImageKeywordlist());
    resampler->SetOutputProjectionRef(panchro->GetProjectionRef());
    resampler->SetEdgePaddingValue(defaultValue);

    resampler->UpdateOutputInformation();
    FloatVectorImageType::Pointer xsResample = resampler->GetOutput();

    FusionFilterType::Pointer  fusionFilter = FusionFilterType::New();
    m_Ref.push_back(fusionFilter.GetPointer());

    fusionFilter->SetPanInput(panchro);
    fusionFilter->SetXsInput(resampler->GetOutput());
    fusionFilter->UpdateOutputInformation();

    SetParameterOutputImage("out", fusionFilter->GetOutput());
  }

  std::vector<itk::ProcessObject::Pointer> m_Ref;

};

}
}

OTB_APPLICATION_EXPORT(otb::Wrapper::BundleToPerfectSensor)
<commit_msg>ENH: OTB-626 : reproduce the superimposition method specific to PHR, (see Superimpose app)<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.

 =========================================================================*/
#include "otbWrapperApplication.h"
#include "otbWrapperApplicationFactory.h"

#include "itkVectorIndexSelectionCastImageFilter.h"
#include "otbGenericRSResampleImageFilter.h"
#include "otbBCOInterpolateImageFunction.h"
#include "otbSimpleRcsPanSharpeningFusionImageFilter.h"
#include "itkFixedArray.h"
#include "itkScalableAffineTransform.h"

// Elevation handler
#include "otbWrapperElevationParametersHandler.h"

#include "otbDateTimeAdapter.h"
#include "otbStreamingResampleImageFilter.h"
#include "otbPleiadesImageMetadataInterface.h"

namespace otb
{
namespace Wrapper
{

enum
{
  Mode_Default,
  Mode_PHR
};

class BundleToPerfectSensor : public Application
{
public:
  /** Standard class typedefs. */
  typedef BundleToPerfectSensor         Self;
  typedef Application                   Superclass;
  typedef itk::SmartPointer<Self>       Pointer;
  typedef itk::SmartPointer<const Self> ConstPointer;

  /** Standard macro */
  itkNewMacro(Self);

  itkTypeMacro(BundleToPerfectSensor, otb::Application);

private:

  void DoInit()
  {
    SetName("BundleToPerfectSensor");
    SetDescription("Perform P+XS pansharpening");

    // Documentation
    SetDocName("Bundle to perfect sensor");
    SetDocLongDescription("This application performs P+XS pansharpening.");
    SetDocLimitations("None");
    SetDocAuthors("OTB-Team");
    SetDocSeeAlso(" ");

    AddDocTag(Tags::Geometry);
    AddDocTag(Tags::Pansharpening);

    AddParameter(ParameterType_InputImage,   "inp",   "Input PAN Image");
    SetParameterDescription("inp"," Input panchromatic image.");
    AddParameter(ParameterType_InputImage,   "inxs",  "Input XS Image");
    SetParameterDescription("inxs"," Input XS image.");

    // Elevation
    ElevationParametersHandler::AddElevationParameters(this, "elev");

    // Superposition mode
    AddParameter(ParameterType_Choice,"mode", "Mode");
    SetParameterDescription("mode", "Superimposition mode");

    AddChoice("mode.default", "Default mode");
    SetParameterDescription("mode.default", "Default superimposition mode : "
      "uses any projection reference or sensor model found in the images");

    AddChoice("mode.phr", "Pleiades mode");
    SetParameterDescription("mode.phr", "Pleiades superimposition mode, "
      "designed for the case of a P+XS bundle in SENSOR geometry. It uses"
      " a simple transform : a scaling and a residual translation.");

    AddParameter(ParameterType_Float,        "lms",   "Spacing of the deformation field");
    SetParameterDescription("lms"," Spacing of the deformation field. Default is 10 times the PAN image spacing.");
    AddParameter(ParameterType_OutputImage,  "out",   "Output image");
    SetParameterDescription("out"," Output image.");
    AddRAMParameter();

    MandatoryOff("lms");

    // Doc example parameter settings
    SetDocExampleParameterValue("inp", "QB_Toulouse_Ortho_PAN.tif");
    SetDocExampleParameterValue("inxs", "QB_Toulouse_Ortho_XS.tif");
    SetDocExampleParameterValue("out", "BundleToPerfectSensor.png uchar");

  }

  void DoUpdateParameters()
  {
    if (!HasUserValue("mode") &&
        GetParameterInt("mode") == Mode_Default &&
        HasValue("inp") &&
        HasValue("inxs"))
      {
      FloatVectorImageType* refImage = GetParameterImage("inp");
      FloatVectorImageType* movingImage = GetParameterImage("inxs");
      bool isRefPHR = false;
      bool isMovingPHR = false;

      otb::PleiadesImageMetadataInterface::Pointer phrIMI =
        otb::PleiadesImageMetadataInterface::New();
      phrIMI->SetMetaDataDictionary(refImage->GetMetaDataDictionary());
      isRefPHR = phrIMI->CanRead();

      phrIMI->SetMetaDataDictionary(movingImage->GetMetaDataDictionary());
      isMovingPHR = phrIMI->CanRead();

      if (isRefPHR && isMovingPHR)
        {
        ImageKeywordlist kwlPan;
        ImageKeywordlist kwlXS;

        itk::ExposeMetaData<ImageKeywordlist>(
          refImage->GetMetaDataDictionary(),
          MetaDataKey::OSSIMKeywordlistKey,
          kwlPan);

        itk::ExposeMetaData<ImageKeywordlist>(
          movingImage->GetMetaDataDictionary(),
          MetaDataKey::OSSIMKeywordlistKey,
          kwlXS);

        // Get geometric processing
        std::string panProcessing = kwlPan.GetMetadataByKey("support_data.processing_level");
        std::string xsProcessing = kwlXS.GetMetadataByKey("support_data.processing_level");

        if (panProcessing.compare("SENSOR") == 0 &&
            xsProcessing.compare("SENSOR") == 0)
          {
          SetParameterInt("mode",Mode_PHR);
          }
        }
      }
  }

  void DoExecute()
  {
    FloatVectorImageType* panchroV = GetParameterImage("inp");
    if ( panchroV->GetNumberOfComponentsPerPixel() != 1 )
      {
      itkExceptionMacro(<< "The panchromatic image must be a single channel image")
      }

    // Transform the PAN image to otb::Image
    typedef otb::Image<FloatVectorImageType::InternalPixelType> FloatImageType;
    typedef itk::VectorIndexSelectionCastImageFilter<FloatVectorImageType, FloatImageType> VectorIndexSelectionCastImageFilterType;

    VectorIndexSelectionCastImageFilterType::Pointer channelSelect = VectorIndexSelectionCastImageFilterType::New();
    m_Ref.push_back(channelSelect.GetPointer());
    channelSelect->SetIndex(0);
    channelSelect->SetInput(panchroV);
    channelSelect->UpdateOutputInformation();
    FloatImageType::Pointer panchro = channelSelect->GetOutput();

    FloatVectorImageType* xs = GetParameterImage("inxs");

    typedef otb::BCOInterpolateImageFunction<FloatVectorImageType> InterpolatorType;
    typedef otb::GenericRSResampleImageFilter<FloatVectorImageType, FloatVectorImageType>  ResamplerType;
    typedef otb::StreamingResampleImageFilter<FloatVectorImageType, FloatVectorImageType>  BasicResamplerType;
    typedef otb::SimpleRcsPanSharpeningFusionImageFilter<FloatImageType, FloatVectorImageType, FloatVectorImageType> FusionFilterType;

    // Resample filter
    ResamplerType::Pointer    resampler = ResamplerType::New();
    m_Ref.push_back(resampler.GetPointer());

    BasicResamplerType::Pointer basicResampler = BasicResamplerType::New();
    m_Ref.push_back(basicResampler.GetPointer());

    InterpolatorType::Pointer interpolator = InterpolatorType::New();
    resampler->SetInterpolator(interpolator);
    basicResampler->SetInterpolator(interpolator);

    // Fusion filter
    FusionFilterType::Pointer  fusionFilter = FusionFilterType::New();
    m_Ref.push_back(fusionFilter.GetPointer());
    fusionFilter->SetPanInput(panchro);

    // Setup the DEM Handler
    otb::Wrapper::ElevationParametersHandler::SetupDEMHandlerFromElevationParameters(this,"elev");

    // Set up output image informations
    FloatVectorImageType::SpacingType spacing = panchro->GetSpacing();
    FloatVectorImageType::IndexType   start = panchro->GetLargestPossibleRegion().GetIndex();
    FloatVectorImageType::SizeType    size = panchro->GetLargestPossibleRegion().GetSize();
    FloatVectorImageType::PointType   origin = panchro->GetOrigin();

    FloatVectorImageType::PixelType defaultValue;
    itk::NumericTraits<FloatVectorImageType::PixelType>::SetLength(defaultValue, xs->GetNumberOfComponentsPerPixel());

    switch ( GetParameterInt("mode") )
    {
    case Mode_Default:
      {
      if(IsParameterEnabled("lms") && HasValue("lms"))
        {
        double defScalarSpacing = GetParameterFloat("lms");
        otbAppLogINFO(<< "Generating coarse deformation field (spacing="<<defScalarSpacing<<")" << std::endl);
        FloatVectorImageType::SpacingType defSpacing;

        defSpacing[0] = defScalarSpacing;
        defSpacing[1] = defScalarSpacing;

        resampler->SetDisplacementFieldSpacing(defSpacing);
        }
      else
        {
        FloatVectorImageType::SpacingType defSpacing;
        defSpacing[0]=10*spacing[0];
        defSpacing[1]=10*spacing[1];
        resampler->SetDisplacementFieldSpacing(defSpacing);
        }

      resampler->SetInput(xs);
      resampler->SetOutputOrigin(origin);
      resampler->SetOutputSpacing(spacing);
      resampler->SetOutputSize(size);
      resampler->SetOutputStartIndex(start);
      resampler->SetOutputKeywordList(panchro->GetImageKeywordlist());
      resampler->SetOutputProjectionRef(panchro->GetProjectionRef());
      resampler->SetEdgePaddingValue(defaultValue);
      //resampler->UpdateOutputInformation();
      // TODO : set the Input keywordlist and ProjRef manually ??
      fusionFilter->SetXsInput(resampler->GetOutput());
      //fusionFilter->UpdateOutputInformation();
      }
      break;
    case Mode_PHR:
      {
      otbAppLogINFO("Using the PHR mode");
      // Setup a simple affine transform using PHR support data
      ImageKeywordlist kwlPan;
      ImageKeywordlist kwlXS;

      itk::ExposeMetaData<ImageKeywordlist>(
        panchroV->GetMetaDataDictionary(),
        MetaDataKey::OSSIMKeywordlistKey,
        kwlPan);

      itk::ExposeMetaData<ImageKeywordlist>(
        xs->GetMetaDataDictionary(),
        MetaDataKey::OSSIMKeywordlistKey,
        kwlXS);

      // Compute time delta
      std::string strStartTimePan = kwlPan.GetMetadataByKey("support_data.time_range_start");
      std::string strStartTimeXS = kwlXS.GetMetadataByKey("support_data.time_range_start");

      DateTimeAdapter::Pointer startTimePan = DateTimeAdapter::New();
      DateTimeAdapter::Pointer startTimeXS = DateTimeAdapter::New();

      startTimePan->SetFromIso8601(strStartTimePan);
      startTimeXS->SetFromIso8601(strStartTimeXS);

      double timeDelta = startTimeXS->GetDeltaInSeconds(startTimePan);

      // Retrieve line period in Pan
      std::string tmpStr = kwlPan.GetMetadataByKey("support_data.line_period");
      double linePeriodPan = atof(tmpStr.c_str());

      // Retrieve column start
      tmpStr = kwlPan.GetMetadataByKey("support_data.swath_first_col");
      int colStartPan = atoi(tmpStr.c_str());
      tmpStr = kwlXS.GetMetadataByKey("support_data.swath_first_col");
      int colStartXS = atoi(tmpStr.c_str());

      // Compute shift between MS and P (in Pan pixels)
      int lineShift_MS_P =int(vcl_floor((timeDelta/(linePeriodPan/1000))  + 0.5));
      int colShift_MS_P = colStartXS*4 - colStartPan - 4;

      // Apply the scaling
      typedef itk::ScalableAffineTransform<double, 2>  TransformType;
      TransformType::Pointer transform = TransformType::New();
      transform->Scale(4.0);

      // Resample filter assumes the origin is attached to the pixel center
      // in order to keep the top left corners unchanged, apply a 3/2 pixels
      // shift in each direction
      // TODO : clarify formula, the '-1.0' for columns is strange
      TransformType::OutputVectorType offset;
      offset[0] = 1.5 + static_cast<double>(colShift_MS_P);
      offset[1] = 1.5 + static_cast<double>(lineShift_MS_P);
      transform->Translate(offset);

      // Invert the transform as the resampler filter expect an output-to-input
      // transform (we have computed the input-to-output transform)
      TransformType::Pointer realTransform = TransformType::New();
      transform->GetInverse(realTransform);
      basicResampler->SetTransform(realTransform);

      basicResampler->SetInput(xs);
      basicResampler->SetOutputOrigin(origin);
      basicResampler->SetOutputSpacing(spacing);
      basicResampler->SetOutputSize(size);
      basicResampler->SetOutputStartIndex(start);
      basicResampler->SetEdgePaddingValue(defaultValue);

      fusionFilter->SetXsInput(basicResampler->GetOutput());
      }
      break;
    default:
      {
      otbAppLogWARNING("Unknown mode");
      }
      break;
    }

    SetParameterOutputImage("out", fusionFilter->GetOutput());
  }

  std::vector<itk::ProcessObject::Pointer> m_Ref;

};

}
}

OTB_APPLICATION_EXPORT(otb::Wrapper::BundleToPerfectSensor)
<|endoftext|>


<commit_before>/*
The MIT License (MIT)

Copyright (c) 2013-2014 winlin

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#ifndef SRS_CORE_HPP
#define SRS_CORE_HPP

/*
#include <srs_core.hpp>
*/

// current release version
#define VERSION_MAJOR "0"
#define VERSION_MINOR "9"
#define VERSION_REVISION "191"
#define RTMP_SIG_SRS_VERSION VERSION_MAJOR"."VERSION_MINOR"."VERSION_REVISION
// server info.
#define RTMP_SIG_SRS_KEY "SRS"
#define RTMP_SIG_SRS_ROLE "origin/edge server"
#define RTMP_SIG_SRS_NAME RTMP_SIG_SRS_KEY"(Simple RTMP Server)"
#define RTMP_SIG_SRS_URL_SHORT "github.com/winlinvip/simple-rtmp-server"
#define RTMP_SIG_SRS_URL "https://"RTMP_SIG_SRS_URL_SHORT
#define RTMP_SIG_SRS_WEB "http://blog.csdn.net/win_lin"
#define RTMP_SIG_SRS_EMAIL "winlin@vip.126.com"
#define RTMP_SIG_SRS_LICENSE "The MIT License (MIT)"
#define RTMP_SIG_SRS_COPYRIGHT "Copyright (c) 2013-2014 winlin"
#define RTMP_SIG_SRS_PRIMARY_AUTHROS "winlin,wenjie.zhao"
#define RTMP_SIG_SRS_CONTRIBUTORS_URL RTMP_SIG_SRS_URL"/blob/master/AUTHORS.txt"

/**
* the core provides the common defined macros, utilities,
* user must include the srs_core.hpp before any header, or maybe
* build failed.
*/

// for 32bit os, 2G big file limit for unistd io,
// ie. read/write/lseek to use 64bits size for huge file.
#ifndef _FILE_OFFSET_BITS
    #define _FILE_OFFSET_BITS 64
#endif

// for int64_t print using PRId64 format.
#ifndef __STDC_FORMAT_MACROS
    #define __STDC_FORMAT_MACROS
#endif
#include <inttypes.h>

#include <assert.h>
#define srs_assert(expression) assert(expression)

#include <stddef.h>
#include <sys/types.h>

// generated by configure.
#include <srs_auto_headers.hpp>

// free the p and set to NULL.
// p must be a T*.
#define srs_freep(p) \
    if (p) { \
        delete p; \
        p = NULL; \
    } \
    (void)0
// sometimes, the freepa is useless,
// it's recomments to free each elem explicit.
// so we remove the srs_freepa utility.

/**
* disable copy constructor of class,
* to avoid the memory leak or corrupt by copy instance.
*/
#define disable_default_copy(className)\
    private:\
        /** \
        * disable the copy constructor and operator=, donot allow directly copy. \
        */ \
        className(const className&); \
        className& operator= (const className&)

#endif

<commit_msg>change to 0.9.192.<commit_after>/*
The MIT License (MIT)

Copyright (c) 2013-2014 winlin

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#ifndef SRS_CORE_HPP
#define SRS_CORE_HPP

/*
#include <srs_core.hpp>
*/

// current release version
#define VERSION_MAJOR "0"
#define VERSION_MINOR "9"
#define VERSION_REVISION "192"
#define RTMP_SIG_SRS_VERSION VERSION_MAJOR"."VERSION_MINOR"."VERSION_REVISION
// server info.
#define RTMP_SIG_SRS_KEY "SRS"
#define RTMP_SIG_SRS_ROLE "origin/edge server"
#define RTMP_SIG_SRS_NAME RTMP_SIG_SRS_KEY"(Simple RTMP Server)"
#define RTMP_SIG_SRS_URL_SHORT "github.com/winlinvip/simple-rtmp-server"
#define RTMP_SIG_SRS_URL "https://"RTMP_SIG_SRS_URL_SHORT
#define RTMP_SIG_SRS_WEB "http://blog.csdn.net/win_lin"
#define RTMP_SIG_SRS_EMAIL "winlin@vip.126.com"
#define RTMP_SIG_SRS_LICENSE "The MIT License (MIT)"
#define RTMP_SIG_SRS_COPYRIGHT "Copyright (c) 2013-2014 winlin"
#define RTMP_SIG_SRS_PRIMARY_AUTHROS "winlin,wenjie.zhao"
#define RTMP_SIG_SRS_CONTRIBUTORS_URL RTMP_SIG_SRS_URL"/blob/master/AUTHORS.txt"

/**
* the core provides the common defined macros, utilities,
* user must include the srs_core.hpp before any header, or maybe
* build failed.
*/

// for 32bit os, 2G big file limit for unistd io,
// ie. read/write/lseek to use 64bits size for huge file.
#ifndef _FILE_OFFSET_BITS
    #define _FILE_OFFSET_BITS 64
#endif

// for int64_t print using PRId64 format.
#ifndef __STDC_FORMAT_MACROS
    #define __STDC_FORMAT_MACROS
#endif
#include <inttypes.h>

#include <assert.h>
#define srs_assert(expression) assert(expression)

#include <stddef.h>
#include <sys/types.h>

// generated by configure.
#include <srs_auto_headers.hpp>

// free the p and set to NULL.
// p must be a T*.
#define srs_freep(p) \
    if (p) { \
        delete p; \
        p = NULL; \
    } \
    (void)0
// sometimes, the freepa is useless,
// it's recomments to free each elem explicit.
// so we remove the srs_freepa utility.

/**
* disable copy constructor of class,
* to avoid the memory leak or corrupt by copy instance.
*/
#define disable_default_copy(className)\
    private:\
        /** \
        * disable the copy constructor and operator=, donot allow directly copy. \
        */ \
        className(const className&); \
        className& operator= (const className&)

#endif

<|endoftext|>


<commit_before>/*M///////////////////////////////////////////////////////////////////////////////////////
//
//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
//  By downloading, copying, installing or using the software you agree to this license.
//  If you do not agree to this license, do not download, install,
//  copy or use the software.
//
//
//                          License Agreement
//                For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistribution's of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//
//   * Redistribution's in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//
//   * The name of the copyright holders may not be used to endorse or promote products
//     derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/

#include "test_precomp.hpp"
#include "opencv2/highgui/highgui.hpp"

#ifdef HAVE_FFMPEG

#include "ffmpeg_codecs.hpp"

using namespace cv;
using namespace std;

class CV_PositioningTest : public cvtest::BaseTest
{
public:
    void CreateTestVideo(const string& format, int codec, int framecount = 125);
    void run(int);
};

void CV_PositioningTest::CreateTestVideo(const string& format, int codec, int framecount)
{
 stringstream s; s << codec;

 cv::VideoWriter writer(ts->get_data_path()+"video/test_video_"+s.str()+"."+format, codec, 25, cv::Size(640, 480), false);

 for (int i = 0; i < framecount; ++i)
 {
   cv::Mat mat(480, 640, CV_8UC1);
   size_t n = 32, tmp = i;

   vector<char> tmp_code; tmp_code.clear();

   while ( tmp > 1 )
   {
       tmp_code.push_back(tmp%2);
       tmp /= 2;
   }
   tmp_code.push_back(tmp);

   vector<char> i_code;

   for (size_t j = 0; j < n; ++j)
   {
    char val = j < n - tmp_code.size() ? 0 : tmp_code.at(n-1-j);
    i_code.push_back(val);
   }

   const size_t w = 480/n;

   for (size_t j = 0; j < n; ++j)
   {
       cv::Scalar color = i_code[j] ? 255 : 0;
       rectangle(mat, Rect(0, w*j, 640, w), color, -1);
   }

   writer << mat;
 }

 writer.~VideoWriter();
}

void CV_PositioningTest::run(int)
{
#if defined WIN32 || (defined __linux__ && !defined ANDROID)
#if !defined HAVE_GSTREAMER || defined HAVE_GSTREAMER_APP

    const string format[] =  {"avi", "mov", "mp4", "mpg", "wmv", "3gp"};

    const char codec[][4] = { {'X', 'V', 'I', 'D'},
                              {'M', 'P', 'G', '2'},
                              {'M', 'J', 'P', 'G'} };

    size_t n_format = sizeof(format)/sizeof(format[0]),
           n_codec = sizeof(codec)/sizeof(codec[0]);

    for (size_t i = 0; i < n_format; ++i)
    for (size_t j = 0; j < n_codec; ++j)
    {
      CreateTestVideo(format[i], CV_FOURCC(codec[j][0], codec[j][1], codec[j][2], codec[j][3]), 125);

      stringstream s; s << CV_FOURCC(codec[j][0], codec[j][1], codec[j][2], codec[j][3]); //codec_bmp_tags[j].tag;

      const string file_path = ts->get_data_path()+"video/test_video_"+s.str()+"."+format[i];

      bool error = false; int failed = 0;

      cv::VideoCapture cap(file_path);

      if (!cap.isOpened())
      {
        ts->printf(ts->LOG, "\nFile: %s\n", file_path.c_str());
        ts->printf(ts->LOG, "\nVideo codec: %s\n", string(&codec[j][0], 4).c_str());
        ts->printf(ts->LOG, "\nError: cannot read video file.\n");
        ts->set_failed_test_info(ts->FAIL_INVALID_TEST_DATA);
        error = true;
      }

      cap.set(CV_CAP_PROP_POS_FRAMES, 0);

      int N = cap.get(CV_CAP_PROP_FRAME_COUNT);

      if (N != 125)
      {
        if (!error)
        {
            ts->printf(ts->LOG, "\nFile: %s\n", file_path.c_str());
            ts->printf(ts->LOG, "\nVideo codec: %s\n", string(&codec[j][0], 4).c_str());
            error = true;
        }
        ts->printf(ts->LOG, "\nError: returned frame count in clip is incorrect.\n");
        ts->set_failed_test_info(ts->FAIL_INVALID_OUTPUT);
      }

      vector <int> idx;

      RNG rng(N);
      idx.clear();
      for( int k = 0; k < N-1; k++ )
      idx.push_back(rng.uniform(0, N));
      idx.push_back(N-1);
      std::swap(idx.at(rng.uniform(0, N-1)), idx.at(N-1));

      for (int k = 0; k < N; ++k)
      {
        cap.set(CV_CAP_PROP_POS_FRAMES, (double)idx[k]);

        cv::Mat img; cap.retrieve(img);

        if (img.empty())
        {
            if (!error)
            {
                ts->printf(ts->LOG, "\nFile: %s\n", file_path.c_str());
                ts->printf(ts->LOG, "\nVideo codec: %s\n", string(&codec[j][0], 4).c_str());
                error = true;
            }
            ts->printf(ts->LOG, "\nError: cannot read a frame in position %d.\n", idx[k]);
            ts->set_failed_test_info(ts->FAIL_EXCEPTION);
        }

        const double thresh = 100;

        const size_t n = 32, w = img.rows/n;

        int index = 0, deg = n-1;

        for (size_t l = 0; l < n; ++l)
        {
            cv::Mat mat = img.rowRange(w*l, w*(l+1)-1);

            Scalar mat_mean = cv::mean(mat);

            if (mat_mean[0] > thresh) index += (int)std::pow(2.0, 1.0*deg);

            deg--;
        }

        if (index != idx[k])
        {
            if (!error)
            {
                ts->printf(ts->LOG, "\nFile: %s\n", file_path.c_str());
                ts->printf(ts->LOG, "\nVideo codec: %s\n\n", string(&codec[j][0], 4).c_str());
                error = true;
            }
            ts->printf(ts->LOG, "Required position: %d   Returned position: %d FAILED\n", idx[k], index);
            ts->set_failed_test_info(ts->FAIL_INVALID_OUTPUT);
            failed++;
        }
      }

      if (!error) ts->printf(ts->LOG, "\nFile: %s\n", file_path.c_str());

      ts->printf(ts->LOG, "\nSuccessfull iterations: %d(%d%%)   Failed iterations: %d(%d%%)\n", N-failed, (N-failed)*100/N, failed, failed*100/N);
      ts->printf(ts->LOG, "\n----------\n");
    }

#endif
#endif
}

TEST(Highgui_Positioning, regression) { CV_PositioningTest test; test.safe_run(); }

#endif
<commit_msg>Updated test_video_pos.cpp<commit_after>/*M///////////////////////////////////////////////////////////////////////////////////////
//
//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
//  By downloading, copying, installing or using the software you agree to this license.
//  If you do not agree to this license, do not download, install,
//  copy or use the software.
//
//
//                          License Agreement
//                For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistribution's of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//
//   * Redistribution's in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//
//   * The name of the copyright holders may not be used to endorse or promote products
//     derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/

#include "test_precomp.hpp"
#include "opencv2/highgui/highgui.hpp"

#ifdef HAVE_FFMPEG

#include "ffmpeg_codecs.hpp"

using namespace cv;
using namespace std;

class CV_PositioningTest : public cvtest::BaseTest
{
public:
    void CreateTestVideo(const string& format, int codec, int framecount = 125);
    void run(int);
};

void CV_PositioningTest::CreateTestVideo(const string& format, int codec, int framecount)
{
 stringstream s; s << codec;

 cv::VideoWriter writer(ts->get_data_path()+"video/test_video_"+s.str()+"."+format, codec, 25, cv::Size(640, 480), false);

 for (int i = 0; i < framecount; ++i)
 {
   cv::Mat mat(480, 640, CV_8UC1);
   size_t n = 8, tmp = i;

   vector<char> tmp_code; tmp_code.clear();

   while ( tmp > 1 )
   {
       tmp_code.push_back(tmp%2);
       tmp /= 2;
   }
   tmp_code.push_back(tmp);

   vector<char> i_code;

   for (size_t j = 0; j < n; ++j)
   {
    char val = j < n - tmp_code.size() ? 0 : tmp_code.at(n-1-j);
    i_code.push_back(val);
   }

   const size_t w = 480/n;

   for (size_t j = 0; j < n; ++j)
   {
       cv::Scalar color = i_code[j] ? 255 : 0;
       rectangle(mat, Rect(0, w*j, 640, w), color, -1);
   }

   writer << mat;
 }

 writer.~VideoWriter();
}

void CV_PositioningTest::run(int)
{
#if defined WIN32 || (defined __linux__ && !defined ANDROID)
#if !defined HAVE_GSTREAMER || defined HAVE_GSTREAMER_APP

    const string format[] =  {"avi", "mov", "mp4", "mpg", "wmv", "3gp"};

    const char codec[][4] = { {'X', 'V', 'I', 'D'},
                              {'M', 'P', 'G', '2'},
                              {'M', 'J', 'P', 'G'} };

    size_t n_format = sizeof(format)/sizeof(format[0]),
           n_codec = sizeof(codec)/sizeof(codec[0]);

    int n_frames = 256;

    for (size_t i = 0; i < n_format; ++i)
    for (size_t j = 0; j < n_codec; ++j)
    {
      CreateTestVideo(format[i], CV_FOURCC(codec[j][0], codec[j][1], codec[j][2], codec[j][3]), n_frames);

      stringstream s; s << CV_FOURCC(codec[j][0], codec[j][1], codec[j][2], codec[j][3]); //codec_bmp_tags[j].tag;

      const string file_path = ts->get_data_path()+"video/test_video_"+s.str()+"."+format[i];

      bool error = false; int failed = 0;

      cv::VideoCapture cap(file_path);

      if (!cap.isOpened())
      {
        ts->printf(ts->LOG, "\n\nFile: %s\n", file_path.c_str());
        ts->printf(ts->LOG, "\nVideo codec: %s\n", string(&codec[j][0], 4).c_str());
        ts->printf(ts->LOG, "\nError: cannot read video file.");
        ts->set_failed_test_info(ts->FAIL_INVALID_TEST_DATA);
        error = true;
      }

      cap.set(CV_CAP_PROP_POS_FRAMES, 0);

      int N = cap.get(CV_CAP_PROP_FRAME_COUNT);

      if (N != n_frames)
      {
        if (!error)
        {
            ts->printf(ts->LOG, "\n\nFile: %s\n", file_path.c_str());
            ts->printf(ts->LOG, "\nVideo codec: %s\n", string(&codec[j][0], 4).c_str());
            error = true;
        }
        ts->printf(ts->LOG, "\nError: returned frame count in clip is incorrect.\n");
        ts->set_failed_test_info(ts->FAIL_INVALID_OUTPUT);
      }

      vector <int> idx;

      RNG rng(N);
      idx.clear();
      for( int k = 0; k < N-1; k++ )
      idx.push_back(rng.uniform(0, N));
      idx.push_back(N-1);
      std::swap(idx.at(rng.uniform(0, N-1)), idx.at(N-1));

      for (int k = 0; k < N; ++k)
      {
        cap.set(CV_CAP_PROP_POS_FRAMES, (double)idx[k]);

        cv::Mat img; cap.retrieve(img);

        if (img.empty())
        {
            if (!error)
            {
                ts->printf(ts->LOG, "\n\nFile: %s\n", file_path.c_str());
                ts->printf(ts->LOG, "\nVideo codec: %s\n", string(&codec[j][0], 4).c_str());
                error = true;
            }
            ts->printf(ts->LOG, "\nError: cannot read a frame in position %d.\n", idx[k]);
            ts->set_failed_test_info(ts->FAIL_INVALID_OUTPUT);
        }

        const double thresh = 100;

        const size_t n = 8, w = img.rows/n;

        int index = 0, deg = n-1;

        for (size_t l = 0; l < n; ++l)
        {
            cv::Mat mat = img.rowRange(w*l, w*(l+1)-1);

            Scalar mat_mean = cv::mean(mat);

            if (mat_mean[0] > thresh) index += (int)std::pow(2.0, 1.0*deg);

            deg--;
        }

        if (index != idx[k])
        {
            if (!error)
            {
                ts->printf(ts->LOG, "\n\nFile: %s\n", file_path.c_str());
                ts->printf(ts->LOG, "\nVideo codec: %s\n\n", string(&codec[j][0], 4).c_str());
                error = true;
            }
            ts->printf(ts->LOG, "Required position: %d   Returned position: %d\n", idx[k], index);
            ts->set_failed_test_info(ts->FAIL_INVALID_OUTPUT);
            failed++;
        }
      }

      if (!error) { ts->printf(ts->LOG, "\n\nFile: %s\n", file_path.c_str());
                    ts->printf(ts->LOG, "\nVideo codec: %s\n", string(&codec[j][0], 4).c_str()); }

      const string status = failed ? "FAILED" : "OK";
      ts->printf(ts->LOG, "\nSuccessfull iterations: %d(%d%%)   Failed iterations: %d(%d%%)   %s\n", N-failed, (N-failed)*100/N, failed, failed*100/N, status.c_str());
      if( i < n_format-1 || j < n_codec-1 ) ts->printf(ts->LOG, "\n----------");
    }

#endif
#endif
}

TEST(Highgui_Positioning, regression) { CV_PositioningTest test; test.safe_run(); }

#endif
<|endoftext|>


<commit_before>//
//  68000Mk2Implementation.hpp
//  Clock Signal
//
//  Created by Thomas Harte on 16/05/2022.
//  Copyright © 2022 Thomas Harte. All rights reserved.
//

#ifndef _8000Mk2Implementation_h
#define _8000Mk2Implementation_h

#include <cassert>
#include <cstdio>

namespace CPU {
namespace MC68000Mk2 {

// MARK: - The state machine.

template <class BusHandler, bool dtack_is_implicit, bool permit_overrun, bool signal_will_perform>
void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perform>::run_for(HalfCycles duration) {
	// Accumulate the newly paid-in cycles. If this instance remains in deficit, exit.
	time_remaining_ += duration;
	if(time_remaining_ <= HalfCycles(0)) return;

	// Check whether all remaining time has been expended; if so then exit, having set this line up as
	// the next resumption point.
#define ConsiderExit()	if(time_remaining_ <= HalfCycles(0)) { state_ = __COUNTER__+1; return; } [[fallthrough]]; case __COUNTER__:

	// Subtracts `n` half-cycles from `time_remaining_`; if permit_overrun is false, also ConsiderExit()
#define Spend(n)		time_remaining_ -= (n); if constexpr (!permit_overrun) ConsiderExit()

	// Performs ConsiderExit() only if permit_overrun is true.
#define CheckOverrun()	if constexpr (permit_overrun) ConsiderExit()

	// Sets `x` as the next state, and exits now if all remaining time has been extended and permit_overrun is true.
#define MoveToState(x)	state_ = (x); if (permit_overrun && time_remaining_ <= HalfCycles(0)) return

	//
	// So basic structure is, in general:
	//
	//	case Action:
	//		do_something();
	//		Spend(20);
	//		do_something_else();
	//		Spend(10);
	//		do_a_third_thing();
	//		Spend(30);
	//
	//		MoveToState(next_action);
	//		break;
	//
	// Additional notes:
	//
	//	Action and all equivalents should be negative values, since the
	//	switch-for-computed-goto-for-a-coroutine structure uses __COUNTER__* for
	//	its invented entry- and exit-points, meaning that negative numbers are
	//	the easiest group that is safely definitely never going to collide.
	//
	//	(* an extension supported by at least GCC, Clang and MSVC)

	// Spare containers:
	HalfCycles delay;		// To receive any additional time added on by calls to perform_bus_operation.

	// Helper macros for common bus transactions:

	// Performs the bus operation and then applies a `Spend` of its length
	// plus any additional length returned by the bus handler.
#define PerformBusOperation(x)										\
	delay = bus_handler_.perform_bus_operation(x, is_supervisor_);	\
	Spend(x.length + delay)

	// Performs no bus activity for the specified number of microcycles.
#define IdleBus(n)						\
	idle.length = HalfCycles(n * 4);	\
	PerformBusOperation(idle)

	// Spin until DTACK, VPA or BERR is asserted (unless DTACK is implicit),
	// holding the bus cycle provided.
#define WaitForDTACK(x)													\
	if constexpr (!dtack_is_implicit && !dtack_ && !vpa_ && !berr_) {	\
		awaiting_dtack = x;												\
		awaiting_dtack.length = HalfCycles(2);							\
		post_dtack_state_ = __COUNTER__+1;								\
		state_ = State::WaitForDTACK;									\
		break;															\
	}																	\
	[[fallthrough]]; case __COUNTER__:

	// Performs the bus operation provided, which will be one with a
	// SelectWord or SelectByte operation, stretching it to match the E
	// bus if VPA is currently asserted.
	//
	// TODO: If BERR is asserted, stop here and perform a bus error exception.
	//
	// TODO: If VPA is asserted, stretch this cycle.
#define CompleteAccess(x)												\
	PerformBusOperation(x)

	// Performs the memory access implied by the announce, perform pair,
	// honouring DTACK, BERR and VPA as necessary.
#define AccessPair(addr, val, announce, perform)	\
	announce.address = perform.address = &addr;		\
	perform.value = &val;							\
	if constexpr (!dtack_is_implicit) {				\
		announce.length = HalfCycles(4);			\
	}												\
	PerformBusOperation(announce);					\
	WaitForDTACK(announce);							\
	CompleteAccess(perform);

	// Reads the data (i.e. non-program) word from addr into val.
#define ReadDataWord(addr, val)										\
	AccessPair(addr, val, read_word_data_announce, read_word_data)

	// Reads the program (i.e. non-data) word from addr into val.
#define ReadProgramWord(val)													\
	AccessPair(program_counter_.l, val, read_program_announce, read_program);	\
	program_counter_.l += 2;

	// Reads one futher word from the program counter and inserts it into
	// the prefetch queue.
#define Prefetch()					\
	prefetch_.high = prefetch_.low;	\
	ReadProgramWord(prefetch_.low)

	using Mode = InstructionSet::M68k::AddressingMode;

	// Otherwise continue for all time, until back in debt.
	// Formatting is slightly obtuse here to make this look more like a coroutine.
	while(true) { switch(state_) {

		// Spin in place, one cycle at a time, until one of DTACK,
		// BERR or VPA is asserted.
		case State::WaitForDTACK:
			PerformBusOperation(awaiting_dtack);

			if(dtack_ || berr_ || vpa_) {
				state_ = post_dtack_state_;
			}
		break;

		// Perform the RESET exception, which seeds the stack pointer and program
		// counter, populates the prefetch queue, and then moves to instruction dispatch.
		case State::Reset:
			IdleBus(7);			// (n-)*5   nn

			// Establish general reset state.
			status_.is_supervisor = true;
			status_.interrupt_level = 7;
			status_.trace_flag = 0;
			did_update_status();

			temporary_address_ = 0;
			ReadDataWord(temporary_address_, registers_[15].high);		// nF

			temporary_address_ += 2;
			ReadDataWord(temporary_address_, registers_[15].low);		// nf

			temporary_address_ += 2;
			ReadDataWord(temporary_address_, program_counter_.high);	// nV

			temporary_address_ += 2;
			ReadDataWord(temporary_address_, program_counter_.low);		// nv

			Prefetch();			// np
			IdleBus(1);			// n
			Prefetch();			// np

			MoveToState(State::Decode);
		break;

		// Inspect the prefetch queue in order to decode the next instruction,
		// and segue into the fetching of operands.
		case State::Decode:
			opcode_ = prefetch_.high.w;
			instruction_ = decoder_.decode(opcode_);
			instruction_address_ = program_counter_.l - 4;

			// TODO: check for privilege and unrecognised instructions.

			// Signal the bus handler if requested.
			if constexpr (signal_will_perform) {
				bus_handler_.will_perform(instruction_address_, opcode_);
			}

			// Obtain operand flags and pick a perform pattern.
			setup_operation();

			// Ensure the first parameter is next fetched.
			next_operand_ = 0;
		[[fallthrough]];

		// Check the operand flags to determine whether the operand at index
		// operand_ needs to be fetched, and if so then calculate the EA and
		// do so.
		//
		// Per Yacht, all instructions other than MOVE.[b/w/;] will read all
		// relevant operands — even when that's a useless endeavour, such as
		// for CLR or MOVE SR, <ea>.
		//
		// TODO: add MOVE special case, somewhere.
		case State::FetchOperand:
			switch(instruction_.mode(next_operand_)) {
				case Mode::None:
					state_ = perform_state_;
				continue;

				case Mode::AddressRegisterDirect:
				case Mode::DataRegisterDirect:
					operand_[next_operand_] = registers_[instruction_.lreg(next_operand_)];
					++next_operand_;
					state_ = next_operand_ == 2 ? perform_state_ : State::FetchOperand;
				continue;

				default:
					assert(false);
			}
		break;

		// Store operand is a lot simpler: only one operand is ever stored, and its address
		// is already known. So this can either skip straight back to ::Decode if the target
		// is a register, otherwise a single write operation can occur.
		case State::StoreOperand:
			if(instruction_.mode(next_operand_) <= Mode::AddressRegisterDirect) {
				registers_[instruction_.lreg(next_operand_)] = operand_[next_operand_];
				state_ = State::Decode;
				continue;
			}

			// TODO: make a decision on how I'm going to deal with byte/word/longword.
			assert(false);
		break;

		//
		// Various forms of perform.
		//
#define MoveToWritePhase()														\
	next_operand_ = operand_flags_ >> 3;										\
	MoveToState(operand_flags_ & 0x0c ? State::StoreOperand : State::Decode)

		case State::Perform_np:
			InstructionSet::M68k::perform<InstructionSet::M68k::Model::M68000>(
				instruction_, operand_[0], operand_[1], status_, *static_cast<ProcessorBase *>(this));
			Prefetch();			// np

			MoveToWritePhase();
		break;

		case State::Perform_np_n:
			InstructionSet::M68k::perform<InstructionSet::M68k::Model::M68000>(
				instruction_, operand_[0], operand_[1], status_, *static_cast<ProcessorBase *>(this));
			Prefetch();			// np
			IdleBus(1);			// n

			MoveToWritePhase();
		break;

#undef MoveToWritePhase

		default:
			printf("Unhandled state: %d\n", state_);
			assert(false);
	}}

#undef Prefetch
#undef ReadProgramWord
#undef ReadDataWord
#undef AccessPair
#undef CompleteAccess
#undef WaitForDTACK
#undef IdleBus
#undef PerformBusOperation
#undef MoveToState
#undef CheckOverrun
#undef Spend
#undef ConsiderExit

}

// MARK: - Operation specifications.

template <class BusHandler, bool dtack_is_implicit, bool permit_overrun, bool signal_will_perform>
void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perform>::setup_operation() {

#define BIND(x, p)	\
	case InstructionSet::M68k::Operation::x:			\
		operand_flags_ = InstructionSet::M68k::operand_flags<InstructionSet::M68k::Model::M68000, InstructionSet::M68k::Operation::x>();	\
		perform_state_ = p;	\
	break;

	using Mode = InstructionSet::M68k::AddressingMode;

	switch(instruction_.operation) {
		BIND(NBCD, instruction_.mode(0) == Mode::DataRegisterDirect ? State::Perform_np_n : State::Perform_np);

		default:
			assert(false);
	}

#undef BIND
}

// MARK: - Flow Controller.

void ProcessorBase::did_update_status() {
	// Shuffle the stack pointers.
	stack_pointers_[is_supervisor_] = registers_[7];
	registers_[7] = stack_pointers_[int(status_.is_supervisor)];
	is_supervisor_ = int(status_.is_supervisor);
}

// MARK: - External state.

template <class BusHandler, bool dtack_is_implicit, bool permit_overrun, bool signal_will_perform>
CPU::MC68000Mk2::State Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perform>::get_state() {
	return CPU::MC68000Mk2::State();
}

template <class BusHandler, bool dtack_is_implicit, bool permit_overrun, bool signal_will_perform>
void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perform>::set_state(const CPU::MC68000Mk2::State &) {
}

}
}

#endif /* _8000Mk2Implementation_h */
<commit_msg>Add enough of state to [sort-of] pass the first test.<commit_after>//
//  68000Mk2Implementation.hpp
//  Clock Signal
//
//  Created by Thomas Harte on 16/05/2022.
//  Copyright © 2022 Thomas Harte. All rights reserved.
//

#ifndef _8000Mk2Implementation_h
#define _8000Mk2Implementation_h

#include <cassert>
#include <cstdio>

namespace CPU {
namespace MC68000Mk2 {

// MARK: - The state machine.

template <class BusHandler, bool dtack_is_implicit, bool permit_overrun, bool signal_will_perform>
void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perform>::run_for(HalfCycles duration) {
	// Accumulate the newly paid-in cycles. If this instance remains in deficit, exit.
	time_remaining_ += duration;
	if(time_remaining_ <= HalfCycles(0)) return;

	// Check whether all remaining time has been expended; if so then exit, having set this line up as
	// the next resumption point.
#define ConsiderExit()	if(time_remaining_ <= HalfCycles(0)) { state_ = __COUNTER__+1; return; } [[fallthrough]]; case __COUNTER__:

	// Subtracts `n` half-cycles from `time_remaining_`; if permit_overrun is false, also ConsiderExit()
#define Spend(n)		time_remaining_ -= (n); if constexpr (!permit_overrun) ConsiderExit()

	// Performs ConsiderExit() only if permit_overrun is true.
#define CheckOverrun()	if constexpr (permit_overrun) ConsiderExit()

	// Sets `x` as the next state, and exits now if all remaining time has been extended and permit_overrun is true.
#define MoveToState(x)	state_ = (x); if (permit_overrun && time_remaining_ <= HalfCycles(0)) return

	//
	// So basic structure is, in general:
	//
	//	case Action:
	//		do_something();
	//		Spend(20);
	//		do_something_else();
	//		Spend(10);
	//		do_a_third_thing();
	//		Spend(30);
	//
	//		MoveToState(next_action);
	//		break;
	//
	// Additional notes:
	//
	//	Action and all equivalents should be negative values, since the
	//	switch-for-computed-goto-for-a-coroutine structure uses __COUNTER__* for
	//	its invented entry- and exit-points, meaning that negative numbers are
	//	the easiest group that is safely definitely never going to collide.
	//
	//	(* an extension supported by at least GCC, Clang and MSVC)

	// Spare containers:
	HalfCycles delay;		// To receive any additional time added on by calls to perform_bus_operation.

	// Helper macros for common bus transactions:

	// Performs the bus operation and then applies a `Spend` of its length
	// plus any additional length returned by the bus handler.
#define PerformBusOperation(x)										\
	delay = bus_handler_.perform_bus_operation(x, is_supervisor_);	\
	Spend(x.length + delay)

	// Performs no bus activity for the specified number of microcycles.
#define IdleBus(n)						\
	idle.length = HalfCycles(n * 4);	\
	PerformBusOperation(idle)

	// Spin until DTACK, VPA or BERR is asserted (unless DTACK is implicit),
	// holding the bus cycle provided.
#define WaitForDTACK(x)													\
	if constexpr (!dtack_is_implicit && !dtack_ && !vpa_ && !berr_) {	\
		awaiting_dtack = x;												\
		awaiting_dtack.length = HalfCycles(2);							\
		post_dtack_state_ = __COUNTER__+1;								\
		state_ = State::WaitForDTACK;									\
		break;															\
	}																	\
	[[fallthrough]]; case __COUNTER__:

	// Performs the bus operation provided, which will be one with a
	// SelectWord or SelectByte operation, stretching it to match the E
	// bus if VPA is currently asserted.
	//
	// TODO: If BERR is asserted, stop here and perform a bus error exception.
	//
	// TODO: If VPA is asserted, stretch this cycle.
#define CompleteAccess(x)												\
	PerformBusOperation(x)

	// Performs the memory access implied by the announce, perform pair,
	// honouring DTACK, BERR and VPA as necessary.
#define AccessPair(addr, val, announce, perform)	\
	announce.address = perform.address = &addr;		\
	perform.value = &val;							\
	if constexpr (!dtack_is_implicit) {				\
		announce.length = HalfCycles(4);			\
	}												\
	PerformBusOperation(announce);					\
	WaitForDTACK(announce);							\
	CompleteAccess(perform);

	// Reads the data (i.e. non-program) word from addr into val.
#define ReadDataWord(addr, val)										\
	AccessPair(addr, val, read_word_data_announce, read_word_data)

	// Reads the program (i.e. non-data) word from addr into val.
#define ReadProgramWord(val)													\
	AccessPair(program_counter_.l, val, read_program_announce, read_program);	\
	program_counter_.l += 2;

	// Reads one futher word from the program counter and inserts it into
	// the prefetch queue.
#define Prefetch()					\
	prefetch_.high = prefetch_.low;	\
	ReadProgramWord(prefetch_.low)

	using Mode = InstructionSet::M68k::AddressingMode;

	// Otherwise continue for all time, until back in debt.
	// Formatting is slightly obtuse here to make this look more like a coroutine.
	while(true) { switch(state_) {

		// Spin in place, one cycle at a time, until one of DTACK,
		// BERR or VPA is asserted.
		case State::WaitForDTACK:
			PerformBusOperation(awaiting_dtack);

			if(dtack_ || berr_ || vpa_) {
				state_ = post_dtack_state_;
			}
		break;

		// Perform the RESET exception, which seeds the stack pointer and program
		// counter, populates the prefetch queue, and then moves to instruction dispatch.
		case State::Reset:
			IdleBus(7);			// (n-)*5   nn

			// Establish general reset state.
			status_.is_supervisor = true;
			status_.interrupt_level = 7;
			status_.trace_flag = 0;
			did_update_status();

			temporary_address_ = 0;
			ReadDataWord(temporary_address_, registers_[15].high);		// nF

			temporary_address_ += 2;
			ReadDataWord(temporary_address_, registers_[15].low);		// nf

			temporary_address_ += 2;
			ReadDataWord(temporary_address_, program_counter_.high);	// nV

			temporary_address_ += 2;
			ReadDataWord(temporary_address_, program_counter_.low);		// nv

			Prefetch();			// np
			IdleBus(1);			// n
			Prefetch();			// np

			MoveToState(State::Decode);
		break;

		// Inspect the prefetch queue in order to decode the next instruction,
		// and segue into the fetching of operands.
		case State::Decode:
			opcode_ = prefetch_.high.w;
			instruction_ = decoder_.decode(opcode_);
			instruction_address_ = program_counter_.l - 4;

			// TODO: check for privilege and unrecognised instructions.

			// Signal the bus handler if requested.
			if constexpr (signal_will_perform) {
				bus_handler_.will_perform(instruction_address_, opcode_);
			}

			// Obtain operand flags and pick a perform pattern.
			setup_operation();

			// Ensure the first parameter is next fetched.
			next_operand_ = 0;
		[[fallthrough]];

		// Check the operand flags to determine whether the operand at index
		// operand_ needs to be fetched, and if so then calculate the EA and
		// do so.
		//
		// Per Yacht, all instructions other than MOVE.[b/w/;] will read all
		// relevant operands — even when that's a useless endeavour, such as
		// for CLR or MOVE SR, <ea>.
		//
		// TODO: add MOVE special case, somewhere.
		case State::FetchOperand:
			switch(instruction_.mode(next_operand_)) {
				case Mode::None:
					state_ = perform_state_;
				continue;

				case Mode::AddressRegisterDirect:
				case Mode::DataRegisterDirect:
					operand_[next_operand_] = registers_[instruction_.lreg(next_operand_)];
					++next_operand_;
					state_ = next_operand_ == 2 ? perform_state_ : State::FetchOperand;
				continue;

				default:
					assert(false);
			}
		break;

		// Store operand is a lot simpler: only one operand is ever stored, and its address
		// is already known. So this can either skip straight back to ::Decode if the target
		// is a register, otherwise a single write operation can occur.
		case State::StoreOperand:
			if(instruction_.mode(next_operand_) <= Mode::AddressRegisterDirect) {
				registers_[instruction_.lreg(next_operand_)] = operand_[next_operand_];
				state_ = State::Decode;
				continue;
			}

			// TODO: make a decision on how I'm going to deal with byte/word/longword.
			assert(false);
		break;

		//
		// Various forms of perform.
		//
#define MoveToWritePhase()														\
	next_operand_ = operand_flags_ >> 3;										\
	MoveToState(operand_flags_ & 0x0c ? State::StoreOperand : State::Decode)

		case State::Perform_np:
			InstructionSet::M68k::perform<InstructionSet::M68k::Model::M68000>(
				instruction_, operand_[0], operand_[1], status_, *static_cast<ProcessorBase *>(this));
			Prefetch();			// np

			MoveToWritePhase();
		break;

		case State::Perform_np_n:
			InstructionSet::M68k::perform<InstructionSet::M68k::Model::M68000>(
				instruction_, operand_[0], operand_[1], status_, *static_cast<ProcessorBase *>(this));
			Prefetch();			// np
			IdleBus(1);			// n

			MoveToWritePhase();
		break;

#undef MoveToWritePhase

		default:
			printf("Unhandled state: %d\n", state_);
			assert(false);
	}}

#undef Prefetch
#undef ReadProgramWord
#undef ReadDataWord
#undef AccessPair
#undef CompleteAccess
#undef WaitForDTACK
#undef IdleBus
#undef PerformBusOperation
#undef MoveToState
#undef CheckOverrun
#undef Spend
#undef ConsiderExit

}

// MARK: - Operation specifications.

template <class BusHandler, bool dtack_is_implicit, bool permit_overrun, bool signal_will_perform>
void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perform>::setup_operation() {

#define BIND(x, p)	\
	case InstructionSet::M68k::Operation::x:			\
		operand_flags_ = InstructionSet::M68k::operand_flags<InstructionSet::M68k::Model::M68000, InstructionSet::M68k::Operation::x>();	\
		perform_state_ = p;	\
	break;

	using Mode = InstructionSet::M68k::AddressingMode;

	switch(instruction_.operation) {
		BIND(NBCD, instruction_.mode(0) == Mode::DataRegisterDirect ? State::Perform_np_n : State::Perform_np);

		default:
			assert(false);
	}

#undef BIND
}

// MARK: - Flow Controller.

void ProcessorBase::did_update_status() {
	// Shuffle the stack pointers.
	stack_pointers_[is_supervisor_] = registers_[15];
	registers_[15] = stack_pointers_[int(status_.is_supervisor)];
	is_supervisor_ = int(status_.is_supervisor);
}

// MARK: - External state.

template <class BusHandler, bool dtack_is_implicit, bool permit_overrun, bool signal_will_perform>
CPU::MC68000Mk2::State Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perform>::get_state() {
	CPU::MC68000Mk2::State state;

	// This isn't true, but will ensure that both stack_pointers_ have their proper values.
	did_update_status();

	for(int c = 0; c < 7; c++) {
		state.registers.data[c] = registers_[c].l;
		state.registers.address[c] = registers_[c + 8].l;
	}
	state.registers.data[7] = registers_[7].l;

	state.registers.program_counter = program_counter_.l;
	state.registers.status = status_.status();
	state.registers.user_stack_pointer = stack_pointers_[0].l;
	state.registers.supervisor_stack_pointer = stack_pointers_[1].l;

	return state;
}

template <class BusHandler, bool dtack_is_implicit, bool permit_overrun, bool signal_will_perform>
void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perform>::set_state(const CPU::MC68000Mk2::State &state) {
	// Copy registers and the program counter.
	for(int c = 0; c < 7; c++) {
		registers_[c].l = state.registers.data[c];
		registers_[c + 8].l = state.registers.address[c];
	}
	registers_[7].l = state.registers.data[7];
	program_counter_.l = state.registers.program_counter;

	// Set status first in order to get the proper is-supervisor flag in place.
	status_.set_status(state.registers.status);

	// Update stack pointers, being careful to copy the right one.
	stack_pointers_[0].l = state.registers.user_stack_pointer;
	stack_pointers_[1].l = state.registers.supervisor_stack_pointer;
	registers_[15] = stack_pointers_[is_supervisor_];

	// Ensure the local is-supervisor flag is updated.
	did_update_status();
}

}
}

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


<commit_before>/// \file
/// \ingroup tutorial_eve
/// Demonstrates how to combine Timur's GL plots with other scene elements.
///
/// \image html eve_glplot_geom.png
/// \macro_code
///
/// \author Matevz Tadel

void glplot_geom()
{
   TEveManager::Create();

   TEveUtil::Macro("show_extract.C");

   TH3F *h31 = new TH3F("h31", "h31", 20, -3, 3, 20, -3, 3, 20, -3, 3);
   h31->FillRandom("gaus", 20*20*20);
   h31->SetFillColor(2);
   auto x = new TEvePlot3D("EvePlot - TH3F");
   x->SetPlot(h31, "glbox");
   x->RefMainTrans().Scale(800, 800, 1000);
   x->RefMainTrans().RotateLF(1, 3, TMath::PiOver2());
   gEve->AddElement(x);

   gEve->Redraw3D(kTRUE);
}
<commit_msg>- fix error: Function: gaus is not a TF3, is a TF1 - use auto<commit_after>/// \file
/// \ingroup tutorial_eve
/// Demonstrates how to combine Timur's GL plots with other scene elements.
///
/// \image html eve_glplot_geom.png
/// \macro_code
///
/// \author Matevz Tadel

void glplot_geom()
{
   TEveManager::Create();

   TEveUtil::Macro("show_extract.C");

   auto h31 = new TH3F("h31", "h31", 20, -3, 3, 20, -3, 3, 20, -3, 3);
   auto gxy = new TF3("gaus2","xygaus");
   gxy->SetParameters(1,0,1,0,0.3);
   h31->FillRandom("gaus2");

   h31->SetFillColor(2);
   auto x = new TEvePlot3D("EvePlot - TH3F");
   x->SetPlot(h31, "glbox");
   x->RefMainTrans().Scale(800, 800, 1000);
   x->RefMainTrans().RotateLF(1, 3, TMath::PiOver2());
   gEve->AddElement(x);

   gEve->Redraw3D(kTRUE);
}
<|endoftext|>


<commit_before>#ifndef MJOLNIR_LOCAL_FORCE_FIELD
#define MJOLNIR_LOCAL_FORCE_FIELD
#include "LocalInteractionBase.hpp"
#include <mjolnir/util/logger.hpp>
#include <utility>
#include <vector>
#include <array>
#include <memory>

namespace mjolnir
{

template<typename traitsT>
class LocalForceField
{
  public:
    typedef traitsT traits_type;
    typedef typename traits_type::real_type         real_type;
    typedef typename traits_type::coordinate_type   coordinate_type;
    typedef System<traits_type>                     system_type;
    typedef LocalInteractionBase<traitsT>           interaction_type;
    typedef std::unique_ptr<interaction_type>       interaction_ptr;
    typedef std::vector<interaction_ptr>            container_type;
    typedef typename container_type::iterator       iterator;
    typedef typename container_type::const_iterator const_iterator;

  public:

    LocalForceField()  = default;
    ~LocalForceField() = default;
    LocalForceField(LocalForceField const&) = delete;
    LocalForceField(LocalForceField&&)      = default;
    LocalForceField& operator=(LocalForceField const&) = delete;
    LocalForceField& operator=(LocalForceField&&)      = default;

    void emplace(interaction_ptr&& interaction)
    {
        interactions_.emplace_back(std::move(interaction));
    }

    // to re-calculate parameters like temperature, ionic concentration, etc...
    void update(const system_type& sys, const real_type dt)
    {
        for(auto& item : this->interactions_)
        {
            item->update(sys, dt);
        }
        return;
    }

    // Topology is defined based on LocalForceField.
    void write_topology(typename system_type::topology_type& topol)
    {
        for(auto& item : this->interactions_)
        {
            item->write_topology(topol);
        }
        return;
    }

    void calc_force(system_type& sys) const
    {
        for(const auto& item : this->interactions_)
        {
            item->calc_force(sys);
        }
        return;
    }
    real_type calc_energy(const system_type& sys) const
    {
        real_type energy = 0.0;
        for(const auto& item : this->interactions_)
        {
            energy += item->calc_energy(sys);
        }
        return energy;
    }

    // TODO simplify
    std::string list_energy() const
    {
        std::string retval;
        for(const auto& i : interactions_)
        {
            retval += i->name();
            retval += ' ';
        }
        return retval;
    }

    std::string dump_energy(const system_type& sys) const
    {
        std::string retval;
        for(const auto& i : interactions_)
        {
            retval += std::to_string(i->calc_energy(sys));
            retval += ' ';
        }
        return retval;
    }

    iterator       begin()        noexcept {return interactions_.begin();}
    iterator       end()          noexcept {return interactions_.end();}
    const_iterator begin()  const noexcept {return interactions_.begin();}
    const_iterator end()    const noexcept {return interactions_.end();}
    const_iterator cbegin() const noexcept {return interactions_.begin();}
    const_iterator cend()   const noexcept {return interactions_.end();}

  private:

    container_type interactions_;
};

} // mjolnir
#endif /* MJOLNIR_LOCAL_FORCE_FIELD */
<commit_msg>add missing initialize() method to LocalForceField for consistency<commit_after>#ifndef MJOLNIR_LOCAL_FORCE_FIELD
#define MJOLNIR_LOCAL_FORCE_FIELD
#include "LocalInteractionBase.hpp"
#include <mjolnir/util/logger.hpp>
#include <utility>
#include <vector>
#include <array>
#include <memory>

namespace mjolnir
{

template<typename traitsT>
class LocalForceField
{
  public:
    typedef traitsT traits_type;
    typedef typename traits_type::real_type         real_type;
    typedef typename traits_type::coordinate_type   coordinate_type;
    typedef System<traits_type>                     system_type;
    typedef LocalInteractionBase<traitsT>           interaction_type;
    typedef std::unique_ptr<interaction_type>       interaction_ptr;
    typedef std::vector<interaction_ptr>            container_type;
    typedef typename container_type::iterator       iterator;
    typedef typename container_type::const_iterator const_iterator;

  public:

    LocalForceField()  = default;
    ~LocalForceField() = default;
    LocalForceField(LocalForceField const&) = delete;
    LocalForceField(LocalForceField&&)      = default;
    LocalForceField& operator=(LocalForceField const&) = delete;
    LocalForceField& operator=(LocalForceField&&)      = default;

    void emplace(interaction_ptr&& interaction)
    {
        interactions_.emplace_back(std::move(interaction));
    }

    void initialize(const system_type& sys, const real_type dt)
    {
        for(auto& item : this->interactions_)
        {
            item->initialize(sys, dt);
        }
    }

    // to re-calculate parameters like temperature, ionic concentration, etc...
    void update(const system_type& sys, const real_type dt)
    {
        for(auto& item : this->interactions_)
        {
            item->update(sys, dt);
        }
        return;
    }

    // Topology is defined based on LocalForceField.
    void write_topology(typename system_type::topology_type& topol)
    {
        for(auto& item : this->interactions_)
        {
            item->write_topology(topol);
        }
        return;
    }

    void calc_force(system_type& sys) const
    {
        for(const auto& item : this->interactions_)
        {
            item->calc_force(sys);
        }
        return;
    }
    real_type calc_energy(const system_type& sys) const
    {
        real_type energy = 0.0;
        for(const auto& item : this->interactions_)
        {
            energy += item->calc_energy(sys);
        }
        return energy;
    }

    // TODO simplify
    std::string list_energy() const
    {
        std::string retval;
        for(const auto& i : interactions_)
        {
            retval += i->name();
            retval += ' ';
        }
        return retval;
    }

    std::string dump_energy(const system_type& sys) const
    {
        std::string retval;
        for(const auto& i : interactions_)
        {
            retval += std::to_string(i->calc_energy(sys));
            retval += ' ';
        }
        return retval;
    }

    iterator       begin()        noexcept {return interactions_.begin();}
    iterator       end()          noexcept {return interactions_.end();}
    const_iterator begin()  const noexcept {return interactions_.begin();}
    const_iterator end()    const noexcept {return interactions_.end();}
    const_iterator cbegin() const noexcept {return interactions_.begin();}
    const_iterator cend()   const noexcept {return interactions_.end();}

  private:

    container_type interactions_;
};

} // mjolnir
#endif /* MJOLNIR_LOCAL_FORCE_FIELD */
<|endoftext|>