<commit_before>/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * 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 <thrift/compiler/sema/standard_mutator.h>

#include <thrift/compiler/lib/cpp2/util.h>
#include <thrift/compiler/sema/patch_mutator.h>
#include <thrift/compiler/sema/standard_mutator_stage.h>

namespace apache {
namespace thrift {
namespace compiler {

constexpr auto kTerseWriteUri = "facebook.com/thrift/annotation/TerseWrite";
constexpr auto kSetGenerated = "facebook.com/thrift/annotation/SetGenerated";
constexpr auto kInjectMetadataFieldsUri =
    "facebook.com/thrift/annotation/InjectMetadataFields";

// TODO(afuller): Instead of mutating the AST, readers should look for
// the interaction level annotation and the validation logic should be moved to
// a standard validator.
void propagate_process_in_event_base_annotation(
    diagnostic_context& ctx, mutator_context&, t_interaction& node) {
  for (auto* func : node.get_functions()) {
    func->set_is_interaction_member();
    ctx.failure_if(
        func->has_annotation("thread"),
        "Interaction methods cannot be individually annotated with "
        "thread='eb'. Use process_in_event_base on the interaction instead.");
  }
  if (node.has_annotation("process_in_event_base")) {
    ctx.failure_if(
        node.has_annotation("serial"), "EB interactions are already serial");
    for (auto* func : node.get_functions()) {
      func->set_annotation("thread", "eb");
    }
  }
}

void remove_param_list_field_qualifiers(
    diagnostic_context& ctx, mutator_context&, t_function& node) {
  for (auto& field : node.params().fields()) {
    switch (field.qualifier()) {
      case t_field_qualifier::none:
        continue;
      case t_field_qualifier::required:
        ctx.warning("optional keyword is ignored in argument lists.");
        break;
      case t_field_qualifier::optional:
        ctx.warning("required keyword is ignored in argument lists.");
        break;
      case t_field_qualifier::terse:
        ctx.warning(
            "@thrift.TerseWrite annotation is ignored in argument lists.");
        break;
    }
    field.set_qualifier(t_field_qualifier::none);
  }
}

// Only an unqualified field is eligible for terse write.
void mutate_terse_write_annotation_field(
    diagnostic_context& ctx, mutator_context&, t_field& node) {
  const t_const* terse_write_annotation =
      node.find_structured_annotation_or_null(kTerseWriteUri);

  if (terse_write_annotation) {
    auto qual = node.qualifier();
    ctx.check(
        qual == t_field_qualifier::none,
        "`@thrift.TerseWrite` cannot be used with qualified fields. Remove `{}` qualifier from field `{}`.",
        qual == t_field_qualifier::required ? "required" : "optional",
        node.name());
    node.set_qualifier(t_field_qualifier::terse);
  }
}

// Only an unqualified field is eligible for terse write.
void mutate_terse_write_annotation_struct(
    diagnostic_context& ctx, mutator_context&, t_struct& node) {
  if (ctx.program().inherit_annotation_or_null(node, kTerseWriteUri)) {
    for (auto& field : node.fields()) {
      if (field.qualifier() == t_field_qualifier::none) {
        field.set_qualifier(t_field_qualifier::terse);
      }
    }
  }
}

void mutate_inject_metadata_fields(
    diagnostic_context& ctx, mutator_context&, t_struct& node) {
  // TODO(dokwon): Currently field injection doesn't work for structs used as
  // transitive annotations. Skipping as a workaround.
  if (is_transitive_annotation(node)) {
    return;
  }

  const t_const* annotation =
      node.find_structured_annotation_or_null(kInjectMetadataFieldsUri);
  if (!annotation) {
    return;
  }

  std::string type_string;
  try {
    type_string =
        annotation->get_value_from_structured_annotation("type").get_string();
  } catch (const std::exception& e) {
    ctx.failure([&](auto& o) { o << e.what(); });
    return;
  }
  // If the specified type and annotation are from the same program, append
  // the current program name.
  if (type_string.find(".") == std::string::npos) {
    type_string = annotation->program()->name() + "." + type_string;
  }

  const auto* ttype = node.program()->scope()->find_type(type_string);
  if (!ttype) {
    ctx.failure([&](auto& o) {
      o << "Can not find expected type `" << type_string
        << "` specified in `@internal.InjectMetadataFields` in the current scope."
        << " Please check the include.";
    });
    return;
  }

  const auto* structured = dynamic_cast<const t_struct*>(ttype);
  // We only allow injecting fields from a struct type.
  if (structured == nullptr || ttype->is_union() || ttype->is_exception() ||
      ttype->is_paramlist()) {
    ctx.failure([&](auto& o) {
      o << "`" << type_string << "` is not a struct type."
        << " `@internal.InjectMetadataFields` can be only used with a struct type.";
    });
    return;
  }
  for (const auto& field : structured->fields()) {
    t_field_id injected_id;
    try {
      injected_id = cpp2::get_internal_injected_field_id(field.id());
    } catch (const std::exception& e) {
      ctx.failure([&](auto& o) { o << e.what(); });
      // Iterate all fields to find more failure.
      continue;
    }
    std::unique_ptr<t_field> cloned_field = field.clone_DO_NOT_USE();
    cloned_field->set_injected_id(injected_id);
    ctx.failure_if(
        !node.try_append_field(std::move(cloned_field)), [&](auto& o) {
          o << "Field id `" << field.id() << "` is already used in `"
            << node.name() << "`.";
        });
  }
}

void set_generated(diagnostic_context&, mutator_context&, t_named& node) {
  if (node.find_structured_annotation_or_null(kSetGenerated)) {
    node.set_generated();
  }
}

void normalize_return_type(
    diagnostic_context& ctx, mutator_context&, t_function& node) {
  auto& types = node.return_types();
  for (size_t i = 0; i < types.size(); ++i) {
    if (!types[i].resolve()) {
      ctx.failure(
          node, "Failed to resolve return type of `" + node.name() + "`.");
      return;
    }

    const auto* type = types[i]->get_true_type();
    if (auto* interaction = dynamic_cast<const t_interaction*>(type)) {
      if (i != 0) {
        ctx.failure([&](auto& o) {
          o << "Interactions are only allowed as the leftmost return type: "
            << type->get_full_name();
        });
      }

      // Old syntax treats returned interaction as response instead
      if (node.is_interaction_constructor()) {
        assert(types.size() == 1);
        node.set_response_pos(i);
        break;
      }
      node.set_returned_interaction_pos(i);
      if (types.size() == 1) {
        node.set_return_type(t_base_type::t_void());
        break;
      }
    } else if (auto* stream = dynamic_cast<const t_stream_response*>(type)) {
      if (i + 1 != types.size()) {
        ctx.failure([&](auto& o) {
          o << "Streams are only allowed as the rightmost return type: "
            << type->get_full_name();
        });
      }
      // TODO: move first response out of t_stream_response
      if (const auto& ret = node.return_type()) {
        const_cast<t_stream_response*>(stream)->set_first_response_type(ret);
      }
      node.set_response_pos(i);
    } else if (auto* sink = dynamic_cast<const t_sink*>(type)) {
      if (i + 1 != types.size()) {
        ctx.failure([&](auto& o) {
          o << "Sinks are only allowed as the rightmost return type: "
            << type->get_full_name();
        });
      }
      // TODO: move first response out of t_sink
      if (const auto& ret = node.return_type()) {
        const_cast<t_sink*>(sink)->set_first_response_type(ret);
      }
      node.set_response_pos(i);
    } else if (
        dynamic_cast<const t_service*>(type) ||
        dynamic_cast<const t_exception*>(type)) {
      ctx.failure([&](auto& o) {
        o << "Invalid return type: " << type->get_full_name();
      });
    } else {
      if (node.return_type()) {
        ctx.failure([&](auto& o) {
          o << "Too many return types: " << type->get_full_name();
        });
      }
      node.set_response_pos(i);
    }
  }
}

ast_mutators standard_mutators() {
  ast_mutators mutators;
  {
    auto& initial = mutators[standard_mutator_stage::initial];
    initial.add_interaction_visitor(
        &propagate_process_in_event_base_annotation);
    initial.add_function_visitor(&remove_param_list_field_qualifiers);
    initial.add_function_visitor(&normalize_return_type);
    initial.add_definition_visitor(&set_generated);
  }

  {
    auto& main = mutators[standard_mutator_stage::main];
    main.add_field_visitor(&mutate_terse_write_annotation_field);
    main.add_struct_visitor(&mutate_terse_write_annotation_struct);
    main.add_struct_visitor(&mutate_inject_metadata_fields);
  }
  add_patch_mutators(mutators);
  return mutators;
}

} // namespace compiler
} // namespace thrift
} // namespace apache
<commit_msg>Remove standard_mutator use of failure_if<commit_after>/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * 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 <thrift/compiler/sema/standard_mutator.h>

#include <thrift/compiler/lib/cpp2/util.h>
#include <thrift/compiler/sema/patch_mutator.h>
#include <thrift/compiler/sema/standard_mutator_stage.h>

