<commit_before>
#include "drake/systems/plants/RigidBodySystem.h"
#include "drake/systems/plants/RigidBodyFrame.h"
#include "drake/util/testUtil.h"

using namespace std;
using namespace Eigen;
using namespace Drake;

int main(int argc, char* argv[]) {
  if (argc < 2) {
    std::cerr << "Usage: " << argv[0]
              << " [options] full_path_to_robot1 full_path_to_robot2 x y z\n"
              << " The x y z parameters are optional and specify the position"
              << " of the second robot in the world, which is useful for URDF"
              << " models)"
              << std::endl;
    return 1;
  }

  std::shared_ptr<RigidBodyFrame> weld_to_frame;

  if (argc > 3) {
    weld_to_frame = allocate_shared<RigidBodyFrame>(
      aligned_allocator<RigidBodyFrame>(),
      "world",
      nullptr,  // not used since the robot is attached to the world
      Eigen::Vector3d(std::stod(argv[3]), std::stod(argv[4]), std::stod(argv[5])),  // xyz of the car's root link
      Eigen::Vector3d(0, 0, 0));       // rpy of the car's root link
  } else {
    weld_to_frame = allocate_shared<RigidBodyFrame>(
      aligned_allocator<RigidBodyFrame>(),
      "world",
      nullptr,
      Isometry3d::Identity());
  }

  auto r1 = make_shared<RigidBodySystem>();
  r1->addRobotFromFile(argv[1], DrakeJoint::QUATERNION);
  auto r2 = make_shared<RigidBodySystem>();
  r2->addRobotFromFile(argv[2], DrakeJoint::QUATERNION, weld_to_frame);

  // for debugging:
  r1->getRigidBodyTree()->drawKinematicTree("/tmp/r1.dot");
  r2->getRigidBodyTree()->drawKinematicTree("/tmp/r2.dot");
  // I ran this at the console to see the output:
  // dot -Tpng -O /tmp/r1.dot; dot -Tpng -O /tmp/r2.dot; open /tmp/r1.dot.png
  // /tmp/r2.dot.png

  try {
    valuecheck(r1->getNumStates(),r2->getNumStates());
  } catch(const std::exception& e) {
    std::cout << "ERROR: Number of states do not match!" << std::endl
              << "  - system 1: " << r1->getNumStates() << std::endl
              << "  - system 2: " << r2->getNumStates() << std::endl;
    return -1;
  }

  try {
    valuecheck(r1->getNumInputs(),r2->getNumInputs());
  } catch(const std::exception& e) {
    std::cout << "ERROR: Number of inputs do not match!" << std::endl
              << "  - system 1: " << r1->getNumInputs() << std::endl
              << "  - system 2: " << r2->getNumInputs() << std::endl;
    return -1;
  }

  try {
    valuecheck(r1->getNumOutputs(),r2->getNumOutputs());
  } catch(const std::exception& e) {
    std::cout << "ERROR: Number of outputs do not match!" << std::endl
              << "  - system 1: " << r1->getNumOutputs() << std::endl
              << "  - system 2: " << r2->getNumOutputs() << std::endl;
    return -1;
  }

  if (*r1->getRigidBodyTree().get() != *r2->getRigidBodyTree().get()) {
    std::cout << "ERROR: The two rigid body trees are numerically different!" << std::endl;
    return -1;
  } else {
    std::cout << "The two models passed the numerical comparison test." << std::endl;
  }

  for (int i = 0; i < 1000; i++) {
    std::cout << "i = " << i << std::endl;
    double t = 0.0;
    VectorXd x = getInitialState(*r1);
    VectorXd u = VectorXd::Random(r1->getNumInputs());

    auto xdot1 = r1->dynamics(t, x, u);
    auto xdot2 = r2->dynamics(t, x, u);
    try {
      valuecheckMatrix(xdot1, xdot2, 1e-8);
    } catch(const std::runtime_error& re) {
      std::cout << "Model mismatch!" << std::endl
                << "  - initial state:" << std::endl << x << std::endl
                << "  - inputs (joint torques?):" << std::endl << u << std::endl
                << "  - xdot1:" << std::endl << xdot1.transpose() << std::endl
                << "  - xdot2:" << std::endl << xdot2.transpose() << std::endl
                << "  - error message:" << std::endl << re.what() << std::endl;
      return -1;
    }
  }
}
<commit_msg>Tried to fix both vehicles 10m high in the air. Dynamics still do not match.<commit_after>
#include "drake/systems/plants/RigidBodySystem.h"
#include "drake/systems/plants/RigidBodyFrame.h"
#include "drake/util/testUtil.h"

using namespace std;
using namespace Eigen;
using namespace Drake;

int main(int argc, char* argv[]) {
  if (argc < 2) {
    std::cerr << "Usage: " << argv[0]
              << " [options] full_path_to_robot1 full_path_to_robot2 x y z\n"
              << " The x y z parameters are optional and specify the position"
              << " of the second robot in the world, which is useful for URDF"
              << " models)"
              << std::endl;
    return 1;
  }

  std::shared_ptr<RigidBodyFrame> weld_to_frame;

  if (argc > 3) {
    weld_to_frame = allocate_shared<RigidBodyFrame>(
      aligned_allocator<RigidBodyFrame>(),
      "world",
      nullptr,  // not used since the robot is attached to the world
      Eigen::Vector3d(std::stod(argv[3]), std::stod(argv[4]), std::stod(argv[5])),  // xyz of the car's root link
      Eigen::Vector3d(0, 0, 0));       // rpy of the car's root link
  } else {
    weld_to_frame = allocate_shared<RigidBodyFrame>(
      aligned_allocator<RigidBodyFrame>(),
      "world",
      nullptr,
      Isometry3d::Identity());
  }

  auto r1 = make_shared<RigidBodySystem>();
  r1->addRobotFromFile(argv[1], DrakeJoint::QUATERNION);
  auto r2 = make_shared<RigidBodySystem>();
  r2->addRobotFromFile(argv[2], DrakeJoint::QUATERNION, weld_to_frame);

  // for debugging:
  r1->getRigidBodyTree()->drawKinematicTree("/tmp/r1.dot");
  r2->getRigidBodyTree()->drawKinematicTree("/tmp/r2.dot");
  // I ran this at the console to see the output:
  // dot -Tpng -O /tmp/r1.dot; dot -Tpng -O /tmp/r2.dot; open /tmp/r1.dot.png
  // /tmp/r2.dot.png

  try {
    valuecheck(r1->getNumStates(),r2->getNumStates());
  } catch(const std::exception& e) {
    std::cout << "ERROR: Number of states do not match!" << std::endl
              << "  - system 1: " << r1->getNumStates() << std::endl
              << "  - system 2: " << r2->getNumStates() << std::endl;
    return -1;
  }

  try {
    valuecheck(r1->getNumInputs(),r2->getNumInputs());
  } catch(const std::exception& e) {
    std::cout << "ERROR: Number of inputs do not match!" << std::endl
              << "  - system 1: " << r1->getNumInputs() << std::endl
              << "  - system 2: " << r2->getNumInputs() << std::endl;
    return -1;
  }

  try {
    valuecheck(r1->getNumOutputs(),r2->getNumOutputs());
  } catch(const std::exception& e) {
    std::cout << "ERROR: Number of outputs do not match!" << std::endl
              << "  - system 1: " << r1->getNumOutputs() << std::endl
              << "  - system 2: " << r2->getNumOutputs() << std::endl;
    return -1;
  }

  if (*r1->getRigidBodyTree().get() != *r2->getRigidBodyTree().get()) {
    std::cout << "ERROR: The two rigid body trees are numerically different!" << std::endl;
    return -1;
  } else {
    std::cout << "The two models passed the numerical comparison test." << std::endl;
  }

  for (int i = 0; i < 1000; i++) {
    std::cout << "i = " << i << std::endl;
    double t = 0.0;
    VectorXd x = getInitialState(*r1);
    x[2] = 10.0; // fix vehicle 10m high in the air
    VectorXd u = VectorXd::Random(r1->getNumInputs());

    auto xdot1 = r1->dynamics(t, x, u);
    auto xdot2 = r2->dynamics(t, x, u);
    try {
      valuecheckMatrix(xdot1, xdot2, 1e-8);
    } catch(const std::runtime_error& re) {
      std::cout << "Model mismatch!" << std::endl
                << "  - initial state:" << std::endl << x << std::endl
                << "  - inputs (joint torques?):" << std::endl << u << std::endl
                << "  - xdot1:" << std::endl << xdot1.transpose() << std::endl
                << "  - xdot2:" << std::endl << xdot2.transpose() << std::endl
                << "  - error message:" << std::endl << re.what() << std::endl;
      return -1;
    }
  }
}
<|endoftext|>


<commit_before>// This file is part of the dune-gdt project:
//   https://github.com/dune-community/dune-gdt
// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved.
// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)
//      or  GPL-2.0+ (http://opensource.org/licenses/gpl-license)
//          with "runtime exception" (http://www.dune-project.org/license.html)
// Authors:
//   Felix Schindler (2019)

#define DUNE_XT_COMMON_TEST_MAIN_CATCH_EXCEPTIONS 1
#define DUNE_XT_COMMON_TEST_MAIN_ENABLE_TIMED_LOGGING 1
#define DUNE_XT_COMMON_TEST_MAIN_ENABLE_INFO_LOGGING 1
#define DUNE_XT_COMMON_TEST_MAIN_ENABLE_DEBUG_LOGGING 1

#include <dune/xt/common/test/main.hxx> // <- this one has to come first (includes the config.h)!

#include <dune/xt/grid/grids.hh>

#include <dune/gdt/test/instationary-eocstudies/hyperbolic-nonconforming.hh>

#include "base.hh"

using namespace Dune;
using namespace Dune::GDT;

using Burgers1dExplicitDgP3Test = BurgersExplicitTest<YASP_1D_EQUIDISTANT_OFFSET>;
TEST_F(Burgers1dExplicitDgP3Test, periodic_boundaries__numerical_engquist_osher_flux)
{
  this->visualization_steps_ = DXTC_TEST_CONFIG_GET("setup.visualization_steps", 0);
  this->num_refinements_ = 2;
  this->num_additional_refinements_for_reference_ = 3;
  this->space_type_ = "dg_p3";
  this->numerical_flux_type_ = "engquist_osher";
  /*const auto actual_results =*/this->run();
  //  const auto expected_results = DXTC_TEST_CONFIG_SUB("results");
  //  XT::Test::check_eoc_study_for_success(expected_results, actual_results);
}
<commit_msg>[test.burgers.dg_p3] reduce refinements to fix timeout<commit_after>// This file is part of the dune-gdt project:
//   https://github.com/dune-community/dune-gdt
// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved.
// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)
//      or  GPL-2.0+ (http://opensource.org/licenses/gpl-license)
//          with "runtime exception" (http://www.dune-project.org/license.html)
// Authors:
//   Felix Schindler (2019)

#define DUNE_XT_COMMON_TEST_MAIN_CATCH_EXCEPTIONS 1
#define DUNE_XT_COMMON_TEST_MAIN_ENABLE_TIMED_LOGGING 1
#define DUNE_XT_COMMON_TEST_MAIN_ENABLE_INFO_LOGGING 1
#define DUNE_XT_COMMON_TEST_MAIN_ENABLE_DEBUG_LOGGING 1

