<commit_before>#include "motion_planning/plan_pick.hpp"
#include <tf/transform_listener.h>

PlanPickAction::PlanPickAction(ros::NodeHandle nh, std::string name) :
  nh_(nh),
  as_(nh_, name, false),
  action_name_(name),
  ac_gripper_("gripper_motion/move_gripper", true),
  ac_move_("motion/move_to_pose", true),
  ac_move_posture_("motion/move_to_posture", true)  {
  //register the goal and feeback callbacks
  as_.registerGoalCallback(boost::bind(&PlanPickAction::goalCB, this));
  as_.registerPreemptCallback(boost::bind(&PlanPickAction::preemptCB, this));

  this->init();
  ROS_INFO("Starting PlanPick server");
  as_.start();
}

PlanPickAction::~PlanPickAction(void) {
}

void PlanPickAction::init() {
  ac_gripper_.waitForServer();
  ac_move_.waitForServer();
  ROS_INFO("Connected to gripper and arm movement servers");
}

void PlanPickAction::goalCB() {
  object_pose_ = as_.acceptNewGoal()->object_pose;
  this->executeCB();
}

void PlanPickAction::preemptCB() {
  ROS_INFO("Preempt");
  as_.setPreempted();
}

void PlanPickAction::executeCB() {
  bool going = true;
  bool success = false;
  // states:
  // 0 initial
  // 1 approached
  // 2 opened gripper
  // 3 grasped
  // 4 closed gripper
  int state = 1;
  ros::Rate r(10);
  feedback_.curr_state = 1;
  as_.publishFeedback(feedback_);
  ROS_INFO("Executing goal for %s", action_name_.c_str());

  // motion attempts
  int motion_attempts = 6;

  geometry_msgs::PoseStamped gripper_pose = object_pose_;
  gripper_pose.pose.orientation = computeGripperGraspPose(object_pose_.pose.position);

  double distanceObj = sqrt(pow(0.14 - object_pose_.pose.position.x, 2) +
                       pow(object_pose_.pose.position.y, 2));
  ROS_INFO("Object 2D distance to base_link is: %f",distanceObj);

  double ground_limit = 0.1;
  // Safety guard for never attempting to reach below the ground
  if (gripper_pose.pose.position.z < ground_limit) {
    ROS_INFO("Attempting to reach below ground limit %f with z-coord: %f", ground_limit, gripper_pose.pose.position.z);
    ROS_INFO("Assuming z='ground limit' for safety");
    gripper_pose.pose.position.z = ground_limit;
  }

  while (going) {
    if (as_.isPreemptRequested() || !ros::ok()) {
      ROS_INFO("%s: Preempted", action_name_.c_str());
      as_.setPreempted();
      going = false;
    }

    // if (state == 0) {
    //   // initial base alignment
    //   if (direction == 1)
    //     arm_posture_goal_.posture = "l_pre_grasp";
    //   else if (direction == 2)
    //     arm_posture_goal_.posture = "f_pre_grasp";
    //   else
    //     arm_posture_goal_.posture = "r_pre_grasp";

    //   // move to pose action
    //   ac_move_posture_.waitForServer();
    //   ROS_INFO("Initial Alignment");

    //   ac_move_posture_.sendGoal(arm_posture_goal_);
    //   feedback_.curr_state = 1;
    //   as_.publishFeedback(feedback_);
    //   ac_move_posture_.waitForResult();
    //   if (ac_move_posture_.getState() == actionlib::SimpleClientGoalState::SUCCEEDED) {
    //     state = 1;
    //   }
    // } else
    if (state == 1) {
      // target pose declaration
      geometry_msgs::PoseStamped target_pose = gripper_pose;

      // approach object
      target_pose.pose.position.z += 0.05;
      arm_goal_.pose = target_pose;
      arm_goal_.distance_tol = 0.01;
      arm_goal_.orientation_tol = 0.05;
      arm_goal_.planning_time = 20.0;
      ROS_INFO("Approaching object");
      ac_move_.sendGoal(arm_goal_);
      ac_move_.waitForResult();

      if (ac_move_.getState() == actionlib::SimpleClientGoalState::SUCCEEDED) {
        state = 2;
        ROS_INFO("Approaching action success");
      } else {
        ROS_INFO("Approaching action failed: %s", ac_move_.getState().toString().c_str());
        if(motion_attempts>0){
          motion_attempts--;
        }else{
          going = false;
        }
      }
    } else if (state == 2) {
      // open gripper action
      gripper_goal_.command = 1;
      ROS_INFO("Opening Gripper");
      ac_gripper_.sendGoal(gripper_goal_);
      ac_gripper_.waitForResult();
      if (ac_gripper_.getState() == actionlib::SimpleClientGoalState::SUCCEEDED) {
        state = 3;
        ROS_INFO("Opening gripper action success");
      } else {
        ROS_INFO("Opening gripper action failed: %s", ac_gripper_.getState().toString().c_str());
      }
    } else if (state == 3) {
      // move to pose action
      arm_goal_.pose = gripper_pose;
      arm_goal_.distance_tol = 0.01;
      arm_goal_.orientation_tol = 0.05;
      arm_goal_.planning_time = 20.0;
      ROS_INFO("Making contact with object");
      ac_move_.sendGoal(arm_goal_);
      ac_move_.waitForResult();
      if (ac_move_.getState() == actionlib::SimpleClientGoalState::SUCCEEDED) {
        state = 4;
        ROS_INFO("Make contact action success");
      } else {
        ROS_INFO("Make contact action failed: %s", ac_move_.getState().toString().c_str());
        if(motion_attempts>0){
          motion_attempts--;
        }else{
          going = false;
        }
      }
    } else if (state == 4) {
      // close gripper
      gripper_goal_.command = 0;
      ROS_INFO("Closing Gripper");
      ac_gripper_.sendGoal(gripper_goal_);
      ac_gripper_.waitForResult();
      if (ac_gripper_.getState() == actionlib::SimpleClientGoalState::SUCCEEDED) {
        state = 5;
        ROS_INFO("Closing gripper action success");
      } else {
        ROS_INFO("Closing gripper action failed: %s", ac_gripper_.getState().toString().c_str());
      }
    } else if (state == 5) {
      // moving away object
      geometry_msgs::PoseStamped target_pose = gripper_pose;
      target_pose.pose.position.z += 0.05;
      arm_goal_.pose = target_pose;
      arm_goal_.distance_tol = 0.01;
      arm_goal_.orientation_tol = 0.05;
      arm_goal_.planning_time = 20.0;
      ROS_INFO("Moving away from object");
      ac_move_.sendGoal(arm_goal_);
      ac_move_.waitForResult();

      if (ac_move_.getState() == actionlib::SimpleClientGoalState::SUCCEEDED) {
        state = 6;
        ROS_INFO("Moving away from object action success");
      } else {
        ROS_INFO("Moving away from object action failed: %s", ac_move_.getState().toString().c_str());
      }
    } else if (state == 6) {
      success = true;
      going = false;
    }

    ros::spinOnce();
    r.sleep();
  }

  feedback_.curr_state = 2;
  as_.publishFeedback(feedback_);

  if (success) {
    result_.success = true;
    ROS_INFO("%s: Succeeded!", action_name_.c_str());
    as_.setSucceeded(result_);
  } else {
    result_.success = false;
    ROS_INFO("%s: Failed!", action_name_.c_str());
    as_.setAborted(result_);
  }
}

geometry_msgs::Quaternion computeGripperGraspPose(geometry_msgs::Point pt) {
  // orientation
  double base_trans = 0.14;
  double tan_angle = atan2(pt.y, pt.x-base_trans);
  ROS_INFO("Computed angle: %f",tan_angle);

  // old
  // tf::Matrix3x3 mat(tf::Quaternion(quat.x, quat.y, quat.z, quat.w));
  // double roll; double pitch; double yaw;
  // mat.getRPY(roll, pitch, yaw);
  // ROS_INFO("Cube RPY orientation: (%f,%f,%f)", roll, pitch, yaw);

  double offset = 0.25;
  double yaw_angle = tan_angle + offset;

  // old
  // if (yaw < 0.0)
  //   yaw_angle += offset;
  // else
  //   yaw_angle -= 3 * offset;

  // if (yaw < -1.5) // front
  //   yaw_angle = 0.2;
  // else if (yaw < 0.5) // left
  //   yaw_angle = 1.77;
  // else // right
  //   yaw_angle = -1.37;

  ROS_INFO("Desired Gripper RPY orientation: (%f,%f,%f)", 3.141, 0.001, yaw_angle);

  return tf::createQuaternionMsgFromRollPitchYaw(3.141, 0.001, yaw_angle);
}
<commit_msg>adjusted the distance safety guard - now allowed to move 1 cm closer to ground<commit_after>#include "motion_planning/plan_pick.hpp"
#include <tf/transform_listener.h>

PlanPickAction::PlanPickAction(ros::NodeHandle nh, std::string name) :
  nh_(nh),
  as_(nh_, name, false),
  action_name_(name),
  ac_gripper_("gripper_motion/move_gripper", true),
  ac_move_("motion/move_to_pose", true),
  ac_move_posture_("motion/move_to_posture", true)  {
  //register the goal and feeback callbacks
  as_.registerGoalCallback(boost::bind(&PlanPickAction::goalCB, this));
  as_.registerPreemptCallback(boost::bind(&PlanPickAction::preemptCB, this));

  this->init();
  ROS_INFO("Starting PlanPick server");
  as_.start();
}

PlanPickAction::~PlanPickAction(void) {
}

void PlanPickAction::init() {
  ac_gripper_.waitForServer();
  ac_move_.waitForServer();
  ROS_INFO("Connected to gripper and arm movement servers");
}

void PlanPickAction::goalCB() {
  object_pose_ = as_.acceptNewGoal()->object_pose;
  this->executeCB();
}

void PlanPickAction::preemptCB() {
  ROS_INFO("Preempt");
  as_.setPreempted();
}