namespace apache {
namespace thrift {
namespace compiler {

constexpr auto kTerseWriteUri = "facebook.com/thrift/annotation/TerseWrite";
constexpr auto kSetGenerated = "facebook.com/thrift/annotation/SetGenerated";
constexpr auto kInjectMetadataFieldsUri =
    "facebook.com/thrift/annotation/InjectMetadataFields";

// TODO(afuller): Instead of mutating the AST, readers should look for
// the interaction level annotation and the validation logic should be moved to
// a standard validator.
void propagate_process_in_event_base_annotation(
    diagnostic_context& ctx, mutator_context&, t_interaction& node) {
  for (auto* func : node.get_functions()) {
    func->set_is_interaction_member();
    ctx.check(
        !func->has_annotation("thread"),
        "Interaction methods cannot be individually annotated with "
        "thread='eb'. Use process_in_event_base on the interaction instead.");
  }
  if (node.has_annotation("process_in_event_base")) {
    ctx.check(
        !node.has_annotation("serial"), "EB interactions are already serial");
    for (auto* func : node.get_functions()) {
      func->set_annotation("thread", "eb");
    }
  }
}

void remove_param_list_field_qualifiers(
    diagnostic_context& ctx, mutator_context&, t_function& node) {
  for (auto& field : node.params().fields()) {
    switch (field.qualifier()) {
      case t_field_qualifier::none:
        continue;
      case t_field_qualifier::required:
        ctx.warning("optional keyword is ignored in argument lists.");
        break;
      case t_field_qualifier::optional:
        ctx.warning("required keyword is ignored in argument lists.");
        break;
      case t_field_qualifier::terse:
        ctx.warning(
            "@thrift.TerseWrite annotation is ignored in argument lists.");
        break;
    }
    field.set_qualifier(t_field_qualifier::none);
  }
}

// Only an unqualified field is eligible for terse write.
void mutate_terse_write_annotation_field(
    diagnostic_context& ctx, mutator_context&, t_field& node) {
  const t_const* terse_write_annotation =
      node.find_structured_annotation_or_null(kTerseWriteUri);

  if (terse_write_annotation) {
    auto qual = node.qualifier();
    ctx.check(
        qual == t_field_qualifier::none,
        "`@thrift.TerseWrite` cannot be used with qualified fields. Remove `{}` qualifier from field `{}`.",
        qual == t_field_qualifier::required ? "required" : "optional",
        node.name());
    node.set_qualifier(t_field_qualifier::terse);
  }
}

// Only an unqualified field is eligible for terse write.
void mutate_terse_write_annotation_struct(
    diagnostic_context& ctx, mutator_context&, t_struct& node) {
  if (ctx.program().inherit_annotation_or_null(node, kTerseWriteUri)) {
    for (auto& field : node.fields()) {
      if (field.qualifier() == t_field_qualifier::none) {
        field.set_qualifier(t_field_qualifier::terse);
      }
    }
  }
}

void mutate_inject_metadata_fields(
    diagnostic_context& ctx, mutator_context&, t_struct& node) {
  // TODO(dokwon): Currently field injection doesn't work for structs used as
  // transitive annotations. Skipping as a workaround.
  if (is_transitive_annotation(node)) {
    return;
  }

  const t_const* annotation =
      node.find_structured_annotation_or_null(kInjectMetadataFieldsUri);
  if (!annotation) {
    return;
  }

  std::string type_string;
  try {
    type_string =
        annotation->get_value_from_structured_annotation("type").get_string();
  } catch (const std::exception& e) {
    ctx.failure([&](auto& o) { o << e.what(); });
    return;
  }
  // If the specified type and annotation are from the same program, append
  // the current program name.
  if (type_string.find(".") == std::string::npos) {
    type_string = annotation->program()->name() + "." + type_string;
  }

  const auto* ttype = node.program()->scope()->find_type(type_string);
  if (!ttype) {
    ctx.failure([&](auto& o) {
      o << "Can not find expected type `" << type_string
        << "` specified in `@internal.InjectMetadataFields` in the current scope."
        << " Please check the include.";
    });
    return;
  }

  const auto* structured = dynamic_cast<const t_struct*>(ttype);
  // We only allow injecting fields from a struct type.
  if (structured == nullptr || ttype->is_union() || ttype->is_exception() ||
      ttype->is_paramlist()) {
    ctx.failure([&](auto& o) {
      o << "`" << type_string << "` is not a struct type."
        << " `@internal.InjectMetadataFields` can be only used with a struct type.";
    });
    return;
  }
  for (const auto& field : structured->fields()) {
    t_field_id injected_id;
    try {
      injected_id = cpp2::get_internal_injected_field_id(field.id());
    } catch (const std::exception& e) {
      ctx.failure([&](auto& o) { o << e.what(); });
      // Iterate all fields to find more failure.
      continue;
    }
    std::unique_ptr<t_field> cloned_field = field.clone_DO_NOT_USE();
    cloned_field->set_injected_id(injected_id);
    ctx.check(
        node.try_append_field(std::move(cloned_field)),
        "Field id `{}` is already used in `{}`.",
        field.id(),
        node.name());
  }
}

void set_generated(diagnostic_context&, mutator_context&, t_named& node) {
  if (node.find_structured_annotation_or_null(kSetGenerated)) {
    node.set_generated();
  }
}

void normalize_return_type(
    diagnostic_context& ctx, mutator_context&, t_function& node) {
  auto& types = node.return_types();
  for (size_t i = 0; i < types.size(); ++i) {
    if (!types[i].resolve()) {
      ctx.failure(
          node, "Failed to resolve return type of `" + node.name() + "`.");
      return;
    }

    const auto* type = types[i]->get_true_type();
    if (auto* interaction = dynamic_cast<const t_interaction*>(type)) {
      if (i != 0) {
        ctx.failure([&](auto& o) {
          o << "Interactions are only allowed as the leftmost return type: "
            << type->get_full_name();
        });
      }

      // Old syntax treats returned interaction as response instead
      if (node.is_interaction_constructor()) {
        assert(types.size() == 1);
        node.set_response_pos(i);
        break;
      }
      node.set_returned_interaction_pos(i);
      if (types.size() == 1) {
        node.set_return_type(t_base_type::t_void());
        break;
      }
    } else if (auto* stream = dynamic_cast<const t_stream_response*>(type)) {
      if (i + 1 != types.size()) {
        ctx.failure([&](auto& o) {
          o << "Streams are only allowed as the rightmost return type: "
            << type->get_full_name();
        });
      }
      // TODO: move first response out of t_stream_response
      if (const auto& ret = node.return_type()) {
        const_cast<t_stream_response*>(stream)->set_first_response_type(ret);
      }
      node.set_response_pos(i);
    } else if (auto* sink = dynamic_cast<const t_sink*>(type)) {
      if (i + 1 != types.size()) {
        ctx.failure([&](auto& o) {
          o << "Sinks are only allowed as the rightmost return type: "
            << type->get_full_name();
        });
      }
      // TODO: move first response out of t_sink
      if (const auto& ret = node.return_type()) {
        const_cast<t_sink*>(sink)->set_first_response_type(ret);
      }
      node.set_response_pos(i);
    } else if (
        dynamic_cast<const t_service*>(type) ||
        dynamic_cast<const t_exception*>(type)) {
      ctx.failure([&](auto& o) {
        o << "Invalid return type: " << type->get_full_name();
      });
    } else {
      if (node.return_type()) {
        ctx.failure([&](auto& o) {
          o << "Too many return types: " << type->get_full_name();
        });
      }
      node.set_response_pos(i);
    }
  }
}

ast_mutators standard_mutators() {
  ast_mutators mutators;
  {
    auto& initial = mutators[standard_mutator_stage::initial];
    initial.add_interaction_visitor(
        &propagate_process_in_event_base_annotation);
    initial.add_function_visitor(&remove_param_list_field_qualifiers);
    initial.add_function_visitor(&normalize_return_type);
    initial.add_definition_visitor(&set_generated);
  }

  {
    auto& main = mutators[standard_mutator_stage::main];
    main.add_field_visitor(&mutate_terse_write_annotation_field);
    main.add_struct_visitor(&mutate_terse_write_annotation_struct);
    main.add_struct_visitor(&mutate_inject_metadata_fields);
  }
  add_patch_mutators(mutators);
  return mutators;
}

} // namespace compiler
} // namespace thrift
} // namespace apache
<|endoftext|>


<commit_before>#pragma once

#include <geneial/core/population/builder/ContinousMultiValueChromosomeFactory.h>
#include <geneial/utility/Random.h>

#include <algorithm>
#include <cassert>

geneial_private_namespace(geneial)
{
geneial_private_namespace(population)
{
geneial_private_namespace(chromosome)
{
using ::geneial::population::chromosome::ContinousMultiValueBuilderSettings;
using ::geneial::population::chromosome::ContinousMultiValueChromosomeFactory;

geneial_export_namespace
{

template<typename VALUE_TYPE, typename FITNESS_TYPE>
typename BaseChromosome<FITNESS_TYPE>::ptr ContinousMultiValueChromosomeFactory<VALUE_TYPE, FITNESS_TYPE>::doCreateChromosome(
        typename BaseChromosomeFactory<FITNESS_TYPE>::PopulateBehavior populateValues)
{
    using namespace geneial::utility;

    auto new_chromosome = this->allocateNewChromsome();

    if (populateValues == BaseChromosomeFactory<FITNESS_TYPE>::CREATE_VALUES)
    {
        const unsigned int amount = _settings.getNum();

        unsigned int i = 0;

        VALUE_TYPE lastVal = 0; //reference to last inserted value

        while (i<amount)
        {

            if (i == 0)
            {
                if (_settings.hasStart())
                {
                    lastVal = _settings.getStartValue();
                }
                else
                {
                    lastVal = Random::generate<VALUE_TYPE>(_settings.getRandomMin(),
                                                           _settings.getRandomMax());
                }
            }

            const VALUE_TYPE val = Random::generate<VALUE_TYPE>(lastVal - _settings.getEps(),
                                                                lastVal + _settings.getEps());
            const VALUE_TYPE lower_limited = std::max(_settings.getRandomMin(), val);
            const VALUE_TYPE upper_limited = std::min(_settings.getRandomMax(), lower_limited);

            new_chromosome->getContainer()[i] = upper_limited;

            lastVal = upper_limited;
            i++;
        }
        assert(new_chromosome->getSize() == _settings.getNum());

    }

    return std::move(new_chromosome);
}

} /* geneial_export_namespace */
} /* private namespace chromosome */
} /* private namespace population */
} /* private namespace geneial */

<commit_msg>fixed a bug in continous factory that was changing random distribution in favor of values towards the limit<commit_after>#pragma once

#include <geneial/core/population/builder/ContinousMultiValueChromosomeFactory.h>
#include <geneial/utility/Random.h>

#include <algorithm>
#include <cassert>

geneial_private_namespace(geneial)
{
geneial_private_namespace(population)
{
geneial_private_namespace(chromosome)
{
using ::geneial::population::chromosome::ContinousMultiValueBuilderSettings;
using ::geneial::population::chromosome::ContinousMultiValueChromosomeFactory;

geneial_export_namespace
{

template<typename VALUE_TYPE, typename FITNESS_TYPE>
typename BaseChromosome<FITNESS_TYPE>::ptr ContinousMultiValueChromosomeFactory<VALUE_TYPE, FITNESS_TYPE>::doCreateChromosome(
        typename BaseChromosomeFactory<FITNESS_TYPE>::PopulateBehavior populateValues)
{
    using namespace geneial::utility;

    auto new_chromosome = this->allocateNewChromsome();

    if (populateValues == BaseChromosomeFactory<FITNESS_TYPE>::CREATE_VALUES)
    {
        const unsigned int amount = _settings.getNum();

        unsigned int i = 0;

        VALUE_TYPE lastVal = 0; //reference to last inserted value

        while (i<amount)
        {

            if (i == 0)
            {
                if (_settings.hasStart())
                {
                    lastVal = _settings.getStartValue();
                }
                else
                {
                    lastVal = Random::generate<VALUE_TYPE>(_settings.getRandomMin(),
                                                           _settings.getRandomMax());
                }
            }

            const VALUE_TYPE lower_limited = std::max(_settings.getRandomMin(), lastVal - _settings.getEps());
            const VALUE_TYPE upper_limited = std::min(_settings.getRandomMax(), lastVal + _settings.getEps());

            const VALUE_TYPE val = Random::generate<VALUE_TYPE>(lower_limited,
                                                                upper_limited,
                                                                lastVal + _settings.getEps());

            new_chromosome->getContainer()[i] = upper_limited;

            lastVal = upper_limited;
            i++;
        }
        assert(new_chromosome->getSize() == _settings.getNum());

    }

    return std::move(new_chromosome);
}

} /* geneial_export_namespace */
} /* private namespace chromosome */
} /* private namespace population */
} /* private namespace geneial */

<|endoftext|>


<commit_before>#define DeutSelector_cxx
// The class definition in DeutSelector.h has been generated automatically
// by the ROOT utility TTree::MakeSelector(). This class is derived
// from the ROOT class TSelector. For more information on the TSelector
// framework see $ROOTSYS/README/README.SELECTOR or the ROOT User Manual.

// The following methods are defined in this file:
//    Begin():        called every time a loop on the tree starts,
//                    a convenient place to create your histograms.
//    SlaveBegin():   called after Begin(), when on PROOF called only on the
//                    slave servers.
//    Process():      called for each event, in this function you decide what
//                    to read and fill your histograms.
//    SlaveTerminate: called at the end of the loop on the tree, when on PROOF
//                    called only on the slave servers.
//    Terminate():    called at the end of the loop on the tree,
//                    a convenient place to draw/fit your histograms.
//
// To use this file, try the following session on your Tree T:
//
// Root > T->Process("DeutSelector.C")
// Root > T->Process("DeutSelector.C","some options")
// Root > T->Process("DeutSelector.C+")
//

#include "DeutSelector.h"
#include <TH2.h>
#include <TH2F.h>
#include <TH1D.h>
#include <TStyle.h>
#include <Riostream.h>
#include <TMath.h>
#include <TCanvas.h>
#include <TAxis.h>
#include <TF1.h>

#define EPSILON 1E-5

static void BinLogAxis(const TH1 *h)
{
  //
  // Method for the correct logarithmic binning of histograms
  //
  TAxis *axis = const_cast<TAxis*>(h->GetXaxis());
  const Int_t bins = axis->GetNbins();

  const Double_t from = axis->GetXmin();
  const Double_t to = axis->GetXmax();
  Double_t *newBins = new Double_t[bins + 1];

  newBins[0] = from;
  Double_t factor = pow(to / from, 1. / bins);

  for (Int_t i = 1; i <= bins; i++) {
    newBins[i] = factor * newBins[i - 1];
  }
  axis->Set(bins, newBins);
  delete [] newBins;
}

Double_t BetheBlochAleph(Double_t bg,
			 Double_t kp1,
			 Double_t kp2,
			 Double_t kp3,
			 Double_t kp4,
			 Double_t kp5) {
  Double_t beta = bg/TMath::Sqrt(1.+ bg*bg);
  Double_t aa = TMath::Power(beta,kp4);
  Double_t bb = TMath::Power(1./bg,kp5);
  bb=TMath::Log(kp3+bb);
  return (kp2-aa-bb)*kp1/aa;
}

Double_t DeuteronTPC(Double_t *x, Double_t *par) {
  // Deuteron expected signal in TPC, taken from AntiHe4 task
  return BetheBlochAleph(x[0]/1.875612,4.69637,7.51827,0.0183746,2.60,2.7);
}

void DeutSelector::Begin(TTree * /*tree*/)
{
  // The Begin() function is called at the start of the query.
  // When running with PROOF Begin() is only called on the client.
  // The tree argument is deprecated (on PROOF 0 is passed).
  TString option = GetOption();
}

int DeutSelector::GetPtBin(float pt) {
  for (int i = 0; i < 13; ++i) {
    if (pt < fBins[i+1] && pt >= fBins[i]) {
      return i;
    }
  }
}

