<commit_before>/***
 * @file sort_policy_test.cc
 * @author Ryan Curtin
 *
 * Tests for each of the implementations of the SortPolicy class.
 */
#include <fastlib/fastlib.h>
#include <armadillo>

// Classes to test.
#include "nearest_neighbor_sort.h"
#include "furthest_neighbor_sort.h"

#define BOOST_TEST_MODULE SortPolicy Test
#include <boost/test/unit_test.hpp>

using namespace mlpack;
using namespace mlpack::neighbor;

// Tests for NearestNeighborSort

/***
 * Ensure the best distance for nearest neighbors is 0.
 */
BOOST_AUTO_TEST_CASE(nns_best_distance) {
  BOOST_REQUIRE(NearestNeighborSort::BestDistance() == 0);
}

/***
 * Ensure the worst distance for nearest neighbors is DBL_MAX.
 */
BOOST_AUTO_TEST_CASE(nns_worst_distance) {
  BOOST_REQUIRE(NearestNeighborSort::WorstDistance() == DBL_MAX);
}

/***
 * Make sure the comparison works for values strictly less than the reference.
 */
BOOST_AUTO_TEST_CASE(nns_is_better_strict) {
  BOOST_REQUIRE(NearestNeighborSort::IsBetter(5.0, 6.0) == true);
}

/***
 * Warn in case the comparison is not strict.
 */
BOOST_AUTO_TEST_CASE(nns_is_better_not_strict) {
  BOOST_WARN(NearestNeighborSort::IsBetter(6.0, 6.0) == true);
}

/***
 * A simple test case of where to insert when all the values in the list are
 * DBL_MAX.
 */
BOOST_AUTO_TEST_CASE(nns_sort_distance_all_dbl_max) {
  arma::vec list(5);
  list.fill(DBL_MAX);

  // Should be inserted at the head of the list.
  BOOST_REQUIRE(NearestNeighborSort::SortDistance(list, 5.0) == 0);
}

/***
 * Another test case, where we are just putting the new value in the middle of
 * the list.
 */
BOOST_AUTO_TEST_CASE(nns_sort_distance_2) {
  arma::vec list(3);
  list[0] = 0.66;
  list[1] = 0.89;
  list[2] = 1.14;

  // Run a couple possibilities through.
  BOOST_REQUIRE(NearestNeighborSort::SortDistance(list, 0.61) == 0);
  BOOST_REQUIRE(NearestNeighborSort::SortDistance(list, 0.76) == 1);
  BOOST_REQUIRE(NearestNeighborSort::SortDistance(list, 0.99) == 2);
  BOOST_REQUIRE(NearestNeighborSort::SortDistance(list, 1.22) ==
      (index_t() - 1));
}

/***
 * Very simple sanity check to ensure that bounds are working alright.  We will
 * use a one-dimensional bound for simplicity.
 */
BOOST_AUTO_TEST_CASE(nns_node_to_node_distance) {
  // Well, there's no easy way to make DHrectBounds the way we want, so we have
  // to make them and then expand the region to include new points.
  BinarySpaceTree<DHrectBound<2>, arma::mat> node_one;
  arma::vec utility(1);
  utility[0] = 0;

  node_one.bound().SetSize(1);
  node_one.bound() |= utility;
  utility[0] = 1;
  node_one.bound() |= utility;

  BinarySpaceTree<DHrectBound<2>, arma::mat> node_two;
  node_two.bound().SetSize(1);

  utility[0] = 5;
  node_two.bound() |= utility;
  utility[0] = 6;
  node_two.bound() |= utility;

  // This should use the L2 squared distance.
  BOOST_REQUIRE_CLOSE(NearestNeighborSort::BestNodeToNodeDistance(&node_one,
      &node_two), 16.0, 1e-5);

  // And another just to be sure, from the other side.
  node_two.bound().Reset();
  utility[0] = -2;
  node_two.bound() |= utility;
  utility[0] = -1;
  node_two.bound() |= utility;

  // Again, the distance is the L2 squared distance.
  BOOST_REQUIRE_CLOSE(NearestNeighborSort::BestNodeToNodeDistance(&node_one,
      &node_two), 1, 1e-5);

  // Now, when the bounds overlap.
  node_two.bound().Reset();
  utility[0] = -0.5;
  node_two.bound() |= utility;
  utility[0] = 0.5;
  node_two.bound() |= utility;

  BOOST_REQUIRE_CLOSE(NearestNeighborSort::BestNodeToNodeDistance(&node_one,
      &node_two), 0, 1e-5);
}

/***
 * Another very simple sanity check for the point-to-node case, again in one
 * dimension.
 */
BOOST_AUTO_TEST_CASE(nns_point_to_node_distance) {
  // Well, there's no easy way to make DHrectBounds the way we want, so we have
  // to make them and then expand the region to include new points.
  arma::vec utility(1);
  utility[0] = 0;

  BinarySpaceTree<DHrectBound<2>, arma::mat> node;
  node.bound().SetSize(1);
  node.bound() |= utility;
  utility[0] = 1;
  node.bound() |= utility;

  arma::vec point(1);
  point[0] = -0.5;

  // The distance is the L2 squared distance.
  BOOST_REQUIRE_CLOSE(NearestNeighborSort::BestPointToNodeDistance(point,
      &node), 0.25, 1e-5);

  // Now from the other side of the bound.
  point[0] = 1.5;

  BOOST_REQUIRE_CLOSE(NearestNeighborSort::BestPointToNodeDistance(point,
      &node), 0.25, 1e-5);

  // And now when the point is inside the bound.
  point[0] = 0.5;

  BOOST_REQUIRE_CLOSE(NearestNeighborSort::BestPointToNodeDistance(point,
      &node), 0, 1e-5);
}

// Tests for FurthestNeighborSort

/***
 * Ensure the best distance for furthest neighbors is DBL_MAX.
 */
BOOST_AUTO_TEST_CASE(fns_best_distance) {
  BOOST_REQUIRE(FurthestNeighborSort::BestDistance() == DBL_MAX);
}

/***
 * Ensure the worst distance for furthest neighbors is 0.
 */
BOOST_AUTO_TEST_CASE(fns_worst_distance) {
  BOOST_REQUIRE(FurthestNeighborSort::WorstDistance() == 0);
}

/***
 * Make sure the comparison works for values strictly less than the reference.
 */
BOOST_AUTO_TEST_CASE(fns_is_better_strict) {
  BOOST_REQUIRE(FurthestNeighborSort::IsBetter(5.0, 4.0) == true);
}

/***
 * Warn in case the comparison is not strict.
 */
BOOST_AUTO_TEST_CASE(fns_is_better_not_strict) {
  BOOST_WARN(FurthestNeighborSort::IsBetter(6.0, 6.0) == true);
}

/***
 * A simple test case of where to insert when all the values in the list are
 * 0.
 */
BOOST_AUTO_TEST_CASE(fns_sort_distance_all_zero) {
  arma::vec list(5);
  list.fill(0);

  // Should be inserted at the head of the list.
  BOOST_REQUIRE(FurthestNeighborSort::SortDistance(list, 5.0) == 0);
}

/***
 * Another test case, where we are just putting the new value in the middle of
 * the list.
 */
BOOST_AUTO_TEST_CASE(fns_sort_distance_2) {
  arma::vec list(3);
  list[0] = 1.14;
  list[1] = 0.89;
  list[2] = 0.66;

  // Run a couple possibilities through.
  BOOST_REQUIRE(FurthestNeighborSort::SortDistance(list, 1.22) == 0);
  BOOST_REQUIRE(FurthestNeighborSort::SortDistance(list, 0.93) == 1);
  BOOST_REQUIRE(FurthestNeighborSort::SortDistance(list, 0.68) == 2);
  BOOST_REQUIRE(FurthestNeighborSort::SortDistance(list, 0.62) ==
      (index_t() - 1));
}

/***
 * Very simple sanity check to ensure that bounds are working alright.  We will
 * use a one-dimensional bound for simplicity.
 */
BOOST_AUTO_TEST_CASE(fns_node_to_node_distance) {
  // Well, there's no easy way to make DHrectBounds the way we want, so we have
  // to make them and then expand the region to include new points.
  arma::vec utility(1);
  utility[0] = 0;

  BinarySpaceTree<DHrectBound<2>, arma::mat> node_one;
  node_one.bound().SetSize(1);
  node_one.bound() |= utility;
  utility[0] = 1;
  node_one.bound() |= utility;

  BinarySpaceTree<DHrectBound<2>, arma::mat> node_two;
  node_two.bound().SetSize(1);
  utility[0] = 5;
  node_two.bound() |= utility;
  utility[0] = 6;
  node_two.bound() |= utility;

  // This should use the L2 squared distance.
  BOOST_REQUIRE_CLOSE(FurthestNeighborSort::BestNodeToNodeDistance(&node_one,
      &node_two), 36.0, 1e-5);

  // And another just to be sure, from the other side.
  node_two.bound().Reset();
  utility[0] = -2;
  node_two.bound() |= utility;
  utility[0] = -1;
  node_two.bound() |= utility;

  // Again, the distance is the L2 squared distance.
  BOOST_REQUIRE_CLOSE(FurthestNeighborSort::BestNodeToNodeDistance(&node_one,
      &node_two), 9.0, 1e-5);

  // Now, when the bounds overlap.
  node_two.bound().Reset();
  utility[0] = -0.5;
  node_two.bound() |= utility;
  utility[0] = 0.5;
  node_two.bound() |= utility;

  BOOST_REQUIRE_CLOSE(FurthestNeighborSort::BestNodeToNodeDistance(&node_one,
      &node_two), (1.5 * 1.5), 1e-5);
}

/***
 * Another very simple sanity check for the point-to-node case, again in one
 * dimension.
 */
BOOST_AUTO_TEST_CASE(fns_point_to_node_distance) {
  // Well, there's no easy way to make DHrectBounds the way we want, so we have
  // to make them and then expand the region to include new points.
  arma::vec utility(1);
  utility[0] = 0;

  BinarySpaceTree<DHrectBound<2>, arma::mat> node;
  node.bound().SetSize(1);
  node.bound() |= utility;
  utility[0] = 1;
  node.bound() |= utility;

  arma::vec point(1);
  point[0] = -0.5;

  // The distance is the L2 squared distance.
  BOOST_REQUIRE_CLOSE(FurthestNeighborSort::BestPointToNodeDistance(point,
      &node), (1.5 * 1.5), 1e-5);

  // Now from the other side of the bound.
  point[0] = 1.5;

  BOOST_REQUIRE_CLOSE(FurthestNeighborSort::BestPointToNodeDistance(point,
      &node), (1.5 * 1.5), 1e-5);

  // And now when the point is inside the bound.
  point[0] = 0.5;

  BOOST_REQUIRE_CLOSE(FurthestNeighborSort::BestPointToNodeDistance(point,
      &node), 0.25, 1e-5);
}
<commit_msg>Explicitly specify floating-point numbers for BOOST_REQUIRE_CLOSE().<commit_after>/***
 * @file sort_policy_test.cc
 * @author Ryan Curtin
 *
 * Tests for each of the implementations of the SortPolicy class.
 */
#include <fastlib/fastlib.h>
#include <armadillo>

// Classes to test.
#include "nearest_neighbor_sort.h"
#include "furthest_neighbor_sort.h"

#define BOOST_TEST_MODULE SortPolicy Test
#include <boost/test/unit_test.hpp>

using namespace mlpack;
using namespace mlpack::neighbor;

// Tests for NearestNeighborSort

/***
 * Ensure the best distance for nearest neighbors is 0.
 */
BOOST_AUTO_TEST_CASE(nns_best_distance) {
  BOOST_REQUIRE(NearestNeighborSort::BestDistance() == 0);
}

/***
 * Ensure the worst distance for nearest neighbors is DBL_MAX.
 */
BOOST_AUTO_TEST_CASE(nns_worst_distance) {
  BOOST_REQUIRE(NearestNeighborSort::WorstDistance() == DBL_MAX);
}

/***
 * Make sure the comparison works for values strictly less than the reference.
 */
BOOST_AUTO_TEST_CASE(nns_is_better_strict) {
  BOOST_REQUIRE(NearestNeighborSort::IsBetter(5.0, 6.0) == true);
}

/***
 * Warn in case the comparison is not strict.
 */
BOOST_AUTO_TEST_CASE(nns_is_better_not_strict) {
  BOOST_WARN(NearestNeighborSort::IsBetter(6.0, 6.0) == true);
}

/***
 * A simple test case of where to insert when all the values in the list are
 * DBL_MAX.
 */
