<commit_before>/*
 * Copyright (C) 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "src/trace_processor/stack_profile_tracker.h"

#include "src/trace_processor/trace_processor_context.h"

#include "perfetto/base/logging.h"
#include "perfetto/ext/base/string_utils.h"

namespace perfetto {
namespace trace_processor {

StackProfileTracker::InternLookup::~InternLookup() = default;

StackProfileTracker::StackProfileTracker(TraceProcessorContext* context)
    : context_(context), empty_(kNullStringId) {}

StackProfileTracker::~StackProfileTracker() = default;

StringId StackProfileTracker::GetEmptyStringId() {
  if (empty_ == kNullStringId) {
    empty_ = context_->storage->InternString({"", 0});
  }

  return empty_;
}

void StackProfileTracker::AddString(SourceStringId id, base::StringView str) {
  string_map_.emplace(id, str.ToStdString());
}

base::Optional<int64_t> StackProfileTracker::AddMapping(
    SourceMappingId id,
    const SourceMapping& mapping,
    const InternLookup* intern_lookup) {
  std::string path;
  for (SourceStringId str_id : mapping.name_ids) {
    auto opt_str =
        FindString(str_id, intern_lookup, InternedStringType::kMappingPath);
    if (!opt_str)
      break;
    path += "/" + *opt_str;
  }

  auto opt_build_id = FindAndInternString(mapping.build_id, intern_lookup,
                                          InternedStringType::kBuildId);
  if (!opt_build_id) {
    context_->storage->IncrementStats(stats::stackprofile_invalid_string_id);
    PERFETTO_DFATAL("Invalid string.");
    return base::nullopt;
  }
  const StringId raw_build_id = opt_build_id.value();
  NullTermStringView raw_build_id_str =
      context_->storage->GetString(raw_build_id);
  StringId build_id = GetEmptyStringId();
  if (raw_build_id_str.size() > 0) {
    std::string hex_build_id =
        base::ToHex(raw_build_id_str.c_str(), raw_build_id_str.size());
    build_id = context_->storage->InternString(base::StringView(hex_build_id));
  }

  TraceStorage::StackProfileMappings::Row row{
      build_id,
      static_cast<int64_t>(mapping.exact_offset),
      static_cast<int64_t>(mapping.start_offset),
      static_cast<int64_t>(mapping.start),
      static_cast<int64_t>(mapping.end),
      static_cast<int64_t>(mapping.load_bias),
      context_->storage->InternString(base::StringView(path))};

  int64_t cur_row;
  auto it = mapping_idx_.find(row);
  if (it != mapping_idx_.end()) {
    cur_row = it->second;
  } else {
    cur_row = context_->storage->mutable_stack_profile_mappings()->Insert(row);
    mapping_idx_.emplace(row, cur_row);
  }
  mappings_.emplace(id, cur_row);
  return cur_row;
}

base::Optional<int64_t> StackProfileTracker::AddFrame(
    SourceFrameId id,
    const SourceFrame& frame,
    const InternLookup* intern_lookup) {
  auto opt_str_id = FindAndInternString(frame.name_id, intern_lookup,
                                        InternedStringType::kFunctionName);
  if (!opt_str_id) {
    context_->storage->IncrementStats(stats::stackprofile_invalid_string_id);
    PERFETTO_DFATAL("Invalid string.");
    return base::nullopt;
  }
  const StringId& str_id = opt_str_id.value();

  auto maybe_mapping = FindMapping(frame.mapping_id, intern_lookup);
  if (!maybe_mapping) {
    context_->storage->IncrementStats(stats::stackprofile_invalid_mapping_id);
    PERFETTO_ELOG("Invalid mapping for frame %" PRIu64, id);
    return base::nullopt;
  }
  int64_t mapping_row = *maybe_mapping;

  TraceStorage::StackProfileFrames::Row row{str_id, mapping_row,
                                            static_cast<int64_t>(frame.rel_pc)};

  int64_t cur_row;
  auto it = frame_idx_.find(row);
  if (it != frame_idx_.end()) {
    cur_row = it->second;
  } else {
    cur_row = context_->storage->mutable_stack_profile_frames()->Insert(row);
    frame_idx_.emplace(row, cur_row);
  }
  frames_.emplace(id, cur_row);
  return cur_row;
}

base::Optional<int64_t> StackProfileTracker::AddCallstack(
    SourceCallstackId id,
    const SourceCallstack& frame_ids,
    const InternLookup* intern_lookup) {
  // TODO(fmayer): This should be NULL.
  int64_t parent_id = -1;
  for (size_t depth = 0; depth < frame_ids.size(); ++depth) {
    std::vector<SourceFrameId> frame_subset = frame_ids;
    frame_subset.resize(depth + 1);
    auto self_it = callstacks_from_frames_.find(frame_subset);
    if (self_it != callstacks_from_frames_.end()) {
      parent_id = self_it->second;
      continue;
    }

    SourceFrameId frame_id = frame_ids[depth];
    auto maybe_frame_row = FindFrame(frame_id, intern_lookup);
    if (!maybe_frame_row) {
      context_->storage->IncrementStats(stats::stackprofile_invalid_frame_id);
      PERFETTO_ELOG("Unknown frame in callstack; ignoring.");
      return base::nullopt;
    }
    int64_t frame_row = *maybe_frame_row;

    tables::StackProfileCallsiteTable::Row row{static_cast<int64_t>(depth),
                                               parent_id, frame_row};

    int64_t self_id;
    auto callsite_it = callsite_idx_.find(row);
    if (callsite_it != callsite_idx_.end()) {
      self_id = callsite_it->second;
    } else {
      self_id =
          context_->storage->mutable_stack_profile_callsite_table()->Insert(
              row);
      callsite_idx_.emplace(row, self_id);
    }
    parent_id = self_id;
  }
  callstacks_.emplace(id, parent_id);
  return parent_id;
}

int64_t StackProfileTracker::GetDatabaseFrameIdForTesting(
    SourceFrameId frame_id) {
  auto it = frames_.find(frame_id);
  if (it == frames_.end()) {
    PERFETTO_DFATAL("Invalid frame.");
    return -1;
  }
  return it->second;
}

base::Optional<StringId> StackProfileTracker::FindAndInternString(
    SourceStringId id,
    const InternLookup* intern_lookup,
    StackProfileTracker::InternedStringType type) {
  if (id == 0)
    return GetEmptyStringId();

  auto opt_str = FindString(id, intern_lookup, type);
  if (!opt_str)
    return GetEmptyStringId();

  return context_->storage->InternString(base::StringView(*opt_str));
}

base::Optional<std::string> StackProfileTracker::FindString(
    SourceStringId id,
    const InternLookup* intern_lookup,
    StackProfileTracker::InternedStringType type) {
  if (id == 0)
    return "";

  auto it = string_map_.find(id);
  if (it == string_map_.end()) {
    if (intern_lookup) {
      auto str = intern_lookup->GetString(id, type);
      if (!str) {
        context_->storage->IncrementStats(
            stats::stackprofile_invalid_string_id);
        PERFETTO_DFATAL("Invalid string.");
        return base::nullopt;
      }
      return str->ToStdString();
    }
    return base::nullopt;
  }

  return it->second;
}

base::Optional<int64_t> StackProfileTracker::FindMapping(
    SourceMappingId mapping_id,
    const InternLookup* intern_lookup) {
  base::Optional<int64_t> res;
  auto it = mappings_.find(mapping_id);
  if (it == mappings_.end()) {
    if (intern_lookup) {
      auto interned_mapping = intern_lookup->GetMapping(mapping_id);
      if (interned_mapping) {
        res = AddMapping(mapping_id, *interned_mapping, intern_lookup);
        return res;
      }
    }
    context_->storage->IncrementStats(stats::stackprofile_invalid_mapping_id);
    PERFETTO_ELOG("Unknown mapping %" PRIu64 " : %zu", mapping_id,
                  mappings_.size());
    return res;
  }
  res = it->second;
  return res;
}

base::Optional<int64_t> StackProfileTracker::FindFrame(
    SourceFrameId frame_id,
    const InternLookup* intern_lookup) {
  base::Optional<int64_t> res;
  auto it = frames_.find(frame_id);
  if (it == frames_.end()) {
    if (intern_lookup) {
      auto interned_frame = intern_lookup->GetFrame(frame_id);
      if (interned_frame) {
        res = AddFrame(frame_id, *interned_frame, intern_lookup);
        return res;
      }
    }
    context_->storage->IncrementStats(stats::stackprofile_invalid_frame_id);
    PERFETTO_DFATAL("Unknown frame %" PRIu64 " : %zu", frame_id,
                    frames_.size());
    return res;
  }
  res = it->second;
  return res;
}

base::Optional<int64_t> StackProfileTracker::FindCallstack(
    SourceCallstackId callstack_id,
    const InternLookup* intern_lookup) {
  base::Optional<int64_t> res;
  auto it = callstacks_.find(callstack_id);
  if (it == callstacks_.end()) {
    auto interned_callstack = intern_lookup->GetCallstack(callstack_id);
    if (interned_callstack) {
      res = AddCallstack(callstack_id, *interned_callstack, intern_lookup);
      return res;
    }
    context_->storage->IncrementStats(stats::stackprofile_invalid_callstack_id);
    PERFETTO_DFATAL("Unknown callstack %" PRIu64 " : %zu", callstack_id,
                    callstacks_.size());
    return res;
  }
  res = it->second;
  return res;
}

void StackProfileTracker::ClearIndices() {
  string_map_.clear();
  mappings_.clear();
  callstacks_from_frames_.clear();
  callstacks_.clear();
  frames_.clear();
}

}  // namespace trace_processor
}  // namespace perfetto
<commit_msg>Stack profiles: Reuse existing frame/module rows rather than adding one per sequence<commit_after>/*
 * Copyright (C) 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "src/trace_processor/stack_profile_tracker.h"

#include "src/trace_processor/trace_processor_context.h"

#include "perfetto/base/logging.h"
#include "perfetto/ext/base/string_utils.h"

namespace perfetto {
namespace trace_processor {

StackProfileTracker::InternLookup::~InternLookup() = default;

StackProfileTracker::StackProfileTracker(TraceProcessorContext* context)
    : context_(context), empty_(kNullStringId) {}

StackProfileTracker::~StackProfileTracker() = default;

StringId StackProfileTracker::GetEmptyStringId() {
  if (empty_ == kNullStringId) {
    empty_ = context_->storage->InternString({"", 0});
  }

  return empty_;
}

void StackProfileTracker::AddString(SourceStringId id, base::StringView str) {
  string_map_.emplace(id, str.ToStdString());
}

base::Optional<int64_t> StackProfileTracker::AddMapping(
    SourceMappingId id,
    const SourceMapping& mapping,
    const InternLookup* intern_lookup) {
  std::string path;
  for (SourceStringId str_id : mapping.name_ids) {
    auto opt_str =
        FindString(str_id, intern_lookup, InternedStringType::kMappingPath);
    if (!opt_str)
      break;
    path += "/" + *opt_str;
  }

  auto opt_build_id = FindAndInternString(mapping.build_id, intern_lookup,
                                          InternedStringType::kBuildId);
  if (!opt_build_id) {
    context_->storage->IncrementStats(stats::stackprofile_invalid_string_id);
    PERFETTO_DFATAL("Invalid string.");
    return base::nullopt;
  }
  const StringId raw_build_id = opt_build_id.value();
  NullTermStringView raw_build_id_str =
      context_->storage->GetString(raw_build_id);
  StringId build_id = GetEmptyStringId();
  if (raw_build_id_str.size() > 0) {
    std::string hex_build_id =
        base::ToHex(raw_build_id_str.c_str(), raw_build_id_str.size());
    build_id = context_->storage->InternString(base::StringView(hex_build_id));
  }

  TraceStorage::StackProfileMappings::Row row{
      build_id,
      static_cast<int64_t>(mapping.exact_offset),
      static_cast<int64_t>(mapping.start_offset),
      static_cast<int64_t>(mapping.start),
      static_cast<int64_t>(mapping.end),
      static_cast<int64_t>(mapping.load_bias),
      context_->storage->InternString(base::StringView(path))};

  TraceStorage::StackProfileMappings* mappings =
      context_->storage->mutable_stack_profile_mappings();
  int64_t cur_row = -1;
  auto it = mapping_idx_.find(row);
  if (it != mapping_idx_.end()) {
    cur_row = it->second;
  } else {
    std::vector<int64_t> db_mappings =
        mappings->FindMappingRow(row.name_id, row.build_id);
    for (const int64_t preexisting_mapping : db_mappings) {
      PERFETTO_DCHECK(preexisting_mapping >= 0);
      size_t preexisting_row_id = static_cast<size_t>(preexisting_mapping);
      TraceStorage::StackProfileMappings::Row preexisting_row{
          mappings->build_ids()[preexisting_row_id],
          mappings->exact_offsets()[preexisting_row_id],
          mappings->start_offsets()[preexisting_row_id],
          mappings->starts()[preexisting_row_id],
          mappings->ends()[preexisting_row_id],
          mappings->load_biases()[preexisting_row_id],
          mappings->names()[preexisting_row_id]};

      if (row == preexisting_row) {
        cur_row = preexisting_mapping;
      }
    }
    if (cur_row == -1) {
      cur_row =
          context_->storage->mutable_stack_profile_mappings()->Insert(row);
    }
    mapping_idx_.emplace(row, cur_row);
  }
  mappings_.emplace(id, cur_row);
  return cur_row;
}

base::Optional<int64_t> StackProfileTracker::AddFrame(
    SourceFrameId id,
    const SourceFrame& frame,
    const InternLookup* intern_lookup) {
  auto opt_str_id = FindAndInternString(frame.name_id, intern_lookup,
                                        InternedStringType::kFunctionName);
  if (!opt_str_id) {
    context_->storage->IncrementStats(stats::stackprofile_invalid_string_id);
    PERFETTO_DFATAL("Invalid string.");
    return base::nullopt;
  }
  const StringId& str_id = opt_str_id.value();

  auto maybe_mapping = FindMapping(frame.mapping_id, intern_lookup);
  if (!maybe_mapping) {
    context_->storage->IncrementStats(stats::stackprofile_invalid_mapping_id);
    PERFETTO_ELOG("Invalid mapping for frame %" PRIu64, id);
    return base::nullopt;
  }
  int64_t mapping_row = *maybe_mapping;

  TraceStorage::StackProfileFrames::Row row{str_id, mapping_row,
                                            static_cast<int64_t>(frame.rel_pc)};

  int64_t cur_row;
  auto it = frame_idx_.find(row);
  if (it != frame_idx_.end()) {
    cur_row = it->second;
  } else {
    cur_row = context_->storage->stack_profile_frames().FindFrameRow(
        static_cast<size_t>(mapping_row), frame.rel_pc);
    if (cur_row == -1) {
      cur_row = context_->storage->mutable_stack_profile_frames()->Insert(row);
    }
    frame_idx_.emplace(row, cur_row);
  }
  frames_.emplace(id, cur_row);
  return cur_row;
}

base::Optional<int64_t> StackProfileTracker::AddCallstack(
    SourceCallstackId id,
    const SourceCallstack& frame_ids,
    const InternLookup* intern_lookup) {
  // TODO(fmayer): This should be NULL.
  int64_t parent_id = -1;
  for (size_t depth = 0; depth < frame_ids.size(); ++depth) {
    std::vector<SourceFrameId> frame_subset = frame_ids;
    frame_subset.resize(depth + 1);
    auto self_it = callstacks_from_frames_.find(frame_subset);
    if (self_it != callstacks_from_frames_.end()) {
      parent_id = self_it->second;
      continue;
    }

    SourceFrameId frame_id = frame_ids[depth];
    auto maybe_frame_row = FindFrame(frame_id, intern_lookup);
    if (!maybe_frame_row) {
      context_->storage->IncrementStats(stats::stackprofile_invalid_frame_id);
      PERFETTO_ELOG("Unknown frame in callstack; ignoring.");
      return base::nullopt;
    }
    int64_t frame_row = *maybe_frame_row;

    tables::StackProfileCallsiteTable::Row row{static_cast<int64_t>(depth),
                                               parent_id, frame_row};

    int64_t self_id;
    auto callsite_it = callsite_idx_.find(row);
    if (callsite_it != callsite_idx_.end()) {
      self_id = callsite_it->second;
    } else {
      self_id =
          context_->storage->mutable_stack_profile_callsite_table()->Insert(
              row);
      callsite_idx_.emplace(row, self_id);
    }
    parent_id = self_id;
  }
  callstacks_.emplace(id, parent_id);
  return parent_id;
}

int64_t StackProfileTracker::GetDatabaseFrameIdForTesting(
    SourceFrameId frame_id) {
  auto it = frames_.find(frame_id);
  if (it == frames_.end()) {
    PERFETTO_DFATAL("Invalid frame.");
    return -1;
  }
  return it->second;
}

base::Optional<StringId> StackProfileTracker::FindAndInternString(
    SourceStringId id,
    const InternLookup* intern_lookup,
    StackProfileTracker::InternedStringType type) {
  if (id == 0)
    return GetEmptyStringId();

  auto opt_str = FindString(id, intern_lookup, type);
  if (!opt_str)
    return GetEmptyStringId();

  return context_->storage->InternString(base::StringView(*opt_str));
}

base::Optional<std::string> StackProfileTracker::FindString(
    SourceStringId id,
    const InternLookup* intern_lookup,
    StackProfileTracker::InternedStringType type) {
  if (id == 0)
    return "";

  auto it = string_map_.find(id);
  if (it == string_map_.end()) {
    if (intern_lookup) {
      auto str = intern_lookup->GetString(id, type);
      if (!str) {
        context_->storage->IncrementStats(
            stats::stackprofile_invalid_string_id);
        PERFETTO_DFATAL("Invalid string.");
        return base::nullopt;
      }
      return str->ToStdString();
    }
    return base::nullopt;
  }

  return it->second;
}

base::Optional<int64_t> StackProfileTracker::FindMapping(
    SourceMappingId mapping_id,
    const InternLookup* intern_lookup) {
  base::Optional<int64_t> res;
  auto it = mappings_.find(mapping_id);
  if (it == mappings_.end()) {
    if (intern_lookup) {
      auto interned_mapping = intern_lookup->GetMapping(mapping_id);
      if (interned_mapping) {
        res = AddMapping(mapping_id, *interned_mapping, intern_lookup);
        return res;
      }
    }
    context_->storage->IncrementStats(stats::stackprofile_invalid_mapping_id);
    PERFETTO_ELOG("Unknown mapping %" PRIu64 " : %zu", mapping_id,
                  mappings_.size());
    return res;
  }
  res = it->second;
  return res;
}

base::Optional<int64_t> StackProfileTracker::FindFrame(
    SourceFrameId frame_id,
    const InternLookup* intern_lookup) {
  base::Optional<int64_t> res;
  auto it = frames_.find(frame_id);
  if (it == frames_.end()) {
    if (intern_lookup) {
      auto interned_frame = intern_lookup->GetFrame(frame_id);
      if (interned_frame) {
        res = AddFrame(frame_id, *interned_frame, intern_lookup);
        return res;
      }
    }
    context_->storage->IncrementStats(stats::stackprofile_invalid_frame_id);
    PERFETTO_DFATAL("Unknown frame %" PRIu64 " : %zu", frame_id,
                    frames_.size());
    return res;
  }
  res = it->second;
  return res;
}

base::Optional<int64_t> StackProfileTracker::FindCallstack(
    SourceCallstackId callstack_id,
    const InternLookup* intern_lookup) {
  base::Optional<int64_t> res;
  auto it = callstacks_.find(callstack_id);
  if (it == callstacks_.end()) {
    auto interned_callstack = intern_lookup->GetCallstack(callstack_id);
    if (interned_callstack) {
      res = AddCallstack(callstack_id, *interned_callstack, intern_lookup);
      return res;
    }
    context_->storage->IncrementStats(stats::stackprofile_invalid_callstack_id);
    PERFETTO_DFATAL("Unknown callstack %" PRIu64 " : %zu", callstack_id,
                    callstacks_.size());
    return res;
  }
  res = it->second;
  return res;
}

void StackProfileTracker::ClearIndices() {
  string_map_.clear();
  mappings_.clear();
  callstacks_from_frames_.clear();
  callstacks_.clear();
  frames_.clear();
}

}  // namespace trace_processor
}  // namespace perfetto
<|endoftext|>


<commit_before><commit_msg>Renamed variable to make name more consistent with usage.<commit_after><|endoftext|>


<commit_before>/**
  MQTT433gateway - MQTT 433.92 MHz radio gateway utilizing ESPiLight
  Project home: https://github.com/puuu/MQTT433gateway/

  The MIT License (MIT)

  Copyright (c) 2017 Jan Losinski

  Permission is hereby granted, free of charge, to any person
  obtaining a copy of this software and associated documentation files
  (the "Software"), to deal in the Software without restriction,
  including without limitation the rights to use, copy, modify, merge,
  publish, distribute, sublicense, and/or sell copies of the Software,
  and to permit persons to whom the Software is furnished to do so,
  subject to the following conditions:

  The above copyright notice and this permission notice shall be
  included in all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  SOFTWARE.
*/

