<commit_before>#include "Binary.hpp"

#include <stdexcept>
#include <algorithm>

#include "constants.hpp"
#include "Tree.hpp"

int safe_fclose(FILE* fptr) { return fptr ? fclose(fptr) : 0; }

Binary::Binary(Binary && other)
  : bin_fptr_(nullptr, safe_fclose)
{
  bin_fptr_ = std::move(other.bin_fptr_);
  map_ = std::move(other.map_);
}

Binary& Binary::operator=(Binary && other)
{
  bin_fptr_ = std::move(other.bin_fptr_);
  map_ = std::move(other.map_);
  return *this;
}

Binary::Binary(const std::string& binary_file_path)
  : bin_fptr_(nullptr, safe_fclose)
{
  // open the binary file
  pll_binary_header_t header;
  bin_fptr_ = file_ptr_type(pllmod_binary_open(binary_file_path.c_str(), &header), safe_fclose);

  if (!bin_fptr_) {
    throw std::runtime_error{"Could not open binary file for reading."};
  }

  if (header.access_type != PLLMOD_BIN_ACCESS_RANDOM) {
    throw std::runtime_error{"Binary file must be random access enabled."};
  }

  if (header.n_blocks <= 0) {
    throw std::runtime_error{std::string("Binary file header must have nonzero positive number of blocks: ")
              + std::to_string(header.n_blocks)};
  }

  // proccess the random access map
  unsigned int n_blocks;
  pll_block_map_t* block_map;
  block_map = pllmod_binary_get_map(bin_fptr_.get(), &n_blocks);

  assert(block_map);
  assert(n_blocks);

  for (size_t i = 0; i < n_blocks; i++) {
    map_.push_back(block_map[i]);
  }

  free(block_map);
}

static long int get_offset(std::vector<pll_block_map_t>& map, const int block_id)
{
  auto item = map.begin();
  while (item != map.end()) {
    if (item->block_id == block_id) {
      break;
    }
    item++;
  }

  if(item == map.end()) {
    throw std::runtime_error{std::string("Map does not contain block_id: ") + std::to_string(block_id)};
  }
  return item->block_offset;
}

void Binary::load_clv(pll_partition_t * partition,
                      const unsigned int clv_index)
{
  std::lock_guard<std::mutex> lock(file_mutex_);
  assert(bin_fptr_);
  assert(clv_index < partition->clv_buffers + partition->tips);
  if (partition->attributes & PLL_ATTRIB_PATTERN_TIP) {
    assert(clv_index >= partition->tips);
  }

  if (!(partition->clv[clv_index])) {
    const size_t clv_size = pll_get_clv_size(partition, clv_index) * sizeof(double);

    partition->clv[clv_index] = static_cast<double*>(pll_aligned_alloc(clv_size, partition->alignment));
    if (!partition->clv[clv_index]) {
      throw std::runtime_error{"Could not allocate CLV memory"};
    }
  }

  unsigned int attributes;
  auto err = pllmod_binary_clv_load(bin_fptr_.get(),
                                    0,
                                    partition,
                                    clv_index,
                                    &attributes,
                                    get_offset(map_, clv_index));

  if (err != PLL_SUCCESS) {
    throw std::runtime_error{std::string("Loading CLV failed: ")
                            + pll_errmsg
                            + std::string(". CLV index: ")
                            + std::to_string(clv_index)};
  }

}

void Binary::load_tipchars(pll_partition_t * partition, const unsigned int tipchars_index)
{
  std::lock_guard<std::mutex> lock(file_mutex_);
  assert(bin_fptr_);
  assert(tipchars_index < partition->tips);
  assert(partition->attributes & PLL_ATTRIB_PATTERN_TIP);

  unsigned int type, attributes;
  size_t size;

  auto ptr = pllmod_binary_custom_load(bin_fptr_.get(), 0, &size, &type, &attributes, get_offset(map_, tipchars_index));
  if (!ptr) {
    throw std::runtime_error{std::string("Loading tipchar failed: ") + pll_errmsg};
  }

  partition->tipchars[tipchars_index] = static_cast<unsigned char*>(ptr);
}

void Binary::load_scaler( pll_partition_t * partition,
                          const unsigned int scaler_index)
{
  std::lock_guard<std::mutex> lock(file_mutex_);
  assert(bin_fptr_);
  assert(scaler_index < partition->scale_buffers);

  auto block_offset = partition->clv_buffers + partition->tips;

  unsigned int type, attributes;
  size_t size;

  auto ptr = pllmod_binary_custom_load( bin_fptr_.get(),
                                        0,
                                        &size,
                                        &type,
                                        &attributes,
                                        get_offset(map_, block_offset + scaler_index));
  if (!ptr) {
    throw std::runtime_error{std::string("Loading scaler failed: ") + pll_errmsg};
  }

  partition->scale_buffer[scaler_index] = static_cast<unsigned int*>(ptr);
}

pll_partition_t* Binary::load_partition()
{
  std::lock_guard<std::mutex> lock(file_mutex_);
  // make skeleton partition that only allocates the pointers to the clv/tipchar buffers
  unsigned int part_attribs = PLLMOD_BIN_ATTRIB_PARTITION_LOAD_SKELETON;
  auto partition =  pllmod_binary_partition_load( bin_fptr_.get(),
                                                  0,
                                                  nullptr,
                                                  &part_attribs,
                                                  get_offset(map_, -1));

  if (!partition) {
    throw std::runtime_error{std::string("Error loading partition: ") + pll_errmsg};
  }

  if (partition->attributes & PLL_ATTRIB_SITE_REPEATS) {
    unsigned int repeats_attribs = 0;
    if (pllmod_binary_repeats_load( bin_fptr_.get(),
                                    0,
                                    partition,
                                    &repeats_attribs,
                                    get_offset(map_, -3))
        != PLL_SUCCESS) {
      throw std::runtime_error{std::string("Error loading repeats: ") + pll_errmsg};
    }
  }

  return partition;
}

pll_utree_t* Binary::load_utree(const unsigned int num_tips)
{
  std::lock_guard<std::mutex> lock(file_mutex_);
  unsigned int attributes = 0;
  auto root =  pllmod_binary_utree_load(bin_fptr_.get(),
                                        0,
                                        &attributes,
                                        get_offset(map_, -2));
  if (!root) {
    throw std::runtime_error{std::string("Loading tree: ") + pll_errmsg};
  }

  return pll_utree_wraptree(root, num_tips);
}

static int full_trav(pll_unode_t*)
{
  return 1;
}

static auto create_scaler_to_clv_map(Tree& tree)
{
  const auto num_scalers = tree.partition()->scale_buffers;
  std::vector<unsigned int> map(num_scalers);

  std::vector<pll_unode_t*> travbuffer(tree.nums().nodes);
  unsigned int trav_size = 0;
  pll_utree_traverse( get_root(tree.tree()),
                      PLL_TREE_TRAVERSE_POSTORDER,
                      full_trav,
                      &travbuffer[0],
                      &trav_size);

  for (auto& n : travbuffer) {
    if (n->scaler_index != PLL_SCALE_BUFFER_NONE) {
      map[n->scaler_index] = n->clv_index;
    }

    // node is an inner?
    if (n->next) {
      auto nn = n->next;
      if (nn->scaler_index != PLL_SCALE_BUFFER_NONE) {
        map[nn->scaler_index] = nn->clv_index;
      }
      nn = nn->next;
      if (nn->scaler_index != PLL_SCALE_BUFFER_NONE) {
        map[nn->scaler_index] = nn->clv_index;
      }
    }
  }

  return map;
}

/**
  Writes the structures and data encapsulated in Tree to the specified file in the binary format.
  Writes them in such a way that the Binary class can read them.
*/
void dump_to_binary(Tree& tree, const std::string& file)
{
  const auto num_clvs = tree.partition()->clv_buffers;
  const auto num_tips = tree.partition()->tips;
  const auto num_scalers = tree.partition()->scale_buffers;
  const auto max_clv_index = num_clvs + num_tips;

  const bool use_tipchars = tree.partition()->attributes & PLL_ATTRIB_PATTERN_TIP;
  const bool use_repeats = tree.partition()->attributes & PLL_ATTRIB_SITE_REPEATS;

  int block_id = use_repeats ? -3 : -2;

  const unsigned int num_blocks = abs(block_id) + num_clvs + num_tips + num_scalers;

  pll_binary_header_t header;
  auto fptr =  pllmod_binary_create(
    file.c_str(),
    &header,
    PLLMOD_BIN_ACCESS_RANDOM,
    num_blocks);

  if(!fptr) {
    throw std::runtime_error{std::string("Error opening binary file for writing: ") + pll_errmsg};
  }

  const auto attributes = PLLMOD_BIN_ATTRIB_UPDATE_MAP | PLLMOD_BIN_ATTRIB_PARTITION_DUMP_WGT;

  if (use_repeats and not
      pllmod_binary_repeats_dump(fptr, block_id++, tree.partition(), attributes)) {
    throw std::runtime_error{std::string("Error dumping the repeats: ") + pll_errmsg};
  }

  // dump the utree structure
  if(!pllmod_binary_utree_dump(fptr, block_id++, get_root(tree.tree()), num_tips, attributes)) {
    throw std::runtime_error{std::string("Error dumping the utree to binary: ") + pll_errmsg};
  }

  // dump the partition
  if(!pllmod_binary_partition_dump(fptr, block_id++, tree.partition(), attributes)) {
    throw std::runtime_error{std::string("Error dumping partition to binary: ") + pll_errmsg};
  }

  // dump the tipchars, but only if partition uses them
  size_t tip_index = 0;
  if (use_tipchars) {
    for (tip_index = 0; tip_index < num_tips; tip_index++) {
      if(!pllmod_binary_custom_dump(fptr,
                                    block_id++,
                                    tree.partition()->tipchars[tip_index],
                                    tree.partition()->sites * sizeof(unsigned char),
                                    attributes)) {
        throw std::runtime_error{std::string("Error dumping tipchars to binary: ") + pll_errmsg};
      }
    }
  }

  // dump the clvs
  for (size_t clv_index = tip_index; clv_index < max_clv_index; clv_index++) {
    if(!pllmod_binary_clv_dump( fptr,
                                block_id++,
                                tree.partition(),
                                clv_index,
                                attributes)) {
      throw std::runtime_error{std::string("Error dumping clvs to binary: ") + pll_errmsg};
    }
  }

  const auto scaler_to_clv = create_scaler_to_clv_map(tree);

  const auto scaler_ptr = tree.partition()->scale_buffer;

  for (size_t scaler_index = 0; scaler_index < num_scalers; scaler_index++) {

    const auto scaler_size =  pll_get_sites_number( tree.partition(),
                                                    scaler_to_clv[scaler_index]);

    // with the repeats the scale buffers might not be allocated. dirty fix:
    // allocate them in this case, just so they can be written and later used
    if (scaler_ptr[scaler_index] == nullptr) {
      scaler_ptr[scaler_index] = static_cast<unsigned int *>(calloc(scaler_size, sizeof(unsigned int)));
    }

    if(!pllmod_binary_custom_dump(fptr,
                                  block_id++,
                                  scaler_ptr[scaler_index],
                                  scaler_size * sizeof(unsigned int),
                                  attributes)) {
      throw std::runtime_error{std::string("Error dumping scalers to binary: ") + pll_errmsg};
    }
  }

  fclose(fptr);
}
<commit_msg>made locking more local<commit_after>#include "Binary.hpp"