void PlanPickAction::executeCB() {
  bool going = true;
  bool success = false;
  // states:
  // 0 initial
  // 1 approached
  // 2 opened gripper
  // 3 grasped
  // 4 closed gripper
  int state = 1;
  ros::Rate r(10);
  feedback_.curr_state = 1;
  as_.publishFeedback(feedback_);
  ROS_INFO("Executing goal for %s", action_name_.c_str());

  // motion attempts
  int motion_attempts = 6;

  geometry_msgs::PoseStamped gripper_pose = object_pose_;
  gripper_pose.pose.orientation = computeGripperGraspPose(object_pose_.pose.position);

  double distanceObj = sqrt(pow(0.14 - object_pose_.pose.position.x, 2) +
                       pow(object_pose_.pose.position.y, 2));
  ROS_INFO("Object 2D distance to base_link is: %f",distanceObj);

  double ground_limit = 0.095;
  // Safety guard for never attempting to reach below the ground
  if (gripper_pose.pose.position.z < ground_limit) {
    ROS_INFO("Attempting to reach below ground limit %f with z-coord: %f", ground_limit, gripper_pose.pose.position.z);
    ROS_INFO("Assuming z='ground limit' for safety");
    gripper_pose.pose.position.z = ground_limit;
  }

  while (going) {
    if (as_.isPreemptRequested() || !ros::ok()) {
      ROS_INFO("%s: Preempted", action_name_.c_str());
      as_.setPreempted();
      going = false;
    }

    // if (state == 0) {
    //   // initial base alignment
    //   if (direction == 1)
    //     arm_posture_goal_.posture = "l_pre_grasp";
    //   else if (direction == 2)
    //     arm_posture_goal_.posture = "f_pre_grasp";
    //   else
    //     arm_posture_goal_.posture = "r_pre_grasp";

    //   // move to pose action
    //   ac_move_posture_.waitForServer();
    //   ROS_INFO("Initial Alignment");

    //   ac_move_posture_.sendGoal(arm_posture_goal_);
    //   feedback_.curr_state = 1;
    //   as_.publishFeedback(feedback_);
    //   ac_move_posture_.waitForResult();
    //   if (ac_move_posture_.getState() == actionlib::SimpleClientGoalState::SUCCEEDED) {
    //     state = 1;
    //   }
    // } else
    if (state == 1) {
      // target pose declaration
      geometry_msgs::PoseStamped target_pose = gripper_pose;

      // approach object
      target_pose.pose.position.z += 0.05;
      arm_goal_.pose = target_pose;
      arm_goal_.distance_tol = 0.01;
      arm_goal_.orientation_tol = 0.05;
      arm_goal_.planning_time = 20.0;
      ROS_INFO("Approaching object");
      ac_move_.sendGoal(arm_goal_);
      ac_move_.waitForResult();

      if (ac_move_.getState() == actionlib::SimpleClientGoalState::SUCCEEDED) {
        state = 2;
        ROS_INFO("Approaching action success");
      } else {
        ROS_INFO("Approaching action failed: %s", ac_move_.getState().toString().c_str());
        if(motion_attempts>0){
          motion_attempts--;
        }else{
          going = false;
        }
      }
    } else if (state == 2) {
      // open gripper action
      gripper_goal_.command = 1;
      ROS_INFO("Opening Gripper");
      ac_gripper_.sendGoal(gripper_goal_);
      ac_gripper_.waitForResult();
      if (ac_gripper_.getState() == actionlib::SimpleClientGoalState::SUCCEEDED) {
        state = 3;
        ROS_INFO("Opening gripper action success");
      } else {
        ROS_INFO("Opening gripper action failed: %s", ac_gripper_.getState().toString().c_str());
      }
    } else if (state == 3) {
      // move to pose action
      arm_goal_.pose = gripper_pose;
      arm_goal_.distance_tol = 0.01;
      arm_goal_.orientation_tol = 0.05;
      arm_goal_.planning_time = 20.0;
      ROS_INFO("Making contact with object");
      ac_move_.sendGoal(arm_goal_);
      ac_move_.waitForResult();
      if (ac_move_.getState() == actionlib::SimpleClientGoalState::SUCCEEDED) {
        state = 4;
        ROS_INFO("Make contact action success");
      } else {
        ROS_INFO("Make contact action failed: %s", ac_move_.getState().toString().c_str());
        if(motion_attempts>0){
          motion_attempts--;
        }else{
          going = false;
        }
      }
    } else if (state == 4) {
      // close gripper
      gripper_goal_.command = 0;
      ROS_INFO("Closing Gripper");
      ac_gripper_.sendGoal(gripper_goal_);
      ac_gripper_.waitForResult();
      if (ac_gripper_.getState() == actionlib::SimpleClientGoalState::SUCCEEDED) {
        state = 5;
        ROS_INFO("Closing gripper action success");
      } else {
        ROS_INFO("Closing gripper action failed: %s", ac_gripper_.getState().toString().c_str());
      }
    } else if (state == 5) {
      // moving away object
      geometry_msgs::PoseStamped target_pose = gripper_pose;
      target_pose.pose.position.z += 0.05;
      arm_goal_.pose = target_pose;
      arm_goal_.distance_tol = 0.01;
      arm_goal_.orientation_tol = 0.05;
      arm_goal_.planning_time = 20.0;
      ROS_INFO("Moving away from object");
      ac_move_.sendGoal(arm_goal_);
      ac_move_.waitForResult();

      if (ac_move_.getState() == actionlib::SimpleClientGoalState::SUCCEEDED) {
        state = 6;
        ROS_INFO("Moving away from object action success");
      } else {
        ROS_INFO("Moving away from object action failed: %s", ac_move_.getState().toString().c_str());
      }
    } else if (state == 6) {
      success = true;
      going = false;
    }

    ros::spinOnce();
    r.sleep();
  }

  feedback_.curr_state = 2;
  as_.publishFeedback(feedback_);

  if (success) {
    result_.success = true;
    ROS_INFO("%s: Succeeded!", action_name_.c_str());
    as_.setSucceeded(result_);
  } else {
    result_.success = false;
    ROS_INFO("%s: Failed!", action_name_.c_str());
    as_.setAborted(result_);
  }
}

geometry_msgs::Quaternion computeGripperGraspPose(geometry_msgs::Point pt) {
  // orientation
  double base_trans = 0.14;
  double tan_angle = atan2(pt.y, pt.x-base_trans);
  ROS_INFO("Computed angle: %f",tan_angle);

  // old
  // tf::Matrix3x3 mat(tf::Quaternion(quat.x, quat.y, quat.z, quat.w));
  // double roll; double pitch; double yaw;
  // mat.getRPY(roll, pitch, yaw);
  // ROS_INFO("Cube RPY orientation: (%f,%f,%f)", roll, pitch, yaw);

  double offset = 0.25;
  double yaw_angle = tan_angle + offset;

  // old
  // if (yaw < 0.0)
  //   yaw_angle += offset;
  // else
  //   yaw_angle -= 3 * offset;

  // if (yaw < -1.5) // front
  //   yaw_angle = 0.2;
  // else if (yaw < 0.5) // left
  //   yaw_angle = 1.77;
  // else // right
  //   yaw_angle = -1.37;

  ROS_INFO("Desired Gripper RPY orientation: (%f,%f,%f)", 3.141, 0.001, yaw_angle);

  return tf::createQuaternionMsgFromRollPitchYaw(3.141, 0.001, yaw_angle);
}
<|endoftext|>


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

  Program:   Visualization Toolkit
  Module:    vtkQtTableRepresentation.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
/*----------------------------------------------------------------------------
 Copyright (c) Sandia Corporation
 See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details.
----------------------------------------------------------------------------*/

#include "vtkQtTableRepresentation.h"
#include "vtkQtTableModelAdapter.h"

#include <vtkAlgorithm.h>
#include <vtkAlgorithmOutput.h>
#include <vtkDataSetAttributes.h>
#include <vtkDoubleArray.h>
#include <vtkIdTypeArray.h>
#include <vtkLookupTable.h>
#include <vtkObjectFactory.h>
#include <vtkTable.h>

#include <QModelIndex>
#include <QColor>

#include <assert.h>

// ----------------------------------------------------------------------
vtkCxxRevisionMacro(vtkQtTableRepresentation, "1.6");

// ----------------------------------------------------------------------
vtkCxxSetObjectMacro(vtkQtTableRepresentation, ColorTable, vtkLookupTable);

// ----------------------------------------------------------------------
vtkQtTableRepresentation::vtkQtTableRepresentation()
{
  this->ModelAdapter = new vtkQtTableModelAdapter;

  this->ColorTable = vtkLookupTable::New();
  this->ColorTable->Register(this);
  this->ColorTable->Delete();

  this->ColorTable->SetHueRange(0.0, 1.0);
  this->ColorTable->SetRange(0.0, 1.0);
  this->ColorTable->Build();

  this->SeriesColors = vtkDoubleArray::New();
  this->SeriesColors->SetNumberOfComponents(4);
  this->SeriesColors->Register(this);
  this->SeriesColors->Delete();

  this->KeyColumnInternal = NULL;
  this->FirstDataColumn = NULL;
  this->LastDataColumn = NULL;
}

// ----------------------------------------------------------------------

vtkQtTableRepresentation::~vtkQtTableRepresentation()
{
  if (this->ModelAdapter)
    {
    delete this->ModelAdapter;
    }
  this->ColorTable->UnRegister(this);
  this->SeriesColors->UnRegister(this);
  this->SetKeyColumnInternal(NULL);
  this->SetFirstDataColumn(NULL);
  this->SetLastDataColumn(NULL);
}

// ----------------------------------------------------------------------

void
vtkQtTableRepresentation::SetupInputConnections()
{
  this->UpdateTable();
}

// ----------------------------------------------------------------------

void
vtkQtTableRepresentation::SetKeyColumn(const char *col)
{
  if((!col && !this->KeyColumnInternal) ||
      (this->KeyColumnInternal && col && strcmp(this->KeyColumnInternal, col) == 0))
    {
    return;
    }

  this->SetKeyColumnInternal(col);
  this->ModelAdapter->SetKeyColumn(-1);
  this->Modified();
  // Is this really good? We never call Update() in algorithms.
  this->Update();
}

// ----------------------------------------------------------------------

char* vtkQtTableRepresentation::GetKeyColumn()
{
  return this->GetKeyColumnInternal();
}