#include <ArduinoSimpleLogging.h>

#include <Version.h>

#include "MqttClient.h"

class PayloadString : public String {
 public:
  PayloadString(const uint8_t *data, unsigned int length) : String() {
    if (reserve(length)) {
      memcpy(buffer, data, length);
      len = length;
    }
  }
};

MqttClient::MqttClient(const Settings &settings, WiFiClient &client)
    : settings(settings), mqttClient(client), lastConnectAttempt(0) {}

MqttClient::~MqttClient() { mqttClient.disconnect(); }

void MqttClient::begin() {
  using namespace std::placeholders;
  mqttClient.setServer(settings.mqttBroker.c_str(), settings.mqttBrokerPort);

  mqttClient.setCallback(std::bind(&MqttClient::onMessage, this, _1, _2, _3));

  reconnect();
}

static String stateMessage(const bool online) {
  return String(F("{\"chipId\":\"")) + chipId() +
         String(F("\",\"firmware\":\"")) + fwVersion() + F("\",\"state\":\"") +
         String(online ? F("online") : F("offline")) + String(F("\"}"));
}

static String stateTopic(const String &devName) {
  return devName + F("/state");
}

bool MqttClient::connect() {
  if (0 == settings.mqttUser.length()) {
    return mqttClient.connect(settings.deviceName.c_str(),
                              stateTopic(settings.deviceName).c_str(), 0, true,
                              stateMessage(false).c_str());
  } else {
    return mqttClient.connect(
        settings.deviceName.c_str(), settings.mqttUser.c_str(),
        settings.mqttPassword.c_str(), stateTopic(settings.deviceName).c_str(),
        0, true, stateMessage(false).c_str());
  }
}

void MqttClient::reconnect() {
  if (lastConnectAttempt > 0 &&
      (millis() - lastConnectAttempt) < MQTT_CONNECTION_ATTEMPT_DELAY) {
    return;
  }

  if (!mqttClient.connected()) {
    Logger.debug.println(F("Try to (re)connect to MQTT broker"));
    if (connect()) {
      Logger.info.println(F("MQTT connected."));
      if (subsrcibe()) {
        mqttClient.publish(stateTopic(settings.deviceName).c_str(),
                           stateMessage(true).c_str(), true);
        Logger.info.println(F("MQTT subscribed."));
      } else {
        Logger.error.println(F("MQTT subsrcibe failed!"));
      }
    } else {
      Logger.error.println(F("MQTT connect failed!"));
    }
  }

  lastConnectAttempt = millis();
}

bool MqttClient::subsrcibe() {
  String topic = settings.mqttSendTopic + "+";

  Logger.debug.print(F("MQTT subscribe to topic: "));
  Logger.debug.println(topic);

  return mqttClient.subscribe(topic.c_str());
}

void MqttClient::loop() {
  reconnect();
  mqttClient.loop();
}

void MqttClient::onMessage(char *topic, uint8_t *payload, unsigned int length) {
  PayloadString strPayload(payload, length);
  String strTopic(topic);

  Logger.debug.print(F("New MQTT message: "));
  Logger.debug.print(strTopic);
  Logger.debug.print(F(" .. "));
  Logger.debug.println(strPayload);

  if (strTopic.startsWith(settings.mqttSendTopic)) {
    if (onRfDataCallback) {
      onRfDataCallback(String(topic + settings.mqttSendTopic.length()),
                       strPayload);
    }
  }
}

void MqttClient::registerRfDataHandler(const MqttClient::RfDataCb &cb) {
  onRfDataCallback = cb;
}

void MqttClient::publishCode(const String &protocol, const String &payload) {
  String topic = settings.mqttReceiveTopic + protocol;

  Logger.debug.print(F("Publish MQTT message: "));
  Logger.debug.print(topic);
  Logger.debug.print(F(" retain="));
  Logger.debug.print(settings.mqttRetain);
  Logger.debug.print(F(" .. "));
  Logger.debug.println(payload);
  mqttClient.publish(topic.c_str(), payload.c_str(), settings.mqttRetain);
}