#include <stdexcept>
#include <algorithm>

#include "constants.hpp"
#include "Tree.hpp"

int safe_fclose(FILE* fptr) { return fptr ? fclose(fptr) : 0; }

Binary::Binary(Binary && other)
  : bin_fptr_(nullptr, safe_fclose)
{
  std::swap(bin_fptr_, other.bin_fptr_);
  std::swap(map_, other.map_);
}

Binary& Binary::operator=(Binary && other)
{
  bin_fptr_ = std::move(other.bin_fptr_);
  map_ = std::move(other.map_);
  return *this;
}

Binary::Binary(const std::string& binary_file_path)
  : bin_fptr_(nullptr, safe_fclose)
{
  // open the binary file
  pll_binary_header_t header;
  bin_fptr_ = file_ptr_type(pllmod_binary_open(binary_file_path.c_str(), &header), safe_fclose);

  if (!bin_fptr_) {
    throw std::runtime_error{"Could not open binary file for reading."};
  }

  if (header.access_type != PLLMOD_BIN_ACCESS_RANDOM) {
    throw std::runtime_error{"Binary file must be random access enabled."};
  }

  if (header.n_blocks <= 0) {
    throw std::runtime_error{std::string("Binary file header must have nonzero positive number of blocks: ")
              + std::to_string(header.n_blocks)};
  }

  // proccess the random access map
  unsigned int n_blocks;
  pll_block_map_t* block_map;
  block_map = pllmod_binary_get_map(bin_fptr_.get(), &n_blocks);

  assert(block_map);
  assert(n_blocks);

  for (size_t i = 0; i < n_blocks; i++) {
    map_.push_back(block_map[i]);
  }

  free(block_map);
}

static long int get_offset(std::vector<pll_block_map_t>& map, const int block_id)
{
  auto item = map.begin();
  while (item != map.end()) {
    if (item->block_id == block_id) {
      break;
    }
    item++;
  }

  if(item == map.end()) {
    throw std::runtime_error{std::string("Map does not contain block_id: ") + std::to_string(block_id)};
  }
  return item->block_offset;
}

void Binary::load_clv(pll_partition_t * partition,
                      const unsigned int clv_index)
{
  assert(bin_fptr_);
  assert(clv_index < partition->clv_buffers + partition->tips);
  if (partition->attributes & PLL_ATTRIB_PATTERN_TIP) {
    assert(clv_index >= partition->tips);
  }

  if (!(partition->clv[clv_index])) {
    const size_t clv_size = pll_get_clv_size(partition, clv_index) * sizeof(double);

    partition->clv[clv_index] = static_cast<double*>(pll_aligned_alloc(clv_size, partition->alignment));
    if (!partition->clv[clv_index]) {
      throw std::runtime_error{"Could not allocate CLV memory"};
    }
  }

  {
    unsigned int attributes;
    std::lock_guard<std::mutex> lock(file_mutex_);
    auto err = pllmod_binary_clv_load(bin_fptr_.get(),
                                    0,
                                    partition,
                                    clv_index,
                                    &attributes,
                                    get_offset(map_, clv_index));
    if (err != PLL_SUCCESS) {
      throw std::runtime_error{std::string("Loading CLV failed: ")
                              + pll_errmsg
                              + std::string(". CLV index: ")
                              + std::to_string(clv_index)};
    }
  }
}

void Binary::load_tipchars( pll_partition_t * partition,
                            const unsigned int tipchars_index)
{
  assert(bin_fptr_);
  assert(tipchars_index < partition->tips);
  assert(partition->attributes & PLL_ATTRIB_PATTERN_TIP);

  unsigned int type = 0;
  unsigned int attributes = 0;
  size_t size = 0;

  {
    std::lock_guard<std::mutex> lock(file_mutex_);
    auto ptr = pllmod_binary_custom_load( bin_fptr_.get(),
                                          0,
                                          &size,
                                          &type,
                                          &attributes,
                                          get_offset(map_, tipchars_index));
    if (!ptr) {
      throw std::runtime_error{std::string("Loading tipchar failed: ") + pll_errmsg};
    }
    partition->tipchars[tipchars_index] = static_cast<unsigned char*>(ptr);
  }
}

void Binary::load_scaler( pll_partition_t * partition,
                          const unsigned int scaler_index)
{
  assert(bin_fptr_);
  assert(scaler_index < partition->scale_buffers);

  auto block_offset = partition->clv_buffers + partition->tips;

  unsigned int type, attributes;
  size_t size;

  {
    std::lock_guard<std::mutex> lock(file_mutex_);
    auto ptr = pllmod_binary_custom_load( bin_fptr_.get(),
                                          0,
                                          &size,
                                          &type,
                                          &attributes,
                                          get_offset(map_, block_offset + scaler_index));
    if (!ptr) {
      throw std::runtime_error{std::string("Loading scaler failed: ") + pll_errmsg};
    }

    partition->scale_buffer[scaler_index] = static_cast<unsigned int*>(ptr);
  }
}

pll_partition_t* Binary::load_partition()
{
  std::lock_guard<std::mutex> lock(file_mutex_);
  // make skeleton partition that only allocates the pointers to the clv/tipchar buffers
  unsigned int part_attribs = PLLMOD_BIN_ATTRIB_PARTITION_LOAD_SKELETON;
  auto partition =  pllmod_binary_partition_load( bin_fptr_.get(),
                                                  0,
                                                  nullptr,
                                                  &part_attribs,
                                                  get_offset(map_, -1));

  if (!partition) {
    throw std::runtime_error{std::string("Error loading partition: ") + pll_errmsg};
  }

  if (partition->attributes & PLL_ATTRIB_SITE_REPEATS) {
    unsigned int repeats_attribs = 0;
    if (pllmod_binary_repeats_load( bin_fptr_.get(),
                                    0,
                                    partition,
                                    &repeats_attribs,
                                    get_offset(map_, -3))
        != PLL_SUCCESS) {
      throw std::runtime_error{std::string("Error loading repeats: ") + pll_errmsg};
    }
  }

  return partition;
}

pll_utree_t* Binary::load_utree(const unsigned int num_tips)
{
  std::lock_guard<std::mutex> lock(file_mutex_);
  unsigned int attributes = 0;
  auto root =  pllmod_binary_utree_load(bin_fptr_.get(),
                                        0,
                                        &attributes,
                                        get_offset(map_, -2));
  if (!root) {
    throw std::runtime_error{std::string("Loading tree: ") + pll_errmsg};
  }

  return pll_utree_wraptree(root, num_tips);
}

static int full_trav(pll_unode_t*)
{
  return 1;
}

static auto create_scaler_to_clv_map(Tree& tree)
{
  const auto num_scalers = tree.partition()->scale_buffers;
  std::vector<unsigned int> map(num_scalers);

  std::vector<pll_unode_t*> travbuffer(tree.nums().nodes);
  unsigned int trav_size = 0;
  pll_utree_traverse( get_root(tree.tree()),
                      PLL_TREE_TRAVERSE_POSTORDER,
                      full_trav,
                      &travbuffer[0],
                      &trav_size);

  for (auto& n : travbuffer) {
    if (n->scaler_index != PLL_SCALE_BUFFER_NONE) {
      map[n->scaler_index] = n->clv_index;
    }

    // node is an inner?
    if (n->next) {
      auto nn = n->next;
      if (nn->scaler_index != PLL_SCALE_BUFFER_NONE) {
        map[nn->scaler_index] = nn->clv_index;
      }
      nn = nn->next;
      if (nn->scaler_index != PLL_SCALE_BUFFER_NONE) {
        map[nn->scaler_index] = nn->clv_index;
      }
    }
  }

  return map;
}

/**
  Writes the structures and data encapsulated in Tree to the specified file in the binary format.
  Writes them in such a way that the Binary class can read them.
*/
void dump_to_binary(Tree& tree, const std::string& file)
{
  const auto num_clvs = tree.partition()->clv_buffers;
  const auto num_tips = tree.partition()->tips;
  const auto num_scalers = tree.partition()->scale_buffers;
  const auto max_clv_index = num_clvs + num_tips;

  const bool use_tipchars = tree.partition()->attributes & PLL_ATTRIB_PATTERN_TIP;
  const bool use_repeats = tree.partition()->attributes & PLL_ATTRIB_SITE_REPEATS;

  int block_id = use_repeats ? -3 : -2;

  const unsigned int num_blocks = abs(block_id) + num_clvs + num_tips + num_scalers;

  pll_binary_header_t header;
  auto fptr =  pllmod_binary_create(
    file.c_str(),
    &header,
    PLLMOD_BIN_ACCESS_RANDOM,
    num_blocks);

  if(!fptr) {
    throw std::runtime_error{std::string("Error opening binary file for writing: ") + pll_errmsg};
  }

  const auto attributes = PLLMOD_BIN_ATTRIB_UPDATE_MAP | PLLMOD_BIN_ATTRIB_PARTITION_DUMP_WGT;

  if (use_repeats and not
      pllmod_binary_repeats_dump(fptr, block_id++, tree.partition(), attributes)) {
    throw std::runtime_error{std::string("Error dumping the repeats: ") + pll_errmsg};
  }

  // dump the utree structure
  if(!pllmod_binary_utree_dump(fptr, block_id++, get_root(tree.tree()), num_tips, attributes)) {
    throw std::runtime_error{std::string("Error dumping the utree to binary: ") + pll_errmsg};
  }

  // dump the partition
  if(!pllmod_binary_partition_dump(fptr, block_id++, tree.partition(), attributes)) {
    throw std::runtime_error{std::string("Error dumping partition to binary: ") + pll_errmsg};
  }

  // dump the tipchars, but only if partition uses them
  size_t tip_index = 0;
  if (use_tipchars) {
    for (tip_index = 0; tip_index < num_tips; tip_index++) {
      if(!pllmod_binary_custom_dump(fptr,
                                    block_id++,
                                    tree.partition()->tipchars[tip_index],
                                    tree.partition()->sites * sizeof(unsigned char),
                                    attributes)) {
        throw std::runtime_error{std::string("Error dumping tipchars to binary: ") + pll_errmsg};
      }
    }
  }

  // dump the clvs
  for (size_t clv_index = tip_index; clv_index < max_clv_index; clv_index++) {
    if(!pllmod_binary_clv_dump( fptr,
                                block_id++,
                                tree.partition(),
                                clv_index,
                                attributes)) {
      throw std::runtime_error{std::string("Error dumping clvs to binary: ") + pll_errmsg};
    }
  }

  const auto scaler_to_clv = create_scaler_to_clv_map(tree);

  const auto scaler_ptr = tree.partition()->scale_buffer;

  for (size_t scaler_index = 0; scaler_index < num_scalers; scaler_index++) {

    const auto scaler_size =  pll_get_sites_number( tree.partition(),
                                                    scaler_to_clv[scaler_index]);

    // with the repeats the scale buffers might not be allocated. dirty fix:
    // allocate them in this case, just so they can be written and later used
    if (scaler_ptr[scaler_index] == nullptr) {
      scaler_ptr[scaler_index] = static_cast<unsigned int *>(calloc(scaler_size, sizeof(unsigned int)));
    }

    if(!pllmod_binary_custom_dump(fptr,
                                  block_id++,
                                  scaler_ptr[scaler_index],
                                  scaler_size * sizeof(unsigned int),
                                  attributes)) {
      throw std::runtime_error{std::string("Error dumping scalers to binary: ") + pll_errmsg};
    }
  }

  fclose(fptr);
}
<|endoftext|>