void DeutSelector::SlaveBegin(TTree * /*tree*/)
{
  // The SlaveBegin() function is called after the Begin() function.
  // When running with PROOF SlaveBegin() is called on each slave server.
  // The tree argument is deprecated (on PROOF 0 is passed).

  TString option = GetOption();
  fBeta = new TH1D("fBeta",";#beta;Entries",100,0.f,1.f);
  fBeta2D = new TH2F("fBeta2D","TOF; #frac{p}{z} (GeV/c); #beta", 500,0.01,5.,2250,0.1,1.);
  fGamma = new TH1D("fGamma",";#gamma;Entries",1000,1.f,1000.f);
  fdEdxTPC = new TH2F("fdEdxTPC",";p (GeV/c);dE/dx (a.u.)",500,0.1,5.,500,0,2000);
  fdEdxTPCSignal = new TH2F("fdEdxTPCSignal",";p (GeV/c);dE/dx (a.u.)",500,0.1,5.,2000,0,2000);
  fdEdxTPCproj = new TH2F("fdEdxTPCproj",";p (GeV/c);dE/dx (a.u.)",93,0.4,3.2,2000,0,2000);
  BinLogAxis(fdEdxTPC);
  fSignal = new TH1D*[13];
  float bins[14] = {0.8f,1.0f,1.2f,1.4f,1.6f,1.8f,2.0f,2.2f,2.4f,2.6f,3.0f,3.5f,4.0f,5.0f};
  fBins[0] = bins[0];
  for (int i = 0; i < 13; ++i) {
    fBins[i+1] = bins[i+1];
    fSignal[i] = new TH1D(Form("fSignal_%4.1f_%4.1f",fBins[i],fBins[i+1]),";(m - m_{PDG})^{2};Entries",600,0.1,6.1);
    GetOutputList()->Add(fSignal[i]);
  }
  GetOutputList()->Add(fdEdxTPC);
  GetOutputList()->Add(fdEdxTPCSignal);
  GetOutputList()->Add(fdEdxTPCproj);
  GetOutputList()->Add(fBeta);
  GetOutputList()->Add(fBeta2D);
  GetOutputList()->Add(fGamma);

  fDeutBB = new TF1("fDeutBB",DeuteronTPC,0.3,6,0);

}

Bool_t DeutSelector::Process(Long64_t entry)
{
  // The Process() function is called for each entry in the tree (or possibly
  // keyed object in the case of PROOF) to be processed. The entry argument
  // specifies which entry in the currently loaded tree is to be processed.
  // It can be passed to either DeutSelector::GetEntry() or TBranch::GetEntry()
  // to read either all or the required parts of the data. When processing
  // keyed objects with PROOF, the object is already loaded and is available
  // via the fObject pointer.
  //
  // This function should contain the "body" of the analysis. It can contain
  // simple or elaborate selection criteria, run algorithms on the data
  // of the event and typically fill histograms.
  //
  // The processing can be stopped by calling Abort().
  //
  // Use fStatus to set the return value of TTree::Process().
  //
  // The return value is currently not used.

  GetEntry(entry);
  if (TMath::Abs(eta) > 0.8)
    return kTRUE;
  if (pTPC == p) {
    return kTRUE;
  }
  fdEdxTPC->Fill(pTPC,TPCsignal);
  fdEdxTPCproj->Fill(pTPC,TPCsignal);

  if (TPCsignal > 0.7f * fDeutBB->Eval(pTPC) && TPCsignal < 1.3f * fDeutBB->Eval(pTPC)) {
    fdEdxTPCSignal->Fill(pTPC,TPCsignal);
    if (pTPC > 5.f) return kTRUE;
    if (TOFtime > 0.f && length > 0.f) {
      Float_t beta = length / (2.99792457999999984e-02 * TOFtime);
      fBeta->Fill(beta);
      fBeta2D->Fill(pTPC,beta);
      if (beta < (1.f - EPSILON)) {
        Float_t gamma = 1 / TMath::Sqrt(1 - (beta * beta));
        fGamma->Fill(gamma);
        const float dm = 1.875612859f - p / (beta * gamma);
        fSignal[GetPtBin(pT)]->Fill(dm * dm);
      }
    }
  }
  return kTRUE;
}

void DeutSelector::SlaveTerminate()
{
  // The SlaveTerminate() function is called after all entries or objects
  // have been processed. When running with PROOF SlaveTerminate() is called
  // on each slave server.
  delete fDeutBB;
}

void DeutSelector::Terminate()
{
  // The Terminate() function is the last function to be called during
  // a query. It always runs on the client, it can be used to present
  // the results graphically or save the results to file.

  TFile f("final.root","recreate");
  TF1 fbb("BBAleph",DeuteronTPC,0.4f,5.f,0);
  TCanvas c;
  fdEdxTPC = dynamic_cast<TH2F*>(GetOutputList()->FindObject("fdEdxTPC"));
  if (fdEdxTPC) {
    c.cd();
    fdEdxTPC->DrawClone();
    fbb.DrawClone("same");
    f.cd();
    c.Write();
    fdEdxTPC->Write();
  }

  fdEdxTPCSignal = dynamic_cast<TH2F*>(GetOutputList()->FindObject("fdEdxTPCSignal"));
  if (fdEdxTPCSignal) {
    fdEdxTPCSignal->Write();
  }

  fdEdxTPCproj = dynamic_cast<TH2F*>(GetOutputList()->FindObject("fdEdxTPCproj"));
  if (fdEdxTPCproj) {
    fdEdxTPCproj->Write();
  }

  fBeta = dynamic_cast<TH1D*>(GetOutputList()->FindObject("fBeta"));
  if (fBeta) {
    fBeta->Write();
  }

  fGamma = dynamic_cast<TH1D*>(GetOutputList()->FindObject("fGamma"));
  if (fGamma) {
    fGamma->Write();
  }

  for (int i = 0; i < 13; ++i) {
    fSignal[i] = dynamic_cast<TH1D*>(GetOutputList()->FindObject(Form("fSignal_%4.1f_%4.1f",fBins[i],fBins[i+1])));
    if (fSignal[i]) {
      fSignal[i]->Write();
    }
  }

  fBeta2D = dynamic_cast<TH2F*>(GetOutputList()->FindObject("fBeta2D"));
  if (fBeta2D) {
    fBeta2D->Write();
  }
  f.Close();

}
<commit_msg>Missing default case<commit_after>#define DeutSelector_cxx
// The class definition in DeutSelector.h has been generated automatically
// by the ROOT utility TTree::MakeSelector(). This class is derived
// from the ROOT class TSelector. For more information on the TSelector
// framework see $ROOTSYS/README/README.SELECTOR or the ROOT User Manual.

// The following methods are defined in this file:
//    Begin():        called every time a loop on the tree starts,
//                    a convenient place to create your histograms.
//    SlaveBegin():   called after Begin(), when on PROOF called only on the
//                    slave servers.
//    Process():      called for each event, in this function you decide what
//                    to read and fill your histograms.
//    SlaveTerminate: called at the end of the loop on the tree, when on PROOF
//                    called only on the slave servers.
//    Terminate():    called at the end of the loop on the tree,
//                    a convenient place to draw/fit your histograms.
//
// To use this file, try the following session on your Tree T:
//
// Root > T->Process("DeutSelector.C")
// Root > T->Process("DeutSelector.C","some options")
// Root > T->Process("DeutSelector.C+")
//

#include "DeutSelector.h"
#include <TH2.h>
#include <TH2F.h>
#include <TH1D.h>
#include <TStyle.h>
#include <Riostream.h>
#include <TMath.h>
#include <TCanvas.h>
#include <TAxis.h>
#include <TF1.h>

#define EPSILON 1E-5

static void BinLogAxis(const TH1 *h)
{
  //
  // Method for the correct logarithmic binning of histograms
  //
  TAxis *axis = const_cast<TAxis*>(h->GetXaxis());
  const Int_t bins = axis->GetNbins();

  const Double_t from = axis->GetXmin();
  const Double_t to = axis->GetXmax();
  Double_t *newBins = new Double_t[bins + 1];

  newBins[0] = from;
  Double_t factor = pow(to / from, 1. / bins);

  for (Int_t i = 1; i <= bins; i++) {
    newBins[i] = factor * newBins[i - 1];
  }
  axis->Set(bins, newBins);
  delete [] newBins;
}

Double_t BetheBlochAleph(Double_t bg,
			 Double_t kp1,
			 Double_t kp2,
			 Double_t kp3,
			 Double_t kp4,
			 Double_t kp5) {
  Double_t beta = bg/TMath::Sqrt(1.+ bg*bg);
  Double_t aa = TMath::Power(beta,kp4);
  Double_t bb = TMath::Power(1./bg,kp5);
  bb=TMath::Log(kp3+bb);
  return (kp2-aa-bb)*kp1/aa;
}

Double_t DeuteronTPC(Double_t *x, Double_t *par) {
  // Deuteron expected signal in TPC, taken from AntiHe4 task
  return BetheBlochAleph(x[0]/1.875612,4.69637,7.51827,0.0183746,2.60,2.7);
}

void DeutSelector::Begin(TTree * /*tree*/)
{
  // The Begin() function is called at the start of the query.
  // When running with PROOF Begin() is only called on the client.
  // The tree argument is deprecated (on PROOF 0 is passed).
  TString option = GetOption();
}

int DeutSelector::GetPtBin(float pt) {
  for (int i = 0; i < 13; ++i) {
    if (pt < fBins[i+1] && pt >= fBins[i]) {
      return i;
    }
  }
  return -1;
}

void DeutSelector::SlaveBegin(TTree * /*tree*/)
{
  // The SlaveBegin() function is called after the Begin() function.
  // When running with PROOF SlaveBegin() is called on each slave server.
  // The tree argument is deprecated (on PROOF 0 is passed).

  TString option = GetOption();
  fBeta = new TH1D("fBeta",";#beta;Entries",100,0.f,1.f);
  fBeta2D = new TH2F("fBeta2D","TOF; #frac{p}{z} (GeV/c); #beta", 500,0.01,5.,2250,0.1,1.);
  fGamma = new TH1D("fGamma",";#gamma;Entries",1000,1.f,1000.f);
  fdEdxTPC = new TH2F("fdEdxTPC",";p (GeV/c);dE/dx (a.u.)",500,0.1,5.,500,0,2000);
  fdEdxTPCSignal = new TH2F("fdEdxTPCSignal",";p (GeV/c);dE/dx (a.u.)",500,0.1,5.,2000,0,2000);
  fdEdxTPCproj = new TH2F("fdEdxTPCproj",";p (GeV/c);dE/dx (a.u.)",93,0.4,3.2,2000,0,2000);
  BinLogAxis(fdEdxTPC);
  fSignal = new TH1D*[13];
  float bins[14] = {0.8f,1.0f,1.2f,1.4f,1.6f,1.8f,2.0f,2.2f,2.4f,2.6f,3.0f,3.5f,4.0f,5.0f};
  fBins[0] = bins[0];
  for (int i = 0; i < 13; ++i) {
    fBins[i+1] = bins[i+1];
    fSignal[i] = new TH1D(Form("fSignal_%4.1f_%4.1f",fBins[i],fBins[i+1]),";(m - m_{PDG})^{2};Entries",600,0.1,6.1);
    GetOutputList()->Add(fSignal[i]);
  }
  GetOutputList()->Add(fdEdxTPC);
  GetOutputList()->Add(fdEdxTPCSignal);
  GetOutputList()->Add(fdEdxTPCproj);
  GetOutputList()->Add(fBeta);
  GetOutputList()->Add(fBeta2D);
  GetOutputList()->Add(fGamma);

  fDeutBB = new TF1("fDeutBB",DeuteronTPC,0.3,6,0);

}

Bool_t DeutSelector::Process(Long64_t entry)
{
  // The Process() function is called for each entry in the tree (or possibly
  // keyed object in the case of PROOF) to be processed. The entry argument
  // specifies which entry in the currently loaded tree is to be processed.
  // It can be passed to either DeutSelector::GetEntry() or TBranch::GetEntry()
  // to read either all or the required parts of the data. When processing
  // keyed objects with PROOF, the object is already loaded and is available
  // via the fObject pointer.
  //
  // This function should contain the "body" of the analysis. It can contain
  // simple or elaborate selection criteria, run algorithms on the data
  // of the event and typically fill histograms.
  //
  // The processing can be stopped by calling Abort().
  //
  // Use fStatus to set the return value of TTree::Process().
  //
  // The return value is currently not used.

  GetEntry(entry);
  if (TMath::Abs(eta) > 0.8)
    return kTRUE;
  if (pTPC == p) {
    return kTRUE;
  }
  fdEdxTPC->Fill(pTPC,TPCsignal);
  fdEdxTPCproj->Fill(pTPC,TPCsignal);

  if (TPCsignal > 0.7f * fDeutBB->Eval(pTPC) && TPCsignal < 1.3f * fDeutBB->Eval(pTPC)) {
    fdEdxTPCSignal->Fill(pTPC,TPCsignal);
    if (pTPC > 5.f) return kTRUE;
    if (TOFtime > 0.f && length > 0.f) {
      Float_t beta = length / (2.99792457999999984e-02 * TOFtime);
      fBeta->Fill(beta);
      fBeta2D->Fill(pTPC,beta);
      if (beta < (1.f - EPSILON)) {
        Float_t gamma = 1 / TMath::Sqrt(1 - (beta * beta));
        fGamma->Fill(gamma);
        const float dm = 1.875612859f - p / (beta * gamma);
        const int j = GetPtBin(pT);
        if (j < 0) {
          return kTRUE;
        }
        fSignal[j]->Fill(dm * dm);
      }
    }
  }
  return kTRUE;
}