BOOST_AUTO_TEST_CASE(nns_sort_distance_all_dbl_max) {
  arma::vec list(5);
  list.fill(DBL_MAX);

  // Should be inserted at the head of the list.
  BOOST_REQUIRE(NearestNeighborSort::SortDistance(list, 5.0) == 0);
}

/***
 * Another test case, where we are just putting the new value in the middle of
 * the list.
 */
BOOST_AUTO_TEST_CASE(nns_sort_distance_2) {
  arma::vec list(3);
  list[0] = 0.66;
  list[1] = 0.89;
  list[2] = 1.14;

  // Run a couple possibilities through.
  BOOST_REQUIRE(NearestNeighborSort::SortDistance(list, 0.61) == 0);
  BOOST_REQUIRE(NearestNeighborSort::SortDistance(list, 0.76) == 1);
  BOOST_REQUIRE(NearestNeighborSort::SortDistance(list, 0.99) == 2);
  BOOST_REQUIRE(NearestNeighborSort::SortDistance(list, 1.22) ==
      (index_t() - 1));
}

/***
 * Very simple sanity check to ensure that bounds are working alright.  We will
 * use a one-dimensional bound for simplicity.
 */
BOOST_AUTO_TEST_CASE(nns_node_to_node_distance) {
  // Well, there's no easy way to make DHrectBounds the way we want, so we have
  // to make them and then expand the region to include new points.
  BinarySpaceTree<DHrectBound<2>, arma::mat> node_one;
  arma::vec utility(1);
  utility[0] = 0;

  node_one.bound().SetSize(1);
  node_one.bound() |= utility;
  utility[0] = 1;
  node_one.bound() |= utility;

  BinarySpaceTree<DHrectBound<2>, arma::mat> node_two;
  node_two.bound().SetSize(1);

  utility[0] = 5;
  node_two.bound() |= utility;
  utility[0] = 6;
  node_two.bound() |= utility;

  // This should use the L2 squared distance.
  BOOST_REQUIRE_CLOSE(NearestNeighborSort::BestNodeToNodeDistance(&node_one,
      &node_two), 16.0, 1e-5);

  // And another just to be sure, from the other side.
  node_two.bound().Reset();
  utility[0] = -2;
  node_two.bound() |= utility;
  utility[0] = -1;
  node_two.bound() |= utility;

  // Again, the distance is the L2 squared distance.
  BOOST_REQUIRE_CLOSE(NearestNeighborSort::BestNodeToNodeDistance(&node_one,
      &node_two), 1.0, 1e-5);

  // Now, when the bounds overlap.
  node_two.bound().Reset();
  utility[0] = -0.5;
  node_two.bound() |= utility;
  utility[0] = 0.5;
  node_two.bound() |= utility;

  BOOST_REQUIRE_CLOSE(NearestNeighborSort::BestNodeToNodeDistance(&node_one,
      &node_two), 0.0, 1e-5);
}

/***
 * Another very simple sanity check for the point-to-node case, again in one
 * dimension.
 */
BOOST_AUTO_TEST_CASE(nns_point_to_node_distance) {
  // Well, there's no easy way to make DHrectBounds the way we want, so we have
  // to make them and then expand the region to include new points.
  arma::vec utility(1);
  utility[0] = 0;

  BinarySpaceTree<DHrectBound<2>, arma::mat> node;
  node.bound().SetSize(1);
  node.bound() |= utility;
  utility[0] = 1;
  node.bound() |= utility;

  arma::vec point(1);
  point[0] = -0.5;

  // The distance is the L2 squared distance.
  BOOST_REQUIRE_CLOSE(NearestNeighborSort::BestPointToNodeDistance(point,
      &node), 0.25, 1e-5);

  // Now from the other side of the bound.
  point[0] = 1.5;

  BOOST_REQUIRE_CLOSE(NearestNeighborSort::BestPointToNodeDistance(point,
      &node), 0.25, 1e-5);

  // And now when the point is inside the bound.
  point[0] = 0.5;

  BOOST_REQUIRE_CLOSE(NearestNeighborSort::BestPointToNodeDistance(point,
      &node), 0.0, 1e-5);
}

// Tests for FurthestNeighborSort

/***
 * Ensure the best distance for furthest neighbors is DBL_MAX.
 */
BOOST_AUTO_TEST_CASE(fns_best_distance) {
  BOOST_REQUIRE(FurthestNeighborSort::BestDistance() == DBL_MAX);
}

/***
 * Ensure the worst distance for furthest neighbors is 0.
 */
BOOST_AUTO_TEST_CASE(fns_worst_distance) {
  BOOST_REQUIRE(FurthestNeighborSort::WorstDistance() == 0);
}

/***
 * Make sure the comparison works for values strictly less than the reference.
 */
BOOST_AUTO_TEST_CASE(fns_is_better_strict) {
  BOOST_REQUIRE(FurthestNeighborSort::IsBetter(5.0, 4.0) == true);
}

/***
 * Warn in case the comparison is not strict.
 */
BOOST_AUTO_TEST_CASE(fns_is_better_not_strict) {
  BOOST_WARN(FurthestNeighborSort::IsBetter(6.0, 6.0) == true);
}

/***
 * A simple test case of where to insert when all the values in the list are
 * 0.
 */
BOOST_AUTO_TEST_CASE(fns_sort_distance_all_zero) {
  arma::vec list(5);
  list.fill(0);

  // Should be inserted at the head of the list.
  BOOST_REQUIRE(FurthestNeighborSort::SortDistance(list, 5.0) == 0);
}

/***
 * Another test case, where we are just putting the new value in the middle of
 * the list.
 */
BOOST_AUTO_TEST_CASE(fns_sort_distance_2) {
  arma::vec list(3);
  list[0] = 1.14;
  list[1] = 0.89;
  list[2] = 0.66;

  // Run a couple possibilities through.
  BOOST_REQUIRE(FurthestNeighborSort::SortDistance(list, 1.22) == 0);
  BOOST_REQUIRE(FurthestNeighborSort::SortDistance(list, 0.93) == 1);
  BOOST_REQUIRE(FurthestNeighborSort::SortDistance(list, 0.68) == 2);
  BOOST_REQUIRE(FurthestNeighborSort::SortDistance(list, 0.62) ==
      (index_t() - 1));
}

/***
 * Very simple sanity check to ensure that bounds are working alright.  We will
 * use a one-dimensional bound for simplicity.
 */
BOOST_AUTO_TEST_CASE(fns_node_to_node_distance) {
  // Well, there's no easy way to make DHrectBounds the way we want, so we have
  // to make them and then expand the region to include new points.
  arma::vec utility(1);
  utility[0] = 0;

  BinarySpaceTree<DHrectBound<2>, arma::mat> node_one;
  node_one.bound().SetSize(1);
  node_one.bound() |= utility;
  utility[0] = 1;
  node_one.bound() |= utility;

  BinarySpaceTree<DHrectBound<2>, arma::mat> node_two;
  node_two.bound().SetSize(1);
  utility[0] = 5;
  node_two.bound() |= utility;
  utility[0] = 6;
  node_two.bound() |= utility;

  // This should use the L2 squared distance.
  BOOST_REQUIRE_CLOSE(FurthestNeighborSort::BestNodeToNodeDistance(&node_one,
      &node_two), 36.0, 1e-5);

  // And another just to be sure, from the other side.
  node_two.bound().Reset();
  utility[0] = -2;
  node_two.bound() |= utility;
  utility[0] = -1;
  node_two.bound() |= utility;

  // Again, the distance is the L2 squared distance.
  BOOST_REQUIRE_CLOSE(FurthestNeighborSort::BestNodeToNodeDistance(&node_one,
      &node_two), 9.0, 1e-5);

  // Now, when the bounds overlap.
  node_two.bound().Reset();
  utility[0] = -0.5;
  node_two.bound() |= utility;
  utility[0] = 0.5;
  node_two.bound() |= utility;

  BOOST_REQUIRE_CLOSE(FurthestNeighborSort::BestNodeToNodeDistance(&node_one,
      &node_two), (1.5 * 1.5), 1e-5);
}

/***
 * Another very simple sanity check for the point-to-node case, again in one
 * dimension.
 */
BOOST_AUTO_TEST_CASE(fns_point_to_node_distance) {
  // Well, there's no easy way to make DHrectBounds the way we want, so we have
  // to make them and then expand the region to include new points.
  arma::vec utility(1);
  utility[0] = 0;

  BinarySpaceTree<DHrectBound<2>, arma::mat> node;
  node.bound().SetSize(1);
  node.bound() |= utility;
  utility[0] = 1;
  node.bound() |= utility;

  arma::vec point(1);
  point[0] = -0.5;

  // The distance is the L2 squared distance.
  BOOST_REQUIRE_CLOSE(FurthestNeighborSort::BestPointToNodeDistance(point,
      &node), (1.5 * 1.5), 1e-5);

  // Now from the other side of the bound.
  point[0] = 1.5;

  BOOST_REQUIRE_CLOSE(FurthestNeighborSort::BestPointToNodeDistance(point,
      &node), (1.5 * 1.5), 1e-5);

  // And now when the point is inside the bound.
  point[0] = 0.5;

  BOOST_REQUIRE_CLOSE(FurthestNeighborSort::BestPointToNodeDistance(point,
      &node), 0.25, 1e-5);
}
<|endoftext|>


<commit_before><commit_msg>Fixed compilation warning<commit_after><|endoftext|>


<commit_before>#ifndef MANIFOLDS_FUNCTIONS_UNARY_MINUS_HH
#define MANIFOLDS_FUNCTIONS_UNARY_MINUS_HH

#include "full_function_defs.hh"
#include "function.hh"

namespace manifolds {

template <class Func>
struct UnaryMinusImpl :
    Function<Func::input_dim,
	     Func::output_dim>
{

  UnaryMinusImpl(){}
  UnaryMinusImpl(const Func & f):f(f){}

  template <class ... Args>
  auto operator()(Args && ... args) const
  {
    return -f(args...);
  }

  auto GetFunction() const
  {
    return f;
  }

  auto GetFunctions() const
  {
    return std::make_tuple(f);
  }

private:
  Func f;
};

  DEF_FF_STEMPLATE(UnaryMinus)

  template <class T>
  std::ostream & operator<<(std::ostream & s,
			    UnaryMinus<T> u)
  {
    return s << '-' << u.GetFunction();
  }

  template <class T, class U>
  bool operator==(UnaryMinus<T>, U)
  {
    return false;
  }

  template <class T>
  bool operator==(UnaryMinus<T> u1, UnaryMinus<T> u2)
  {
    return u1.f == u2.f;
  }
}
#endif
<commit_msg>Added simplifications for multiplication by unaryminus<commit_after>
#ifndef MANIFOLDS_FUNCTIONS_UNARY_MINUS_HH
#define MANIFOLDS_FUNCTIONS_UNARY_MINUS_HH

#include "full_function_defs.hh"
#include "function.hh"

namespace manifolds {

template <class Func>
struct UnaryMinusImpl :
    Function<
  list<int_<24>, typename Func::indices>,
  Func::input_dim,
  Func::output_dim>
{

  UnaryMinusImpl(){}
  UnaryMinusImpl(const Func & f):f(f){}

  template <class ... Args>
  auto operator()(Args ... args) const
  {
    return -f(args...);
  }

  auto GetFunction() const
  {
    return f;
  }

  auto GetFunctions() const
  {
    return std::make_tuple(f);
  }

private:
  Func f;
};

  DEF_FF_STEMPLATE(UnaryMinus)

  template <class T>
  std::ostream & operator<<(std::ostream & s,
			    UnaryMinus<T> u)
  {
    return s << '-' << u.GetFunction();
  }

  template <class T, class U>
  bool operator==(UnaryMinus<T>, U)
  {
    return false;
  }

  template <class T>
  bool operator==(UnaryMinus<T> u1, UnaryMinus<T> u2)
  {
    return u1.f == u2.f;
  }

  template <class F>
  struct Simplification<
    UnaryMinus<UnaryMinus<F>>>
  {
    typedef F type;
    static type Combine(UnaryMinus<UnaryMinus<F>> u)
    {
      return u.GetFunction().GetFunction();
    }
  };

  template <class F>
  struct Simplification<
    UnaryMinus<F>, 2>
  {
    static auto Combine(UnaryMinus<F> u)
    {
      auto f = Simplify(u.GetFunction());
      return UnaryMinus<decltype(f)>(f);
    }
  };
}
#endif
<|endoftext|>