<commit_before>#include "Calib3D.h"
#include "Matrix.h"

void Calib3D::Init(Handle<Object> target)
{
    Persistent<Object> inner;
    Local<Object> obj = NanNew<Object>();
    NanAssignPersistent(inner, obj);

    NODE_SET_METHOD(obj, "findChessboardCorners", FindChessboardCorners);
    NODE_SET_METHOD(obj, "drawChessboardCorners", DrawChessboardCorners);
    NODE_SET_METHOD(obj, "calibrateCamera", CalibrateCamera);
    NODE_SET_METHOD(obj, "solvePnP", SolvePnP);
    NODE_SET_METHOD(obj, "getOptimalNewCameraMatrix", GetOptimalNewCameraMatrix);

    target->Set(NanNew("calib3d"), obj);
}

// cv::findChessboardCorners
NAN_METHOD(Calib3D::FindChessboardCorners)
{
    NanEscapableScope();

    try {
        // Get the arguments from javascript

        // Arg 0 is the image
        Matrix* m = ObjectWrap::Unwrap<Matrix>(args[0]->ToObject());
        cv::Mat mat = m->mat;

        // Arg 1 is the pattern size
        cv::Size patternSize;
        if (args[1]->IsArray()) {
            Local<Object> v8sz = args[1]->ToObject();

            patternSize = cv::Size(v8sz->Get(0)->IntegerValue(), v8sz->Get(1)->IntegerValue());
        } else {
            JSTHROW_TYPE("Must pass pattern size");
        }

        // Arg 2 would normally be the flags, ignoring this for now and using the default flags

        // Find the corners
        std::vector<cv::Point2f> corners;
        bool found = cv::findChessboardCorners(mat, patternSize, corners);

        // Make the return value
        Local<Object> ret = NanNew<Object>();
        ret->Set(NanNew<String>("found"), NanNew<Boolean>(found));

        Local<Array> cornersArray = NanNew<Array>(corners.size());
        for(unsigned int i = 0; i < corners.size(); i++)
        {
            Local<Object> point_data = NanNew<Object>();
            point_data->Set(NanNew<String>("x"), NanNew<Number>(corners[i].x));
            point_data->Set(NanNew<String>("y"), NanNew<Number>(corners[i].y));

            cornersArray->Set(NanNew<Number>(i), point_data);
        }

        ret->Set(NanNew<String>("corners"), cornersArray);

        NanReturnValue(ret);

    } catch (cv::Exception &e) {
        const char *err_msg = e.what();
        NanThrowError(err_msg);
        NanReturnUndefined();
    }

};

// cv::drawChessboardCorners
NAN_METHOD(Calib3D::DrawChessboardCorners)
{
    NanEscapableScope();

    try {
        // Get the arguments

        // Arg 0 is the image
        Matrix* m = ObjectWrap::Unwrap<Matrix>(args[0]->ToObject());
        cv::Mat mat = m->mat;

        // Arg 1 is the pattern size
        cv::Size patternSize;
        if (args[1]->IsArray()) {
            Local<Object> v8sz = args[1]->ToObject();

            patternSize = cv::Size(v8sz->Get(0)->IntegerValue(), v8sz->Get(1)->IntegerValue());
        } else {
            JSTHROW_TYPE("Must pass pattern size");
        }

        // Arg 2 is the corners array
        std::vector<cv::Point2f> corners;
        if(args[2]->IsArray()) {
            Local<Array> cornersArray = Local<Array>::Cast(args[2]);

            for(unsigned int i = 0; i < cornersArray->Length(); i++)
            {
                Local<Object> pt = cornersArray->Get(i)->ToObject();
                corners.push_back(cv::Point2f(pt->Get(NanNew<String>("x"))->ToNumber()->Value(),
                                              pt->Get(NanNew<String>("y"))->ToNumber()->Value()));
            }
        } else {
            JSTHROW_TYPE("Must pass corners array");
        }

        // Arg 3, pattern found boolean
        bool patternWasFound = args[3]->ToBoolean()->Value();

        // Draw the corners
        cv::drawChessboardCorners(mat, patternSize, corners, patternWasFound);

        // Return the passed image, now with corners drawn on it
        NanReturnValue(args[0]);

    } catch (cv::Exception &e) {
        const char *err_msg = e.what();
        NanThrowError(err_msg);
        NanReturnUndefined();
    }
}

// cv::calibrateCamera
NAN_METHOD(Calib3D::CalibrateCamera)
{
    NanEscapableScope();

    try {
        // Get the arguments

        // Arg 0, the array of object points, an array of arrays
        std::vector<std::vector<cv::Point3f> > objectPoints;
        if(args[0]->IsArray()) {
            Local<Array> objectPointsArray = Local<Array>::Cast(args[0]);

            for(unsigned int i = 0; i < objectPointsArray->Length(); i++)
            {
                std::vector<cv::Point3f> points;

                Local<Array> pointsArray = Local<Array>::Cast(objectPointsArray->Get(i));
                for(unsigned int j = 0; j < pointsArray->Length(); j++)
                {
                    Local<Object> pt = pointsArray->Get(j)->ToObject();
                    points.push_back(cv::Point3f(pt->Get(NanNew<String>("x"))->ToNumber()->Value(),
                                                 pt->Get(NanNew<String>("y"))->ToNumber()->Value(),
                                                 pt->Get(NanNew<String>("z"))->ToNumber()->Value()));
                }

                objectPoints.push_back(points);
            }
        } else {
            JSTHROW_TYPE("Must pass array of object points for each frame")
        }

        // Arg 1, the image points, another array of arrays =(
        std::vector<std::vector<cv::Point2f> > imagePoints;
        if(args[1]->IsArray()) {
            Local<Array> imagePointsArray = Local<Array>::Cast(args[1]);

            for(unsigned int i = 0; i < imagePointsArray->Length(); i++)
            {
                std::vector<cv::Point2f> points;

                Local<Array> pointsArray = Local<Array>::Cast(imagePointsArray->Get(i));
                for(unsigned int j = 0; j < pointsArray->Length(); j++)
                {
                    Local<Object> pt = pointsArray->Get(j)->ToObject();
                    points.push_back(cv::Point2f(pt->Get(NanNew<String>("x"))->ToNumber()->Value(),
                                                 pt->Get(NanNew<String>("y"))->ToNumber()->Value()));
                }

                imagePoints.push_back(points);
            }
        } else {
            JSTHROW_TYPE("Must pass array of object points for each frame")
        }

        // Arg 2, the image size
        cv::Size imageSize;
        if (args[2]->IsArray()) {
            Local<Object> v8sz = args[2]->ToObject();

            imageSize = cv::Size(v8sz->Get(0)->IntegerValue(), v8sz->Get(1)->IntegerValue());
        } else {
            JSTHROW_TYPE("Must pass pattern size");
        }

        // Arg 3, 4, input guesses for the camrea matrix and distortion coefficients, skipping for now
        cv::Mat K, dist;

        // Arg 5, 6 flags and termination criteria, skipping for now

        // Calibrate the camera
        std::vector<cv::Mat> rvecs, tvecs;

        double error = cv::calibrateCamera(objectPoints, imagePoints, imageSize, K, dist, rvecs, tvecs);

        // make the return values
        Local<Object> ret = NanNew<Object>();

        // Reprojection error
        ret->Set(NanNew<String>("reprojectionError"), NanNew<Number>(error));

        // K
        Local<Object> KMatrixWrap = NanNew(Matrix::constructor)->GetFunction()->NewInstance();
        Matrix *KMatrix = ObjectWrap::Unwrap<Matrix>(KMatrixWrap);
        KMatrix->mat = K;

        ret->Set(NanNew<String>("K"), KMatrixWrap);

        // dist
        Local<Object> distMatrixWrap = NanNew(Matrix::constructor)->GetFunction()->NewInstance();
        Matrix *distMatrix = ObjectWrap::Unwrap<Matrix>(distMatrixWrap);
        distMatrix->mat = dist;

        ret->Set(NanNew<String>("distortion"), distMatrixWrap);

        // Per frame R and t, skiping for now

        // Return
        NanReturnValue(ret);

    } catch (cv::Exception &e) {
        const char *err_msg = e.what();
        NanThrowError(err_msg);
        NanReturnUndefined();
    }
}