void DeutSelector::SlaveTerminate()
{
  // The SlaveTerminate() function is called after all entries or objects
  // have been processed. When running with PROOF SlaveTerminate() is called
  // on each slave server.
  delete fDeutBB;
}

void DeutSelector::Terminate()
{
  // The Terminate() function is the last function to be called during
  // a query. It always runs on the client, it can be used to present
  // the results graphically or save the results to file.

  TFile f("final.root","recreate");
  TF1 fbb("BBAleph",DeuteronTPC,0.4f,5.f,0);
  TCanvas c;
  fdEdxTPC = dynamic_cast<TH2F*>(GetOutputList()->FindObject("fdEdxTPC"));
  if (fdEdxTPC) {
    c.cd();
    fdEdxTPC->DrawClone();
    fbb.DrawClone("same");
    f.cd();
    c.Write();
    fdEdxTPC->Write();
  }

  fdEdxTPCSignal = dynamic_cast<TH2F*>(GetOutputList()->FindObject("fdEdxTPCSignal"));
  if (fdEdxTPCSignal) {
    fdEdxTPCSignal->Write();
  }

  fdEdxTPCproj = dynamic_cast<TH2F*>(GetOutputList()->FindObject("fdEdxTPCproj"));
  if (fdEdxTPCproj) {
    fdEdxTPCproj->Write();
  }

  fBeta = dynamic_cast<TH1D*>(GetOutputList()->FindObject("fBeta"));
  if (fBeta) {
    fBeta->Write();
  }

  fGamma = dynamic_cast<TH1D*>(GetOutputList()->FindObject("fGamma"));
  if (fGamma) {
    fGamma->Write();
  }

  for (int i = 0; i < 13; ++i) {
    fSignal[i] = dynamic_cast<TH1D*>(GetOutputList()->FindObject(Form("fSignal_%4.1f_%4.1f",fBins[i],fBins[i+1])));
    if (fSignal[i]) {
      fSignal[i]->Write();
    }
  }

  fBeta2D = dynamic_cast<TH2F*>(GetOutputList()->FindObject("fBeta2D"));
  if (fBeta2D) {
    fBeta2D->Write();
  }
  f.Close();

}
<|endoftext|>


<commit_before>#ifndef CMDSTAN_ARGUMENTS_ARG_ID_HPP
#define CMDSTAN_ARGUMENTS_ARG_ID_HPP

#include <cmdstan/arguments/singleton_argument.hpp>

namespace cmdstan {

  class arg_id: public int_argument {
  public:
    arg_id(): int_argument() {
      _name = "id";
      _description = "Unique process identifier";
      _validity = "id > 0";
      _default = "0";
      _default_value = 0;
      _constrained = true;
      _good_value = 2.0;
      _bad_value = -1.0;
      _value = _default_value;
    }

    bool is_valid(int value) { return value > 0; }
  };

}
#endif
<commit_msg>changed the validity of the id argument<commit_after>#ifndef CMDSTAN_ARGUMENTS_ARG_ID_HPP
#define CMDSTAN_ARGUMENTS_ARG_ID_HPP

#include <cmdstan/arguments/singleton_argument.hpp>

namespace cmdstan {

  class arg_id: public int_argument {
  public:
    arg_id(): int_argument() {
      _name = "id";
      _description = "Unique process identifier";
      _validity = "id >= 0";
      _default = "0";
      _default_value = 0;
      _constrained = true;
      _good_value = 2.0;
      _bad_value = -1.0;
      _value = _default_value;
    }

    bool is_valid(int value) { return value >= 0; }
  };

}
#endif
<|endoftext|>


<commit_before>#include <assimp_converter.hpp>

#include <sigma/graphics/static_mesh.hpp>
#include <sigma/util/filesystem.hpp>
#include <sigma/util/json_conversion.hpp>

#include <assimp/Importer.hpp>
#include <assimp/postprocess.h>
#include <assimp/scene.h>

#include <json/json.h>

#include <glm/gtc/quaternion.hpp>
#include <glm/gtx/rotate_vector.hpp>

#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/replace.hpp>

#include <iostream>
#include <unordered_map>

namespace sigma {

struct converter {
    virtual glm::vec3 convert_color(aiColor3D c)
    {
        return glm::vec3(c.r, c.g, c.b);
    }

    virtual glm::vec3 convert_3d(aiVector3D v)
    {
        return { v.x, v.y, v.z };
    }

    virtual glm::quat convert_3d(aiQuaternion q)
    {
        return glm::quat(q.w, q.x, q.y, q.z);
    }

    virtual glm::vec2 convert_2d(aiVector3D v)
    {
        return glm::vec2(v.x, v.y);
    }
};

struct blender_converter : public converter {
    virtual glm::vec3 convert_color(aiColor3D c) override
    {
        return glm::vec3(c.r, c.g, c.b);
    }

    virtual glm::vec3 convert_3d(aiVector3D v) override
    {
        return { v.x, v.z, -v.y };
    }

    virtual glm::quat convert_3d(aiQuaternion q) override
    {
        return glm::quat(q.w, q.x, q.z, -q.y);
    }

    virtual glm::vec2 convert_2d(aiVector3D v) override
    {
        return glm::vec2(v.x, v.y);
    }
};

assimp_converter::assimp_converter(boost::filesystem::path package_root, boost::filesystem::path source_file)
    : root_directroy_(filesystem::make_relative(package_root, source_file).parent_path())
    , source_file_(source_file)
    , importer_(std::make_unique<Assimp::Importer>())
{
    auto filename = source_file_.string();

    if (boost::algorithm::ends_with(filename, ".blend"))
        converter_ = std::make_unique<blender_converter>();
    else
        converter_ = std::make_unique<converter>();

    const aiScene* scene = importer_->ReadFile(filename.c_str(),
        aiProcess_CalcTangentSpace
            | aiProcess_JoinIdenticalVertices
            | aiProcess_Triangulate
            | aiProcess_LimitBoneWeights
            | aiProcess_ValidateDataStructure
            | aiProcess_ImproveCacheLocality
            //| aiProcess_RemoveRedundantMaterials
            | aiProcess_SortByPType
            | aiProcess_FindDegenerates
            | aiProcess_FindInvalidData
            // | aiProcess_GenUVCoords
            | aiProcess_FindInstances
            | aiProcess_FlipUVs
            | aiProcess_CalcTangentSpace
        // | aiProcess_MakeLeftHanded
        // | aiProcess_RemoveComponent
        // | aiProcess_GenNormals
        // | aiProcess_GenSmoothNormals
        // | aiProcess_SplitLargeMeshes
        // | aiProcess_PreTransformVertices
        // | aiProcess_FixInfacingNormals
        // | aiProcess_TransformUVCoords
        // | aiProcess_ConvertToLeftHanded
        // | aiProcess_OptimizeMeshes
        // | aiProcess_OptimizeGraph
        // | aiProcess_FlipWindingOrder
        // | aiProcess_SplitByBoneCount
        // | aiProcess_Debone
        );
    if (scene == nullptr) {
        // TODO error handling
        std::cout << importer_->GetErrorString() << '\n';
        return;
    }

    for (unsigned int i = 0; i < scene->mNumMaterials; ++i) {
        if (is_source(scene->mMaterials[i])) {
            std::string name = get_name(scene->mMaterials[i]);
            material_names_.insert(name);
        }
    }

    for (unsigned int i = 0; i < scene->mNumMeshes; ++i) {
        std::string name = get_name(scene->mMeshes[i]);
        // if (!scene->mMeshes[i]->HasBones())
        static_mesh_names_.insert(name);
        // else
        //     static_mesh_names_.erase(name);
    }

    // TODO recursive
    for (unsigned int i = 0; i < scene->mRootNode->mNumChildren; ++i) {
        object_names_.insert(get_name(scene->mRootNode->mChildren[i]));
    }

    // TODO skeletal mesehes.
    // TODO matericonvertals
    // TODO the whole scene.
    // TODO animations.
    // TODO textures?
}

assimp_converter::~assimp_converter() {}

const std::set<std::string>& assimp_converter::material_names() const
{
    return material_names_;
}

const std::set<std::string>& assimp_converter::static_mesh_names() const
{
    return static_mesh_names_;
}

const std::set<std::string>& assimp_converter::scene_object_names() const
{
    return object_names_;
}

void assimp_converter::convert_material(std::string name, Json::Value& material) const
{
    const aiScene* aiScene = importer_->GetScene();

    std::unordered_map<aiTextureType, std::string> texture_type_map = {
        { aiTextureType_DIFFUSE, "basecolor_map" },
        { aiTextureType_SPECULAR, "roughness_map" },
        { aiTextureType_AMBIENT, "metallic_map" },
        { aiTextureType_EMISSIVE, "emissive_map" },
        { aiTextureType_HEIGHT, "normal_map" },
        { aiTextureType_NORMALS, "normal_map" },
        { aiTextureType_SHININESS, "roughness_map" },
        { aiTextureType_OPACITY, "opacity_map" },
        { aiTextureType_DISPLACEMENT, "displacement_map" },
        { aiTextureType_LIGHTMAP, "lightmap_map" },
        { aiTextureType_REFLECTION, "reflection_map" }
    };

    material["vertex"] = "default";
    material["fragment"] = "default_basic";
    for (unsigned int i = 0; i < aiScene->mNumMaterials; ++i) {
        auto aimat = aiScene->mMaterials[i];
        if (get_name(aimat) != name)
            continue;

        aiColor3D color;
        if (AI_SUCCESS == aimat->Get(AI_MATKEY_COLOR_DIFFUSE, color))
            material["basecolor"] = json::to_json(converter_->convert_color(color));
        if (AI_SUCCESS == aimat->Get(AI_MATKEY_COLOR_SPECULAR, color))
            material["roughness"] = converter_->convert_color(color).x;
        if (AI_SUCCESS == aimat->Get(AI_MATKEY_COLOR_AMBIENT, color))
            material["metalness"] = converter_->convert_color(color).x;
        if (AI_SUCCESS == aimat->Get(AI_MATKEY_COLOR_EMISSIVE, color))
            material["emissive"] = json::to_json(converter_->convert_color(color));
        if (AI_SUCCESS == aimat->Get(AI_MATKEY_COLOR_TRANSPARENT, color))
            material["transparent"] = converter_->convert_color(color).x;
        if (AI_SUCCESS == aimat->Get(AI_MATKEY_COLOR_REFLECTIVE, color))
            material["reflective"] = converter_->convert_color(color).x;

        for (auto texture_type : texture_type_map) {
            if (aimat->GetTextureCount(texture_type.first) > 0) {
                material["textures"][texture_type.second] = get_name(aimat, texture_type.first);
                material["fragment"] = "default";
            }
        }
        return;
    }
}

void assimp_converter::convert_static_mesh(std::string name, graphics::static_mesh_data& mesh) const
{
    const aiScene* aiScene = importer_->GetScene();

    for (unsigned int i = 0; i < aiScene->mNumMeshes; ++i) {
        const aiMesh* aimesh = aiScene->mMeshes[i];
        if (name != get_name(aimesh))
            continue;

        std::vector<sigma::graphics::static_mesh_data::vertex> submesh_vertices(aimesh->mNumVertices);
        for (unsigned int j = 0; j < aimesh->mNumVertices; ++j) {
            auto pos = aimesh->mVertices[j];
            submesh_vertices[j].position = converter_->convert_3d(pos);

            if (aimesh->HasNormals()) {
                auto nor = aimesh->mNormals[j];
                submesh_vertices[j].normal = converter_->convert_3d(nor);
            }

            if (aimesh->HasTangentsAndBitangents()) {
                auto tan = aimesh->mTangents[j];
                submesh_vertices[j].tangent = converter_->convert_3d(tan);
            }
            if (aimesh->HasTextureCoords(0)) {
                auto tex = converter_->convert_2d(aimesh->mTextureCoords[0][j]);
                submesh_vertices[j].texcoord = tex;
            }
        }

        std::vector<sigma::graphics::static_mesh_data::triangle> submesh_triangles(aimesh->mNumFaces);
        for (unsigned int j = 0; j < aimesh->mNumFaces; ++j) {
            aiFace f = aimesh->mFaces[j];
            for (unsigned int k = 0; k < 3; ++k)
                submesh_triangles[j][k] = f.mIndices[k] + static_cast<unsigned int>(mesh.vertices.size());
        }

        std::string material_name = get_name(aiScene->mMaterials[aimesh->mMaterialIndex]);

        // TODO warn if material slot has been used.
        mesh.materials[resource::identifier{ "material", material_name }.name()] = std::make_pair(mesh.triangles.size(), aimesh->mNumFaces);

        mesh.vertices.reserve(mesh.vertices.size() + aimesh->mNumVertices);
        mesh.vertices.insert(mesh.vertices.end(), submesh_vertices.begin(), submesh_vertices.end());

        mesh.triangles.reserve(mesh.triangles.size() + submesh_triangles.size());
        mesh.triangles.insert(mesh.triangles.end(), submesh_triangles.begin(), submesh_triangles.end());
    }
    mesh.vertices.shrink_to_fit();
    mesh.triangles.shrink_to_fit();
}

void assimp_converter::convert_object(std::string name, Json::Value& entity) const
{
    const aiScene* aiScene = importer_->GetScene();
    const aiNode* ainode = aiScene->mRootNode->FindNode(name.c_str());
    aiVector3D aiposition;
    aiQuaternion airotation;
    aiVector3D aiscale;
    ainode->mTransformation.Decompose(aiscale, airotation, aiposition);
    aiscale.y *= -1;

    entity["sigma::transform"]["position"] = json::to_json(converter_->convert_3d(aiposition));
    entity["sigma::transform"]["rotation"] = json::to_json(glm::degrees(glm::eulerAngles(converter_->convert_3d(airotation))));
    entity["sigma::transform"]["scale"] = json::to_json(converter_->convert_3d(aiscale));

    if (ainode->mNumMeshes > 0) {
        // TODO warn if more than one mesh per object
        const aiMesh* aimesh = aiScene->mMeshes[ainode->mMeshes[0]];
        sigma::resource::identifier meshid("static_mesh", source_file_, get_name(aimesh));
        entity["sigma::graphics::static_mesh"] = meshid.nice_name();
    }

    for (unsigned int i = 0; i < aiScene->mNumLights; ++i) {
        const aiLight* ailight = aiScene->mLights[i];
        if (name == ailight->mName.C_Str()) {
            auto color = converter_->convert_color(ailight->mColorDiffuse);
            float intensity = color[0]; // TOOD check intensity and color
            color /= intensity;

            switch (ailight->mType) {
            case aiLightSource_POINT:
                entity["sigma::graphics::point_light"]["color"] = json::to_json(color);
                entity["sigma::graphics::point_light"]["intensity"] = json::to_json(intensity);
                break;
            case aiLightSource_DIRECTIONAL:
                entity["sigma::graphics::directional_light"]["color"] = json::to_json(color);
                entity["sigma::graphics::directional_light"]["intensity"] = json::to_json(intensity);
                break;
            case aiLightSource_SPOT:
                entity["sigma::graphics::spot_light"]["color"] = json::to_json(color);
                entity["sigma::graphics::spot_light"]["intensity"] = json::to_json(intensity);
                entity["sigam::graphics::spot_light"]["cutoff"] = json::to_json(ailight->mAngleOuterCone);
                break;
            default: // TODO more lights
                break;
            }
            break;
        }
    }
}

std::string assimp_converter::get_name(const aiMaterial* mat, int texture_type) const
{
    aiString texture;
    mat->GetTexture((aiTextureType)texture_type, 0, &texture);
    std::string name = texture.C_Str();
    boost::algorithm::replace_all(name, "\\", "/");

    boost::filesystem::path texture_path = root_directroy_ / name;
    if (boost::starts_with(name, "//"))
        texture_path = root_directroy_ / name.substr(2);
    else if (name[0] == '/')
        texture_path = name.substr(1);
    else if (!boost::filesystem::exists(texture_path))
        texture_path = name;

    return texture_path.replace_extension("").string();
}

bool assimp_converter::is_source(const aiMaterial* mat) const
{
    aiString matName;
    mat->Get(AI_MATKEY_NAME, matName);
    std::string name = matName.C_Str();
    return name[0] != '/' && name != "DefaultMaterial";
}

std::string assimp_converter::get_name(const aiMaterial* mat) const
{
    aiString matName;
    mat->Get(AI_MATKEY_NAME, matName);
    std::string name = matName.C_Str();
    if (name == "DefaultMaterial")
        return "default";

    if (boost::starts_with(name, "//"))
        return (root_directroy_ / name.substr(2))
            .string();
    if (name[0] == '/')
        return name.substr(1);
    return (root_directroy_ / name).string();
}

std::string assimp_converter::get_name(const aiMesh* mesh) const
{
    std::string name = mesh->mName.C_Str();
    if (name == "")
        return "unnamed";
    return name;
}

std::string assimp_converter::get_name(const aiNode* node) const
{
    std::string name = node->mName.C_Str();
    if (name == "")
        return "unnamed";
    return name;
}
}
<commit_msg>Fixed a few typos.<commit_after>#include <assimp_converter.hpp>