// ----------------------------------------------------------------------
void vtkQtTableRepresentation::UpdateTable()
{
  this->ResetModel();

  if (!this->GetInput())
    {
    return;
    }

  vtkTable *table = vtkTable::SafeDownCast(this->GetInput());
  if (!table)
    {
    vtkErrorMacro(<<"vtkQtTableRepresentation: I need a vtkTable as input.  You supplied a " << this->GetInput()->GetClassName() << ".");
    return;
    }

  // Set first/last data column names if they
  // have not already been set.
  const char* firstDataColumn = this->FirstDataColumn;
  const char* lastDataColumn = this->LastDataColumn;
  if (!firstDataColumn)
    {
    firstDataColumn = table->GetColumnName(0);
    }
  if (!lastDataColumn)
    {
    lastDataColumn = table->GetColumnName(table->GetNumberOfColumns()-1);
    }

  // Now that we're sure of having data, put it into a Qt model
  // adapter that we can push into the QListView.  Before we hand that
  // off, though, we'll need to come up with colors for
  // each series.
  int keyColumnIndex = -1;
  int firstDataColumnIndex = -1;
  int lastDataColumnIndex = -1;
  //if (this->KeyColumnInternal != NULL)
  //  {
  //  table->GetRowData()->GetAbstractArray(this->KeyColumnInternal, keyColumnIndex);
  //  if (keyColumnIndex >= 0)
  //    {
  //    this->ModelAdapter->SetKeyColumn(keyColumnIndex);
  //    }
  //  else
  //    {
  //    // Either the user didn't specify a key column or else it wasn't
  //    // found.  We'll do the best we can.
  //    vtkWarningMacro(<<"vtkQtTableRepresentation: Key column "
  //                    << (this->KeyColumnInternal ? this->KeyColumnInternal : "(NULL)")
  //                    << " not found.  Defaulting to column 0.");
  //    this->ModelAdapter->SetKeyColumn(0);
  //    }
  //  }
  if (firstDataColumn != NULL)
    {
    table->GetRowData()->GetAbstractArray(firstDataColumn,
                                          firstDataColumnIndex);
    }
  if (lastDataColumn != NULL)
    {
    table->GetRowData()->GetAbstractArray(lastDataColumn,
                                          lastDataColumnIndex);
    }
  this->ModelAdapter->SetDataColumnRange(firstDataColumnIndex, lastDataColumnIndex);

  // The view will try to do this when we add the representation, but
  // we need the model to be populated before that so we'll just do it
  // here.

  this->ModelAdapter->SetVTKDataObject(table);
  if (this->KeyColumnInternal != NULL)
    {
    this->ModelAdapter->SetKeyColumnName(this->KeyColumnInternal);
    }
  this->CreateSeriesColors();
}

// ----------------------------------------------------------------------

void
vtkQtTableRepresentation::ResetModel()
{
  this->SetModelType();
  if (this->ModelAdapter)
    {
    // FIXME
    // Need to alert the model of potential changes to the vtkTable
    // in different way than disconnecting/reconnecting the vtkTable from
    // the model adapter
    //this->ModelAdapter->SetVTKDataObject(NULL);
    }
  this->SeriesColors->Reset();
  this->SeriesColors->SetNumberOfComponents(4);
}

// ----------------------------------------------------------------------

void
vtkQtTableRepresentation::CreateSeriesColors()
{
  this->SeriesColors->Reset();
  this->SeriesColors->SetNumberOfComponents(4);

  int size = this->ModelAdapter->rowCount(QModelIndex());

  this->SeriesColors->SetNumberOfTuples(size);

  for (int i = 0; i < size; ++i)
    {
    double seriesValue = 1;
    if (size > 1)
      {
      seriesValue = static_cast<double>(i) / (size-1);
      }
    QColor c;
    if (this->ColorTable)
      {
      double rgb[3];
      double opacity;
      this->ColorTable->GetColor(seriesValue, rgb);
      opacity = this->ColorTable->GetOpacity(seriesValue);
      c.setRgbF(rgb[0], rgb[1], rgb[2], opacity);
      }
    else
      {
      c.setHsvF(seriesValue, 1, 0.7);
      }

    this->SeriesColors->SetComponent(i, 0, c.redF());
    this->SeriesColors->SetComponent(i, 1, c.greenF());
    this->SeriesColors->SetComponent(i, 2, c.blueF());
    this->SeriesColors->SetComponent(i, 3, c.alphaF());
    }
}

// ----------------------------------------------------------------------

void
vtkQtTableRepresentation::PrintSelf(ostream &os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);

  os << indent << "First data column: "
     << (this->FirstDataColumn ? this->FirstDataColumn : "(NULL)")
     << "\n";

  os << indent << "Last data column: "
     << (this->LastDataColumn ? this->LastDataColumn : "(NULL)")
     << "\n";

  os << indent << "Key column: "
     << (this->KeyColumnInternal ? this->KeyColumnInternal : "(NULL)")
     << "\n";

  os << indent << "Model adapter: Qt object " << this->ModelAdapter
     << "\n";

  os << indent << "Color creation table: ";
  this->ColorTable->PrintSelf(os, indent.GetNextIndent());

  os << indent << "Series color table: ";
  this->SeriesColors->PrintSelf(os, indent.GetNextIndent());
}
<commit_msg>COMP: fixed warning.<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkQtTableRepresentation.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
/*----------------------------------------------------------------------------
 Copyright (c) Sandia Corporation
 See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details.
----------------------------------------------------------------------------*/

#include "vtkQtTableRepresentation.h"
#include "vtkQtTableModelAdapter.h"

#include <vtkAlgorithm.h>
#include <vtkAlgorithmOutput.h>
#include <vtkDataSetAttributes.h>
#include <vtkDoubleArray.h>
#include <vtkIdTypeArray.h>
#include <vtkLookupTable.h>
#include <vtkObjectFactory.h>
#include <vtkTable.h>

#include <QModelIndex>
#include <QColor>

#include <assert.h>

// ----------------------------------------------------------------------
vtkCxxRevisionMacro(vtkQtTableRepresentation, "1.7");

// ----------------------------------------------------------------------
vtkCxxSetObjectMacro(vtkQtTableRepresentation, ColorTable, vtkLookupTable);

// ----------------------------------------------------------------------
vtkQtTableRepresentation::vtkQtTableRepresentation()
{
  this->ModelAdapter = new vtkQtTableModelAdapter;

  this->ColorTable = vtkLookupTable::New();
  this->ColorTable->Register(this);
  this->ColorTable->Delete();

  this->ColorTable->SetHueRange(0.0, 1.0);
  this->ColorTable->SetRange(0.0, 1.0);
  this->ColorTable->Build();

  this->SeriesColors = vtkDoubleArray::New();
  this->SeriesColors->SetNumberOfComponents(4);
  this->SeriesColors->Register(this);
  this->SeriesColors->Delete();

  this->KeyColumnInternal = NULL;
  this->FirstDataColumn = NULL;
  this->LastDataColumn = NULL;
}

// ----------------------------------------------------------------------

vtkQtTableRepresentation::~vtkQtTableRepresentation()
{
  if (this->ModelAdapter)
    {
    delete this->ModelAdapter;
    }
  this->ColorTable->UnRegister(this);
  this->SeriesColors->UnRegister(this);
  this->SetKeyColumnInternal(NULL);
  this->SetFirstDataColumn(NULL);
  this->SetLastDataColumn(NULL);
}

// ----------------------------------------------------------------------

void
vtkQtTableRepresentation::SetupInputConnections()
{
  this->UpdateTable();
}

// ----------------------------------------------------------------------

void
vtkQtTableRepresentation::SetKeyColumn(const char *col)
{
  if((!col && !this->KeyColumnInternal) ||
      (this->KeyColumnInternal && col && strcmp(this->KeyColumnInternal, col) == 0))
    {
    return;
    }

  this->SetKeyColumnInternal(col);
  this->ModelAdapter->SetKeyColumn(-1);
  this->Modified();
  // Is this really good? We never call Update() in algorithms.
  this->Update();
}

// ----------------------------------------------------------------------

char* vtkQtTableRepresentation::GetKeyColumn()
{
  return this->GetKeyColumnInternal();
}

// ----------------------------------------------------------------------
void vtkQtTableRepresentation::UpdateTable()
{
  this->ResetModel();

  if (!this->GetInput())
    {
    return;
    }

  vtkTable *table = vtkTable::SafeDownCast(this->GetInput());
  if (!table)
    {
    vtkErrorMacro(<<"vtkQtTableRepresentation: I need a vtkTable as input.  You supplied a " << this->GetInput()->GetClassName() << ".");
    return;
    }

  // Set first/last data column names if they
  // have not already been set.
  const char* firstDataColumn = this->FirstDataColumn;
  const char* lastDataColumn = this->LastDataColumn;
  if (!firstDataColumn)
    {
    firstDataColumn = table->GetColumnName(0);
    }
  if (!lastDataColumn)
    {
    lastDataColumn = table->GetColumnName(table->GetNumberOfColumns()-1);
    }

  // Now that we're sure of having data, put it into a Qt model
  // adapter that we can push into the QListView.  Before we hand that
  // off, though, we'll need to come up with colors for
  // each series.
  //int keyColumnIndex = -1;
  int firstDataColumnIndex = -1;
  int lastDataColumnIndex = -1;
  //if (this->KeyColumnInternal != NULL)
  //  {
  //  table->GetRowData()->GetAbstractArray(this->KeyColumnInternal, keyColumnIndex);
  //  if (keyColumnIndex >= 0)
  //    {
  //    this->ModelAdapter->SetKeyColumn(keyColumnIndex);
  //    }
  //  else
  //    {
  //    // Either the user didn't specify a key column or else it wasn't
  //    // found.  We'll do the best we can.
  //    vtkWarningMacro(<<"vtkQtTableRepresentation: Key column "
  //                    << (this->KeyColumnInternal ? this->KeyColumnInternal : "(NULL)")
  //                    << " not found.  Defaulting to column 0.");
  //    this->ModelAdapter->SetKeyColumn(0);
  //    }
  //  }
  if (firstDataColumn != NULL)
    {
    table->GetRowData()->GetAbstractArray(firstDataColumn,
                                          firstDataColumnIndex);
    }
  if (lastDataColumn != NULL)
    {
    table->GetRowData()->GetAbstractArray(lastDataColumn,
                                          lastDataColumnIndex);
    }
  this->ModelAdapter->SetDataColumnRange(firstDataColumnIndex, lastDataColumnIndex);

  // The view will try to do this when we add the representation, but
  // we need the model to be populated before that so we'll just do it
  // here.

  this->ModelAdapter->SetVTKDataObject(table);
  if (this->KeyColumnInternal != NULL)
    {
    this->ModelAdapter->SetKeyColumnName(this->KeyColumnInternal);
    }
  this->CreateSeriesColors();
}

// ----------------------------------------------------------------------

void
vtkQtTableRepresentation::ResetModel()
{
  this->SetModelType();
  if (this->ModelAdapter)
    {
    // FIXME
    // Need to alert the model of potential changes to the vtkTable
    // in different way than disconnecting/reconnecting the vtkTable from
    // the model adapter
    //this->ModelAdapter->SetVTKDataObject(NULL);
    }
  this->SeriesColors->Reset();
  this->SeriesColors->SetNumberOfComponents(4);
}

// ----------------------------------------------------------------------