// cv::solvePnP
NAN_METHOD(Calib3D::SolvePnP)
{
    NanEscapableScope();

    try {
        // Get the arguments

        // Arg 0, the array of object points
        std::vector<cv::Point3f> objectPoints;
        if(args[0]->IsArray()) {
            Local<Array> objectPointsArray = Local<Array>::Cast(args[0]);

            for(unsigned int i = 0; i < objectPointsArray->Length(); i++)
            {
                Local<Object> pt = objectPointsArray->Get(i)->ToObject();
                objectPoints.push_back(cv::Point3f(pt->Get(NanNew<String>("x"))->ToNumber()->Value(),
                                             pt->Get(NanNew<String>("y"))->ToNumber()->Value(),
                                             pt->Get(NanNew<String>("z"))->ToNumber()->Value()));
            }
        } else {
            JSTHROW_TYPE("Must pass array of object points for each frame")
        }

        // Arg 1, the image points
        std::vector<cv::Point2f> imagePoints;
        if(args[1]->IsArray()) {
            Local<Array> imagePointsArray = Local<Array>::Cast(args[1]);

            for(unsigned int i = 0; i < imagePointsArray->Length(); i++)
            {
                Local<Object> pt = imagePointsArray->Get(i)->ToObject();
                imagePoints.push_back(cv::Point2f(pt->Get(NanNew<String>("x"))->ToNumber()->Value(),
                                                  pt->Get(NanNew<String>("y"))->ToNumber()->Value()));
            }
        } else {
            JSTHROW_TYPE("Must pass array of object points for each frame")
        }

        // Arg 2, the camera matrix
        Matrix* kWrap = ObjectWrap::Unwrap<Matrix>(args[2]->ToObject());
        cv::Mat K = kWrap->mat;

        // Arg 3, the distortion coefficients
        Matrix* distWrap = ObjectWrap::Unwrap<Matrix>(args[3]->ToObject());
        cv::Mat dist = distWrap->mat;

        // Arg 4, use extrinsic guess, skipped for now

        // Arg 5, flags, skip for now

        // solve for r and t
        cv::Mat rvec, tvec;

        cv::solvePnP(objectPoints, imagePoints, K, dist, rvec, tvec);

        // make the return values
        Local<Object> ret = NanNew<Object>();

        // rvec
        Local<Object> rMatrixWrap = NanNew(Matrix::constructor)->GetFunction()->NewInstance();
        Matrix *rMatrix = ObjectWrap::Unwrap<Matrix>(rMatrixWrap);
        rMatrix->mat = rvec;

        ret->Set(NanNew<String>("rvec"), rMatrixWrap);

        // tvec
        Local<Object> tMatrixWrap = NanNew(Matrix::constructor)->GetFunction()->NewInstance();
        Matrix *tMatrix = ObjectWrap::Unwrap<Matrix>(tMatrixWrap);
        tMatrix->mat = tvec;

        ret->Set(NanNew<String>("tvec"), tMatrixWrap);

        // Return
        NanReturnValue(ret);

    } catch (cv::Exception &e) {
        const char *err_msg = e.what();
        NanThrowError(err_msg);
        NanReturnUndefined();
    }
}

// cv::solvePnP
NAN_METHOD(Calib3D::GetOptimalNewCameraMatrix)
{
    NanEscapableScope();

    try {
        // Get the arguments

        // Arg 0 is the original camera matrix
        Matrix* m0 = ObjectWrap::Unwrap<Matrix>(args[0]->ToObject());
        cv::Mat Kin = m0->mat;

        // Arg 1 is the distortion coefficients
        Matrix* m1 = ObjectWrap::Unwrap<Matrix>(args[1]->ToObject());
        cv::Mat dist = m1->mat;

        // Arg 2, the image size
        cv::Size imageSize;
        if (args[2]->IsArray()) {
            Local<Object> v8sz = args[2]->ToObject();

            imageSize = cv::Size(v8sz->Get(0)->IntegerValue(), v8sz->Get(1)->IntegerValue());
        } else {
            JSTHROW_TYPE("Must pass pattern size");
        }

        // Arg 3 is the alpha free scaling parameter
        double alpha = args[3]->ToNumber()->Value();

        // Arg 4, the new image size
        cv::Size newImageSize;
        if (args[4]->IsArray()) {
            Local<Object> v8sz = args[4]->ToObject();

            newImageSize = cv::Size(v8sz->Get(0)->IntegerValue(), v8sz->Get(1)->IntegerValue());
        } else {
            JSTHROW_TYPE("Must pass pattern size");
        }

        // Arg 5, valid ROI, skip for now
        // Arg 6, center principal point, skip for now

        // Get the optimal new camera matrix
        cv::Mat Kout = cv::getOptimalNewCameraMatrix(Kin, dist, imageSize, alpha, newImageSize);

        // Wrap the output K
        Local<Object> KMatrixWrap = NanNew(Matrix::constructor)->GetFunction()->NewInstance();
        Matrix *KMatrix = ObjectWrap::Unwrap<Matrix>(KMatrixWrap);
        KMatrix->mat = Kout;

        // Return the new K matrix
        NanReturnValue(KMatrixWrap);

    } catch (cv::Exception &e) {
        const char *err_msg = e.what();
        NanThrowError(err_msg);
        NanReturnUndefined();
    }
}
<commit_msg>Fixed bug causing image sizes to be transposed<commit_after>#include "Calib3D.h"
#include "Matrix.h"

void Calib3D::Init(Handle<Object> target)
{
    Persistent<Object> inner;
    Local<Object> obj = NanNew<Object>();
    NanAssignPersistent(inner, obj);

    NODE_SET_METHOD(obj, "findChessboardCorners", FindChessboardCorners);
    NODE_SET_METHOD(obj, "drawChessboardCorners", DrawChessboardCorners);
    NODE_SET_METHOD(obj, "calibrateCamera", CalibrateCamera);
    NODE_SET_METHOD(obj, "solvePnP", SolvePnP);
    NODE_SET_METHOD(obj, "getOptimalNewCameraMatrix", GetOptimalNewCameraMatrix);

    target->Set(NanNew("calib3d"), obj);
}

// cv::findChessboardCorners
NAN_METHOD(Calib3D::FindChessboardCorners)
{
    NanEscapableScope();

    try {
        // Get the arguments from javascript

        // Arg 0 is the image
        Matrix* m = ObjectWrap::Unwrap<Matrix>(args[0]->ToObject());
        cv::Mat mat = m->mat;

        // Arg 1 is the pattern size
        cv::Size patternSize;
        if (args[1]->IsArray()) {
            Local<Object> v8sz = args[1]->ToObject();

            patternSize = cv::Size(v8sz->Get(0)->IntegerValue(), v8sz->Get(1)->IntegerValue());
        } else {
            JSTHROW_TYPE("Must pass pattern size");
        }

        // Arg 2 would normally be the flags, ignoring this for now and using the default flags

        // Find the corners
        std::vector<cv::Point2f> corners;
        bool found = cv::findChessboardCorners(mat, patternSize, corners);

        // Make the return value
        Local<Object> ret = NanNew<Object>();
        ret->Set(NanNew<String>("found"), NanNew<Boolean>(found));

        Local<Array> cornersArray = NanNew<Array>(corners.size());
        for(unsigned int i = 0; i < corners.size(); i++)
        {
            Local<Object> point_data = NanNew<Object>();
            point_data->Set(NanNew<String>("x"), NanNew<Number>(corners[i].x));
            point_data->Set(NanNew<String>("y"), NanNew<Number>(corners[i].y));

            cornersArray->Set(NanNew<Number>(i), point_data);
        }

        ret->Set(NanNew<String>("corners"), cornersArray);

        NanReturnValue(ret);

    } catch (cv::Exception &e) {
        const char *err_msg = e.what();
        NanThrowError(err_msg);
        NanReturnUndefined();
    }

};

// cv::drawChessboardCorners
NAN_METHOD(Calib3D::DrawChessboardCorners)
{
    NanEscapableScope();

    try {
        // Get the arguments

        // Arg 0 is the image
        Matrix* m = ObjectWrap::Unwrap<Matrix>(args[0]->ToObject());
        cv::Mat mat = m->mat;

        // Arg 1 is the pattern size
        cv::Size patternSize;
        if (args[1]->IsArray()) {
            Local<Object> v8sz = args[1]->ToObject();

            patternSize = cv::Size(v8sz->Get(0)->IntegerValue(), v8sz->Get(1)->IntegerValue());
        } else {
            JSTHROW_TYPE("Must pass pattern size");
        }

        // Arg 2 is the corners array
        std::vector<cv::Point2f> corners;
        if(args[2]->IsArray()) {
            Local<Array> cornersArray = Local<Array>::Cast(args[2]);

            for(unsigned int i = 0; i < cornersArray->Length(); i++)
            {
                Local<Object> pt = cornersArray->Get(i)->ToObject();
                corners.push_back(cv::Point2f(pt->Get(NanNew<String>("x"))->ToNumber()->Value(),
                                              pt->Get(NanNew<String>("y"))->ToNumber()->Value()));
            }
        } else {
            JSTHROW_TYPE("Must pass corners array");
        }

        // Arg 3, pattern found boolean
        bool patternWasFound = args[3]->ToBoolean()->Value();

        // Draw the corners
        cv::drawChessboardCorners(mat, patternSize, corners, patternWasFound);

        // Return the passed image, now with corners drawn on it
        NanReturnValue(args[0]);

    } catch (cv::Exception &e) {
        const char *err_msg = e.what();
        NanThrowError(err_msg);
        NanReturnUndefined();
    }
}

// cv::calibrateCamera
NAN_METHOD(Calib3D::CalibrateCamera)
{
    NanEscapableScope();

    try {
        // Get the arguments

        // Arg 0, the array of object points, an array of arrays
        std::vector<std::vector<cv::Point3f> > objectPoints;
        if(args[0]->IsArray()) {
            Local<Array> objectPointsArray = Local<Array>::Cast(args[0]);

            for(unsigned int i = 0; i < objectPointsArray->Length(); i++)
            {
                std::vector<cv::Point3f> points;

                Local<Array> pointsArray = Local<Array>::Cast(objectPointsArray->Get(i));
                for(unsigned int j = 0; j < pointsArray->Length(); j++)
                {
                    Local<Object> pt = pointsArray->Get(j)->ToObject();
                    points.push_back(cv::Point3f(pt->Get(NanNew<String>("x"))->ToNumber()->Value(),
                                                 pt->Get(NanNew<String>("y"))->ToNumber()->Value(),
                                                 pt->Get(NanNew<String>("z"))->ToNumber()->Value()));
                }

                objectPoints.push_back(points);
            }
        } else {
            JSTHROW_TYPE("Must pass array of object points for each frame")
        }

        // Arg 1, the image points, another array of arrays =(
        std::vector<std::vector<cv::Point2f> > imagePoints;
        if(args[1]->IsArray()) {
            Local<Array> imagePointsArray = Local<Array>::Cast(args[1]);

            for(unsigned int i = 0; i < imagePointsArray->Length(); i++)
            {
                std::vector<cv::Point2f> points;

                Local<Array> pointsArray = Local<Array>::Cast(imagePointsArray->Get(i));
                for(unsigned int j = 0; j < pointsArray->Length(); j++)
                {
                    Local<Object> pt = pointsArray->Get(j)->ToObject();
                    points.push_back(cv::Point2f(pt->Get(NanNew<String>("x"))->ToNumber()->Value(),
                                                 pt->Get(NanNew<String>("y"))->ToNumber()->Value()));
                }

                imagePoints.push_back(points);
            }
        } else {
            JSTHROW_TYPE("Must pass array of object points for each frame")
        }

        // Arg 2, the image size
        cv::Size imageSize;
        if (args[2]->IsArray()) {
            Local<Object> v8sz = args[2]->ToObject();

            imageSize = cv::Size(v8sz->Get(1)->IntegerValue(), v8sz->Get(0)->IntegerValue());
        } else {
            JSTHROW_TYPE("Must pass pattern size");
        }

        // Arg 3, 4, input guesses for the camrea matrix and distortion coefficients, skipping for now
        cv::Mat K, dist;

        // Arg 5, 6 flags and termination criteria, skipping for now

        // Calibrate the camera
        std::vector<cv::Mat> rvecs, tvecs;

        double error = cv::calibrateCamera(objectPoints, imagePoints, imageSize, K, dist, rvecs, tvecs);

        // make the return values
        Local<Object> ret = NanNew<Object>();

        // Reprojection error
        ret->Set(NanNew<String>("reprojectionError"), NanNew<Number>(error));

        // K
        Local<Object> KMatrixWrap = NanNew(Matrix::constructor)->GetFunction()->NewInstance();
        Matrix *KMatrix = ObjectWrap::Unwrap<Matrix>(KMatrixWrap);
        KMatrix->mat = K;

        ret->Set(NanNew<String>("K"), KMatrixWrap);

        // dist
        Local<Object> distMatrixWrap = NanNew(Matrix::constructor)->GetFunction()->NewInstance();
        Matrix *distMatrix = ObjectWrap::Unwrap<Matrix>(distMatrixWrap);
        distMatrix->mat = dist;

        ret->Set(NanNew<String>("distortion"), distMatrixWrap);

        // Per frame R and t, skiping for now

        // Return
        NanReturnValue(ret);

    } catch (cv::Exception &e) {
        const char *err_msg = e.what();
        NanThrowError(err_msg);
        NanReturnUndefined();
    }
}