#include <sigma/graphics/static_mesh.hpp>
#include <sigma/util/filesystem.hpp>
#include <sigma/util/json_conversion.hpp>

#include <assimp/Importer.hpp>
#include <assimp/postprocess.h>
#include <assimp/scene.h>

#include <json/json.h>

#include <glm/gtc/quaternion.hpp>
#include <glm/gtx/rotate_vector.hpp>

#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/replace.hpp>

#include <unordered_map>

namespace sigma {

struct converter {
    virtual glm::vec3 convert_color(aiColor3D c)
    {
        return glm::vec3(c.r, c.g, c.b);
    }

    virtual glm::vec3 convert_3d(aiVector3D v)
    {
        return { v.x, v.y, v.z };
    }

    virtual glm::quat convert_3d(aiQuaternion q)
    {
        return glm::quat(q.w, q.x, q.y, q.z);
    }

    virtual glm::vec2 convert_2d(aiVector3D v)
    {
        return glm::vec2(v.x, v.y);
    }
};

struct blender_converter : public converter {
    virtual glm::vec3 convert_color(aiColor3D c) override
    {
        return glm::vec3(c.r, c.g, c.b);
    }

    virtual glm::vec3 convert_3d(aiVector3D v) override
    {
        return { v.x, v.z, -v.y };
    }

    virtual glm::quat convert_3d(aiQuaternion q) override
    {
        return glm::quat(q.w, q.x, q.z, -q.y);
    }

    virtual glm::vec2 convert_2d(aiVector3D v) override
    {
        return glm::vec2(v.x, v.y);
    }
};

assimp_converter::assimp_converter(boost::filesystem::path package_root, boost::filesystem::path source_file)
    : root_directroy_(filesystem::make_relative(package_root, source_file).parent_path())
    , source_file_(source_file)
    , importer_(std::make_unique<Assimp::Importer>())
{
    auto filename = source_file_.string();

    if (boost::algorithm::ends_with(filename, ".blend"))
        converter_ = std::make_unique<blender_converter>();
    else
        converter_ = std::make_unique<converter>();

    const aiScene* scene = importer_->ReadFile(filename.c_str(),
        aiProcess_CalcTangentSpace
            | aiProcess_JoinIdenticalVertices
            | aiProcess_Triangulate
            | aiProcess_LimitBoneWeights
            | aiProcess_ValidateDataStructure
            | aiProcess_ImproveCacheLocality
            //| aiProcess_RemoveRedundantMaterials
            | aiProcess_SortByPType
            | aiProcess_FindDegenerates
            | aiProcess_FindInvalidData
            // | aiProcess_GenUVCoords
            | aiProcess_FindInstances
            | aiProcess_FlipUVs
            | aiProcess_CalcTangentSpace
        // | aiProcess_MakeLeftHanded
        // | aiProcess_RemoveComponent
        // | aiProcess_GenNormals
        // | aiProcess_GenSmoothNormals
        // | aiProcess_SplitLargeMeshes
        // | aiProcess_PreTransformVertices
        // | aiProcess_FixInfacingNormals
        // | aiProcess_TransformUVCoords
        // | aiProcess_ConvertToLeftHanded
        // | aiProcess_OptimizeMeshes
        // | aiProcess_OptimizeGraph
        // | aiProcess_FlipWindingOrder
        // | aiProcess_SplitByBoneCount
        // | aiProcess_Debone
        );
    if (scene == nullptr) {
        // TODO error handling
        std::cout << importer_->GetErrorString() << '\n';
        return;
    }

    for (unsigned int i = 0; i < scene->mNumMaterials; ++i) {
        if (is_source(scene->mMaterials[i])) {
            std::string name = get_name(scene->mMaterials[i]);
            material_names_.insert(name);
        }
    }

    for (unsigned int i = 0; i < scene->mNumMeshes; ++i) {
        std::string name = get_name(scene->mMeshes[i]);
        // if (!scene->mMeshes[i]->HasBones())
        static_mesh_names_.insert(name);
        // else
        //     static_mesh_names_.erase(name);
    }

    // TODO recursive
    for (unsigned int i = 0; i < scene->mRootNode->mNumChildren; ++i) {
        object_names_.insert(get_name(scene->mRootNode->mChildren[i]));
    }

    // TODO skeletal mesehes.
    // TODO matericonvertals
    // TODO the whole scene.
    // TODO animations.
    // TODO textures?
}

assimp_converter::~assimp_converter() {}

const std::set<std::string>& assimp_converter::material_names() const
{
    return material_names_;
}

const std::set<std::string>& assimp_converter::static_mesh_names() const
{
    return static_mesh_names_;
}

const std::set<std::string>& assimp_converter::scene_object_names() const
{
    return object_names_;
}

void assimp_converter::convert_material(std::string name, Json::Value& material) const
{
    const aiScene* aiScene = importer_->GetScene();

    std::unordered_map<aiTextureType, std::string> texture_type_map = {
        { aiTextureType_DIFFUSE, "basecolor_map" },
        { aiTextureType_SPECULAR, "roughness_map" },
        { aiTextureType_AMBIENT, "metallic_map" },
        { aiTextureType_EMISSIVE, "emissive_map" },
        { aiTextureType_HEIGHT, "normal_map" },
        { aiTextureType_NORMALS, "normal_map" },
        { aiTextureType_SHININESS, "roughness_map" },
        { aiTextureType_OPACITY, "opacity_map" },
        { aiTextureType_DISPLACEMENT, "displacement_map" },
        { aiTextureType_LIGHTMAP, "lightmap_map" },
        { aiTextureType_REFLECTION, "reflection_map" }
    };

    material["vertex"] = "default";
    material["fragment"] = "default_basic";
    for (unsigned int i = 0; i < aiScene->mNumMaterials; ++i) {
        auto aimat = aiScene->mMaterials[i];
        if (get_name(aimat) != name)
            continue;

        aiColor3D color;
        if (AI_SUCCESS == aimat->Get(AI_MATKEY_COLOR_DIFFUSE, color))
            material["basecolor"] = json::to_json(converter_->convert_color(color));
        if (AI_SUCCESS == aimat->Get(AI_MATKEY_COLOR_SPECULAR, color))
            material["roughness"] = converter_->convert_color(color).x;
        if (AI_SUCCESS == aimat->Get(AI_MATKEY_COLOR_AMBIENT, color))
            material["metalness"] = converter_->convert_color(color).x;
        if (AI_SUCCESS == aimat->Get(AI_MATKEY_COLOR_EMISSIVE, color))
            material["emissive"] = json::to_json(converter_->convert_color(color));
        if (AI_SUCCESS == aimat->Get(AI_MATKEY_COLOR_TRANSPARENT, color))
            material["transparent"] = converter_->convert_color(color).x;
        if (AI_SUCCESS == aimat->Get(AI_MATKEY_COLOR_REFLECTIVE, color))
            material["reflective"] = converter_->convert_color(color).x;

        for (auto texture_type : texture_type_map) {
            if (aimat->GetTextureCount(texture_type.first) > 0) {
                material["textures"][texture_type.second] = get_name(aimat, texture_type.first);
                material["fragment"] = "default";
            }
        }
        return;
    }
}

void assimp_converter::convert_static_mesh(std::string name, graphics::static_mesh_data& mesh) const
{
    const aiScene* aiScene = importer_->GetScene();

    for (unsigned int i = 0; i < aiScene->mNumMeshes; ++i) {
        const aiMesh* aimesh = aiScene->mMeshes[i];
        if (name != get_name(aimesh))
            continue;

        std::vector<sigma::graphics::static_mesh_data::vertex> submesh_vertices(aimesh->mNumVertices);
        for (unsigned int j = 0; j < aimesh->mNumVertices; ++j) {
            auto pos = aimesh->mVertices[j];
            submesh_vertices[j].position = converter_->convert_3d(pos);

            if (aimesh->HasNormals()) {
                auto nor = aimesh->mNormals[j];
                submesh_vertices[j].normal = converter_->convert_3d(nor);
            }

            if (aimesh->HasTangentsAndBitangents()) {
                auto tan = aimesh->mTangents[j];
                submesh_vertices[j].tangent = converter_->convert_3d(tan);
            }
            if (aimesh->HasTextureCoords(0)) {
                auto tex = converter_->convert_2d(aimesh->mTextureCoords[0][j]);
                submesh_vertices[j].texcoord = tex;
            }
        }

        std::vector<sigma::graphics::static_mesh_data::triangle> submesh_triangles(aimesh->mNumFaces);
        for (unsigned int j = 0; j < aimesh->mNumFaces; ++j) {
            aiFace f = aimesh->mFaces[j];
            for (unsigned int k = 0; k < 3; ++k)
                submesh_triangles[j][k] = f.mIndices[k] + static_cast<unsigned int>(mesh.vertices.size());
        }

        std::string material_name = get_name(aiScene->mMaterials[aimesh->mMaterialIndex]);

        // TODO warn if material slot has been used.
        mesh.materials[resource::identifier{ "material", material_name }.name()] = std::make_pair(mesh.triangles.size(), aimesh->mNumFaces);

        mesh.vertices.reserve(mesh.vertices.size() + aimesh->mNumVertices);
        mesh.vertices.insert(mesh.vertices.end(), submesh_vertices.begin(), submesh_vertices.end());

        mesh.triangles.reserve(mesh.triangles.size() + submesh_triangles.size());
        mesh.triangles.insert(mesh.triangles.end(), submesh_triangles.begin(), submesh_triangles.end());
    }
    mesh.vertices.shrink_to_fit();
    mesh.triangles.shrink_to_fit();
}

void assimp_converter::convert_object(std::string name, Json::Value& entity) const
{
    const aiScene* aiScene = importer_->GetScene();
    const aiNode* ainode = aiScene->mRootNode->FindNode(name.c_str());
    aiVector3D aiposition;
    aiQuaternion airotation;
    aiVector3D aiscale;
    ainode->mTransformation.Decompose(aiscale, airotation, aiposition);
    aiscale.y *= -1;

    entity["sigma::transform"]["position"] = json::to_json(converter_->convert_3d(aiposition));
    entity["sigma::transform"]["rotation"] = json::to_json(glm::degrees(glm::eulerAngles(converter_->convert_3d(airotation))));
    entity["sigma::transform"]["scale"] = json::to_json(converter_->convert_3d(aiscale));

    if (ainode->mNumMeshes > 0) {
        // TODO warn if more than one mesh per object
        const aiMesh* aimesh = aiScene->mMeshes[ainode->mMeshes[0]];
        sigma::resource::identifier meshid("static_mesh", source_file_, get_name(aimesh));
        entity["sigma::graphics::static_mesh"] = meshid.nice_name();
    }

    for (unsigned int i = 0; i < aiScene->mNumLights; ++i) {
        const aiLight* ailight = aiScene->mLights[i];
        if (name == ailight->mName.C_Str()) {
            auto color = converter_->convert_color(ailight->mColorDiffuse);
            float intensity = color[0]; // TOOD check intensity and color
            color /= intensity;

            switch (ailight->mType) {
            case aiLightSource_POINT:
                entity["sigma::graphics::point_light"]["color"] = json::to_json(color);
                entity["sigma::graphics::point_light"]["intensity"] = json::to_json(intensity);
                break;
            case aiLightSource_DIRECTIONAL:
                entity["sigma::graphics::directional_light"]["color"] = json::to_json(color);
                entity["sigma::graphics::directional_light"]["intensity"] = json::to_json(intensity);
                break;
            case aiLightSource_SPOT:
                entity["sigma::graphics::spot_light"]["color"] = json::to_json(color);
                entity["sigma::graphics::spot_light"]["intensity"] = json::to_json(intensity);
                entity["sigam::graphics::spot_light"]["cutoff"] = json::to_json(ailight->mAngleOuterCone);
                break;
            default: // TODO more lights
                break;
            }
            break;
        }
    }
}

std::string assimp_converter::get_name(const aiMaterial* mat, int texture_type) const
{
    aiString texture;
    mat->GetTexture((aiTextureType)texture_type, 0, &texture);
    std::string name = texture.C_Str();
    boost::algorithm::replace_all(name, "\\", "/");

    boost::filesystem::path texture_path = root_directroy_ / name;
    if (boost::starts_with(name, "//"))
        texture_path = root_directroy_ / name.substr(2);
    else if (name[0] == '/')
        texture_path = name.substr(1);
    else if (!boost::filesystem::exists(texture_path))
        texture_path = name;

    return texture_path.replace_extension("").string();
}

bool assimp_converter::is_source(const aiMaterial* mat) const
{
    aiString matName;
    mat->Get(AI_MATKEY_NAME, matName);
    std::string name = matName.C_Str();
    return name[0] != '/' && name != "DefaultMaterial";
}

std::string assimp_converter::get_name(const aiMaterial* mat) const
{
    aiString matName;
    mat->Get(AI_MATKEY_NAME, matName);
    std::string name = matName.C_Str();
    if (name == "DefaultMaterial")
        return "default";

    if (boost::starts_with(name, "//"))
        return (root_directroy_ / name.substr(2)).string();
    if (name[0] == '/')
        return name.substr(1);
    return (root_directroy_ / name).string();
}

std::string assimp_converter::get_name(const aiMesh* mesh) const
{
    std::string name = mesh->mName.C_Str();
    if (name == "")
        return "unnamed";
    return name;
}

std::string assimp_converter::get_name(const aiNode* node) const
{
    std::string name = node->mName.C_Str();
    if (name == "")
        return "unnamed";
    return name;
}
}
<|endoftext|>