#include <dune/xt/common/test/main.hxx> // <- this one has to come first (includes the config.h)!

#include <dune/xt/grid/grids.hh>

#include <dune/gdt/test/instationary-eocstudies/hyperbolic-nonconforming.hh>

#include "base.hh"

using namespace Dune;
using namespace Dune::GDT;

using Burgers1dExplicitDgP3Test = BurgersExplicitTest<YASP_1D_EQUIDISTANT_OFFSET>;
TEST_F(Burgers1dExplicitDgP3Test, periodic_boundaries__numerical_engquist_osher_flux)
{
  this->visualization_steps_ = DXTC_TEST_CONFIG_GET("setup.visualization_steps", 0);
  this->num_refinements_ = 1;
  this->num_additional_refinements_for_reference_ = 1;
  this->space_type_ = "dg_p3";
  this->numerical_flux_type_ = "engquist_osher";
  /*const auto actual_results =*/this->run();
  //  const auto expected_results = DXTC_TEST_CONFIG_SUB("results");
  //  XT::Test::check_eoc_study_for_success(expected_results, actual_results);
}
<|endoftext|>


<commit_before>/*******************************************************************************
GPU OPTIMIZED MONTE CARLO (GOMC) 2.31
Copyright (C) 2018  GOMC Group
A copy of the GNU General Public License can be found in the COPYRIGHT.txt
along with this program, also can be found at <http://www.gnu.org/licenses/>.
********************************************************************************/
#include "MoveSettings.h" //header spec.
#include "BoxDimensions.h" //For axis sizes
#include "BoxDimensionsNonOrth.h"
#include "StaticVals.h" //For init info.

#include "NumLib.h" //For bounding functions.
#include "GeomLib.h"    //For M_PI

const double MoveSettings::TARGET_ACCEPT_FRACT = 0.50;
const double MoveSettings::TINY_AMOUNT = 0.0000001;

void MoveSettings::Init(StaticVals const& statV,
                        pdb_setup::Remarks const& remarks,
                        const uint tkind)
{

  totKind = tkind;
  perAdjust = statV.simEventFreq.perAdjust;
  for(uint b = 0; b < BOX_TOTAL; b++) {
    for(uint m = 0; m < mv::MOVE_KINDS_TOTAL; m++) {
      acceptPercent[b][m].resize(totKind, 0);
      scale[b][m].resize(totKind, 0);
      accepted[b][m].resize(totKind, 0);
      tries[b][m].resize(totKind, 0);
      tempAccepted[b][m].resize(totKind, 0);
      tempTries[b][m].resize(totKind, 0);
    }
  }

  for(uint b = 0; b < BOX_TOTAL; b++) {
    for(uint m = 0; m < mv::MOVE_KINDS_TOTAL; m++) {
      for(uint k = 0; k < totKind; k++){
        if(m == mv::DISPLACE) {
          if(remarks.restart && remarks.disp[b] > 0.0) {
            scale[b][m][k] = remarks.disp[b];
          } else {
            scale[b][m][k] = boxDimRef.axis.Min(b) / 4;
          }
        } else if (m == mv::ROTATE) {
          if(remarks.restart && remarks.rotate[b] > 0.0) {
            scale[b][m][k] = remarks.rotate[b];
          } else {
            scale[b][m][k] = M_PI_4;
          }
        }
#if ENSEMBLE == NPT || ENSEMBLE == GEMC
        else if (m == mv::VOL_TRANSFER) {
          if(remarks.restart && remarks.vol[b] > 0.0) {
            scale[b][m][k] = remarks.vol[b];
          } else {
            scale[b][m][k] = 500;
          }
        }
#endif
      }
    }
  }
}

//Process results of move we just did in terms of acceptance counters
void MoveSettings::Update(const uint move, const bool isAccepted,
                          const uint step, const uint box, const uint kind)
{
  tries[box][move][kind]++;
  tempTries[box][move][kind]++;
  if(isAccepted) {
    tempAccepted[box][move][kind]++;
    accepted[box][move][kind]++;
  }

  acceptPercent[box][move][kind] = (double)(accepted[box][move][kind]) /
                                  (double)(tries[box][move][kind]);

  //for any move that we dont care about kind of molecule, it should be included
  //in the if condition
  if (move == mv::INTRA_MEMC || move == mv::MULTIPARTICLE
  #if ENSEMBLE == GEMC || ENSEMBLE == GCMC
      || move == mv::MEMC
  #endif
  #if ENSEMBLE == NPT || ENSEMBLE == GEMC
      || move == mv::VOL_TRANSFER
  #endif
    ) {
    for (uint k = 1; k < totKind; k++) {
      tries[box][move][kind]++;
      tempTries[box][move][kind]++;
      if(isAccepted) {
        tempAccepted[box][move][kind]++;
        accepted[box][move][kind]++;
      }
      acceptPercent[box][move][kind] = (double)(accepted[box][move][kind]) /
                                      (double)(tries[box][move][kind]);
    }
  }
}

void MoveSettings::AdjustMoves(const uint step)
{
  //Check whether we need to adjust this move's scaling.
  if ((step + 1) % perAdjust == 0) {
    for(uint b = 0; b < BOX_TOTAL; b++) {
      for (uint m = 0; m < mv::MOVE_KINDS_TOTAL; ++m) {
        for(uint k = 0; k < totKind; k++) {
          Adjust(b, m, k);
        }
      }
    }
  }
}

//Adjust responsibly
void MoveSettings::Adjust(const uint box, const uint move, const uint kind)
{
  if(move == mv::DISPLACE) {
    if(tempTries[box][move][kind] > 0) {
      double currentAccept = (double)(tempAccepted[box][move][kind]) /
                           (double)(tempTries[box][move][kind]);
      double fractOfTargetAccept = currentAccept / TARGET_ACCEPT_FRACT;
      if (fractOfTargetAccept > 0.0) {
        scale[box][move][kind] *= fractOfTargetAccept;
      } else {
        scale[box][move][kind] *= 0.5;
      }
    }
    num::Bound<double>(scale[box][move][kind], 0.0000000001,
                       (boxDimRef.axis.Min(box) / 2) - TINY_AMOUNT);
  } else if(move == mv::ROTATE) {
    if(tempTries[box][move][kind] > 0) {
      double currentAccept = (double)(tempAccepted[box][move][kind]) /
                           (double)(tempTries[box][move][kind]);
      double fractOfTargetAccept = currentAccept / TARGET_ACCEPT_FRACT;
      if (fractOfTargetAccept > 0.0) {
        scale[box][move][kind] *= fractOfTargetAccept;
      } else {
        scale[box][move][kind] *= 0.5;
      }
    }
    num::Bound<double>(scale[box][move][kind], 0.000001, M_PI - TINY_AMOUNT);
  }
#if ENSEMBLE == NPT || ENSEMBLE == GEMC
  else if(move == mv::VOL_TRANSFER) {
    if(tempTries[box][move][kind] > 0) {
      double currentAccept = (double)(tempAccepted[box][move][kind]) /
                           (double)(tempTries[box][move][kind]);
      double fractOfTargetAccept = currentAccept / TARGET_ACCEPT_FRACT;
      if (fractOfTargetAccept > 0.0) {
        scale[box][move][kind] *= fractOfTargetAccept;
      } else {
        scale[box][move][kind] *= 0.5;
      }
    }
    //Warning: This will lead to have acceptance > %50
    double maxVolExchange = boxDimRef.volume[box] - boxDimRef.minVol[box];
    num::Bound<double>(scale[box][move][kind], 0.001,  maxVolExchange - 0.001);
  }
#endif
  tempAccepted[box][move][kind] = 0;
  tempTries[box][move][kind] = 0;
}

uint MoveSettings::GetAcceptTot(const uint box, const uint move) const
{
  uint sum= 0;
  for(uint k = 0; k < totKind; k++) {
    sum += accepted[box][move][k];
  }
  return sum;
}

double MoveSettings::GetScaleTot(const uint box, const uint move) const
{
  double sum = 0.0;
  for(uint k = 0; k < totKind; k++) {
    sum += scale[box][move][k];
  }
  return sum / (double)(totKind);
}

uint MoveSettings::GetTrialTot(const uint box, const uint move) const
{
  uint sum = 0.0;
  for(uint k = 0; k < totKind; k++) {
    sum += tries[box][move][k];
  }

  if(move == mv::INTRA_MEMC || move == mv::MULTIPARTICLE
  #if ENSEMBLE == GEMC || ENSEMBLE == GCMC
      || move == mv::MEMC
  #endif
  #if ENSEMBLE == NPT || ENSEMBLE == GEMC
      || move == mv::VOL_TRANSFER
  #endif
    ) {
    sum /= totKind;
  }

  return sum;
}
<commit_msg>Fix to console acceptance printing<commit_after>/*******************************************************************************
GPU OPTIMIZED MONTE CARLO (GOMC) 2.31
Copyright (C) 2018  GOMC Group
A copy of the GNU General Public License can be found in the COPYRIGHT.txt
along with this program, also can be found at <http://www.gnu.org/licenses/>.
********************************************************************************/
#include "MoveSettings.h" //header spec.
#include "BoxDimensions.h" //For axis sizes
#include "BoxDimensionsNonOrth.h"
#include "StaticVals.h" //For init info.

#include "NumLib.h" //For bounding functions.
#include "GeomLib.h"    //For M_PI

const double MoveSettings::TARGET_ACCEPT_FRACT = 0.50;
const double MoveSettings::TINY_AMOUNT = 0.0000001;

void MoveSettings::Init(StaticVals const& statV,
                        pdb_setup::Remarks const& remarks,
                        const uint tkind)
{

  totKind = tkind;
  perAdjust = statV.simEventFreq.perAdjust;
  for(uint b = 0; b < BOX_TOTAL; b++) {
    for(uint m = 0; m < mv::MOVE_KINDS_TOTAL; m++) {
      acceptPercent[b][m].resize(totKind, 0);
      scale[b][m].resize(totKind, 0);
      accepted[b][m].resize(totKind, 0);
      tries[b][m].resize(totKind, 0);
      tempAccepted[b][m].resize(totKind, 0);
      tempTries[b][m].resize(totKind, 0);
    }
  }

  for(uint b = 0; b < BOX_TOTAL; b++) {
    for(uint m = 0; m < mv::MOVE_KINDS_TOTAL; m++) {
      for(uint k = 0; k < totKind; k++){
        if(m == mv::DISPLACE) {
          if(remarks.restart && remarks.disp[b] > 0.0) {
            scale[b][m][k] = remarks.disp[b];
          } else {
            scale[b][m][k] = boxDimRef.axis.Min(b) / 4;
          }
        } else if (m == mv::ROTATE) {
          if(remarks.restart && remarks.rotate[b] > 0.0) {
            scale[b][m][k] = remarks.rotate[b];
          } else {
            scale[b][m][k] = M_PI_4;
          }
        }
#if ENSEMBLE == NPT || ENSEMBLE == GEMC
        else if (m == mv::VOL_TRANSFER) {
          if(remarks.restart && remarks.vol[b] > 0.0) {
            scale[b][m][k] = remarks.vol[b];
          } else {
            scale[b][m][k] = 500;
          }
        }
#endif
      }
    }
  }
}