// cv::solvePnP
NAN_METHOD(Calib3D::SolvePnP)
{
    NanEscapableScope();

    try {
        // Get the arguments

        // Arg 0, the array of object points
        std::vector<cv::Point3f> objectPoints;
        if(args[0]->IsArray()) {
            Local<Array> objectPointsArray = Local<Array>::Cast(args[0]);

            for(unsigned int i = 0; i < objectPointsArray->Length(); i++)
            {
                Local<Object> pt = objectPointsArray->Get(i)->ToObject();
                objectPoints.push_back(cv::Point3f(pt->Get(NanNew<String>("x"))->ToNumber()->Value(),
                                             pt->Get(NanNew<String>("y"))->ToNumber()->Value(),
                                             pt->Get(NanNew<String>("z"))->ToNumber()->Value()));
            }
        } else {
            JSTHROW_TYPE("Must pass array of object points for each frame")
        }

        // Arg 1, the image points
        std::vector<cv::Point2f> imagePoints;
        if(args[1]->IsArray()) {
            Local<Array> imagePointsArray = Local<Array>::Cast(args[1]);

            for(unsigned int i = 0; i < imagePointsArray->Length(); i++)
            {
                Local<Object> pt = imagePointsArray->Get(i)->ToObject();
                imagePoints.push_back(cv::Point2f(pt->Get(NanNew<String>("x"))->ToNumber()->Value(),
                                                  pt->Get(NanNew<String>("y"))->ToNumber()->Value()));
            }
        } else {
            JSTHROW_TYPE("Must pass array of object points for each frame")
        }

        // Arg 2, the camera matrix
        Matrix* kWrap = ObjectWrap::Unwrap<Matrix>(args[2]->ToObject());
        cv::Mat K = kWrap->mat;

        // Arg 3, the distortion coefficients
        Matrix* distWrap = ObjectWrap::Unwrap<Matrix>(args[3]->ToObject());
        cv::Mat dist = distWrap->mat;

        // Arg 4, use extrinsic guess, skipped for now

        // Arg 5, flags, skip for now

        // solve for r and t
        cv::Mat rvec, tvec;

        cv::solvePnP(objectPoints, imagePoints, K, dist, rvec, tvec);

        // make the return values
        Local<Object> ret = NanNew<Object>();

        // rvec
        Local<Object> rMatrixWrap = NanNew(Matrix::constructor)->GetFunction()->NewInstance();
        Matrix *rMatrix = ObjectWrap::Unwrap<Matrix>(rMatrixWrap);
        rMatrix->mat = rvec;

        ret->Set(NanNew<String>("rvec"), rMatrixWrap);

        // tvec
        Local<Object> tMatrixWrap = NanNew(Matrix::constructor)->GetFunction()->NewInstance();
        Matrix *tMatrix = ObjectWrap::Unwrap<Matrix>(tMatrixWrap);
        tMatrix->mat = tvec;

        ret->Set(NanNew<String>("tvec"), tMatrixWrap);

        // Return
        NanReturnValue(ret);

    } catch (cv::Exception &e) {
        const char *err_msg = e.what();
        NanThrowError(err_msg);
        NanReturnUndefined();
    }
}

// cv::solvePnP
NAN_METHOD(Calib3D::GetOptimalNewCameraMatrix)
{
    NanEscapableScope();

    try {
        // Get the arguments

        // Arg 0 is the original camera matrix
        Matrix* m0 = ObjectWrap::Unwrap<Matrix>(args[0]->ToObject());
        cv::Mat Kin = m0->mat;

        // Arg 1 is the distortion coefficients
        Matrix* m1 = ObjectWrap::Unwrap<Matrix>(args[1]->ToObject());
        cv::Mat dist = m1->mat;

        // Arg 2, the image size
        cv::Size imageSize;
        if (args[2]->IsArray()) {
            Local<Object> v8sz = args[2]->ToObject();

            imageSize = cv::Size(v8sz->Get(1)->IntegerValue(), v8sz->Get(0)->IntegerValue());
        } else {
            JSTHROW_TYPE("Must pass original image size");
        }

        // Arg 3 is the alpha free scaling parameter
        double alpha = args[3]->ToNumber()->Value();

        // Arg 4, the new image size
        cv::Size newImageSize;
        if (args[4]->IsArray()) {
            Local<Object> v8sz = args[4]->ToObject();

            newImageSize = cv::Size(v8sz->Get(1)->IntegerValue(), v8sz->Get(0)->IntegerValue());
        } else {
            JSTHROW_TYPE("Must pass new image size");
        }

        // Arg 5, valid ROI, skip for now
        // Arg 6, center principal point, skip for now

        // Get the optimal new camera matrix
        cv::Mat Kout = cv::getOptimalNewCameraMatrix(Kin, dist, imageSize, alpha, newImageSize);

        // Wrap the output K
        Local<Object> KMatrixWrap = NanNew(Matrix::constructor)->GetFunction()->NewInstance();
        Matrix *KMatrix = ObjectWrap::Unwrap<Matrix>(KMatrixWrap);
        KMatrix->mat = Kout;

        // Return the new K matrix
        NanReturnValue(KMatrixWrap);

    } catch (cv::Exception &e) {
        const char *err_msg = e.what();
        NanThrowError(err_msg);
        NanReturnUndefined();
    }
}
<|endoftext|>


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

  Program:   Visualization Toolkit
  Module:    CellLoc.cc
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 1993-1995 Ken Martin, Will Schroeder, Bill Lorensen.

This software is copyrighted by Ken Martin, Will Schroeder and Bill Lorensen.
The following terms apply to all files associated with the software unless
explicitly disclaimed in individual files. This copyright specifically does
not apply to the related textbook "The Visualization Toolkit" ISBN
013199837-4 published by Prentice Hall which is covered by its own copyright.

The authors hereby grant permission to use, copy, and distribute this
software and its documentation for any purpose, provided that existing
copyright notices are retained in all copies and that this notice is included
verbatim in any distributions. Additionally, the authors grant permission to
modify this software and its documentation for any purpose, provided that
such modifications are not distributed without the explicit consent of the
authors and that existing copyright notices are retained in all copies. Some
of the algorithms implemented by this software are patented, observe all
applicable patent law.

IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF,
EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON AN
"AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

=========================================================================*/
#include <math.h>
#include "CellLoc.hh"
#include "Locator.hh"
#include "vtkMath.hh"
#include "IntArray.hh"

#define OUTSIDE 0
#define INSIDE 1

typedef vtkIdList *vtkIdListPtr;

// Description:
// Construct with automatic computation of divisions, averaging
// 25 cells per octant.
vtkCellLocator::vtkCellLocator()
{
  this->DataSet = NULL;
  this->Level = 4;
  this->MaxLevel = 5;
  this->Automatic = 1;
  this->NumberOfCellsInOctant = 25;
  this->Tolerance = 0.01;
  this->Tree = NULL;
  this->H[0] = this->H[1] = this->H[2] = 1.0;
  this->NumberOfDivisions = 1;
}

vtkCellLocator::~vtkCellLocator()
{
  this->Initialize();
}

void vtkCellLocator::Initialize()
{
  // free up octants
  this->FreeSearchStructure();
}

void vtkCellLocator::FreeSearchStructure()
{
  vtkIdList *cellIds;
  int i;

  if ( this->Tree )
    {
    for (i=0; i<this->NumberOfOctants; i++)
      {
      if ( (cellIds = this->Tree[i]) ) delete cellIds;
      }
    this->Tree = NULL;
    }
}

// Description:
// Given a position x, return the id of the cell closest to it. Cell may
// contain the point, or just lie near it. Parametric coordinates, subId,
// and distance squared to cell are returned.
int vtkCellLocator::FindClosestCell(float x[3], float dist2,
                                   int& subId, float pcoords[3])
{
  int closest=(-1);

  return closest;
}

// Description:
// Return list of octants that are intersected by line. The octants
// are ordered along the line and are represented by octant number. To obtain
// the cells in the octant, use the method GetOctantCells().
int vtkCellLocator::IntersectWithLine(float a0[3], float a1[3], vtkIdList& cells)
{
  return 0;
}

// Description:
// Get the cells in an octant.
vtkIdList* vtkCellLocator::GetOctantCells(int octantId)
{
  return NULL;
}

// Description:
// Intersect against another vtkCellLocator returning cells that lie in
// intersecting octants.
int vtkCellLocator::IntersectWithCellLocator(vtkCellLocator& locator, vtkIdList cells)
{
  return 0;
}