<commit_before>/**
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <activemq/commands/WireFormatInfo.h>

#include <activemq/state/CommandVisitor.h>
#include <activemq/wireformat/openwire/marshal/PrimitiveTypesMarshaller.h>
#include <decaf/lang/exceptions/NullPointerException.h>

using namespace std;
using namespace decaf;
using namespace decaf::lang;
using namespace decaf::lang::exceptions;
using namespace activemq;
using namespace activemq::exceptions;
using namespace activemq::wireformat;
using namespace activemq::wireformat::openwire;
using namespace activemq::wireformat::openwire::marshal;
using namespace activemq::commands;

////////////////////////////////////////////////////////////////////////////////
WireFormatInfo::WireFormatInfo() : BaseCommand(), magic(), marshalledProperties(), properties(), version(5) {

    // Initialize the MAGIC buffer.
    magic.push_back( 'A' );
    magic.push_back( 'c' );
    magic.push_back( 't' );
    magic.push_back( 'i' );
    magic.push_back( 'v' );
    magic.push_back( 'e' );
    magic.push_back( 'M' );
    magic.push_back( 'Q' );
}

////////////////////////////////////////////////////////////////////////////////
WireFormatInfo::~WireFormatInfo() {
}

////////////////////////////////////////////////////////////////////////////////
DataStructure* WireFormatInfo::cloneDataStructure() const {
    WireFormatInfo* wireFormatInfo = new WireFormatInfo();

    // Copy the data from the base class or classes
    wireFormatInfo->copyDataStructure( this );

    return wireFormatInfo;
}

////////////////////////////////////////////////////////////////////////////////
void WireFormatInfo::copyDataStructure( const DataStructure* src ) {

    // Copy the data of the base class or classes
    BaseCommand::copyDataStructure( src );

    const WireFormatInfo* srcPtr = dynamic_cast<const WireFormatInfo*>( src );

    if( srcPtr == NULL || src == NULL ) {
        throw NullPointerException(
            __FILE__, __LINE__,
            "WireFormatInfo::copyDataStructure - src is NULL or invalid" );
    }

    this->properties.copy( srcPtr->getProperties() );
    this->version = srcPtr->getVersion();
}

////////////////////////////////////////////////////////////////////////////////
unsigned char WireFormatInfo::getDataStructureType() const {
    return WireFormatInfo::ID_WIREFORMATINFO;
}

////////////////////////////////////////////////////////////////////////////////
std::string WireFormatInfo::toString() const {

    std::ostringstream stream;

    stream << "WireFormatInfo { "
           << "commandId = " << this->getCommandId() << ", "
           << "responseRequired = " << boolalpha << this->isResponseRequired() << ", ";

    std::vector<unsigned char> magic;
    std::vector<unsigned char> marshalledProperties;

    stream << "Magic = [ ";
    for( size_t imagic = 0; imagic < magic.size(); ++imagic ) {
        stream << magic[imagic];
        if( imagic < magic.size() - 1 ) {
            stream << ", ";
        }
    }

    stream << "Version = " << version << ", ";
    stream << "StackTraceEnabled = " << isStackTraceEnabled() << ", ";
    stream << "TcpNoDelayEnabled = " << isTcpNoDelayEnabled() << ", ";
    stream << "CacheEnabled = " << isCacheEnabled() << ", ";
    stream << "CacheSize = " << getCacheSize() << ", ";
    stream << "TightEncodingEnabled = " << isTightEncodingEnabled() << ", ";
    stream << "SizePrefixDisabled = " << isSizePrefixDisabled() << ", ";
    stream << "MaxInactivityDuration = " << getMaxInactivityDuration() << ", ";
    stream << "MaxInactivityDuration = " << getMaxInactivityDurationInitalDelay();

    stream << " }";

    return stream.str();
}

////////////////////////////////////////////////////////////////////////////////
bool WireFormatInfo::equals( const DataStructure* value ) const {

    const WireFormatInfo* wireFormatInfo =
        dynamic_cast<const WireFormatInfo*>( value );

    if( value == NULL || wireFormatInfo == NULL ) {
        return false;
    }

    if( magic != wireFormatInfo->getMagic() ) {
        return false;
    }
    if( marshalledProperties != wireFormatInfo->getMarshalledProperties() ) {
        return false;
    }
    if( !properties.equals( wireFormatInfo->properties ) ) {
        return false;
    }
    if( version != wireFormatInfo->getVersion() ) {
        return false;
    }
    if( isStackTraceEnabled() != wireFormatInfo->isStackTraceEnabled() ) {
        return false;
    }
    if( isTcpNoDelayEnabled() != wireFormatInfo->isTcpNoDelayEnabled() ) {
        return false;
    }
    if( isCacheEnabled() != wireFormatInfo->isCacheEnabled() ) {
        return false;
    }
    if( getCacheSize() != wireFormatInfo->getCacheSize() ) {
        return false;
    }
    if( isTightEncodingEnabled() != wireFormatInfo->isTightEncodingEnabled() ) {
        return false;
    }
    if( isSizePrefixDisabled() != wireFormatInfo->isSizePrefixDisabled() ) {
        return false;
    }
    if( !BaseCommand::equals( value ) ) {
        return false;
    }
    if( getMaxInactivityDuration() != wireFormatInfo->getMaxInactivityDuration() ) {
        return false;
    }
    if( getMaxInactivityDurationInitalDelay() != wireFormatInfo->getMaxInactivityDurationInitalDelay() ) {
        return false;
    }

    return true;
}

////////////////////////////////////////////////////////////////////////////////
decaf::lang::Pointer<commands::Command> WireFormatInfo::visit( activemq::state::CommandVisitor* visitor )
    throw( activemq::exceptions::ActiveMQException ) {

    return visitor->processWireFormat( this );
}

////////////////////////////////////////////////////////////////////////////////
bool WireFormatInfo::isValid() const {

    if( magic.size() != std::string( "ActiveMQ" ).size() ) {
        return false;
    }

    if( magic[0] != 'A' ||
        magic[1] != 'c' ||
        magic[2] != 't' ||
        magic[3] != 'i' ||
        magic[4] != 'v' ||
        magic[5] != 'e' ||
        magic[6] != 'M' ||
        magic[7] != 'Q' ) {

        return false;
    }

    return true;
}

////////////////////////////////////////////////////////////////////////////////
bool WireFormatInfo::isStackTraceEnabled() const {

    try {
        return properties.getBool( "StackTraceEnabled" );
    }
    AMQ_CATCH_NOTHROW( exceptions::ActiveMQException )
    AMQ_CATCHALL_NOTHROW()

    return false;
}

////////////////////////////////////////////////////////////////////////////////
void WireFormatInfo::setStackTraceEnabled( bool stackTraceEnabled ) {

    try {
        properties.setBool( "StackTraceEnabled", stackTraceEnabled );
    }
    AMQ_CATCH_NOTHROW( exceptions::ActiveMQException )
    AMQ_CATCHALL_NOTHROW()
}

////////////////////////////////////////////////////////////////////////////////
bool WireFormatInfo::isTcpNoDelayEnabled() const {

    try {
        return properties.getBool( "TcpNoDelayEnabled" );
    }
    AMQ_CATCH_NOTHROW( exceptions::ActiveMQException )
    AMQ_CATCHALL_NOTHROW()

    return false;
}

////////////////////////////////////////////////////////////////////////////////
void WireFormatInfo::setTcpNoDelayEnabled( bool tcpNoDelayEnabled ) {

    try {
        properties.setBool( "TcpNoDelayEnabled", tcpNoDelayEnabled );
    }
    AMQ_CATCH_NOTHROW( exceptions::ActiveMQException )
    AMQ_CATCHALL_NOTHROW()
}

////////////////////////////////////////////////////////////////////////////////
bool WireFormatInfo::isCacheEnabled() const {

    try {
        return properties.getBool( "CacheEnabled" );
    }
    AMQ_CATCH_NOTHROW( exceptions::ActiveMQException )
    AMQ_CATCHALL_NOTHROW()

    return false;
}

////////////////////////////////////////////////////////////////////////////////
void WireFormatInfo::setCacheEnabled( bool cacheEnabled ) {

    try {
        properties.setBool( "CacheEnabled", cacheEnabled );
    }
    AMQ_CATCH_NOTHROW( exceptions::ActiveMQException )
    AMQ_CATCHALL_NOTHROW()
}

////////////////////////////////////////////////////////////////////////////////
bool WireFormatInfo::isTightEncodingEnabled() const {

    try {
        return properties.getBool( "TightEncodingEnabled" );
    }
    AMQ_CATCH_NOTHROW( exceptions::ActiveMQException )
    AMQ_CATCHALL_NOTHROW()

    return false;
}

////////////////////////////////////////////////////////////////////////////////
void WireFormatInfo::setTightEncodingEnabled( bool tightEncodingEnabled ) {

    try {
        properties.setBool( "TightEncodingEnabled", tightEncodingEnabled );
    }
    AMQ_CATCH_NOTHROW( exceptions::ActiveMQException )
    AMQ_CATCHALL_NOTHROW()
}

////////////////////////////////////////////////////////////////////////////////
bool WireFormatInfo::isSizePrefixDisabled() const {

    try {
        return properties.getBool( "SizePrefixDisabled" );
    }
    AMQ_CATCH_NOTHROW( exceptions::ActiveMQException )
    AMQ_CATCHALL_NOTHROW()

    return false;
}

////////////////////////////////////////////////////////////////////////////////
void WireFormatInfo::setSizePrefixDisabled( bool sizePrefixDisabled ) {

    try {
        properties.setBool( "SizePrefixDisabled", sizePrefixDisabled );
    }
    AMQ_CATCH_NOTHROW( exceptions::ActiveMQException )
    AMQ_CATCHALL_NOTHROW()
}

////////////////////////////////////////////////////////////////////////////////
void WireFormatInfo::beforeMarshal( WireFormat* wireFormat AMQCPP_UNUSED ) {

    try{

        marshalledProperties.clear();
        if( !properties.isEmpty() ) {
            marshal::PrimitiveTypesMarshaller::marshal(
                &properties, marshalledProperties );
        }
    }
    AMQ_CATCH_RETHROW( decaf::io::IOException )
    AMQ_CATCH_EXCEPTION_CONVERT( exceptions::ActiveMQException, decaf::io::IOException )
    AMQ_CATCHALL_THROW( decaf::io::IOException )
}

////////////////////////////////////////////////////////////////////////////////
void WireFormatInfo::afterUnmarshal( WireFormat* wireFormat AMQCPP_UNUSED ) {

    try{

        marshal::PrimitiveTypesMarshaller::unmarshal(
            &properties, marshalledProperties );
    }
    AMQ_CATCH_RETHROW( decaf::io::IOException )
    AMQ_CATCH_EXCEPTION_CONVERT( exceptions::ActiveMQException, decaf::io::IOException )
    AMQ_CATCHALL_THROW( decaf::io::IOException )
}

////////////////////////////////////////////////////////////////////////////////
long long WireFormatInfo::getMaxInactivityDuration() const {
    try {
        return properties.getLong( "MaxInactivityDuration" );
    }
    AMQ_CATCH_NOTHROW( exceptions::ActiveMQException )
    AMQ_CATCHALL_NOTHROW()

    return 0LL;
}

////////////////////////////////////////////////////////////////////////////////
void WireFormatInfo::setMaxInactivityDuration( long long maxInactivityDuration ) {
    try {
        properties.setLong( "MaxInactivityDuration", maxInactivityDuration );
    }
    AMQ_CATCH_NOTHROW( exceptions::ActiveMQException )
    AMQ_CATCHALL_NOTHROW()
}

////////////////////////////////////////////////////////////////////////////////
long long WireFormatInfo::getMaxInactivityDurationInitalDelay() const {
    try {
        return properties.getLong( "MaxInactivityDurationInitalDelay" );
    }
    AMQ_CATCH_NOTHROW( exceptions::ActiveMQException )
    AMQ_CATCHALL_NOTHROW()

    return 0LL;
}

////////////////////////////////////////////////////////////////////////////////
void WireFormatInfo::setMaxInactivityDurationInitalDelay( long long maxInactivityDurationInitalDelay ) {
    try {
        properties.setLong( "MaxInactivityDurationInitalDelay", maxInactivityDurationInitalDelay );
    }
    AMQ_CATCH_NOTHROW( exceptions::ActiveMQException )
    AMQ_CATCHALL_NOTHROW()
}

////////////////////////////////////////////////////////////////////////////////
int WireFormatInfo::getCacheSize() const {
    try {
        return properties.getInt( "CacheSize" );
    }
    AMQ_CATCH_NOTHROW( exceptions::ActiveMQException )
    AMQ_CATCHALL_NOTHROW()

    return 0;
}

////////////////////////////////////////////////////////////////////////////////
void WireFormatInfo::setCacheSize( int value ) {
    try {
        properties.setInt( "CacheSize", value );
    }
    AMQ_CATCH_NOTHROW( exceptions::ActiveMQException )
    AMQ_CATCHALL_NOTHROW()
}
<commit_msg>Disable setting the cache enabled property to on.<commit_after>/**
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <activemq/commands/WireFormatInfo.h>

#include <activemq/state/CommandVisitor.h>
#include <activemq/wireformat/openwire/marshal/PrimitiveTypesMarshaller.h>
#include <decaf/lang/exceptions/NullPointerException.h>

using namespace std;
using namespace decaf;
using namespace decaf::lang;
using namespace decaf::lang::exceptions;
using namespace activemq;
using namespace activemq::exceptions;
using namespace activemq::wireformat;
using namespace activemq::wireformat::openwire;
using namespace activemq::wireformat::openwire::marshal;
using namespace activemq::commands;

////////////////////////////////////////////////////////////////////////////////
WireFormatInfo::WireFormatInfo() : BaseCommand(), magic(), marshalledProperties(), properties(), version(5) {

    // Initialize the MAGIC buffer.
    magic.push_back( 'A' );
    magic.push_back( 'c' );
    magic.push_back( 't' );
    magic.push_back( 'i' );
    magic.push_back( 'v' );
    magic.push_back( 'e' );
    magic.push_back( 'M' );
    magic.push_back( 'Q' );
}

////////////////////////////////////////////////////////////////////////////////
WireFormatInfo::~WireFormatInfo() {
}

////////////////////////////////////////////////////////////////////////////////
DataStructure* WireFormatInfo::cloneDataStructure() const {
    WireFormatInfo* wireFormatInfo = new WireFormatInfo();

    // Copy the data from the base class or classes
    wireFormatInfo->copyDataStructure( this );

    return wireFormatInfo;
}

////////////////////////////////////////////////////////////////////////////////
void WireFormatInfo::copyDataStructure( const DataStructure* src ) {

    // Copy the data of the base class or classes
    BaseCommand::copyDataStructure( src );

    const WireFormatInfo* srcPtr = dynamic_cast<const WireFormatInfo*>( src );

    if( srcPtr == NULL || src == NULL ) {
        throw NullPointerException(
            __FILE__, __LINE__,
            "WireFormatInfo::copyDataStructure - src is NULL or invalid" );
    }

    this->properties.copy( srcPtr->getProperties() );
    this->version = srcPtr->getVersion();
}

////////////////////////////////////////////////////////////////////////////////
unsigned char WireFormatInfo::getDataStructureType() const {
    return WireFormatInfo::ID_WIREFORMATINFO;
}

////////////////////////////////////////////////////////////////////////////////
std::string WireFormatInfo::toString() const {

    std::ostringstream stream;

    stream << "WireFormatInfo { "
           << "commandId = " << this->getCommandId() << ", "
           << "responseRequired = " << boolalpha << this->isResponseRequired() << ", ";

    std::vector<unsigned char> magic;
    std::vector<unsigned char> marshalledProperties;

    stream << "Magic = [ ";
    for( size_t imagic = 0; imagic < magic.size(); ++imagic ) {
        stream << magic[imagic];
        if( imagic < magic.size() - 1 ) {
            stream << ", ";
        }
    }

    stream << "Version = " << version << ", ";
    stream << "StackTraceEnabled = " << isStackTraceEnabled() << ", ";
    stream << "TcpNoDelayEnabled = " << isTcpNoDelayEnabled() << ", ";
    stream << "CacheEnabled = " << isCacheEnabled() << ", ";
    stream << "CacheSize = " << getCacheSize() << ", ";
    stream << "TightEncodingEnabled = " << isTightEncodingEnabled() << ", ";
    stream << "SizePrefixDisabled = " << isSizePrefixDisabled() << ", ";
    stream << "MaxInactivityDuration = " << getMaxInactivityDuration() << ", ";
    stream << "MaxInactivityDuration = " << getMaxInactivityDurationInitalDelay();

    stream << " }";

    return stream.str();
}

////////////////////////////////////////////////////////////////////////////////
bool WireFormatInfo::equals( const DataStructure* value ) const {

    const WireFormatInfo* wireFormatInfo =
        dynamic_cast<const WireFormatInfo*>( value );

    if( value == NULL || wireFormatInfo == NULL ) {
        return false;
    }

    if( magic != wireFormatInfo->getMagic() ) {
        return false;
    }
    if( marshalledProperties != wireFormatInfo->getMarshalledProperties() ) {
        return false;
    }
    if( !properties.equals( wireFormatInfo->properties ) ) {
        return false;
    }
    if( version != wireFormatInfo->getVersion() ) {
        return false;
    }
    if( isStackTraceEnabled() != wireFormatInfo->isStackTraceEnabled() ) {
        return false;
    }
    if( isTcpNoDelayEnabled() != wireFormatInfo->isTcpNoDelayEnabled() ) {
        return false;
    }
    if( isCacheEnabled() != wireFormatInfo->isCacheEnabled() ) {
        return false;
    }
    if( getCacheSize() != wireFormatInfo->getCacheSize() ) {
        return false;
    }
    if( isTightEncodingEnabled() != wireFormatInfo->isTightEncodingEnabled() ) {
        return false;
    }
    if( isSizePrefixDisabled() != wireFormatInfo->isSizePrefixDisabled() ) {
        return false;
    }
    if( !BaseCommand::equals( value ) ) {
        return false;
    }
    if( getMaxInactivityDuration() != wireFormatInfo->getMaxInactivityDuration() ) {
        return false;
    }
    if( getMaxInactivityDurationInitalDelay() != wireFormatInfo->getMaxInactivityDurationInitalDelay() ) {
        return false;
    }

    return true;
}

////////////////////////////////////////////////////////////////////////////////
decaf::lang::Pointer<commands::Command> WireFormatInfo::visit( activemq::state::CommandVisitor* visitor )
    throw( activemq::exceptions::ActiveMQException ) {

    return visitor->processWireFormat( this );
}

////////////////////////////////////////////////////////////////////////////////
bool WireFormatInfo::isValid() const {

    if( magic.size() != std::string( "ActiveMQ" ).size() ) {
        return false;
    }

    if( magic[0] != 'A' ||
        magic[1] != 'c' ||
        magic[2] != 't' ||
        magic[3] != 'i' ||
        magic[4] != 'v' ||
        magic[5] != 'e' ||
        magic[6] != 'M' ||
        magic[7] != 'Q' ) {

        return false;
    }

    return true;
}

////////////////////////////////////////////////////////////////////////////////
bool WireFormatInfo::isStackTraceEnabled() const {

    try {
        return properties.getBool( "StackTraceEnabled" );
    }
    AMQ_CATCH_NOTHROW( exceptions::ActiveMQException )
    AMQ_CATCHALL_NOTHROW()

    return false;
}

////////////////////////////////////////////////////////////////////////////////
void WireFormatInfo::setStackTraceEnabled( bool stackTraceEnabled ) {

    try {
        properties.setBool( "StackTraceEnabled", stackTraceEnabled );
    }
    AMQ_CATCH_NOTHROW( exceptions::ActiveMQException )
    AMQ_CATCHALL_NOTHROW()
}

////////////////////////////////////////////////////////////////////////////////
bool WireFormatInfo::isTcpNoDelayEnabled() const {

    try {
        return properties.getBool( "TcpNoDelayEnabled" );
    }
    AMQ_CATCH_NOTHROW( exceptions::ActiveMQException )
    AMQ_CATCHALL_NOTHROW()

    return false;
}

////////////////////////////////////////////////////////////////////////////////
void WireFormatInfo::setTcpNoDelayEnabled( bool tcpNoDelayEnabled ) {

    try {
        properties.setBool( "TcpNoDelayEnabled", tcpNoDelayEnabled );
    }
    AMQ_CATCH_NOTHROW( exceptions::ActiveMQException )
    AMQ_CATCHALL_NOTHROW()
}

////////////////////////////////////////////////////////////////////////////////
bool WireFormatInfo::isCacheEnabled() const {

    try {
        return false;
    }
    AMQ_CATCH_NOTHROW( exceptions::ActiveMQException )
    AMQ_CATCHALL_NOTHROW()

    return false;
}

////////////////////////////////////////////////////////////////////////////////
void WireFormatInfo::setCacheEnabled( bool cacheEnabled AMQCPP_UNUSED ) {

    try {
        // Turning this on is not supported as it causes the client to not work.
        properties.setBool( "CacheEnabled", false );
    }
    AMQ_CATCH_NOTHROW( exceptions::ActiveMQException )
    AMQ_CATCHALL_NOTHROW()
}

////////////////////////////////////////////////////////////////////////////////
bool WireFormatInfo::isTightEncodingEnabled() const {

    try {
        return properties.getBool( "TightEncodingEnabled" );
    }
    AMQ_CATCH_NOTHROW( exceptions::ActiveMQException )
    AMQ_CATCHALL_NOTHROW()

    return false;
}

////////////////////////////////////////////////////////////////////////////////
void WireFormatInfo::setTightEncodingEnabled( bool tightEncodingEnabled ) {

    try {
        properties.setBool( "TightEncodingEnabled", tightEncodingEnabled );
    }
    AMQ_CATCH_NOTHROW( exceptions::ActiveMQException )
    AMQ_CATCHALL_NOTHROW()
}

////////////////////////////////////////////////////////////////////////////////
bool WireFormatInfo::isSizePrefixDisabled() const {

    try {
        return properties.getBool( "SizePrefixDisabled" );
    }
    AMQ_CATCH_NOTHROW( exceptions::ActiveMQException )
    AMQ_CATCHALL_NOTHROW()

    return false;
}

////////////////////////////////////////////////////////////////////////////////
void WireFormatInfo::setSizePrefixDisabled( bool sizePrefixDisabled ) {

    try {
        properties.setBool( "SizePrefixDisabled", sizePrefixDisabled );
    }
    AMQ_CATCH_NOTHROW( exceptions::ActiveMQException )
    AMQ_CATCHALL_NOTHROW()
}

////////////////////////////////////////////////////////////////////////////////
void WireFormatInfo::beforeMarshal( WireFormat* wireFormat AMQCPP_UNUSED ) {

    try{

        marshalledProperties.clear();
        if( !properties.isEmpty() ) {
            marshal::PrimitiveTypesMarshaller::marshal(
                &properties, marshalledProperties );
        }
    }
    AMQ_CATCH_RETHROW( decaf::io::IOException )
    AMQ_CATCH_EXCEPTION_CONVERT( exceptions::ActiveMQException, decaf::io::IOException )
    AMQ_CATCHALL_THROW( decaf::io::IOException )
}

////////////////////////////////////////////////////////////////////////////////
void WireFormatInfo::afterUnmarshal( WireFormat* wireFormat AMQCPP_UNUSED ) {

    try{

        marshal::PrimitiveTypesMarshaller::unmarshal(
            &properties, marshalledProperties );
    }
    AMQ_CATCH_RETHROW( decaf::io::IOException )
    AMQ_CATCH_EXCEPTION_CONVERT( exceptions::ActiveMQException, decaf::io::IOException )
    AMQ_CATCHALL_THROW( decaf::io::IOException )
}

////////////////////////////////////////////////////////////////////////////////
long long WireFormatInfo::getMaxInactivityDuration() const {
    try {
        return properties.getLong( "MaxInactivityDuration" );
    }
    AMQ_CATCH_NOTHROW( exceptions::ActiveMQException )
    AMQ_CATCHALL_NOTHROW()

    return 0LL;
}

////////////////////////////////////////////////////////////////////////////////
void WireFormatInfo::setMaxInactivityDuration( long long maxInactivityDuration ) {
    try {
        properties.setLong( "MaxInactivityDuration", maxInactivityDuration );
    }
    AMQ_CATCH_NOTHROW( exceptions::ActiveMQException )
    AMQ_CATCHALL_NOTHROW()
}

////////////////////////////////////////////////////////////////////////////////
long long WireFormatInfo::getMaxInactivityDurationInitalDelay() const {
    try {
        return properties.getLong( "MaxInactivityDurationInitalDelay" );
    }
    AMQ_CATCH_NOTHROW( exceptions::ActiveMQException )
    AMQ_CATCHALL_NOTHROW()

    return 0LL;
}

////////////////////////////////////////////////////////////////////////////////
void WireFormatInfo::setMaxInactivityDurationInitalDelay( long long maxInactivityDurationInitalDelay ) {
    try {
        properties.setLong( "MaxInactivityDurationInitalDelay", maxInactivityDurationInitalDelay );
    }
    AMQ_CATCH_NOTHROW( exceptions::ActiveMQException )
    AMQ_CATCHALL_NOTHROW()
}

////////////////////////////////////////////////////////////////////////////////
int WireFormatInfo::getCacheSize() const {
    try {
        return properties.getInt( "CacheSize" );
    }
    AMQ_CATCH_NOTHROW( exceptions::ActiveMQException )
    AMQ_CATCHALL_NOTHROW()

    return 0;
}

////////////////////////////////////////////////////////////////////////////////
void WireFormatInfo::setCacheSize( int value ) {
    try {
        properties.setInt( "CacheSize", value );
    }
    AMQ_CATCH_NOTHROW( exceptions::ActiveMQException )
    AMQ_CATCHALL_NOTHROW()
}
<|endoftext|>


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

Program:   Medical Imaging & Interaction Toolkit
Language:  C++
Date:      $Date: 2008-10-02 16:21:08 +0200 (Do, 02 Okt 2008) $
Version:   $Revision: 13129 $

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html 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 "mitkAffineInteractor3D.h"
#include "mitkPointOperation.h"
#include "mitkPositionEvent.h"
#include "mitkStatusBar.h"
#include "mitkDataTreeNode.h"
#include "mitkInteractionConst.h"
#include "mitkAction.h"
#include "mitkStateEvent.h"
#include "mitkOperationEvent.h"
#include "mitkUndoController.h"
#include "mitkStateMachineFactory.h"
#include "mitkStateTransitionOperation.h"
#include "mitkBaseRenderer.h"
#include "mitkRenderingManager.h"
#include "mitkRotationOperation.h"

#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkInteractorStyle.h>
#include <vtkRenderer.h>
#include <vtkCamera.h>

namespace mitk
{

//how precise must the user pick the point
//default value
AffineInteractor3D
::AffineInteractor3D(const char * type, DataTreeNode* dataTreeNode, int /* n */ )
: Interactor( type, dataTreeNode ),
  m_Precision( 6.5 ),
  m_InteractionMode( INTERACTION_MODE_TRANSLATION )
{
  m_OriginalGeometry = Geometry3D::New();
}

