<commit_before>////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Jan Steemann
////////////////////////////////////////////////////////////////////////////////

#include "PathBasedIndex.h"
#include "Aql/AstNode.h"
#include "Basics/Logger.h"

#include <velocypack/Iterator.h>
#include <velocypack/velocypack-aliases.h>

using namespace arangodb;

arangodb::aql::AstNode const* PathBasedIndex::PermutationState::getValue()
    const {
  if (type == arangodb::aql::NODE_TYPE_OPERATOR_BINARY_EQ) {
    TRI_ASSERT(current == 0);
    return value;
  } else if (type == arangodb::aql::NODE_TYPE_OPERATOR_BINARY_IN) {
    TRI_ASSERT(n > 0);
    TRI_ASSERT(current < n);
    return value->getMember(current);
  }

  TRI_ASSERT(false);
  return nullptr;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief create the index
////////////////////////////////////////////////////////////////////////////////

PathBasedIndex::PathBasedIndex(
    TRI_idx_iid_t iid, TRI_document_collection_t* collection,
    std::vector<std::vector<arangodb::basics::AttributeName>> const& fields,
    bool unique, bool sparse, bool allowPartialIndex)
    : Index(iid, collection, fields, unique, sparse),
      _useExpansion(false),
      _allowPartialIndex(allowPartialIndex) {
  TRI_ASSERT(!fields.empty());

  TRI_ASSERT(iid != 0);

  fillPaths(_paths, _expanding);

  for (auto const& it : fields) {
    if (TRI_AttributeNamesHaveExpansion(it)) {
      _useExpansion = true;
      break;
    }
  }
}

////////////////////////////////////////////////////////////////////////////////
/// @brief create an index stub with a hard-coded selectivity estimate
/// this is used in the cluster coordinator case
////////////////////////////////////////////////////////////////////////////////

PathBasedIndex::PathBasedIndex(VPackSlice const& slice, bool allowPartialIndex)
    : Index(slice),
      _paths(),
      _useExpansion(false),
      _allowPartialIndex(allowPartialIndex) {
  TRI_ASSERT(!_fields.empty());

  for (auto const& it : _fields) {
    if (TRI_AttributeNamesHaveExpansion(it)) {
      _useExpansion = true;
      break;
    }
  }
}

////////////////////////////////////////////////////////////////////////////////
/// @brief destroy the index
////////////////////////////////////////////////////////////////////////////////

PathBasedIndex::~PathBasedIndex() {}

////////////////////////////////////////////////////////////////////////////////
/// @brief helper function to insert a document into any index type
////////////////////////////////////////////////////////////////////////////////

int PathBasedIndex::fillElement(std::vector<TRI_index_element_t*>& elements,
                                TRI_doc_mptr_t const* document) {
  TRI_ASSERT(document != nullptr);
  TRI_ASSERT(document->getDataPtr() != nullptr);

  VPackSlice const slice(document->vpack());

  if (slice.isNone()) {
    LOG(WARN) << "encountered invalid marker with slice of type None";

    return TRI_ERROR_INTERNAL;
  }

  TRI_IF_FAILURE("FillElementIllegalSlice") { return TRI_ERROR_INTERNAL; }

  size_t const n = _paths.size();

  if (!_useExpansion) {
    // fast path for inserts... no array elements used
    auto slices = buildIndexValue(slice);

    if (slices.size() == n) {
      // if shapes.size() != n, then the value is not inserted into the index
      // because of index sparsity!
      TRI_index_element_t* element = TRI_index_element_t::allocate(n);
      if (element == nullptr) {
        return TRI_ERROR_OUT_OF_MEMORY;
      }
      TRI_IF_FAILURE("FillElementOOM") {
        // clean up manually
        TRI_index_element_t::freeElement(element);
        return TRI_ERROR_OUT_OF_MEMORY;
      }

      element->document(const_cast<TRI_doc_mptr_t*>(document));
      TRI_vpack_sub_t* subObjects = element->subObjects();

      for (size_t i = 0; i < n; ++i) {
        TRI_FillVPackSub(&subObjects[i], slice, slices[i]);
      }

      try {
        TRI_IF_FAILURE("FillElementOOM2") {
          THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
        }

        elements.emplace_back(element);
      } catch (...) {
        TRI_index_element_t::freeElement(element);
        return TRI_ERROR_OUT_OF_MEMORY;
      }
    }
  } else {
    // other path for handling array elements, too
    std::vector<std::vector<VPackSlice>> toInsert;
    std::vector<VPackSlice> sliceStack;

    buildIndexValues(slice, 0, toInsert, sliceStack);

    if (!toInsert.empty()) {
      elements.reserve(toInsert.size());

      for (auto& info : toInsert) {
        TRI_ASSERT(info.size() == n);
        TRI_index_element_t* element = TRI_index_element_t::allocate(n);

        if (element == nullptr) {
          return TRI_ERROR_OUT_OF_MEMORY;
        }
        TRI_IF_FAILURE("FillElementOOM") {
          // clean up manually
          TRI_index_element_t::freeElement(element);
          return TRI_ERROR_OUT_OF_MEMORY;
        }

        element->document(const_cast<TRI_doc_mptr_t*>(document));
        TRI_vpack_sub_t* subObjects = element->subObjects();

        for (size_t j = 0; j < n; ++j) {
          TRI_FillVPackSub(&subObjects[j], slice, info[j]);
        }

        try {
          TRI_IF_FAILURE("FillElementOOM2") {
            THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
          }

          elements.emplace_back(element);
        } catch (...) {
          TRI_index_element_t::freeElement(element);
          return TRI_ERROR_OUT_OF_MEMORY;
        }
      }
    }
  }

  return TRI_ERROR_NO_ERROR;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief helper function to create the sole index value insert
////////////////////////////////////////////////////////////////////////////////

std::vector<VPackSlice> PathBasedIndex::buildIndexValue(
    VPackSlice const documentSlice) {
  size_t const n = _paths.size();

  std::vector<VPackSlice> result;
  for (size_t i = 0; i < n; ++i) {
    TRI_ASSERT(!_paths[i].empty());

    VPackSlice slice = documentSlice.get(_paths[i]);
    if (slice.isNone()) {
      // attribute not found
      if (_sparse) {
        // if sparse we do not have to index, this is indicated by result
        // being shorter than n
        result.clear();
        break;
      }
      slice.set(reinterpret_cast<uint8_t const*>("\0x18"));
        // null, note that this will be copied later!
    }
    result.push_back(slice);
  }
  return result;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief helper function to create a set of index combinations to insert
////////////////////////////////////////////////////////////////////////////////

void PathBasedIndex::buildIndexValues(
    VPackSlice const document, size_t level,
    std::vector<std::vector<VPackSlice>>& toInsert,
    std::vector<VPackSlice>& sliceStack) {
  // Invariant: level == sliceStack.size()

  // Stop the recursion:
  if (level == _paths.size()) {
    toInsert.push_back(sliceStack);
    return;
  }

  if (_expanding[level] == -1) {   // the trivial, non-expanding case
    VPackSlice slice = document.get(_paths[level]);
    if (slice.isNone()) {
      if (_sparse) {
        return;
      }
      slice.set(reinterpret_cast<uint8_t const*>("\0x18"));   // null
    }
    sliceStack.push_back(slice);
    buildIndexValues(document, level+1, toInsert, sliceStack);
    sliceStack.pop_back();
    return;
  }

  // Finally, the complex case, where we have to expand one entry.
  // Note again that at most one step in the attribute path can be
  // an array step. Furthermore, if _allowPartialIndex is true and
  // anything goes wrong with this attribute path, we have to bottom out
  // with None values to be able to use the index for a prefix match.

  auto finishWithNones = [&]() -> void {
    if (level > 0 && !_allowPartialIndex) {
      return;
    }
    // Trivial case to bottom out with None types.
    VPackSlice noneSlice;
    for (size_t i = level; i < _paths.size(); i++) {
      sliceStack.push_back(noneSlice);
    }
    toInsert.push_back(sliceStack);
    for (size_t i = level; i < _paths.size(); i++) {
      sliceStack.pop_back();
    }
  };
  size_t const n = _paths[level].size();
  // We have 0 <= _expanding[level] < n.
  VPackSlice current(document);
  for (size_t i = 0; i <= static_cast<size_t>(_expanding[level]); i++) {
    if (!current.isObject()) {
      finishWithNones();
      return;
    }
    current = current.get(_paths[level][i]);
    if (current.isNone()) {
      finishWithNones();
      return;
    }
  }
  // Now the expansion:
  if (!current.isArray() || current.length() == 0) {
    finishWithNones();
    return;
  }
  std::unordered_set<VPackSlice> seen;
  auto moveOn = [&](VPackSlice something) -> void {
    auto it = seen.find(something);
    if (it != seen.end()) {
      seen.insert(something);
      sliceStack.push_back(something);
      buildIndexValues(document, level+1, toInsert, sliceStack);
      sliceStack.pop_back();
    }
  };
  VPackSlice null("\x18");
  for (auto const& member : VPackArrayIterator(current)) {
    VPackSlice current2(member);
    bool doneNull = false;
    for (size_t i = _expanding[level]+1; i < n; i++) {
      if (!current2.isObject()) {
        if (!_sparse) {
          moveOn(null);
        }
        doneNull = true;
        break;
      }
      current2 = current2.get(_paths[level][i]);
      if (current2.isNone()) {
        if (!_sparse) {
          moveOn(null);
        }
        doneNull = true;
        break;
      }
    }
    if (!doneNull) {
      moveOn(current2);
    }
  }
}

////////////////////////////////////////////////////////////////////////////////
/// @brief helper function to transform AttributeNames into strings.
////////////////////////////////////////////////////////////////////////////////

void PathBasedIndex::fillPaths(std::vector<std::vector<std::string>>& paths,
                               std::vector<int>& expanding) {
  paths.clear();
  expanding.clear();
  for (std::vector<arangodb::basics::AttributeName> const& list : _fields) {
    paths.emplace_back();
    std::vector<std::string>& interior(paths.back());
    int expands = -1;
    int count = 0;
    std::vector<std::string> joinedNames;
    for (auto const& att : list) {
      interior.push_back(att.name);
      if (att.shouldExpand) {
        expands = count;
      }
      ++count;
    }
    expanding.push_back(expands);
  }
}
<commit_msg>Fix buildIndexValues.<commit_after>////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Jan Steemann
////////////////////////////////////////////////////////////////////////////////

#include "PathBasedIndex.h"
#include "Aql/AstNode.h"
#include "Basics/Logger.h"

#include <velocypack/Iterator.h>
#include <velocypack/velocypack-aliases.h>

using namespace arangodb;

arangodb::aql::AstNode const* PathBasedIndex::PermutationState::getValue()
    const {
  if (type == arangodb::aql::NODE_TYPE_OPERATOR_BINARY_EQ) {
    TRI_ASSERT(current == 0);
    return value;
  } else if (type == arangodb::aql::NODE_TYPE_OPERATOR_BINARY_IN) {
    TRI_ASSERT(n > 0);
    TRI_ASSERT(current < n);
    return value->getMember(current);
  }

  TRI_ASSERT(false);
  return nullptr;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief create the index
////////////////////////////////////////////////////////////////////////////////

PathBasedIndex::PathBasedIndex(
    TRI_idx_iid_t iid, TRI_document_collection_t* collection,
    std::vector<std::vector<arangodb::basics::AttributeName>> const& fields,
    bool unique, bool sparse, bool allowPartialIndex)
    : Index(iid, collection, fields, unique, sparse),
      _useExpansion(false),
      _allowPartialIndex(allowPartialIndex) {
  TRI_ASSERT(!fields.empty());

  TRI_ASSERT(iid != 0);

  fillPaths(_paths, _expanding);

  for (auto const& it : fields) {
    if (TRI_AttributeNamesHaveExpansion(it)) {
      _useExpansion = true;
      break;
    }
  }
}

////////////////////////////////////////////////////////////////////////////////
/// @brief create an index stub with a hard-coded selectivity estimate
/// this is used in the cluster coordinator case
////////////////////////////////////////////////////////////////////////////////

PathBasedIndex::PathBasedIndex(VPackSlice const& slice, bool allowPartialIndex)
    : Index(slice),
      _paths(),
      _useExpansion(false),
      _allowPartialIndex(allowPartialIndex) {
  TRI_ASSERT(!_fields.empty());

  for (auto const& it : _fields) {
    if (TRI_AttributeNamesHaveExpansion(it)) {
      _useExpansion = true;
      break;
    }
  }
}

////////////////////////////////////////////////////////////////////////////////
/// @brief destroy the index
////////////////////////////////////////////////////////////////////////////////

PathBasedIndex::~PathBasedIndex() {}

////////////////////////////////////////////////////////////////////////////////
/// @brief helper function to insert a document into any index type
////////////////////////////////////////////////////////////////////////////////

int PathBasedIndex::fillElement(std::vector<TRI_index_element_t*>& elements,
                                TRI_doc_mptr_t const* document) {
  TRI_ASSERT(document != nullptr);
  TRI_ASSERT(document->getDataPtr() != nullptr);

  VPackSlice const slice(document->vpack());

  if (slice.isNone()) {
    LOG(WARN) << "encountered invalid marker with slice of type None";

    return TRI_ERROR_INTERNAL;
  }

  TRI_IF_FAILURE("FillElementIllegalSlice") { return TRI_ERROR_INTERNAL; }

  size_t const n = _paths.size();

  if (!_useExpansion) {
    // fast path for inserts... no array elements used
    auto slices = buildIndexValue(slice);

    if (slices.size() == n) {
      // if shapes.size() != n, then the value is not inserted into the index
      // because of index sparsity!
      TRI_index_element_t* element = TRI_index_element_t::allocate(n);
      if (element == nullptr) {
        return TRI_ERROR_OUT_OF_MEMORY;
      }
      TRI_IF_FAILURE("FillElementOOM") {
        // clean up manually
        TRI_index_element_t::freeElement(element);
        return TRI_ERROR_OUT_OF_MEMORY;
      }

      element->document(const_cast<TRI_doc_mptr_t*>(document));
      TRI_vpack_sub_t* subObjects = element->subObjects();

      for (size_t i = 0; i < n; ++i) {
        TRI_FillVPackSub(&subObjects[i], slice, slices[i]);
      }

      try {
        TRI_IF_FAILURE("FillElementOOM2") {
          THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
        }

        elements.emplace_back(element);
      } catch (...) {
        TRI_index_element_t::freeElement(element);
        return TRI_ERROR_OUT_OF_MEMORY;
      }
    }
  } else {
    // other path for handling array elements, too
    std::vector<std::vector<VPackSlice>> toInsert;
    std::vector<VPackSlice> sliceStack;

    buildIndexValues(slice, 0, toInsert, sliceStack);

    if (!toInsert.empty()) {
      elements.reserve(toInsert.size());

      for (auto& info : toInsert) {
        TRI_ASSERT(info.size() == n);
        TRI_index_element_t* element = TRI_index_element_t::allocate(n);

        if (element == nullptr) {
          return TRI_ERROR_OUT_OF_MEMORY;
        }
        TRI_IF_FAILURE("FillElementOOM") {
          // clean up manually
          TRI_index_element_t::freeElement(element);
          return TRI_ERROR_OUT_OF_MEMORY;
        }

        element->document(const_cast<TRI_doc_mptr_t*>(document));
        TRI_vpack_sub_t* subObjects = element->subObjects();

        for (size_t j = 0; j < n; ++j) {
          TRI_FillVPackSub(&subObjects[j], slice, info[j]);
        }

        try {
          TRI_IF_FAILURE("FillElementOOM2") {
            THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
          }

          elements.emplace_back(element);
        } catch (...) {
          TRI_index_element_t::freeElement(element);
          return TRI_ERROR_OUT_OF_MEMORY;
        }
      }
    }
  }

  return TRI_ERROR_NO_ERROR;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief helper function to create the sole index value insert
////////////////////////////////////////////////////////////////////////////////

std::vector<VPackSlice> PathBasedIndex::buildIndexValue(
    VPackSlice const documentSlice) {
  size_t const n = _paths.size();

  std::vector<VPackSlice> result;
  for (size_t i = 0; i < n; ++i) {
    TRI_ASSERT(!_paths[i].empty());

    VPackSlice slice = documentSlice.get(_paths[i]);
    if (slice.isNone()) {
      // attribute not found
      if (_sparse) {
        // if sparse we do not have to index, this is indicated by result
        // being shorter than n
        result.clear();
        break;
      }
      slice.set(reinterpret_cast<uint8_t const*>("\0x18"));
        // null, note that this will be copied later!
    }
    result.push_back(slice);
  }
  return result;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief helper function to create a set of index combinations to insert
////////////////////////////////////////////////////////////////////////////////

void PathBasedIndex::buildIndexValues(
    VPackSlice const document, size_t level,
    std::vector<std::vector<VPackSlice>>& toInsert,
    std::vector<VPackSlice>& sliceStack) {
  // Invariant: level == sliceStack.size()

  // Stop the recursion:
  if (level == _paths.size()) {
    toInsert.push_back(sliceStack);
    return;
  }

  if (_expanding[level] == -1) {   // the trivial, non-expanding case
    VPackSlice slice = document.get(_paths[level]);
    if (slice.isNone()) {
      if (_sparse) {
        return;
      }
      slice.set(reinterpret_cast<uint8_t const*>("\0x18"));   // null
    }
    sliceStack.push_back(slice);
    buildIndexValues(document, level+1, toInsert, sliceStack);
    sliceStack.pop_back();
    return;
  }

  // Finally, the complex case, where we have to expand one entry.
  // Note again that at most one step in the attribute path can be
  // an array step. Furthermore, if _allowPartialIndex is true and
  // anything goes wrong with this attribute path, we have to bottom out
  // with None values to be able to use the index for a prefix match.

  auto finishWithNones = [&]() -> void {
    if (level > 0 && !_allowPartialIndex) {
      return;
    }
    // Trivial case to bottom out with None types.
    VPackSlice noneSlice;
    for (size_t i = level; i < _paths.size(); i++) {
      sliceStack.push_back(noneSlice);
    }
    toInsert.push_back(sliceStack);
    for (size_t i = level; i < _paths.size(); i++) {
      sliceStack.pop_back();
    }
  };
  size_t const n = _paths[level].size();
  // We have 0 <= _expanding[level] < n.
  VPackSlice current(document);
  for (size_t i = 0; i <= static_cast<size_t>(_expanding[level]); i++) {
    if (!current.isObject()) {
      finishWithNones();
      return;
    }
    current = current.get(_paths[level][i]);
    if (current.isNone()) {
      finishWithNones();
      return;
    }
  }
  // Now the expansion:
  if (!current.isArray() || current.length() == 0) {
    finishWithNones();
    return;
  }
  std::unordered_set<VPackSlice> seen;
  auto moveOn = [&](VPackSlice something) -> void {
    auto it = seen.find(something);
    if (it != seen.end()) {
      seen.insert(something);
      sliceStack.push_back(something);
      buildIndexValues(document, level+1, toInsert, sliceStack);
      sliceStack.pop_back();
    }
  };
  VPackSlice null("\x18");
  for (auto const& member : VPackArrayIterator(current)) {
    VPackSlice current2(member);
    bool doneNull = false;
    for (size_t i = _expanding[level]+1; i < n; i++) {
      if (!current2.isObject()) {
        if (!_sparse) {
          moveOn(null);
        }
        doneNull = true;
        break;
      }
      current2 = current2.get(_paths[level][i]);
      if (current2.isNone()) {
        if (!_sparse) {
          moveOn(null);
        }
        doneNull = true;
        break;
      }
    }
    if (!doneNull) {
      moveOn(current2);
    }
    // Finally, if, because of sparsity, we have not inserted anything by now,
    // we need to play the above trick with None because of the above mentioned
    // reasons:
    if (seen.empty()) {
      finishWithNones();
    }
  }
}

////////////////////////////////////////////////////////////////////////////////
/// @brief helper function to transform AttributeNames into strings.
////////////////////////////////////////////////////////////////////////////////

void PathBasedIndex::fillPaths(std::vector<std::vector<std::string>>& paths,
                               std::vector<int>& expanding) {
  paths.clear();
  expanding.clear();
  for (std::vector<arangodb::basics::AttributeName> const& list : _fields) {
    paths.emplace_back();
    std::vector<std::string>& interior(paths.back());
    int expands = -1;
    int count = 0;
    std::vector<std::string> joinedNames;
    for (auto const& att : list) {
      interior.push_back(att.name);
      if (att.shouldExpand) {
        expands = count;
      }
      ++count;
    }
    expanding.push_back(expands);
  }
}
<|endoftext|>


<commit_before>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/registry.h"
#include "base/string_util.h"
#include "chrome/common/win_util.h"
#include "testing/gtest/include/gtest/gtest.h"

class WinUtilTest: public testing::Test {
};

// Retrieve the OS primary language
unsigned GetSystemLanguage() {
  RegKey language_key(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\Nls\\Language");
  std::wstring language;
  language_key.ReadValue(L"InstallLanguage", &language);
  wchar_t * unused_endptr;
  return PRIMARYLANGID(wcstol(language.c_str(), &unused_endptr, 16));
}

TEST(WinUtilTest, FormatMessage) {
  const int kAccessDeniedErrorCode = 5;
  SetLastError(kAccessDeniedErrorCode);
  ASSERT_EQ(GetLastError(), kAccessDeniedErrorCode);
  std::wstring value;

  unsigned language = GetSystemLanguage();
  ASSERT_TRUE(language);
  if (language == LANG_ENGLISH) {
    // This test would fail on non-English system.
    TrimWhitespace(win_util::FormatLastWin32Error(), TRIM_ALL, &value);
    EXPECT_EQ(value, std::wstring(L"Access is denied."));
  } else if (language == LANG_FRENCH) {
    // This test would fail on non-French system.
    TrimWhitespace(win_util::FormatLastWin32Error(), TRIM_ALL, &value);
    EXPECT_EQ(value, std::wstring(L"Acc\00e8s refus\00e9."));
  } else {
    EXPECT_TRUE(0) << "Please implement the test for your OS language.";
  }

  // Manually call the OS function
  wchar_t * string_buffer = NULL;
  unsigned string_length = ::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
                                    FORMAT_MESSAGE_FROM_SYSTEM |
                                    FORMAT_MESSAGE_IGNORE_INSERTS, NULL,
                                    kAccessDeniedErrorCode, 0,
                                    reinterpret_cast<wchar_t *>(&string_buffer),
                                    0, NULL);

  // Verify the call succeeded
  ASSERT_TRUE(string_length);
  ASSERT_TRUE(string_buffer);

  // Verify the string is the same by different calls
  EXPECT_EQ(win_util::FormatLastWin32Error(), std::wstring(string_buffer));
  EXPECT_EQ(win_util::FormatMessage(kAccessDeniedErrorCode),
            std::wstring(string_buffer));

  // Done with the buffer allocated by ::FormatMessage()
  LocalFree(string_buffer);
}

TEST(WinUtilTest, EnsureRectIsVisibleInRect) {
  gfx::Rect parent_rect(0, 0, 500, 400);

  {
    // Child rect x < 0
    gfx::Rect child_rect(-50, 20, 100, 100);
    win_util::EnsureRectIsVisibleInRect(parent_rect, &child_rect, 10);
    EXPECT_EQ(gfx::Rect(10, 20, 100, 100), child_rect);
  }

  {
    // Child rect y < 0
    gfx::Rect child_rect(20, -50, 100, 100);
    win_util::EnsureRectIsVisibleInRect(parent_rect, &child_rect, 10);
    EXPECT_EQ(gfx::Rect(20, 10, 100, 100), child_rect);
  }

  {
    // Child rect right > parent_rect.right
    gfx::Rect child_rect(450, 20, 100, 100);
    win_util::EnsureRectIsVisibleInRect(parent_rect, &child_rect, 10);
    EXPECT_EQ(gfx::Rect(390, 20, 100, 100), child_rect);
  }

  {
    // Child rect bottom > parent_rect.bottom
    gfx::Rect child_rect(20, 350, 100, 100);
    win_util::EnsureRectIsVisibleInRect(parent_rect, &child_rect, 10);
    EXPECT_EQ(gfx::Rect(20, 290, 100, 100), child_rect);
  }

  {
    // Child rect width > parent_rect.width
    gfx::Rect child_rect(20, 20, 700, 100);
    win_util::EnsureRectIsVisibleInRect(parent_rect, &child_rect, 10);
    EXPECT_EQ(gfx::Rect(20, 20, 480, 100), child_rect);
  }

  {
    // Child rect height > parent_rect.height
    gfx::Rect child_rect(20, 20, 100, 700);
    win_util::EnsureRectIsVisibleInRect(parent_rect, &child_rect, 10);
    EXPECT_EQ(gfx::Rect(20, 20, 100, 380), child_rect);
  }
}

<commit_msg>Fix the unit test when run from a MUI-Aware Vista installation and the current UI language is not the same as the installation language.<commit_after>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/registry.h"
#include "base/string_util.h"
#include "chrome/common/win_util.h"
#include "testing/gtest/include/gtest/gtest.h"

class WinUtilTest: public testing::Test {
 protected:
  // Retrieve the OS primary language
  static unsigned GetSystemLanguage() {
    std::wstring language;

    typedef BOOL (WINAPI *fnGetThreadPreferredUILanguages)(
        DWORD dwFlags,
        PULONG pulNumLanguages,
        PWSTR pwszLanguagesBuffer,
        PULONG pcchLanguagesBuffer);
    fnGetThreadPreferredUILanguages pGetThreadPreferredUILanguages = NULL;
    pGetThreadPreferredUILanguages =
        reinterpret_cast<fnGetThreadPreferredUILanguages>(
            GetProcAddress(GetModuleHandle(L"kernel32.dll"),
                           "GetThreadPreferredUILanguages"));
    if (pGetThreadPreferredUILanguages) {
      // Vista, MUI-aware.
      ULONG number = 0;
      wchar_t buffer[256] = {0};
      ULONG buffer_size = sizeof(buffer);
      EXPECT_TRUE(pGetThreadPreferredUILanguages(MUI_LANGUAGE_ID, &number,
                                                 buffer, &buffer_size));
      language = buffer;
    } else {
      // XP
      RegKey language_key(HKEY_LOCAL_MACHINE,
                          L"SYSTEM\\CurrentControlSet\\Control\\Nls\\Language");
      language_key.ReadValue(L"InstallLanguage", &language);
    }
    wchar_t * unused_endptr;
    return PRIMARYLANGID(wcstol(language.c_str(), &unused_endptr, 16));
  }
};

TEST_F(WinUtilTest, FormatMessage) {
  const int kAccessDeniedErrorCode = 5;
  SetLastError(kAccessDeniedErrorCode);
  ASSERT_EQ(GetLastError(), kAccessDeniedErrorCode);
  std::wstring value;

  unsigned language = GetSystemLanguage();
  ASSERT_TRUE(language);
  if (language == LANG_ENGLISH) {
    // This test would fail on non-English system.
    TrimWhitespace(win_util::FormatLastWin32Error(), TRIM_ALL, &value);
    EXPECT_EQ(std::wstring(L"Access is denied."), value);
  } else if (language == LANG_FRENCH) {
    // This test would fail on non-French system.
    TrimWhitespace(win_util::FormatLastWin32Error(), TRIM_ALL, &value);
    EXPECT_EQ(std::wstring(L"Acc\u00e8s refus\u00e9."), value);
  } else {
    EXPECT_TRUE(0) << "Please implement the test for your OS language.";
  }

  // Manually call the OS function
  wchar_t * string_buffer = NULL;
  unsigned string_length = ::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
                                    FORMAT_MESSAGE_FROM_SYSTEM |
                                    FORMAT_MESSAGE_IGNORE_INSERTS, NULL,
                                    kAccessDeniedErrorCode, 0,
                                    reinterpret_cast<wchar_t *>(&string_buffer),
                                    0, NULL);

  // Verify the call succeeded
  ASSERT_TRUE(string_length);
  ASSERT_TRUE(string_buffer);

  // Verify the string is the same by different calls
  EXPECT_EQ(win_util::FormatLastWin32Error(), std::wstring(string_buffer));
  EXPECT_EQ(win_util::FormatMessage(kAccessDeniedErrorCode),
            std::wstring(string_buffer));

  // Done with the buffer allocated by ::FormatMessage()
  LocalFree(string_buffer);
}

TEST_F(WinUtilTest, EnsureRectIsVisibleInRect) {
  gfx::Rect parent_rect(0, 0, 500, 400);

  {
    // Child rect x < 0
    gfx::Rect child_rect(-50, 20, 100, 100);
    win_util::EnsureRectIsVisibleInRect(parent_rect, &child_rect, 10);
    EXPECT_EQ(gfx::Rect(10, 20, 100, 100), child_rect);
  }

  {
    // Child rect y < 0
    gfx::Rect child_rect(20, -50, 100, 100);
    win_util::EnsureRectIsVisibleInRect(parent_rect, &child_rect, 10);
    EXPECT_EQ(gfx::Rect(20, 10, 100, 100), child_rect);
  }

  {
    // Child rect right > parent_rect.right
    gfx::Rect child_rect(450, 20, 100, 100);
    win_util::EnsureRectIsVisibleInRect(parent_rect, &child_rect, 10);
    EXPECT_EQ(gfx::Rect(390, 20, 100, 100), child_rect);
  }

  {
    // Child rect bottom > parent_rect.bottom
    gfx::Rect child_rect(20, 350, 100, 100);
    win_util::EnsureRectIsVisibleInRect(parent_rect, &child_rect, 10);
    EXPECT_EQ(gfx::Rect(20, 290, 100, 100), child_rect);
  }

  {
    // Child rect width > parent_rect.width
    gfx::Rect child_rect(20, 20, 700, 100);
    win_util::EnsureRectIsVisibleInRect(parent_rect, &child_rect, 10);
    EXPECT_EQ(gfx::Rect(20, 20, 480, 100), child_rect);
  }

  {
    // Child rect height > parent_rect.height
    gfx::Rect child_rect(20, 20, 100, 700);
    win_util::EnsureRectIsVisibleInRect(parent_rect, &child_rect, 10);
    EXPECT_EQ(gfx::Rect(20, 20, 100, 380), child_rect);
  }
}

<|endoftext|>


<commit_before>// For conditions of distribution and use, see copyright notice in license.txt

#include "StableHeaders.h"
#include "DebugOperatorNew.h"
#include "MemoryLeakCheck.h"

#include "PhononPlayerModule.h"
#include "Service.h"
//#include "Service.h"

namespace PlayerService
{
    std::string PhononPlayerModule::type_name_static_ = "PhononPlayer";

    PhononPlayerModule::PhononPlayerModule()
        : ModuleInterface(type_name_static_)
    {
    }

    PhononPlayerModule::~PhononPlayerModule()
    {
    }

    void PhononPlayerModule::Load()
    {
    }

    void PhononPlayerModule::Unload()
    {
    }

    void PhononPlayerModule::Initialize()
    {
        player_service_ = Player::PlayerServicePtr(new PlayerService::Service());

        framework_->GetServiceManager()->RegisterService(Foundation::Service::ST_Player, player_service_);
    }

    void PhononPlayerModule::PostInitialize()
    {
    }

    void PhononPlayerModule::Uninitialize()
    {
        if (player_service_)
            framework_->GetServiceManager()->UnregisterService(player_service_);
    }

    void PhononPlayerModule::Update(f64 frametime)
    {
    }

    bool PhononPlayerModule::HandleEvent(event_category_id_t category_id, event_id_t event_id, Foundation::EventDataInterface* data)
    {
        return false;
    }

} // PlayerService

extern "C" void POCO_LIBRARY_API SetProfiler(Foundation::Profiler *profiler);
void SetProfiler(Foundation::Profiler *profiler)
{
    Foundation::ProfilerSection::SetProfiler(profiler);
}

using namespace PlayerService;

POCO_BEGIN_MANIFEST(Foundation::ModuleInterface)
POCO_EXPORT_CLASS(PhononPlayerModule)
POCO_END_MANIFEST
<commit_msg>Fixed include header order.<commit_after>// For conditions of distribution and use, see copyright notice in license.txt

#include "StableHeaders.h"
#include "DebugOperatorNew.h"

#include "PhononPlayerModule.h"
#include "Service.h"

#include "MemoryLeakCheck.h"

namespace PlayerService
{
    std::string PhononPlayerModule::type_name_static_ = "PhononPlayer";

    PhononPlayerModule::PhononPlayerModule()
        : ModuleInterface(type_name_static_)
    {
    }

    PhononPlayerModule::~PhononPlayerModule()
    {
    }

    void PhononPlayerModule::Load()
    {
    }

    void PhononPlayerModule::Unload()
    {
    }

    void PhononPlayerModule::Initialize()
    {
        player_service_ = Player::PlayerServicePtr(new PlayerService::Service());

        framework_->GetServiceManager()->RegisterService(Foundation::Service::ST_Player, player_service_);
    }

    void PhononPlayerModule::PostInitialize()
    {
    }

    void PhononPlayerModule::Uninitialize()
    {
        if (player_service_)
            framework_->GetServiceManager()->UnregisterService(player_service_);
    }

    void PhononPlayerModule::Update(f64 frametime)
    {
    }

    bool PhononPlayerModule::HandleEvent(event_category_id_t category_id, event_id_t event_id, Foundation::EventDataInterface* data)
    {
        return false;
    }

} // PlayerService

extern "C" void POCO_LIBRARY_API SetProfiler(Foundation::Profiler *profiler);
void SetProfiler(Foundation::Profiler *profiler)
{
    Foundation::ProfilerSection::SetProfiler(profiler);
}

using namespace PlayerService;

POCO_BEGIN_MANIFEST(Foundation::ModuleInterface)
POCO_EXPORT_CLASS(PhononPlayerModule)
POCO_END_MANIFEST
<|endoftext|>


<commit_before>#define _XOPEN_SOURCE 600
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <time.h>
#ifdef _WIN32
#include <windows.h>
#define snprintf _snprintf
//#define strdup _strdup
#define strerror_r(errno, buf, buflen) strerror_s(buf, buflen, errno)
typedef unsigned __int64    uint64_t;
typedef __int64             int64_t;
#define Log_GetThreadID() (uint64_t)(GetCurrentThreadId())
#else
#include <sys/time.h>
#include <pthread.h>
#include <stdint.h>
#define Log_GetThreadID() ((uint64_t)(pthread_self()))
#endif

#include "Log.h"
#include "Formatting.h"
#include "System/Threading/Mutex.h"

#define LOG_MSG_SIZE    1024
#define LOG_OLD_EXT     ".old"

static bool     timestamping = false;
static bool     threadedOutput = false;
static bool     trace = false;
#ifdef DEBUG
static bool     debug = true;
#else
static bool     debug = false;
#endif
static int      maxLine = LOG_MSG_SIZE;
static int      target = LOG_TARGET_NOWHERE;
static FILE*    logfile = NULL;
static char*    logfilename = NULL;
static uint64_t maxSize = 0;
static uint64_t logFileSize = 0;
static Mutex    logFileMutex;
static bool     autoFlush = true;

#ifdef _WIN32
typedef char log_timestamp_t[24];
#else
typedef char log_timestamp_t[27];
#endif

static const char* GetFullTimestamp(log_timestamp_t ts)
{
    if (!timestamping)
        return "";

#ifdef _WIN32
    SYSTEMTIME  st;
    GetLocalTime(&st);

    snprintf(ts, sizeof(log_timestamp_t), "%04d-%02d-%02d %02d:%02d:%02d.%03d",
     (int) st.wYear,
     (int) st.wMonth,
     (int) st.wDay,
     (int) st.wHour,
     (int) st.wMinute,
     (int) st.wSecond,
     (int) st.wMilliseconds);
#else
    struct tm tm;
    time_t sec;
    struct timeval tv;

    gettimeofday(&tv, NULL);
    sec = (time_t) tv.tv_sec;
    localtime_r(&sec, &tm);

    snprintf(ts, sizeof(log_timestamp_t), "%04d-%02d-%02d %02d:%02d:%02d.%06lu",
     tm.tm_year + 1900,
     tm.tm_mon + 1,
     tm.tm_mday,
     tm.tm_hour,
     tm.tm_min,
     tm.tm_sec,
     (long unsigned int) tv.tv_usec);
#endif

    return ts;
}

// These functions are duplicates of the functions in FileSystem, but here they don't use logging obviously
#ifdef _WIN32
static bool Log_RenameFile(const char* src, const char* dst)
{
    BOOL    ret;

    ret = MoveFileEx(src, dst, MOVEFILE_WRITE_THROUGH);
    if (!ret)
        return false;

    return true;
}

static bool Log_DeleteFile(const char* filename)
{
    BOOL    ret;

    ret = DeleteFile(filename);
    if (!ret)
        return false;

    return true;
}

static int64_t Log_FileSize(const char* path)
{
    WIN32_FILE_ATTRIBUTE_DATA   attrData;
    BOOL                        ret;

    ret = GetFileAttributesEx(path, GetFileExInfoStandard, &attrData);
    if (!ret)
        return -1;

    return ((int64_t) attrData.nFileSizeHigh) << 32 | attrData.nFileSizeLow;
}

#else

static bool Log_RenameFile(const char* src, const char* dst)
{
    int     ret;

    ret = rename(src, dst);
    if (ret < 0)
        return false;

    return true;
}

static bool Log_DeleteFile(const char* filename)
{
    int ret;

    ret = unlink(filename);
    if (ret < 0)
        return false;

    return true;
}

int64_t FS_FileSize(const char* path)
{
    int64_t     ret;
    struct stat buf;

    ret = stat(path, &buf);
    if (ret < 0)
        return ret;

    return buf.st_size;
}

#endif

static void Log_Append(char*& p, int& remaining, const char* s, int len)
{
    if (len > remaining)
        len = remaining;

    if (len > 0)
        memcpy(p, s, len);

    p += len;
    remaining -= len;
}

static void Log_Rotate()
{
    char*   filenameCopy;
    char*   oldFilename;
    size_t  oldFilenameSize;
    char*   oldOldFilename;
    size_t  oldOldFilenameSize;
    size_t  filenameLen;
    size_t  extLen;

    fprintf(stderr, "Rotating...\n");

    filenameCopy = strdup(logfilename);

    filenameLen = strlen(logfilename);
    extLen = sizeof(LOG_OLD_EXT) - 1;

    oldFilenameSize = filenameLen + extLen + 1;
    oldFilename = new char[oldFilenameSize];
    snprintf(oldFilename, oldFilenameSize, "%s" LOG_OLD_EXT, logfilename);

    oldOldFilenameSize = filenameLen + extLen + extLen + 1;
    oldOldFilename = new char[oldOldFilenameSize];
    snprintf(oldOldFilename, oldOldFilenameSize, "%s" LOG_OLD_EXT LOG_OLD_EXT, logfilename);

    // delete any previously created temporary file
    Log_DeleteFile(oldOldFilename);

    // rename the old version to a temporary name
    if (!Log_RenameFile(oldFilename, oldOldFilename))
    {
        Log_DeleteFile(oldFilename);
    }

    // close the current file
    if (logfile)
    {
        fclose(logfile);
        logfile = NULL;
    }

    // rename the current to old
    if (!Log_RenameFile(logfilename, oldFilename))
    {
        // TODO:
    }

    // create a new file
    Log_SetOutputFile(filenameCopy, true);

    // delete any previously created temporary file
    Log_DeleteFile(oldOldFilename);

    // cleanup
    free(filenameCopy);
    delete[] oldFilename;
    delete[] oldOldFilename;
}

static void Log_Write(const char* buf, int size, int flush)
{
    if ((target & LOG_TARGET_STDOUT) == LOG_TARGET_STDOUT)
    {
        if (buf)
            fputs(buf, stdout);
        if (flush)
			fflush(stdout);
    }

    if ((target & LOG_TARGET_STDERR) == LOG_TARGET_STDERR)
    {
        if (buf)
            fputs(buf, stderr);
		if (flush)
			fflush(stderr);
    }

    if ((target & LOG_TARGET_FILE) == LOG_TARGET_FILE && logfile)
    {
        logFileMutex.Lock();

        if (buf)
            fputs(buf, logfile);
		if (flush)
			fflush(logfile);

        if (maxSize > 0)
        {

            // we keep the previous logfile, hence the division by two
            if (logFileSize + size > maxSize / 2)
            {
                // rotate the logfile
                Log_Rotate();
            }
            else
            {
                logFileSize += size;
            }
        }

        logFileMutex.Unlock();
    }
}

void Log_SetTimestamping(bool ts)
{
    timestamping = ts;
}

void Log_SetThreadedOutput(bool to)
{
    threadedOutput = to;
}

bool Log_SetTrace(bool trace_)
{
    bool prev = trace;

    trace = trace_;
    return prev;
}

bool Log_SetDebug(bool debug_)
{
    bool prev = debug;

    debug = debug_;
    return prev;
}

bool Log_SetAutoFlush(bool autoFlush_)
{
    bool prev = autoFlush;

    autoFlush = autoFlush_;
    return prev;
}

void Log_SetMaxLine(int maxLine_)
{
    maxLine = maxLine_ > LOG_MSG_SIZE ? LOG_MSG_SIZE : maxLine_;
}

void Log_SetTarget(int target_)
{
    target = target_;
}

int Log_GetTarget()
{
    return target;
}

bool Log_SetOutputFile(const char* filename, bool truncate)
{
    if (logfile)
    {
        fclose(logfile);
        free(logfilename);
        logfilename = NULL;
    }

    if (!filename)
        return false;

    if (truncate)
        logfile = fopen(filename, "w");
    else
        logfile = fopen(filename, "a");
    if (!logfile)
    {
        target &= ~LOG_TARGET_FILE;
        return false;
    }

    logfilename = strdup(filename);
    logFileSize = Log_FileSize(filename);
    return true;
}

void Log_SetMaxSize(unsigned maxSizeMB)
{
    maxSize = ((uint64_t)maxSizeMB) * 1000 * 1000;
}

void Log_Flush()
{
    Log_Write(NULL, 0, true);
}

void Log_Shutdown()
{
    if (logfilename)
    {
        free(logfilename);
        logfilename = NULL;
    }

    if (logfile)
    {
        fclose(logfile);
        logfile = NULL;
    }

    fflush(stdout);
    fflush(stderr);

    trace = false;
    timestamping = false;
}

void Log(const char* file, int line, const char* func, int type, const char* fmt, ...)
{
    char        buf[LOG_MSG_SIZE];
    int         remaining;
    char        *p;
    const char  *sep;
    int         ret;
    va_list     ap;
    uint64_t    threadID;

    // In debug mode enable ERRNO type messages
    if ((type == LOG_TYPE_TRACE || type == LOG_TYPE_ERRNO) && !trace)
        return;

    buf[maxLine - 1] = 0;
    p = buf;
    remaining = maxLine - 1;

    // print timestamp
    if (timestamping)
    {
        GetFullTimestamp(p);
        p += sizeof(log_timestamp_t) - 1;
        remaining -= sizeof(log_timestamp_t) - 1;
        Log_Append(p, remaining, ": ", 2);
    }

    // print threadID
    if (threadedOutput)
    {
        threadID = Log_GetThreadID();
        ret = Writef(p, remaining, "[%U]: ", threadID);
        if (ret < 0 || ret > remaining)
            ret = remaining;

        p += ret;
        remaining -= ret;
    }

    // don't print filename and func in debug mode on ERRNO messages
    if (file && func && (type == LOG_TYPE_TRACE || (type == LOG_TYPE_ERRNO && trace)))
    {
#ifdef _WIN32
        sep = strrchr(file, '/');
        if (!sep)
            sep = strrchr(file, '\\');
#else
        sep = strrchr(file, '/');
#endif
        if (sep)
            file = sep + 1;

        // print filename, number of line and function name
        ret = snprintf(p, remaining + 1, "%s:%d:%s()", file, line, func);
        if (ret < 0 || ret > remaining)
            ret = remaining;

        p += ret;
        remaining -= ret;

        if (fmt[0] != '\0' || type == LOG_TYPE_ERRNO)
            Log_Append(p, remaining, ": ", 2);
    }

    // in case of error print the errno message otherwise print our message
    if (type == LOG_TYPE_ERRNO)
    {
#ifdef _GNU_SOURCE
        // this is a workaround for g++ on Debian Lenny
        // see http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=485135
        // _GNU_SOURCE is unconditionally defined so always the GNU style
        // sterror_r() is used, which is broken
        char* err = strerror_r(errno, p, remaining - 1);
        if (err)
        {
                ret = strlen(err);
                if (err != p)
                {
                        memcpy(p, err, ret);
                        p[ret] = 0;
                }
        }
        else
                ret = -1;
#elif _WIN32
        DWORD lastError = GetLastError();
        ret = snprintf(p, remaining, "Error %u: ", lastError);
        if (ret < 0 || ret >= remaining)
            ret = remaining - 1;

        p += ret;
        remaining -= ret;
        if (remaining > 2)
        {
            ret = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
                FORMAT_MESSAGE_IGNORE_INSERTS |
                (FORMAT_MESSAGE_MAX_WIDTH_MASK & remaining - 2),
                NULL,
                lastError,
                MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                (LPTSTR) p,
                remaining - 2,
                NULL);
        }
        else
            ret = 0;
#else
        ret = strerror_r(errno, p, remaining - 1);
        if (ret >= 0)
            ret = (int) strlen(p);
#endif
        if (ret < 0)
            ret = remaining;

        p += ret;
        remaining -= ret;
        if (fmt[0] != '\0')
            Log_Append(p, remaining, ": ", 2);
    }
//    else
    {
        va_start(ap, fmt);
        ret = VWritef(p, remaining, fmt, ap);
        va_end(ap);
        if (ret < 0 || ret >= remaining)
            ret = remaining - 1;

        p += ret;
        remaining -= ret;
    }

    Log_Append(p, remaining, "\n", 2);
    if (autoFlush)
        Log_Write(buf, maxLine - remaining, type != LOG_TYPE_TRACE && type != LOG_TYPE_DEBUG);
    else
        Log_Write(buf, maxLine - remaining, false);
}
<commit_msg>Fixed switchable debug log option.<commit_after>#define _XOPEN_SOURCE 600
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <time.h>
#ifdef _WIN32
#include <windows.h>
#define snprintf _snprintf
//#define strdup _strdup
#define strerror_r(errno, buf, buflen) strerror_s(buf, buflen, errno)
typedef unsigned __int64    uint64_t;
typedef __int64             int64_t;
#define Log_GetThreadID() (uint64_t)(GetCurrentThreadId())
#else
#include <sys/time.h>
#include <pthread.h>
#include <stdint.h>
#define Log_GetThreadID() ((uint64_t)(pthread_self()))
#endif

#include "Log.h"
#include "Formatting.h"
#include "System/Threading/Mutex.h"

#define LOG_MSG_SIZE    1024
#define LOG_OLD_EXT     ".old"

static bool     timestamping = false;
static bool     threadedOutput = false;
static bool     trace = false;
#ifdef DEBUG
static bool     debug = true;
#else
static bool     debug = false;
#endif
static int      maxLine = LOG_MSG_SIZE;
static int      target = LOG_TARGET_NOWHERE;
static FILE*    logfile = NULL;
static char*    logfilename = NULL;
static uint64_t maxSize = 0;
static uint64_t logFileSize = 0;
static Mutex    logFileMutex;
static bool     autoFlush = true;

#ifdef _WIN32
typedef char log_timestamp_t[24];
#else
typedef char log_timestamp_t[27];
#endif

static const char* GetFullTimestamp(log_timestamp_t ts)
{
    if (!timestamping)
        return "";

#ifdef _WIN32
    SYSTEMTIME  st;
    GetLocalTime(&st);

    snprintf(ts, sizeof(log_timestamp_t), "%04d-%02d-%02d %02d:%02d:%02d.%03d",
     (int) st.wYear,
     (int) st.wMonth,
     (int) st.wDay,
     (int) st.wHour,
     (int) st.wMinute,
     (int) st.wSecond,
     (int) st.wMilliseconds);
#else
    struct tm tm;
    time_t sec;
    struct timeval tv;

    gettimeofday(&tv, NULL);
    sec = (time_t) tv.tv_sec;
    localtime_r(&sec, &tm);

    snprintf(ts, sizeof(log_timestamp_t), "%04d-%02d-%02d %02d:%02d:%02d.%06lu",
     tm.tm_year + 1900,
     tm.tm_mon + 1,
     tm.tm_mday,
     tm.tm_hour,
     tm.tm_min,
     tm.tm_sec,
     (long unsigned int) tv.tv_usec);
#endif

    return ts;
}

// These functions are duplicates of the functions in FileSystem, but here they don't use logging obviously
#ifdef _WIN32
static bool Log_RenameFile(const char* src, const char* dst)
{
    BOOL    ret;

    ret = MoveFileEx(src, dst, MOVEFILE_WRITE_THROUGH);
    if (!ret)
        return false;

    return true;
}

static bool Log_DeleteFile(const char* filename)
{
    BOOL    ret;

    ret = DeleteFile(filename);
    if (!ret)
        return false;

    return true;
}

static int64_t Log_FileSize(const char* path)
{
    WIN32_FILE_ATTRIBUTE_DATA   attrData;
    BOOL                        ret;

    ret = GetFileAttributesEx(path, GetFileExInfoStandard, &attrData);
    if (!ret)
        return -1;

    return ((int64_t) attrData.nFileSizeHigh) << 32 | attrData.nFileSizeLow;
}

#else

static bool Log_RenameFile(const char* src, const char* dst)
{
    int     ret;

    ret = rename(src, dst);
    if (ret < 0)
        return false;

    return true;
}

static bool Log_DeleteFile(const char* filename)
{
    int ret;

    ret = unlink(filename);
    if (ret < 0)
        return false;

    return true;
}

int64_t FS_FileSize(const char* path)
{
    int64_t     ret;
    struct stat buf;

    ret = stat(path, &buf);
    if (ret < 0)
        return ret;

    return buf.st_size;
}

#endif

static void Log_Append(char*& p, int& remaining, const char* s, int len)
{
    if (len > remaining)
        len = remaining;

    if (len > 0)
        memcpy(p, s, len);

    p += len;
    remaining -= len;
}

static void Log_Rotate()
{
    char*   filenameCopy;
    char*   oldFilename;
    size_t  oldFilenameSize;
    char*   oldOldFilename;
    size_t  oldOldFilenameSize;
    size_t  filenameLen;
    size_t  extLen;

    fprintf(stderr, "Rotating...\n");

    filenameCopy = strdup(logfilename);

    filenameLen = strlen(logfilename);
    extLen = sizeof(LOG_OLD_EXT) - 1;

    oldFilenameSize = filenameLen + extLen + 1;
    oldFilename = new char[oldFilenameSize];
    snprintf(oldFilename, oldFilenameSize, "%s" LOG_OLD_EXT, logfilename);

    oldOldFilenameSize = filenameLen + extLen + extLen + 1;
    oldOldFilename = new char[oldOldFilenameSize];
    snprintf(oldOldFilename, oldOldFilenameSize, "%s" LOG_OLD_EXT LOG_OLD_EXT, logfilename);

    // delete any previously created temporary file
    Log_DeleteFile(oldOldFilename);

    // rename the old version to a temporary name
    if (!Log_RenameFile(oldFilename, oldOldFilename))
    {
        Log_DeleteFile(oldFilename);
    }

    // close the current file
    if (logfile)
    {
        fclose(logfile);
        logfile = NULL;
    }

    // rename the current to old
    if (!Log_RenameFile(logfilename, oldFilename))
    {
        // TODO:
    }

    // create a new file
    Log_SetOutputFile(filenameCopy, true);

    // delete any previously created temporary file
    Log_DeleteFile(oldOldFilename);

    // cleanup
    free(filenameCopy);
    delete[] oldFilename;
    delete[] oldOldFilename;
}

static void Log_Write(const char* buf, int size, int flush)
{
    if ((target & LOG_TARGET_STDOUT) == LOG_TARGET_STDOUT)
    {
        if (buf)
            fputs(buf, stdout);
        if (flush)
			fflush(stdout);
    }

    if ((target & LOG_TARGET_STDERR) == LOG_TARGET_STDERR)
    {
        if (buf)
            fputs(buf, stderr);
		if (flush)
			fflush(stderr);
    }

    if ((target & LOG_TARGET_FILE) == LOG_TARGET_FILE && logfile)
    {
        logFileMutex.Lock();

        if (buf)
            fputs(buf, logfile);
		if (flush)
			fflush(logfile);

        if (maxSize > 0)
        {

            // we keep the previous logfile, hence the division by two
            if (logFileSize + size > maxSize / 2)
            {
                // rotate the logfile
                Log_Rotate();
            }
            else
            {
                logFileSize += size;
            }
        }

        logFileMutex.Unlock();
    }
}

void Log_SetTimestamping(bool ts)
{
    timestamping = ts;
}

void Log_SetThreadedOutput(bool to)
{
    threadedOutput = to;
}

bool Log_SetTrace(bool trace_)
{
    bool prev = trace;

    trace = trace_;
    return prev;
}

bool Log_SetDebug(bool debug_)
{
    bool prev = debug;

    debug = debug_;
    return prev;
}

bool Log_SetAutoFlush(bool autoFlush_)
{
    bool prev = autoFlush;

    autoFlush = autoFlush_;
    return prev;
}

void Log_SetMaxLine(int maxLine_)
{
    maxLine = maxLine_ > LOG_MSG_SIZE ? LOG_MSG_SIZE : maxLine_;
}

void Log_SetTarget(int target_)
{
    target = target_;
}

int Log_GetTarget()
{
    return target;
}

bool Log_SetOutputFile(const char* filename, bool truncate)
{
    if (logfile)
    {
        fclose(logfile);
        free(logfilename);
        logfilename = NULL;
    }

    if (!filename)
        return false;

    if (truncate)
        logfile = fopen(filename, "w");
    else
        logfile = fopen(filename, "a");
    if (!logfile)
    {
        target &= ~LOG_TARGET_FILE;
        return false;
    }

    logfilename = strdup(filename);
    logFileSize = Log_FileSize(filename);
    return true;
}

void Log_SetMaxSize(unsigned maxSizeMB)
{
    maxSize = ((uint64_t)maxSizeMB) * 1000 * 1000;
}

void Log_Flush()
{
    Log_Write(NULL, 0, true);
}

void Log_Shutdown()
{
    if (logfilename)
    {
        free(logfilename);
        logfilename = NULL;
    }

    if (logfile)
    {
        fclose(logfile);
        logfile = NULL;
    }

    fflush(stdout);
    fflush(stderr);

    trace = false;
    timestamping = false;
}

void Log(const char* file, int line, const char* func, int type, const char* fmt, ...)
{
    char        buf[LOG_MSG_SIZE];
    int         remaining;
    char        *p;
    const char  *sep;
    int         ret;
    va_list     ap;
    uint64_t    threadID;

    // In debug mode enable ERRNO type messages
    if ((type == LOG_TYPE_TRACE || type == LOG_TYPE_ERRNO) && !trace)
        return;

    if ((type == LOG_TYPE_DEBUG) && !debug)
        return;

    buf[maxLine - 1] = 0;
    p = buf;
    remaining = maxLine - 1;

    // print timestamp
    if (timestamping)
    {
        GetFullTimestamp(p);
        p += sizeof(log_timestamp_t) - 1;
        remaining -= sizeof(log_timestamp_t) - 1;
        Log_Append(p, remaining, ": ", 2);
    }

    // print threadID
    if (threadedOutput)
    {
        threadID = Log_GetThreadID();
        ret = Writef(p, remaining, "[%U]: ", threadID);
        if (ret < 0 || ret > remaining)
            ret = remaining;

        p += ret;
        remaining -= ret;
    }

    // don't print filename and func in debug mode on ERRNO messages
    if (file && func && (type == LOG_TYPE_TRACE || (type == LOG_TYPE_ERRNO && trace)))
    {
#ifdef _WIN32
        sep = strrchr(file, '/');
        if (!sep)
            sep = strrchr(file, '\\');
#else
        sep = strrchr(file, '/');
#endif
        if (sep)
            file = sep + 1;

        // print filename, number of line and function name
        ret = snprintf(p, remaining + 1, "%s:%d:%s()", file, line, func);
        if (ret < 0 || ret > remaining)
            ret = remaining;

        p += ret;
        remaining -= ret;

        if (fmt[0] != '\0' || type == LOG_TYPE_ERRNO)
            Log_Append(p, remaining, ": ", 2);
    }

    // in case of error print the errno message otherwise print our message
    if (type == LOG_TYPE_ERRNO)
    {
#ifdef _GNU_SOURCE
        // this is a workaround for g++ on Debian Lenny
        // see http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=485135
        // _GNU_SOURCE is unconditionally defined so always the GNU style
        // sterror_r() is used, which is broken
        char* err = strerror_r(errno, p, remaining - 1);
        if (err)
        {
                ret = strlen(err);
                if (err != p)
                {
                        memcpy(p, err, ret);
                        p[ret] = 0;
                }
        }
        else
                ret = -1;
#elif _WIN32
        DWORD lastError = GetLastError();
        ret = snprintf(p, remaining, "Error %u: ", lastError);
        if (ret < 0 || ret >= remaining)
            ret = remaining - 1;

        p += ret;
        remaining -= ret;
        if (remaining > 2)
        {
            ret = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
                FORMAT_MESSAGE_IGNORE_INSERTS |
                (FORMAT_MESSAGE_MAX_WIDTH_MASK & remaining - 2),
                NULL,
                lastError,
                MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                (LPTSTR) p,
                remaining - 2,
                NULL);
        }
        else
            ret = 0;
#else
        ret = strerror_r(errno, p, remaining - 1);
        if (ret >= 0)
            ret = (int) strlen(p);
#endif
        if (ret < 0)
            ret = remaining;

        p += ret;
        remaining -= ret;
        if (fmt[0] != '\0')
            Log_Append(p, remaining, ": ", 2);
    }
//    else
    {
        va_start(ap, fmt);
        ret = VWritef(p, remaining, fmt, ap);
        va_end(ap);
        if (ret < 0 || ret >= remaining)
            ret = remaining - 1;

        p += ret;
        remaining -= ret;
    }

    Log_Append(p, remaining, "\n", 2);
    if (autoFlush)
        Log_Write(buf, maxLine - remaining, type != LOG_TYPE_TRACE && type != LOG_TYPE_DEBUG);
    else
        Log_Write(buf, maxLine - remaining, false);
}
<|endoftext|>


<commit_before>#include "Visit.h"
#include "Command.h"
#include "WebPage.h"

Visit::Visit(WebPage *page, QObject *parent) : Command(page, parent) {
  connect(page, SIGNAL(pageFinished(bool)), this, SLOT(loadFinished(bool)));
}

void Visit::start(QStringList &arguments) {
  QUrl requestedUrl = QUrl(arguments[0]);
  page()->currentFrame()->load(QUrl(requestedUrl));
}

void Visit::loadFinished(bool success) {
  QString message;
  if (!success)
    message = page()->failureString();

  emit finished(new Response(success, message));
}
<commit_msg>Fix issue #39<commit_after>#include "Visit.h"
#include "Command.h"
#include "WebPage.h"

Visit::Visit(WebPage *page, QObject *parent) : Command(page, parent) {
  connect(page, SIGNAL(pageFinished(bool)), this, SLOT(loadFinished(bool)));
}

void Visit::start(QStringList &arguments) {
  QUrl requestedUrl = QUrl(arguments[0]);
  page()->currentFrame()->load(QUrl(requestedUrl));
}

void Visit::loadFinished(bool success) {
  QString message;
  if (!success)
    message = page()->failureString();

  disconnect(page(), SIGNAL(pageFinished(bool)), this, SLOT(loadFinished(bool)));
  emit finished(new Response(success, message));
}
<|endoftext|>


<commit_before>// License: Apache 2.0. See LICENSE file in root directory.
// Copyright(c) 2015 Intel Corporation. All Rights Reserved.

#include <librealsense/rs.hpp>
#include <cv_bridge/cv_bridge.h>
#include <sensor_msgs/Image.h>
#include <sensor_msgs/CameraInfo.h>
#include <sensor_msgs/distortion_models.h>
#include <std_msgs/Header.h>
#include <ros/ros.h>

#include <iostream>
#include <algorithm>

void rsIntrinsics2CameraInfo(const rs::intrinsics& intrinsics, sensor_msgs::CameraInfo& cam_info)
{
  cam_info.width  = intrinsics.width;
  cam_info.height = intrinsics.height;
  cam_info.distortion_model = sensor_msgs::distortion_models::PLUMB_BOB;
  cam_info.D.resize(5);
  cam_info.D[0] = intrinsics.coeffs[0];
  cam_info.D[1] = intrinsics.coeffs[1];
  cam_info.D[2] = intrinsics.coeffs[2];
  cam_info.D[3] = intrinsics.coeffs[3];
  cam_info.D[4] = intrinsics.coeffs[4];
  cam_info.K[0] = intrinsics.fx; cam_info.K[1] = 0; cam_info.K[2] = intrinsics.ppx;
  cam_info.K[3] = 0; cam_info.K[4] = intrinsics.fy; cam_info.K[5] = intrinsics.ppy;
  cam_info.K[6] = 0; cam_info.K[7] = 0; cam_info.K[8] = 1;
  cam_info.binning_x = 1;
  cam_info.binning_y = 1;
  cam_info.roi.x_offset = 0;
  cam_info.roi.y_offset = 0;
  cam_info.roi.width = cam_info.width;
  cam_info.roi.height = cam_info.height;
  cam_info.roi.do_rectify = false;
}

int main(int argc, char * argv[]) try
{
  ros::init(argc, argv, "kcf_tracker");
  ros::NodeHandle nh;

  int32_t skip_frame_num;
  ros::param::param<int32_t>("~skip_frame_num", skip_frame_num, 5);

  rs::context ctx;
  if(ctx.get_device_count() == 0) throw std::runtime_error("No device detected. Is it plugged in?");

  // Enumerate all devices
  std::vector<rs::device *> devices;
  std::vector<ros::Publisher> depth_pubs(ctx.get_device_count());
  std::vector<ros::Publisher> rgb_pubs(ctx.get_device_count());
  std::vector<ros::Publisher> depth_info_pubs(ctx.get_device_count());
  std::vector<ros::Publisher> rgb_info_pubs(ctx.get_device_count());
  std::vector<sensor_msgs::CameraInfo> depth_infos(ctx.get_device_count());
  std::vector<sensor_msgs::CameraInfo> rgb_infos(ctx.get_device_count());
  for(int i = 0; i < ctx.get_device_count(); ++i)
  {
    devices.push_back(ctx.get_device(i));
    depth_pubs[i] = nh.advertise<sensor_msgs::Image>("camera" + std::to_string(i) +
        "/depth/image_raw", 1, true);
    rgb_pubs[i] = nh.advertise<sensor_msgs::Image>("camera" + std::to_string(i) +
        "/rgb/image_raw", 1, true);
    depth_info_pubs[i] = nh.advertise<sensor_msgs::CameraInfo>("camera" +
        std::to_string(i) + "/depth/camera_info", 1, true);
    rgb_info_pubs[i] = nh.advertise<sensor_msgs::CameraInfo>("camera" +
        std::to_string(i) + "/rgb/camera_info", 1, true);
  }

  // Configure and start our devices
  int i = 0;
  for(auto dev : devices)
  {
    ROS_INFO("Starting %s...", dev->get_name());
    dev->enable_stream(rs::stream::depth, 640, 480, rs::format::z16, 30);
    dev->enable_stream(rs::stream::color, 1920, 1080, rs::format::bgr8, 30);
    rs::intrinsics depth_intrinsics = dev->get_stream_intrinsics(rs::stream::depth);
    rs::intrinsics color_intrinsics = dev->get_stream_intrinsics(rs::stream::color);

    rsIntrinsics2CameraInfo(depth_intrinsics, depth_infos[i]);
    rsIntrinsics2CameraInfo(color_intrinsics, rgb_infos[i]);

    dev->start();
    ROS_INFO("done.");
    ++i;
  }

  // Depth and color
  cv::Mat depth_img(cv::Size(640, 480), CV_16UC1);
  cv::Mat rgb_img(cv::Size(1920, 1080), CV_8UC3);
  cv_bridge::CvImage cv_img;

  std_msgs::Header header;
  int skip_count = 0;
  while (ros::ok())
  {
    int i = 0;
    if (skip_count == skip_frame_num)
    {
      skip_count = 0;
    }
    else
    {
      ++skip_count;
    }

    for (auto dev : devices)
    {
      header.stamp = ros::Time::now();
      dev->wait_for_frames();

      if (skip_count != skip_frame_num)
      {
        continue;
      }

      const uint16_t* depth_frame = reinterpret_cast<const uint16_t*>(
          dev->get_frame_data(rs::stream::depth));
      memcpy(depth_img.data, depth_frame, depth_img.cols*depth_img.rows*sizeof(uint16_t));
      header.frame_id = "depth_frame";
      cv_img.header = header;
      cv_img.encoding = "mono16";
      cv_img.image = depth_img;
      depth_pubs[i].publish(cv_img.toImageMsg());
      depth_infos[i].header = header;
      depth_info_pubs[i].publish(depth_infos[i]);

      const uint8_t* rgb_frame = reinterpret_cast<const uint8_t*>(
          dev->get_frame_data(rs::stream::color));
      memcpy(rgb_img.data, rgb_frame, rgb_img.cols*rgb_img.rows*sizeof(uint8_t)*rgb_img.channels());
      header.frame_id = "rgb_frame";
      cv_img.header = header;
      cv_img.encoding = "bgr8";
      cv_img.image = rgb_img;
      rgb_pubs[i].publish(cv_img);
      rgb_infos[i].header = header;
      rgb_info_pubs[i].publish(rgb_infos[i]);
      ++i;
    }
    ++header.seq;
  }

  return EXIT_SUCCESS;
}

catch(const rs::error & e)
{
    std::cerr << "RealSense error calling " << e.get_failed_function() << "("
        << e.get_failed_args() << "):\n    " << e.what() << std::endl;
    return EXIT_FAILURE;
}
catch(const std::exception & e)
{
    std::cerr << e.what() << std::endl;
    return EXIT_FAILURE;
}
<commit_msg>realsense pointcloud publications<commit_after>// License: Apache 2.0. See LICENSE file in root directory.
// Copyright(c) 2015 Intel Corporation. All Rights Reserved.

#include <librealsense/rs.hpp>
#include <cv_bridge/cv_bridge.h>
#include <sensor_msgs/Image.h>
#include <sensor_msgs/PointCloud.h>
#include <sensor_msgs/CameraInfo.h>
#include <sensor_msgs/distortion_models.h>
#include <std_msgs/Header.h>
#include <ros/ros.h>

#include <iostream>
#include <algorithm>

void rsIntrinsics2CameraInfo(const rs::intrinsics& intrinsics, sensor_msgs::CameraInfo& cam_info)
{
  cam_info.width  = intrinsics.width;
  cam_info.height = intrinsics.height;
  cam_info.distortion_model = sensor_msgs::distortion_models::PLUMB_BOB;
  cam_info.D.resize(5);
  cam_info.D[0] = intrinsics.coeffs[0];
  cam_info.D[1] = intrinsics.coeffs[1];
  cam_info.D[2] = intrinsics.coeffs[2];
  cam_info.D[3] = intrinsics.coeffs[3];
  cam_info.D[4] = intrinsics.coeffs[4];
  cam_info.K[0] = intrinsics.fx; cam_info.K[1] = 0; cam_info.K[2] = intrinsics.ppx;
  cam_info.K[3] = 0; cam_info.K[4] = intrinsics.fy; cam_info.K[5] = intrinsics.ppy;
  cam_info.K[6] = 0; cam_info.K[7] = 0; cam_info.K[8] = 1;
  cam_info.binning_x = 1;
  cam_info.binning_y = 1;
  cam_info.roi.x_offset = 0;
  cam_info.roi.y_offset = 0;
  cam_info.roi.width = cam_info.width;
  cam_info.roi.height = cam_info.height;
  cam_info.roi.do_rectify = false;
}

void publishPoints(const std_msgs::Header& header, const cv::Mat& depth_img,
    const ros::Publisher& publisher, rs::intrinsics& depth_intrinsics)
{
  sensor_msgs::PointCloud points_msg;
  points_msg.header = header;

  for(int dy = 0; dy < depth_intrinsics.height; ++dy)
  {
    for(int dx = 0; dx < depth_intrinsics.width; ++dx)
    {
      // Retrieve the 16-bit depth value and map it into a depth in meters
      uint16_t depth_value = depth_img.at<uint16_t>(dy, dx);
      float depth_in_meters = depth_value * 1000;

      // Skip over pixels with a depth value of zero, which is used to indicate no data
      if(depth_value == 0) continue;

      // Map from pixel coordinates in the depth image to pixel coordinates in the color image
      rs::float2 depth_pixel = {(float)dx, (float)dy};
      rs::float3 depth_point = depth_intrinsics.deproject(depth_pixel, depth_in_meters);

      geometry_msgs::Point32 point;
      point.x = depth_point.x;
      point.y = depth_point.y;
      point.z = depth_point.z;

      points_msg.points.push_back(point);
    }
  }
  publisher.publish(points_msg);
}

int main(int argc, char * argv[]) try
{
  ros::init(argc, argv, "realsense_multi_cam");
  ros::NodeHandle nh;

  int32_t skip_frame_num;
  bool pub_points;
  ros::param::param<int32_t>("~skip_frame_num", skip_frame_num, 5);
  ros::param::param<bool>("~pub_points", pub_points, false);

  int32_t rgb_width, rgb_height, depth_width, depth_height;
  ros::param::param<int32_t>("~rgb_width", rgb_width, 1920);
  ros::param::param<int32_t>("~rgb_height", rgb_height, 1080);
  ros::param::param<int32_t>("~depth_width", depth_width, 640);
  ros::param::param<int32_t>("~depth_height", depth_height, 480);

  rs::context ctx;
  if(ctx.get_device_count() == 0) throw std::runtime_error("No device detected. Is it plugged in?");

  // Enumerate all devices
  std::vector<rs::device *> devices;
  std::vector<ros::Publisher> depth_pubs(ctx.get_device_count());
  std::vector<ros::Publisher> rgb_pubs(ctx.get_device_count());
  std::vector<ros::Publisher> depth_info_pubs(ctx.get_device_count());
  std::vector<ros::Publisher> rgb_info_pubs(ctx.get_device_count());
  std::vector<ros::Publisher> point_pubs(ctx.get_device_count());
  std::vector<sensor_msgs::CameraInfo> depth_infos(ctx.get_device_count());
  std::vector<sensor_msgs::CameraInfo> rgb_infos(ctx.get_device_count());
  for(int i = 0; i < ctx.get_device_count(); ++i)
  {
    devices.push_back(ctx.get_device(i));
    depth_pubs[i] = nh.advertise<sensor_msgs::Image>("camera" + std::to_string(i) +
        "/depth/image_raw", 1, true);
    rgb_pubs[i] = nh.advertise<sensor_msgs::Image>("camera" + std::to_string(i) +
        "/rgb/image_raw", 1, true);
    depth_info_pubs[i] = nh.advertise<sensor_msgs::CameraInfo>("camera" +
        std::to_string(i) + "/depth/camera_info", 1, true);
    rgb_info_pubs[i] = nh.advertise<sensor_msgs::CameraInfo>("camera" +
        std::to_string(i) + "/rgb/camera_info", 1, true);
    point_pubs[i] = nh.advertise<sensor_msgs::PointCloud>("camera" +
        std::to_string(i) + "/depth/points", 1, true);
  }

  // Configure and start our devices
  int i = 0;
  for(auto dev : devices)
  {
    ROS_INFO("Starting %s...", dev->get_name());
    dev->enable_stream(rs::stream::depth, depth_width, depth_height, rs::format::z16, 30);
    dev->enable_stream(rs::stream::color, rgb_width, rgb_height, rs::format::bgr8, 30);
    rs::intrinsics depth_intrinsics = dev->get_stream_intrinsics(rs::stream::depth);
    rs::intrinsics color_intrinsics = dev->get_stream_intrinsics(rs::stream::color);

    rsIntrinsics2CameraInfo(depth_intrinsics, depth_infos[i]);
    rsIntrinsics2CameraInfo(color_intrinsics, rgb_infos[i]);

    dev->start();
    ROS_INFO("done.");
    ++i;
  }

  // Depth and color
  cv::Mat depth_img(cv::Size(depth_width, depth_height), CV_16UC1);
  cv::Mat rgb_img(cv::Size(rgb_width, rgb_height), CV_8UC3);
  cv_bridge::CvImage cv_img;

  std_msgs::Header header;
  int skip_count = 0;
  while (ros::ok())
  {
    int i = 0;
    if (skip_count == skip_frame_num)
    {
      skip_count = 0;
    }
    else
    {
      ++skip_count;
    }

    for (auto dev : devices)
    {
      header.stamp = ros::Time::now();
      dev->wait_for_frames();

      if (skip_count != skip_frame_num)
      {
        continue;
      }

      const uint16_t* depth_frame = reinterpret_cast<const uint16_t*>(
          dev->get_frame_data(rs::stream::depth));
      memcpy(depth_img.data, depth_frame, depth_img.cols*depth_img.rows*sizeof(uint16_t));
      header.frame_id = "depth_frame" + std::to_string(i);
      cv_img.header = header;
      cv_img.encoding = "mono16";
      cv_img.image = depth_img;
      depth_pubs[i].publish(cv_img.toImageMsg());
      depth_infos[i].header = header;
      depth_info_pubs[i].publish(depth_infos[i]);
      if (pub_points)
      {
        rs::intrinsics depth_intrinsics = dev->get_stream_intrinsics(rs::stream::depth);
        publishPoints(header, depth_img, point_pubs[i], depth_intrinsics);
      }

      const uint8_t* rgb_frame = reinterpret_cast<const uint8_t*>(
          dev->get_frame_data(rs::stream::color));
      memcpy(rgb_img.data, rgb_frame, rgb_img.cols*rgb_img.rows*sizeof(uint8_t)*rgb_img.channels());
      header.frame_id = "rgb_frame" + std::to_string(i);
      cv_img.header = header;
      cv_img.encoding = "bgr8";
      cv_img.image = rgb_img;
      rgb_pubs[i].publish(cv_img);
      rgb_infos[i].header = header;
      rgb_info_pubs[i].publish(rgb_infos[i]);
      ++i;
    }
    ++header.seq;
  }

  return EXIT_SUCCESS;
}
catch(const rs::error & e)
{
    std::cerr << "RealSense error calling " << e.get_failed_function() << "("
        << e.get_failed_args() << "):\n    " << e.what() << std::endl;
    return EXIT_FAILURE;
}
catch(const std::exception & e)
{
    std::cerr << e.what() << std::endl;
    return EXIT_FAILURE;
}
<|endoftext|>


<commit_before>#include "TextureAtlas.h"

TextureAtlas::TextureAtlas(const std::string& textureFileName)
{
    sf::Image i;
    if (!i.loadFromFile("Res/Textures/" + textureFileName + ".png"))
    {
        throw std::runtime_error("Unable to open image: " + textureFileName);
    }
    loadFromImage(i);

    m_imageSize             = 256;
    m_individualTextureSize = 16;
}

std::array<GLfloat, 8> TextureAtlas::getTexture(const sf::Vector2i& coords)
{
    static const GLfloat TEX_PER_ROW      = (GLfloat)m_imageSize / (GLfloat)m_individualTextureSize;
    static const GLfloat INDV_TEX_SIZE    = 1.0f / TEX_PER_ROW;
    static const GLfloat PIXEL_SIZE       = 1.0f / (float)m_imageSize;

    GLfloat xMin = (coords.x * INDV_TEX_SIZE) + 0.5 * PIXEL_SIZE;
    GLfloat yMin = (coords.y * INDV_TEX_SIZE) + 0.5 * PIXEL_SIZE;

    GLfloat xMax = (xMin + INDV_TEX_SIZE) - 0.5 * PIXEL_SIZE;
    GLfloat yMax = (yMin + INDV_TEX_SIZE) - 0.5 * PIXEL_SIZE;

    return
    {
        xMax, yMax,
        xMin, yMax,
        xMin, yMin,
        xMax, yMin
    };
}
<commit_msg>Fix to compile on MacOSX<commit_after>#include "TextureAtlas.h"
#include <array>

TextureAtlas::TextureAtlas(const std::string& textureFileName)
{
    sf::Image i;
    if (!i.loadFromFile("Res/Textures/" + textureFileName + ".png"))
    {
        throw std::runtime_error("Unable to open image: " + textureFileName);
    }
    loadFromImage(i);

    m_imageSize             = 256;
    m_individualTextureSize = 16;
}

std::array<GLfloat, 8> TextureAtlas::getTexture(const sf::Vector2i& coords)
{
    static const GLfloat TEX_PER_ROW      = (GLfloat)m_imageSize / (GLfloat)m_individualTextureSize;
    static const GLfloat INDV_TEX_SIZE    = 1.0f / TEX_PER_ROW;
    static const GLfloat PIXEL_SIZE       = 1.0f / (float)m_imageSize;

    GLfloat xMin = (coords.x * INDV_TEX_SIZE) + 0.5 * PIXEL_SIZE;
    GLfloat yMin = (coords.y * INDV_TEX_SIZE) + 0.5 * PIXEL_SIZE;

    GLfloat xMax = (xMin + INDV_TEX_SIZE) - 0.5 * PIXEL_SIZE;
    GLfloat yMax = (yMin + INDV_TEX_SIZE) - 0.5 * PIXEL_SIZE;

    return
    {
        xMax, yMax,
        xMin, yMax,
        xMin, yMin,
        xMax, yMin
    };
}
<|endoftext|>


<commit_before>#include "tocman.h"
#include <poppler-qt4.h>

TocManager::TocManager(const QString &path, QObject *parent)
    : QObject(parent),
      _path(path),
      _coordinator(path, this) { }

TocManager::~TocManager() { }

void TocManager::refresh() {
  Poppler::Document *doc = Poppler::Document::load(_path);

  if (doc) {
    QList<Choice> choices;
    QDomDocument *toc = doc->toc();
    if (toc) {
      QDomNode child = toc->documentElement();
      while (!child.isNull()) {
        if (child.isElement()) {
          QDomElement el = child.toElement();
          QString destName = el.attribute("DestinationName", "");
          Poppler::LinkDestination *dest = doc->linkDestination(destName);
          QUrl url("file:" + _path + "#page:" + QString::number(dest->pageNumber()));
          choices << Choice(el.nodeName(), url.toString());
          delete dest;
        }
        child = child.nextSibling();
      }
      delete toc;
    } else {
      qDebug() << "NO TOC";
    }

    emit contentsChanged(choices);
  }

  delete doc;
}

void TocManager::activate(Choice c) {
  _coordinator.openItem("runcible-view-pdf", QUrl(c.id()));
}
<commit_msg>PDF TOC is now hierarchical.<commit_after>#include "tocman.h"
#include <poppler-qt4.h>

TocManager::TocManager(const QString &path, QObject *parent)
    : QObject(parent),
      _path(path),
      _coordinator(path, this) { }

TocManager::~TocManager() { }

static void copyToc(const QUrl &docUrl, Poppler::Document *doc, QDomNode node,
    QList<Choice> &choices, int indent) {
  while (!node.isNull()) {
    if (node.isElement()) {
      QDomElement el = node.toElement();
      QString destName = el.attribute("DestinationName", QString());
      if (!destName.isNull()) {
        Poppler::LinkDestination *dest = doc->linkDestination(destName);
        QUrl refUrl(docUrl);
        refUrl.setFragment("page:" + QString::number(dest->pageNumber()));
        delete dest;

        QString displayName(QString(indent * 2, ' ') + el.nodeName());
        choices << Choice(displayName, refUrl.toString());
      }
    }
    if (node.hasChildNodes()) {
      copyToc(docUrl, doc, node.firstChild(), choices, indent + 1);
    }
    node = node.nextSibling();
  }
}

void TocManager::refresh() {
  Poppler::Document *doc = Poppler::Document::load(_path);

  if (doc) {
    QList<Choice> choices;
    QUrl docUrl("file:" + _path);
    QDomDocument *toc = doc->toc();
    if (toc) {
      QDomNode child = toc->documentElement();
      copyToc(docUrl, doc, child, choices, 0);
      /*
      while (!child.isNull()) {
        if (child.isElement()) {
          QDomElement el = child.toElement();
          QString destName = el.attribute("DestinationName", "");
          Poppler::LinkDestination *dest = doc->linkDestination(destName);
          QUrl url("file:" + _path + "#page:" + QString::number(dest->pageNumber()));
          choices << Choice(el.nodeName(), url.toString());
          delete dest;
        }
        child = child.nextSibling();
      }
      */
      delete toc;
    } else {
      qDebug() << "NO TOC";
    }

    emit contentsChanged(choices);
  }

  delete doc;
}

void TocManager::activate(Choice c) {
  qDebug() << c.id();
  _coordinator.openItem("runcible-view-pdf", QUrl(c.id()));
}
<|endoftext|>


<commit_before>//Copyright (c) 2017 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.

#include "infill.h"
#include "LayerPlan.h"
#include "TopSurface.h"

namespace cura
{

TopSurface::TopSurface()
{
    //Do nothing. Areas stays empty.
}

TopSurface::TopSurface(SliceMeshStorage& mesh, size_t layer_number)
{
    //The top surface is all parts of the mesh where there's no mesh above it, so find the layer above it first.
    Polygons mesh_above;
    if (layer_number < mesh.layers.size() - 1)
    {
        mesh_above = mesh.layers[layer_number + 1].getOutlines();
    } //If this is the top-most layer, mesh_above stays empty.

    areas = mesh.layers[layer_number].getOutlines().difference(mesh_above);
}

bool TopSurface::ironing(const SliceMeshStorage& mesh, const GCodePathConfig& line_config, LayerPlan& layer)
{
    if (areas.empty())
    {
        return false; //Nothing to do.
    }
    //Generate the lines to cover the surface.
    const EFillMethod pattern = mesh.getSettingAsFillMethod("ironing_pattern");
    const coord_t line_spacing = mesh.getSettingInMicrons("ironing_line_spacing");
    const coord_t outline_offset = -mesh.getSettingInMicrons("ironing_inset");
    const coord_t line_width = line_config.getLineWidth();
    const double direction = mesh.skin_angles[layer.getLayerNr() % mesh.skin_angles.size()] + 90.0; //Always perpendicular to the skin lines.
    constexpr coord_t infill_overlap = 0;
    constexpr coord_t shift = 0;
    Infill infill_generator(pattern, areas, outline_offset, line_width, line_spacing, infill_overlap, direction, layer.z - 10, shift);
    Polygons ironing_polygons;
    Polygons ironing_lines;
    infill_generator.generate(ironing_polygons, ironing_lines);

    //Add the lines as travel moves to the layer plan.
    bool added = false;
    const float ironing_flow = mesh.getSettingAsRatio("ironing_flow");
    if (!ironing_polygons.empty())
    {
        layer.addPolygonsByOptimizer(ironing_polygons, &line_config, nullptr, EZSeamType::SHORTEST, Point(0, 0), 0, false, ironing_flow);
        added = true;
    }
    if (!ironing_lines.empty())
    {
        layer.addLinesByOptimizer(ironing_lines, &line_config, SpaceFillType::PolyLines, 0, ironing_flow);
        added = true;
    }
    return added;
}

}<commit_msg>Start ironing at corner perpendicular to ironing lines<commit_after>//Copyright (c) 2017 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.

#include "infill.h"
#include "LayerPlan.h"
#include "TopSurface.h"

namespace cura
{

TopSurface::TopSurface()
{
    //Do nothing. Areas stays empty.
}

TopSurface::TopSurface(SliceMeshStorage& mesh, size_t layer_number)
{
    //The top surface is all parts of the mesh where there's no mesh above it, so find the layer above it first.
    Polygons mesh_above;
    if (layer_number < mesh.layers.size() - 1)
    {
        mesh_above = mesh.layers[layer_number + 1].getOutlines();
    } //If this is the top-most layer, mesh_above stays empty.

    areas = mesh.layers[layer_number].getOutlines().difference(mesh_above);
}

bool TopSurface::ironing(const SliceMeshStorage& mesh, const GCodePathConfig& line_config, LayerPlan& layer)
{
    if (areas.empty())
    {
        return false; //Nothing to do.
    }
    //Generate the lines to cover the surface.
    const EFillMethod pattern = mesh.getSettingAsFillMethod("ironing_pattern");
    const coord_t line_spacing = mesh.getSettingInMicrons("ironing_line_spacing");
    const coord_t outline_offset = -mesh.getSettingInMicrons("ironing_inset");
    const coord_t line_width = line_config.getLineWidth();
    const double direction = mesh.skin_angles[layer.getLayerNr() % mesh.skin_angles.size()] + 90.0; //Always perpendicular to the skin lines.
    constexpr coord_t infill_overlap = 0;
    constexpr coord_t shift = 0;
    Infill infill_generator(pattern, areas, outline_offset, line_width, line_spacing, infill_overlap, direction, layer.z - 10, shift);
    Polygons ironing_polygons;
    Polygons ironing_lines;
    infill_generator.generate(ironing_polygons, ironing_lines);

    if (pattern == EFillMethod::LINES || pattern == EFillMethod::ZIG_ZAG)
    {
        //Move to a corner of the area that is perpendicular to the ironing lines, to reduce the number of seams.
        const AABB bounding_box(areas);
        PointMatrix rotate(-direction + 90);
        const Point center = bounding_box.getMiddle();
        const Point far_away = rotate.apply(Point(0, vSize(bounding_box.max - center) * 100)); //Some direction very far away in the direction perpendicular to the ironing lines, relative to the centre.
        //Two options to start, both perpendicular to the ironing lines. Which is closer?
        const Point front_side = PolygonUtils::findNearestVert(center + far_away, areas).p();
        const Point back_side = PolygonUtils::findNearestVert(center - far_away, areas).p();
        if (vSize2(layer.getLastPosition() - front_side) < vSize2(layer.getLastPosition() - back_side))
        {
            layer.addTravel(front_side);
        }
        else
        {
            layer.addTravel(back_side);
        }
    }

    //Add the lines as travel moves to the layer plan.
    bool added = false;
    const float ironing_flow = mesh.getSettingAsRatio("ironing_flow");
    if (!ironing_polygons.empty())
    {
        layer.addPolygonsByOptimizer(ironing_polygons, &line_config, nullptr, EZSeamType::SHORTEST, Point(0, 0), 0, false, ironing_flow);
        added = true;
    }
    if (!ironing_lines.empty())
    {
        layer.addLinesByOptimizer(ironing_lines, &line_config, SpaceFillType::PolyLines, 0, ironing_flow);
        added = true;
    }
    return added;
}

}<|endoftext|>


<commit_before>/*!
*	@file	Liepa.cpp
*	@brief	Implementation of Liepa's subdivision scheme
*/

#include <cmath>
#include "Liepa.h"

namespace psalm
{

/*!
*	Sets default values for Liepa subdivision.
*/

Liepa::Liepa()
{
	alpha = sqrt(2);
}

/*!
*	Sets current value of density parameter for the algorithm.
*
*	@param alpha New value for density parameter
*/

void Liepa::set_alpha(double alpha)
{
	this->alpha = alpha;
}

/*!
*	@returns Current value of density parameter for the algorithm.
*/

double Liepa::get_alpha()
{
	return(alpha);
}

/*!
*	Applies Liepa's subdivision scheme to the given mesh. The mesh will be
*	irreversibly _changed_ by this function.
*
*	@param	input_mesh Mesh on which the algorithm is applied
*	@return	true on success, else false
*/

bool Liepa::apply_to(mesh& input_mesh)
{
	/*
		Compute scale attribute as the average length of the edges
		adjacent to a vertex.

		ASSUMPTION: Mesh consists of a single triangulated hole, i.e.
		_all_ vertices are boundary vertices.
	*/

	for(size_t i = 0; i < input_mesh.num_vertices(); i++)
	{
		vertex* v = input_mesh.get_vertex(i);
		size_t n = v->valency();

		double attribute = 0.0;
		for(size_t i = 0; i < n; i++)
			attribute += v->get_edge(i)->calc_length()/static_cast<double>(n);

		v->set_scale_attribute(attribute);
	}

	bool created_new_triangle;
	do
	{
		// if no new triangle has been created, the algorithm
		// terminates
		created_new_triangle = false;

		// Need to store the number of faces here because new faces
		// might be created within the for-loop below. These must _not_
		// be considered in the same iteration.
		size_t num_faces = input_mesh.num_faces();

		// Compute scale attribute for each face of the mesh
		for(size_t i = 0; i < num_faces; i++)
		{
			face* f = input_mesh.get_face(i);
			if(f->num_edges() != 3)
			{
				std::cerr << "psalm: Input mesh contains non-triangular face. Liepa's subdivision scheme is not applicable.\n";
				return(false);
			}

			vertex* vertices[3];
			vertices[0] = f->get_vertex(0);
			vertices[1] = f->get_vertex(1);
			vertices[2] = f->get_vertex(2);

			// Compute centroid and scale attribute. If the scale
			// attribute test fails, replace the triangle.

			v3ctor centroid_pos;
			double centroid_scale_attribute = 0.0;

			for(size_t j = 0; j < 3; j++)
			{
				centroid_pos += vertices[j]->get_position()/3.0;
				centroid_scale_attribute += vertices[j]->get_scale_attribute()/3.0;
			}

			size_t tests_failed = 0;
			for(size_t j = 0; j < 3; j++)
			{
				double scaled_distance = alpha*(centroid_pos - vertices[j]->get_position()).length();
				if(	scaled_distance > centroid_scale_attribute &&
					scaled_distance > vertices[j]->get_scale_attribute())
				{
					// We will replace the triangle only if
					// _all_ three tests failed
					tests_failed++;
				}
			}

			// Replace old triangle with three smaller triangles
			if(tests_failed == 3)
			{
				created_new_triangle = true;

				vertex* centroid_vertex = input_mesh.add_vertex(centroid_pos);
				centroid_vertex->set_scale_attribute(centroid_scale_attribute);

				// Remove old face and replace it by three new
				// faces. Calling remove_face() will ensure
				// that the edges are updated correctly.

				input_mesh.remove_face(f);
				delete f;

				face* new_face1 = input_mesh.add_face(vertices[0], vertices[1], centroid_vertex);
				face* new_face2 = input_mesh.add_face(centroid_vertex, vertices[1], vertices[2]);
				face* new_face3 = input_mesh.add_face(vertices[0], centroid_vertex, vertices[2]);

				if(!new_face1 || !new_face2 || !new_face3)
				{
					std::cerr << "psalm: Error: Liepa::apply_to(): Unable to add new face\n";
					return(false);
				}

				num_faces--;
				i--;

				// Relax edges afterwards to maintain
				// Delaunay-like mesh

				input_mesh.relax_edge(new_face1->get_edge(0).e);
				input_mesh.relax_edge(new_face2->get_edge(1).e);
				input_mesh.relax_edge(new_face3->get_edge(2).e);
			}
		}

		if(!created_new_triangle)
			return(true);

		// Relax interior edges
		bool relaxed_edge;
		do
		{
			relaxed_edge = false;
			for(size_t i = 0; i < input_mesh.num_edges(); i++)
			{
				if(input_mesh.relax_edge(input_mesh.get_edge(i)))
					relaxed_edge = true;
			}
		}
		while(relaxed_edge);

		/*
			XXX: This might lead to wrong results...

			// Calculate new scaling attributes. TODO: This should become a
			// function.
			for(std::vector<vertex*>::iterator v_it = V.begin(); v_it < V.end(); v_it++)
			{
				vertex* v = *v_it;
				size_t n = v->valency();

				if(!v->is_on_boundary())
					continue;

				double attribute = 0.0;
				for(size_t i = 0; i < n; i++)
					attribute += v->get_edge(i)->calc_length()/static_cast<double>(n);

				v->set_scale_attribute(attribute);
			}
		*/

		if(!relaxed_edge)
			continue;
	}
	while(created_new_triangle);

	return(true);
}

} // end of namespace "psalm"
<commit_msg>Temporary change in `Liepa` subdivision algorithm<commit_after>/*!
*	@file	Liepa.cpp
*	@brief	Implementation of Liepa's subdivision scheme
*/

#include <cmath>
#include "Liepa.h"

namespace psalm
{

/*!
*	Sets default values for Liepa subdivision.
*/

Liepa::Liepa()
{
	alpha = sqrt(2);
}

/*!
*	Sets current value of density parameter for the algorithm.
*
*	@param alpha New value for density parameter
*/

void Liepa::set_alpha(double alpha)
{
	this->alpha = alpha;
}

/*!
*	@returns Current value of density parameter for the algorithm.
*/

double Liepa::get_alpha()
{
	return(alpha);
}

/*!
*	Applies Liepa's subdivision scheme to the given mesh. The mesh will be
*	irreversibly _changed_ by this function.
*
*	@param	input_mesh Mesh on which the algorithm is applied
*	@return	true on success, else false
*/

bool Liepa::apply_to(mesh& input_mesh)
{
	/*
		Compute scale attribute as the average length of the edges
		adjacent to a vertex.

		ASSUMPTION: Mesh consists of a single triangulated hole, i.e.
		_all_ vertices are boundary vertices.
	*/

	for(size_t i = 0; i < input_mesh.num_vertices(); i++)
	{
		vertex* v = input_mesh.get_vertex(i);
		size_t n = v->valency();

		double attribute = 0.0;
		for(size_t i = 0; i < n; i++)
			attribute += v->get_edge(i)->calc_length()/static_cast<double>(n);

		v->set_scale_attribute(attribute);
	}

	bool created_new_triangle;
	do
	{
		// if no new triangle has been created, the algorithm
		// terminates
		created_new_triangle = false;

		// Need to store the number of faces here because new faces
		// might be created within the for-loop below. These must _not_
		// be considered in the same iteration.
		size_t num_faces = input_mesh.num_faces();

		// Compute scale attribute for each face of the mesh
		for(size_t i = 0; i < num_faces; i++)
		{
			face* f = input_mesh.get_face(i);
			if(f->num_edges() != 3)
			{
				std::cerr << "psalm: Input mesh contains non-triangular face. Liepa's subdivision scheme is not applicable.\n";
				return(false);
			}

			vertex* vertices[3];
			vertices[0] = f->get_vertex(0);
			vertices[1] = f->get_vertex(1);
			vertices[2] = f->get_vertex(2);

			// Compute centroid and scale attribute. If the scale
			// attribute test fails, replace the triangle.

			v3ctor centroid_pos;
			double centroid_scale_attribute = 0.0;

			for(size_t j = 0; j < 3; j++)
			{
				centroid_pos += vertices[j]->get_position()/3.0;
				centroid_scale_attribute += vertices[j]->get_scale_attribute()/3.0;
			}

			size_t tests_failed = 0;
			for(size_t j = 0; j < 3; j++)
			{
				double scaled_distance = alpha*(centroid_pos - vertices[j]->get_position()).length();
				if(	scaled_distance > centroid_scale_attribute &&
					scaled_distance > vertices[j]->get_scale_attribute())
				{
					// We will replace the triangle only if
					// _all_ three tests failed
					tests_failed++;
				}
			}

			// Replace old triangle with three smaller triangles
			if(tests_failed == 3)
			{
				created_new_triangle = true;

				vertex* centroid_vertex = input_mesh.add_vertex(centroid_pos);
				centroid_vertex->set_scale_attribute(centroid_scale_attribute);

				// Remove old face and replace it by three new
				// faces. Calling remove_face() will ensure
				// that the edges are updated correctly.

				input_mesh.remove_face(f);
				delete f;

				face* new_face1 = input_mesh.add_face(vertices[0], vertices[1], centroid_vertex);
				face* new_face2 = input_mesh.add_face(centroid_vertex, vertices[1], vertices[2]);
				face* new_face3 = input_mesh.add_face(vertices[0], centroid_vertex, vertices[2]);

				if(!new_face1 || !new_face2 || !new_face3)
				{
					std::cerr << "psalm: Error: Liepa::apply_to(): Unable to add new face\n";
					return(false);
				}

				num_faces--;
				i--;

				// Relax edges afterwards to maintain
				// Delaunay-like mesh

				input_mesh.relax_edge(new_face1->get_edge(0).e);
				input_mesh.relax_edge(new_face2->get_edge(1).e);
				input_mesh.relax_edge(new_face3->get_edge(2).e);
			}
		}

		if(!created_new_triangle)
			return(true);

		// Relax interior edges
		bool relaxed_edge;
		do
		{
			relaxed_edge = false;
			for(size_t i = 0; i < input_mesh.num_edges(); i++)
			{
				if(input_mesh.relax_edge(input_mesh.get_edge(i)))
					relaxed_edge = true;
			}
		}
		while(relaxed_edge);

		/*
			XXX: This might lead to wrong results...

			// Calculate new scaling attributes. TODO: This should become a
			// function.
			for(size_t i = 0; i < input_mesh.num_vertices(); i++)
			{
				vertex* v = input_mesh.get_vertex(i);
				size_t n = v->valency();

				if(!v->is_on_boundary())
					continue;

				double attribute = 0.0;
				for(size_t i = 0; i < n; i++)
					attribute += v->get_edge(i)->calc_length()/static_cast<double>(n);

				v->set_scale_attribute(attribute);
			}
		*/

		if(!relaxed_edge)
			continue;
	}
	while(created_new_triangle);

	return(true);
}

} // end of namespace "psalm"
<|endoftext|>