//
//  Method to form subdivision of space based on the cells provided and
//  subject to the constraints of levels and NumberOfCellsInOctant.
//  The result is directly addressable and of uniform subdivision.
//
void vtkCellLocator::SubDivide()
{
  vtkCell *cell;
  float *bounds, *cellBounds;
  int numCells;
  float level;
  int ndivs, product;
  int i, j, k, cellId, ijkMin[3], ijkMax[3];
  int idx, parentOffset;
  vtkIdList *octant;
  int numCellsInOctant = this->NumberOfCellsInOctant;
  typedef vtkIdList *vtkIdListPtr;
  int prod, numOctants;

  if ( this->Tree != NULL && this->SubDivideTime > this->MTime ) return;

  vtkDebugMacro( << "Subdividing octree..." );

  if ( !this->DataSet || (numCells = this->DataSet->GetNumberOfCells()) < 1 )
    {
    vtkErrorMacro( << "No cells to subdivide");
    return;
    }
//
//  Make sure the appropriate data is available
//
  if ( this->Tree ) this->FreeSearchStructure();
//
//  Size the root cell.  Initialize cell data structure, compute
//  level and divisions.
//
  bounds = this->DataSet->GetBounds();
  for (i=0; i<6; i++) this->Bounds[i] = bounds[i];

  if ( this->Automatic )
    {
    this->Level = (int) (ceil(log((double)numCells/numCellsInOctant) /
                              (log((double) 8.0))));
    this->Level =(this->Level > this->MaxLevel ? this->MaxLevel : this->Level);
    }

  // compute number of octants and number of divisions
  for (ndivs=1,prod=1,numOctants=1,i=0; i<this->Level; i++)
    {
    ndivs *= 2;
    prod *= 8;
    numOctants += prod;
    }
  this->NumberOfDivisions = ndivs;
  this->NumberOfOctants = numOctants;

  this->Tree = new vtkIdListPtr[numOctants];
  memset (this->Tree, (int)NULL, numOctants*sizeof(vtkIdListPtr));
//
//  Compute width of leaf octant in three directions
//
  for (i=0; i<3; i++) this->H[i] = (bounds[2*i+1] - bounds[2*i]) / ndivs;
//
//  Insert each cell into the appropriate octant.  Make sure cell
//  falls within octant.
//
  parentOffset = numOctants - (ndivs * ndivs * ndivs);
  product = ndivs * ndivs;
  for (cellId=0; cellId<numCells; cellId++)
    {
    cell = this->DataSet->GetCell(cellId);
    cellBounds = cell->GetBounds();

    // find min/max locations of bounding box
    for (i=0; i<3; i++)
      {
      ijkMin[i] = (int) ((float) ((cellBounds[2*i] - bounds[2*i])*0.999 /
                         (bounds[2*i+1] - bounds[2*i])) * ndivs);
      ijkMax[i] = (int) ((float) ((cellBounds[2*i+1] - bounds[2*i])*0.999 /
                         (bounds[2*i+1] - bounds[2*i])) * ndivs);
      }

    // each octant inbetween min/max point may have cell in it
    for ( k = ijkMin[2]; k <= ijkMin[2]; k++ )
      {
      for ( j = ijkMin[1]; j <= ijkMax[1]; j++ )
        {
        for ( i = ijkMin[0]; i <= ijkMin[0]; i++ )
          {
          this->MarkParents((void*)INSIDE,i,j,k);
          idx = parentOffset + i + j*ndivs + k*product;
          octant = this->Tree[idx];
          if ( ! octant )
            {
            octant = new vtkIdList(numCellsInOctant);
            this->Tree[idx] = octant;
            }
          octant->InsertNextId(cellId);
          }
        }
      }

    } //for all cells

  this->SubDivideTime.Modified();
}

void vtkCellLocator::MarkParents(void* a, int i, int j, int k)
{
  // will's code
}

<commit_msg>removed an unused variable<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    CellLoc.cc
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 1993-1995 Ken Martin, Will Schroeder, Bill Lorensen.

This software is copyrighted by Ken Martin, Will Schroeder and Bill Lorensen.
The following terms apply to all files associated with the software unless
explicitly disclaimed in individual files. This copyright specifically does
not apply to the related textbook "The Visualization Toolkit" ISBN
013199837-4 published by Prentice Hall which is covered by its own copyright.

The authors hereby grant permission to use, copy, and distribute this
software and its documentation for any purpose, provided that existing
copyright notices are retained in all copies and that this notice is included
verbatim in any distributions. Additionally, the authors grant permission to
modify this software and its documentation for any purpose, provided that
such modifications are not distributed without the explicit consent of the
authors and that existing copyright notices are retained in all copies. Some
of the algorithms implemented by this software are patented, observe all
applicable patent law.

IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF,
EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON AN
"AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

=========================================================================*/
#include <math.h>
#include "CellLoc.hh"
#include "Locator.hh"
#include "vtkMath.hh"
#include "IntArray.hh"

#define OUTSIDE 0
#define INSIDE 1

typedef vtkIdList *vtkIdListPtr;

// Description:
// Construct with automatic computation of divisions, averaging
// 25 cells per octant.
vtkCellLocator::vtkCellLocator()
{
  this->DataSet = NULL;
  this->Level = 4;
  this->MaxLevel = 5;
  this->Automatic = 1;
  this->NumberOfCellsInOctant = 25;
  this->Tolerance = 0.01;
  this->Tree = NULL;
  this->H[0] = this->H[1] = this->H[2] = 1.0;
  this->NumberOfDivisions = 1;
}

vtkCellLocator::~vtkCellLocator()
{
  this->Initialize();
}

void vtkCellLocator::Initialize()
{
  // free up octants
  this->FreeSearchStructure();
}

void vtkCellLocator::FreeSearchStructure()
{
  vtkIdList *cellIds;
  int i;

  if ( this->Tree )
    {
    for (i=0; i<this->NumberOfOctants; i++)
      {
      if ( (cellIds = this->Tree[i]) ) delete cellIds;
      }
    this->Tree = NULL;
    }
}

// Description:
// Given a position x, return the id of the cell closest to it. Cell may
// contain the point, or just lie near it. Parametric coordinates, subId,
// and distance squared to cell are returned.
int vtkCellLocator::FindClosestCell(float x[3], float dist2,
                                   int& subId, float pcoords[3])
{
  int closest=(-1);

  return closest;
}

// Description:
// Return list of octants that are intersected by line. The octants
// are ordered along the line and are represented by octant number. To obtain
// the cells in the octant, use the method GetOctantCells().
int vtkCellLocator::IntersectWithLine(float a0[3], float a1[3], vtkIdList& cells)
{
  return 0;
}

// Description:
// Get the cells in an octant.
vtkIdList* vtkCellLocator::GetOctantCells(int octantId)
{
  return NULL;
}

// Description:
// Intersect against another vtkCellLocator returning cells that lie in
// intersecting octants.
int vtkCellLocator::IntersectWithCellLocator(vtkCellLocator& locator, vtkIdList cells)
{
  return 0;
}

//
//  Method to form subdivision of space based on the cells provided and
//  subject to the constraints of levels and NumberOfCellsInOctant.
//  The result is directly addressable and of uniform subdivision.
//
void vtkCellLocator::SubDivide()
{
  vtkCell *cell;
  float *bounds, *cellBounds;
  int numCells;
  int ndivs, product;
  int i, j, k, cellId, ijkMin[3], ijkMax[3];
  int idx, parentOffset;
  vtkIdList *octant;
  int numCellsInOctant = this->NumberOfCellsInOctant;
  typedef vtkIdList *vtkIdListPtr;
  int prod, numOctants;

  if ( this->Tree != NULL && this->SubDivideTime > this->MTime ) return;

  vtkDebugMacro( << "Subdividing octree..." );

  if ( !this->DataSet || (numCells = this->DataSet->GetNumberOfCells()) < 1 )
    {
    vtkErrorMacro( << "No cells to subdivide");
    return;
    }
//
//  Make sure the appropriate data is available
//
  if ( this->Tree ) this->FreeSearchStructure();
//
//  Size the root cell.  Initialize cell data structure, compute
//  level and divisions.
//
  bounds = this->DataSet->GetBounds();
  for (i=0; i<6; i++) this->Bounds[i] = bounds[i];

  if ( this->Automatic )
    {
    this->Level = (int) (ceil(log((double)numCells/numCellsInOctant) /
                              (log((double) 8.0))));
    this->Level =(this->Level > this->MaxLevel ? this->MaxLevel : this->Level);
    }

  // compute number of octants and number of divisions
  for (ndivs=1,prod=1,numOctants=1,i=0; i<this->Level; i++)
    {
    ndivs *= 2;
    prod *= 8;
    numOctants += prod;
    }
  this->NumberOfDivisions = ndivs;
  this->NumberOfOctants = numOctants;

  this->Tree = new vtkIdListPtr[numOctants];
  memset (this->Tree, (int)NULL, numOctants*sizeof(vtkIdListPtr));
//
//  Compute width of leaf octant in three directions
//
  for (i=0; i<3; i++) this->H[i] = (bounds[2*i+1] - bounds[2*i]) / ndivs;
//
//  Insert each cell into the appropriate octant.  Make sure cell
//  falls within octant.
//
  parentOffset = numOctants - (ndivs * ndivs * ndivs);
  product = ndivs * ndivs;
  for (cellId=0; cellId<numCells; cellId++)
    {
    cell = this->DataSet->GetCell(cellId);
    cellBounds = cell->GetBounds();

    // find min/max locations of bounding box
    for (i=0; i<3; i++)
      {
      ijkMin[i] = (int) ((float) ((cellBounds[2*i] - bounds[2*i])*0.999 /
                         (bounds[2*i+1] - bounds[2*i])) * ndivs);
      ijkMax[i] = (int) ((float) ((cellBounds[2*i+1] - bounds[2*i])*0.999 /
                         (bounds[2*i+1] - bounds[2*i])) * ndivs);
      }

    // each octant inbetween min/max point may have cell in it
    for ( k = ijkMin[2]; k <= ijkMin[2]; k++ )
      {
      for ( j = ijkMin[1]; j <= ijkMax[1]; j++ )
        {
        for ( i = ijkMin[0]; i <= ijkMin[0]; i++ )
          {
          this->MarkParents((void*)INSIDE,i,j,k);
          idx = parentOffset + i + j*ndivs + k*product;
          octant = this->Tree[idx];
          if ( ! octant )
            {
            octant = new vtkIdList(numCellsInOctant);
            this->Tree[idx] = octant;
            }
          octant->InsertNextId(cellId);
          }
        }
      }

    } //for all cells

  this->SubDivideTime.Modified();
}

void vtkCellLocator::MarkParents(void* a, int i, int j, int k)
{
  // will's code
}

<|endoftext|>


<commit_before>// Copyright 2012 Bifrost Entertainment. All rights reserved.

#include <cstdlib>
#include <cstring>

#include "Config.h"
#include "Common/Data.h"

