/*! \file demo_2d_autoscaling.cpp
    \brief Demonstration of autoscaling in 2D plots.
    \details  An example to demonstrate simplest 2d *default* settings.
     See also auto_2d_plot.cpp for a wider range of use.

    \date 20 Mar 2009
    \author Paul A. Bristow
*/
// Copyright Paul A Bristow 2009, 2021

// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)

// This file is written to be included from a Quickbook .qbk document.
// It can be compiled by the C++ compiler, and run. Any output can
// also be added here as comment or included or pasted in elsewhere.
// Caution: this file contains Quickbook markup as well as code
// and comments: don't change any of the special comment markups!

//[demo_2d_autoscaling_1

/*`As always, we need a few includes to use Boost.Plot:
*/

#include <boost/svg_plot/svg_2d_plot.hpp>
  //using namespace boost::svg;
  //using boost::svg::svg_2d_plot;

#include <iostream>
  //using std::cout;
  //using std::endl;
  //using std::dec;
  //using std::hex;

#include <map>
//  using std::map;
//] [demo_2d_autoscaling_1]

int main()
{

//[demo_2d_autoscaling_2
/*`Some fictional data is pushed into an STL container, here `std::map`:\n

  This example uses a single map to demonstrate autoscaling.
  We construct a `std::map` to hold our data-series, and insert some fictional values (that also sorts the data).
  The 'index' value in [ ] is the X value.
  */
  std::map<const double, double> my_data;
  my_data[1.1] = 3.2;
  my_data[7.3] = 9.1;
  my_data[2.12] = 2.4394;
  my_data[5.47] = 5.3861;

  using namespace boost::svg; // Convenient for access to named colors and data-point marker shapes.

  try
  {
    // try'n'catch blocks are needed to ensure error messages from any exceptions are shown by the catch block below.
   using boost::svg::svg_2d_plot;
    svg_2d_plot my_2d_plot; // Construct a plot with all the default constructor values.
    my_2d_plot.title("Autoscaling 2d Values"); // Add a string title of the plot.

/*` With the defaults ranges would be -10 to +10 for both X and Y axes.  We could chose our own ranges thus:
    `.x_range(0, 6) // Add a range for the X-axis.
    .y_range(0, 10) // Add a range for the Y-axis.`
  Or we can use autoscaling.

*/
   my_2d_plot.xy_autoscale(my_data); // Autoscale both X and Y axes.

/*`This says use the entire STL `std::map` container `my_data` to set both X and Y ranges.
(The data used to autoscale the range(s) does not have to be the same as the data being plotted.
For example, if we have analysed a product and know that an attribute like strength can only decline as the product ages,
it would make sense to use the reference 'as new' data to scale the plot for the 'aged' product samples).
*/

  /*`We can show the ranges used by autoscaling; */
   std::cout << "X min " << my_2d_plot.x_range().first << ", X max " << my_2d_plot.x_range().second << std::endl;
   std::cout << "Y min " << my_2d_plot.y_range().first << ", Y max "  << my_2d_plot.y_range().second << std::endl;

/*`Then add the (one but could be more) data-series, @c my_data and a description, and how the data-points are to be marked,
here a circle with a diameter of 5 pixels, without a line joining the points (also the default).
*/
    my_2d_plot.plot(my_data, "2d Values").shape(circlet).size(8).line_on(false);

/*`To use all these settings, finally write the plot to file.
*/
    my_2d_plot.write("./demo_2d_autoscaling.svg");

//] [demo_2d_autoscaling_2]
  }
  catch(const std::exception& e)
  {
    std::cout <<
      "\n""Message from thrown exception was:\n   " << e.what() << std::endl;
  }
  return 0;
} // int main()

/*

//[demo_2d_autoscaling_output

Output:
Checked: x_min 1.1, x_max 7.3, y_min 2.4394, y_max 9.1, 4 'good' values, 0 values at limits

*/


//
// OpenTissue, A toolbox for physical based simulation and animation.
// Copyright (C) 2007 Department of Computer Science, University of Copenhagen
//
#include <OpenTissue/configuration.h>

#include <OpenTissue/core/math/big/big_types.h>
#include <OpenTissue/core/math/math_basic_types.h>
#include <OpenTissue/kinematics/skeleton/skeleton_types.h>
#include <OpenTissue/kinematics/inverse/inverse_compute_jacobian.h>
#include <OpenTissue/kinematics/inverse/inverse_chain.h>