bool MqttClient::isConnected() { return mqttClient.connected(); }
<commit_msg>lib/MQTT/MqttClient.cpp: use Mqtt state topic from Settings<commit_after>/**
  MQTT433gateway - MQTT 433.92 MHz radio gateway utilizing ESPiLight
  Project home: https://github.com/puuu/MQTT433gateway/

  The MIT License (MIT)

  Copyright (c) 2017 Jan Losinski

  Permission is hereby granted, free of charge, to any person
  obtaining a copy of this software and associated documentation files
  (the "Software"), to deal in the Software without restriction,
  including without limitation the rights to use, copy, modify, merge,
  publish, distribute, sublicense, and/or sell copies of the Software,
  and to permit persons to whom the Software is furnished to do so,
  subject to the following conditions:

  The above copyright notice and this permission notice shall be
  included in all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  SOFTWARE.
*/

#include <ArduinoSimpleLogging.h>

#include <Version.h>

#include "MqttClient.h"

class PayloadString : public String {
 public:
  PayloadString(const uint8_t *data, unsigned int length) : String() {
    if (reserve(length)) {
      memcpy(buffer, data, length);
      len = length;
    }
  }
};

MqttClient::MqttClient(const Settings &settings, WiFiClient &client)
    : settings(settings), mqttClient(client), lastConnectAttempt(0) {}

MqttClient::~MqttClient() { mqttClient.disconnect(); }

void MqttClient::begin() {
  using namespace std::placeholders;
  mqttClient.setServer(settings.mqttBroker.c_str(), settings.mqttBrokerPort);

  mqttClient.setCallback(std::bind(&MqttClient::onMessage, this, _1, _2, _3));

  reconnect();
}

static String stateMessage(const bool online) {
  return String(F("{\"chipId\":\"")) + chipId() +
         String(F("\",\"firmware\":\"")) + fwVersion() + F("\",\"state\":\"") +
         String(online ? F("online") : F("offline")) + String(F("\"}"));
}

bool MqttClient::connect() {
  if (0 == settings.mqttUser.length()) {
    return mqttClient.connect(settings.deviceName.c_str(),
                              settings.mqttStateTopic.c_str(), 0, true,
                              stateMessage(false).c_str());
  } else {
    return mqttClient.connect(
        settings.deviceName.c_str(), settings.mqttUser.c_str(),
        settings.mqttPassword.c_str(), settings.mqttStateTopic.c_str(), 0, true,
        stateMessage(false).c_str());
  }
}

void MqttClient::reconnect() {
  if (lastConnectAttempt > 0 &&
      (millis() - lastConnectAttempt) < MQTT_CONNECTION_ATTEMPT_DELAY) {
    return;
  }

  if (!mqttClient.connected()) {
    Logger.debug.println(F("Try to (re)connect to MQTT broker"));
    if (connect()) {
      Logger.info.println(F("MQTT connected."));
      if (subsrcibe()) {
        mqttClient.publish(settings.mqttStateTopic.c_str(),
                           stateMessage(true).c_str(), true);
        Logger.info.println(F("MQTT subscribed."));
      } else {
        Logger.error.println(F("MQTT subsrcibe failed!"));
      }
    } else {
      Logger.error.println(F("MQTT connect failed!"));
    }
  }

  lastConnectAttempt = millis();
}

bool MqttClient::subsrcibe() {
  String topic = settings.mqttSendTopic + "+";

  Logger.debug.print(F("MQTT subscribe to topic: "));
  Logger.debug.println(topic);

  return mqttClient.subscribe(topic.c_str());
}

void MqttClient::loop() {
  reconnect();
  mqttClient.loop();
}

void MqttClient::onMessage(char *topic, uint8_t *payload, unsigned int length) {
  PayloadString strPayload(payload, length);
  String strTopic(topic);

  Logger.debug.print(F("New MQTT message: "));
  Logger.debug.print(strTopic);
  Logger.debug.print(F(" .. "));
  Logger.debug.println(strPayload);

  if (strTopic.startsWith(settings.mqttSendTopic)) {
    if (onRfDataCallback) {
      onRfDataCallback(String(topic + settings.mqttSendTopic.length()),
                       strPayload);
    }
  }
}

void MqttClient::registerRfDataHandler(const MqttClient::RfDataCb &cb) {
  onRfDataCallback = cb;
}

void MqttClient::publishCode(const String &protocol, const String &payload) {
  String topic = settings.mqttReceiveTopic + protocol;

  Logger.debug.print(F("Publish MQTT message: "));
  Logger.debug.print(topic);
  Logger.debug.print(F(" retain="));
  Logger.debug.print(settings.mqttRetain);
  Logger.debug.print(F(" .. "));
  Logger.debug.println(payload);
  mqttClient.publish(topic.c_str(), payload.c_str(), settings.mqttRetain);
}

bool MqttClient::isConnected() { return mqttClient.connected(); }
<|endoftext|>


<commit_before>#include "qbottombar.h"
#include "common/qstealth.h"
#include "util.h"
#include "guiutil.h"

#define SC_QSS_BOTTOM_BAR               "background-color: #eaeaea; " + SC_QSS_TOOLTIP_DEFAULT

#define SC_QSS_BOTTOM_BAR_VERSION       "color: white; font-family:" + QString(SC_BOLD_FONT_NAME) + ";"

#define SC_QSS_BTN_UNENCRYPTED          "QPushButton {background-image: url(':/resources/res/images/icons/ico_not_encrypted.png'); background-position: center; background-repeat: no-repeat; border: none; outline: none;}"
#define SC_QSS_BTN_LOCKED               "QPushButton {background-image: url(':/resources/res/images/icons/ico_lock.png'); background-position: center; background-repeat: no-repeat; border: none; outline: none;}"
#define SC_QSS_BTN_MINT_ONLY            "QPushButton {background-image: url(':/resources/res/images/icons/ico_unlock.png'); background-position: center; background-repeat: no-repeat; border: none; outline: none;}"
#define SC_QSS_BTN_UNLOCKED             "QPushButton {background-image: url(':/resources/res/images/icons/ico_unlock_red.png'); background-position: center; background-repeat: no-repeat; border: none; outline: none;}"

QStealthStatusBar::QStealthStatusBar(QWidget *parent) :
    QLabel(parent)
{
    setStyleSheet(SC_QSS_BOTTOM_BAR);

    for (int i = 0; i < SC_TRAY_ITEM_COUNT; i++) {
        lblIcons[i] = new QLabel(this);
        lblIcons[i]->setGeometry(5 + 35 * (i + 1), 10, 30, 30);
        setActive(i, true);
    }
    setActive(SC_STATUS_ID_CHECK, false);

    btnLock = new QPushButton(this);
    btnLock->setGeometry(0, 10, 30, 30);
    setLockState(SC_LS_UNLOCKED);
}

void QStealthStatusBar::setLockState(SC_LOCK_STATE nLockState)
{
    this->nLockState = nLockState;
    switch (nLockState) {
      case SC_LS_UNENCRYPTED: {
        btnLock->setStyleSheet(SC_QSS_BTN_UNENCRYPTED);
        break;
      }
      case SC_LS_UNLOCKED: {
        btnLock->setStyleSheet(SC_QSS_BTN_UNLOCKED);
        break;
      }
      case SC_LS_MINT_ONLY: {
        btnLock->setStyleSheet(SC_QSS_BTN_MINT_ONLY);
        break;
      }
      case SC_LS_LOCKED: {
        btnLock->setStyleSheet(SC_QSS_BTN_LOCKED);
        break;
      }
    }
}

SC_LOCK_STATE QStealthStatusBar::lockState()
{
    return nLockState;
}

void QStealthStatusBar::setActive(int index, bool active)
{
    // set icon
    QString iconPath[SC_TRAY_ITEM_COUNT] = {
        "ico_stealth",
        "ico_increase",
        "ico_check",
    };

    if (index < 0 || index > SC_TRAY_ITEM_COUNT - 1) return;
    state[index] = active;

    QString path = (active == false) ? SC_ICON_PATH_DEFAULT : SC_ICON_PATH_ACTIVE;
    path += iconPath[index];
    path += ".png";

    lblIcons[index]->setPixmap(QPixmap(path));
    lblIcons[index]->setObjectName("statusIcon");
    lblIcons[index]->setStyleSheet(SC_QSS_TOOLTIP_DEFAULT);
}

QBottomBar::QBottomBar(QWidget *parent) :
    QLabel(parent)
{
    setGeometry(0, 650, 1100, 50);
    setStyleSheet(SC_QSS_BOTTOM_BAR);

    QString qstrVersion = tr("") +
                          "" + tr("TheGCCcoin client") + " " + "
"+
                          " V " + QString::fromStdString(FormatVersionNumbers()) +
                          "";

    lblVersion = new QLabel(this);
    lblVersion->setGeometry(0, 0, 250, 50);
    QFont fntVersion = GUIUtil::stealthBoldFont();
    fntVersion.setPixelSize(12);
    lblVersion->setFont(fntVersion);
    lblVersion->setText(qstrVersion);
    lblVersion->setAlignment(Qt::AlignCenter);
    lblVersion->setStyleSheet(SC_QSS_BOTTOM_BAR_VERSION);

    progressBar = new QStealthProgressBar(this);
    progressBar->setGeometry(250 + 25, 0, 310, 50);
    progressBarLabel = new QLabel(this);
    progressBarLabel->setGeometry(585, 0, 360, 50);
    progressBarLabel->setStyleSheet(QString(SC_QSS_PROGRESS_NORMAL));

    progressBarLabel->setVisible(false);

    statusBar = new QStealthStatusBar(this);
    statusBar->setGeometry(width() - 155, 0, 150, 50);

    progressBar->setPercent(0);
}
<commit_msg>v2.3.0.0<commit_after>#include "qbottombar.h"
#include "common/qstealth.h"
#include "util.h"
#include "guiutil.h"

#define SC_QSS_BOTTOM_BAR               "background-color: #eaeaea; " + SC_QSS_TOOLTIP_DEFAULT

#define SC_QSS_BOTTOM_BAR_VERSION       "color: white; font-family:" + QString(SC_BOLD_FONT_NAME) + ";"

#define SC_QSS_BTN_UNENCRYPTED          "QPushButton {background-image: url(':/resources/res/images/icons/ico_not_encrypted.png'); background-position: center; background-repeat: no-repeat; border: none; outline: none;}"
#define SC_QSS_BTN_LOCKED               "QPushButton {background-image: url(':/resources/res/images/icons/ico_lock.png'); background-position: center; background-repeat: no-repeat; border: none; outline: none;}"
#define SC_QSS_BTN_MINT_ONLY            "QPushButton {background-image: url(':/resources/res/images/icons/ico_unlock.png'); background-position: center; background-repeat: no-repeat; border: none; outline: none;}"
#define SC_QSS_BTN_UNLOCKED             "QPushButton {background-image: url(':/resources/res/images/icons/ico_unlock_red.png'); background-position: center; background-repeat: no-repeat; border: none; outline: none;}"

QStealthStatusBar::QStealthStatusBar(QWidget *parent) :
    QLabel(parent)
{
    setStyleSheet(SC_QSS_BOTTOM_BAR);

    for (int i = 0; i < SC_TRAY_ITEM_COUNT; i++) {
        lblIcons[i] = new QLabel(this);
        lblIcons[i]->setGeometry(5 + 35 * (i + 1), 10, 30, 30);
        setActive(i, true);
    }
    setActive(SC_STATUS_ID_CHECK, false);

    btnLock = new QPushButton(this);
    btnLock->setGeometry(0, 10, 30, 30);
    setLockState(SC_LS_UNLOCKED);
}

void QStealthStatusBar::setLockState(SC_LOCK_STATE nLockState)
{
    this->nLockState = nLockState;
    switch (nLockState) {
      case SC_LS_UNENCRYPTED: {
        btnLock->setStyleSheet(SC_QSS_BTN_UNENCRYPTED);
        break;
      }
      case SC_LS_UNLOCKED: {
        btnLock->setStyleSheet(SC_QSS_BTN_UNLOCKED);
        break;
      }
      case SC_LS_MINT_ONLY: {
        btnLock->setStyleSheet(SC_QSS_BTN_MINT_ONLY);
        break;
      }
      case SC_LS_LOCKED: {
        btnLock->setStyleSheet(SC_QSS_BTN_LOCKED);
        break;
      }
    }
}

SC_LOCK_STATE QStealthStatusBar::lockState()
{
    return nLockState;
}

void QStealthStatusBar::setActive(int index, bool active)
{
    // set icon
    QString iconPath[SC_TRAY_ITEM_COUNT] = {
        "ico_stealth",
        "ico_increase",
        "ico_check",
    };

    if (index < 0 || index > SC_TRAY_ITEM_COUNT - 1) return;
    state[index] = active;

    QString path = (active == false) ? SC_ICON_PATH_DEFAULT : SC_ICON_PATH_ACTIVE;
    path += iconPath[index];
    path += ".png";

    lblIcons[index]->setPixmap(QPixmap(path));
    lblIcons[index]->setObjectName("statusIcon");
    lblIcons[index]->setStyleSheet(SC_QSS_TOOLTIP_DEFAULT);
}

