// ******************************************************************************************
// Calculate Offset Position
// ******************************************************************************************
void PlanningSceneDisplay::calculateOffsetPosition()
{  
  if (!getRobotModel())
    return;
  
  tf::Stamped<tf::Pose> pose(tf::Pose::getIdentity(), ros::Time(0), getRobotModel()->getModelFrame());
  static const unsigned int max_attempts = 10;
  unsigned int attempts = 0;
  while (!context_->getTFClient()->canTransform(fixed_frame_.toStdString(), getRobotModel()->getModelFrame(), ros::Time(0)) && attempts < max_attempts)
  {
    ros::Duration(0.1).sleep();
    attempts++;
  }
  
  if (attempts < max_attempts)
  {
    try
    {
      context_->getTFClient()->transformPose(fixed_frame_.toStdString(), pose, pose);
    }
    catch (tf::TransformException& e)
    {
      ROS_ERROR( "Error transforming from frame '%s' to frame '%s'", pose.frame_id_.c_str(), fixed_frame_.toStdString().c_str() );
    }
  }

  Ogre::Vector3 position(pose.getOrigin().x(), pose.getOrigin().y(), pose.getOrigin().z());
  const tf::Quaternion &q = pose.getRotation();
  Ogre::Quaternion orientation( q.getW(), q.getX(), q.getY(), q.getZ() );
  planning_scene_node_->setPosition(position);
  planning_scene_node_->setOrientation(orientation);
}
// ******************************************************************************************
// Calculate Offset Position
// ******************************************************************************************
void RobotStateDisplay::calculateOffsetPosition()
{
  if (!getRobotModel())
    return;

  ros::Time stamp;
  std::string err_string;
  if (context_->getTFClient()->getLatestCommonTime(fixed_frame_.toStdString(), getRobotModel()->getModelFrame(), stamp, &err_string) != tf::NO_ERROR)
    return;

  tf::Stamped<tf::Pose> pose(tf::Pose::getIdentity(), stamp, getRobotModel()->getModelFrame());

  if (context_->getTFClient()->canTransform(fixed_frame_.toStdString(), getRobotModel()->getModelFrame(), stamp))
  {
    try
    {
      context_->getTFClient()->transformPose(fixed_frame_.toStdString(), pose, pose);
    }
    catch (tf::TransformException& e)
    {
      ROS_ERROR( "Error transforming from frame '%s' to frame '%s'", pose.frame_id_.c_str(), fixed_frame_.toStdString().c_str() );
    }
  }

  Ogre::Vector3 position(pose.getOrigin().x(), pose.getOrigin().y(), pose.getOrigin().z());
  const tf::Quaternion &q = pose.getRotation();
  Ogre::Quaternion orientation( q.getW(), q.getX(), q.getY(), q.getZ() );
  scene_node_->setPosition(position);
  scene_node_->setOrientation(orientation);
}
void PlanningSceneDisplay::unsetAllColors(rviz::Robot* robot)
{ 
  if (getRobotModel())
  {
    const std::vector<std::string> &links = getRobotModel()->getLinkModelNamesWithCollisionGeometry();
    for (std::size_t i = 0 ; i < links.size() ; ++i)
      unsetLinkColor(robot, links[i]);
  }
}
void PlanningSceneDisplay::unsetGroupColor(rviz::Robot* robot, const std::string& group_name )
{
  if (getRobotModel())
  {
    const robot_model::JointModelGroup *jmg = getRobotModel()->getJointModelGroup(group_name);
    if (jmg)
    {
      const std::vector<std::string> &links = jmg->getLinkModelNamesWithCollisionGeometry();
      for (std::size_t i = 0 ; i < links.size() ; ++i)
        unsetLinkColor(robot, links[i]);
    }
  }
}
void PlanningSceneDisplay::onRobotModelLoaded()
{
  planning_scene_robot_->load(*getRobotModel()->getURDF());
  const planning_scene_monitor::LockedPlanningSceneRO &ps = getPlanningSceneRO();
  planning_scene_robot_->update(robot_state::RobotStatePtr(new robot_state::RobotState(ps->getCurrentState())));

  bool oldState = scene_name_property_->blockSignals(true);
  scene_name_property_->setStdString(ps->getName());
  scene_name_property_->blockSignals(oldState);

  oldState = root_link_name_property_->blockSignals(true);
  root_link_name_property_->setStdString(getRobotModel()->getRootLinkName());
  root_link_name_property_->blockSignals(oldState);  
}
bool SBPLCollisionModel::init(std::string ns)
{
  if(!getRobotModel())
    return false;

  if(ns.empty())
    ns = "~";
  return readGroups(ns);
}
void robot_sphere_representation::RobotSphereRepresentation::copySrdfSpheres(const srdf::Model *srdf)
{
  if (!srdf)
    srdf = getRobotModel()->getSRDF().get();

  std::map<std::string, LinkSphereRepresentation*>::iterator lsr = links_.begin();
  std::map<std::string, LinkSphereRepresentation*>::iterator lsr_end = links_.end();
  for ( ; lsr != lsr_end ; ++lsr )
    lsr->second->copySrdfSpheres(srdf);
}
void PlanningSceneDisplay::onSceneMonitorReceivedUpdate(planning_scene_monitor::PlanningSceneMonitor::SceneUpdateType update_type)
{
  bool oldState = scene_name_property_->blockSignals(true);
  scene_name_property_->setStdString(getPlanningSceneRO()->getName());
  scene_name_property_->blockSignals(oldState);

  oldState = root_link_name_property_->blockSignals(true);
  root_link_name_property_->setStdString(getRobotModel()->getRootLinkName());
  root_link_name_property_->blockSignals(oldState);
  
  planning_scene_needs_render_ = true;
}
// ******************************************************************************************
// Load
// ******************************************************************************************
void RobotStateDisplay::loadRobotModel()
{
  if (!rdf_loader_)
    rdf_loader_.reset(new rdf_loader::RDFLoader(robot_description_property_->getStdString()));

  if (rdf_loader_->getURDF())
  {
    const boost::shared_ptr<srdf::Model> &srdf = rdf_loader_->getSRDF() ? rdf_loader_->getSRDF() : boost::shared_ptr<srdf::Model>(new srdf::Model());
    kmodel_.reset(new robot_model::RobotModel(rdf_loader_->getURDF(), srdf));
    robot_->load(*kmodel_->getURDF());
    kstate_.reset(new robot_state::RobotState(kmodel_));
    kstate_->setToDefaultValues();
    bool oldState = root_link_name_property_->blockSignals(true);
    root_link_name_property_->setStdString(getRobotModel()->getRootLinkName());
    root_link_name_property_->blockSignals(oldState);
    update_state_ = true;
    setStatus( rviz::StatusProperty::Ok, "RobotState", "Planning Model Loaded Successfully" );
  }
  else
    setStatus( rviz::StatusProperty::Error, "RobotState", "No Planning Model Loaded" );

  highlights_.clear();
}
void PlanningSceneDisplay::changedRootLinkName()
{
  if (getRobotModel())
    root_link_name_property_->setStdString(getRobotModel()->getRootLinkName());
}
bool CartesianTrajectoryPlannerModule::plan(vigir_planning_msgs::RequestDrakeCartesianTrajectory &request_message, vigir_planning_msgs::ResultDrakeTrajectory &result_message)
{
    // stay at q0 for nominal trajectory
    bool received_world_transform = false;
    VectorXd q0 = VectorXd::Zero(this->getRobotModel()->num_positions);
    q0 = messageQs2DrakeQs(q0, request_message.current_state, received_world_transform);

    std::cout << "q0 = " << std::endl;
    MatrixXd printQ = q0;
    printSortedQs(printQ);

    if ( request_message.waypoint_times.empty() ) {
        request_message.waypoint_times = estimateWaypointTimes(q0, request_message.target_link_names, request_message.waypoints);
        if ( request_message.waypoint_times.empty() ) { // request was invalid
            return false;
        }
    }

    std::vector<Waypoint*> waypoints = extractOrderedWaypoints(request_message);
        
    int nq = getRobotModel()->num_positions;
    int num_steps = waypoints.size();
    bool success = true;
    
    // run inverse kinematics
    MatrixXd q_sol(nq,0);
    MatrixXd qd_sol(nq,0);
    MatrixXd qdd_sol(nq,0);
    std::vector<double> t_sol;

    int last_successful_waypoint = -1;
    for ( int i = 1; i < num_steps; i++ ) {
        Waypoint *current_start_point = waypoints[i-1];
        Waypoint *current_target_point = waypoints[i];

        double time_step = (current_target_point->waypoint_time - current_start_point->waypoint_time) / NUM_TIME_STEPS;
        
        // check trajectory every time_step seconds
        std::vector<double> t_vec;

        double duration = current_target_point->waypoint_time - current_start_point->waypoint_time;
        t_vec.push_back(current_start_point->waypoint_time);
        t_vec.push_back(current_start_point->waypoint_time + duration/2.0);
        t_vec.push_back(current_target_point->waypoint_time);
        t_sol.push_back(current_start_point->waypoint_time);
        t_sol.push_back(current_start_point->waypoint_time + duration/2.0);
        
        VectorXd qdot_0 = VectorXd::Zero(this->getRobotModel()->num_velocities);
        MatrixXd q_seed = q0.replicate(1, t_vec.size());
        MatrixXd q_nom = q_seed;

        // build list of constraints from message
        IKoptions *ik_options = buildIKOptions(duration);

        // build constraints
        std::vector<RigidBodyConstraint*> constraints = buildIKConstraints(request_message, current_start_point, current_target_point, q0);

        // run IK trajectory calculation
        MatrixXd q_sol_part(this->getRobotModel()->num_positions,t_vec.size());
        MatrixXd qd_sol_part(this->getRobotModel()->num_positions,t_vec.size());
        MatrixXd qdd_sol_part(this->getRobotModel()->num_positions,t_vec.size());
    
        int info;
        std::vector<std::string> infeasible_constraints;
        inverseKinTraj(this->getRobotModel(),t_vec.size(),t_vec.data(),qdot_0,q_seed,q_nom,constraints.size(),constraints.data(),q_sol_part,qd_sol_part,qdd_sol_part,info,infeasible_constraints,*ik_options);

        if(info>=10) { // something went wrong
            std::string constraint_string = "";
            for (auto const& constraint : infeasible_constraints) { constraint_string += (constraint+" | "); }

            ROS_WARN("Step %d / %d: SNOPT info is %d, IK mex fails to solve the problem", i+1, num_steps, info);
            ROS_INFO("Infeasible constraints: %s", constraint_string.c_str());

            if ( i == 1 || request_message.execute_incomplete_cartesian_plans == false) {
                success = false;                
                break;
            }
            else {
                t_sol.erase(t_sol.end()-1, t_sol.end());
                q_sol.conservativeResize(nq, q_sol.cols() + 1 );
                qd_sol.conservativeResize(nq, qd_sol.cols() + 1 );
                qdd_sol.conservativeResize(nq, qdd_sol.cols() + 1 );

                q_sol.block(0, q_sol.cols()-1, nq, 1) = q0;
                qd_sol.block(0, q_sol.cols()-1, nq, 1) = MatrixXd::Zero(nq, 1);
                qdd_sol.block(0, q_sol.cols()-1, nq, 1) = MatrixXd::Zero(nq, 1);
                break;
            }

        }

        int old_q_size = q_sol.cols();
        q_sol.conservativeResize(nq, q_sol.cols() + q_sol_part.cols()-1 );
        qd_sol.conservativeResize(nq, qd_sol.cols() + qd_sol_part.cols()-1 );
        qdd_sol.conservativeResize(nq, qdd_sol.cols() + qdd_sol_part.cols()-1 );
        q_sol.block(0, old_q_size, nq, q_sol_part.cols()-1) = q_sol_part.block(0, 0, nq, q_sol_part.cols()-1);
        qd_sol.block(0, old_q_size, nq, qd_sol_part.cols()-1) = qd_sol_part.block(0, 0, nq, qd_sol_part.cols()-1);
        qdd_sol.block(0, old_q_size, nq, qdd_sol_part.cols()-1) = qdd_sol_part.block(0, 0, nq, qdd_sol_part.cols()-1);

        // add final element at the very end
        if ( i == num_steps-1 ) {
            t_sol.push_back(waypoints[ waypoints.size()-1 ]->waypoint_time);
            q_sol.conservativeResize(nq, q_sol.cols() + 1 );
            qd_sol.conservativeResize(nq, qd_sol.cols() + 1 );
            qdd_sol.conservativeResize(nq, qdd_sol.cols() + 1 );

            q_sol.block(0, q_sol.cols()-1, nq, 1) = q_sol_part.block(0, q_sol_part.cols()-1, nq, 1);
            qd_sol.block(0, q_sol.cols()-1, nq, 1) = qd_sol_part.block(0, qd_sol_part.cols()-1, nq, 1);
            qdd_sol.block(0, q_sol.cols()-1, nq, 1) = qdd_sol_part.block(0, qdd_sol_part.cols()-1, nq, 1);
        }

        q0 = q_sol_part.col( q_sol_part.cols()-1 );
        last_successful_waypoint = i;
    }

    if ( success ) {
        // generate spline from result matrices (default sample rate = 4.0Hz)
        if ( request_message.trajectory_sample_rate == 0.0 ) {
            request_message.trajectory_sample_rate = 4.0;
        }
        double time_step = 1.0 / request_message.trajectory_sample_rate;
        double duration = waypoints[ last_successful_waypoint]->waypoint_time;
        int num_steps = (duration / time_step) + 0.5;
        Eigen::VectorXd response_t(num_steps+1);

        for ( int i = 0; i <= num_steps; i++) {
            response_t(i) = i*time_step;
        }

        Eigen::VectorXd interpolated_t = Map<VectorXd>(t_sol.data(), t_sol.size());
        interpolateTrajectory(q_sol, interpolated_t, response_t, q_sol, qd_sol, qdd_sol);



        result_message = buildTrajectoryResultMsg(q_sol, qd_sol, qdd_sol, response_t, request_message.free_joint_names, received_world_transform);
    }
    else {
        // return an invalid message
        result_message.is_valid = false;
    }

    return success;
}
std::vector<RigidBodyConstraint*> CartesianTrajectoryPlannerModule::buildIKConstraints(vigir_planning_msgs::RequestDrakeCartesianTrajectory &request_message, CartesianTrajectoryPlannerModule::Waypoint *start_waypoint, CartesianTrajectoryPlannerModule::Waypoint *target_waypoint, Eigen::VectorXd &q0) {
    std::vector<RigidBodyConstraint*> constraints;

    Vector2d t_span_total;
    t_span_total << start_waypoint->waypoint_time, target_waypoint->waypoint_time;
    Vector2d t_span_target;
    t_span_target << target_waypoint->waypoint_time, target_waypoint->waypoint_time;

    // avoid self-collisions
    if ( request_message.check_self_collisions ) {
            constraints.push_back( new AllBodiesClosestDistanceConstraint(getRobotModel(), 0.01, 1e10, std::vector<int>(), std::set<std::string>(), t_span_total) );
            //constraints.push_back( new MinDistanceConstraint(getRobotModel(), 0.001, std::vector<int>(), std::set<std::string>(), t_span) );
    }

    // keep torso more or less upright
    int torso_body_idx = getRobotModel()->findLinkId("utorso");
    Vector3d axis;
    axis << 0.0, 0.0, 1.0;
    constraints.push_back(new WorldGazeDirConstraint(getRobotModel(), torso_body_idx, axis, axis, 0.1, t_span_total));

    // fixed foot placement
    int l_foot_id = this->getRobotModel()->findLinkId("l_foot");
    int r_foot_id = this->getRobotModel()->findLinkId("r_foot");

    Vector4d hom_foot_pts;
    hom_foot_pts << 0.0,0.0,0.0,1.0;
    Vector3d foot_pts;
    foot_pts << 0.0,0.0,0.0;

    VectorXd v = VectorXd::Zero(this->getRobotModel()->num_velocities);
    this->getRobotModel()->doKinematicsNew(q0, v);
    Vector7d l_foot_pos = this->getRobotModel()->forwardKinNew(foot_pts, l_foot_id, 0, 2, 0).value();
    Vector7d r_foot_pos = this->getRobotModel()->forwardKinNew(foot_pts, r_foot_id, 0, 2, 0).value();

    constraints.push_back( new WorldPositionConstraint(this->getRobotModel(), l_foot_id, hom_foot_pts, l_foot_pos.block<3,1>(0,0), l_foot_pos.block<3,1>(0,0)) );
    constraints.push_back( new WorldPositionConstraint(this->getRobotModel(), r_foot_id, hom_foot_pts, r_foot_pos.block<3,1>(0,0), r_foot_pos.block<3,1>(0,0)) );
    constraints.push_back( new WorldQuatConstraint(this->getRobotModel(), l_foot_id, l_foot_pos.block<4,1>(3,0), 0.0));
    constraints.push_back( new WorldQuatConstraint(this->getRobotModel(), r_foot_id, l_foot_pos.block<4,1>(3,0), 0.0));

    // add quasi static constraint
    MatrixXd l_foot_contact_pts = getRobotModel()->bodies[l_foot_id]->contact_pts;
    MatrixXd r_foot_contact_pts = getRobotModel()->bodies[r_foot_id]->contact_pts;
    QuasiStaticConstraint *quasi_static_constraint = new QuasiStaticConstraint(this->getRobotModel());
    quasi_static_constraint->addContact(1, &l_foot_id, &l_foot_contact_pts);
    quasi_static_constraint->addContact(1, &r_foot_id, &r_foot_contact_pts);
    quasi_static_constraint->setActive(true);
    quasi_static_constraint->setShrinkFactor(0.9);
    constraints.push_back( quasi_static_constraint );

    // add waypoint constraints
    Vector3d goal_position_vec, target_link_axis_vec;
    Vector4d eef_pts, goal_orientation_quat;
    eef_pts << 0.0, 0.0, 0.0, 1.0;
    for ( int target_waypoint_idx = 0; target_waypoint_idx < target_waypoint->target_link_names.size(); target_waypoint_idx++ ) {
        int start_waypoint_idx = -1;
        for ( int j = 0; j < start_waypoint->target_link_names.size(); j++ ) {
            if ( start_waypoint->target_link_names[j].find( target_waypoint->target_link_names[j]) != std::string::npos ) {
                start_waypoint_idx = j;
                break;
            }
        }

        std::string target_link_name = target_waypoint->target_link_names[target_waypoint_idx];

        // get endeffector body ids and points
        int eef_body_id = getRobotModel()->findLinkId(target_link_name);

        // goal position constraint        
        goal_position_vec << target_waypoint->poses[target_waypoint_idx].position.x, target_waypoint->poses[target_waypoint_idx].position.y, target_waypoint->poses[target_waypoint_idx].position.z;
        constraints.push_back( new WorldPositionConstraint(getRobotModel(), eef_body_id, eef_pts, goal_position_vec, goal_position_vec, t_span_target) );

        // goal orientation constraint and straight line between start and target constraint
        if ( start_waypoint_idx >= 0 && start_waypoint->keep_line_and_orientation[start_waypoint_idx] == true ) {
            goal_orientation_quat << start_waypoint->poses[start_waypoint_idx].orientation.w, start_waypoint->poses[start_waypoint_idx].orientation.x, start_waypoint->poses[start_waypoint_idx].orientation.y, start_waypoint->poses[start_waypoint_idx].orientation.z;
            target_link_axis_vec << start_waypoint->target_link_axis[start_waypoint_idx].x, start_waypoint->target_link_axis[start_waypoint_idx].y, start_waypoint->target_link_axis[start_waypoint_idx].z;
        }
        else if ( target_waypoint->keep_line_and_orientation[target_waypoint_idx] == true ) {
            goal_orientation_quat << target_waypoint->poses[target_waypoint_idx].orientation.w, target_waypoint->poses[target_waypoint_idx].orientation.x, target_waypoint->poses[target_waypoint_idx].orientation.y, target_waypoint->poses[target_waypoint_idx].orientation.z;
            target_link_axis_vec << target_waypoint->target_link_axis[target_waypoint_idx].x, target_waypoint->target_link_axis[target_waypoint_idx].y, target_waypoint->target_link_axis[target_waypoint_idx].z;
        }

        if ( request_message.target_orientation_type == vigir_planning_msgs::ExtendedPlanningOptions::ORIENTATION_FULL ) {
           constraints.push_back( new WorldQuatConstraint(getRobotModel(), eef_body_id, goal_orientation_quat, 0, t_span_target));
        }
        else if ( request_message.target_orientation_type == vigir_planning_msgs::ExtendedPlanningOptions::ORIENTATION_AXIS_ONLY ) { // goal axis orientation constraint
           constraints.push_back( new WorldGazeOrientConstraint(getRobotModel(), eef_body_id, target_link_axis_vec, goal_orientation_quat, 0.01, M_PI, t_span_target ));
        }

        if ( start_waypoint_idx >= 0 && start_waypoint->keep_line_and_orientation[start_waypoint_idx] == true ) {
            // line segment
            Vector4d line_start_vec, line_end_vec;
            line_start_vec << start_waypoint->poses[start_waypoint_idx].position.x, start_waypoint->poses[start_waypoint_idx].position.y, start_waypoint->poses[start_waypoint_idx].position.z, 1.0;
            line_end_vec   << target_waypoint->poses[target_waypoint_idx].position.x, target_waypoint->poses[target_waypoint_idx].position.y, target_waypoint->poses[target_waypoint_idx].position.z, 1.0;

            Matrix4Xd line(4,2);
            line << line_start_vec, line_end_vec;

            constraints.push_back( new Point2LineSegDistConstraint(getRobotModel(),eef_body_id,eef_pts,0,line,0.0,0.02,t_span_total) );
        }

    }

    return constraints;
}