AffineInteractor3D::~AffineInteractor3D()
{
}

void AffineInteractor3D::SetInteractionMode( unsigned int interactionMode )
{
  m_InteractionMode = interactionMode;
}

void AffineInteractor3D::SetInteractionModeToTranslation()
{
  m_InteractionMode = INTERACTION_MODE_TRANSLATION;
}

void AffineInteractor3D::SetInteractionModeToRotation()
{
  m_InteractionMode = INTERACTION_MODE_ROTATION;
}

unsigned int AffineInteractor3D::GetInteractionMode() const
{
  return m_InteractionMode;
}

void AffineInteractor3D::SetPrecision( ScalarType precision )
{
  m_Precision = precision;
}

// Overwritten since this class can handle it better!
float AffineInteractor3D
::CalculateJurisdiction(StateEvent const* stateEvent) const
{
  float returnValue = 0.5;

  // If it is a key event that can be handled in the current state,
  // then return 0.5
  DisplayPositionEvent const *disPosEvent =
    dynamic_cast <const DisplayPositionEvent *> (stateEvent->GetEvent());

  // Key event handling:
  if (disPosEvent == NULL)
  {
    // Check if the current state has a transition waiting for that key event.
    if (this->GetCurrentState()->GetTransition(stateEvent->GetId())!=NULL)
    {
      return 0.5;
    }
    else
    {
      return 0.0;
    }
  }

  //on MouseMove do nothing!
  //if (stateEvent->GetEvent()->GetType() == Type_MouseMove)
  //{
  //  return 0.0;
  //}

  //if the event can be understood and if there is a transition waiting for that event
  if (this->GetCurrentState()->GetTransition(stateEvent->GetId())!=NULL)
  {
    returnValue = 0.5;//it can be understood
  }

  int timeStep = disPosEvent->GetSender()->GetTimeStep();

  //CurveModel *curveModel = dynamic_cast<CurveModel *>(
  //  m_DataTreeNode->GetData() );

  //if ( curveModel != NULL )
  //{
  //  // Get the Geometry2D of the window the user interacts with (for 2D point
  //  // projection)
  //  BaseRenderer *renderer = stateEvent->GetEvent()->GetSender();
  //  const Geometry2D *projectionPlane = renderer->GetCurrentWorldGeometry2D();

  //  // For reading on the points, Ids etc
  //  //CurveModel::PointSetType *pointSet = curveModel->GetPointSet( timeStep );
  //  //if ( pointSet == NULL )
  //  //{
  //  //  return 0.0;
  //  //}

  //}
  return returnValue;
}