QBottomBar::QBottomBar(QWidget *parent) :
    QLabel(parent)
{
    setGeometry(0, 650, 1100, 50);
    setStyleSheet(SC_QSS_BOTTOM_BAR);

    QString qstrVersion = tr("") +
                          "" + tr("TheGCCcoin client") + " " + "
"+
                          " V " + QString::fromStdString(FormatVersionNumbers()) +
                          ";\"> V 2.3.0.0" +
                          "";

    lblVersion = new QLabel(this);
    lblVersion->setGeometry(0, 0, 250, 50);
    QFont fntVersion = GUIUtil::stealthBoldFont();
    fntVersion.setPixelSize(12);
    lblVersion->setFont(fntVersion);
    lblVersion->setText(qstrVersion);
    lblVersion->setAlignment(Qt::AlignCenter);
    lblVersion->setStyleSheet(SC_QSS_BOTTOM_BAR_VERSION);

    progressBar = new QStealthProgressBar(this);
    progressBar->setGeometry(250 + 25, 0, 310, 50);
    progressBarLabel = new QLabel(this);
    progressBarLabel->setGeometry(585, 0, 360, 50);
    progressBarLabel->setStyleSheet(QString(SC_QSS_PROGRESS_NORMAL));

    progressBarLabel->setVisible(false);

    statusBar = new QStealthStatusBar(this);
    statusBar->setGeometry(width() - 155, 0, 150, 50);

    progressBar->setPercent(0);
}
<|endoftext|>


<commit_before>// The MIT License (MIT)
//
// Copyright (c) 2015 Relja Ljubobratovic, ljubobratovic.relja@gmail.com
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
// Description:
// Implementation of contour structure, and various derivatives as a polygon
// structure.
//
// Author:
// Relja Ljubobratovic, ljubobratovic.relja@gmail.com

#ifndef CONTOUR_HPP_XOOB1YC7
#define CONTOUR_HPP_XOOB1YC7

#include "fwd.hpp"
#include "vector.hpp"
#include "region.hpp"

#include <vector>

namespace cv {

namespace internal {
// Index comparator used for comparing arrays by only one axis values.
struct idx_cmp {
	unsigned index = 0;

	idx_cmp(unsigned index) : index(index) {}

	template<typename _ArrayType>
	bool operator ()(const _ArrayType &rhs, const _ArrayType &lhs) const {
		return (rhs[index] < lhs[index]);
	}
};
}

/*!
 * @brief 2D contour template class.
 */
template<typename _Tp>
class contour {
  public:
	typedef _Tp value_type;
	typedef _Tp &reference;
	typedef const _Tp &const_reference;
	typedef vectorx<_Tp, 2> point_type;
	typedef vectorx<_Tp, 2> &point_reference;
	typedef const vectorx<_Tp, 2> &point_const_reference;

	typedef typename std::vector<vectorx<_Tp, 2> >::iterator iterator;
	typedef typename std::vector<vectorx<_Tp, 2> >::const_iterator const_iterator;

	enum PounsignedInPolygonStat {
		POINT_OUT_OF_POLYGON = 0, POINT_IN_POLYGON = 1, POINT_ON_EDGE = 2
	};

  private:
	std::vector<point_type> _pts; // point array which defines the contour in index ordered manor.

  public:
	//! Default constructor.
	contour() {
	}
	//! Constructor using initial number of points in contour.
	contour(unsigned point_length) :
		_pts(point_length) {
	}
	//! Constructor using range of points.
	template<typename point_iterator>
	contour(point_iterator begin, point_iterator end) :
		_pts() {
		auto dist = std::distance(begin, end);
		ASSERT(dist);
		this->_pts.create(begin, end);
	}
	//! Constructor using initializer list of points.
	contour(std::initializer_list<point_type> list) :
		_pts(list) {
	}
	//! Copy constructor.
	contour(const contour &cpy) :
		_pts(cpy._pts) {
	}
	//! Move constructor.
	contour(contour &&move) :
		_pts(std::move(move._pts)) {
	}
	//! Assignment operator - performs copy.
	contour &operator =(const contour &rhs) {
		if (this != &rhs) {
			this->_pts = rhs._pts;
		}
		return *this;
	}
	//! Move operator.
	contour &operator =(contour && rhs) {
		if (this != &rhs) {
			this->_pts = std::move(rhs._pts);
		}
		return *this;
	}
	//! Get point iterator at begin.
	iterator begin() {
		return this->_pts.begin();
	}
	//! Get point iterator at end.
	iterator end() {
		return this->_pts.end();
	}
	//! Get read-only point iterator at begin.
	const_iterator begin() const {
		return this->_pts.begin();
	}
	//! Get read-only point iterator at end.
	const_iterator end() const {
		return this->_pts.end();
	}
	//! Add point to the contour.
	void add_point(point_const_reference ptn) {
		this->_pts.push_back(ptn);
	}
	//! Add multiple points to the contour.
	void add_points(const std::vector<point_type> &ptns) {
		this->_pts.insert(ptns.begin(), ptns.end());
	}
	//! Remove point from the contour.
	void remove_point(unsigned index) {
		this->_pts.remove(this->_pts.begin() + index);
	}

	void remove_all_points() {
		this->_pts.clear();
	}

	point_reference get_point(unsigned index) {
		return this->_pts[index];
	}

	point_const_reference get_point(unsigned index) const {
		return this->_pts[index];
	}

	vec2d get_edge_vector(unsigned startId, unsigned endId) const {
		return vec2d(this->_pts[endId] - this->_pts[startId]);
	}

	vec2d get_contour_vector() const {
		return this->get_edge_vector(0, -1);
	}

	unsigned point_length() const {
		return this->_pts.length();
	}

	void sort_by_axis(unsigned axis) {
		ASSERT(axis == 0 || axis == 1);
		std::sort(this->begin(), this->end(), internal::idx_cmp(axis));
	}

	regiond get_bounding_box() const {
		point_type min, max, *data;

		data = this->_pts.data();
		bool init = false;

		for (int i = 0; i < this->point_length(); ++i) {
			if (!init) {
				min = data[i];
				max = data[i];
				init = true;
				continue;
			}

			if (data[i][0] < min[0]) {
				min[0] = data[i][0];
			}
			if (data[i][1] < min[1]) {
				min[1] = data[i][1];
			}
			if (data[i][0] > max[0]) {
				max[0] = data[i][0];
			}
			if (data[i][1] > max[1]) {
				max[1] = data[i][1];
			}
		}
		return regiond(min[0], min[1], max[0] - min[0], max[1] - min[1]);
	}

	point_reference operator[](unsigned index) {
		return this->_pts[index];
	}

	point_const_reference operator[](unsigned index) const {
		return this->_pts[index];
	}

	contour &operator <<(point_const_reference ptn) {
		this->_pts.push_back(ptn);
		return this;
	}

	contour &operator <<(const std::vector<point_const_reference> &ptn) {
		this->add_points(ptn);
		return this;
	}

	bool operator ==(const contour &rhs) const {
		if (this->point_length() != rhs.point_length()) {
			return false;
		}
		LOOP_FOR_TO(this->point_length()) {
			if (this->_pts[i] != rhs[i]) {
				return false;
			}
		}
		return true;
	}

	bool operator !=(const contour &rhs) const {
		return !operator ==(rhs);
	}

	bool operator <(const contour &rhs) const {
		return std::lexicographical_compare(this->begin(), this->end(), rhs.begin(), rhs.end());
	}

	operator bool() const {
		return static_cast<bool>(this->_pts.length());
	}
};

/*!
 * @brief 2D polygon template class.
 */
template<typename _Tp>
class polygon: public contour<_Tp> {
  private:
	typedef contour<_Tp> super;
  public:
	typedef typename contour<_Tp>::value_type value_type;
	typedef typename contour<_Tp>::reference reference;
	typedef typename contour<_Tp>::const_reference const_reference;
	typedef vectorx<_Tp, 2> point_type;
	typedef vectorx<_Tp, 2> &point_reference;
	typedef const vectorx<_Tp, 2> &point_const_reference;

	typedef typename std::vector<vectorx<_Tp, 2> >::iterator iterator;
	typedef typename std::vector<vectorx<_Tp, 2> >::const_iterator const_iterator;

  public:
	polygon() :
		super() {
	}

	polygon(unsigned point_length) :
		super(point_length) {
	}

	polygon(std::initializer_list<point_type> list) :
		super(list) {
	}

	polygon(const polygon &) = default;
	polygon(polygon &&) = default;
	polygon &operator=(const polygon &) = default;
	polygon &operator=(polygon &&) = default;

	unsigned pointInPolygon(point_const_reference ptn) const {
		return pointInPolygon(ptn[0], ptn[1]);
	}

	unsigned pointInPolygon(const_reference x, const_reference y) const {
		unsigned i, j, c = 0;
		point_type *pt_data = this->_pts.data();
		for (i = 0, j = this->point_length() - 1; i < this->point_length(); j = i++) {
			if (((pt_data[i][1] > y) != (pt_data[j][1] > y))
			        && (x
			            < (pt_data[j][0] - pt_data[i][0]) * (y - pt_data[i][1]) / (pt_data[j][1] - pt_data[i][1])
			            + pt_data[i][0])) {
				c = !c;
			}
		}
		return c;
	}

	point_reference operator[](unsigned index) {
		return this->_pts[index];
	}

	point_const_reference operator[](unsigned index) const {
		return this->_pts[index];
	}

	polygon &operator <<(point_const_reference ptn) {
		this->add_point(ptn);
		return this;
	}

	polygon &operator <<(const std::vector<point_const_reference> &ptn) {
		this->add_points(ptn);
		return this;
	}

	bool operator ==(const polygon &rhs) const {
		if (this->point_length() != rhs.point_length()) {
			return false;
		}
		LOOP_FOR_TO(this->point_length()) {
			if (this->_pts[i] != rhs[i]) {
				return false;
			}
		}
		return true;
	}

	bool operator !=(const polygon &rhs) const {
		return !operator ==(rhs);
	}

	bool operator <(const polygon &rhs) const {
		return std::lexicographical_compare(this->begin(), this->end(), rhs.begin(), rhs.end());
	}

	operator std::vector<vectorx<_Tp, 2> >() {
		return this->_pts;
	}

};

typedef contour<float> contourf;
typedef contour<double> contourd;
typedef contour<int> contouri;
typedef contour<short> contours;
typedef polygon<float> polygonf;
typedef polygon<double> polygond;
typedef polygon<int> polygoni;
typedef polygon<short> polygons;

}

#endif /* end of include guard: CONTOUR_HPP_XOOB1YC7 */

<commit_msg>style modif<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2015 Relja Ljubobratovic, ljubobratovic.relja@gmail.com
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
// Description:
// Implementation of contour structure, and various derivatives as a polygon
// structure.
//
// Author:
// Relja Ljubobratovic, ljubobratovic.relja@gmail.com

#ifndef CONTOUR_HPP_XOOB1YC7
#define CONTOUR_HPP_XOOB1YC7

#include "fwd.hpp"
#include "vector.hpp"
#include "region.hpp"

#include <vector>

namespace cv {

namespace internal {
// Index comparator used for comparing arrays by only one axis values.
struct idx_cmp {
	unsigned index = 0;

	idx_cmp(unsigned index) : index(index) {}

	template<typename _ArrayType>
	bool operator ()(const _ArrayType &rhs, const _ArrayType &lhs) const {
		return (rhs[index] < lhs[index]);
	}
};
}

/*!
 * @brief 2D contour template class.
 */
template<typename _Tp>
class contour {
  public:
	typedef _Tp value_type;
	typedef _Tp &reference;
	typedef const _Tp &const_reference;
	typedef vectorx<_Tp, 2> point_type;
	typedef vectorx<_Tp, 2> &point_reference;
	typedef const vectorx<_Tp, 2> &point_const_reference;

	typedef typename std::vector<vectorx<_Tp, 2> >::iterator iterator;
	typedef typename std::vector<vectorx<_Tp, 2> >::const_iterator const_iterator;

	enum PounsignedInPolygonStat {
		POINT_OUT_OF_POLYGON = 0, POINT_IN_POLYGON = 1, POINT_ON_EDGE = 2
	};

  private:
	std::vector<point_type> _pts; // point array which defines the contour in index ordered manor.