//Process results of move we just did in terms of acceptance counters
void MoveSettings::Update(const uint move, const bool isAccepted,
                          const uint step, const uint box, const uint kind)
{
  tries[box][move][kind]++;
  tempTries[box][move][kind]++;
  if(isAccepted) {
    tempAccepted[box][move][kind]++;
    accepted[box][move][kind]++;
  }

  acceptPercent[box][move][kind] = (double)(accepted[box][move][kind]) /
                                  (double)(tries[box][move][kind]);

  //for any move that we dont care about kind of molecule, it should be included
  //in the if condition
  if (move == mv::INTRA_MEMC || move == mv::MULTIPARTICLE
  #if ENSEMBLE == GEMC || ENSEMBLE == GCMC
      || move == mv::MEMC
  #endif
  #if ENSEMBLE == NPT || ENSEMBLE == GEMC
      || move == mv::VOL_TRANSFER
  #endif
    ) {
    for (uint k = 1; k < totKind; k++) {
      tries[box][move][kind]++;
      tempTries[box][move][kind]++;
      if(isAccepted) {
        tempAccepted[box][move][kind]++;
        accepted[box][move][kind]++;
      }
      acceptPercent[box][move][kind] = (double)(accepted[box][move][kind]) /
                                      (double)(tries[box][move][kind]);
    }
  }
}

void MoveSettings::AdjustMoves(const uint step)
{
  //Check whether we need to adjust this move's scaling.
  if ((step + 1) % perAdjust == 0) {
    for(uint b = 0; b < BOX_TOTAL; b++) {
      for (uint m = 0; m < mv::MOVE_KINDS_TOTAL; ++m) {
        for(uint k = 0; k < totKind; k++) {
          Adjust(b, m, k);
        }
      }
    }
  }
}

//Adjust responsibly
void MoveSettings::Adjust(const uint box, const uint move, const uint kind)
{
  if(move == mv::DISPLACE) {
    if(tempTries[box][move][kind] > 0) {
      double currentAccept = (double)(tempAccepted[box][move][kind]) /
                           (double)(tempTries[box][move][kind]);
      double fractOfTargetAccept = currentAccept / TARGET_ACCEPT_FRACT;
      if (fractOfTargetAccept > 0.0) {
        scale[box][move][kind] *= fractOfTargetAccept;
      } else {
        scale[box][move][kind] *= 0.5;
      }
    }
    num::Bound<double>(scale[box][move][kind], 0.0000000001,
                       (boxDimRef.axis.Min(box) / 2) - TINY_AMOUNT);
  } else if(move == mv::ROTATE) {
    if(tempTries[box][move][kind] > 0) {
      double currentAccept = (double)(tempAccepted[box][move][kind]) /
                           (double)(tempTries[box][move][kind]);
      double fractOfTargetAccept = currentAccept / TARGET_ACCEPT_FRACT;
      if (fractOfTargetAccept > 0.0) {
        scale[box][move][kind] *= fractOfTargetAccept;
      } else {
        scale[box][move][kind] *= 0.5;
      }
    }
    num::Bound<double>(scale[box][move][kind], 0.000001, M_PI - TINY_AMOUNT);
  }
#if ENSEMBLE == NPT || ENSEMBLE == GEMC
  else if(move == mv::VOL_TRANSFER) {
    if(tempTries[box][move][kind] > 0) {
      double currentAccept = (double)(tempAccepted[box][move][kind]) /
                           (double)(tempTries[box][move][kind]);
      double fractOfTargetAccept = currentAccept / TARGET_ACCEPT_FRACT;
      if (fractOfTargetAccept > 0.0) {
        scale[box][move][kind] *= fractOfTargetAccept;
      } else {
        scale[box][move][kind] *= 0.5;
      }
    }
    //Warning: This will lead to have acceptance > %50
    double maxVolExchange = boxDimRef.volume[box] - boxDimRef.minVol[box];
    num::Bound<double>(scale[box][move][kind], 0.001,  maxVolExchange - 0.001);
  }
#endif
  tempAccepted[box][move][kind] = 0;
  tempTries[box][move][kind] = 0;
}

uint MoveSettings::GetAcceptTot(const uint box, const uint move) const
{
  uint sum= 0;
  for(uint k = 0; k < totKind; k++) {
    sum += accepted[box][move][k];
  }

  if(move == mv::INTRA_MEMC || move == mv::MULTIPARTICLE
  #if ENSEMBLE == GEMC || ENSEMBLE == GCMC
      || move == mv::MEMC
  #endif
  #if ENSEMBLE == NPT || ENSEMBLE == GEMC
      || move == mv::VOL_TRANSFER
  #endif
    ) {
    sum /= totKind;
  }
  return sum;
}

double MoveSettings::GetScaleTot(const uint box, const uint move) const
{
  double sum = 0.0;
  for(uint k = 0; k < totKind; k++) {
    sum += scale[box][move][k];
  }
  return sum / (double)(totKind);
}

uint MoveSettings::GetTrialTot(const uint box, const uint move) const
{
  uint sum = 0.0;
  for(uint k = 0; k < totKind; k++) {
    sum += tries[box][move][k];
  }

  if(move == mv::INTRA_MEMC || move == mv::MULTIPARTICLE
  #if ENSEMBLE == GEMC || ENSEMBLE == GCMC
      || move == mv::MEMC
  #endif
  #if ENSEMBLE == NPT || ENSEMBLE == GEMC
      || move == mv::VOL_TRANSFER
  #endif
    ) {
    sum /= totKind;
  }

  return sum;
}
<|endoftext|>


<commit_before>/***********************************
   Copyright 2017 Ravishankar Mathur

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
***********************************/

#include <OpenFrames/QWidgetPanel.hpp>
#include <OpenFrames/QtOSGAdapters.hpp>

#include <osg/Vec3d>
#include <osg/Quat>
#include <osg/Geode>
#include <osg/PolygonOffset>
#include <osg/Shape>
#include <osg/Texture2D>
#include <osgDB/ReadFile>
#include <osgUtil/CullVisitor>

#include <iostream>
#include <algorithm>
#include <cmath>

namespace OpenFrames
{

  /// Default half length for the hyperrectangle
  const double QWidgetPanel::DEFAULT_LENGTH = 1.0;
  /// Only used when the QWidget has an invalid preferred size
  const double QWidgetPanel::DEFAULT_PIXELS_PER_UNIT = 100.0;

  QWidgetPanel::QWidgetPanel(const std::string &name)
    : ReferenceFrame(name)
  {
    _init();
  }

  QWidgetPanel::QWidgetPanel(const std::string &name, const osg::Vec3 &color)
    : ReferenceFrame(name, color)
  {
    _init();
  }

  QWidgetPanel::QWidgetPanel(const std::string &name, const osg::Vec4 &color)
    : ReferenceFrame(name, color)
  {
    _init();
  }

  QWidgetPanel::QWidgetPanel(const std::string &name, float r, float g, float b, float a)
    : ReferenceFrame(name, r, g, b, a)
  {
    _init();
  }

  QWidgetPanel::~QWidgetPanel() { }