void
vtkQtTableRepresentation::CreateSeriesColors()
{
  this->SeriesColors->Reset();
  this->SeriesColors->SetNumberOfComponents(4);

  int size = this->ModelAdapter->rowCount(QModelIndex());

  this->SeriesColors->SetNumberOfTuples(size);

  for (int i = 0; i < size; ++i)
    {
    double seriesValue = 1;
    if (size > 1)
      {
      seriesValue = static_cast<double>(i) / (size-1);
      }
    QColor c;
    if (this->ColorTable)
      {
      double rgb[3];
      double opacity;
      this->ColorTable->GetColor(seriesValue, rgb);
      opacity = this->ColorTable->GetOpacity(seriesValue);
      c.setRgbF(rgb[0], rgb[1], rgb[2], opacity);
      }
    else
      {
      c.setHsvF(seriesValue, 1, 0.7);
      }

    this->SeriesColors->SetComponent(i, 0, c.redF());
    this->SeriesColors->SetComponent(i, 1, c.greenF());
    this->SeriesColors->SetComponent(i, 2, c.blueF());
    this->SeriesColors->SetComponent(i, 3, c.alphaF());
    }
}

// ----------------------------------------------------------------------

void
vtkQtTableRepresentation::PrintSelf(ostream &os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);

  os << indent << "First data column: "
     << (this->FirstDataColumn ? this->FirstDataColumn : "(NULL)")
     << "\n";

  os << indent << "Last data column: "
     << (this->LastDataColumn ? this->LastDataColumn : "(NULL)")
     << "\n";

  os << indent << "Key column: "
     << (this->KeyColumnInternal ? this->KeyColumnInternal : "(NULL)")
     << "\n";

  os << indent << "Model adapter: Qt object " << this->ModelAdapter
     << "\n";

  os << indent << "Color creation table: ";
  this->ColorTable->PrintSelf(os, indent.GetNextIndent());

  os << indent << "Series color table: ";
  this->SeriesColors->PrintSelf(os, indent.GetNextIndent());
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2007 Kevin Wolf
 *
 * This program is free software. It comes without any warranty, to
 * the extent permitted by applicable law. You can redistribute it
 * and/or modify it under the terms of the Do What The Fuck You Want
 * To Public License, Version 2, as published by Sam Hocevar. See
 * http://sam.zoy.org/projects/COPYING.WTFPL for more details.
 */

//#include <stdlib.h>

#include <Module.h>
#include <machine/Device.h>

#include <cdi.h>
#include <cdi-osdep.h>
#include <cdi/lists.h>
#include <cdi/pci.h>

static cdi_list_t drivers = NULL;
static cdi_list_t devices = NULL;

static void cdi_destroy(void);

void iterateDeviceTree(Device *root)
{
    for(size_t i = 0; i < root->getNumChildren(); i++)
    {
        Device *p = root->getChild(i);

        struct cdi_pci_device *dev = new struct cdi_pci_device;
        dev->bus_data.bus_type = CDI_PCI;

        dev->bus = p->getPciBusPosition();
        dev->dev = p->getPciDevicePosition();
        dev->function = p->getPciFunctionNumber();

        dev->vendor_id = p->getPciVendorId();
        dev->device_id = p->getPciDeviceId();

        dev->class_id = p->getPciClassCode();
        dev->subclass_id = p->getPciSubclassCode();
        dev->interface_id = p->getPciProgInterface();

        dev->rev_id = 0; /// \todo Implement into Device

        dev->irq = p->getInterruptNumber();

        dev->resources = cdi_list_create();
        for(size_t j = 0; j < p->addresses().count(); j++)
        {
            Device::Address *addr = p->addresses()[j];
            struct cdi_pci_resource *res = new struct cdi_pci_resource;
            if(addr->m_IsIoSpace)
                res->type = CDI_PCI_IOPORTS;
            else
                res->type = CDI_PCI_MEMORY;
            res->start = addr->m_Address;
            res->length = addr->m_Size;
            res->index = j;
            res->address = reinterpret_cast<void*>(res->start);

            cdi_list_push(dev->resources, res);
        }

        dev->meta.backdev = reinterpret_cast<void *>(p);

        cdi_list_push(devices, dev);

        if(p->getNumChildren())
            iterateDeviceTree(p);
    }
}

/**
 * Muss vor dem ersten Aufruf einer anderen CDI-Funktion aufgerufen werden.
 * Initialisiert interne Datenstruktur der Implementierung fuer das jeweilige
 * Betriebssystem.
 */
void cdi_init(void)
{
    drivers = cdi_list_create();
    devices = cdi_list_create();

    // Iterate the device tree and add cdi_bus_data structs to the device list
    // for each found device.
    Device *root = &Device::root();
    iterateDeviceTree(root);
}

void cdi_pedigree_walk_dev_list_init(struct cdi_driver *dev)
{
    struct cdi_driver* driver = dev;
    struct cdi_bus_data* device;
    int i;
    for (i = 0; (device = reinterpret_cast<struct cdi_bus_data*>(cdi_list_get(devices, i))); i++) {
        if (driver->init_device) {
            struct cdi_device *p = driver->init_device(device);
            if(p)
            {
                p->driver = driver;
            }
        }
    }
}

void cdi_pedigree_walk_dev_list_destroy(struct cdi_driver *dev)
{
    struct cdi_driver* driver = dev;
    struct cdi_device* device;
    int i;
    for (i = 0; (device = reinterpret_cast<struct cdi_device*>(cdi_list_get(devices, i))); i++) {
        if (driver->remove_device) {
            driver->remove_device(device);
        }
    }
}

/**
 * Wird bei der Deinitialisierung aufgerufen
 */
static void cdi_destroy(void)
{
    // Drivers are already destroyed by the module exit function
}

/**
 * Fuehrt alle registrierten Treiber aus. Nach dem Aufruf dieser Funktion
 * duerfen keine weiteren Befehle ausgefuehrt werden, da nicht definiert ist,
 * ob und wann die Funktion zurueckkehrt.
 */
void cdi_run_drivers(void)
{
    // Geraete initialisieren
    struct cdi_driver* driver;
    int i;
    for (i = 0; (driver = reinterpret_cast<struct cdi_driver*>(cdi_list_get(drivers, i))); i++) {
        cdi_pedigree_walk_dev_list_init(driver);
    }
}

/**
 * Initialisiert die Datenstrukturen fuer einen Treiber
 */
void cdi_driver_init(struct cdi_driver* driver)
{
    driver->devices = cdi_list_create();
}

/**
 * Deinitialisiert die Datenstrukturen fuer einen Treiber
 */
void cdi_driver_destroy(struct cdi_driver* driver)
{
    cdi_list_destroy(driver->devices);
}

/**
 * Registriert den Treiber fuer ein neues Geraet
 *
 * @param driver Zu registierender Treiber
 */
void cdi_driver_register(struct cdi_driver* driver)
{
    cdi_list_push(drivers, driver);
}

MODULE_INFO("cdi", &cdi_init, &cdi_destroy, "dma", "network-stack", "vfs");
<commit_msg>CDI: implemented cdi_provide_device for PCI devices.<commit_after>/*
 * Copyright (c) 2007 Kevin Wolf
 *
 * This program is free software. It comes without any warranty, to
 * the extent permitted by applicable law. You can redistribute it
 * and/or modify it under the terms of the Do What The Fuck You Want
 * To Public License, Version 2, as published by Sam Hocevar. See
 * http://sam.zoy.org/projects/COPYING.WTFPL for more details.
 */

//#include <stdlib.h>

#include <Module.h>
#include <machine/Device.h>

#include <cdi.h>
#include <cdi-osdep.h>
#include <cdi/lists.h>
#include <cdi/pci.h>

static cdi_list_t drivers = NULL;
static cdi_list_t devices = NULL;

static void cdi_destroy(void);

void iterateDeviceTree(Device *root)
{
    for(size_t i = 0; i < root->getNumChildren(); i++)
    {
        Device *p = root->getChild(i);

        struct cdi_pci_device *dev = new struct cdi_pci_device;
        dev->bus_data.bus_type = CDI_PCI;

        dev->bus = p->getPciBusPosition();
        dev->dev = p->getPciDevicePosition();
        dev->function = p->getPciFunctionNumber();

        dev->vendor_id = p->getPciVendorId();
        dev->device_id = p->getPciDeviceId();

        dev->class_id = p->getPciClassCode();
        dev->subclass_id = p->getPciSubclassCode();
        dev->interface_id = p->getPciProgInterface();

        dev->rev_id = 0; /// \todo Implement into Device

        dev->irq = p->getInterruptNumber();

        dev->resources = cdi_list_create();
        for(size_t j = 0; j < p->addresses().count(); j++)
        {
            Device::Address *addr = p->addresses()[j];
            struct cdi_pci_resource *res = new struct cdi_pci_resource;
            if(addr->m_IsIoSpace)
                res->type = CDI_PCI_IOPORTS;
            else
                res->type = CDI_PCI_MEMORY;
            res->start = addr->m_Address;
            res->length = addr->m_Size;
            res->index = j;
            res->address = reinterpret_cast<void*>(res->start);

            cdi_list_push(dev->resources, res);
        }

        dev->meta.backdev = reinterpret_cast<void *>(p);

        cdi_list_push(devices, dev);

        if(p->getNumChildren())
            iterateDeviceTree(p);
    }
}

/**
 * Muss vor dem ersten Aufruf einer anderen CDI-Funktion aufgerufen werden.
 * Initialisiert interne Datenstruktur der Implementierung fuer das jeweilige
 * Betriebssystem.
 */
void cdi_init(void)
{
    drivers = cdi_list_create();
    devices = cdi_list_create();

    // Iterate the device tree and add cdi_bus_data structs to the device list
    // for each found device.
    Device *root = &Device::root();
    iterateDeviceTree(root);
}

void cdi_pedigree_walk_dev_list_init(struct cdi_driver *dev)
{
    struct cdi_driver* driver = dev;
    struct cdi_bus_data* device;
    int i;
    for (i = 0; (device = reinterpret_cast<struct cdi_bus_data*>(cdi_list_get(devices, i))); i++) {
        if (driver->init_device) {
            struct cdi_device *p = driver->init_device(device);
            if(p)
            {
                p->driver = driver;
            }
        }
    }
}

void cdi_pedigree_walk_dev_list_destroy(struct cdi_driver *dev)
{
    struct cdi_driver* driver = dev;
    struct cdi_device* device;
    int i;
    for (i = 0; (device = reinterpret_cast<struct cdi_device*>(cdi_list_get(devices, i))); i++) {
        if (driver->remove_device) {
            driver->remove_device(device);
        }
    }
}