  public:
	//! Default constructor.
	contour() {
	}
	//! Constructor using initial number of points in contour.
	contour(unsigned point_length) :
		_pts(point_length) {
	}
	//! Constructor using range of points.
	template<typename point_iterator>
	contour(point_iterator begin, point_iterator end) :
		_pts() {
		auto dist = std::distance(begin, end);
		ASSERT(dist);
		this->_pts.create(begin, end);
	}
	//! Constructor using initializer list of points.
	contour(std::initializer_list<point_type> list) :
		_pts(list) {
	}
	//! Copy constructor.
	contour(const contour &cpy) :
		_pts(cpy._pts) {
	}
	//! Move constructor.
	contour(contour &&move) :
		_pts(std::move(move._pts)) {
	}
	//! Assignment operator - performs copy.
	contour &operator =(const contour &rhs) {
		if (this != &rhs) {
			this->_pts = rhs._pts;
		}
		return *this;
	}
	//! Move operator.
	contour &operator =(contour && rhs) {
		if (this != &rhs) {
			this->_pts = std::move(rhs._pts);
		}
		return *this;
	}
	//! Get point iterator at begin.
	iterator begin() {
		return this->_pts.begin();
	}
	//! Get point iterator at end.
	iterator end() {
		return this->_pts.end();
	}
	//! Get read-only point iterator at begin.
	const_iterator begin() const {
		return this->_pts.begin();
	}
	//! Get read-only point iterator at end.
	const_iterator end() const {
		return this->_pts.end();
	}
	//! Add point to the contour.
	void add_point(point_const_reference ptn) {
		this->_pts.push_back(ptn);
	}
	//! Add multiple points to the contour.
	void add_points(const std::vector<point_type> &ptns) {
		this->_pts.insert(ptns.begin(), ptns.end());
	}
	//! Remove point from the contour.
	void remove_point(unsigned index) {
		this->_pts.remove(this->_pts.begin() + index);
	}

	void remove_all_points() {
		this->_pts.clear();
	}

	point_reference get_point(unsigned index) {
		return this->_pts[index];
	}

	point_const_reference get_point(unsigned index) const {
		return this->_pts[index];
	}

	vec2d get_edge_vector(unsigned startId, unsigned endId) const {
		return vec2d(this->_pts[endId] - this->_pts[startId]);
	}

	vec2d get_contour_vector() const {
		return this->get_edge_vector(0, -1);
	}

	unsigned point_length() const {
		return this->_pts.length();
	}

	void sort_by_axis(unsigned axis) {
		ASSERT(axis == 0 || axis == 1);
		std::sort(this->begin(), this->end(), internal::idx_cmp(axis));
	}

	regiond get_bounding_box() const {
		point_type min, max, *data;

		data = this->_pts.data();
		bool init = false;

		for (int i = 0; i < this->point_length(); ++i) {
			if (!init) {
				min = data[i];
				max = data[i];
				init = true;
				continue;
			}

			if (data[i][0] < min[0]) {
				min[0] = data[i][0];
			}
			if (data[i][1] < min[1]) {
				min[1] = data[i][1];
			}
			if (data[i][0] > max[0]) {
				max[0] = data[i][0];
			}
			if (data[i][1] > max[1]) {
				max[1] = data[i][1];
			}
		}
		return regiond(min[0], min[1], max[0] - min[0], max[1] - min[1]);
	}

	point_reference operator[](unsigned index) {
		return this->_pts[index];
	}

	point_const_reference operator[](unsigned index) const {
		return this->_pts[index];
	}

	contour &operator <<(point_const_reference ptn) {
		this->_pts.push_back(ptn);
		return this;
	}

	contour &operator <<(const std::vector<point_const_reference> &ptn) {
		this->add_points(ptn);
		return this;
	}

	bool operator ==(const contour &rhs) const {
		if (this->point_length() != rhs.point_length()) {
			return false;
		}
		LOOP_FOR_TO(this->point_length()) {
			if (this->_pts[i] != rhs[i]) {
				return false;
			}
		}
		return true;
	}

	bool operator !=(const contour &rhs) const {
		return !operator ==(rhs);
	}

	bool operator <(const contour &rhs) const {
		return std::lexicographical_compare(this->begin(), this->end(), rhs.begin(), rhs.end());
	}

	operator bool() const {
		return static_cast<bool>(this->_pts.length());
	}
};

/*!
 * @brief 2D polygon template class.
 */
template<typename _Tp>
class polygon: public contour<_Tp> {
  private:
	typedef contour<_Tp> super;
  public:
	typedef typename contour<_Tp>::value_type value_type;
	typedef typename contour<_Tp>::reference reference;
	typedef typename contour<_Tp>::const_reference const_reference;
	typedef vectorx<_Tp, 2> point_type;
	typedef vectorx<_Tp, 2> &point_reference;
	typedef const vectorx<_Tp, 2> &point_const_reference;

	typedef typename std::vector<vectorx<_Tp, 2> >::iterator iterator;
	typedef typename std::vector<vectorx<_Tp, 2> >::const_iterator const_iterator;

  public:
	polygon() :
		super() {
	}

	polygon(unsigned point_length) :
		super(point_length) {
	}

	polygon(std::initializer_list<point_type> list) :
		super(list) {
	}

	polygon(const polygon &) = default;
	polygon(polygon &&) = default;
	polygon &operator=(const polygon &) = default;
	polygon &operator=(polygon &&) = default;

	unsigned point_in_polygon(point_const_reference ptn) const {
		return point_in_polygon(ptn[0], ptn[1]);
	}

	unsigned point_in_polygon(const_reference x, const_reference y) const {
		unsigned i, j, c = 0;
		point_type *pt_data = this->_pts.data();
		for (i = 0, j = this->point_length() - 1; i < this->point_length(); j = i++) {
			if (((pt_data[i][1] > y) != (pt_data[j][1] > y))
			        && (x
			            < (pt_data[j][0] - pt_data[i][0]) * (y - pt_data[i][1]) / (pt_data[j][1] - pt_data[i][1])
			            + pt_data[i][0])) {
				c = !c;
			}
		}
		return c;
	}

	point_reference operator[](unsigned index) {
		return this->_pts[index];
	}

	point_const_reference operator[](unsigned index) const {
		return this->_pts[index];
	}

	polygon &operator <<(point_const_reference ptn) {
		this->add_point(ptn);
		return this;
	}

	polygon &operator <<(const std::vector<point_const_reference> &ptn) {
		this->add_points(ptn);
		return this;
	}

	bool operator ==(const polygon &rhs) const {
		if (this->point_length() != rhs.point_length()) {
			return false;
		}
		LOOP_FOR_TO(this->point_length()) {
			if (this->_pts[i] != rhs[i]) {
				return false;
			}
		}
		return true;
	}

	bool operator !=(const polygon &rhs) const {
		return !operator ==(rhs);
	}

	bool operator <(const polygon &rhs) const {
		return std::lexicographical_compare(this->begin(), this->end(), rhs.begin(), rhs.end());
	}

	operator std::vector<vectorx<_Tp, 2> >() {
		return this->_pts;
	}

};

typedef contour<float> contourf;
typedef contour<double> contourd;
typedef contour<int> contouri;
typedef contour<short> contours;
typedef polygon<float> polygonf;
typedef polygon<double> polygond;
typedef polygon<int> polygoni;
typedef polygon<short> polygons;

}

#endif /* end of include guard: CONTOUR_HPP_XOOB1YC7 */

<|endoftext|>


<commit_before>/*
 * Copyright 2006-2008 The FLWOR Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <iostream>

#include "util/unordered_map.h"

using namespace std;

static void instantiate() {
  return;

  typedef unordered_map<string,int> map_type;

  map_type m;
  map_type m2( m );
  m = m2;
  map_type const cm;

  map_type::iterator i;
  map_type::const_iterator ci;

  m.begin();
  m.cbegin();
  m.end();
  m.cend();

  m.begin( 0 );
  m.cbegin( 0 );
  m.end( 0 );
  m.cend( 0 );

  m.clear();
  m.erase( i );
  m.erase( ci );
  m.erase( ci, ci );
  m.erase( "x" );

  m.insert( make_pair( "a", 1 ) );
  m.insert( ci, make_pair( "a", 1 ) );

  m.rehash( 41 );
  m.swap( m2 );

  m.at( "x" );
  cm.at( "x" );

  m[ "b" ] = 2;

  m.count( "x" );
  m.find( "x" );
  cm.find( "x" );
  m.equal_range( "x" );
  cm.equal_range( "x" );

  m.bucket( "x" );
  m.bucket_count();
  m.bucket_size( 0 );
  m.max_bucket_count();

  m.empty();
  m.get_allocator();
  m.hash_function();
  m.key_eq();
  m.load_factor();
  m.max_load_factor();
  m.max_size();
  m.size();
}
/* vim:set et sw=2 ts=2: */
<commit_msg>Added iterator instantiations.<commit_after>/*
 * Copyright 2006-2008 The FLWOR Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <string>

#include "util/unordered_map.h"

using namespace std;

static void instantiate() {
  return;

  typedef unordered_map<string,int> map_type;

  map_type::iterator i, j;
  map_type::const_iterator ci, cj;

  (void)*i;
  (void)i->first;
  (void)i->second;
  (void)++i;
  (void)i++;
  (void)(i == j);
  (void)(i != j);

  (void)*ci;
  (void)ci->first;
  (void)ci->second;
  (void)++ci;
  (void)ci++;
  (void)(ci == cj);
  (void)(ci != cj);

  map_type::local_iterator li, lj;
  map_type::const_local_iterator cli, clj;

  (void)*li;
  (void)li->first;
  (void)li->second;
  (void)++li;
  (void)li++;
  (void)(li == lj);
  (void)(li != lj);

  (void)*cli;
  (void)cli->first;
  (void)cli->second;
  (void)++cli;
  (void)cli++;
  (void)(cli == clj);
  (void)(cli != clj);

  map_type m;
  map_type m2( m );
  m = m2;
  map_type const cm;

  i = m.begin();
  ci = m.cbegin();
  j = m.end();
  cj = m.cend();

  li = m.begin( 0 );
  cli = m.cbegin( 0 );
  lj = m.end( 0 );
  clj = m.cend( 0 );

  m.clear();
  m.erase( i );
  m.erase( ci );
  m.erase( ci, ci );
  m.erase( "x" );

  m.insert( make_pair( "a", 1 ) );
  m.insert( ci, make_pair( "a", 1 ) );

  m.rehash( 41 );
  m.swap( m2 );

  m.at( "x" );
  cm.at( "x" );

  m[ "b" ] = 2;

  m.count( "x" );
  m.find( "x" );
  cm.find( "x" );
  m.equal_range( "x" );
  cm.equal_range( "x" );

  m.bucket( "x" );
  m.bucket_count();
  m.bucket_size( 0 );
  m.max_bucket_count();

  m.empty();
  m.get_allocator();
  m.hash_function();
  m.key_eq();
  m.load_factor();
  m.max_load_factor();
  m.max_size();
  m.size();
}
/* vim:set et sw=2 ts=2: */
<|endoftext|>


<commit_before>/*
 * Ubitrack - Library for Ubiquitous Tracking
 * Copyright 2006, Technische Universitaet Muenchen, and individual
 * contributors as indicated by the @authors tag. See the
 * copyright.txt in the distribution for a full listing of individual
 * contributors.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */

/**
 * @ingroup vision_components
 * @file
 * Computes the intrinsic matrix and the distortion coefficients
 *
 * @author Christian Waechter <christian.waechter@cs.tum.edu>
 */

//std
#include <vector>
#include <numeric>
#include <algorithm>

// OpenCV (for the calibration function)
#include <opencv/cv.h>

// for data preperation.
#include <boost/scoped_array.hpp>

#include <utMath/Vector.h>
#include <utMath/Matrix.h>
#include <utMath/CameraIntrinsics.h>
#include <utDataflow/TriggerComponent.h>
#include <utDataflow/ExpansionInPort.h>
#include <utDataflow/TriggerOutPort.h>
#include <utDataflow/ComponentFactory.h>
#include <utMeasurement/Measurement.h>