<commit_before>#include "stdint.h"
struct rs_context{ int x; };
struct rs_camera{ int x; };
struct rs_stream_config{ int x; };
/*struct rs_frame {}; */
struct rs_error{ int x; };

struct rs_intrinsics
{
	int image_size[2];          /* width and height of the image in pixels */
	float focal_length[2];      /* focal length of the image plane, as a multiple of pixel width and height */
	float principal_point[2];   /* coordinates of the principal point of the image, as a pixel offset from the top left */
	float distortion_coeff[5];  /* distortion coefficients */
	int distortion_model;		/* distortion model */
};

struct rs_extrinsics
{
	float rotation[9];
	float translation[3];
};

struct rs_context *			rs_create_context			(int api_version, struct rs_error ** error){ return 0; };
void						rs_free_context				(struct rs_context * context, struct rs_error ** err){};

int							rs_get_camera_count			(struct rs_context * context, struct rs_error **err){ return 0; };
struct rs_camera *			rs_get_camera				(struct rs_context * context, int index, struct rs_error **err){ return 0; };

void						rs_get_stream_cfg_count		(struct rs_camera * camera, int stream_type, struct rs_error **err){};
struct rs_stream_config *	rs_get_stream_cfg_by_index	(struct rs_camera * camera, int stream_type, int index, struct rs_error **err){ return 0; };
int							rs_get_stream_cfg_property_i(struct rs_stream_config * cfg, int prop, struct rs_error ** error){ return 0; };
int							rs_get_stream_cfg_property_f(struct rs_stream_config * cfg, float prop, struct rs_error ** error){ return 0; };
void						rs_set_stream_cfg_property_i(struct rs_stream_config * cfg, int prop, int value, struct rs_error ** error){  };
void						rs_set_stream_cfg_property_f(struct rs_stream_config * cfg, float prop, float value, struct rs_error ** error){  };
void						rs_free_stream_cfg			(struct rs_stream_config * error){};

void						rs_enable_stream_from_cfg	(struct rs_camera * camera, int stream_type, struct rs_stream_config * cfg, struct rs_error **err){};
struct rs_stream_config *	rs_get_current_stream_cfg	(struct rs_camera * camera, int stream_type, struct rs_error ** err){ return 0; };

/*convenience functions. Perform best-effort selection of a valid configuration and return result of rs_get_current_stream_cfg*/
struct rs_stream_config *	rs_enable_stream(struct rs_camera * camera, int stream_type, int width, int height, int fps, int format, struct rs_error **err){ return 0; };
struct rs_stream_config *	rs_enable_stream(struct rs_camera * camera, int stream_type, int width, int height, int fps, int format_depth, int format_intensity, struct rs_error **err){ return 0; };

/*alternative would be to create/destroy a new opaque type (rs_stream) */
void						rs_start_streaming			(struct rs_camera * camera, struct rs_error **err){};
void						rs_stop_streaming			(struct rs_camera * camera, struct rs_error **err){};

/*alternative could be to create/destroy a new opaque type (rs_frame)*/
void						rs_wait_one_update			(struct rs_camera * camera, int stream_type, int blocking_call, struct rs_error ** error){ };
void						rs_wait_all_update			(struct rs_camera * camera, int stream_type, int blocking_call, struct rs_error ** error){ };

typedef void(rs_frame_callback_t)(struct rs_camera *camera, void *user_ptr);
void						rs_register_wait_one_update	(struct rs_camera * camera, int stream_type, rs_frame_callback_t *cb, void *user_ptr, struct rs_error ** error){ };
void						rs_register_wait_all_update	(struct rs_camera * camera, int stream_type, rs_frame_callback_t *cb, void *user_ptr, struct rs_error ** error){ };

void *						rs_get_data					(struct rs_camera * camera, int stream_type, struct rs_error ** error){ return 0; };

/*alternatives for async operation should go here set stream callback for all/one and given*/
int 						rs_is_streaming				(struct rs_camera * camera, struct rs_error ** error){ return 0; };
int							rs_get_camera_index			(struct rs_camera * camera, struct rs_error ** error){ return 0; };
uint32_t					rs_get_frame_count			(struct rs_camera * camera, struct rs_error ** error){ return 0; };
int							rs_get_stream_property_i	(struct rs_camera * camera, int stream_type, int prop, struct rs_error ** error){ return 0; };
float						rs_get_stream_property_f	(struct rs_camera * camera, int stream_type, int prop, struct rs_error ** error){ return 0; };
int							rs_get_s2s_property_i		(struct rs_camera * camera, int stream_type_from, int stream_type_to, int prop, struct rs_error ** error){ return 0; };
float						rs_get_s2s_property_f		(struct rs_camera * camera, int stream_type_from, int stream_type_to, int prop, struct rs_error ** error){ return 0; };
void						rs_set_stream_property_i	(struct rs_camera * camera, int stream_type, int prop, int value, struct rs_error ** error){ };
void						rs_set_stream_property_f	(struct rs_camera * camera, int stream_type, int prop, float value, struct rs_error ** error){ };

/*convenience functions. Image dimensions and camera model calibration information */
void						rs_get_stream_intrinsics	(struct rs_camera * camera, int stream_type, struct rs_intrinsics * intrin, struct rs_error ** error);
void						rs_get_stream_extrinsics	(struct rs_camera * camera, int stream_type_from, int stream_type_to, struct rs_extrinsics * extrin, struct rs_error ** error);

const char *				rs_get_failed_function		(struct rs_error * error){ return 0; };
const char *				rs_get_error_message		(struct rs_error * error){ return 0; };
void						rs_free_error				(struct rs_error * error){};
#define RS_API_VERSION 0
#define NULL 0

/*define vs. enum?*/
/*@tofix -- DS also supports disparity mode and changing the disparity to depth multiplier*/
#define RS_FRAME_FORMAT_UNKNOWN			0
#define RS_FRAME_FORMAT_ANY				0 /* Any supported format*/
#define RS_FRAME_FORMAT_UNCOMPRESSED	1
#define RS_FRAME_FORMAT_COMPRESSED		2
#define RS_FRAME_FORMAT_YUYV			3 /* YUYV/YUV2/YUV422: YUV encoding with one luminance value per pixel and one UV (chrominance) pair for every two pixels.*/
#define RS_FRAME_FORMAT_UYVY			4
#define RS_FRAME_FORMAT_Y12I			5
#define RS_FRAME_FORMAT_Y16				6
#define RS_FRAME_FORMAT_Y8				7
#define RS_FRAME_FORMAT_Z16				8
#define RS_FRAME_FORMAT_RGB				9
#define RS_FRAME_FORMAT_BGR				10
#define RS_FRAME_FORMAT_MJPEG			11
#define RS_FRAME_FORMAT_GRAY8			12
#define RS_FRAME_FORMAT_BY8				13
#define RS_FRAME_FORMAT_INVI			14 /*IR*/
#define RS_FRAME_FORMAT_RELI			15 /*IR*/
#define RS_FRAME_FORMAT_INVR			16 /*Depth*/
#define RS_FRAME_FORMAT_INVZ			17 /*Depth*/
#define RS_FRAME_FORMAT_INRI			18 /*Depth (24 bit)*/

/* @tofix - this has an overloaded meaning for R200*/
/* Valid arguments for rsEnableStream/rsStartStream/rsStopStream/rsGetStreamProperty**/
#define RS_STREAM_DEPTH					1
#define RS_STREAM_L						2
#define RS_STREAM_R						4
#define RS_STREAM_COLOR					8

/* Valid Distortion Models*/
#define RS_DISTORTION_MODEL_NONE				0
#define RS_DISTORTION_MODEL_FORWARD_BROWN		1
#define RS_DISTORTION_MODEL_FORWARD_FITZGIBBON	2
#define RS_DISTORTION_MODEL_INVERSE_BROWN		3