  /** Create the panel */
  void QWidgetPanel::_init()
  {
    // Create the panel as a textured quad
    _panel = osg::createTexturedQuadGeometry(
      osg::Vec3(0.0, 0.0, 0.001), // Bottom-left corner (panel origin)
      osg::Vec3(DEFAULT_LENGTH, 0, 0), // Width vector
      osg::Vec3(0, DEFAULT_LENGTH, 0)); // Height vector
    _panel->setName("QWidgetPanel Front");
    _panel->setUseDisplayList(false);
    _panel->setUseVertexBufferObjects(true);

    // Create the back panel as a textured quad
    _panelBack = osg::createTexturedQuadGeometry(
      osg::Vec3(DEFAULT_LENGTH, 0, -0.001),  // Origin of reversed panel
      osg::Vec3(-DEFAULT_LENGTH, 0, 0), // Width of reversed panel
      osg::Vec3(0, DEFAULT_LENGTH, 0)); // Height same as front panel
    _panelBack->setName("QWidgetPanel Back");
    _panelBack->setUseDisplayList(false);
    _panelBack->setUseVertexBufferObjects(true);
    _panelBack->setColorArray(_panel->getColorArray(), osg::Array::BIND_OVERALL); // Use color from front panel

    // Set rendering properties
    osg::StateSet* stateset = _panel->getOrCreateStateSet();
    _panelBack->setStateSet(stateset); // Share stateset between front & back panels
    stateset->setMode(GL_CULL_FACE, osg::StateAttribute::ON); // Don't draw panel backfaces
    stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF); // Panel not altered by lighting
    stateset->setMode(GL_BLEND, osg::StateAttribute::ON); // Enable transparency
    stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);

    // Create the node that contains the QWidgetPanel
    _geode = new osg::Geode;
    _geode->setName(_name);
    _geode->addDrawable(_panel);
    _geode->addDrawable(_panelBack);

    // Add the box to the ReferenceFrame
    _xform->addChild(_geode.get());
  }

  void QWidgetPanel::showContents(bool showContents)
  {
    if (showContents) _geode->setNodeMask(0xffffffff);
    else _geode->setNodeMask(0x0);
  }

  bool QWidgetPanel::getContentsShown() const
  {
    return (_geode->getNodeMask() != 0x0);
  }

  void QWidgetPanel::setSize(const double &width, const double &height)
  {
    // Resize front panel (its normals and colors don't change)
    // Quad vertices are defined as CCW starting from top-left, with origin at bottom-left corner
    // See osg::createTexturedQuadGeometry() for details
    osg::Vec3Array* coords = dynamic_cast<osg::Vec3Array*>(_panel->getVertexArray());
    osg::Vec3 corner = (*coords)[1];
    osg::Vec3 widthVec(width, 0, 0);
    osg::Vec3 heightVec(0, height, 0);
    (*coords)[0] = corner + heightVec; // Top-left vertex
    (*coords)[2] = corner + widthVec; // Bottom-right vertex
    (*coords)[3] = corner + widthVec + heightVec; // Top-right vertex

    // Resize back panel
    osg::Vec3Array* coordsBack = dynamic_cast<osg::Vec3Array*>(_panelBack->getVertexArray());
    (*coordsBack)[0] = (*coords)[3]; // Back top-left = Front top-right
    (*coordsBack)[1] = (*coords)[2]; // Back bottom-left = Front bottom-right
    (*coordsBack)[2] = (*coords)[1]; // Back bottom-right = Front bottom-left
    (*coordsBack)[3] = (*coords)[0]; // Back top-right = Front top-left

    // Indicate that panel data has changed
    coords->dirty();
    coordsBack->dirty();
    _panel->dirtyBound();
    _panelBack->dirtyBound();

    // Move axes to compensate for size change
    double averageSize = (width + height) / 2.0;
    moveXAxis(osg::Vec3(width, 0, 0), 0.5*averageSize);
    moveYAxis(osg::Vec3(0, height, 0), 0.5*averageSize);
    moveZAxis(osg::Vec3(0, 0, 0.5*averageSize), 0.5*averageSize);

    // Resize the underlying QWidget
    _rescaleWidget();
  }

  void QWidgetPanel::getSize(double &width, double &height)
  {
    // Quad vertices are defined as CCW starting from top-left, with origin at bottom-left
    // See osg::createTexturedQuadGeometry() for details
    osg::Vec3Array* coords = dynamic_cast<osg::Vec3Array*>(_panel->getVertexArray());
    width = (*coords)[2].x(); // Bottom-right vertex
    height = (*coords)[0].y(); // Top-left vertex
  }

  bool QWidgetPanel::setWidget(QWidget *widget)
  {
    osg::StateSet* stateset = _panel->getStateSet();
    if (stateset == nullptr) return false;

    if(widget == nullptr) // Remove existing texture
    {
      _image.release(); // Release the old controls

      stateset->removeTextureAttribute(0, osg::StateAttribute::TEXTURE);
      stateset->removeTextureAttribute(0, osg::StateAttribute::TEXENV);

      // Revert color from white to reference frame color
      osg::Vec4Array* colors = dynamic_cast<osg::Vec4Array*>(_panel->getColorArray());
      (*colors)[0] = getColor();
      colors->dirty();

      return false;
    }
    else
    {
      // Check if there is already a texture being used.
      osg::Texture2D* texture = dynamic_cast<osg::Texture2D*>(stateset->getTextureAttribute(0, osg::StateAttribute::TEXTURE));

      // Disable context menus when embedding. They can popup outside the scene graph.
      if (widget->contextMenuPolicy() == Qt::DefaultContextMenu)
        widget->setContextMenuPolicy(Qt::NoContextMenu);
      QList<QWidget*> children = widget->findChildren<QWidget*>();
      for(QList<QWidget*>::iterator child = children.begin(); child < children.end(); child++)
      {
        if ((*child)->contextMenuPolicy() == Qt::DefaultContextMenu)
        (*child)->setContextMenuPolicy(Qt::NoContextMenu);
      }

      // Wrap the QWidget into an osg::Image
      _image = new QWidgetImage(widget);
#if (QT_VERSION >= QT_VERSION_CHECK(4, 5, 0))
      _image->getQWidget()->setAttribute(Qt::WA_TranslucentBackground);
#endif
      const osg::Vec4 &color = getColor();
      _image->getQGraphicsViewAdapter()->setBackgroundColor(QColor(255.0f*color[0], 255.0f*color[1], 255.0f*color[2], 255.0f*color[3]));
      _rescaleWidget();
      _image->getQGraphicsViewAdapter()->setIgnoredWidgets(_ignoredWidgets);

      // Create texture using image, and make sure it wraps around the
      // box without a seam at the edges.
      texture = new osg::Texture2D;
      texture->setResizeNonPowerOfTwoHint(false);
      texture->setImage(_image);
      texture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
      texture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
      texture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE);

      // Set the texture to the box
      stateset->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON);

      // Don't use the box's color when mapping the texture.
      osg::TexEnv* texenv = new osg::TexEnv;
      texenv->setMode(osg::TexEnv::MODULATE);
      stateset->setTextureAttribute(0, texenv);

      // Set default image handler to convert user events to Qt widget selections
      if (getImageHandler() == NULL) setImageHandler(new osgViewer::InteractiveImageHandler(_image.get()));

      // Set color to white for modulation of texture
      osg::Vec4Array* colors = dynamic_cast<osg::Vec4Array*>(_panel->getColorArray());
      (*colors)[0] = { 1.0, 1.0, 1.0, 1.0 };
      colors->dirty();

      return true;
    }
  }

  void QWidgetPanel::setIgnoreWidget( QWidget *widget, bool ignore )
  {
    auto widgetIteratorInList = std::find(_ignoredWidgets.begin(), _ignoredWidgets.end(), widget);
    bool notInList = ( widgetIteratorInList ==  _ignoredWidgets.end() );
    if (ignore)
    {
      if (notInList)
      {
        _ignoredWidgets.push_back(widget);
        if (_image.valid())
          _image->getQGraphicsViewAdapter()->setIgnoredWidgets(_ignoredWidgets);
      }
    }
    else
    {
      if (!notInList)
      {
        _ignoredWidgets.erase(widgetIteratorInList);
        if (_image.valid())
          _image->getQGraphicsViewAdapter()->setIgnoredWidgets(_ignoredWidgets);
      }
    }
  }

  void QWidgetPanel::setImageHandler(osgViewer::InteractiveImageHandler *handler)
  {
    _panel->setEventCallback(handler);
    _panel->setCullCallback(handler);
  }

  osgViewer::InteractiveImageHandler* QWidgetPanel::getImageHandler() const
  {
    return dynamic_cast<osgViewer::InteractiveImageHandler*>(_panel->getEventCallback());
  }

  void QWidgetPanel::setColor( const osg::Vec4 &color )
  {
    ReferenceFrame::setColor(color);
    if (_image.valid())
    {
      // Set the QWidget background color, keep geometry white
      _image->getQGraphicsViewAdapter()->setBackgroundColor(QColor(255.0f*color[0], 255.0f*color[1], 255.0f*color[2], 255.0f*color[3]));
    }
    else
    {
      // Set the geometry color
      osg::Vec4Array* colors = dynamic_cast<osg::Vec4Array*>(_panel->getColorArray());
      (*colors)[0] = color;
      colors->dirty();
    }
  }

  const osg::BoundingSphere& QWidgetPanel::getBound() const
  {
    osg::BoundingSphere bs = _geode->getBound();

    // Keep bound center but expand to include axes/labels
    ReferenceFrame::getBound();
    bs.expandRadiusBy(_bound);
    _bound = bs;

    return _bound;
  }

  void QWidgetPanel::_rescaleWidget()
  {
    if (_image.valid())
    {
      // Scale the QWidget to the X-Y plane size
      double panelWidth, panelHeight;
      double imageWidth, imageHeight;

      getSize(panelWidth, panelHeight); // Use x,y as current panel width,height

      QSize preferredSize = _image->getQGraphicsViewAdapter()->getQGraphicsView()->sizeHint();
      if (preferredSize.isValid())
      {
        double preferredWidth = static_cast<double>(preferredSize.width());
        double preferredHeight = static_cast<double>(preferredSize.height());
        if ((panelWidth / panelHeight) > (preferredWidth / preferredHeight))
        {
          // Panel is taller than the preferred size
          imageHeight = preferredHeight;
          // Qt may get upset if we accidently round down below the minimum size
          imageWidth = ceil(panelWidth * preferredHeight / panelHeight);
          std::cout << " y = " << imageHeight << " x = " << imageWidth << std::endl;
        }
        else
        {
          // Panel is wider than the preferred size
          imageWidth = preferredWidth;
          // Qt may get upset if we accidently round down below the minimum size
          imageHeight = ceil(panelHeight * preferredWidth / panelWidth);
          std::cout << "x = " << imageWidth << " y = " << imageHeight << std::endl;
        }
      }
      else
      {
        imageWidth = DEFAULT_PIXELS_PER_UNIT * panelWidth;
        imageHeight = DEFAULT_PIXELS_PER_UNIT * panelHeight;
      }

      _image->scaleImage(imageWidth, imageHeight, 0, 0U);
    }
  }

} // !namespace OpenFrames

<commit_msg>Fix interaction bug in QWidgetPanel's back-facing panel<commit_after>/***********************************
   Copyright 2017 Ravishankar Mathur

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
***********************************/

#include <OpenFrames/QWidgetPanel.hpp>
#include <OpenFrames/QtOSGAdapters.hpp>

#include <osg/Vec3d>
#include <osg/Quat>
#include <osg/Geode>
#include <osg/PolygonOffset>
#include <osg/Shape>
#include <osg/Texture2D>
#include <osgDB/ReadFile>
#include <osgUtil/CullVisitor>

#include <iostream>
#include <algorithm>
#include <cmath>

namespace OpenFrames
{

  /// Default half length for the hyperrectangle
  const double QWidgetPanel::DEFAULT_LENGTH = 1.0;
  /// Only used when the QWidget has an invalid preferred size
  const double QWidgetPanel::DEFAULT_PIXELS_PER_UNIT = 100.0;

  QWidgetPanel::QWidgetPanel(const std::string &name)
    : ReferenceFrame(name)
  {
    _init();
  }

  QWidgetPanel::QWidgetPanel(const std::string &name, const osg::Vec3 &color)
    : ReferenceFrame(name, color)
  {
    _init();
  }

  QWidgetPanel::QWidgetPanel(const std::string &name, const osg::Vec4 &color)
    : ReferenceFrame(name, color)
  {
    _init();
  }

  QWidgetPanel::QWidgetPanel(const std::string &name, float r, float g, float b, float a)
    : ReferenceFrame(name, r, g, b, a)
  {
    _init();
  }

  QWidgetPanel::~QWidgetPanel() { }