namespace Ubitrack { namespace Vision {

class CameraCalibration
	: public Dataflow::TriggerComponent
{
protected:

	///shortcut for the type of 2d measurements
	typedef std::vector < Math::Vector< 2 > > vector_2d_type;

	///shortcut for the type of 3d measurements
	typedef std::vector < Math::Vector< 3 > > vector_3d_type;

	/** the intrinsic parameters, estimated so far */
	Math::CameraIntrinsics< double > m_camIntrinsics;

	/** signs constraints for the calibration,
	please have a look at the OpenCV Doku for explanations */
	int m_flags;

	/** Input port of the component for 2D measurements. */
	Dataflow::ExpansionInPort< vector_2d_type > m_inPort2D;

	/** Input port of the component for 3D measurements. */
	Dataflow::ExpansionInPort< vector_3d_type > m_inPort3D;

	/** Output port of the component providing the camera intrinsic parameters. */
	Dataflow::TriggerOutPort< Measurement::CameraIntrinsics > m_intrPort;

public:
	/**
	 * Standard component constructor.
	 *
	 * @param sName Unique name of the component.
	 * @param cfg ComponentConfiguration containing all configuration.
	 */
	CameraCalibration( const std::string& sName, boost::shared_ptr< Graph::UTQLSubgraph > pCfg )
		: Dataflow::TriggerComponent( sName, pCfg )
		, m_flags( 0 )
		, m_inPort2D( "Points2D", *this )
		, m_inPort3D( "Points3D", *this )
		, m_intrPort( "CameraIntrinsics", *this )
    {

		// look for some flags which can be specified...
		if ( pCfg->m_DataflowAttributes.hasAttribute( "fixPrincipalPoint" ) ) // fixes principal point to centre of image plane
			if( pCfg->m_DataflowAttributes.getAttributeString( "fixPrincipalPoint" ) == "true" )
				m_flags |= CV_CALIB_FIX_PRINCIPAL_POINT;

		if ( pCfg->m_DataflowAttributes.hasAttribute( "noTangentialDistortion" ) ) // assumes no tangential distortion
			if( pCfg->m_DataflowAttributes.getAttributeString( "noTangentialDistortion" ) == "true" )
				m_flags |= CV_CALIB_ZERO_TANGENT_DIST;

		if ( pCfg->m_DataflowAttributes.hasAttribute( "fixAspectRatio" ) ) // fixes aspect ratio, such that fx/fy
			if( pCfg->m_DataflowAttributes.getAttributeString( "fixAspectRatio" ) == "true" )
				m_flags |= CV_CALIB_FIX_ASPECT_RATIO;

		///@todo add some other flags, that are possible with newer versions of OpenCV
    }

	/** Method that computes the result. */
	void compute( Measurement::Timestamp t )
	{
		if( hasNewPush() )
			computeIntrinsic();
		m_intrPort.send( Measurement::CameraIntrinsics ( t, m_camIntrinsics ) );
	}

	void computeIntrinsic()
	{
		//just fetch the reference here
		const std::vector< vector_2d_type >& points2D = *m_inPort2D.get();
		const std::vector< vector_3d_type >& points3D = *m_inPort3D.get();

		const std::size_t m_values = points2D.size();

		if( m_values != points3D.size() )
			UBITRACK_THROW( "Cannot perform camera calibration, number of 2D/3D correspondences does not match." );

		if( m_values < 2 )
			UBITRACK_THROW( "Cannot perform camera calibration, need at lest two corresponding measurements." );

		//count the number of available correspondences
		boost::scoped_array< int > chessNumber( new int[ m_values ] );

		std::vector< std::size_t > num_points;
		num_points.reserve( m_values );

		for( std::size_t i( 0 ); i < m_values; ++i )
		{
			const std::size_t n2D = points2D.at( i ).size();
			const std::size_t n3D = points3D.at( i ).size();
			if( n2D != n3D )
				UBITRACK_THROW( "Cannot perform camera calibration, number of corresponding 2D/3D measurements does not match." );
			num_points.push_back( n2D );
			chessNumber[ i ] = static_cast< int > ( n2D );
		}

		const std::size_t summe2D3D = std::accumulate( num_points.begin(), num_points.end(), 0 );

		// everything is fine so far, prepare copying the data
		boost::scoped_array< float > imgPoints( new float[2*summe2D3D] );
		boost::scoped_array< float > objPoints( new float[3*summe2D3D] );

		// copy image corners to big array
		for( std::size_t i ( 0 ); i < m_values; ++i )
		{
			const std::size_t corners2D = points2D.at( i ).size();
			for( std::size_t j ( 0 ) ; j < corners2D; ++j )
			{
				imgPoints[2*i*corners2D + 2*j] = static_cast< float > ( points2D.at( i ).at( j )( 0 ) );
				imgPoints[2*i*corners2D + 2*j + 1] = static_cast< float> ( points2D.at( i ).at( j )( 1 ) );
			}

			const std::size_t corners3D = points3D.at( i ).size();
			for( std::size_t j ( 0 ) ; j < corners3D; ++j )
			{
				objPoints[3*i*corners3D + 3*j] = static_cast< float > ( points3D.at( i ).at( j )( 0 ) );
				objPoints[3*i*corners3D + 3*j + 1] = static_cast< float> ( points3D.at( i ).at( j )( 1 ) );
				objPoints[3*i*corners3D + 3*j + 2] = static_cast< float > ( points3D.at( i ).at( j )( 2 ) );
			}
		}

		CvMat object_points = cvMat ( summe2D3D, 3, CV_32F, objPoints.get() );
		CvMat image_points = cvMat ( summe2D3D, 2, CV_32F, imgPoints.get() );
		CvMat point_counts = cvMat( 1, m_values, CV_32S, chessNumber.get() );

		float intrVal[9];
		CvMat intrinsic_matrix = cvMat ( 3, 3, CV_32FC1, intrVal );

		float disVal[8];
		CvMat distortion_coeffs = cvMat( 8, 1, CV_32FC1, disVal );

		cvCalibrateCamera2(
						&object_points,
						&image_points,
						&point_counts,
						cvSize( 1, 1 ),
						&intrinsic_matrix,
						&distortion_coeffs,
						NULL ,		//	NULL for no output
						NULL ,	//	NULL for no output
						m_flags );

		///@todo check if the paramrers should not be flipped, as it is done at some other places.
		const Math::Vector< 2, double > tangential( disVal[ 1 ], disVal[ 2 ] );
		Math::Vector< 6, double > radial;
		radial( 0 ) = disVal[ 0 ];
		radial( 1 ) = disVal[ 3 ];
		radial( 2 ) = disVal[ 4 ];
		radial( 3 ) = disVal[ 5 ];
		radial( 4 ) = disVal[ 6 ];
		radial( 5 ) = disVal[ 7 ];

		Math::Matrix< 3, 3, double > intrinsic;
		intrinsic( 0, 0 ) = static_cast< double >( intrVal[0] );
		intrinsic( 0, 1 ) = static_cast< double >( intrVal[1] );
		intrinsic( 0, 2 ) = -static_cast< double >( intrVal[2] );
		intrinsic( 1, 0 ) = static_cast< double >( intrVal[3] );
		intrinsic( 1, 1 ) = static_cast< double >( intrVal[4] );
		intrinsic( 1, 2 ) = -static_cast< double >( intrVal[5] );
		intrinsic( 2, 0 ) = 0.0;
		intrinsic( 2, 1 ) = 0.0;
		intrinsic( 2, 2 ) = -1.0;

		m_camIntrinsics = Math::CameraIntrinsics< double > ( intrinsic, radial, tangential );
    }
};

UBITRACK_REGISTER_COMPONENT( Dataflow::ComponentFactory* const cf ) {
	cf->registerComponent< CameraCalibration > ( "CameraCalibration" );
}

} } // namespace Ubitrack::Vision

<commit_msg>changed component, such that calibration procedure is running in a thread now. It is only triggered when not already running.<commit_after>/*
 * Ubitrack - Library for Ubiquitous Tracking
 * Copyright 2006, Technische Universitaet Muenchen, and individual
 * contributors as indicated by the @authors tag. See the
 * copyright.txt in the distribution for a full listing of individual
 * contributors.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */

/**
 * @ingroup vision_components
 * @file
 * Computes the intrinsic matrix and the distortion coefficients
 *
 * @author Christian Waechter <christian.waechter@cs.tum.edu>
 */

//std
#include <vector>
#include <numeric>
#include <algorithm>

// OpenCV (for the calibration function)
#include <opencv/cv.h>

// Boost (for data preperation)
#include <boost/bind.hpp>
#include <boost/thread.hpp>
#include <boost/scoped_ptr.hpp>

// Ubitrack
#include <utUtil/OS.h>
#include <utMath/Vector.h>
#include <utMath/Matrix.h>
#include <utMath/CameraIntrinsics.h>
#include <utDataflow/TriggerComponent.h>
#include <utDataflow/ExpansionInPort.h>
#include <utDataflow/TriggerOutPort.h>
#include <utDataflow/ComponentFactory.h>
#include <utMeasurement/Measurement.h>

#include <log4cpp/Category.hh>
static log4cpp::Category& logger( log4cpp::Category::getInstance( "Ubitrack.Vision.CameraCalibration" ) );

namespace Ubitrack { namespace Vision {

class CameraCalibration
	: public Dataflow::TriggerComponent
{
protected:

	///shortcut for the type of 2d measurements
	typedef std::vector < Math::Vector< 2 > > vector_2d_type;

	///shortcut for the type of 3d measurements
	typedef std::vector < Math::Vector< 3 > > vector_3d_type;

	/** the intrinsic parameters, estimated so far */
	Math::CameraIntrinsics< double > m_camIntrinsics;

	/** signs constraints for the calibration,
	please have a look at the OpenCV Doku for explanations */
	int m_flags;

	/** Input port of the component for 2D measurements. */
	Dataflow::ExpansionInPort< vector_2d_type > m_inPort2D;

	/** Input port of the component for 3D measurements. */
	Dataflow::ExpansionInPort< vector_3d_type > m_inPort3D;

	/** Output port of the component providing the camera intrinsic parameters. */
	Dataflow::TriggerOutPort< Measurement::CameraIntrinsics > m_intrPort;

	/** signs if the thread is running. */
	boost::mutex m_mutexThread;

	/** thread performing camera calibration in the background. */
	boost::scoped_ptr< boost::thread > m_pThread;

public:
	/**
	 * Standard component constructor.
	 *
	 * @param sName Unique name of the component.
	 * @param cfg ComponentConfiguration containing all configuration.
	 */
	CameraCalibration( const std::string& sName, boost::shared_ptr< Graph::UTQLSubgraph > pCfg )
		: Dataflow::TriggerComponent( sName, pCfg )
		, m_flags( CV_CALIB_RATIONAL_MODEL ) // for using 6 instead of 3 distortion parameters
		, m_inPort2D( "Points2D", *this )
		, m_inPort3D( "Points3D", *this )
		, m_intrPort( "CameraIntrinsics", *this )
		, m_mutexThread( )
    {

		// look for some flags which can be specified...
		if ( pCfg->m_DataflowAttributes.hasAttribute( "fixPrincipalPoint" ) ) // fixes principal point to centre of image plane
			if( pCfg->m_DataflowAttributes.getAttributeString( "fixPrincipalPoint" ) == "true" )
				m_flags |= CV_CALIB_FIX_PRINCIPAL_POINT;

		if ( pCfg->m_DataflowAttributes.hasAttribute( "noTangentialDistortion" ) ) // assumes no tangential distortion
			if( pCfg->m_DataflowAttributes.getAttributeString( "noTangentialDistortion" ) == "true" )
				m_flags |= CV_CALIB_ZERO_TANGENT_DIST;

		if ( pCfg->m_DataflowAttributes.hasAttribute( "fixAspectRatio" ) ) // fixes aspect ratio, such that fx/fy
			if( pCfg->m_DataflowAttributes.getAttributeString( "fixAspectRatio" ) == "true" )
				m_flags |= CV_CALIB_FIX_ASPECT_RATIO;

		///@todo add some other flags, that are possible with newer versions of OpenCV
    }

	/** Method that computes the result. */
	void compute( Measurement::Timestamp t )
	{
		if( hasNewPush() )
		{
			if( !boost::mutex::scoped_try_lock ( m_mutexThread ) )
			{
				LOG4CPP_WARN( logger, "Cannot perform camera calibration, thread is still busy, sending old calibration data." );
				return;
			}
			else
			{
				const std::vector< vector_2d_type >& points2D = *m_inPort2D.get();
				const std::vector< vector_3d_type >& points3D = *m_inPort3D.get();
				m_pThread.reset( new boost::thread( boost::bind( &CameraCalibration::computeIntrinsic, this, points3D, points2D )));
			}
		}

		m_intrPort.send( Measurement::CameraIntrinsics ( t, m_camIntrinsics ) );
	}

	void computeIntrinsic( const std::vector< vector_3d_type > points3D, const std::vector< vector_2d_type > points2D )
	{
		boost::mutex::scoped_lock lock( m_mutexThread );
		const std::size_t m_values = points2D.size();

		if( m_values < 2 )
		{
			// UBITRACK_THROW( "Cannot perform camera calibration, need at lest two different views." );
			LOG4CPP_ERROR( logger, "Cannot perform camera calibration, need at lest two different views." );
			return;
		}

		if( m_values != points3D.size() )
		{
			// UBITRACK_THROW( "Cannot perform camera calibration, number of views in 2D does not match number of 3D grids." );
			LOG4CPP_ERROR( logger, "Cannot perform camera calibration, number of views in 2D does not match number of 3D grids." );
			return;
		}

		//count the number of available correspondences
		boost::scoped_array< int > chessNumber( new int[ m_values ] );

		std::vector< std::size_t > num_points;
		num_points.reserve( m_values );

		for( std::size_t i( 0 ); i < m_values; ++i )
		{
			const std::size_t n2D = points2D.at( i ).size();
			const std::size_t n3D = points3D.at( i ).size();
			if( n2D != n3D )
			{
				// UBITRACK_THROW( "Cannot perform camera calibration, number of corresponding 2D/3D measurements does not match." );
				LOG4CPP_ERROR( logger, "Cannot perform camera calibration, number of corresponding 2D/3D measurements does not match." );
				return;
			}

			num_points.push_back( n2D );
			chessNumber[ i ] = static_cast< int > ( n2D );
		}

		const std::size_t summe2D3D = std::accumulate( num_points.begin(), num_points.end(), 0 );

		// everything is fine so far, prepare copying the data
		boost::scoped_array< float > imgPoints( new float[2*summe2D3D] );
		boost::scoped_array< float > objPoints( new float[3*summe2D3D] );

		// copy image corners to big array
		for( std::size_t i ( 0 ); i < m_values; ++i )
		{
			const std::size_t corners2D = points2D.at( i ).size();
			for( std::size_t j ( 0 ) ; j < corners2D; ++j )
			{
				imgPoints[2*i*corners2D + 2*j] = static_cast< float > ( points2D.at( i ).at( j )( 0 ) );
				imgPoints[2*i*corners2D + 2*j + 1] = static_cast< float> ( points2D.at( i ).at( j )( 1 ) );
			}

			const std::size_t corners3D = points3D.at( i ).size();
			for( std::size_t j ( 0 ) ; j < corners3D; ++j )
			{
				objPoints[3*i*corners3D + 3*j] = static_cast< float > ( points3D.at( i ).at( j )( 0 ) );
				objPoints[3*i*corners3D + 3*j + 1] = static_cast< float> ( points3D.at( i ).at( j )( 1 ) );
				objPoints[3*i*corners3D + 3*j + 2] = static_cast< float > ( points3D.at( i ).at( j )( 2 ) );
			}
		}

		CvMat object_points = cvMat ( summe2D3D, 3, CV_32F, objPoints.get() );
		CvMat image_points = cvMat ( summe2D3D, 2, CV_32F, imgPoints.get() );
		CvMat point_counts = cvMat( 1, m_values, CV_32S, chessNumber.get() );

		float intrVal[9];
		CvMat intrinsic_matrix = cvMat ( 3, 3, CV_32FC1, intrVal );

		float disVal[8];
		CvMat distortion_coeffs = cvMat( 8, 1, CV_32FC1, disVal );

		try
		{
			cvCalibrateCamera2(
						&object_points,
						&image_points,
						&point_counts,
						cvSize( 1, 1 ),
						&intrinsic_matrix,
						&distortion_coeffs,
						NULL ,		//	NULL for no output
						NULL ,	//	NULL for no output
						m_flags );
		}
		catch( const std::exception & e )
		{
			LOG4CPP_ERROR( logger, "Cannot perform camera calibration, error in OpenCV function call.\n" << e.what() );
			return;
		}

		///@todo check if the paramrers should not be flipped, as it is done at some other places.
		const Math::Vector< 2, double > tangential( disVal[ 2 ], disVal[ 3 ] );
		Math::Vector< 6, double > radial;
		radial( 0 ) = disVal[ 0 ];
		radial( 1 ) = disVal[ 1 ];
		radial( 2 ) = disVal[ 4 ];
		radial( 3 ) = disVal[ 5 ];
		radial( 4 ) = disVal[ 6 ];
		radial( 5 ) = disVal[ 7 ];

		Math::Matrix< 3, 3, double > intrinsic;
		intrinsic( 0, 0 ) = static_cast< double >( intrVal[0] );
		intrinsic( 0, 1 ) = static_cast< double >( intrVal[1] );
		intrinsic( 0, 2 ) = -static_cast< double >( intrVal[2] );
		intrinsic( 1, 0 ) = static_cast< double >( intrVal[3] );
		intrinsic( 1, 1 ) = static_cast< double >( intrVal[4] );
		intrinsic( 1, 2 ) = -static_cast< double >( intrVal[5] );
		intrinsic( 2, 0 ) = 0.0;
		intrinsic( 2, 1 ) = 0.0;
		intrinsic( 2, 2 ) = -1.0;

		m_camIntrinsics = Math::CameraIntrinsics< double > ( intrinsic, radial, tangential );
		m_intrPort.send( Measurement::CameraIntrinsics ( Measurement::now(), m_camIntrinsics ) );
		LOG4CPP_INFO( logger, "Finished camera calibration using " << m_values << " views." );
    }
};

UBITRACK_REGISTER_COMPONENT( Dataflow::ComponentFactory* const cf ) {
	cf->registerComponent< CameraCalibration > ( "CameraCalibration" );
}

} } // namespace Ubitrack::Vision