bool AffineInteractor3D
::ExecuteAction( Action *action, StateEvent const *stateEvent )
{
  bool ok = false;

  // Get data object
  BaseData *data = m_DataTreeNode->GetData();

  // Get Event and extract renderer
  const Event *event = stateEvent->GetEvent();
  BaseRenderer *renderer = NULL;
  vtkRenderWindow *renderWindow = NULL;
  vtkRenderWindowInteractor *renderWindowInteractor = NULL;
  vtkRenderer *currentVtkRenderer = NULL;
  vtkCamera *camera = NULL;

  if ( event != NULL )
  {
    renderer = event->GetSender();
    if ( renderer != NULL )
    {
      renderWindow = renderer->GetRenderWindow();
      if ( renderWindow != NULL )
      {
        renderWindowInteractor = renderWindow->GetInteractor();
        if ( renderWindowInteractor != NULL )
        {
          currentVtkRenderer = renderWindowInteractor
            ->GetInteractorStyle()->GetCurrentRenderer();
          if ( currentVtkRenderer != NULL )
          {
            camera = currentVtkRenderer->GetActiveCamera();
          }
        }
      }
    }
  }

  // Get the timestep to also support 3D+t
  int timeStep = 0;
  ScalarType timeInMS = 0.0;
  if ( renderer != NULL )
  {
    timeStep = renderer->GetTimeStep( data );
    timeInMS = renderer->GetTime();
  }

  // Make sure that the data (if time-resolved) has enough entries;
  // if not, create the required extra ones (empty)
  data->Expand( timeStep+1 );

  switch (action->GetActionId())
  {
  case AcDONOTHING:
    ok = true;
    break;

  case AcCHECKOBJECT:
    {
      // Re-enable VTK interactor (may have been disabled previously)
      if ( renderWindowInteractor != NULL )
      {
        renderWindowInteractor->Enable();
      }

      // Check if we have a DisplayPositionEvent
      const DisplayPositionEvent *dpe =
        dynamic_cast< const DisplayPositionEvent * >( stateEvent->GetEvent() );
      if ( dpe == NULL )
      {
        ok = true;
        break;
      }

      // Check if an object is present at the current mouse position
      DataTreeNode *pickedNode = dpe->GetPickedObjectNode();
      StateEvent *newStateEvent;
      if ( pickedNode == m_DataTreeNode )
      {
        // Yes: object will be selected
        newStateEvent = new StateEvent( EIDYES );
      }
      else
      {
        // No: back to start state
        newStateEvent = new StateEvent( EIDNO );
      }

      this->HandleEvent( newStateEvent );

      ok = true;
      break;
    }

  case AcDESELECTOBJECT:
    {
      // Color object white
      m_DataTreeNode->SetColor( 1.0, 1.0, 1.0 );
      RenderingManager::GetInstance()->RequestUpdateAll();
      ok = true;
      break;
    }

  case AcSELECTPICKEDOBJECT:
    {
      // Color object red
      m_DataTreeNode->SetColor( 1.0, 0.0, 0.0 );
      RenderingManager::GetInstance()->RequestUpdateAll();
      ok = true;
      break;
    }

  case AcINITMOVE:
    {
      // Disable VTK interactor until MITK interaction has been completed
      if ( renderWindowInteractor != NULL )
      {
        renderWindowInteractor->Disable();
      }

      // Check if we have a DisplayPositionEvent
      const DisplayPositionEvent *dpe =
        dynamic_cast< const DisplayPositionEvent * >( stateEvent->GetEvent() );
      if ( dpe == NULL )
      {
        ok = true;
        break;
      }

      DataTreeNode *pickedNode = dpe->GetPickedObjectNode();
      m_InitialInteractionPickedPoint = dpe->GetWorldPosition();

      m_InitialInteractionPointDisplay = dpe->GetDisplayPosition();
      if ( currentVtkRenderer != NULL )
      {
        vtkInteractorObserver::ComputeDisplayToWorld(
          currentVtkRenderer,
          m_InitialInteractionPointDisplay[0],
          m_InitialInteractionPointDisplay[1],
          0.0, //m_InitialInteractionPickedPoint[2],
          m_InitialInteractionPointWorld );
      }

      // Make deep copy of current Geometry3D of the plane
      data->UpdateOutputInformation(); // make sure that the Geometry is up-to-date
      m_OriginalGeometry = static_cast< Geometry3D * >(
        data->GetGeometry( timeStep )->Clone().GetPointer() );

      ok = true;
      break;
    }

  case AcMOVE:
    {
      // Check if we have a DisplayPositionEvent
      const DisplayPositionEvent *dpe =
        dynamic_cast< const DisplayPositionEvent * >( stateEvent->GetEvent() );
      if ( dpe == NULL )
      {
        ok = true;
        break;
      }

      m_CurrentInteractionPointDisplay = dpe->GetDisplayPosition();
      if ( currentVtkRenderer != NULL )
      {
        vtkInteractorObserver::ComputeDisplayToWorld(
          currentVtkRenderer,
          m_CurrentInteractionPointDisplay[0],
          m_CurrentInteractionPointDisplay[1],
          0.0, //m_InitialInteractionPickedPoint[2],
          m_CurrentInteractionPointWorld );
      }

      Vector3D interactionMove;
      interactionMove[0] = m_CurrentInteractionPointWorld[0] - m_InitialInteractionPointWorld[0];
      interactionMove[1] = m_CurrentInteractionPointWorld[1] - m_InitialInteractionPointWorld[1];
      interactionMove[2] = m_CurrentInteractionPointWorld[2] - m_InitialInteractionPointWorld[2];

      if ( m_InteractionMode == INTERACTION_MODE_TRANSLATION )
      {
        Vector3D objectNormal;
        objectNormal.SetVnlVector( data->GetGeometry( timeStep )->GetMatrixColumn( 2 ) );
        objectNormal.Normalize();

        Point3D origin = m_OriginalGeometry->GetOrigin();

        data->GetGeometry( timeStep )->SetOrigin(
          origin + objectNormal * (interactionMove * objectNormal) );
      }
      else if ( m_InteractionMode == INTERACTION_MODE_ROTATION )
      {
        if ( camera )
        {
          vtkFloatingPointType vpn[3];
          camera->GetViewPlaneNormal( vpn );

          Vector3D viewPlaneNormal;
          viewPlaneNormal[0] = vpn[0];
          viewPlaneNormal[1] = vpn[1];
          viewPlaneNormal[2] = vpn[2];

          Vector3D rotationAxis =
            itk::CrossProduct( viewPlaneNormal, interactionMove );
          rotationAxis.Normalize();

          int *size = currentVtkRenderer->GetSize();
          double l2 =
            (m_CurrentInteractionPointDisplay[0] - m_InitialInteractionPointDisplay[0]) *
            (m_CurrentInteractionPointDisplay[0] - m_InitialInteractionPointDisplay[0]) +
            (m_CurrentInteractionPointDisplay[1] - m_InitialInteractionPointDisplay[1]) *
            (m_CurrentInteractionPointDisplay[1] - m_InitialInteractionPointDisplay[1]);

          double rotationAngle = 360.0 * sqrt(l2/(size[0]*size[0]+size[1]*size[1]));

          // Use center of data bounding box as center of rotation
          Point3D rotationCenter = m_OriginalGeometry->GetBoundingBox()->GetCenter();;

          // Reset current Geometry3D to original state (pre-interaction) and
          // apply rotation
          RotationOperation op( OpROTATE, rotationCenter, rotationAxis, rotationAngle );
          Geometry3D::Pointer newGeometry = static_cast< Geometry3D * >(
            m_OriginalGeometry->Clone().GetPointer() );
          newGeometry->ExecuteOperation( &op );
          data->SetGeometry( newGeometry, timeStep );

        }
      }

      RenderingManager::GetInstance()->RequestUpdateAll();
      ok = true;
      break;
    }

  default:
    return Superclass::ExecuteAction( action, stateEvent );
  }

  return ok;
}

} // namespace<commit_msg>FIX (#2469): Use correct center of rotation for rotation mode in 3D affine interactor<commit_after>/*=========================================================================