Config::Config() : accelerometer(true), width(0), height(0)
{
	const char *const path = Data::get_path("config");
	Data config(path);
	Data::free(path);
	if (!config)
		return;

	unsigned int length = 0;
	const char *line = config;
	for (const char *i = line; *i; ++i)
	{
		if (*i == '\n')
		{
			if (!length)
				continue;

			this->parse_accelerometer(line, length)
			|| this->parse_resolution(line, length);

			line = i + 1;
			length = 0;
		}
		else
			++length;
	}
}

bool Config::keycmp(const char *line, const char *key)
{
	if (strlen(line) < strlen(key))
		return false;
	for (; *key; ++key, ++line)
		if (*line != *key)
			return false;
	return true;
}

bool Config::parse_accelerometer(const char *line, const unsigned int length)
{
	static const char *key = "accelerometer";

	if (length < 16 || !keycmp(line, key))
		return false;

	this->accelerometer = (line[15] != '0');
	return true;
}

bool Config::parse_resolution(const char *line, const unsigned int length)
{
	static const char *key = "resolution";

	if (length < 19 || !keycmp(line, key))
		return false;
	line += 12;

	const char *h = line;
	for (; *h && *h != 'x'; ++h);
	if (*h != '\0' && *(++h) != '\0')
	{
		this->width = atoi(line);
		this->height = atoi(h);
	}
	return true;
}
<commit_msg>Don't attempt to load config file if it doesn't exist.<commit_after>// Copyright 2012 Bifrost Entertainment. All rights reserved.

#include <cstdlib>
#include <cstring>

#include "Config.h"
#include "Common/Data.h"

Config::Config() : accelerometer(true), width(0), height(0)
{
	const char *const path = Data::get_path("config");
	if (!path)
		return;

	Data config(path);
	Data::free(path);
	if (!config)
		return;

	unsigned int length = 0;
	const char *line = config;
	for (const char *i = line; *i; ++i)
	{
		if (*i == '\n')
		{
			if (!length)
				continue;

			this->parse_accelerometer(line, length)
			|| this->parse_resolution(line, length);

			line = i + 1;
			length = 0;
		}
		else
			++length;
	}
}

bool Config::keycmp(const char *line, const char *key)
{
	if (strlen(line) < strlen(key))
		return false;
	for (; *key; ++key, ++line)
		if (*line != *key)
			return false;
	return true;
}

bool Config::parse_accelerometer(const char *line, const unsigned int length)
{
	static const char *key = "accelerometer";

	if (length < 16 || !keycmp(line, key))
		return false;

	this->accelerometer = (line[15] != '0');
	return true;
}

bool Config::parse_resolution(const char *line, const unsigned int length)
{
	static const char *key = "resolution";

	if (length < 19 || !keycmp(line, key))
		return false;
	line += 12;

	const char *h = line;
	for (; *h && *h != 'x'; ++h);
	if (*h != '\0' && *(++h) != '\0')
	{
		this->width = atoi(line);
		this->height = atoi(h);
	}
	return true;
}
<|endoftext|>