  /** Create the panel */
  void QWidgetPanel::_init()
  {
    // Create the panel as a textured quad
    _panel = osg::createTexturedQuadGeometry(
      osg::Vec3(), // Bottom-left corner (panel origin)
      osg::Vec3(DEFAULT_LENGTH, 0, 0), // Width vector
      osg::Vec3(0, DEFAULT_LENGTH, 0)); // Height vector
    _panel->setName("QWidgetPanel Front");
    _panel->setUseDisplayList(false);
    _panel->setUseVertexBufferObjects(true);

    // Create the back panel as a textured quad
    // Note that we slightly offset the back panel Z coordinate so that it is not
    // coplanar with the front panel (causes picking issues)
    _panelBack = osg::createTexturedQuadGeometry(
      osg::Vec3(DEFAULT_LENGTH, 0, -0.001),  // Origin of reversed panel
      osg::Vec3(-DEFAULT_LENGTH, 0, 0), // Width of reversed panel
      osg::Vec3(0, DEFAULT_LENGTH, 0)); // Height same as front panel
    _panelBack->setName("QWidgetPanel Back");
    _panelBack->setUseDisplayList(false);
    _panelBack->setUseVertexBufferObjects(true);
    _panelBack->setColorArray(_panel->getColorArray(), osg::Array::BIND_OVERALL); // Use color from front panel

    // Set rendering properties
    osg::StateSet* stateset = _panel->getOrCreateStateSet();
    _panelBack->setStateSet(stateset); // Share stateset between front & back panels
    stateset->setMode(GL_CULL_FACE, osg::StateAttribute::ON); // Don't draw panel backfaces
    stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF); // Panel not altered by lighting
    stateset->setMode(GL_BLEND, osg::StateAttribute::ON); // Enable transparency
    stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);

    // Create the node that contains the QWidgetPanel
    _geode = new osg::Geode;
    _geode->setName(_name);
    _geode->addDrawable(_panel);
    _geode->addDrawable(_panelBack);

    // Add the box to the ReferenceFrame
    _xform->addChild(_geode.get());
  }

  void QWidgetPanel::showContents(bool showContents)
  {
    if (showContents) _geode->setNodeMask(0xffffffff);
    else _geode->setNodeMask(0x0);
  }

  bool QWidgetPanel::getContentsShown() const
  {
    return (_geode->getNodeMask() != 0x0);
  }

  void QWidgetPanel::setSize(const double &width, const double &height)
  {
    // Resize front panel (its normals and colors don't change)
    // Quad vertices are defined as CCW starting from top-left, with origin at bottom-left corner
    // See osg::createTexturedQuadGeometry() for details
    osg::Vec3Array* coords = dynamic_cast<osg::Vec3Array*>(_panel->getVertexArray());
    osg::Vec3 corner = (*coords)[1];
    osg::Vec3 widthVec(width, 0, 0);
    osg::Vec3 heightVec(0, height, 0);
    (*coords)[0] = corner + heightVec; // Top-left vertex
    (*coords)[2] = corner + widthVec; // Bottom-right vertex
    (*coords)[3] = corner + widthVec + heightVec; // Top-right vertex

    // Resize back panel
    osg::Vec3Array* coordsBack = dynamic_cast<osg::Vec3Array*>(_panelBack->getVertexArray());
    float backZ = (*coordsBack)[0].z(); // Save Z-offset for back panel
    (*coordsBack)[0] = (*coords)[3]; // Back top-left = Front top-right
    (*coordsBack)[1] = (*coords)[2]; // Back bottom-left = Front bottom-right
    (*coordsBack)[2] = (*coords)[1]; // Back bottom-right = Front bottom-left
    (*coordsBack)[3] = (*coords)[0]; // Back top-right = Front top-left
    (*coordsBack)[0].z() = backZ; // Restore Z-offset for back panel
    (*coordsBack)[1].z() = backZ; // Restore Z-offset for back panel
    (*coordsBack)[2].z() = backZ; // Restore Z-offset for back panel
    (*coordsBack)[3].z() = backZ; // Restore Z-offset for back panel

    // Indicate that panel data has changed
    coords->dirty();
    coordsBack->dirty();
    _panel->dirtyBound();
    _panelBack->dirtyBound();

    // Move axes to compensate for size change
    double averageSize = (width + height) / 2.0;
    moveXAxis(osg::Vec3(width, 0, 0), 0.5*averageSize);
    moveYAxis(osg::Vec3(0, height, 0), 0.5*averageSize);
    moveZAxis(osg::Vec3(0, 0, 0.5*averageSize), 0.5*averageSize);

    // Resize the underlying QWidget
    _rescaleWidget();
  }

  void QWidgetPanel::getSize(double &width, double &height)
  {
    // Quad vertices are defined as CCW starting from top-left, with origin at bottom-left
    // See osg::createTexturedQuadGeometry() for details
    osg::Vec3Array* coords = dynamic_cast<osg::Vec3Array*>(_panel->getVertexArray());
    width = (*coords)[2].x(); // Bottom-right vertex
    height = (*coords)[0].y(); // Top-left vertex
  }

  bool QWidgetPanel::setWidget(QWidget *widget)
  {
    osg::StateSet* stateset = _panel->getStateSet();
    if (stateset == nullptr) return false;

    if(widget == nullptr) // Remove existing texture
    {
      _image.release(); // Release the old controls

      stateset->removeTextureAttribute(0, osg::StateAttribute::TEXTURE);
      stateset->removeTextureAttribute(0, osg::StateAttribute::TEXENV);

      // Revert color from white to reference frame color
      osg::Vec4Array* colors = dynamic_cast<osg::Vec4Array*>(_panel->getColorArray());
      (*colors)[0] = getColor();
      colors->dirty();

      return false;
    }
    else
    {
      // Check if there is already a texture being used.
      osg::Texture2D* texture = dynamic_cast<osg::Texture2D*>(stateset->getTextureAttribute(0, osg::StateAttribute::TEXTURE));

      // Disable context menus when embedding. They can popup outside the scene graph.
      if (widget->contextMenuPolicy() == Qt::DefaultContextMenu)
        widget->setContextMenuPolicy(Qt::NoContextMenu);
      QList<QWidget*> children = widget->findChildren<QWidget*>();
      for(QList<QWidget*>::iterator child = children.begin(); child < children.end(); child++)
      {
        if ((*child)->contextMenuPolicy() == Qt::DefaultContextMenu)
        (*child)->setContextMenuPolicy(Qt::NoContextMenu);
      }

      // Wrap the QWidget into an osg::Image
      _image = new QWidgetImage(widget);
#if (QT_VERSION >= QT_VERSION_CHECK(4, 5, 0))
      _image->getQWidget()->setAttribute(Qt::WA_TranslucentBackground);
#endif
      const osg::Vec4 &color = getColor();
      _image->getQGraphicsViewAdapter()->setBackgroundColor(QColor(255.0f*color[0], 255.0f*color[1], 255.0f*color[2], 255.0f*color[3]));
      _rescaleWidget();
      _image->getQGraphicsViewAdapter()->setIgnoredWidgets(_ignoredWidgets);

      // Create texture using image, and make sure it wraps around the
      // box without a seam at the edges.
      texture = new osg::Texture2D;
      texture->setResizeNonPowerOfTwoHint(false);
      texture->setImage(_image);
      texture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
      texture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
      texture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE);

      // Set the texture to the box
      stateset->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON);

      // Don't use the box's color when mapping the texture.
      osg::TexEnv* texenv = new osg::TexEnv;
      texenv->setMode(osg::TexEnv::MODULATE);
      stateset->setTextureAttribute(0, texenv);

      // Set default image handler to convert user events to Qt widget selections
      if (getImageHandler() == NULL) setImageHandler(new osgViewer::InteractiveImageHandler(_image.get()));

      // Set color to white for modulation of texture
      osg::Vec4Array* colors = dynamic_cast<osg::Vec4Array*>(_panel->getColorArray());
      (*colors)[0] = { 1.0, 1.0, 1.0, 1.0 };
      colors->dirty();

      return true;
    }
  }

  void QWidgetPanel::setIgnoreWidget( QWidget *widget, bool ignore )
  {
    auto widgetIteratorInList = std::find(_ignoredWidgets.begin(), _ignoredWidgets.end(), widget);
    bool notInList = ( widgetIteratorInList ==  _ignoredWidgets.end() );
    if (ignore)
    {
      if (notInList)
      {
        _ignoredWidgets.push_back(widget);
        if (_image.valid())
          _image->getQGraphicsViewAdapter()->setIgnoredWidgets(_ignoredWidgets);
      }
    }
    else
    {
      if (!notInList)
      {
        _ignoredWidgets.erase(widgetIteratorInList);
        if (_image.valid())
          _image->getQGraphicsViewAdapter()->setIgnoredWidgets(_ignoredWidgets);
      }
    }
  }

  void QWidgetPanel::setImageHandler(osgViewer::InteractiveImageHandler *handler)
  {
    // Add event handler to geode so that it can handle front and back panel events
    _geode->setEventCallback(handler);

    // NOTE: If the cull handler is added to the geode, then no images are rendered
    // at all for Qt widgets. This may be because the osg/Qt adapter thinks it has
    // already rendered the image. This may require future investigation. For now,
    // we only add the cull handler to the front panel which solves the problem.
    _panel->setCullCallback(handler);
  }

  osgViewer::InteractiveImageHandler* QWidgetPanel::getImageHandler() const
  {
    return dynamic_cast<osgViewer::InteractiveImageHandler*>(_panel->getCullCallback());
  }

  void QWidgetPanel::setColor( const osg::Vec4 &color )
  {
    ReferenceFrame::setColor(color);
    if (_image.valid())
    {
      // Set the QWidget background color, keep geometry white
      _image->getQGraphicsViewAdapter()->setBackgroundColor(QColor(255.0f*color[0], 255.0f*color[1], 255.0f*color[2], 255.0f*color[3]));
    }
    else
    {
      // Set the geometry color
      osg::Vec4Array* colors = dynamic_cast<osg::Vec4Array*>(_panel->getColorArray());
      (*colors)[0] = color;
      colors->dirty();
    }
  }

  const osg::BoundingSphere& QWidgetPanel::getBound() const
  {
    osg::BoundingSphere bs = _geode->getBound();

    // Keep bound center but expand to include axes/labels
    ReferenceFrame::getBound();
    bs.expandRadiusBy(_bound);
    _bound = bs;

    return _bound;
  }

  void QWidgetPanel::_rescaleWidget()
  {
    if (_image.valid())
    {
      // Scale the QWidget to the X-Y plane size
      double panelWidth, panelHeight;
      double imageWidth, imageHeight;

      getSize(panelWidth, panelHeight); // Use x,y as current panel width,height

      QSize preferredSize = _image->getQGraphicsViewAdapter()->getQGraphicsView()->sizeHint();
      if (preferredSize.isValid())
      {
        double preferredWidth = static_cast<double>(preferredSize.width());
        double preferredHeight = static_cast<double>(preferredSize.height());
        if ((panelWidth / panelHeight) > (preferredWidth / preferredHeight))
        {
          // Panel is taller than the preferred size
          imageHeight = preferredHeight;
          // Qt may get upset if we accidently round down below the minimum size
          imageWidth = ceil(panelWidth * preferredHeight / panelHeight);
          std::cout << " y = " << imageHeight << " x = " << imageWidth << std::endl;
        }
        else
        {
          // Panel is wider than the preferred size
          imageWidth = preferredWidth;
          // Qt may get upset if we accidently round down below the minimum size
          imageHeight = ceil(panelHeight * preferredWidth / panelWidth);
          std::cout << "x = " << imageWidth << " y = " << imageHeight << std::endl;
        }
      }
      else
      {
        imageWidth = DEFAULT_PIXELS_PER_UNIT * panelWidth;
        imageHeight = DEFAULT_PIXELS_PER_UNIT * panelHeight;
      }

      _image->scaleImage(imageWidth, imageHeight, 0, 0U);
    }
  }

} // !namespace OpenFrames

<|endoftext|>


<commit_before>/*
  Asynchronous WebServer library for Espressif MCUs

  Copyright (c) 2016 Hristo Gochkov. All rights reserved.
  This file is part of the esp8266 core for Arduino environment.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/
#include "ESPAsyncWebServer.h"
#include "WebResponseImpl.h"
#include "cbuf.h"

/*
 * Abstract Response
 * */
const char* AsyncWebServerResponse::_responseCodeToString(int code) {
  switch (code) {
    case 100: return "Continue";
    case 101: return "Switching Protocols";
    case 200: return "OK";
    case 201: return "Created";
    case 202: return "Accepted";
    case 203: return "Non-Authoritative Information";
    case 204: return "No Content";
    case 205: return "Reset Content";
    case 206: return "Partial Content";
    case 300: return "Multiple Choices";
    case 301: return "Moved Permanently";
    case 302: return "Found";
    case 303: return "See Other";
    case 304: return "Not Modified";
    case 305: return "Use Proxy";
    case 307: return "Temporary Redirect";
    case 400: return "Bad Request";
    case 401: return "Unauthorized";
    case 402: return "Payment Required";
    case 403: return "Forbidden";
    case 404: return "Not Found";
    case 405: return "Method Not Allowed";
    case 406: return "Not Acceptable";
    case 407: return "Proxy Authentication Required";
    case 408: return "Request Time-out";
    case 409: return "Conflict";
    case 410: return "Gone";
    case 411: return "Length Required";
    case 412: return "Precondition Failed";
    case 413: return "Request Entity Too Large";
    case 414: return "Request-URI Too Large";
    case 415: return "Unsupported Media Type";
    case 416: return "Requested range not satisfiable";
    case 417: return "Expectation Failed";
    case 500: return "Internal Server Error";
    case 501: return "Not Implemented";
    case 502: return "Bad Gateway";
    case 503: return "Service Unavailable";
    case 504: return "Gateway Time-out";
    case 505: return "HTTP Version not supported";
    default:  return "";
  }
}