Program:   Medical Imaging & Interaction Toolkit
Language:  C++
Date:      $Date: 2008-10-02 16:21:08 +0200 (Do, 02 Okt 2008) $
Version:   $Revision: 13129 $

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html 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 "mitkAffineInteractor3D.h"
#include "mitkPointOperation.h"
#include "mitkPositionEvent.h"
#include "mitkStatusBar.h"
#include "mitkDataTreeNode.h"
#include "mitkInteractionConst.h"
#include "mitkAction.h"
#include "mitkStateEvent.h"
#include "mitkOperationEvent.h"
#include "mitkUndoController.h"
#include "mitkStateMachineFactory.h"
#include "mitkStateTransitionOperation.h"
#include "mitkBaseRenderer.h"
#include "mitkRenderingManager.h"
#include "mitkRotationOperation.h"

#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkInteractorStyle.h>
#include <vtkRenderer.h>
#include <vtkCamera.h>

namespace mitk
{

//how precise must the user pick the point
//default value
AffineInteractor3D
::AffineInteractor3D(const char * type, DataTreeNode* dataTreeNode, int /* n */ )
: Interactor( type, dataTreeNode ),
  m_Precision( 6.5 ),
  m_InteractionMode( INTERACTION_MODE_TRANSLATION )
{
  m_OriginalGeometry = Geometry3D::New();
}

AffineInteractor3D::~AffineInteractor3D()
{
}

void AffineInteractor3D::SetInteractionMode( unsigned int interactionMode )
{
  m_InteractionMode = interactionMode;
}

void AffineInteractor3D::SetInteractionModeToTranslation()
{
  m_InteractionMode = INTERACTION_MODE_TRANSLATION;
}

void AffineInteractor3D::SetInteractionModeToRotation()
{
  m_InteractionMode = INTERACTION_MODE_ROTATION;
}

unsigned int AffineInteractor3D::GetInteractionMode() const
{
  return m_InteractionMode;
}

void AffineInteractor3D::SetPrecision( ScalarType precision )
{
  m_Precision = precision;
}

// Overwritten since this class can handle it better!
float AffineInteractor3D
::CalculateJurisdiction(StateEvent const* stateEvent) const
{
  float returnValue = 0.5;

  // If it is a key event that can be handled in the current state,
  // then return 0.5
  DisplayPositionEvent const *disPosEvent =
    dynamic_cast <const DisplayPositionEvent *> (stateEvent->GetEvent());

  // Key event handling:
  if (disPosEvent == NULL)
  {
    // Check if the current state has a transition waiting for that key event.
    if (this->GetCurrentState()->GetTransition(stateEvent->GetId())!=NULL)
    {
      return 0.5;
    }
    else
    {
      return 0.0;
    }
  }

  //on MouseMove do nothing!
  //if (stateEvent->GetEvent()->GetType() == Type_MouseMove)
  //{
  //  return 0.0;
  //}

  //if the event can be understood and if there is a transition waiting for that event
  if (this->GetCurrentState()->GetTransition(stateEvent->GetId())!=NULL)
  {
    returnValue = 0.5;//it can be understood
  }

  int timeStep = disPosEvent->GetSender()->GetTimeStep();

  //CurveModel *curveModel = dynamic_cast<CurveModel *>(
  //  m_DataTreeNode->GetData() );

  //if ( curveModel != NULL )
  //{
  //  // Get the Geometry2D of the window the user interacts with (for 2D point
  //  // projection)
  //  BaseRenderer *renderer = stateEvent->GetEvent()->GetSender();
  //  const Geometry2D *projectionPlane = renderer->GetCurrentWorldGeometry2D();

  //  // For reading on the points, Ids etc
  //  //CurveModel::PointSetType *pointSet = curveModel->GetPointSet( timeStep );
  //  //if ( pointSet == NULL )
  //  //{
  //  //  return 0.0;
  //  //}

  //}
  return returnValue;
}

bool AffineInteractor3D
::ExecuteAction( Action *action, StateEvent const *stateEvent )
{
  bool ok = false;

  // Get data object
  BaseData *data = m_DataTreeNode->GetData();

  // Get Event and extract renderer
  const Event *event = stateEvent->GetEvent();
  BaseRenderer *renderer = NULL;
  vtkRenderWindow *renderWindow = NULL;
  vtkRenderWindowInteractor *renderWindowInteractor = NULL;
  vtkRenderer *currentVtkRenderer = NULL;
  vtkCamera *camera = NULL;

  if ( event != NULL )
  {
    renderer = event->GetSender();
    if ( renderer != NULL )
    {
      renderWindow = renderer->GetRenderWindow();
      if ( renderWindow != NULL )
      {
        renderWindowInteractor = renderWindow->GetInteractor();
        if ( renderWindowInteractor != NULL )
        {
          currentVtkRenderer = renderWindowInteractor
            ->GetInteractorStyle()->GetCurrentRenderer();
          if ( currentVtkRenderer != NULL )
          {
            camera = currentVtkRenderer->GetActiveCamera();
          }
        }
      }
    }
  }

  // Get the timestep to also support 3D+t
  int timeStep = 0;
  ScalarType timeInMS = 0.0;
  if ( renderer != NULL )
  {
    timeStep = renderer->GetTimeStep( data );
    timeInMS = renderer->GetTime();
  }

  // Make sure that the data (if time-resolved) has enough entries;
  // if not, create the required extra ones (empty)
  data->Expand( timeStep+1 );

  switch (action->GetActionId())
  {
  case AcDONOTHING:
    ok = true;
    break;

  case AcCHECKOBJECT:
    {
      // Re-enable VTK interactor (may have been disabled previously)
      if ( renderWindowInteractor != NULL )
      {
        renderWindowInteractor->Enable();
      }

      // Check if we have a DisplayPositionEvent
      const DisplayPositionEvent *dpe =
        dynamic_cast< const DisplayPositionEvent * >( stateEvent->GetEvent() );
      if ( dpe == NULL )
      {
        ok = true;
        break;
      }

      // Check if an object is present at the current mouse position
      DataTreeNode *pickedNode = dpe->GetPickedObjectNode();
      StateEvent *newStateEvent;
      if ( pickedNode == m_DataTreeNode )
      {
        // Yes: object will be selected
        newStateEvent = new StateEvent( EIDYES );
      }
      else
      {
        // No: back to start state
        newStateEvent = new StateEvent( EIDNO );
      }

      this->HandleEvent( newStateEvent );

      ok = true;
      break;
    }

  case AcDESELECTOBJECT:
    {
      // Color object white
      m_DataTreeNode->SetColor( 1.0, 1.0, 1.0 );
      RenderingManager::GetInstance()->RequestUpdateAll();
      ok = true;
      break;
    }

  case AcSELECTPICKEDOBJECT:
    {
      // Color object red
      m_DataTreeNode->SetColor( 1.0, 0.0, 0.0 );
      RenderingManager::GetInstance()->RequestUpdateAll();
      ok = true;
      break;
    }

  case AcINITMOVE:
    {
      // Disable VTK interactor until MITK interaction has been completed
      if ( renderWindowInteractor != NULL )
      {
        renderWindowInteractor->Disable();
      }

      // Check if we have a DisplayPositionEvent
      const DisplayPositionEvent *dpe =
        dynamic_cast< const DisplayPositionEvent * >( stateEvent->GetEvent() );
      if ( dpe == NULL )
      {
        ok = true;
        break;
      }

      DataTreeNode *pickedNode = dpe->GetPickedObjectNode();
      m_InitialInteractionPickedPoint = dpe->GetWorldPosition();

      m_InitialInteractionPointDisplay = dpe->GetDisplayPosition();
      if ( currentVtkRenderer != NULL )
      {
        vtkInteractorObserver::ComputeDisplayToWorld(
          currentVtkRenderer,
          m_InitialInteractionPointDisplay[0],
          m_InitialInteractionPointDisplay[1],
          0.0, //m_InitialInteractionPickedPoint[2],
          m_InitialInteractionPointWorld );
      }

      // Make deep copy of current Geometry3D of the plane
      data->UpdateOutputInformation(); // make sure that the Geometry is up-to-date
      m_OriginalGeometry = static_cast< Geometry3D * >(
        data->GetGeometry( timeStep )->Clone().GetPointer() );

      ok = true;
      break;
    }

  case AcMOVE:
    {
      // Check if we have a DisplayPositionEvent
      const DisplayPositionEvent *dpe =
        dynamic_cast< const DisplayPositionEvent * >( stateEvent->GetEvent() );
      if ( dpe == NULL )
      {
        ok = true;
        break;
      }

      m_CurrentInteractionPointDisplay = dpe->GetDisplayPosition();
      if ( currentVtkRenderer != NULL )
      {
        vtkInteractorObserver::ComputeDisplayToWorld(
          currentVtkRenderer,
          m_CurrentInteractionPointDisplay[0],
          m_CurrentInteractionPointDisplay[1],
          0.0, //m_InitialInteractionPickedPoint[2],
          m_CurrentInteractionPointWorld );
      }

      Vector3D interactionMove;
      interactionMove[0] = m_CurrentInteractionPointWorld[0] - m_InitialInteractionPointWorld[0];
      interactionMove[1] = m_CurrentInteractionPointWorld[1] - m_InitialInteractionPointWorld[1];
      interactionMove[2] = m_CurrentInteractionPointWorld[2] - m_InitialInteractionPointWorld[2];

      if ( m_InteractionMode == INTERACTION_MODE_TRANSLATION )
      {
        Vector3D objectNormal;
        objectNormal.SetVnlVector( data->GetGeometry( timeStep )->GetMatrixColumn( 2 ) );
        objectNormal.Normalize();

        Point3D origin = m_OriginalGeometry->GetOrigin();

        data->GetGeometry( timeStep )->SetOrigin(
          origin + objectNormal * (interactionMove * objectNormal) );
      }
      else if ( m_InteractionMode == INTERACTION_MODE_ROTATION )
      {
        if ( camera )
        {
          vtkFloatingPointType vpn[3];
          camera->GetViewPlaneNormal( vpn );

          Vector3D viewPlaneNormal;
          viewPlaneNormal[0] = vpn[0];
          viewPlaneNormal[1] = vpn[1];
          viewPlaneNormal[2] = vpn[2];

          Vector3D rotationAxis =
            itk::CrossProduct( viewPlaneNormal, interactionMove );
          rotationAxis.Normalize();

          int *size = currentVtkRenderer->GetSize();
          double l2 =
            (m_CurrentInteractionPointDisplay[0] - m_InitialInteractionPointDisplay[0]) *
            (m_CurrentInteractionPointDisplay[0] - m_InitialInteractionPointDisplay[0]) +
            (m_CurrentInteractionPointDisplay[1] - m_InitialInteractionPointDisplay[1]) *
            (m_CurrentInteractionPointDisplay[1] - m_InitialInteractionPointDisplay[1]);

          double rotationAngle = 360.0 * sqrt(l2/(size[0]*size[0]+size[1]*size[1]));

          // Use center of data bounding box as center of rotation
          Point3D rotationCenter = m_OriginalGeometry->GetCenter();;

          // Reset current Geometry3D to original state (pre-interaction) and
          // apply rotation
          RotationOperation op( OpROTATE, rotationCenter, rotationAxis, rotationAngle );
          Geometry3D::Pointer newGeometry = static_cast< Geometry3D * >(
            m_OriginalGeometry->Clone().GetPointer() );
          newGeometry->ExecuteOperation( &op );
          data->SetGeometry( newGeometry, timeStep );

        }
      }

      RenderingManager::GetInstance()->RequestUpdateAll();
      ok = true;
      break;
    }

  default:
    return Superclass::ExecuteAction( action, stateEvent );
  }

  return ok;
}

} // namespace<|endoftext|>


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

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center (DKFZ)
All rights reserved.

Use of this source code is governed by a 3-clause BSD license that can be
found in the LICENSE file.

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

#include "mitkSetRegionTool.h"

#include "mitkToolManager.h"

#include "mitkBaseRenderer.h"
#include "mitkImageDataItem.h"
#include "mitkLabelSetImage.h"

#include <mitkITKImageImport.h>
#include <mitkImagePixelReadAccessor.h>
#include <mitkImageToContourModelFilter.h>

#include <itkBinaryFillholeImageFilter.h>
#include <itkConnectedThresholdImageFilter.h>

mitk::SetRegionTool::SetRegionTool(int paintingPixelValue)
  : FeedbackContourTool("PressMoveRelease"), m_PaintingPixelValue(paintingPixelValue)
{
}

mitk::SetRegionTool::~SetRegionTool()
{
}