#define BOOST_AUTO_TEST_MAIN
#include <OpenTissue/utility/utility_push_boost_filter.h>
#include <boost/test/auto_unit_test.hpp>
#include <boost/test/unit_test_suite.hpp>
#include <boost/test/floating_point_comparison.hpp>
#include <boost/test/test_tools.hpp>
#include <OpenTissue/utility/utility_pop_boost_filter.h>

typedef float																             real_type;
typedef OpenTissue::math::default_math_types		  			 math_types;
typedef ublas::compressed_matrix<real_type>              matrix_type;

/**
* This is a dummy bone traits class implementation created just for
* the unit-test compile.
*
* The bone trait class was created to fill out the Jacobian
* matrix with the index of the bone. This way we can test
* which bones map into which sub-blocks in the resulting Jacobian matrix.
*
* param size and dofs were chosen to create Jacobian sub-blocks of
* size 1-by-1.
*/
class MyBoneTraits
  : public OpenTissue::skeleton::DefaultBoneTraits<math_types>
{
public:

  size_t active_dofs() const { return 1; };

  template<typename bone_type, typename chain_type, typename matrix_range>
  static void compute_jacobian( bone_type & bone, chain_type & chain, matrix_range & J )
  {
    BOOST_CHECK( J.size1() == chain.get_goal_dimension());
    BOOST_CHECK( J.size2() == 1);

    for( size_t i=0;i<chain.get_goal_dimension();++i)
      J(i,0) = 1.0f*bone.get_number();
  }

};

typedef OpenTissue::skeleton::Types<math_types,MyBoneTraits>      skeleton_types;
typedef skeleton_types::skeleton_type                             skeleton_type;
typedef skeleton_types::bone_type                                 bone_type;
typedef skeleton_types::bone_traits                               bone_traits;
typedef OpenTissue::kinematics::inverse::Chain< skeleton_type >   chain_type;

BOOST_AUTO_TEST_SUITE(opentissue_kinematics_inverse_compute_jacobian);

BOOST_AUTO_TEST_CASE(test_cases)
{
  skeleton_type skeleton;

  bone_type * b0 = skeleton.create_bone();
  bone_type * b1 = skeleton.create_bone(b0);
  bone_type * b2 = skeleton.create_bone(b1);
  bone_type * b3 = skeleton.create_bone(b0);

  // Create a few different kinematic chains
  std::vector<chain_type> chains;
  chains.resize( 3 );
  chains[0].init( b0, b2 );
  chains[1].init( b0, b1 );
  chains[2].init( b0, b3 );

  // Assemble Jacobian matrix of the kinematic chains.
  matrix_type J;
  OpenTissue::kinematics::inverse::compute_jacobian( chains.begin(), chains.end(), skeleton.begin(), skeleton.end(), J);

  // Verify that the assembled Jacobian has the expeced pattern and data.
  BOOST_CHECK( J.size1() == 9);
  BOOST_CHECK( J.size2() == 4);

  for( size_t i=0;i<chains[0].get_goal_dimension();++i)
  {
    BOOST_CHECK( J(i,0) == 1.0f*b0->get_number() );
    BOOST_CHECK( J(i,1) == 1.0f*b1->get_number() );
    BOOST_CHECK( J(i,2) == 1.0f*b2->get_number() );
    BOOST_CHECK( J(i,3) == 0.0f                  );
  }

  size_t offset = chains[0].get_goal_dimension();
  for( size_t i=0;i<chains[1].get_goal_dimension();++i)
  {

    BOOST_CHECK( J(i+offset,0) == 1.0f*b0->get_number() );
    BOOST_CHECK( J(i+offset,1) == 1.0f*b1->get_number() );
    BOOST_CHECK( J(i+offset,2) == 0.0f                  );
    BOOST_CHECK( J(i+offset,3) == 0.0f                  );
  }

  offset += chains[1].get_goal_dimension();
  for( size_t i=0;i<chains[2].get_goal_dimension();++i)
  {

    BOOST_CHECK( J(i+offset,0) == 1.0f*b0->get_number() );
    BOOST_CHECK( J(i+offset,1) == 0.0f                  );
    BOOST_CHECK( J(i+offset,2) == 0.0f                  );
    BOOST_CHECK( J(i+offset,3) == 1.0f*b3->get_number() );
  }
}

BOOST_AUTO_TEST_SUITE_END();