/**
 * Wird bei der Deinitialisierung aufgerufen
 */
static void cdi_destroy(void)
{
    // Drivers are already destroyed by the module exit function
}

/**
 * Fuehrt alle registrierten Treiber aus. Nach dem Aufruf dieser Funktion
 * duerfen keine weiteren Befehle ausgefuehrt werden, da nicht definiert ist,
 * ob und wann die Funktion zurueckkehrt.
 */
void cdi_run_drivers(void)
{
    // Geraete initialisieren
    struct cdi_driver* driver;
    int i;
    for (i = 0; (driver = reinterpret_cast<struct cdi_driver*>(cdi_list_get(drivers, i))); i++) {
        cdi_pedigree_walk_dev_list_init(driver);
    }
}

/**
 * Initialisiert die Datenstrukturen fuer einen Treiber
 */
void cdi_driver_init(struct cdi_driver* driver)
{
    driver->devices = cdi_list_create();
}

/**
 * Deinitialisiert die Datenstrukturen fuer einen Treiber
 */
void cdi_driver_destroy(struct cdi_driver* driver)
{
    cdi_list_destroy(driver->devices);
}

/**
 * Registriert den Treiber fuer ein neues Geraet
 *
 * @param driver Zu registierender Treiber
 */
void cdi_driver_register(struct cdi_driver* driver)
{
    cdi_list_push(drivers, driver);
}

int cdi_provide_device(struct cdi_bus_data *device)
{
    // What type is the device?
    switch(device->bus_type)
    {
        case CDI_PCI:
            {
                // Grab the cdi_pci_device for this device
                struct cdi_pci_device *pci = reinterpret_cast<struct cdi_pci_device *>(device);

                // Create a new device object to add to the tree
                Device *pDevice = new Device();

                // PCI data
                pDevice->setPciPosition(pci->bus, pci->dev, pci->function);
                pDevice->setPciIdentifiers(pci->class_id, pci->subclass_id, pci->vendor_id, pci->device_id, pci->interface_id);
                pDevice->setInterruptNumber(pci->irq);

                // PCI BARs
                struct cdi_pci_resource *pResource = 0;
                for(int i = 0; (pResource = reinterpret_cast<struct cdi_pci_resource *>(cdi_list_get(pci->resources, i))); i++)
                {
                    TinyStaticString barName("BAR");
                    barName.append(i, 10);

                    Device::Address *pAddress = new Device::Address(String(barName), pResource->start, pResource->length, pResource->type == CDI_PCI_IOPORTS);

                    pDevice->addresses().pushBack(pAddress);
                }

                // Link into the tree
                pDevice->setParent(&Device::root());
                Device::root().addChild(pDevice);

                return 0;
            }
            break;

        default:
            WARNING("CDI: Unimplemented device type for cdi_provide_device(): " << device->bus_type);
            break;
    };

    return -1;
}

MODULE_INFO("cdi", &cdi_init, &cdi_destroy, "dma", "network-stack", "vfs");
<|endoftext|>