<|endoftext|>


<commit_before>// Copyright (c) 2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "main.h"
#include "bitcoinrpc.h"

using namespace json_spirit;
using namespace std;

extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, json_spirit::Object& entry);
extern enum Checkpoints::CPMode CheckpointsMode;

double GetDifficulty(const CBlockIndex* blockindex)
{
    // Floating point number that is a multiple of the minimum difficulty,
    // minimum difficulty = 1.0.
    if (blockindex == NULL)
    {
        if (pindexBest == NULL)
            return 1.0;
        else
            blockindex = GetLastBlockIndex(pindexBest, false);
    }

    int nShift = (blockindex->nBits >> 24) & 0xff;

    double dDiff =
        (double)0x0000ffff / (double)(blockindex->nBits & 0x00ffffff);

    while (nShift < 29)
    {
        dDiff *= 256.0;
        nShift++;
    }
    while (nShift > 29)
    {
        dDiff /= 256.0;
        nShift--;
    }

    return dDiff;
}

double GetPoWMHashPS()
{
    int nPoWInterval = 72;
    int64 nTargetSpacingWorkMin = 30, nTargetSpacingWork = 30;

    CBlockIndex* pindex = pindexGenesisBlock;
    CBlockIndex* pindexPrevWork = pindexGenesisBlock;

    while (pindex)
    {
        if (pindex->IsProofOfWork())
        {
            int64 nActualSpacingWork = pindex->GetBlockTime() - pindexPrevWork->GetBlockTime();
            nTargetSpacingWork = ((nPoWInterval - 1) * nTargetSpacingWork + nActualSpacingWork + nActualSpacingWork) / (nPoWInterval + 1);
            nTargetSpacingWork = max(nTargetSpacingWork, nTargetSpacingWorkMin);
            pindexPrevWork = pindex;
        }

        pindex = pindex->pnext;
    }

    return GetDifficulty() * 4294.967296 / nTargetSpacingWork;
}

double GetPoSKernelPS()
{
    int nPoSInterval = 72;
    double dStakeKernelsTriedAvg = 0;
    int nStakesHandled = 0, nStakesTime = 0;

    CBlockIndex* pindex = pindexBest;;
    CBlockIndex* pindexPrevStake = NULL;

    while (pindex && nStakesHandled < nPoSInterval)
    {
        if (pindex->IsProofOfStake())
        {
            dStakeKernelsTriedAvg += GetDifficulty(pindex) * 4294967296.0;
            nStakesTime += pindexPrevStake ? (pindexPrevStake->nTime - pindex->nTime) : 0;
            pindexPrevStake = pindex;
            nStakesHandled++;
        }

        pindex = pindex->pprev;
    }

    return nStakesTime ? dStakeKernelsTriedAvg / nStakesTime : 0;
}

Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool fPrintTransactionDetail)
{
    Object result;
    result.push_back(Pair("hash", block.GetHash().GetHex()));
    CMerkleTx txGen(block.vtx[0]);
    txGen.SetMerkleBranch(&block);
    result.push_back(Pair("confirmations", (int)txGen.GetDepthInMainChain()));
    result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION)));
    result.push_back(Pair("height", blockindex->nHeight));
    result.push_back(Pair("version", block.nVersion));
    result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex()));
    result.push_back(Pair("mint", ValueFromAmount(blockindex->nMint)));
    result.push_back(Pair("time", (boost::int64_t)block.GetBlockTime()));
    result.push_back(Pair("nonce", (boost::uint64_t)block.nNonce));
    result.push_back(Pair("bits", HexBits(block.nBits)));
    result.push_back(Pair("difficulty", GetDifficulty(blockindex)));
    result.push_back(Pair("blocktrust", leftTrim(blockindex->GetBlockTrust().GetHex(), '0')));
    result.push_back(Pair("chaintrust", leftTrim(blockindex->nChainTrust.GetHex(), '0')));
    if (blockindex->pprev)
        result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()));
    if (blockindex->pnext)
        result.push_back(Pair("nextblockhash", blockindex->pnext->GetBlockHash().GetHex()));

    result.push_back(Pair("flags", strprintf("%s%s", blockindex->IsProofOfStake()? "proof-of-stake" : "proof-of-work", blockindex->GeneratedStakeModifier()? " stake-modifier": "")));
    result.push_back(Pair("proofhash", blockindex->IsProofOfStake()? blockindex->hashProofOfStake.GetHex() : blockindex->GetBlockHash().GetHex()));
    result.push_back(Pair("entropybit", (int)blockindex->GetStakeEntropyBit()));
    result.push_back(Pair("modifier", strprintf("%016"PRI64x, blockindex->nStakeModifier)));
    result.push_back(Pair("modifierchecksum", strprintf("%08x", blockindex->nStakeModifierChecksum)));
    Array txinfo;
    BOOST_FOREACH (const CTransaction& tx, block.vtx)
    {
        if (fPrintTransactionDetail)
        {
            Object entry;

            entry.push_back(Pair("txid", tx.GetHash().GetHex()));
            TxToJSON(tx, 0, entry);

            txinfo.push_back(entry);
        }
        else
            txinfo.push_back(tx.GetHash().GetHex());
    }

    result.push_back(Pair("tx", txinfo));

    if (block.IsProofOfStake())
        result.push_back(Pair("signature", HexStr(block.vchBlockSig.begin(), block.vchBlockSig.end())));

    return result;
}

Value getbestblockhash(const Array& params, bool fHelp)
{
    if (fHelp || params.size() != 0)
        throw runtime_error(
            "getbestblockhash\n"
            "Returns the hash of the best block in the longest block chain.");

    return hashBestChain.GetHex();
}

Value getblockcount(const Array& params, bool fHelp)
{
    if (fHelp || params.size() != 0)
        throw runtime_error(
            "getblockcount\n"
            "Returns the number of blocks in the longest block chain.");

    return nBestHeight;
}

Value getdifficulty(const Array& params, bool fHelp)
{
    if (fHelp || params.size() != 0)
        throw runtime_error(
            "getdifficulty\n"
            "Returns the difficulty as a multiple of the minimum difficulty.");

    Object obj;
    obj.push_back(Pair("proof-of-work",        GetDifficulty()));
    obj.push_back(Pair("proof-of-stake",       GetDifficulty(GetLastBlockIndex(pindexBest, true))));
    obj.push_back(Pair("search-interval",      (int)nLastCoinStakeSearchInterval));
    return obj;
}

Value settxfee(const Array& params, bool fHelp)
{
    if (fHelp || params.size() < 1 || params.size() > 1 || AmountFromValue(params[0]) < MIN_TX_FEE)
        throw runtime_error(
            "settxfee <amount>\n"
            "<amount> is a real and is rounded to the nearest 0.01");

    nTransactionFee = AmountFromValue(params[0]);
    nTransactionFee = (nTransactionFee / CENT) * CENT;  // round to cent

    return true;
}

Value getrawmempool(const Array& params, bool fHelp)
{
    if (fHelp || params.size() != 0)
        throw runtime_error(
            "getrawmempool\n"
            "Returns all transaction ids in memory pool.");

    vector<uint256> vtxid;
    mempool.queryHashes(vtxid);

    Array a;
    BOOST_FOREACH(const uint256& hash, vtxid)
        a.push_back(hash.ToString());

    return a;
}

Value getblockhash(const Array& params, bool fHelp)
{
    if (fHelp || params.size() != 1)
        throw runtime_error(
            "getblockhash <index>\n"
            "Returns hash of block in best-block-chain at <index>.");

    int nHeight = params[0].get_int();
    if (nHeight < 0 || nHeight > nBestHeight)
        throw runtime_error("Block number out of range.");

    CBlockIndex* pblockindex = FindBlockByHeight(nHeight);
    return pblockindex->phashBlock->GetHex();
}

Value getblock(const Array& params, bool fHelp)
{
    if (fHelp || params.size() < 1 || params.size() > 2)
        throw runtime_error(
            "getblock <hash> [txinfo]\n"
            "txinfo optional to print more detailed tx info\n"
            "Returns details of a block with given block-hash.");

    std::string strHash = params[0].get_str();
    uint256 hash(strHash);

    if (mapBlockIndex.count(hash) == 0)
        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");

    CBlock block;
    CBlockIndex* pblockindex = mapBlockIndex[hash];
    block.ReadFromDisk(pblockindex, true);

    return blockToJSON(block, pblockindex, params.size() > 1 ? params[1].get_bool() : false);
}