AsyncWebServerResponse::AsyncWebServerResponse()
  : _code(0)
  , _headers(NULL)
  , _contentType()
  , _contentLength(0)
  , _sendContentLength(true)
  , _chunked(false)
  , _headLength(0)
  , _sentLength(0)
  , _ackedLength(0)
  , _state(RESPONSE_SETUP)
{
  addHeader("Connection","close");
  addHeader("Access-Control-Allow-Origin","*");
}

AsyncWebServerResponse::~AsyncWebServerResponse(){
  while(_headers != NULL){
    AsyncWebHeader *h = _headers;
    _headers = h->next;
    delete h;
  }
}

void AsyncWebServerResponse::setContentLength(size_t len){
  if(_state == RESPONSE_SETUP)
    _contentLength = len;
}

void AsyncWebServerResponse::setContentType(String type){
  if(_state == RESPONSE_SETUP)
    _contentType = type;
}

void AsyncWebServerResponse::addHeader(String name, String value){
  AsyncWebHeader *header = new AsyncWebHeader(name, value);
  if(_headers == NULL){
    _headers = header;
  } else {
    AsyncWebHeader *h = _headers;
    while(h->next != NULL) h = h->next;
    h->next = header;
  }
}

String AsyncWebServerResponse::_assembleHead(uint8_t version){
  if(version){
    addHeader("Accept-Ranges","none");
    if(_chunked)
      addHeader("Transfer-Encoding","chunked");
  }
  String out = "HTTP/1." + String(version) + " " + String(_code) + " " + _responseCodeToString(_code) + "\r\n";
  if(_sendContentLength)
    out += "Content-Length: " + String(_contentLength) + "\r\n";

  if(_contentType.length())
    out += "Content-Type: " + _contentType + "\r\n";

  AsyncWebHeader *h;
  while(_headers != NULL){
    h = _headers;
    _headers = _headers->next;
    out += h->toString();
    delete h;
  }
  out += "\r\n";
  _headLength = out.length();
  return out;
}

bool AsyncWebServerResponse::_started(){ return _state > RESPONSE_SETUP; }
bool AsyncWebServerResponse::_finished(){ return _state > RESPONSE_WAIT_ACK; }
bool AsyncWebServerResponse::_failed(){ return _state == RESPONSE_FAILED; }
void AsyncWebServerResponse::_respond(AsyncWebServerRequest *request){ _state = RESPONSE_END; request->client()->close(); }
size_t AsyncWebServerResponse::_ack(AsyncWebServerRequest *request, size_t len, uint32_t time){ return 0; }

/*
 * String/Code Response
 * */
AsyncBasicResponse::AsyncBasicResponse(int code, String contentType, String content){
  _code = code;
  _content = content;
  _contentType = contentType;
  if(_content.length()){
    _contentLength = _content.length();
    if(!_contentType.length())
      _contentType = "text/plain";
  }
}

void AsyncBasicResponse::_respond(AsyncWebServerRequest *request){
  _state = RESPONSE_HEADERS;
  String out = _assembleHead(request->version());
  size_t outLen = out.length();
  size_t space = request->client()->space();
  if(!_contentLength && space >= outLen){
    request->client()->write(out.c_str(), outLen);
    _state = RESPONSE_WAIT_ACK;
  } else if(_contentLength && space >= outLen + _contentLength){
    out += _content;
    outLen += _contentLength;
    request->client()->write(out.c_str(), outLen);
    _state = RESPONSE_WAIT_ACK;
  } else if(space && space < out.length()){
    String partial = out.substring(0, space);
    _content = out.substring(space) + _content;
    _contentLength += outLen - space;
    request->client()->write(partial.c_str(), partial.length());
    _state = RESPONSE_CONTENT;
  } else if(space > outLen && space < (outLen + _contentLength)){
    size_t shift = space - outLen;
    outLen += shift;
    _sentLength += shift;
    out += _content.substring(0, shift);
    _content = _content.substring(shift);
    request->client()->write(out.c_str(), outLen);
    _state = RESPONSE_CONTENT;
  } else {
    _content = out + _content;
    _contentLength += outLen;
    _state = RESPONSE_CONTENT;
  }
}

size_t AsyncBasicResponse::_ack(AsyncWebServerRequest *request, size_t len, uint32_t time){
  _ackedLength += len;
  if(_state == RESPONSE_CONTENT){
    size_t available = _contentLength - _sentLength;
    size_t space = request->client()->space();
    //we can fit in this packet
    if(space > available){
      request->client()->write(_content.c_str(), available);
      _content = String();
      _state = RESPONSE_WAIT_ACK;
      return available;
    }
    //send some data, the rest on ack
    String out = _content.substring(0, space);
    _content = _content.substring(space);
    _sentLength += space;
    request->client()->write(out.c_str(), space);
    return space;
  } else if(_state == RESPONSE_WAIT_ACK){
    if(_ackedLength >= (_headLength+_contentLength)){
      _state = RESPONSE_END;
    }
  }
  return 0;
}

/*
 * Abstract Response
 * */

void AsyncAbstractResponse::_respond(AsyncWebServerRequest *request){
  if(!_sourceValid()){
    _state = RESPONSE_FAILED;
    request->send(500);
    return;
  }
  _head = _assembleHead(request->version());
  _state = RESPONSE_HEADERS;
  size_t outLen = _head.length();
  size_t space = request->client()->space();
  if(space >= outLen){
    request->client()->write(_head.c_str(), outLen);
    _head = String();
    _state = RESPONSE_CONTENT;
  } else {
    String out = _head.substring(0, space);
    _head = _head.substring(space);
    request->client()->write(out.c_str(), out.length());
    out = String();
  }
}

size_t AsyncAbstractResponse::_ack(AsyncWebServerRequest *request, size_t len, uint32_t time){
  if(!_sourceValid()){
    _state = RESPONSE_FAILED;
    request->client()->close();
    return 0;
  }
  _ackedLength += len;
  size_t space = request->client()->space();
  if(_state == RESPONSE_CONTENT){
    size_t outLen;
    size_t readLen = 0;

    if(_chunked || !_sendContentLength){
      outLen = space;
    } else {
      size_t remaining = _contentLength - _sentLength;
      outLen = (remaining > space)?space:remaining;
    }
    uint8_t *buf = (uint8_t *)malloc(outLen);

    if(_chunked){
      readLen = _fillBuffer(buf, outLen - 8);
      char pre[6];
      sprintf(pre, "%x\r\n", readLen);
      size_t preLen = strlen(pre);
      memmove(buf+preLen, buf, readLen);
      for(size_t i=0; i<preLen; i++)
        buf[i] = pre[i];
      outLen = preLen + readLen;
      buf[outLen++] = '\r';
      buf[outLen++] = '\n';
    } else {
      outLen = _fillBuffer(buf, outLen);
    }

    if(outLen)
      outLen = request->client()->write((const char*)buf, outLen);
    if(_chunked)
      _sentLength += readLen;
    else
      _sentLength += outLen;
    free(buf);

    if((_chunked && readLen == 0) || (!_sendContentLength && outLen == 0) || _sentLength == _contentLength){
      _state = RESPONSE_WAIT_ACK;
    }
    return outLen;

  } else if(_state == RESPONSE_HEADERS){
    size_t outLen = _head.length();
    if(space >= outLen){
      request->client()->write(_head.c_str(), outLen);
      _head = String();
      _state = RESPONSE_CONTENT;
      return outLen;
    } else {
      String out = _head.substring(0, space);
      _head = _head.substring(space);
      request->client()->write(out.c_str(), out.length());
      return out.length();
    }
  } else if(_state == RESPONSE_WAIT_ACK){
    if(!_sendContentLength || _ackedLength >= (_headLength+_contentLength)){
      _state = RESPONSE_END;
      if(!_chunked && !_sendContentLength)
        request->client()->close(true);
    }
  }
  return 0;
}

/*
 * File Response
 * */

AsyncFileResponse::~AsyncFileResponse(){
  if(_content)
    _content.close();
}

void AsyncFileResponse::_setContentType(String path){
  if (path.endsWith(".html")) _contentType = "text/html";
  else if (path.endsWith(".htm")) _contentType = "text/html";
  else if (path.endsWith(".css")) _contentType = "text/css";
  else if (path.endsWith(".txt")) _contentType = "text/plain";
  else if (path.endsWith(".js")) _contentType = "application/javascript";
  else if (path.endsWith(".png")) _contentType = "image/png";
  else if (path.endsWith(".gif")) _contentType = "image/gif";
  else if (path.endsWith(".jpg")) _contentType = "image/jpeg";
  else if (path.endsWith(".ico")) _contentType = "image/x-icon";
  else if (path.endsWith(".svg")) _contentType = "image/svg+xml";
  else if (path.endsWith(".xml")) _contentType = "text/xml";
  else if (path.endsWith(".pdf")) _contentType = "application/pdf";
  else if (path.endsWith(".zip")) _contentType = "application/zip";
  else if(path.endsWith(".gz")) _contentType = "application/x-gzip";
  else _contentType = "application/octet-stream";
}

AsyncFileResponse::AsyncFileResponse(FS &fs, String path, String contentType, bool download){
  _code = 200;
  _path = path;
  if(!download && !fs.exists(_path) && fs.exists(_path+".gz")){
    _path = _path+".gz";
    addHeader("Content-Encoding", "gzip");
  }

  if(download)
    _contentType = "application/octet-stream";
  else
    _setContentType(path);
  _content = fs.open(_path, "r");
  _contentLength = _content.size();
}

size_t AsyncFileResponse::_fillBuffer(uint8_t *data, size_t len){
  _content.read(data, len);
  return len;
}

/*
 * Stream Response
 * */

AsyncStreamResponse::AsyncStreamResponse(Stream &stream, String contentType, size_t len){
  _code = 200;
  _content = &stream;
  _contentLength = len;
  _contentType = contentType;
}

size_t AsyncStreamResponse::_fillBuffer(uint8_t *data, size_t len){
  size_t available = _content->available();
  size_t outLen = (available > len)?len:available;
  size_t i;
  for(i=0;i<outLen;i++)
    data[i] = _content->read();
  return outLen;
}

/*
 * Callback Response
 * */

AsyncCallbackResponse::AsyncCallbackResponse(String contentType, size_t len, AwsResponseFiller callback){
  _code = 200;
  _content = callback;
  _contentLength = len;
  if(!len)
    _sendContentLength = false;
  _contentType = contentType;
}

size_t AsyncCallbackResponse::_fillBuffer(uint8_t *data, size_t len){
  return _content(data, len, _sentLength);
}

/*
 * Chunked Response
 * */

AsyncChunkedResponse::AsyncChunkedResponse(String contentType, AwsResponseFiller callback){
  _code = 200;
  _content = callback;
  _contentLength = 0;
  _contentType = contentType;
  _sendContentLength = false;
  _chunked = true;
}

size_t AsyncChunkedResponse::_fillBuffer(uint8_t *data, size_t len){
  return _content(data, len, _sentLength);
}

/*
 * Response Stream (You can print/write/printf to it, up to the contentLen bytes)
 * */