<commit_before>/*
 * transition_qtblend.cpp -- Qt composite transition
 * Copyright (c) 2016 Jean-Baptiste Mardelle <jb@kdenlive.org>
 *
 * 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 Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "common.h"
#include <framework/mlt.h>
#include <stdio.h>
#include <string.h>
#include <QImage>
#include <QPainter>
#include <QTransform>

static int get_image( mlt_frame a_frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
{
	int error = 0;
	mlt_frame b_frame = mlt_frame_pop_frame( a_frame );
	mlt_properties b_properties = MLT_FRAME_PROPERTIES( b_frame );
	mlt_properties properties = MLT_FRAME_PROPERTIES( a_frame );
	mlt_transition transition = MLT_TRANSITION( mlt_frame_pop_service( a_frame ) );
	mlt_properties transition_properties = MLT_TRANSITION_PROPERTIES( transition );

	uint8_t *b_image = NULL;
	bool hasAlpha = false;
	double opacity = 1.0;
	QTransform transform;
	// reference rect
	mlt_rect rect;

	// Determine length
	mlt_position length = mlt_transition_get_length( transition );
	// Get current position
	mlt_position position =  mlt_transition_get_position( transition, a_frame );

	// Obtain the normalised width and height from the a_frame
	mlt_profile profile = mlt_service_profile( MLT_TRANSITION_SERVICE( transition ) );
	int normalised_width = profile->width;
	int normalised_height = profile->height;
	double consumer_ar = mlt_profile_sar( profile );
	int b_width = mlt_properties_get_int( b_properties, "meta.media.width" );
	int b_height = mlt_properties_get_int( b_properties, "meta.media.height" );
	if ( b_height == 0 )
	{
		b_width = normalised_width;
		b_height = normalised_height;
	}
	double b_ar = mlt_frame_get_aspect_ratio( b_frame );
	double b_dar = b_ar * b_width / b_height;
	rect.w = -1;
	rect.h = -1;
	bool consumerScaling = false;

	// Check transform
	if ( mlt_properties_get( transition_properties, "rect" ) )
	{
		rect = mlt_properties_anim_get_rect( transition_properties, "rect", position, length );
		if (mlt_properties_get(transition_properties, "rect") && ::strchr(mlt_properties_get(transition_properties, "rect"), '%')) {
			rect.x *= normalised_width;
			rect.y *= normalised_height;
			rect.w *= normalised_width;
			rect.h *= normalised_height;
		}
		double scale = mlt_profile_scale_width(profile, *width);
		if ( scale != 1.0 ) {
			consumerScaling = true;
		}
		rect.x *= scale;
		rect.w *= scale;
		scale = mlt_profile_scale_height(profile, *height);
		if ( !consumerScaling && scale != 1.0 ) {
			consumerScaling = true;
		}
		rect.y *= scale;
		rect.h *= scale;
		transform.translate(rect.x, rect.y);
		opacity = rect.o;
	}

	double output_ar = mlt_profile_sar( profile );
	if ( mlt_frame_get_aspect_ratio( b_frame ) == 0 )
	{
		mlt_frame_set_aspect_ratio( b_frame, output_ar );
	}

	if ( mlt_properties_get( transition_properties, "rotation" ) )
	{
		double angle = mlt_properties_anim_get_double( transition_properties, "rotation", position, length );
		if (angle != 0.0) {
			if ( mlt_properties_get_int( transition_properties, "rotate_center" ) )
			{
				transform.translate( rect.w / 2.0, rect.h / 2.0 );
				transform.rotate( angle );
				transform.translate( -rect.w / 2.0, -rect.h / 2.0 );
			}
			else
			{
				transform.rotate( angle );
			}
			hasAlpha = true;
		}
	}

	// This is not a field-aware transform.
	mlt_properties_set_int( b_properties, "consumer_deinterlace", 1 );

	// Suppress padding and aspect normalization.
	char *interps = mlt_properties_get( properties, "rescale.interp" );
	if ( interps )
		interps = strdup( interps );

	if ( error )
	{
		return error;
	}

	// Adjust if consumer is scaling
	if ( consumerScaling )
	{
		// Scale request of b frame image to consumer scale maintaining its aspect ratio.
		b_height = *height;
		b_width = b_height * b_dar / b_ar;
	}

	if ( rect.w != -1 )
	{
		if ( mlt_properties_get_int( transition_properties, "distort" ) && b_width != 0 && b_height != 0 )
		{
			transform.scale( rect.w / b_width, rect.h / b_height );
		}
		else
		{
			// Determine scale with respect to aspect ratio.
			double geometry_dar = rect.w * consumer_ar / rect.h;
			double scale;
			if ( b_dar > geometry_dar )
			{
				scale = rect.w / b_width;
			}
			else
			{
				scale = rect.h / b_height * b_ar;
			}

			transform.translate((rect.w - (b_width * scale)) / 2.0, (rect.h - (b_height * scale)) / 2.0);
			transform.scale( scale, scale );
		}

		if ( opacity < 1 || rect.x > 0 || rect.y > 0 || (rect.x + rect.w < *width ) || (rect.y + rect.w < *height ) )
		{
			// we will process operations on top frame, so also process b_frame
			hasAlpha = true;
		}
	}
	else
	{
		// No transform, request profile sized image
		if (b_dar != mlt_profile_dar( profile ) )
		{
			// Activate transparency if the clips don't have the same aspect ratio
			hasAlpha = true;
		}
		// resize to consumer request
		b_width = *width;
		b_height = *height;
	}
	if ( !hasAlpha && ( mlt_properties_get_int( transition_properties, "compositing" ) != 0 || b_width < *width || b_height < *height ) )
	{
		hasAlpha = true;
	}

	// Check if we have transparency
	if ( !hasAlpha )
	{
		// fetch image
		error = mlt_frame_get_image( b_frame, &b_image, format, width, height, 1 );
		if ( *format == mlt_image_rgb24a || mlt_frame_get_alpha( b_frame ) )
		{
			hasAlpha = true;
		}
	}
	if ( !hasAlpha )
	{
		// Prepare output image
		*image = b_image;
		mlt_frame_replace_image( a_frame, b_image, *format, *width, *height );
		free( interps );
		return 0;
	}
	// Get RGBA image to process
	*format = mlt_image_rgb24a;
	error = mlt_frame_get_image( b_frame, &b_image, format, &b_width, &b_height, writable );

	// Get bottom frame
	uint8_t *a_image = NULL;
	error = mlt_frame_get_image( a_frame, &a_image, format, width, height, 1 );
	if (error)
	{
		free( interps );
		return error;
	}
	// Prepare output image
	int image_size = mlt_image_format_size( *format, *width, *height, NULL );
	*image = (uint8_t *) mlt_pool_alloc( image_size );

	// Copy bottom frame in output
	memcpy( *image, a_image, image_size );

	bool hqPainting = false;
	if ( interps )
	{
		if ( strcmp( interps, "bilinear" ) == 0 || strcmp( interps, "bicubic" ) == 0 )
		{
			hqPainting = true;
		}
	}

	// convert bottom mlt image to qimage
	QImage bottomImg;
	convert_mlt_to_qimage_rgba( *image, &bottomImg, *width, *height );

	// convert top mlt image to qimage
	QImage topImg;
	convert_mlt_to_qimage_rgba( b_image, &topImg, b_width, b_height );

	// setup Qt drawing
	QPainter painter( &bottomImg );
	painter.setCompositionMode( ( QPainter::CompositionMode ) mlt_properties_get_int( transition_properties, "compositing" ) );
	painter.setRenderHints( QPainter::Antialiasing | QPainter::SmoothPixmapTransform, hqPainting );
	painter.setTransform(transform);
	painter.setOpacity(opacity);

	// Composite top frame
	painter.drawImage(0, 0, topImg);

	// finish Qt drawing
	painter.end();
	convert_qimage_to_mlt_rgba( &bottomImg, *image, *width, *height );
	mlt_frame_set_image( a_frame, *image, image_size, mlt_pool_release);
	free( interps );
	return error;
}

static mlt_frame process( mlt_transition transition, mlt_frame a_frame, mlt_frame b_frame )
{
	mlt_frame_push_service( a_frame, transition );
	mlt_frame_push_frame( a_frame, b_frame );
	mlt_frame_push_get_image( a_frame, get_image );
	return a_frame;
}

extern "C" {

mlt_transition transition_qtblend_init( mlt_profile profile, mlt_service_type type, const char *id, void *arg )
{
	mlt_transition transition = mlt_transition_new();

	if ( transition )
	{
		mlt_properties properties = MLT_TRANSITION_PROPERTIES( transition );

		if ( !createQApplicationIfNeeded( MLT_TRANSITION_SERVICE(transition) ) )
		{
			mlt_transition_close( transition );
			return NULL;
		}
		transition->process = process;
		mlt_properties_set_int( properties, "_transition_type", 1 ); // video only
		mlt_properties_set( properties, "rect", (char *) arg );
		mlt_properties_set_int( properties, "compositing", 0 );
		mlt_properties_set_int( properties, "distort", 0 );
		mlt_properties_set_int( properties, "rotate_center", 0 );
	}

	return transition;
}

} // extern "C"
<commit_msg>qtblend transition speedup: request original source format instead of consumer format first to avoid unnecessary yuv->rgba conversions<commit_after>/*
 * transition_qtblend.cpp -- Qt composite transition
 * Copyright (c) 2016 Jean-Baptiste Mardelle <jb@kdenlive.org>
 *
 * 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 Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "common.h"
#include <framework/mlt.h>
#include <stdio.h>
#include <string.h>
#include <QImage>
#include <QPainter>
#include <QTransform>

static int get_image( mlt_frame a_frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
{
	int error = 0;
	mlt_frame b_frame = mlt_frame_pop_frame( a_frame );
	mlt_properties b_properties = MLT_FRAME_PROPERTIES( b_frame );
	mlt_properties properties = MLT_FRAME_PROPERTIES( a_frame );
	mlt_transition transition = MLT_TRANSITION( mlt_frame_pop_service( a_frame ) );
	mlt_properties transition_properties = MLT_TRANSITION_PROPERTIES( transition );

	uint8_t *b_image = NULL;
	bool hasAlpha = false;
	double opacity = 1.0;
	QTransform transform;
	// reference rect
	mlt_rect rect;

	// Determine length
	mlt_position length = mlt_transition_get_length( transition );
	// Get current position
	mlt_position position =  mlt_transition_get_position( transition, a_frame );

	// Obtain the normalised width and height from the a_frame
	mlt_profile profile = mlt_service_profile( MLT_TRANSITION_SERVICE( transition ) );
	int normalised_width = profile->width;
	int normalised_height = profile->height;
	double consumer_ar = mlt_profile_sar( profile );
	int b_width = mlt_properties_get_int( b_properties, "meta.media.width" );
	int b_height = mlt_properties_get_int( b_properties, "meta.media.height" );
	if ( b_height == 0 )
	{
		b_width = normalised_width;
		b_height = normalised_height;
	}
	double b_ar = mlt_frame_get_aspect_ratio( b_frame );
	double b_dar = b_ar * b_width / b_height;
	rect.w = -1;
	rect.h = -1;
	bool consumerScaling = false;

	// Check transform
	if ( mlt_properties_get( transition_properties, "rect" ) )
	{
		rect = mlt_properties_anim_get_rect( transition_properties, "rect", position, length );
		if (mlt_properties_get(transition_properties, "rect") && ::strchr(mlt_properties_get(transition_properties, "rect"), '%')) {
			rect.x *= normalised_width;
			rect.y *= normalised_height;
			rect.w *= normalised_width;
			rect.h *= normalised_height;
		}
		double scale = mlt_profile_scale_width(profile, *width);
		if ( scale != 1.0 ) {
			consumerScaling = true;
		}
		rect.x *= scale;
		rect.w *= scale;
		scale = mlt_profile_scale_height(profile, *height);
		if ( !consumerScaling && scale != 1.0 ) {
			consumerScaling = true;
		}
		rect.y *= scale;
		rect.h *= scale;
		transform.translate(rect.x, rect.y);
		opacity = rect.o;
	}

	double output_ar = mlt_profile_sar( profile );
	if ( mlt_frame_get_aspect_ratio( b_frame ) == 0 )
	{
		mlt_frame_set_aspect_ratio( b_frame, output_ar );
	}

	if ( mlt_properties_get( transition_properties, "rotation" ) )
	{
		double angle = mlt_properties_anim_get_double( transition_properties, "rotation", position, length );
		if (angle != 0.0) {
			if ( mlt_properties_get_int( transition_properties, "rotate_center" ) )
			{
				transform.translate( rect.w / 2.0, rect.h / 2.0 );
				transform.rotate( angle );
				transform.translate( -rect.w / 2.0, -rect.h / 2.0 );
			}
			else
			{
				transform.rotate( angle );
			}
			hasAlpha = true;
		}
	}

	// This is not a field-aware transform.
	mlt_properties_set_int( b_properties, "consumer_deinterlace", 1 );

	// Suppress padding and aspect normalization.
	char *interps = mlt_properties_get( properties, "rescale.interp" );
	if ( interps )
		interps = strdup( interps );

	if ( error )
	{
		return error;
	}

	// Adjust if consumer is scaling
	if ( consumerScaling )
	{
		// Scale request of b frame image to consumer scale maintaining its aspect ratio.
		b_height = *height;
		b_width = b_height * b_dar / b_ar;
	}

	if ( rect.w != -1 )
	{
		if ( mlt_properties_get_int( transition_properties, "distort" ) && b_width != 0 && b_height != 0 )
		{
			transform.scale( rect.w / b_width, rect.h / b_height );
		}
		else
		{
			// Determine scale with respect to aspect ratio.
			double geometry_dar = rect.w * consumer_ar / rect.h;
			double scale;
			if ( b_dar > geometry_dar )
			{
				scale = rect.w / b_width;
			}
			else
			{
				scale = rect.h / b_height * b_ar;
			}

			transform.translate((rect.w - (b_width * scale)) / 2.0, (rect.h - (b_height * scale)) / 2.0);
			transform.scale( scale, scale );
		}

		if ( opacity < 1 || rect.x > 0 || rect.y > 0 || (rect.x + rect.w < *width ) || (rect.y + rect.w < *height ) )
		{
			// we will process operations on top frame, so also process b_frame
			hasAlpha = true;
		}
	}
	else
	{
		// No transform, request profile sized image
		if (b_dar != mlt_profile_dar( profile ) )
		{
			// Activate transparency if the clips don't have the same aspect ratio
			hasAlpha = true;
		}
		// resize to consumer request
		b_width = *width;
		b_height = *height;
	}
	if ( !hasAlpha && ( mlt_properties_get_int( transition_properties, "compositing" ) != 0 || b_width < *width || b_height < *height ) )
	{
		hasAlpha = true;
	}

	// Check if we have transparency
	if ( !hasAlpha )
	{
		// fetch image
		mlt_image_format fmt = mlt_image_none;
		error = mlt_frame_get_image( b_frame, &b_image, &fmt, width, height, 1 );
		*format = fmt;
		if ( *format == mlt_image_rgb24a || mlt_frame_get_alpha( b_frame ) )
		{
			hasAlpha = true;
		}
	}
	if ( !hasAlpha )
	{
		// Prepare output image
		*image = b_image;
		mlt_frame_replace_image( a_frame, b_image, *format, *width, *height );
		free( interps );
		return 0;
	}
	// Get RGBA image to process
	*format = mlt_image_rgb24a;
	error = mlt_frame_get_image( b_frame, &b_image, format, &b_width, &b_height, writable );

	// Get bottom frame
	uint8_t *a_image = NULL;
	error = mlt_frame_get_image( a_frame, &a_image, format, width, height, 1 );
	if (error)
	{
		free( interps );
		return error;
	}
	// Prepare output image
	int image_size = mlt_image_format_size( *format, *width, *height, NULL );
	*image = (uint8_t *) mlt_pool_alloc( image_size );

	// Copy bottom frame in output
	memcpy( *image, a_image, image_size );

	bool hqPainting = false;
	if ( interps )
	{
		if ( strcmp( interps, "bilinear" ) == 0 || strcmp( interps, "bicubic" ) == 0 )
		{
			hqPainting = true;
		}
	}

	// convert bottom mlt image to qimage
	QImage bottomImg;
	convert_mlt_to_qimage_rgba( *image, &bottomImg, *width, *height );

	// convert top mlt image to qimage
	QImage topImg;
	convert_mlt_to_qimage_rgba( b_image, &topImg, b_width, b_height );

	// setup Qt drawing
	QPainter painter( &bottomImg );
	painter.setCompositionMode( ( QPainter::CompositionMode ) mlt_properties_get_int( transition_properties, "compositing" ) );
	painter.setRenderHints( QPainter::Antialiasing | QPainter::SmoothPixmapTransform, hqPainting );
	painter.setTransform(transform);
	painter.setOpacity(opacity);

	// Composite top frame
	painter.drawImage(0, 0, topImg);

	// finish Qt drawing
	painter.end();
	convert_qimage_to_mlt_rgba( &bottomImg, *image, *width, *height );
	mlt_frame_set_image( a_frame, *image, image_size, mlt_pool_release);
	free( interps );
	return error;
}

static mlt_frame process( mlt_transition transition, mlt_frame a_frame, mlt_frame b_frame )
{
	mlt_frame_push_service( a_frame, transition );
	mlt_frame_push_frame( a_frame, b_frame );
	mlt_frame_push_get_image( a_frame, get_image );
	return a_frame;
}

extern "C" {

mlt_transition transition_qtblend_init( mlt_profile profile, mlt_service_type type, const char *id, void *arg )
{
	mlt_transition transition = mlt_transition_new();

	if ( transition )
	{
		mlt_properties properties = MLT_TRANSITION_PROPERTIES( transition );

		if ( !createQApplicationIfNeeded( MLT_TRANSITION_SERVICE(transition) ) )
		{
			mlt_transition_close( transition );
			return NULL;
		}
		transition->process = process;
		mlt_properties_set_int( properties, "_transition_type", 1 ); // video only
		mlt_properties_set( properties, "rect", (char *) arg );
		mlt_properties_set_int( properties, "compositing", 0 );
		mlt_properties_set_int( properties, "distort", 0 );
		mlt_properties_set_int( properties, "rotate_center", 0 );
	}

	return transition;
}

} // extern "C"
<|endoftext|>


<commit_before>// Copyright (c) 2015, Baidu.com, Inc. All Rights Reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Author: yanshiguang02@baidu.com

#define private public
#include "nameserver/namespace.h"

#include "common/util.h"
#include <fcntl.h>

#include <gflags/gflags.h>
#include <gtest/gtest.h>

DECLARE_string(namedb_path);

namespace baidu {
namespace bfs {

class NameSpaceTest : public ::testing::Test {
public:
    NameSpaceTest() {}
protected:
};

TEST_F(NameSpaceTest, EncodingStoreKey) {
    std::string key_start;
    NameSpace::EncodingStoreKey(5, "", &key_start);
    ASSERT_EQ(key_start.size(), 8);
    for (int i = 0; i < 7; i++) {
        ASSERT_EQ(key_start[i], 0);
    }
    ASSERT_EQ(key_start[7], '\5');

    NameSpace::EncodingStoreKey(3<<16, "/home", &key_start);
    ASSERT_EQ(key_start.size(), 13);
    ASSERT_EQ(key_start[5], 3);
    ASSERT_EQ(key_start.substr(8), std::string("/home"));
}

TEST_F(NameSpaceTest, SplitPath) {
    std::vector<std::string> element;
    ASSERT_TRUE(common::util::SplitPath("/home", &element));
    ASSERT_EQ(1U, element.size());
    ASSERT_EQ(element[0], std::string("home"));
    ASSERT_TRUE(common::util::SplitPath("/dir1/subdir1/file3", &element));
    ASSERT_EQ(3U, element.size());
    ASSERT_EQ(element[0], std::string("dir1"));
    ASSERT_EQ(element[1], std::string("subdir1"));
    ASSERT_EQ(element[2], std::string("file3"));
    ASSERT_TRUE(common::util::SplitPath("/", &element));
    ASSERT_EQ(0U, element.size());
    ASSERT_FALSE(common::util::SplitPath("", &element));

}

bool CreateTree(NameSpace* ns) {
    int ret = ns->CreateFile("/file1", 0, 0);
    ret |= ns->CreateFile("/file2", 0, 0);
    ret |= ns->CreateFile("/dir1/subdir1/file3", 0, 0);
    ret |= ns->CreateFile("/dir1/subdir1/file4", 0, 0);
    ret |= ns->CreateFile("/dir1/subdir2/file5", 0, 0);
    return ret == 0;
}

TEST_F(NameSpaceTest, NameSpace) {
    std::string version;
    {
        FLAGS_namedb_path = "./db";
        system("rm -rf ./db");
        NameSpace init_ns;
        leveldb::Iterator* it = init_ns._db->NewIterator(leveldb::ReadOptions());
        it->SeekToFirst();
        ASSERT_TRUE(it->Valid());
        ASSERT_EQ(it->key().ToString(), std::string(8, 0) + "version");
        version = it->value().ToString();
        delete it;
    }

    // Load  namespace with old version
    NameSpace ns;
    CreateTree(&ns);
    leveldb::Iterator* it = ns._db->NewIterator(leveldb::ReadOptions());
    it->SeekToFirst();
    ASSERT_EQ(version, it->value().ToString());

    // Iterate namespace
    it->Seek(std::string(7, 0) + '\1');
    ASSERT_TRUE(it->Valid());
    std::string entry1(it->key().data(), it->key().size());
    ASSERT_EQ(entry1.substr(8), std::string("dir1"));

    // next entry
    it->Next();
    // key
    std::string entry2(it->key().data(), it->key().size());
    ASSERT_EQ(entry2.substr(8), std::string("file1"));
    ASSERT_EQ(entry2[0], 0);
    ASSERT_EQ(*reinterpret_cast<int*>(&entry2[1]), 0);
    ASSERT_EQ(entry2[7], 1);
    // value
    FileInfo info;
    ASSERT_TRUE(info.ParseFromArray(it->value().data(), it->value().size()));
    ASSERT_EQ(2, info.entry_id());

    delete it;
}

TEST_F(NameSpaceTest, CreateFile) {
    FLAGS_namedb_path = "./db";
    system("rm -rf ./db");
    NameSpace ns;
    ASSERT_EQ(0, ns.CreateFile("/file1", 0, 0));
    ASSERT_NE(0, ns.CreateFile("/file1", 0, 0));
    ASSERT_EQ(0, ns.CreateFile("/dir1/subdir1/file1", 0, 0));
    ASSERT_EQ(0, ns.CreateFile("/dir1/subdir1/file1", O_TRUNC, 0));
    ASSERT_EQ(0, ns.CreateFile("/dir1/subdir2/file1", 0, 0));
}

TEST_F(NameSpaceTest, List) {
    FLAGS_namedb_path = "./db";
    system("rm -rf ./db");
    NameSpace ns;
    ASSERT_TRUE(CreateTree(&ns));
    google::protobuf::RepeatedPtrField<FileInfo> outputs;
    ASSERT_EQ(0, ns.ListDirectory("/dir1", &outputs));
    ASSERT_EQ(2U, outputs.size());
    ASSERT_EQ(std::string("subdir1"), outputs.Get(0).name());
    ASSERT_EQ(std::string("subdir2"), outputs.Get(1).name());
}

TEST_F(NameSpaceTest, Rename) {
    NameSpace ns;
    bool need_unlink;
    FileInfo remove_file;
    /// dir -> none
    ASSERT_EQ(0, ns.Rename("/dir1/subdir1", "/dir1/subdir3", &need_unlink, &remove_file));
    ASSERT_FALSE(need_unlink);
    /// dir -> existing dir
    ASSERT_NE(0, ns.Rename("/dir1/subdir2", "/dir1/subdir3", &need_unlink, &remove_file));
    ASSERT_FALSE(need_unlink);
    /// file -> not exist parent
    ASSERT_NE(0, ns.Rename("/file1", "/dir1/subdir4/file1", &need_unlink, &remove_file));
    /// file -> existing dir
    ASSERT_NE(0, ns.Rename("/file1", "/dir1/subdir3", &need_unlink, &remove_file));
    ASSERT_FALSE(need_unlink);
    /// file -> none
    ASSERT_EQ(0, ns.Rename("/file1", "/dir1/subdir3/file1", &need_unlink, &remove_file));
    ASSERT_FALSE(need_unlink);
    /// noe -> none
    ASSERT_NE(0, ns.Rename("/file1", "/dir1/subdir3/file2", &need_unlink, &remove_file));
    ASSERT_FALSE(need_unlink);
    /// file -> existing file
    ASSERT_EQ(0, ns.Rename("/dir1/subdir2/file5", "/dir1/subdir3/file1", &need_unlink, &remove_file));
    ASSERT_TRUE(need_unlink);
    ASSERT_EQ(remove_file.entry_id(), 2);

    /// Root dir to root dir
    ASSERT_NE(0, ns.Rename("/", "/dir2", &need_unlink, &remove_file));
    ASSERT_EQ(0, ns.Rename("/dir1", "/dir2", &need_unlink, &remove_file));

    /// Deep rename
    ASSERT_EQ(0, ns.CreateFile("/tera/meta/0/00000001.dbtmp", 0, 0));
    ASSERT_EQ(0, ns.Rename("/tera/meta/0/00000001.dbtmp", "/tera/meta/0/CURRENT", &need_unlink, &remove_file));
    ASSERT_FALSE(need_unlink);
    ASSERT_TRUE(ns.LookUp("/tera/meta/0/CURRENT", &remove_file));
}

TEST_F(NameSpaceTest, RemoveFile) {
    FLAGS_namedb_path = "./db";
    system("rm -rf ./db");
    NameSpace ns;
    ASSERT_TRUE(CreateTree(&ns));
    FileInfo file_removed;
    ASSERT_EQ(0, ns.RemoveFile("/file2",&file_removed));
    ASSERT_EQ(3, file_removed.entry_id());
    ASSERT_NE(0, ns.RemoveFile("/",&file_removed));
    ASSERT_EQ(0, ns.RemoveFile("/file1",&file_removed));
    ASSERT_EQ(2, file_removed.entry_id());
    ASSERT_NE(0, ns.RemoveFile("/file2",&file_removed));
    ASSERT_NE(0, ns.RemoveFile("/file3",&file_removed));
}

TEST_F(NameSpaceTest, DeleteDirectory) {
    FLAGS_namedb_path = "./db";
    system("rm -rf ./db");
    NameSpace ns;
    ASSERT_TRUE(CreateTree(&ns));
    std::vector<FileInfo> files_removed;

    // Delete not empty
    ASSERT_NE(0, ns.DeleteDirectory("/dir1", false, &files_removed));
    ASSERT_NE(0, ns.DeleteDirectory("/dir1/subdir2", false, &files_removed));
    // Delete root dir
    ASSERT_NE(0, ns.DeleteDirectory("/", false, &files_removed));
    // Delete subdir
    ASSERT_EQ(0, ns.DeleteDirectory("/dir1/subdir2", true, &files_removed));
    ASSERT_EQ(files_removed.size(), 1U);
    ASSERT_EQ(files_removed[0].entry_id(), 9);
    // List after delete
    google::protobuf::RepeatedPtrField<FileInfo> outputs;
    ASSERT_EQ(0, ns.ListDirectory("/dir1", &outputs));
    ASSERT_EQ(1U, outputs.size());
    ASSERT_EQ(std::string("subdir1"), outputs.Get(0).name());

    // Delete another subdir
    printf("Delete another subdir\n");
    ASSERT_NE(0, ns.DeleteDirectory("/dir1/subdir1", false, &files_removed));
    ASSERT_EQ(0, ns.ListDirectory("/dir1/subdir1", &outputs));
    ASSERT_EQ(2U, outputs.size());

    ASSERT_EQ(0, ns.DeleteDirectory("/dir1", true, &files_removed));
    ASSERT_EQ(files_removed.size(), 2U);
    ASSERT_EQ(files_removed[0].entry_id(), 6);
    ASSERT_EQ(files_removed[1].entry_id(), 7);
    ASSERT_NE(0, ns.ListDirectory("/dir1/subdir1", &outputs));
    ASSERT_NE(0, ns.ListDirectory("/dir1", &outputs));

    // Use rmr to delete a file
    ASSERT_EQ(886, ns.DeleteDirectory("/file1", true, &files_removed));
}
}
}

int main(int argc, char** argv) {
    ::testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}

/* vim: set expandtab ts=4 sw=4 sts=4 tw=100: */
<commit_msg>Update namespace_test.cc<commit_after>// Copyright (c) 2015, Baidu.com, Inc. All Rights Reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Author: yanshiguang02@baidu.com