/* Valid arguments to rsGetStreamProperty**/
/* Boolean-based properties*/
#define RS_IMAGE_ENABLED		0
#define RS_IMAGE_RECTIFIED		1
#define RS_IMAGE_CROPPED		2
/* Integer-based properties*/
#define RS_IMAGE_SIZE_X			3
#define RS_IMAGE_SIZE_Y			4
#define RS_DATA_FPS				5
#define RS_DATA_FORMAT			6
/* Floating-point properties*/
#define RS_FOCAL_LENGTH_X		7
#define RS_FOCAL_LENGTH_Y		8
#define RS_PRINCIPAL_POINT_X	9
#define RS_PRINCIPAL_POINT_Y	10
#define RS_LATEST_TIMESTAMP		11
#define RS_DISTORTION_MODEL		12
#define RS_DISTORTION_K1		13
#define RS_DISTORTION_K2		14
#define RS_DISTORTION_K3		15
#define RS_DISTORTION_K4		16
#define RS_DISTORTION_K5		17

/* Integer-based properties betweens streams*/
#define RS_SYNCHRONIZED			0

/* Floating-point properties between streams*/
#define RS_TRANSLATION_X		1
#define RS_TRANSLATION_Y		2
#define RS_TRANSLATION_Z		3
#define RS_ROTATION_XX			4
#define RS_ROTATION_XY			5
#define RS_ROTATION_XZ			6
#define RS_ROTATION_YX			7
#define RS_ROTATION_YY			8
#define RS_ROTATION_YZ			9
#define RS_ROTATION_ZX			10
#define RS_ROTATION_ZY			11
#define RS_ROTATION_ZZ			12
#define RS_SYNCHRONIZED_OFFSET	13

int test_main(int argc, char * argv[])
{
	struct rs_context * ctx;

	struct rs_camera * cam;

	struct rs_error * error;
	ctx = rs_create_context(RS_API_VERSION, &error);
	int cam_count = rs_get_camera_count(ctx, NULL);
	if (cam_count) {
		cam = rs_get_camera(ctx, 0, &error);
		struct rs_stream_config * z_cfg = rs_enable_stream(cam, RS_STREAM_DEPTH, 628, 469, 30, RS_FRAME_FORMAT_Z16, &error); /*should be a best-effort call.*/
		struct rs_stream_config * rgb_cfg = rs_enable_stream(cam, RS_STREAM_COLOR, 640, 480, 30, RS_FRAME_FORMAT_YUYV, &error);
		rs_start_streaming(cam, NULL);

		do {
			rs_wait_one_update(cam, RS_STREAM_DEPTH | RS_STREAM_COLOR, 1, &error);
			uint16_t * z = (uint16_t*)rs_get_data(cam, RS_STREAM_DEPTH, &error);
			uint8_t * rgb = (uint8_t*)rs_get_data(cam, RS_STREAM_COLOR, &error);
		} while (!error);
	}
	rs_free_context(ctx, &error);
	return 0;
}
<commit_msg>added stop streaming callback<commit_after>#include "stdint.h"
struct rs_context{ int x; };
struct rs_camera{ int x; };
struct rs_stream_config{ int x; };
/*struct rs_frame {}; */
struct rs_error{ int x; };

struct rs_intrinsics
{
	int image_size[2];          /* width and height of the image in pixels */
	float focal_length[2];      /* focal length of the image plane, as a multiple of pixel width and height */
	float principal_point[2];   /* coordinates of the principal point of the image, as a pixel offset from the top left */
	float distortion_coeff[5];  /* distortion coefficients */
	int distortion_model;		/* distortion model */
};

struct rs_extrinsics
{
	float rotation[9];
	float translation[3];
};

struct rs_context *			rs_create_context			(int api_version, struct rs_error ** error){ return 0; };
void						rs_free_context				(struct rs_context * context, struct rs_error ** err){};

int							rs_get_camera_count			(struct rs_context * context, struct rs_error **err){ return 0; };
struct rs_camera *			rs_get_camera				(struct rs_context * context, int index, struct rs_error **err){ return 0; };

void						rs_get_stream_cfg_count		(struct rs_camera * camera, int stream_type, struct rs_error **err){};
struct rs_stream_config *	rs_get_stream_cfg_by_index	(struct rs_camera * camera, int stream_type, int index, struct rs_error **err){ return 0; };
int							rs_get_stream_cfg_property_i(struct rs_stream_config * cfg, int prop, struct rs_error ** error){ return 0; };
int							rs_get_stream_cfg_property_f(struct rs_stream_config * cfg, float prop, struct rs_error ** error){ return 0; };
void						rs_set_stream_cfg_property_i(struct rs_stream_config * cfg, int prop, int value, struct rs_error ** error){  };
void						rs_set_stream_cfg_property_f(struct rs_stream_config * cfg, float prop, float value, struct rs_error ** error){  };
void						rs_free_stream_cfg			(struct rs_stream_config * error){};

void						rs_enable_stream_from_cfg	(struct rs_camera * camera, int stream_type, struct rs_stream_config * cfg, struct rs_error **err){};
struct rs_stream_config *	rs_get_current_stream_cfg	(struct rs_camera * camera, int stream_type, struct rs_error ** err){ return 0; };

/*convenience functions. Perform best-effort selection of a valid configuration and return result of rs_get_current_stream_cfg*/
struct rs_stream_config *	rs_enable_stream(struct rs_camera * camera, int stream_type, int width, int height, int fps, int format, struct rs_error **err){ return 0; };
struct rs_stream_config *	rs_enable_stream(struct rs_camera * camera, int stream_type, int width, int height, int fps, int format_depth, int format_intensity, struct rs_error **err){ return 0; };

/*alternative would be to create/destroy a new opaque type (rs_stream) */
void						rs_start_streaming			(struct rs_camera * camera, struct rs_error **err){};
void						rs_stop_streaming			(struct rs_camera * camera, struct rs_error **err){};

/*alternative could be to create/destroy a new opaque type (rs_frame)*/
void						rs_wait_one_update			(struct rs_camera * camera, int stream_type, int blocking_call, struct rs_error ** error){ };
void						rs_wait_all_update			(struct rs_camera * camera, int stream_type, int blocking_call, struct rs_error ** error){ };

typedef void(rs_frame_callback_t)(struct rs_camera *camera, void *user_ptr);
void						rs_register_wait_one_update	(struct rs_camera * camera, int stream_type, rs_frame_callback_t *cb, void *user_ptr, struct rs_error ** error){ };
void						rs_register_wait_all_update	(struct rs_camera * camera, int stream_type, rs_frame_callback_t *cb, void *user_ptr, struct rs_error ** error){ };
void						rs_register_streaming_error	(struct rs_camera * camera, int stream_type, rs_frame_callback_t *cb, void *user_ptr, struct rs_error ** error){ };

void *						rs_get_data					(struct rs_camera * camera, int stream_type, struct rs_error ** error){ return 0; };

/*alternatives for async operation should go here set stream callback for all/one and given*/
int 						rs_is_streaming				(struct rs_camera * camera, struct rs_error ** error){ return 0; };
int							rs_get_camera_index			(struct rs_camera * camera, struct rs_error ** error){ return 0; };
uint32_t					rs_get_frame_count			(struct rs_camera * camera, struct rs_error ** error){ return 0; };
int							rs_get_stream_property_i	(struct rs_camera * camera, int stream_type, int prop, struct rs_error ** error){ return 0; };
float						rs_get_stream_property_f	(struct rs_camera * camera, int stream_type, int prop, struct rs_error ** error){ return 0; };
int							rs_get_s2s_property_i		(struct rs_camera * camera, int stream_type_from, int stream_type_to, int prop, struct rs_error ** error){ return 0; };
float						rs_get_s2s_property_f		(struct rs_camera * camera, int stream_type_from, int stream_type_to, int prop, struct rs_error ** error){ return 0; };
void						rs_set_stream_property_i	(struct rs_camera * camera, int stream_type, int prop, int value, struct rs_error ** error){ };
void						rs_set_stream_property_f	(struct rs_camera * camera, int stream_type, int prop, float value, struct rs_error ** error){ };

/*convenience functions. Image dimensions and camera model calibration information */
void						rs_get_stream_intrinsics	(struct rs_camera * camera, int stream_type, struct rs_intrinsics * intrin, struct rs_error ** error);
void						rs_get_stream_extrinsics	(struct rs_camera * camera, int stream_type_from, int stream_type_to, struct rs_extrinsics * extrin, struct rs_error ** error);

const char *				rs_get_failed_function		(struct rs_error * error){ return 0; };
const char *				rs_get_error_message		(struct rs_error * error){ return 0; };
void						rs_free_error				(struct rs_error * error){};
#define RS_API_VERSION 0
#define NULL 0

/*define vs. enum?*/
/*@tofix -- DS also supports disparity mode and changing the disparity to depth multiplier*/
#define RS_FRAME_FORMAT_UNKNOWN			0
#define RS_FRAME_FORMAT_ANY				0 /* Any supported format*/
#define RS_FRAME_FORMAT_UNCOMPRESSED	1
#define RS_FRAME_FORMAT_COMPRESSED		2
#define RS_FRAME_FORMAT_YUYV			3 /* YUYV/YUV2/YUV422: YUV encoding with one luminance value per pixel and one UV (chrominance) pair for every two pixels.*/
#define RS_FRAME_FORMAT_UYVY			4
#define RS_FRAME_FORMAT_Y12I			5
#define RS_FRAME_FORMAT_Y16				6
#define RS_FRAME_FORMAT_Y8				7
#define RS_FRAME_FORMAT_Z16				8
#define RS_FRAME_FORMAT_RGB				9
#define RS_FRAME_FORMAT_BGR				10
#define RS_FRAME_FORMAT_MJPEG			11
#define RS_FRAME_FORMAT_GRAY8			12
#define RS_FRAME_FORMAT_BY8				13
#define RS_FRAME_FORMAT_INVI			14 /*IR*/
#define RS_FRAME_FORMAT_RELI			15 /*IR*/
#define RS_FRAME_FORMAT_INVR			16 /*Depth*/
#define RS_FRAME_FORMAT_INVZ			17 /*Depth*/
#define RS_FRAME_FORMAT_INRI			18 /*Depth (24 bit)*/

/* @tofix - this has an overloaded meaning for R200*/
/* Valid arguments for rsEnableStream/rsStartStream/rsStopStream/rsGetStreamProperty**/
#define RS_STREAM_DEPTH					1
#define RS_STREAM_L						2
#define RS_STREAM_R						4
#define RS_STREAM_COLOR					8

/* Valid Distortion Models*/
#define RS_DISTORTION_MODEL_NONE				0
#define RS_DISTORTION_MODEL_FORWARD_BROWN		1
#define RS_DISTORTION_MODEL_FORWARD_FITZGIBBON	2
#define RS_DISTORTION_MODEL_INVERSE_BROWN		3

/* Valid arguments to rsGetStreamProperty**/
/* Boolean-based properties*/
#define RS_IMAGE_ENABLED		0
#define RS_IMAGE_RECTIFIED		1
#define RS_IMAGE_CROPPED		2
/* Integer-based properties*/
#define RS_IMAGE_SIZE_X			3
#define RS_IMAGE_SIZE_Y			4
#define RS_DATA_FPS				5
#define RS_DATA_FORMAT			6
/* Floating-point properties*/
#define RS_FOCAL_LENGTH_X		7
#define RS_FOCAL_LENGTH_Y		8
#define RS_PRINCIPAL_POINT_X	9
#define RS_PRINCIPAL_POINT_Y	10
#define RS_LATEST_TIMESTAMP		11
#define RS_DISTORTION_MODEL		12
#define RS_DISTORTION_K1		13
#define RS_DISTORTION_K2		14
#define RS_DISTORTION_K3		15
#define RS_DISTORTION_K4		16
#define RS_DISTORTION_K5		17

/* Integer-based properties betweens streams*/
#define RS_SYNCHRONIZED			0

/* Floating-point properties between streams*/
#define RS_TRANSLATION_X		1
#define RS_TRANSLATION_Y		2
#define RS_TRANSLATION_Z		3
#define RS_ROTATION_XX			4
#define RS_ROTATION_XY			5
#define RS_ROTATION_XZ			6
#define RS_ROTATION_YX			7
#define RS_ROTATION_YY			8
#define RS_ROTATION_YZ			9
#define RS_ROTATION_ZX			10
#define RS_ROTATION_ZY			11
#define RS_ROTATION_ZZ			12
#define RS_SYNCHRONIZED_OFFSET	13