<commit_before>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (info@qt.nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at info@qt.nokia.com.
**
**************************************************************************/

#include "abstractmsvctoolchain.h"

#include "msvcparser.h"

#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/projectexplorersettings.h>
#include <projectexplorer/gcctoolchain.h>

#include <utils/fileutils.h>
#include <utils/qtcprocess.h>
#include <utils/synchronousprocess.h>

#include <QFileInfo>
#include <QDir>
#include <QTemporaryFile>

enum { debug = 0 };

namespace ProjectExplorer {
namespace Internal {

AbstractMsvcToolChain::AbstractMsvcToolChain(const QString &id,
                                             bool autodetect,
                                             const Abi &abi,
                                             const QString& vcvarsBat) :
    ToolChain(id, autodetect),
    m_lastEnvironment(Utils::Environment::systemEnvironment()),
    m_abi(abi),
    m_vcvarsBat(vcvarsBat)
{
    Q_ASSERT(abi.os() == Abi::WindowsOS);
    Q_ASSERT(abi.binaryFormat() == Abi::PEFormat);
    Q_ASSERT(abi.osFlavor() != Abi::WindowsMSysFlavor);
    Q_ASSERT(!m_vcvarsBat.isEmpty());
}

AbstractMsvcToolChain::AbstractMsvcToolChain(const QString &id, bool autodetect) :
    ToolChain(id, autodetect),
    m_lastEnvironment(Utils::Environment::systemEnvironment())
{

}

Abi AbstractMsvcToolChain::targetAbi() const
{
    return m_abi;
}

bool AbstractMsvcToolChain::isValid() const
{
    return !m_vcvarsBat.isEmpty();
}

QByteArray AbstractMsvcToolChain::predefinedMacros(const QStringList &cxxflags) const
{
    if (m_predefinedMacros.isEmpty()) {
        Utils::Environment env(m_lastEnvironment);
        addToEnvironment(env);
        m_predefinedMacros = msvcPredefinedMacros(cxxflags, env);
    }
    return m_predefinedMacros;
}

ToolChain::CompilerFlags AbstractMsvcToolChain::compilerFlags(const QStringList &cxxflags) const
{
    Q_UNUSED(cxxflags);
    return NO_FLAGS;
}

QList<HeaderPath> AbstractMsvcToolChain::systemHeaderPaths() const
{
    if (m_headerPaths.isEmpty()) {
        Utils::Environment env(m_lastEnvironment);
        addToEnvironment(env);
        foreach (const QString &path, env.value(QLatin1String("INCLUDE")).split(QLatin1Char(';')))
            m_headerPaths.append(HeaderPath(path, HeaderPath::GlobalHeaderPath));
    }
    return m_headerPaths;
}

void AbstractMsvcToolChain::addToEnvironment(Utils::Environment &env) const
{
    // We cache the full environment (incoming + modifications by setup script).
    if (!m_resultEnvironment.size() || env != m_lastEnvironment) {
        if (debug)
            qDebug() << "addToEnvironment: " << displayName();
        m_lastEnvironment = env;
        m_resultEnvironment = readEnvironmentSetting(env);
    }
    env = m_resultEnvironment;
}

QString AbstractMsvcToolChain::makeCommand() const
{
    if (ProjectExplorerPlugin::instance()->projectExplorerSettings().useJom) {
        return findInstalledJom();
    }
    return QLatin1String("nmake.exe");
}

void AbstractMsvcToolChain::setDebuggerCommand(const Utils::FileName &d)
{
    if (m_debuggerCommand == d)
        return;
    m_debuggerCommand = d;
    toolChainUpdated();
}

Utils::FileName AbstractMsvcToolChain::compilerCommand() const
{
    Utils::Environment env;
    addToEnvironment(env);
    return Utils::FileName::fromString(env.searchInPath("cl.exe"));
}

Utils::FileName AbstractMsvcToolChain::debuggerCommand() const
{
    return m_debuggerCommand;
}

IOutputParser *AbstractMsvcToolChain::outputParser() const
{
    return new MsvcParser;
}

bool AbstractMsvcToolChain::canClone() const
{
    return true;
}

QByteArray AbstractMsvcToolChain::msvcPredefinedMacros(const QStringList cxxflags,
                                                       const Utils::Environment& env) const
{
    Q_UNUSED(cxxflags);
    Q_UNUSED(env);

    QByteArray predefinedMacros = "#define __MSVCRT__\n"
            "#define __w64\n"
            "#define __int64 long long\n"
            "#define __int32 long\n"
            "#define __int16 short\n"
            "#define __int8 char\n"
            "#define __ptr32\n"
            "#define __ptr64\n";

    return predefinedMacros;
}

bool AbstractMsvcToolChain::generateEnvironmentSettings(Utils::Environment &env,
                                                        const QString& batchFile,
                                                        const QString& batchArgs,
                                                        QMap<QString, QString>& envPairs) const
{
    // Create a temporary file name for the output. Use a temporary file here
    // as I don't know another way to do this in Qt...
    // Note, can't just use a QTemporaryFile all the way through as it remains open
    // internally so it can't be streamed to later.
    QString tempOutFile;
    QTemporaryFile* pVarsTempFile = new QTemporaryFile(QDir::tempPath() + QLatin1String("/XXXXXX.txt"));
    pVarsTempFile->setAutoRemove(false);
    pVarsTempFile->open();
    pVarsTempFile->close();
    tempOutFile = pVarsTempFile->fileName();
    delete pVarsTempFile;

    // Create a batch file to create and save the env settings
    Utils::TempFileSaver saver(QDir::tempPath() + QLatin1String("/XXXXXX.bat"));

    QByteArray call = "call ";
    call += Utils::QtcProcess::quoteArg(batchFile).toLocal8Bit() + "\r\n";
    if (!batchArgs.isEmpty()) {
        call += ' ';
        call += batchArgs.toLocal8Bit();
    }
    call += "\r\n";

    saver.write(call);
    const QByteArray redirect = "set > " + Utils::QtcProcess::quoteArg(
                                    QDir::toNativeSeparators(tempOutFile)).toLocal8Bit() + "\r\n";
    saver.write(redirect);
    if (!saver.finalize()) {
        qWarning("%s: %s", Q_FUNC_INFO, qPrintable(saver.errorString()));
        return false;
    }

    Utils::QtcProcess run;
    // As of WinSDK 7.1, there is logic preventing the path from being set
    // correctly if "ORIGINALPATH" is already set. That can cause problems
    // if Creator is launched within a session set up by setenv.cmd.
    env.unset(QLatin1String("ORIGINALPATH"));
    run.setEnvironment(env);
    const QString cmdPath = QString::fromLocal8Bit(qgetenv("COMSPEC"));
    // Windows SDK setup scripts require command line switches for environment expansion.
    QString cmdArguments = QLatin1String(" /E:ON /V:ON /c \"");
    cmdArguments += QDir::toNativeSeparators(saver.fileName());
    cmdArguments += QLatin1Char('"');
    run.setCommand(cmdPath, cmdArguments);
    if (debug)
        qDebug() << "readEnvironmentSetting: " << call << cmdPath << cmdArguments
                 << " Env: " << env.size();
    run.start();

    if (!run.waitForStarted()) {
        qWarning("%s: Unable to run '%s': %s", Q_FUNC_INFO, qPrintable(m_vcvarsBat),
                 qPrintable(run.errorString()));
        return false;
    }
    if (!run.waitForFinished()) {
        qWarning("%s: Timeout running '%s'", Q_FUNC_INFO, qPrintable(m_vcvarsBat));
        Utils::SynchronousProcess::stopProcess(run);
        return false;
    }

    //
    // Now parse the file to get the environment settings
    QFile varsFile(tempOutFile);
    if (!varsFile.open(QIODevice::ReadOnly))
        return false;

    QRegExp regexp(QLatin1String("(\\w*)=(.*)"));
    while (!varsFile.atEnd()) {
        const QString line = QString::fromLocal8Bit(varsFile.readLine()).trimmed();
        if (regexp.exactMatch(line)) {
            const QString varName = regexp.cap(1);
            const QString varValue = regexp.cap(2);

            if (!varValue.isEmpty())
                envPairs.insert(varName, varValue);
        }
    }

    // Tidy up and remove the file
    varsFile.close();
    varsFile.remove();

    return true;
}

QString AbstractMsvcToolChain::findInstalledJom()
{
    if (Abi::hostAbi().os() != Abi::WindowsOS) {
        qWarning() << "Jom can only be used on Windows";
        return QString();
    }

    // We want jom! Try to find it.
    const QString jom = QLatin1String("jom.exe");
    const QFileInfo installedJom = QFileInfo(QCoreApplication::applicationDirPath()
                                             + QLatin1Char('/') + jom);
    if (installedJom.isFile() && installedJom.isExecutable())
        return installedJom.absoluteFilePath();
    else
        return jom;
}

bool AbstractMsvcToolChain::operator ==(const ToolChain &other) const
{
    if (!ToolChain::operator ==(other))
        return false;

    const AbstractMsvcToolChain *msvcTc = static_cast<const AbstractMsvcToolChain *>(&other);
    return targetAbi() == msvcTc->targetAbi()
            && m_debuggerCommand == msvcTc->m_debuggerCommand
            && m_vcvarsBat == msvcTc->m_vcvarsBat;
}

} // namespace Internal
} // namespace ProjectExplorer

<commit_msg>MSVC: Fix env retrieval<commit_after>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (info@qt.nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at info@qt.nokia.com.
**
**************************************************************************/

#include "abstractmsvctoolchain.h"

#include "msvcparser.h"

#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/projectexplorersettings.h>
#include <projectexplorer/gcctoolchain.h>

#include <utils/fileutils.h>
#include <utils/qtcprocess.h>
#include <utils/synchronousprocess.h>

#include <QFileInfo>
#include <QDir>
#include <QTemporaryFile>

enum { debug = 0 };

namespace ProjectExplorer {
namespace Internal {

AbstractMsvcToolChain::AbstractMsvcToolChain(const QString &id,
                                             bool autodetect,
                                             const Abi &abi,
                                             const QString& vcvarsBat) :
    ToolChain(id, autodetect),
    m_lastEnvironment(Utils::Environment::systemEnvironment()),
    m_abi(abi),
    m_vcvarsBat(vcvarsBat)
{
    Q_ASSERT(abi.os() == Abi::WindowsOS);
    Q_ASSERT(abi.binaryFormat() == Abi::PEFormat);
    Q_ASSERT(abi.osFlavor() != Abi::WindowsMSysFlavor);
    Q_ASSERT(!m_vcvarsBat.isEmpty());
}

AbstractMsvcToolChain::AbstractMsvcToolChain(const QString &id, bool autodetect) :
    ToolChain(id, autodetect),
    m_lastEnvironment(Utils::Environment::systemEnvironment())
{

}

Abi AbstractMsvcToolChain::targetAbi() const
{
    return m_abi;
}

bool AbstractMsvcToolChain::isValid() const
{
    return !m_vcvarsBat.isEmpty();
}

QByteArray AbstractMsvcToolChain::predefinedMacros(const QStringList &cxxflags) const
{
    if (m_predefinedMacros.isEmpty()) {
        Utils::Environment env(m_lastEnvironment);
        addToEnvironment(env);
        m_predefinedMacros = msvcPredefinedMacros(cxxflags, env);
    }
    return m_predefinedMacros;
}

ToolChain::CompilerFlags AbstractMsvcToolChain::compilerFlags(const QStringList &cxxflags) const
{
    Q_UNUSED(cxxflags);
    return NO_FLAGS;
}

QList<HeaderPath> AbstractMsvcToolChain::systemHeaderPaths() const
{
    if (m_headerPaths.isEmpty()) {
        Utils::Environment env(m_lastEnvironment);
        addToEnvironment(env);
        foreach (const QString &path, env.value(QLatin1String("INCLUDE")).split(QLatin1Char(';')))
            m_headerPaths.append(HeaderPath(path, HeaderPath::GlobalHeaderPath));
    }
    return m_headerPaths;
}

void AbstractMsvcToolChain::addToEnvironment(Utils::Environment &env) const
{
    // We cache the full environment (incoming + modifications by setup script).
    if (!m_resultEnvironment.size() || env != m_lastEnvironment) {
        if (debug)
            qDebug() << "addToEnvironment: " << displayName();
        m_lastEnvironment = env;
        m_resultEnvironment = readEnvironmentSetting(env);
    }
    env = m_resultEnvironment;
}

QString AbstractMsvcToolChain::makeCommand() const
{
    if (ProjectExplorerPlugin::instance()->projectExplorerSettings().useJom) {
        return findInstalledJom();
    }
    return QLatin1String("nmake.exe");
}

void AbstractMsvcToolChain::setDebuggerCommand(const Utils::FileName &d)
{
    if (m_debuggerCommand == d)
        return;
    m_debuggerCommand = d;
    toolChainUpdated();
}

Utils::FileName AbstractMsvcToolChain::compilerCommand() const
{
    Utils::Environment env;
    addToEnvironment(env);
    return Utils::FileName::fromString(env.searchInPath("cl.exe"));
}

Utils::FileName AbstractMsvcToolChain::debuggerCommand() const
{
    return m_debuggerCommand;
}

IOutputParser *AbstractMsvcToolChain::outputParser() const
{
    return new MsvcParser;
}

bool AbstractMsvcToolChain::canClone() const
{
    return true;
}

QByteArray AbstractMsvcToolChain::msvcPredefinedMacros(const QStringList cxxflags,
                                                       const Utils::Environment& env) const
{
    Q_UNUSED(cxxflags);
    Q_UNUSED(env);

    QByteArray predefinedMacros = "#define __MSVCRT__\n"
            "#define __w64\n"
            "#define __int64 long long\n"
            "#define __int32 long\n"
            "#define __int16 short\n"
            "#define __int8 char\n"
            "#define __ptr32\n"
            "#define __ptr64\n";

    return predefinedMacros;
}

bool AbstractMsvcToolChain::generateEnvironmentSettings(Utils::Environment &env,
                                                        const QString& batchFile,
                                                        const QString& batchArgs,
                                                        QMap<QString, QString>& envPairs) const
{
    // Create a temporary file name for the output. Use a temporary file here
    // as I don't know another way to do this in Qt...
    // Note, can't just use a QTemporaryFile all the way through as it remains open
    // internally so it can't be streamed to later.
    QString tempOutFile;
    QTemporaryFile* pVarsTempFile = new QTemporaryFile(QDir::tempPath() + QLatin1String("/XXXXXX.txt"));
    pVarsTempFile->setAutoRemove(false);
    pVarsTempFile->open();
    pVarsTempFile->close();
    tempOutFile = pVarsTempFile->fileName();
    delete pVarsTempFile;

    // Create a batch file to create and save the env settings
    Utils::TempFileSaver saver(QDir::tempPath() + QLatin1String("/XXXXXX.bat"));

    QByteArray call = "call ";
    call += Utils::QtcProcess::quoteArg(batchFile).toLocal8Bit();
    if (!batchArgs.isEmpty()) {
        call += ' ';
        call += batchArgs.toLocal8Bit();
    }
    call += "\r\n";

    saver.write(call);
    const QByteArray redirect = "set > " + Utils::QtcProcess::quoteArg(
                                    QDir::toNativeSeparators(tempOutFile)).toLocal8Bit() + "\r\n";
    saver.write(redirect);
    if (!saver.finalize()) {
        qWarning("%s: %s", Q_FUNC_INFO, qPrintable(saver.errorString()));
        return false;
    }

    Utils::QtcProcess run;
    // As of WinSDK 7.1, there is logic preventing the path from being set
    // correctly if "ORIGINALPATH" is already set. That can cause problems
    // if Creator is launched within a session set up by setenv.cmd.
    env.unset(QLatin1String("ORIGINALPATH"));
    run.setEnvironment(env);
    const QString cmdPath = QString::fromLocal8Bit(qgetenv("COMSPEC"));
    // Windows SDK setup scripts require command line switches for environment expansion.
    QString cmdArguments = QLatin1String(" /E:ON /V:ON /c \"");
    cmdArguments += QDir::toNativeSeparators(saver.fileName());
    cmdArguments += QLatin1Char('"');
    run.setCommand(cmdPath, cmdArguments);
    if (debug)
        qDebug() << "readEnvironmentSetting: " << call << cmdPath << cmdArguments
                 << " Env: " << env.size();
    run.start();

    if (!run.waitForStarted()) {
        qWarning("%s: Unable to run '%s': %s", Q_FUNC_INFO, qPrintable(m_vcvarsBat),
                 qPrintable(run.errorString()));
        return false;
    }
    if (!run.waitForFinished()) {
        qWarning("%s: Timeout running '%s'", Q_FUNC_INFO, qPrintable(m_vcvarsBat));
        Utils::SynchronousProcess::stopProcess(run);
        return false;
    }

    //
    // Now parse the file to get the environment settings
    QFile varsFile(tempOutFile);
    if (!varsFile.open(QIODevice::ReadOnly))
        return false;

    QRegExp regexp(QLatin1String("(\\w*)=(.*)"));
    while (!varsFile.atEnd()) {
        const QString line = QString::fromLocal8Bit(varsFile.readLine()).trimmed();
        if (regexp.exactMatch(line)) {
            const QString varName = regexp.cap(1);
            const QString varValue = regexp.cap(2);

            if (!varValue.isEmpty())
                envPairs.insert(varName, varValue);
        }
    }

    // Tidy up and remove the file
    varsFile.close();
    varsFile.remove();

    return true;
}

QString AbstractMsvcToolChain::findInstalledJom()
{
    if (Abi::hostAbi().os() != Abi::WindowsOS) {
        qWarning() << "Jom can only be used on Windows";
        return QString();
    }

    // We want jom! Try to find it.
    const QString jom = QLatin1String("jom.exe");
    const QFileInfo installedJom = QFileInfo(QCoreApplication::applicationDirPath()
                                             + QLatin1Char('/') + jom);
    if (installedJom.isFile() && installedJom.isExecutable())
        return installedJom.absoluteFilePath();
    else
        return jom;
}

bool AbstractMsvcToolChain::operator ==(const ToolChain &other) const
{
    if (!ToolChain::operator ==(other))
        return false;

    const AbstractMsvcToolChain *msvcTc = static_cast<const AbstractMsvcToolChain *>(&other);
    return targetAbi() == msvcTc->targetAbi()
            && m_debuggerCommand == msvcTc->m_debuggerCommand
            && m_vcvarsBat == msvcTc->m_vcvarsBat;
}

} // namespace Internal
} // namespace ProjectExplorer

<|endoftext|>