#define private public
#include "nameserver/namespace.h"

#include "common/util.h"
#include <fcntl.h>

#include <gflags/gflags.h>
#include <gtest/gtest.h>

DECLARE_string(namedb_path);

namespace baidu {
namespace bfs {

class NameSpaceTest : public ::testing::Test {
public:
    NameSpaceTest() {}
protected:
};

TEST_F(NameSpaceTest, EncodingStoreKey) {
    std::string key_start;
    NameSpace::EncodingStoreKey(5, "", &key_start);
    ASSERT_EQ(key_start.size(), 8U);
    for (int i = 0; i < 7; i++) {
        ASSERT_EQ(key_start[i], 0);
    }
    ASSERT_EQ(key_start[7], '\5');

    NameSpace::EncodingStoreKey(3<<16, "/home", &key_start);
    ASSERT_EQ(key_start.size(), 13U);
    ASSERT_EQ(key_start[5], 3);
    ASSERT_EQ(key_start.substr(8), std::string("/home"));
}

TEST_F(NameSpaceTest, SplitPath) {
    std::vector<std::string> element;
    ASSERT_TRUE(common::util::SplitPath("/home", &element));
    ASSERT_EQ(1U, element.size());
    ASSERT_EQ(element[0], std::string("home"));
    ASSERT_TRUE(common::util::SplitPath("/dir1/subdir1/file3", &element));
    ASSERT_EQ(3U, element.size());
    ASSERT_EQ(element[0], std::string("dir1"));
    ASSERT_EQ(element[1], std::string("subdir1"));
    ASSERT_EQ(element[2], std::string("file3"));
    ASSERT_TRUE(common::util::SplitPath("/", &element));
    ASSERT_EQ(0U, element.size());
    ASSERT_FALSE(common::util::SplitPath("", &element));

}

bool CreateTree(NameSpace* ns) {
    int ret = ns->CreateFile("/file1", 0, 0);
    ret |= ns->CreateFile("/file2", 0, 0);
    ret |= ns->CreateFile("/dir1/subdir1/file3", 0, 0);
    ret |= ns->CreateFile("/dir1/subdir1/file4", 0, 0);
    ret |= ns->CreateFile("/dir1/subdir2/file5", 0, 0);
    return ret == 0;
}

TEST_F(NameSpaceTest, NameSpace) {
    std::string version;
    {
        FLAGS_namedb_path = "./db";
        system("rm -rf ./db");
        NameSpace init_ns;
        leveldb::Iterator* it = init_ns._db->NewIterator(leveldb::ReadOptions());
        it->SeekToFirst();
        ASSERT_TRUE(it->Valid());
        ASSERT_EQ(it->key().ToString(), std::string(8, 0) + "version");
        version = it->value().ToString();
        delete it;
    }

    // Load  namespace with old version
    NameSpace ns;
    CreateTree(&ns);
    leveldb::Iterator* it = ns._db->NewIterator(leveldb::ReadOptions());
    it->SeekToFirst();
    ASSERT_EQ(version, it->value().ToString());

    // Iterate namespace
    it->Seek(std::string(7, 0) + '\1');
    ASSERT_TRUE(it->Valid());
    std::string entry1(it->key().data(), it->key().size());
    ASSERT_EQ(entry1.substr(8), std::string("dir1"));

    // next entry
    it->Next();
    // key
    std::string entry2(it->key().data(), it->key().size());
    ASSERT_EQ(entry2.substr(8), std::string("file1"));
    ASSERT_EQ(entry2[0], 0);
    ASSERT_EQ(*reinterpret_cast<int*>(&entry2[1]), 0);
    ASSERT_EQ(entry2[7], 1);
    // value
    FileInfo info;
    ASSERT_TRUE(info.ParseFromArray(it->value().data(), it->value().size()));
    ASSERT_EQ(2, info.entry_id());

    delete it;
}

TEST_F(NameSpaceTest, CreateFile) {
    FLAGS_namedb_path = "./db";
    system("rm -rf ./db");
    NameSpace ns;
    ASSERT_EQ(0, ns.CreateFile("/file1", 0, 0));
    ASSERT_NE(0, ns.CreateFile("/file1", 0, 0));
    ASSERT_EQ(0, ns.CreateFile("/dir1/subdir1/file1", 0, 0));
    ASSERT_EQ(0, ns.CreateFile("/dir1/subdir1/file1", O_TRUNC, 0));
    ASSERT_EQ(0, ns.CreateFile("/dir1/subdir2/file1", 0, 0));
}

TEST_F(NameSpaceTest, List) {
    FLAGS_namedb_path = "./db";
    system("rm -rf ./db");
    NameSpace ns;
    ASSERT_TRUE(CreateTree(&ns));
    google::protobuf::RepeatedPtrField<FileInfo> outputs;
    ASSERT_EQ(0, ns.ListDirectory("/dir1", &outputs));
    ASSERT_EQ(2, outputs.size());
    ASSERT_EQ(std::string("subdir1"), outputs.Get(0).name());
    ASSERT_EQ(std::string("subdir2"), outputs.Get(1).name());
}

TEST_F(NameSpaceTest, Rename) {
    NameSpace ns;
    bool need_unlink;
    FileInfo remove_file;
    /// dir -> none
    ASSERT_EQ(0, ns.Rename("/dir1/subdir1", "/dir1/subdir3", &need_unlink, &remove_file));
    ASSERT_FALSE(need_unlink);
    /// dir -> existing dir
    ASSERT_NE(0, ns.Rename("/dir1/subdir2", "/dir1/subdir3", &need_unlink, &remove_file));
    ASSERT_FALSE(need_unlink);
    /// file -> not exist parent
    ASSERT_NE(0, ns.Rename("/file1", "/dir1/subdir4/file1", &need_unlink, &remove_file));
    /// file -> existing dir
    ASSERT_NE(0, ns.Rename("/file1", "/dir1/subdir3", &need_unlink, &remove_file));
    ASSERT_FALSE(need_unlink);
    /// file -> none
    ASSERT_EQ(0, ns.Rename("/file1", "/dir1/subdir3/file1", &need_unlink, &remove_file));
    ASSERT_FALSE(need_unlink);
    /// noe -> none
    ASSERT_NE(0, ns.Rename("/file1", "/dir1/subdir3/file2", &need_unlink, &remove_file));
    ASSERT_FALSE(need_unlink);
    /// file -> existing file
    ASSERT_EQ(0, ns.Rename("/dir1/subdir2/file5", "/dir1/subdir3/file1", &need_unlink, &remove_file));
    ASSERT_TRUE(need_unlink);
    ASSERT_EQ(remove_file.entry_id(), 2);

    /// Root dir to root dir
    ASSERT_NE(0, ns.Rename("/", "/dir2", &need_unlink, &remove_file));
    ASSERT_EQ(0, ns.Rename("/dir1", "/dir2", &need_unlink, &remove_file));

    /// Deep rename
    ASSERT_EQ(0, ns.CreateFile("/tera/meta/0/00000001.dbtmp", 0, 0));
    ASSERT_EQ(0, ns.Rename("/tera/meta/0/00000001.dbtmp", "/tera/meta/0/CURRENT", &need_unlink, &remove_file));
    ASSERT_FALSE(need_unlink);
    ASSERT_TRUE(ns.LookUp("/tera/meta/0/CURRENT", &remove_file));
}

TEST_F(NameSpaceTest, RemoveFile) {
    FLAGS_namedb_path = "./db";
    system("rm -rf ./db");
    NameSpace ns;
    ASSERT_TRUE(CreateTree(&ns));
    FileInfo file_removed;
    ASSERT_EQ(0, ns.RemoveFile("/file2",&file_removed));
    ASSERT_EQ(3, file_removed.entry_id());
    ASSERT_NE(0, ns.RemoveFile("/",&file_removed));
    ASSERT_EQ(0, ns.RemoveFile("/file1",&file_removed));
    ASSERT_EQ(2, file_removed.entry_id());
    ASSERT_NE(0, ns.RemoveFile("/file2",&file_removed));
    ASSERT_NE(0, ns.RemoveFile("/file3",&file_removed));
}

TEST_F(NameSpaceTest, DeleteDirectory) {
    FLAGS_namedb_path = "./db";
    system("rm -rf ./db");
    NameSpace ns;
    ASSERT_TRUE(CreateTree(&ns));
    std::vector<FileInfo> files_removed;

    // Delete not empty
    ASSERT_NE(0, ns.DeleteDirectory("/dir1", false, &files_removed));
    ASSERT_NE(0, ns.DeleteDirectory("/dir1/subdir2", false, &files_removed));
    // Delete root dir
    ASSERT_NE(0, ns.DeleteDirectory("/", false, &files_removed));
    // Delete subdir
    ASSERT_EQ(0, ns.DeleteDirectory("/dir1/subdir2", true, &files_removed));
    ASSERT_EQ(files_removed.size(), 1U);
    ASSERT_EQ(files_removed[0].entry_id(), 9);
    // List after delete
    google::protobuf::RepeatedPtrField<FileInfo> outputs;
    ASSERT_EQ(0, ns.ListDirectory("/dir1", &outputs));
    ASSERT_EQ(1, outputs.size());
    ASSERT_EQ(std::string("subdir1"), outputs.Get(0).name());

    // Delete another subdir
    printf("Delete another subdir\n");
    ASSERT_NE(0, ns.DeleteDirectory("/dir1/subdir1", false, &files_removed));
    ASSERT_EQ(0, ns.ListDirectory("/dir1/subdir1", &outputs));
    ASSERT_EQ(2, outputs.size());

    ASSERT_EQ(0, ns.DeleteDirectory("/dir1", true, &files_removed));
    ASSERT_EQ(files_removed.size(), 2U);
    ASSERT_EQ(files_removed[0].entry_id(), 6);
    ASSERT_EQ(files_removed[1].entry_id(), 7);
    ASSERT_NE(0, ns.ListDirectory("/dir1/subdir1", &outputs));
    ASSERT_NE(0, ns.ListDirectory("/dir1", &outputs));

    // Use rmr to delete a file
    ASSERT_EQ(886, ns.DeleteDirectory("/file1", true, &files_removed));
}
}
}

int main(int argc, char** argv) {
    ::testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}

/* vim: set expandtab ts=4 sw=4 sts=4 tw=100: */
<|endoftext|>