AsyncResponseStream::AsyncResponseStream(String contentType, size_t bufferSize){
  _code = 200;
  _contentLength = 0;
  _contentType = contentType;
  _content = new cbuf(bufferSize);
}

AsyncResponseStream::~AsyncResponseStream(){
  delete _content;
}

size_t AsyncResponseStream::_fillBuffer(uint8_t *buf, size_t maxLen){
  return _content->read((char*)buf, maxLen);
}

size_t AsyncResponseStream::write(const uint8_t *data, size_t len){
  if(_started())
    return 0;

  if(len > _content->room()){
    size_t needed = len - _content->room();
    _content->resizeAdd(needed);
  }
  size_t written = _content->write((const char*)data, len);
  _contentLength += written;
  return written;
}

size_t AsyncResponseStream::write(uint8_t data){
  return write(&data, 1);
}

<commit_msg>Gracefully handle out of memory<commit_after>/*
  Asynchronous WebServer library for Espressif MCUs

  Copyright (c) 2016 Hristo Gochkov. All rights reserved.
  This file is part of the esp8266 core for Arduino environment.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/
#include "ESPAsyncWebServer.h"
#include "WebResponseImpl.h"
#include "cbuf.h"

/*
 * Abstract Response
 * */
const char* AsyncWebServerResponse::_responseCodeToString(int code) {
  switch (code) {
    case 100: return "Continue";
    case 101: return "Switching Protocols";
    case 200: return "OK";
    case 201: return "Created";
    case 202: return "Accepted";
    case 203: return "Non-Authoritative Information";
    case 204: return "No Content";
    case 205: return "Reset Content";
    case 206: return "Partial Content";
    case 300: return "Multiple Choices";
    case 301: return "Moved Permanently";
    case 302: return "Found";
    case 303: return "See Other";
    case 304: return "Not Modified";
    case 305: return "Use Proxy";
    case 307: return "Temporary Redirect";
    case 400: return "Bad Request";
    case 401: return "Unauthorized";
    case 402: return "Payment Required";
    case 403: return "Forbidden";
    case 404: return "Not Found";
    case 405: return "Method Not Allowed";
    case 406: return "Not Acceptable";
    case 407: return "Proxy Authentication Required";
    case 408: return "Request Time-out";
    case 409: return "Conflict";
    case 410: return "Gone";
    case 411: return "Length Required";
    case 412: return "Precondition Failed";
    case 413: return "Request Entity Too Large";
    case 414: return "Request-URI Too Large";
    case 415: return "Unsupported Media Type";
    case 416: return "Requested range not satisfiable";
    case 417: return "Expectation Failed";
    case 500: return "Internal Server Error";
    case 501: return "Not Implemented";
    case 502: return "Bad Gateway";
    case 503: return "Service Unavailable";
    case 504: return "Gateway Time-out";
    case 505: return "HTTP Version not supported";
    default:  return "";
  }
}

AsyncWebServerResponse::AsyncWebServerResponse()
  : _code(0)
  , _headers(NULL)
  , _contentType()
  , _contentLength(0)
  , _sendContentLength(true)
  , _chunked(false)
  , _headLength(0)
  , _sentLength(0)
  , _ackedLength(0)
  , _state(RESPONSE_SETUP)
{
  addHeader("Connection","close");
  addHeader("Access-Control-Allow-Origin","*");
}

AsyncWebServerResponse::~AsyncWebServerResponse(){
  while(_headers != NULL){
    AsyncWebHeader *h = _headers;
    _headers = h->next;
    delete h;
  }
}

void AsyncWebServerResponse::setContentLength(size_t len){
  if(_state == RESPONSE_SETUP)
    _contentLength = len;
}

void AsyncWebServerResponse::setContentType(String type){
  if(_state == RESPONSE_SETUP)
    _contentType = type;
}

void AsyncWebServerResponse::addHeader(String name, String value){
  AsyncWebHeader *header = new AsyncWebHeader(name, value);
  if(_headers == NULL){
    _headers = header;
  } else {
    AsyncWebHeader *h = _headers;
    while(h->next != NULL) h = h->next;
    h->next = header;
  }
}

String AsyncWebServerResponse::_assembleHead(uint8_t version){
  if(version){
    addHeader("Accept-Ranges","none");
    if(_chunked)
      addHeader("Transfer-Encoding","chunked");
  }
  String out = "HTTP/1." + String(version) + " " + String(_code) + " " + _responseCodeToString(_code) + "\r\n";
  if(_sendContentLength)
    out += "Content-Length: " + String(_contentLength) + "\r\n";

  if(_contentType.length())
    out += "Content-Type: " + _contentType + "\r\n";

  AsyncWebHeader *h;
  while(_headers != NULL){
    h = _headers;
    _headers = _headers->next;
    out += h->toString();
    delete h;
  }
  out += "\r\n";
  _headLength = out.length();
  return out;
}

bool AsyncWebServerResponse::_started(){ return _state > RESPONSE_SETUP; }
bool AsyncWebServerResponse::_finished(){ return _state > RESPONSE_WAIT_ACK; }
bool AsyncWebServerResponse::_failed(){ return _state == RESPONSE_FAILED; }
void AsyncWebServerResponse::_respond(AsyncWebServerRequest *request){ _state = RESPONSE_END; request->client()->close(); }
size_t AsyncWebServerResponse::_ack(AsyncWebServerRequest *request, size_t len, uint32_t time){ return 0; }

/*
 * String/Code Response
 * */
AsyncBasicResponse::AsyncBasicResponse(int code, String contentType, String content){
  _code = code;
  _content = content;
  _contentType = contentType;
  if(_content.length()){
    _contentLength = _content.length();
    if(!_contentType.length())
      _contentType = "text/plain";
  }
}

void AsyncBasicResponse::_respond(AsyncWebServerRequest *request){
  _state = RESPONSE_HEADERS;
  String out = _assembleHead(request->version());
  size_t outLen = out.length();
  size_t space = request->client()->space();
  if(!_contentLength && space >= outLen){
    request->client()->write(out.c_str(), outLen);
    _state = RESPONSE_WAIT_ACK;
  } else if(_contentLength && space >= outLen + _contentLength){
    out += _content;
    outLen += _contentLength;
    request->client()->write(out.c_str(), outLen);
    _state = RESPONSE_WAIT_ACK;
  } else if(space && space < out.length()){
    String partial = out.substring(0, space);
    _content = out.substring(space) + _content;
    _contentLength += outLen - space;
    request->client()->write(partial.c_str(), partial.length());
    _state = RESPONSE_CONTENT;
  } else if(space > outLen && space < (outLen + _contentLength)){
    size_t shift = space - outLen;
    outLen += shift;
    _sentLength += shift;
    out += _content.substring(0, shift);
    _content = _content.substring(shift);
    request->client()->write(out.c_str(), outLen);
    _state = RESPONSE_CONTENT;
  } else {
    _content = out + _content;
    _contentLength += outLen;
    _state = RESPONSE_CONTENT;
  }
}

size_t AsyncBasicResponse::_ack(AsyncWebServerRequest *request, size_t len, uint32_t time){
  _ackedLength += len;
  if(_state == RESPONSE_CONTENT){
    size_t available = _contentLength - _sentLength;
    size_t space = request->client()->space();
    //we can fit in this packet
    if(space > available){
      request->client()->write(_content.c_str(), available);
      _content = String();
      _state = RESPONSE_WAIT_ACK;
      return available;
    }
    //send some data, the rest on ack
    String out = _content.substring(0, space);
    _content = _content.substring(space);
    _sentLength += space;
    request->client()->write(out.c_str(), space);
    return space;
  } else if(_state == RESPONSE_WAIT_ACK){
    if(_ackedLength >= (_headLength+_contentLength)){
      _state = RESPONSE_END;
    }
  }
  return 0;
}

/*
 * Abstract Response
 * */

void AsyncAbstractResponse::_respond(AsyncWebServerRequest *request){
  if(!_sourceValid()){
    _state = RESPONSE_FAILED;
    request->send(500);
    return;
  }
  _head = _assembleHead(request->version());
  _state = RESPONSE_HEADERS;
  size_t outLen = _head.length();
  size_t space = request->client()->space();
  if(space >= outLen){
    request->client()->write(_head.c_str(), outLen);
    _head = String();
    _state = RESPONSE_CONTENT;
  } else {
    String out = _head.substring(0, space);
    _head = _head.substring(space);
    request->client()->write(out.c_str(), out.length());
    out = String();
  }
}

size_t AsyncAbstractResponse::_ack(AsyncWebServerRequest *request, size_t len, uint32_t time){
  if(!_sourceValid()){
    _state = RESPONSE_FAILED;
    request->client()->close();
    return 0;
  }
  _ackedLength += len;
  size_t space = request->client()->space();
  if(_state == RESPONSE_CONTENT){
    size_t outLen;
    size_t readLen = 0;

    if(_chunked || !_sendContentLength){
      outLen = space;
    } else {
      size_t remaining = _contentLength - _sentLength;
      outLen = (remaining > space)?space:remaining;
    }
    uint8_t *buf = (uint8_t *)malloc(outLen);
    if (!buf) {
      // os_printf("_ack malloc %d failed\n", outLen);
      return 0;
    }

    if(_chunked){
      readLen = _fillBuffer(buf, outLen - 8);
      char pre[6];
      sprintf(pre, "%x\r\n", readLen);
      size_t preLen = strlen(pre);
      memmove(buf+preLen, buf, readLen);
      for(size_t i=0; i<preLen; i++)
        buf[i] = pre[i];
      outLen = preLen + readLen;
      buf[outLen++] = '\r';
      buf[outLen++] = '\n';
    } else {
      outLen = _fillBuffer(buf, outLen);
    }

    if(outLen)
      outLen = request->client()->write((const char*)buf, outLen);
    if(_chunked)
      _sentLength += readLen;
    else
      _sentLength += outLen;
    free(buf);

    if((_chunked && readLen == 0) || (!_sendContentLength && outLen == 0) || _sentLength == _contentLength){
      _state = RESPONSE_WAIT_ACK;
    }
    return outLen;

  } else if(_state == RESPONSE_HEADERS){
    size_t outLen = _head.length();
    if(space >= outLen){
      request->client()->write(_head.c_str(), outLen);
      _head = String();
      _state = RESPONSE_CONTENT;
      return outLen;
    } else {
      String out = _head.substring(0, space);
      _head = _head.substring(space);
      request->client()->write(out.c_str(), out.length());
      return out.length();
    }
  } else if(_state == RESPONSE_WAIT_ACK){
    if(!_sendContentLength || _ackedLength >= (_headLength+_contentLength)){
      _state = RESPONSE_END;
      if(!_chunked && !_sendContentLength)
        request->client()->close(true);
    }
  }
  return 0;
}

/*
 * File Response
 * */

AsyncFileResponse::~AsyncFileResponse(){
  if(_content)
    _content.close();
}