int test_main(int argc, char * argv[])
{
	struct rs_context * ctx;

	struct rs_camera * cam;

	struct rs_error * error;
	ctx = rs_create_context(RS_API_VERSION, &error);
	int cam_count = rs_get_camera_count(ctx, NULL);
	if (cam_count) {
		cam = rs_get_camera(ctx, 0, &error);
		struct rs_stream_config * z_cfg = rs_enable_stream(cam, RS_STREAM_DEPTH, 628, 469, 30, RS_FRAME_FORMAT_Z16, &error); /*should be a best-effort call.*/
		struct rs_stream_config * rgb_cfg = rs_enable_stream(cam, RS_STREAM_COLOR, 640, 480, 30, RS_FRAME_FORMAT_YUYV, &error);
		rs_start_streaming(cam, NULL);

		do {
			rs_wait_one_update(cam, RS_STREAM_DEPTH | RS_STREAM_COLOR, 1, &error);
			uint16_t * z = (uint16_t*)rs_get_data(cam, RS_STREAM_DEPTH, &error);
			uint8_t * rgb = (uint8_t*)rs_get_data(cam, RS_STREAM_COLOR, &error);
		} while (!error);
	}
	rs_free_context(ctx, &error);
	return 0;
}
<|endoftext|>


<commit_before>// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

#include "pch.h"
#include "MessageUwp.h"

#include <locale>
#include <codecvt>

using namespace Microsoft::Azure::IoT::Gateway;

Message::Message(MESSAGE_HANDLE message_handle)
{
	if (message_handle == nullptr)
	{
		throw ref new Platform::InvalidArgumentException("message_handle must be non-null.");
	}

	_message_handle = message_handle;
}

Message^ Message::CreateMessage(Message^ message)
{
	if (message == nullptr)
	{
		throw ref new Platform::InvalidArgumentException("message must be non-null.");
	}

	return ref new Message(message->_message_handle);
}

Message::Message(Windows::Foundation::Collections::IVector<byte> ^msgInByteArray)
{
	if (msgInByteArray == nullptr)
	{
		throw ref new Platform::InvalidArgumentException("msgInByteArray must be non-null.");
	}

	std::vector<byte> bytes(msgInByteArray->Size);
	std::copy(begin(msgInByteArray), end(msgInByteArray), bytes.begin());

	_message_handle = Message_CreateFromByteArray(bytes.data(), bytes.size());
	if (_message_handle == nullptr)
	{
		throw ref new Platform::FailureException("Failed to create message.");
	}
}

std::string wstrtostr(const std::wstring &wstr)
{
	std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> wstringToString;
	return wstringToString.to_bytes(wstr);
}

std::wstring strtowstr(const std::string &str)
{
	std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> stringToWstring;
	return stringToWstring.from_bytes(str.data());
}

Message::Message(Platform::String ^content, Windows::Foundation::Collections::IMapView<Platform::String^, Platform::String^>^ properties)
{
	if (properties == nullptr)
	{
		throw ref new Platform::InvalidArgumentException("properties must be non-null.");
	}

	// There is no distinction between an empty Platform::String and a NULL.
	std::string cntnt = "";
	if (content != nullptr)
	{
		cntnt = wstrtostr(content->Data());
	}

	MESSAGE_CONFIG msg;
	msg.source = (unsigned char*)cntnt.c_str();
	msg.size = cntnt.size();
	msg.sourceProperties = Map_Create(NULL);

	for (auto iter = begin(properties); iter != end(properties); iter++)
	{
		std::string key = wstrtostr((*iter)->Key->Data());
		std::string value = wstrtostr((*iter)->Value->ToString()->Data());
		Map_Add(msg.sourceProperties, key.c_str(), value.c_str());
	}

	_message_handle = Message_Create(&msg);
	if (_message_handle == nullptr)
	{
		throw ref new Platform::FailureException("Failed to create message.");
	}
}

Message^ Message::CreateMessage(Windows::Foundation::Collections::IVector<byte>^ content, Windows::Foundation::Collections::IMapView<Platform::String^, Platform::String^>^ properties)
{
	if (content == nullptr)
	{
		throw ref new Platform::InvalidArgumentException("content must be non-null.");
	}
	if (properties == nullptr)
	{
		throw ref new Platform::InvalidArgumentException("properties must be non-null.");
	}

	std::vector<byte> contentBytes(content->Size);
	std::copy(begin(content), end(content), contentBytes.begin());

	MESSAGE_CONFIG msg;
	msg.source = contentBytes.data();
	msg.size = contentBytes.size();
	msg.sourceProperties = Map_Create(NULL);
	if (msg.sourceProperties == nullptr)
	{
		throw ref new Platform::FailureException("Failed to create message's properties.");
	}

	for (auto iter = begin(properties); iter != end(properties); iter++)
	{
		std::string key = wstrtostr((*iter)->Key->Data());
		std::string value = wstrtostr((*iter)->Value->ToString()->Data());
		Map_Add(msg.sourceProperties, key.c_str(), value.c_str());
	}

	auto message_handle = Message_Create(&msg);
	if (message_handle == nullptr)
	{
		throw ref new Platform::FailureException("Failed to create message.");
	}
	return ref new Message(message_handle);
}

Windows::Foundation::Collections::IVector<byte>^ Message::ToBytes()
{
	int arrayLength = 0;
	auto byteArray = Message_ToByteArray(this->_message_handle, &arrayLength);
	if (byteArray == nullptr)
	{
		throw ref new Platform::FailureException("Failed to create byte array for message.");
	}

	Windows::Foundation::Collections::IVector<byte>^ messageBytes =
		ref new Platform::Collections::Vector<byte>(byteArray, arrayLength);
	return messageBytes;
}

Windows::Foundation::Collections::IVector<byte>^ Message::GetContent()
{
	auto content_buffer = Message_GetContent(_message_handle);
	if (content_buffer == nullptr)
	{
		throw ref new Platform::FailureException("Failed to get message content.");
	}

	Windows::Foundation::Collections::IVector<byte>^ content =
		ref new Platform::Collections::Vector<byte>(content_buffer->buffer, content_buffer->size);
	return content;
}

Windows::Foundation::Collections::IMapView<Platform::String^, Platform::String^>^ Message::GetProperties()
{
	Windows::Foundation::Collections::IMap<Platform::String^, Platform::String^>^ properties = ref new
		Platform::Collections::Map<Platform::String^, Platform::String^>();

	const char* const* keys;
	const char* const* values;
	size_t nProperties;

	auto constmap_handle = Message_GetProperties(_message_handle);
	if (constmap_handle == nullptr)
	{
		throw ref new Platform::FailureException("Failed to get message properties.");
	}

	if (ConstMap_GetInternals(constmap_handle, &keys, &values, &nProperties) == CONSTMAP_OK)
	{
		for (size_t i = 0; i < nProperties; i++)
		{
			std::wstring key = strtowstr(keys[i]);
			std::wstring value = strtowstr(values[i]);

			properties->Insert(ref new Platform::String(key.c_str()), ref new Platform::String(value.c_str()));
		}
	}
	else
	{
		throw ref new Platform::FailureException("Failed to get message property key/value pairs.");
	}

	return properties->GetView();
}
<commit_msg>UWP build fix<commit_after>// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

#include "pch.h"
#include "MessageUwp.h"

#include <locale>
#include <codecvt>

using namespace Microsoft::Azure::IoT::Gateway;

Message::Message(MESSAGE_HANDLE message_handle)
{
	if (message_handle == nullptr)
	{
		throw ref new Platform::InvalidArgumentException("message_handle must be non-null.");
	}

	_message_handle = message_handle;
}

Message^ Message::CreateMessage(Message^ message)
{
	if (message == nullptr)
	{
		throw ref new Platform::InvalidArgumentException("message must be non-null.");
	}

	return ref new Message(message->_message_handle);
}

Message::Message(Windows::Foundation::Collections::IVector<byte> ^msgInByteArray)
{
	if (msgInByteArray == nullptr)
	{
		throw ref new Platform::InvalidArgumentException("msgInByteArray must be non-null.");
	}

	std::vector<byte> bytes(msgInByteArray->Size);
	std::copy(begin(msgInByteArray), end(msgInByteArray), bytes.begin());

	_message_handle = Message_CreateFromByteArray(bytes.data(), bytes.size());
	if (_message_handle == nullptr)
	{
		throw ref new Platform::FailureException("Failed to create message.");
	}
}

std::string wstrtostr(const std::wstring &wstr)
{
	std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> wstringToString;
	return wstringToString.to_bytes(wstr);
}

std::wstring strtowstr(const std::string &str)
{
	std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> stringToWstring;
	return stringToWstring.from_bytes(str.data());
}

Message::Message(Platform::String ^content, Windows::Foundation::Collections::IMapView<Platform::String^, Platform::String^>^ properties)
{
	if (properties == nullptr)
	{
		throw ref new Platform::InvalidArgumentException("properties must be non-null.");
	}

	// There is no distinction between an empty Platform::String and a NULL.
	std::string cntnt = "";
	if (content != nullptr)
	{
		cntnt = wstrtostr(content->Data());
	}

	MESSAGE_CONFIG msg;
	msg.source = (unsigned char*)cntnt.c_str();
	msg.size = cntnt.size();
	msg.sourceProperties = Map_Create(NULL);

	for (auto iter = begin(properties); iter != end(properties); iter++)
	{
		std::string key = wstrtostr((*iter)->Key->Data());
		std::string value = wstrtostr((*iter)->Value->ToString()->Data());
		Map_Add(msg.sourceProperties, key.c_str(), value.c_str());
	}

	_message_handle = Message_Create(&msg);
	if (_message_handle == nullptr)
	{
		throw ref new Platform::FailureException("Failed to create message.");
	}
}

Message^ Message::CreateMessage(Windows::Foundation::Collections::IVector<byte>^ content, Windows::Foundation::Collections::IMapView<Platform::String^, Platform::String^>^ properties)
{
	if (content == nullptr)
	{
		throw ref new Platform::InvalidArgumentException("content must be non-null.");
	}
	if (properties == nullptr)
	{
		throw ref new Platform::InvalidArgumentException("properties must be non-null.");
	}

	std::vector<byte> contentBytes(content->Size);
	std::copy(begin(content), end(content), contentBytes.begin());

	MESSAGE_CONFIG msg;
	msg.source = contentBytes.data();
	msg.size = contentBytes.size();
	msg.sourceProperties = Map_Create(NULL);
	if (msg.sourceProperties == nullptr)
	{
		throw ref new Platform::FailureException("Failed to create message's properties.");
	}

	for (auto iter = begin(properties); iter != end(properties); iter++)
	{
		std::string key = wstrtostr((*iter)->Key->Data());
		std::string value = wstrtostr((*iter)->Value->ToString()->Data());
		Map_Add(msg.sourceProperties, key.c_str(), value.c_str());
	}

	auto message_handle = Message_Create(&msg);
	if (message_handle == nullptr)
	{
		throw ref new Platform::FailureException("Failed to create message.");
	}
	return ref new Message(message_handle);
}

Windows::Foundation::Collections::IVector<byte>^ Message::ToBytes()
{
	int arrayLength = Message_ToByteArray(this->_message_handle, NULL,0);
	unsigned char *byteArray;
	if (arrayLength < 0 )
	{
			throw ref new Platform::FailureException("Failed to serialize message.");
	}
	else
	{
		byteArray = (unsigned char *)malloc(arrayLength);
		if (byteArray == nullptr)
		{
			throw ref new Platform::FailureException("Failed to create byte array for message.");
		}
		else
		{
			Message_ToByteArray(this->_message_handle, byteArray, arrayLength);
		}
	}

	Windows::Foundation::Collections::IVector<byte>^ messageBytes =
		ref new Platform::Collections::Vector<byte>(byteArray, arrayLength);
	return messageBytes;
}

Windows::Foundation::Collections::IVector<byte>^ Message::GetContent()
{
	auto content_buffer = Message_GetContent(_message_handle);
	if (content_buffer == nullptr)
	{
		throw ref new Platform::FailureException("Failed to get message content.");
	}

	Windows::Foundation::Collections::IVector<byte>^ content =
		ref new Platform::Collections::Vector<byte>(content_buffer->buffer, content_buffer->size);
	return content;
}

Windows::Foundation::Collections::IMapView<Platform::String^, Platform::String^>^ Message::GetProperties()
{
	Windows::Foundation::Collections::IMap<Platform::String^, Platform::String^>^ properties = ref new
		Platform::Collections::Map<Platform::String^, Platform::String^>();

	const char* const* keys;
	const char* const* values;
	size_t nProperties;

	auto constmap_handle = Message_GetProperties(_message_handle);
	if (constmap_handle == nullptr)
	{
		throw ref new Platform::FailureException("Failed to get message properties.");
	}

	if (ConstMap_GetInternals(constmap_handle, &keys, &values, &nProperties) == CONSTMAP_OK)
	{
		for (size_t i = 0; i < nProperties; i++)
		{
			std::wstring key = strtowstr(keys[i]);
			std::wstring value = strtowstr(values[i]);

			properties->Insert(ref new Platform::String(key.c_str()), ref new Platform::String(value.c_str()));
		}
	}
	else
	{
		throw ref new Platform::FailureException("Failed to get message property key/value pairs.");
	}

	return properties->GetView();
}
<|endoftext|>