void mitk::SetRegionTool::ConnectActionsAndFunctions()
{
  CONNECT_FUNCTION("PrimaryButtonPressed", OnMousePressed);
  CONNECT_FUNCTION("Release", OnMouseReleased);
  CONNECT_FUNCTION("Move", OnMouseMoved);
}

void mitk::SetRegionTool::Activated()
{
  Superclass::Activated();
}

void mitk::SetRegionTool::Deactivated()
{
  Superclass::Deactivated();
}

void mitk::SetRegionTool::OnMousePressed(StateMachineAction *, InteractionEvent *interactionEvent)
{
  auto *positionEvent = dynamic_cast<mitk::InteractionPositionEvent *>(interactionEvent);
  if (!positionEvent)
    return;

  m_LastEventSender = positionEvent->GetSender();
  m_LastEventSlice = m_LastEventSender->GetSlice();

  // 1. Get the working image
  Image::Pointer workingSlice = FeedbackContourTool::GetAffectedWorkingSlice(positionEvent);
  if (workingSlice.IsNull())
    return; // can't do anything without the segmentation

  // if click was outside the image, don't continue
  const BaseGeometry *sliceGeometry = workingSlice->GetGeometry();
  itk::Index<3> projectedPointIn2D;
  sliceGeometry->WorldToIndex(positionEvent->GetPositionInWorld(), projectedPointIn2D);
  if (!sliceGeometry->IsIndexInside(projectedPointIn2D))
  {
    MITK_WARN << "Point outside of segmentation slice." << std::endl;
    return; // can't use that as a seed point
  }

  typedef itk::Image<DefaultSegmentationDataType, 2> InputImageType;
  typedef InputImageType::IndexType IndexType;
  typedef itk::ConnectedThresholdImageFilter<InputImageType, InputImageType> RegionGrowingFilterType;
  RegionGrowingFilterType::Pointer regionGrower = RegionGrowingFilterType::New();

  // convert world coordinates to image indices
  IndexType seedIndex;
  sliceGeometry->WorldToIndex(positionEvent->GetPositionInWorld(), seedIndex);

  // perform region growing in desired segmented region
  InputImageType::Pointer itkImage = InputImageType::New();
  CastToItkImage(workingSlice, itkImage);
  regionGrower->SetInput(itkImage);
  regionGrower->AddSeed(seedIndex);

  InputImageType::PixelType bound = itkImage->GetPixel(seedIndex);

  regionGrower->SetLower(bound);
  regionGrower->SetUpper(bound);
  regionGrower->SetReplaceValue(1);

  itk::BinaryFillholeImageFilter<InputImageType>::Pointer fillHolesFilter =
    itk::BinaryFillholeImageFilter<InputImageType>::New();

  fillHolesFilter->SetInput(regionGrower->GetOutput());
  fillHolesFilter->SetForegroundValue(1);

  // Store result and preview
  mitk::Image::Pointer resultImage = mitk::GrabItkImageMemory(fillHolesFilter->GetOutput());
  resultImage->SetGeometry(workingSlice->GetGeometry());
  // Get the current working color
  DataNode *workingNode(m_ToolManager->GetWorkingData(0));
  if (!workingNode)
    return;

  mitk::ImageToContourModelFilter::Pointer contourextractor = mitk::ImageToContourModelFilter::New();
  contourextractor->SetInput(resultImage);
  contourextractor->Update();

  mitk::ContourModel::Pointer awesomeContour = contourextractor->GetOutput();
  auto t = positionEvent->GetSender()->GetTimeStep();

  FeedbackContourTool::SetFeedbackContour(0 != t
    ? ContourModelUtils::MoveZerothContourTimeStep(awesomeContour, t)
    : awesomeContour);

  FeedbackContourTool::SetFeedbackContourVisible(true);
  mitk::RenderingManager::GetInstance()->RequestUpdate(positionEvent->GetSender()->GetRenderWindow());
}

void mitk::SetRegionTool::OnMouseReleased(StateMachineAction *, InteractionEvent *interactionEvent)
{
  auto *positionEvent = dynamic_cast<mitk::InteractionPositionEvent *>(interactionEvent);
  if (!positionEvent)
    return;

  assert(positionEvent->GetSender()->GetRenderWindow());
  // 1. Hide the feedback contour, find out which slice the user clicked, find out which slice of the toolmanager's
  // working image corresponds to that
  FeedbackContourTool::SetFeedbackContourVisible(false);
  mitk::RenderingManager::GetInstance()->RequestUpdate(positionEvent->GetSender()->GetRenderWindow());

  int timeStep = positionEvent->GetSender()->GetTimeStep();

  DataNode *workingNode(m_ToolManager->GetWorkingData(0));
  if (!workingNode)
    return;

  auto *image = dynamic_cast<Image *>(workingNode->GetData());
  const PlaneGeometry *planeGeometry((positionEvent->GetSender()->GetCurrentWorldPlaneGeometry()));
  if (!image || !planeGeometry)
    return;

  Image::Pointer slice = FeedbackContourTool::GetAffectedImageSliceAs2DImage(positionEvent, image);

  if (slice.IsNull())
  {
    MITK_ERROR << "Unable to extract slice." << std::endl;
    return;
  }

  ContourModel *feedbackContour(FeedbackContourTool::GetFeedbackContour());
  ContourModel::Pointer projectedContour = FeedbackContourTool::ProjectContourTo2DSlice(
    slice, feedbackContour, false, false); // false: don't add 0.5 (done by FillContourInSlice)
  // false: don't constrain the contour to the image's inside
  if (projectedContour.IsNull())
    return;

  int activePixelValue = ContourModelUtils::GetActivePixelValue(image);

  mitk::ContourModelUtils::FillContourInSlice(
    projectedContour, timeStep, slice, image, m_PaintingPixelValue * activePixelValue);

  this->WriteBackSegmentationResult(positionEvent, slice);
}