void AsyncFileResponse::_setContentType(String path){
  if (path.endsWith(".html")) _contentType = "text/html";
  else if (path.endsWith(".htm")) _contentType = "text/html";
  else if (path.endsWith(".css")) _contentType = "text/css";
  else if (path.endsWith(".txt")) _contentType = "text/plain";
  else if (path.endsWith(".js")) _contentType = "application/javascript";
  else if (path.endsWith(".png")) _contentType = "image/png";
  else if (path.endsWith(".gif")) _contentType = "image/gif";
  else if (path.endsWith(".jpg")) _contentType = "image/jpeg";
  else if (path.endsWith(".ico")) _contentType = "image/x-icon";
  else if (path.endsWith(".svg")) _contentType = "image/svg+xml";
  else if (path.endsWith(".xml")) _contentType = "text/xml";
  else if (path.endsWith(".pdf")) _contentType = "application/pdf";
  else if (path.endsWith(".zip")) _contentType = "application/zip";
  else if(path.endsWith(".gz")) _contentType = "application/x-gzip";
  else _contentType = "application/octet-stream";
}

AsyncFileResponse::AsyncFileResponse(FS &fs, String path, String contentType, bool download){
  _code = 200;
  _path = path;
  if(!download && !fs.exists(_path) && fs.exists(_path+".gz")){
    _path = _path+".gz";
    addHeader("Content-Encoding", "gzip");
  }

  if(download)
    _contentType = "application/octet-stream";
  else
    _setContentType(path);
  _content = fs.open(_path, "r");
  _contentLength = _content.size();
}

size_t AsyncFileResponse::_fillBuffer(uint8_t *data, size_t len){
  _content.read(data, len);
  return len;
}

/*
 * Stream Response
 * */

AsyncStreamResponse::AsyncStreamResponse(Stream &stream, String contentType, size_t len){
  _code = 200;
  _content = &stream;
  _contentLength = len;
  _contentType = contentType;
}

size_t AsyncStreamResponse::_fillBuffer(uint8_t *data, size_t len){
  size_t available = _content->available();
  size_t outLen = (available > len)?len:available;
  size_t i;
  for(i=0;i<outLen;i++)
    data[i] = _content->read();
  return outLen;
}

/*
 * Callback Response
 * */

AsyncCallbackResponse::AsyncCallbackResponse(String contentType, size_t len, AwsResponseFiller callback){
  _code = 200;
  _content = callback;
  _contentLength = len;
  if(!len)
    _sendContentLength = false;
  _contentType = contentType;
}

size_t AsyncCallbackResponse::_fillBuffer(uint8_t *data, size_t len){
  return _content(data, len, _sentLength);
}

/*
 * Chunked Response
 * */

AsyncChunkedResponse::AsyncChunkedResponse(String contentType, AwsResponseFiller callback){
  _code = 200;
  _content = callback;
  _contentLength = 0;
  _contentType = contentType;
  _sendContentLength = false;
  _chunked = true;
}

size_t AsyncChunkedResponse::_fillBuffer(uint8_t *data, size_t len){
  return _content(data, len, _sentLength);
}

/*
 * Response Stream (You can print/write/printf to it, up to the contentLen bytes)
 * */

AsyncResponseStream::AsyncResponseStream(String contentType, size_t bufferSize){
  _code = 200;
  _contentLength = 0;
  _contentType = contentType;
  _content = new cbuf(bufferSize);
}

AsyncResponseStream::~AsyncResponseStream(){
  delete _content;
}

size_t AsyncResponseStream::_fillBuffer(uint8_t *buf, size_t maxLen){
  return _content->read((char*)buf, maxLen);
}

size_t AsyncResponseStream::write(const uint8_t *data, size_t len){
  if(_started())
    return 0;

  if(len > _content->room()){
    size_t needed = len - _content->room();
    _content->resizeAdd(needed);
  }
  size_t written = _content->write((const char*)data, len);
  _contentLength += written;
  return written;
}

size_t AsyncResponseStream::write(uint8_t data){
  return write(&data, 1);
}

<|endoftext|>


<commit_before>#include <ace-vm/Value.hpp>
#include <ace-vm/Object.hpp>
#include <ace-vm/Array.hpp>

#include <stdio.h>
#include <cinttypes>

namespace ace {
namespace vm {

Value::Value()
    : m_type(HEAP_POINTER)
{
    // initialize to null reference
    m_value.ptr = nullptr;
}

Value::Value(const Value &other)
    : m_type(other.m_type),
      m_value(other.m_value)
{
}

void Value::Mark()
{
    HeapValue *ptr = m_value.ptr;

    if (m_type == Value::HEAP_POINTER && ptr != nullptr && !(ptr->GetFlags() & GC_MARKED)) {
        if (Object *object = ptr->GetPointer<Object>()) {
            int size = object->GetSize();
            for (int i = 0; i < size; i++) {
                object->GetMember(i).value.Mark();
            }
        } else if (Array *array = ptr->GetPointer<Array>()) {
            int size = array->GetSize();
            for (int i = 0; i < size; i++) {
                array->AtIndex(i).Mark();
            }
        }

        ptr->GetFlags() |= GC_MARKED;
    }
}

utf::Utf8String Value::ToString()
{
    const int buf_size = 256;
    char buf[buf_size] = {'\0'};
    int n = 0;

    switch (m_type) {
        case Value::I32: {
            n = snprintf(buf, buf_size, "%d", m_value.i32);
            if (n >= buf_size) {
                utf::Utf8String res((size_t)n);
                snprintf(res.GetData(), n, "%d", m_value.i32);
                return res;
            }
            return utf::Utf8String(buf);
        }
        case Value::I64:
            n = snprintf(buf, buf_size, "%" PRId64, m_value.i64);
            if (n >= buf_size) {
                utf::Utf8String res((size_t)n);
                snprintf(res.GetData(), n, "%" PRId64, m_value.i64);
                return res;
            }
            return utf::Utf8String(buf);
        case Value::F32:
            n = snprintf(buf, buf_size, "%g", m_value.f);
            if (n >= buf_size) {
                utf::Utf8String res((size_t)n);
                snprintf(res.GetData(), n, "%g", m_value.f);
                return res;
            }
            return utf::Utf8String(buf);
        case Value::F64:
            n = snprintf(buf, buf_size, "%g", m_value.d);
            if (n >= buf_size) {
                utf::Utf8String res((size_t)n);
                snprintf(res.GetData(), n, "%g", m_value.d);
                return res;
            }
            return utf::Utf8String(buf);
        case Value::BOOLEAN:
            snprintf(buf, buf_size, "%s", m_value.b ? "true" : "false");
            return utf::Utf8String(buf);
        case Value::HEAP_POINTER:
        {
            if (!m_value.ptr) {
                return utf::Utf8String("null");
            } else if (utf::Utf8String *string = m_value.ptr->GetPointer<utf::Utf8String>()) {
                return *string;
            } else if (Array *array = m_value.ptr->GetPointer<Array>()) {
                // convert array list to string
                const char sep_str[] = ", ";

                utf::Utf8String res("[", 256);

                // convert all array elements to string
                const int size = array->GetSize();
                for (int i = 0; i < size; i++) {
                    res += array->AtIndex(i).ToString();

                    if (i != size - 1) {
                        res += sep_str;
                    }
                }

                res += "]";

                return res;
            } else {
                // return memory address as string
                n = snprintf(buf, buf_size, "%p", (void*)m_value.ptr);
                if (n >= buf_size) {
                    utf::Utf8String res((size_t)n);
                    snprintf(res.GetData(), n, "%p", (void*)m_value.ptr);
                    return res;
                }
                return utf::Utf8String(buf);
            }

            break;
        }
        default: return GetTypeString();
    }
}

} // namespace vm
} // namespace ace<commit_msg>Delete value.cpp<commit_after><|endoftext|>


<commit_before>/*
This file is part of Groho, a simulator for inter-planetary travel and warfare.
Copyright (c) 2018 by Kaushik Ghose. Some rights reserved, see LICENSE

Timed burn - set acceleration and the unset it after a predetermined time
*/

#include "flightplanaction.hpp"

namespace sim {

// TODO: What happens when burns are fractions of a time step?
struct BURN : public FlightPlanAction {

    double                acc;
    double                burn_duration;
    std::optional<double> burn_end_time;

    void setup(
        [[maybe_unused]] SnapShot<ShipLike>&                    this_ship,
        [[maybe_unused]] const Collection<SnapShotV<RockLike>>& system)
    {
        ;
    }

    ShipCommand execute(
        const SnapShot<ShipLike>&                               this_ship,
        [[maybe_unused]] const Collection<SnapShotV<RockLike>>& system)
    {
        if (burn_end_time) {
            if (*burn_end_time < this_ship.state.t_s) {
                return { acc, {}, {} };
            } else {
                done = true;
                return { 0, {}, {} };
            }
        } else {
            burn_end_time = this_ship.state.t_s + burn_duration;
            if (acc > this_ship.property.max_acc) {
                LOG_S(WARNING)
                    << line_no << ": SET_ACCEL for "
                    << this_ship.property.naif.name << " exceeds max_acc";
                acc = this_ship.property.max_acc;
            }
            return { acc, {}, {} };
        }
    }

    bool is_blocking() const { return false; }

    std::string usage() const
    {
        return R"(Fire engines for given time.
    acc:0.01 \ ; acceleration in km/s^2
    for:10  ; duration in s)";
    }
};

template <> std::unique_ptr<FlightPlanAction> construct<BURN>(params_t* params)
{
    auto action = std::unique_ptr<BURN>(new BURN());
    if (params) {
        action->acc           = stof((*params)["acc"]);
        action->burn_duration = stod((*params)["for"]);
    }
    return action;
}
}<commit_msg>bugfix: Correct conditional for burn action<commit_after>/*
This file is part of Groho, a simulator for inter-planetary travel and warfare.
Copyright (c) 2018 by Kaushik Ghose. Some rights reserved, see LICENSE

Timed burn - set acceleration and the unset it after a predetermined time
*/

#include "flightplanaction.hpp"

namespace sim {

// TODO: What happens when burns are fractions of a time step?
struct BURN : public FlightPlanAction {

    double                acc;
    double                burn_duration;
    std::optional<double> burn_end_time;

    void setup(
        [[maybe_unused]] SnapShot<ShipLike>&                    this_ship,
        [[maybe_unused]] const Collection<SnapShotV<RockLike>>& system)
    {
        ;
    }

    ShipCommand execute(
        const SnapShot<ShipLike>&                               this_ship,
        [[maybe_unused]] const Collection<SnapShotV<RockLike>>& system)
    {
        if (burn_end_time) {
            if (this_ship.state.t_s < *burn_end_time) {
                return { acc, {}, {} };
            } else {
                done = true;
                return { 0, {}, {} };
            }
        } else {
            burn_end_time = this_ship.state.t_s + burn_duration;
            if (acc > this_ship.property.max_acc) {
                LOG_S(WARNING)
                    << line_no << ": SET_ACCEL for "
                    << this_ship.property.naif.name << " exceeds max_acc";
                acc = this_ship.property.max_acc;
            }
            return { acc, {}, {} };
        }
    }

    bool is_blocking() const { return false; }

    std::string usage() const
    {
        return R"(Fire engines for given time.
    acc:0.01 \ ; acceleration in km/s^2
    for:10  ; duration in s)";
    }
};

template <> std::unique_ptr<FlightPlanAction> construct<BURN>(params_t* params)
{
    auto action = std::unique_ptr<BURN>(new BURN());
    if (params) {
        action->acc           = stof((*params)["acc"]);
        action->burn_duration = stod((*params)["for"]);
    }
    return action;
}
}<|endoftext|>