Value getblockbynumber(const Array& params, bool fHelp)
{
    if (fHelp || params.size() < 1 || params.size() > 2)
        throw runtime_error(
            "getblock <number> [txinfo]\n"
            "txinfo optional to print more detailed tx info\n"
            "Returns details of a block with given block-number.");

    int nHeight = params[0].get_int();
    if (nHeight < 0 || nHeight > nBestHeight)
        throw runtime_error("Block number out of range.");

    CBlock block;
    CBlockIndex* pblockindex = mapBlockIndex[hashBestChain];
    while (pblockindex->nHeight > nHeight)
        pblockindex = pblockindex->pprev;

    uint256 hash = *pblockindex->phashBlock;

    pblockindex = mapBlockIndex[hash];
    block.ReadFromDisk(pblockindex, true);

    return blockToJSON(block, pblockindex, params.size() > 1 ? params[1].get_bool() : false);
}

// ppcoin: get information of sync-checkpoint
Value getcheckpoint(const Array& params, bool fHelp)
{
    if (fHelp || params.size() != 0)
        throw runtime_error(
            "getcheckpoint\n"
            "Show info of synchronized checkpoint.\n");

    Object result;
    CBlockIndex* pindexCheckpoint;

    result.push_back(Pair("synccheckpoint", Checkpoints::hashSyncCheckpoint.ToString().c_str()));
    pindexCheckpoint = mapBlockIndex[Checkpoints::hashSyncCheckpoint];
    result.push_back(Pair("height", pindexCheckpoint->nHeight));
    result.push_back(Pair("timestamp", DateTimeStrFormat(pindexCheckpoint->GetBlockTime()).c_str()));

    // Check that the block satisfies synchronized checkpoint
    if (CheckpointsMode == Checkpoints::STRICT)
        result.push_back(Pair("policy", "strict"));

    if (CheckpointsMode == Checkpoints::ADVISORY)
        result.push_back(Pair("policy", "advisory"));

    if (CheckpointsMode == Checkpoints::PERMISSIVE)
        result.push_back(Pair("policy", "permissive"));

    if (mapArgs.count("-checkpointkey"))
        result.push_back(Pair("checkpointmaster", true));

    return result;
}
<commit_msg>fix netmhashps<commit_after>// Copyright (c) 2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "main.h"
#include "bitcoinrpc.h"

using namespace json_spirit;
using namespace std;

extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, json_spirit::Object& entry);
extern enum Checkpoints::CPMode CheckpointsMode;

double GetDifficulty(const CBlockIndex* blockindex)
{
    // Floating point number that is a multiple of the minimum difficulty,
    // minimum difficulty = 1.0.
    if (blockindex == NULL)
    {
        if (pindexBest == NULL)
            return 1.0;
        else
            blockindex = GetLastBlockIndex(pindexBest, false);
    }

    int nShift = (blockindex->nBits >> 24) & 0xff;

    double dDiff =
        (double)0x0000ffff / (double)(blockindex->nBits & 0x00ffffff);

    while (nShift < 29)
    {
        dDiff *= 256.0;
        nShift++;
    }
    while (nShift > 29)
    {
        dDiff /= 256.0;
        nShift--;
    }

    return dDiff;
}

double GetPoWMHashPS()
{
    if (pindexBest->nHeight >= LAST_POW_BLOCK)
        return 0;

    int nPoWInterval = 72;
    int64 nTargetSpacingWorkMin = 30, nTargetSpacingWork = 30;

    CBlockIndex* pindex = pindexGenesisBlock;
    CBlockIndex* pindexPrevWork = pindexGenesisBlock;

    while (pindex)
    {
        if (pindex->IsProofOfWork())
        {
            int64 nActualSpacingWork = pindex->GetBlockTime() - pindexPrevWork->GetBlockTime();
            nTargetSpacingWork = ((nPoWInterval - 1) * nTargetSpacingWork + nActualSpacingWork + nActualSpacingWork) / (nPoWInterval + 1);
            nTargetSpacingWork = max(nTargetSpacingWork, nTargetSpacingWorkMin);
            pindexPrevWork = pindex;
        }

        pindex = pindex->pnext;
    }

    return GetDifficulty() * 4294.967296 / nTargetSpacingWork;
}

double GetPoSKernelPS()
{
    int nPoSInterval = 72;
    double dStakeKernelsTriedAvg = 0;
    int nStakesHandled = 0, nStakesTime = 0;

    CBlockIndex* pindex = pindexBest;;
    CBlockIndex* pindexPrevStake = NULL;

    while (pindex && nStakesHandled < nPoSInterval)
    {
        if (pindex->IsProofOfStake())
        {
            dStakeKernelsTriedAvg += GetDifficulty(pindex) * 4294967296.0;
            nStakesTime += pindexPrevStake ? (pindexPrevStake->nTime - pindex->nTime) : 0;
            pindexPrevStake = pindex;
            nStakesHandled++;
        }

        pindex = pindex->pprev;
    }

    return nStakesTime ? dStakeKernelsTriedAvg / nStakesTime : 0;
}

Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool fPrintTransactionDetail)
{
    Object result;
    result.push_back(Pair("hash", block.GetHash().GetHex()));
    CMerkleTx txGen(block.vtx[0]);
    txGen.SetMerkleBranch(&block);
    result.push_back(Pair("confirmations", (int)txGen.GetDepthInMainChain()));
    result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION)));
    result.push_back(Pair("height", blockindex->nHeight));
    result.push_back(Pair("version", block.nVersion));
    result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex()));
    result.push_back(Pair("mint", ValueFromAmount(blockindex->nMint)));
    result.push_back(Pair("time", (boost::int64_t)block.GetBlockTime()));
    result.push_back(Pair("nonce", (boost::uint64_t)block.nNonce));
    result.push_back(Pair("bits", HexBits(block.nBits)));
    result.push_back(Pair("difficulty", GetDifficulty(blockindex)));
    result.push_back(Pair("blocktrust", leftTrim(blockindex->GetBlockTrust().GetHex(), '0')));
    result.push_back(Pair("chaintrust", leftTrim(blockindex->nChainTrust.GetHex(), '0')));
    if (blockindex->pprev)
        result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()));
    if (blockindex->pnext)
        result.push_back(Pair("nextblockhash", blockindex->pnext->GetBlockHash().GetHex()));

    result.push_back(Pair("flags", strprintf("%s%s", blockindex->IsProofOfStake()? "proof-of-stake" : "proof-of-work", blockindex->GeneratedStakeModifier()? " stake-modifier": "")));
    result.push_back(Pair("proofhash", blockindex->IsProofOfStake()? blockindex->hashProofOfStake.GetHex() : blockindex->GetBlockHash().GetHex()));
    result.push_back(Pair("entropybit", (int)blockindex->GetStakeEntropyBit()));
    result.push_back(Pair("modifier", strprintf("%016"PRI64x, blockindex->nStakeModifier)));
    result.push_back(Pair("modifierchecksum", strprintf("%08x", blockindex->nStakeModifierChecksum)));
    Array txinfo;
    BOOST_FOREACH (const CTransaction& tx, block.vtx)
    {
        if (fPrintTransactionDetail)
        {
            Object entry;

            entry.push_back(Pair("txid", tx.GetHash().GetHex()));
            TxToJSON(tx, 0, entry);

            txinfo.push_back(entry);
        }
        else
            txinfo.push_back(tx.GetHash().GetHex());
    }

    result.push_back(Pair("tx", txinfo));

    if (block.IsProofOfStake())
        result.push_back(Pair("signature", HexStr(block.vchBlockSig.begin(), block.vchBlockSig.end())));

    return result;
}

Value getbestblockhash(const Array& params, bool fHelp)
{
    if (fHelp || params.size() != 0)
        throw runtime_error(
            "getbestblockhash\n"
            "Returns the hash of the best block in the longest block chain.");

    return hashBestChain.GetHex();
}

Value getblockcount(const Array& params, bool fHelp)
{
    if (fHelp || params.size() != 0)
        throw runtime_error(
            "getblockcount\n"
            "Returns the number of blocks in the longest block chain.");

    return nBestHeight;
}

Value getdifficulty(const Array& params, bool fHelp)
{
    if (fHelp || params.size() != 0)
        throw runtime_error(
            "getdifficulty\n"
            "Returns the difficulty as a multiple of the minimum difficulty.");

    Object obj;
    obj.push_back(Pair("proof-of-work",        GetDifficulty()));
    obj.push_back(Pair("proof-of-stake",       GetDifficulty(GetLastBlockIndex(pindexBest, true))));
    obj.push_back(Pair("search-interval",      (int)nLastCoinStakeSearchInterval));
    return obj;
}

Value settxfee(const Array& params, bool fHelp)
{
    if (fHelp || params.size() < 1 || params.size() > 1 || AmountFromValue(params[0]) < MIN_TX_FEE)
        throw runtime_error(
            "settxfee <amount>\n"
            "<amount> is a real and is rounded to the nearest 0.01");

    nTransactionFee = AmountFromValue(params[0]);
    nTransactionFee = (nTransactionFee / CENT) * CENT;  // round to cent

    return true;
}

Value getrawmempool(const Array& params, bool fHelp)
{
    if (fHelp || params.size() != 0)
        throw runtime_error(
            "getrawmempool\n"
            "Returns all transaction ids in memory pool.");

    vector<uint256> vtxid;
    mempool.queryHashes(vtxid);

    Array a;
    BOOST_FOREACH(const uint256& hash, vtxid)
        a.push_back(hash.ToString());

    return a;
}

Value getblockhash(const Array& params, bool fHelp)
{
    if (fHelp || params.size() != 1)
        throw runtime_error(
            "getblockhash <index>\n"
            "Returns hash of block in best-block-chain at <index>.");

    int nHeight = params[0].get_int();
    if (nHeight < 0 || nHeight > nBestHeight)
        throw runtime_error("Block number out of range.");

    CBlockIndex* pblockindex = FindBlockByHeight(nHeight);
    return pblockindex->phashBlock->GetHex();
}

Value getblock(const Array& params, bool fHelp)
{
    if (fHelp || params.size() < 1 || params.size() > 2)
        throw runtime_error(
            "getblock <hash> [txinfo]\n"
            "txinfo optional to print more detailed tx info\n"
            "Returns details of a block with given block-hash.");

    std::string strHash = params[0].get_str();
    uint256 hash(strHash);

    if (mapBlockIndex.count(hash) == 0)
        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");

    CBlock block;
    CBlockIndex* pblockindex = mapBlockIndex[hash];
    block.ReadFromDisk(pblockindex, true);

    return blockToJSON(block, pblockindex, params.size() > 1 ? params[1].get_bool() : false);
}

Value getblockbynumber(const Array& params, bool fHelp)
{
    if (fHelp || params.size() < 1 || params.size() > 2)
        throw runtime_error(
            "getblock <number> [txinfo]\n"
            "txinfo optional to print more detailed tx info\n"
            "Returns details of a block with given block-number.");

    int nHeight = params[0].get_int();
    if (nHeight < 0 || nHeight > nBestHeight)
        throw runtime_error("Block number out of range.");

    CBlock block;
    CBlockIndex* pblockindex = mapBlockIndex[hashBestChain];
    while (pblockindex->nHeight > nHeight)
        pblockindex = pblockindex->pprev;

    uint256 hash = *pblockindex->phashBlock;

    pblockindex = mapBlockIndex[hash];
    block.ReadFromDisk(pblockindex, true);

    return blockToJSON(block, pblockindex, params.size() > 1 ? params[1].get_bool() : false);
}

// ppcoin: get information of sync-checkpoint
Value getcheckpoint(const Array& params, bool fHelp)
{
    if (fHelp || params.size() != 0)
        throw runtime_error(
            "getcheckpoint\n"
            "Show info of synchronized checkpoint.\n");

    Object result;
    CBlockIndex* pindexCheckpoint;

    result.push_back(Pair("synccheckpoint", Checkpoints::hashSyncCheckpoint.ToString().c_str()));
    pindexCheckpoint = mapBlockIndex[Checkpoints::hashSyncCheckpoint];
    result.push_back(Pair("height", pindexCheckpoint->nHeight));
    result.push_back(Pair("timestamp", DateTimeStrFormat(pindexCheckpoint->GetBlockTime()).c_str()));

    // Check that the block satisfies synchronized checkpoint
    if (CheckpointsMode == Checkpoints::STRICT)
        result.push_back(Pair("policy", "strict"));

    if (CheckpointsMode == Checkpoints::ADVISORY)
        result.push_back(Pair("policy", "advisory"));

    if (CheckpointsMode == Checkpoints::PERMISSIVE)
        result.push_back(Pair("policy", "permissive"));

    if (mapArgs.count("-checkpointkey"))
        result.push_back(Pair("checkpointmaster", true));

    return result;
}
<|endoftext|>


<commit_before><commit_msg>fixed typo in last check-in<commit_after><|endoftext|>


<commit_before><commit_msg>Add more topological sort tests<commit_after><|endoftext|>