void mitk::SetRegionTool::OnMouseMoved(mitk::StateMachineAction *, mitk::InteractionEvent *)
{
}
<commit_msg>Refactored SetRegionTool<commit_after>/*============================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center (DKFZ)
All rights reserved.

Use of this source code is governed by a 3-clause BSD license that can be
found in the LICENSE file.

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

#include "mitkSetRegionTool.h"

#include "mitkToolManager.h"

#include "mitkBaseRenderer.h"

#include <mitkITKImageImport.h>
#include <mitkImageToContourModelFilter.h>

#include <itkBinaryFillholeImageFilter.h>
#include <itkConnectedThresholdImageFilter.h>

mitk::SetRegionTool::SetRegionTool(int paintingPixelValue)
  : FeedbackContourTool("PressMoveRelease"), m_PaintingPixelValue(paintingPixelValue)
{
}

mitk::SetRegionTool::~SetRegionTool()
{
}

void mitk::SetRegionTool::ConnectActionsAndFunctions()
{
  CONNECT_FUNCTION("PrimaryButtonPressed", OnMousePressed);
  CONNECT_FUNCTION("Release", OnMouseReleased);
  CONNECT_FUNCTION("Move", OnMouseMoved);
}

void mitk::SetRegionTool::Activated()
{
  Superclass::Activated();
}

void mitk::SetRegionTool::Deactivated()
{
  Superclass::Deactivated();
}

void mitk::SetRegionTool::OnMousePressed(StateMachineAction *, InteractionEvent *interactionEvent)
{
  auto *positionEvent = dynamic_cast<mitk::InteractionPositionEvent *>(interactionEvent);
  if (!positionEvent)
    return;

  m_LastEventSender = positionEvent->GetSender();
  m_LastEventSlice = m_LastEventSender->GetSlice();

  // 1. Get the working image
  Image::Pointer workingSlice = FeedbackContourTool::GetAffectedWorkingSlice(positionEvent);
  if (workingSlice.IsNull())
    return; // can't do anything without the segmentation

  // if click was outside the image, don't continue
  const BaseGeometry *sliceGeometry = workingSlice->GetGeometry();
  itk::Index<3> projectedPointIn2D;
  sliceGeometry->WorldToIndex(positionEvent->GetPositionInWorld(), projectedPointIn2D);
  if (!sliceGeometry->IsIndexInside(projectedPointIn2D))
  {
    MITK_WARN << "Point outside of segmentation slice." << std::endl;
    return; // can't use that as a seed point
  }

  typedef itk::Image<DefaultSegmentationDataType, 2> InputImageType;
  typedef InputImageType::IndexType IndexType;
  typedef itk::ConnectedThresholdImageFilter<InputImageType, InputImageType> RegionGrowingFilterType;
  RegionGrowingFilterType::Pointer regionGrower = RegionGrowingFilterType::New();

  // convert world coordinates to image indices
  IndexType seedIndex;
  sliceGeometry->WorldToIndex(positionEvent->GetPositionInWorld(), seedIndex);

  // perform region growing in desired segmented region
  InputImageType::Pointer itkImage = InputImageType::New();
  CastToItkImage(workingSlice, itkImage);
  regionGrower->SetInput(itkImage);
  regionGrower->AddSeed(seedIndex);

  InputImageType::PixelType bound = itkImage->GetPixel(seedIndex);

  regionGrower->SetLower(bound);
  regionGrower->SetUpper(bound);
  regionGrower->SetReplaceValue(1);

  itk::BinaryFillholeImageFilter<InputImageType>::Pointer fillHolesFilter =
    itk::BinaryFillholeImageFilter<InputImageType>::New();

  fillHolesFilter->SetInput(regionGrower->GetOutput());
  fillHolesFilter->SetForegroundValue(1);

  // Store result and preview
  mitk::Image::Pointer resultImage = mitk::GrabItkImageMemory(fillHolesFilter->GetOutput());
  resultImage->SetGeometry(workingSlice->GetGeometry());
  // Get the current working color
  DataNode *workingNode(m_ToolManager->GetWorkingData(0));
  if (!workingNode)
    return;

  mitk::ImageToContourModelFilter::Pointer contourextractor = mitk::ImageToContourModelFilter::New();
  contourextractor->SetInput(resultImage);
  contourextractor->Update();

  mitk::ContourModel::Pointer awesomeContour = contourextractor->GetOutput();

  this->UpdateCurrentFeedbackContour(awesomeContour);

  FeedbackContourTool::SetFeedbackContourVisible(true);
  mitk::RenderingManager::GetInstance()->RequestUpdate(positionEvent->GetSender()->GetRenderWindow());
}

void mitk::SetRegionTool::OnMouseReleased(StateMachineAction *, InteractionEvent *interactionEvent)
{
  auto *positionEvent = dynamic_cast<mitk::InteractionPositionEvent *>(interactionEvent);
  if (!positionEvent)
    return;

  assert(positionEvent->GetSender()->GetRenderWindow());
  // 1. Hide the feedback contour, find out which slice the user clicked, find out which slice of the toolmanager's
  // working image corresponds to that
  mitk::RenderingManager::GetInstance()->RequestUpdate(positionEvent->GetSender()->GetRenderWindow());

  this->WriteBackFeedbackContourAsSegmentationResult(positionEvent, m_PaintingPixelValue);
}

void mitk::SetRegionTool::OnMouseMoved(mitk::StateMachineAction *, mitk::InteractionEvent *)
{
}
<|endoftext|>


<commit_before>#include <OpenSim/OpenSim.h>

using namespace OpenSim;
using namespace SimTK;

class ComplexResponse : public ModelComponent {
    OpenSim_DECLARE_CONCRETE_OBJECT(ComplexResponse, ModelComponent);
public:
    OpenSim_DECLARE_PROPERTY(strength, double, "per-coord param.");
    ComplexResponse() {
        constructInfrastructure();
        constructProperty_strength(3.0);
    }
    double getTerm1(const State& s) const {
        if (!isCacheVariableValid(s, "term_1")) {
            const auto& coord = getConnectee<Coordinate>("coord");
            const auto value = coord.getValue(s);
            setCacheVariableValue(s, "term_1", get_strength() * value);
            markCacheVariableValid(s, "term_1");
        }
        return getCacheVariableValue<double>(s, "term_1");
    }
    double getTerm2(const State& s) const {
        if (!isCacheVariableValid(s, "term_2")) {
            const auto& coord = getConnectee<Coordinate>("coord");
            const auto speed = coord.getSpeedValue(s);
            setCacheVariableValue(s, "term_2", 2.0 * speed);
            markCacheVariableValid(s, "term_2");
        }
        return getCacheVariableValue<double>(s, "term_2");
    }
    double getTotal(const State& s) const {
        if (!isCacheVariableValid(s, "sum")) {
            const auto& coord = getConnectee<Coordinate>("coord");
            const auto speed = coord.getSpeedValue(s);
            setCacheVariableValue(s, "sum", getTerm1(s) + getTerm2(s));
            markCacheVariableValid(s, "sum");
        }
        return getCacheVariableValue<double>(s, "sum");
    }
private:
    void constructConnectors() override {
        constructConnector<Coordinate>("coord");
    }
    void constructOutputs() override {
        constructOutput<double>("term_1",
                &ComplexResponse::getTerm1, SimTK::Stage::Position);
        constructOutput<double>("term_2",
                &ComplexResponse::getTerm2, SimTK::Stage::Velocity);
        constructOutput<double>("sum", &ComplexResponse::getTotal,
                SimTK::Stage::Time);
    }
    void extendAddToSystem(MultibodySystem& system) const override {
        Super::extendAddToSystem(system);
        addCacheVariable<double>("term_1",
                0.0, SimTK::Stage::Velocity);
        addCacheVariable<double>("term_2",
                0.0, SimTK::Stage::Velocity);
        addCacheVariable<double>("sum",
                0.0, SimTK::Stage::Velocity);
    }
};

//class AggregateResponse : public ModelComponent {
//    OpenSim_DECLARE_LIST_PROPERTY(responses, ComplexResponse,
//            "for individual coordinates.");
//    OpenSim_DECLARE_PROPERTY(scaling_factor, double, "Affects each coord.");
//};

template <typename T>
class ConsoleReporter : public ModelComponent {
    OpenSim_DECLARE_CONCRETE_OBJECT(ConsoleReporter, Component);
public:
    ConsoleReporter() {
        constructInfrastructure();
    }
private:
    void constructInputs() override {
        constructInput<T>("input", SimTK::Stage::Acceleration);
        // multi input: constructMultiInput<T>("input", SimTK::Stage::Acceleration);
    }
    void extendRealizeReport(const State& state) const override {
        // multi input: loop through multi-inputs.
        std::cout << std::setw(10) << state.getTime() << ": " <<
            getInputValue<T>(state, "input") << std::endl;
    }
};

void integrate(const System& system, Integrator& integrator,
        const State& initialState,
        Real finalTime) {
    TimeStepper ts(system, integrator);
    ts.initialize(initialState);
    ts.setReportAllSignificantStates(true);
    integrator.setReturnEveryInternalStep(true);
    while (ts.getState().getTime() < finalTime) {
        ts.stepTo(finalTime);
        system.realize(ts.getState(), SimTK::Stage::Report);
    }
}

void testComplexResponse() {
    Model model;
    auto b1 = new OpenSim::Body("b1", 1, Vec3(0), Inertia(0));
    auto b2 = new OpenSim::Body("b2", 1, Vec3(0), Inertia(0));
    auto b3 = new OpenSim::Body("b3", 1, Vec3(0), Inertia(0));
    auto j1 = new PinJoint("j1", model.getGround(), Vec3(0), Vec3(0),
            *b1, Vec3(0, 1, 0), Vec3(0));
    auto j2 = new PinJoint("j2", *b1, Vec3(0), Vec3(0),
               *b2, Vec3(0, 1, 0), Vec3(0));
    auto j3 = new PinJoint("j3", *b2, Vec3(0), Vec3(0),
               *b3, Vec3(0, 1, 0), Vec3(0));

    auto cr = new ComplexResponse();
    cr->setName("complex_response");
    cr->updConnector<Coordinate>("coord").set_connectee_name("j1_coord_0");

    auto reporter = new ConsoleReporter<double>();
    reporter->setName("reporter");
    reporter->getInput("input").connect(cr->getOutput("sum"));
    // TODO connect by path: reporter->getInput("input").connect("/complex_response/sum");
    // multi input: reporter->getMultiInput("input").append_connect(cr->getOutput("sum"));

    model.addBody(b1);
    model.addBody(b2);
    model.addBody(b3);
    model.addJoint(j1);
    model.addJoint(j2);
    model.addJoint(j3);
    model.addModelComponent(cr);
    model.addModelComponent(reporter);

    State& state = model.initSystem();

    model.updCoordinateSet().get("j1_coord_0").setValue(state, 0.5 * Pi);

    RungeKuttaMersonIntegrator integrator(model.getSystem());
    integrate(model.getSystem(), integrator, state, 1);
}

int main() {
    SimTK_START_TEST("futureMuscleMetabolicsResponse");
        SimTK_SUBTEST(testComplexResponse);
    SimTK_END_TEST();
}
<commit_msg>[future] Start exploring aggregate response.<commit_after>#include <OpenSim/OpenSim.h>

using namespace OpenSim;
using namespace SimTK;

class ComplexResponse : public ModelComponent {
    OpenSim_DECLARE_CONCRETE_OBJECT(ComplexResponse, ModelComponent);
public:
    OpenSim_DECLARE_PROPERTY(strength, double, "per-coord param.");
    ComplexResponse() {
        constructInfrastructure();
        constructProperty_strength(3.0);
    }
    double getTerm1(const State& s) const {
        if (!isCacheVariableValid(s, "term_1")) {
            const auto& coord = getConnectee<Coordinate>("coord");
            const auto value = coord.getValue(s);
            setCacheVariableValue(s, "term_1", get_strength() * value);
            markCacheVariableValid(s, "term_1");
        }
        return getCacheVariableValue<double>(s, "term_1");
    }
    double getTerm2(const State& s) const {
        if (!isCacheVariableValid(s, "term_2")) {
            const auto& coord = getConnectee<Coordinate>("coord");
            const auto speed = coord.getSpeedValue(s);
            setCacheVariableValue(s, "term_2", 2.0 * speed);
            markCacheVariableValid(s, "term_2");
        }
        return getCacheVariableValue<double>(s, "term_2");
    }
    double getTotal(const State& s) const {
        if (!isCacheVariableValid(s, "sum")) {
            const auto& coord = getConnectee<Coordinate>("coord");
            const auto speed = coord.getSpeedValue(s);
            setCacheVariableValue(s, "sum", getTerm1(s) + getTerm2(s));
            markCacheVariableValid(s, "sum");
        }
        return getCacheVariableValue<double>(s, "sum");
    }
private:
    void constructConnectors() override {
        constructConnector<Coordinate>("coord");
    }
    void constructOutputs() override {
        constructOutput<double>("term_1",
                &ComplexResponse::getTerm1, SimTK::Stage::Position);
        constructOutput<double>("term_2",
                &ComplexResponse::getTerm2, SimTK::Stage::Velocity);
        constructOutput<double>("sum", &ComplexResponse::getTotal,
                SimTK::Stage::Velocity);
    }
    void extendAddToSystem(MultibodySystem& system) const override {
        Super::extendAddToSystem(system);
        addCacheVariable<double>("term_1",
                0.0, SimTK::Stage::Velocity);
        addCacheVariable<double>("term_2",
                0.0, SimTK::Stage::Velocity);
        addCacheVariable<double>("sum",
                0.0, SimTK::Stage::Velocity);
    }
};

class AggregateResponse : public ModelComponent {
    OpenSim_DECLARE_CONCRETE_OBJECT(AggregateResponse, ModelComponent);
public:
    AggregateResponse() { constructInfrastructure(); }
// TODO want to use list property, but that makes clones and inputs/outputs
// don't get copied yet.
//    OpenSim_DECLARE_LIST_PROPERTY(responses, ComplexResponse,
//            "for individual coordinates.");
    // Temporary solution:
    std::vector<std::shared_ptr<ComplexResponse>> responses;

    // TODO how do we propagate this scaling_factor to the ComplexResponses?
    OpenSim_DECLARE_PROPERTY(scaling_factor, double, "Affects each coord.");

    double getTotalSum(const State& s) const {
        const double basalRate = 1.0;
        double totalSum = 1.0;
        for (const auto& response : responses) {
            totalSum += response->getOutputValue<double>(s, "sum");
        }
        return totalSum;
    }

    double getTotalTerm1(const State& s) const {
        double totalTerm1;
        for (const auto& response : responses) {
            totalTerm1 += response->getOutputValue<double>(s, "term_1");
        }
        return totalTerm1;
    }

    double getTotalTerm2(const State& s) const {
        double totalTerm2;
        for (const auto& response : responses) {
            totalTerm2 += response->getOutputValue<double>(s, "term_2");
        }
        return totalTerm2;
    }

private:
    void extendFinalizeFromProperties() {
        Super::extendFinalizeFromProperties();
        for (auto& response : responses) {
            addComponent(response.get());
        }
    }
    void constructOutputs() override {
        constructOutput<double>("total_sum",
                &AggregateResponse::getTotalSum, SimTK::Stage::Position);
        constructOutput<double>("total_term_1",
                &AggregateResponse::getTotalTerm1, SimTK::Stage::Velocity);
        constructOutput<double>("total_term_2",
                &AggregateResponse::getTotalTerm2, SimTK::Stage::Velocity);
    }
};

template <typename T>
class ConsoleReporter : public ModelComponent {
    OpenSim_DECLARE_CONCRETE_OBJECT(ConsoleReporter, Component);
public:
    ConsoleReporter() {
        constructInfrastructure();
    }
private:
    void constructInputs() override {
        constructInput<T>("input1", SimTK::Stage::Acceleration);
        // constructInput<T>("input2", SimTK::Stage::Acceleration);
        constructInput<T>("input3", SimTK::Stage::Acceleration);
        // multi input: constructMultiInput<T>("input", SimTK::Stage::Acceleration);
    }
    void extendRealizeReport(const State& state) const override {
        // multi input: loop through multi-inputs.
        std::cout << std::setw(10) << state.getTime() << ": " <<
            getInputValue<T>(state, "input1") << " " <<
            // getInputValue<T>(state, "input2") << " " <<
            getInputValue<T>(state, "input3") << std::endl;
    }
};

void integrate(const System& system, Integrator& integrator,
        const State& initialState,
        Real finalTime) {
    TimeStepper ts(system, integrator);
    ts.initialize(initialState);
    ts.setReportAllSignificantStates(true);
    integrator.setReturnEveryInternalStep(true);
    while (ts.getState().getTime() < finalTime) {
        ts.stepTo(finalTime);
        system.realize(ts.getState(), SimTK::Stage::Report);
    }
}

void testComplexResponse() {
    Model model;
    auto b1 = new OpenSim::Body("b1", 1, Vec3(0), Inertia(0));
    auto b2 = new OpenSim::Body("b2", 1, Vec3(0), Inertia(0));
    auto b3 = new OpenSim::Body("b3", 1, Vec3(0), Inertia(0));
    auto j1 = new PinJoint("j1", model.getGround(), Vec3(0), Vec3(0),
            *b1, Vec3(0, 1, 0), Vec3(0));
    auto j2 = new PinJoint("j2", *b1, Vec3(0), Vec3(0),
               *b2, Vec3(0, 1, 0), Vec3(0));
    auto j3 = new PinJoint("j3", *b2, Vec3(0), Vec3(0),
               *b3, Vec3(0, 1, 0), Vec3(0));

    auto aggregate = new AggregateResponse();
    aggregate->setName("aggregate_response");
    aggregate->responses.push_back(
            std::shared_ptr<ComplexResponse>(new ComplexResponse()));
    aggregate->responses[0]->setName("complex_response_j1");
    aggregate->responses[0]->updConnector<Coordinate>("coord")
        .set_connectee_name("j1_coord_0");
    aggregate->responses.push_back(
            std::shared_ptr<ComplexResponse>(new ComplexResponse()));
    aggregate->responses[1]->setName("complex_response_j2");
    aggregate->responses[1]->updConnector<Coordinate>("coord")
        .set_connectee_name("j2_coord_0");

    auto reporter = new ConsoleReporter<double>();
    reporter->setName("reporter");
    reporter->getInput("input1").connect(aggregate->responses[0]->getOutput("sum"));
    //reporter->getInput("input2").connect(aggregate->responses[1]->getOutput("sum"));
    reporter->getInput("input3").connect(aggregate->getOutput("total_sum"));
    // TODO connect by path: reporter->getInput("input").connect("/complex_response/sum");
    // multi input: reporter->getMultiInput("input").append_connect(cr->getOutput("sum"));

    model.addBody(b1);
    model.addBody(b2);
    model.addBody(b3);
    model.addJoint(j1);
    model.addJoint(j2);
    model.addJoint(j3);
    model.addModelComponent(aggregate);
    model.addModelComponent(reporter);

    State& state = model.initSystem();

    model.updCoordinateSet().get("j1_coord_0").setValue(state, 0.5 * Pi);

    RungeKuttaMersonIntegrator integrator(model.getSystem());
    integrate(model.getSystem(), integrator, state, 1);
}

int main() {
    SimTK_START_TEST("futureMuscleMetabolicsResponse");
        SimTK_SUBTEST(testComplexResponse);
    SimTK_END_TEST();
}
<|endoftext|>