<commit_before>#include "tree_widget.h"

#include <QHBoxLayout>

#include <dependency_graph/network.h>
#include <dependency_graph/node.h>

#include "adaptor.h"

TreeWidget::TreeWidget(QWidget* parent, Adaptor* adaptor) : QWidget(parent), m_adaptor(adaptor) {
	QHBoxLayout* layout = new QHBoxLayout(this);
	layout->setContentsMargins(0,0,0,0);

	m_tree = new QTreeWidget();
	m_tree->headerItem()->setHidden(true);
	m_tree->sortByColumn(0, Qt::AscendingOrder);
	m_tree->setSortingEnabled(true);
	layout->addWidget(m_tree);

	QTreeWidgetItem* root = new QTreeWidgetItem();
	root->setText(0, "/");
	root->setIcon(0, QIcon(":icons/network.png"));
	m_tree->addTopLevelItem(root);

	m_items.left.insert(std::make_pair(m_adaptor->graph().index(), root));

	m_signals.push_back(m_adaptor->graph().onAddNode(
		[this](dependency_graph::NodeBase& node) { onAddNode(node); }
	));

	m_signals.push_back(m_adaptor->graph().onRemoveNode(
		[this](dependency_graph::NodeBase& node) { onRemoveNode(node); }
	));

	connect(adaptor, &Adaptor::currentNetworkChanged, this, &TreeWidget::onCurrentNetworkChanged);
	connect(m_tree, &QTreeWidget::itemSelectionChanged, this, &TreeWidget::onCurrentSelectionChanged);
}

TreeWidget::~TreeWidget() {
	for(auto& s : m_signals)
		s.disconnect();
}

void TreeWidget::onAddNode(dependency_graph::NodeBase& node) {
	assert(node.hasParentNetwork());

	auto parent = m_items.left.find(node.network().index());
	assert(parent != m_items.left.end());

	QTreeWidgetItem* item = new QTreeWidgetItem();
	item->setText(0, node.name().c_str());

	if(node.is<dependency_graph::Network>())
		item->setIcon(0, QIcon(":icons/network.png"));
	else
		item->setIcon(0, QIcon(":icons/node.png"));
	parent->second->addChild(item);

	m_items.left.insert(std::make_pair(node.index(), item));
}

void TreeWidget::onRemoveNode(dependency_graph::NodeBase& node) {
	auto it = m_items.left.find(node.index());
	assert(it != m_items.left.end());

	it->second->parent()->removeChild(it->second);
	delete it->second;
	m_items.left.erase(it);
}

void TreeWidget::onCurrentNetworkChanged(const dependency_graph::NodeBase& node) {
	auto it = m_items.left.find(node.index());
	assert(it != m_items.left.end());

	if(!it->second->isExpanded())
		it->second->setExpanded(true);
}

void TreeWidget::onSelectionChanged(dependency_graph::Selection selection) {
	bool originalBlock = m_tree->blockSignals(true);

	m_tree->clearSelection();

	for(auto& n : selection.nodes()) {
		auto it = m_items.left.find(n.get().index());
		assert(it != m_items.left.end());

		it->second->setSelected(true);
	}

	m_tree->blockSignals(originalBlock);
}

void TreeWidget::onCurrentSelectionChanged() {
	// build a selection
	dependency_graph::Selection selection;
	for(auto& s : m_tree->selectedItems()) {
		auto it = m_items.right.find(s);
		assert(it != m_items.right.end());
		dependency_graph::UniqueId id = it->second;

		dependency_graph::NodeBase& node = *m_adaptor->index().find(id)->second.graphNode;

		selection.addNode(node);

		if(node.hasParentNetwork())
			for(auto& con : node.network().connections())
				if(con.first.node().index() == node.index() || con.second.node().index() == node.index())
					selection.addConnection(con.first, con.second);
	}

	// and set this selection in the parent adaptor
	bool originalBlock = m_tree->blockSignals(true);
	m_adaptor->setSelection(selection);
	m_tree->blockSignals(originalBlock);
}
<commit_msg>TreeWidget - fixed a crash when selecting the root network<commit_after>#include "tree_widget.h"

#include <QHBoxLayout>

#include <dependency_graph/network.h>
#include <dependency_graph/node.h>

#include "adaptor.h"

TreeWidget::TreeWidget(QWidget* parent, Adaptor* adaptor) : QWidget(parent), m_adaptor(adaptor) {
	QHBoxLayout* layout = new QHBoxLayout(this);
	layout->setContentsMargins(0,0,0,0);

	m_tree = new QTreeWidget();
	m_tree->headerItem()->setHidden(true);
	m_tree->sortByColumn(0, Qt::AscendingOrder);
	m_tree->setSortingEnabled(true);
	layout->addWidget(m_tree);

	QTreeWidgetItem* root = new QTreeWidgetItem();
	root->setText(0, "/");
	root->setIcon(0, QIcon(":icons/network.png"));
	m_tree->addTopLevelItem(root);

	m_items.left.insert(std::make_pair(m_adaptor->graph().index(), root));

	m_signals.push_back(m_adaptor->graph().onAddNode(
		[this](dependency_graph::NodeBase& node) { onAddNode(node); }
	));

	m_signals.push_back(m_adaptor->graph().onRemoveNode(
		[this](dependency_graph::NodeBase& node) { onRemoveNode(node); }
	));

	connect(adaptor, &Adaptor::currentNetworkChanged, this, &TreeWidget::onCurrentNetworkChanged);
	connect(m_tree, &QTreeWidget::itemSelectionChanged, this, &TreeWidget::onCurrentSelectionChanged);
}

TreeWidget::~TreeWidget() {
	for(auto& s : m_signals)
		s.disconnect();
}

void TreeWidget::onAddNode(dependency_graph::NodeBase& node) {
	assert(node.hasParentNetwork());

	auto parent = m_items.left.find(node.network().index());
	assert(parent != m_items.left.end());

	QTreeWidgetItem* item = new QTreeWidgetItem();
	item->setText(0, node.name().c_str());

	if(node.is<dependency_graph::Network>())
		item->setIcon(0, QIcon(":icons/network.png"));
	else
		item->setIcon(0, QIcon(":icons/node.png"));
	parent->second->addChild(item);

	m_items.left.insert(std::make_pair(node.index(), item));
}

void TreeWidget::onRemoveNode(dependency_graph::NodeBase& node) {
	auto it = m_items.left.find(node.index());
	assert(it != m_items.left.end());

	it->second->parent()->removeChild(it->second);
	delete it->second;
	m_items.left.erase(it);
}

void TreeWidget::onCurrentNetworkChanged(const dependency_graph::NodeBase& node) {
	auto it = m_items.left.find(node.index());
	assert(it != m_items.left.end());

	if(!it->second->isExpanded())
		it->second->setExpanded(true);
}

void TreeWidget::onSelectionChanged(dependency_graph::Selection selection) {
	bool originalBlock = m_tree->blockSignals(true);

	m_tree->clearSelection();

	for(auto& n : selection.nodes()) {
		auto it = m_items.left.find(n.get().index());
		assert(it != m_items.left.end());

		it->second->setSelected(true);
	}

	m_tree->blockSignals(originalBlock);
}

void TreeWidget::onCurrentSelectionChanged() {
	// build a selection
	dependency_graph::Selection selection;
	for(auto& s : m_tree->selectedItems()) {
		auto it = m_items.right.find(s);
		assert(it != m_items.right.end());
		dependency_graph::UniqueId id = it->second;

		dependency_graph::NodeBase* node = m_adaptor->index().find(id)->second.graphNode;
		if(node) {
			selection.addNode(*node);

			if(node->hasParentNetwork())
				for(auto& con : node->network().connections())
					if(con.first.node().index() == node->index() || con.second.node().index() == node->index())
						selection.addConnection(con.first, con.second);
		}

		// if the node doesn't exist in the adaptor's Index instance, it has to be the root
		else
			assert(id == m_adaptor->graph().index());
	}

	// and set this selection in the parent adaptor
	bool originalBlock = m_tree->blockSignals(true);
	m_adaptor->setSelection(selection);
	m_tree->blockSignals(originalBlock);
}
<|endoftext|>


<commit_before>///////////////////////////////////////////////////////////////////////
// File:        equationdetectbase.cpp
// Description: The base class equation detection class.
// Author:      Zongyi (Joe) Liu (joeliu@google.com)
// Created:     Fri Aug 31 11:13:01 PST 2011
//
// (C) Copyright 2011, Google Inc.
// 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 "equationdetectbase.h"
#include <allheaders.h>
#include "blobbox.h"

namespace tesseract {

// Destructor.
// It is defined here, so the compiler can create a single vtable
// instead of weak vtables in every compilation unit.
EquationDetectBase::~EquationDetectBase() = default;

void EquationDetectBase::RenderSpecialText(Pix *pix, BLOBNBOX *blob) {
  ASSERT_HOST(pix != nullptr && pixGetDepth(pix) == 32 && blob != nullptr);
  const TBOX &tbox = blob->bounding_box();
  int height = pixGetHeight(pix);
  const int box_width = 5;

  // Coordinate translation: tesseract use left bottom as the original, while
  // leptonica uses left top as the original.
  Box *box = boxCreate(tbox.left(), height - tbox.top(), tbox.width(), tbox.height());
  switch (blob->special_text_type()) {
    case BSTT_MATH: // Red box.
      pixRenderBoxArb(pix, box, box_width, 255, 0, 0);
      break;
    case BSTT_DIGIT: // cyan box.
      pixRenderBoxArb(pix, box, box_width, 0, 255, 255);
      break;
    case BSTT_ITALIC: // Green box.
      pixRenderBoxArb(pix, box, box_width, 0, 255, 0);
      break;
    case BSTT_UNCLEAR: // blue box.
      pixRenderBoxArb(pix, box, box_width, 0, 255, 0);
      break;
    case BSTT_NONE:
    default:
      // yellow box.
      pixRenderBoxArb(pix, box, box_width, 255, 255, 0);
      break;
  }
  boxDestroy(&box);
}

} // namespace tesseract
<commit_msg>Include missing config_auto.h<commit_after>///////////////////////////////////////////////////////////////////////
// File:        equationdetectbase.cpp
// Description: The base class equation detection class.
// Author:      Zongyi (Joe) Liu (joeliu@google.com)
// Created:     Fri Aug 31 11:13:01 PST 2011
//
// (C) Copyright 2011, Google Inc.
// 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.
//
///////////////////////////////////////////////////////////////////////

#ifdef HAVE_CONFIG_H
#  include "config_auto.h"
#endif

#include "equationdetectbase.h"

#include "blobbox.h"

#include <allheaders.h>

namespace tesseract {

// Destructor.
// It is defined here, so the compiler can create a single vtable
// instead of weak vtables in every compilation unit.
EquationDetectBase::~EquationDetectBase() = default;

void EquationDetectBase::RenderSpecialText(Pix *pix, BLOBNBOX *blob) {
  ASSERT_HOST(pix != nullptr && pixGetDepth(pix) == 32 && blob != nullptr);
  const TBOX &tbox = blob->bounding_box();
  int height = pixGetHeight(pix);
  const int box_width = 5;

  // Coordinate translation: tesseract use left bottom as the original, while
  // leptonica uses left top as the original.
  Box *box = boxCreate(tbox.left(), height - tbox.top(), tbox.width(), tbox.height());
  switch (blob->special_text_type()) {
    case BSTT_MATH: // Red box.
      pixRenderBoxArb(pix, box, box_width, 255, 0, 0);
      break;
    case BSTT_DIGIT: // cyan box.
      pixRenderBoxArb(pix, box, box_width, 0, 255, 255);
      break;
    case BSTT_ITALIC: // Green box.
      pixRenderBoxArb(pix, box, box_width, 0, 255, 0);
      break;
    case BSTT_UNCLEAR: // blue box.
      pixRenderBoxArb(pix, box, box_width, 0, 255, 0);
      break;
    case BSTT_NONE:
    default:
      // yellow box.
      pixRenderBoxArb(pix, box, box_width, 255, 255, 0);
      break;
  }
  boxDestroy(&box);
}

} // namespace tesseract
<|endoftext|>


<commit_before>/**
  This is a tool shipped by 'Aleph - A Library for Exploring Persistent
  Homology'.

  Given a set of patches from a database of images, this tool performs
  the pre-processing steps of the corresponding point cloud. Mainly, a
  procedure from the paper *On the Local Behavior of Spaces of Natural
  Images* by Gunnar Carlsson et al. is followed.
*/

#include <aleph/containers/PointCloud.hh>

#include <aleph/math/KahanSummation.hh>

#include <algorithm>
#include <iostream>
#include <string>

#include <cmath>

using DataType   = float;
using PointCloud = aleph::containers::PointCloud<DataType>;

template <class T> T log( T x )
{
  if( x == T() )
    return T();
  else
    return std::log10( x );
}

int main( int argc, char** argv )
{
  if( argc <= 1 )
    return -1;

  // Input -------------------------------------------------------------
  //
  // This tool assumes that the input is already in the form of a point
  // cloud, containing the 'raw' image patches.

  std::string filename = argv[1];

  std::cerr << "* Loading input point cloud...";

  PointCloud pointCloud = aleph::containers::load<DataType>( filename );

  std::cerr << "finished\n";

  // Pre-processing ----------------------------------------------------
  //
  // 1. Replace values by their logarithm
  // 2. Subtract mean

  using IndexType                = decltype( pointCloud.size() );
  PointCloud processedPointCloud = PointCloud( pointCloud.size(), pointCloud.dimension() );

  for( IndexType i = 0; i < pointCloud.size(); i++ )
  {
    auto p = pointCloud[i];

    std::transform( p.begin(), p.end(), p.begin(),
                    [] ( DataType x )
                    {
                      return log( x );
                    } );

    auto mean  = aleph::math::accumulate_kahan_sorted( p.begin(), p.end(), DataType() );
    mean      /= static_cast<DataType>( pointCloud.dimension() );

    std::transform( p.begin(), p.end(), p.begin(),
                    [&mean] ( DataType x )
                    {
                      return x - mean;
                    } );

    processedPointCloud.set( i, p.begin(), p.end() );
  }

}
<commit_msg>Added normalization based on contrast norm<commit_after>/**
  This is a tool shipped by 'Aleph - A Library for Exploring Persistent
  Homology'.

  Given a set of patches from a database of images, this tool performs
  the pre-processing steps of the corresponding point cloud. Mainly, a
  procedure from the paper *On the Local Behavior of Spaces of Natural
  Images* by Gunnar Carlsson et al. is followed.
*/

#include <aleph/containers/PointCloud.hh>

#include <aleph/math/KahanSummation.hh>

#include <algorithm>
#include <iostream>
#include <iterator>
#include <string>

#include <cmath>

using DataType   = float;
using PointCloud = aleph::containers::PointCloud<DataType>;

template <class T> T log( T x )
{
  if( x == T() )
    return T();
  else
    return std::log10( x );
}

template <class InputIterator> DataType contrastNorm( InputIterator begin, InputIterator end )
{
  using T = typename std::iterator_traits<InputIterator>::value_type;
  std::vector<T> data( begin, end );

  unsigned n = static_cast<unsigned>( std::sqrt( data.size() ) );

  aleph::math::KahanSummation<T> difference = T();

  for( unsigned i = 0; i < n; i++ )
  {
    for( unsigned j = 0; j < n; j++ )
    {
      auto index = n * i + j;

      if( j+1 <  n )
        difference += std::pow( data.at(index) - data.at(index+1), T(2) );

      if( j   >= 1 )
        difference += std::pow( data.at(index) - data.at(index-1), T(2) );

      if( i+1 <  n )
        difference += std::pow( data.at(index) - data.at(index+n), T(2) );

      if( i-1 <  n )
        difference += std::pow( data.at(index) - data.at(index-n), T(2) );
    }
  }

  return static_cast<DataType>( difference );
}

int main( int argc, char** argv )
{
  if( argc <= 1 )
    return -1;

  // Input -------------------------------------------------------------
  //
  // This tool assumes that the input is already in the form of a point
  // cloud, containing the 'raw' image patches.

  std::string filename = argv[1];

  std::cerr << "* Loading input point cloud...";

  PointCloud pointCloud = aleph::containers::load<DataType>( filename );

  std::cerr << "finished\n";

  // Pre-processing ----------------------------------------------------
  //
  // 1. Replace values by their logarithm
  // 2. Subtract mean
  // 3. Normalize by the contrast norm

  using IndexType                = decltype( pointCloud.size() );
  PointCloud processedPointCloud = PointCloud( pointCloud.size(), pointCloud.dimension() );

  for( IndexType i = 0; i < pointCloud.size(); i++ )
  {
    auto p = pointCloud[i];

    std::transform( p.begin(), p.end(), p.begin(),
                    [] ( DataType x )
                    {
                      return log( x );
                    } );

    auto mean  = aleph::math::accumulate_kahan_sorted( p.begin(), p.end(), DataType() );
    mean      /= static_cast<DataType>( pointCloud.dimension() );

    std::transform( p.begin(), p.end(), p.begin(),
                    [&mean] ( DataType x )
                    {
                      return x - mean;
                    } );

    auto norm = contrastNorm( p.begin(), p.end() );

    if( norm > DataType() )
    {
      std::transform( p.begin(), p.end(), p.begin(),
                      [&norm] ( DataType x )
                      {
                        return x / norm;
                      } );
    }

    processedPointCloud.set( i, p.begin(), p.end() );
  }
}
<|endoftext|>


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

#include <emscripten/emscripten.h>
#include <map>
#include <string>

#include "perfetto/base/logging.h"
#include "perfetto/trace_processor/trace_processor.h"

#include "perfetto/trace_processor/raw_query.pb.h"
#include "perfetto/trace_processor/sched.pb.h"

namespace perfetto {
namespace trace_processor {

using RequestID = uint32_t;

// Reply(): replies to a RPC method invocation.
// Called asynchronously (i.e. in a separate task) by the C++ code inside the
// trace processor to return data for a RPC method call.
// The function is generic and thankfully we need just one for all methods
// because the output is always a protobuf buffer.
// Args:
//  RequestID: the ID passed by the embedder when invoking the RPC method (e.g.,
//             the first argument passed to sched_getSchedEvents()).
using ReplyFunction = void (*)(RequestID,
                               bool success,
                               const char* /*proto_reply_data*/,
                               uint32_t /*len*/);

namespace {
TraceProcessor* g_trace_processor;
ReplyFunction g_reply;
}  // namespace
// +---------------------------------------------------------------------------+
// | Exported functions called by the JS/TS running in the worker.             |
// +---------------------------------------------------------------------------+
extern "C" {

void EMSCRIPTEN_KEEPALIVE Initialize(ReplyFunction);
void Initialize(ReplyFunction reply_function) {
  PERFETTO_ILOG("Initializing WASM bridge");
  Config config;
  g_trace_processor = TraceProcessor::CreateInstance(config).release();
  g_reply = reply_function;
}

void EMSCRIPTEN_KEEPALIVE trace_processor_parse(RequestID,
                                                const uint8_t*,
                                                uint32_t);
void trace_processor_parse(RequestID id, const uint8_t* data, size_t size) {
  // TODO(primiano): This copy is extremely unfortunate. Ideally there should be
  // a way to take the Blob coming from JS (either from FileReader or from th
  // fetch() stream) and move into WASM.
  // See https://github.com/WebAssembly/design/issues/1162.
  std::unique_ptr<uint8_t[]> buf(new uint8_t[size]);
  memcpy(buf.get(), data, size);
  g_trace_processor->Parse(std::move(buf), size);
  g_reply(id, true, "", 0);
}

// We keep the same signature as other methods even though we don't take input
// arguments for simplicity.
void EMSCRIPTEN_KEEPALIVE trace_processor_notifyEof(RequestID,
                                                    const uint8_t*,
                                                    uint32_t);
void trace_processor_notifyEof(RequestID id, const uint8_t*, uint32_t size) {
  PERFETTO_DCHECK(!size);
  g_trace_processor->NotifyEndOfFile();
  g_reply(id, true, "", 0);
}

void EMSCRIPTEN_KEEPALIVE trace_processor_rawQuery(RequestID,
                                                   const uint8_t*,
                                                   int);
void trace_processor_rawQuery(RequestID id,
                              const uint8_t* query_data,
                              int len) {
  protos::RawQueryArgs query;
  bool parsed = query.ParseFromArray(query_data, len);
  if (!parsed) {
    std::string err = "Failed to parse input request";
    g_reply(id, false, err.data(), err.size());
    return;
  }

  // When the C++ class implementing the service replies, serialize the protobuf
  // result and post it back to the worker script (|g_reply|).
  auto callback = [id](const protos::RawQueryResult& res) {
    std::string encoded;
    res.SerializeToString(&encoded);
    g_reply(id, true, encoded.data(), static_cast<uint32_t>(encoded.size()));
  };

  g_trace_processor->ExecuteQuery(query, callback);
}

}  // extern "C"

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

#include <emscripten/emscripten.h>
#include <map>
#include <string>

#include "perfetto/base/logging.h"
#include "perfetto/trace_processor/trace_processor.h"

#include "perfetto/trace_processor/raw_query.pb.h"
#include "perfetto/trace_processor/sched.pb.h"

namespace perfetto {
namespace trace_processor {

using RequestID = uint32_t;

// Reply(): replies to a RPC method invocation.
// Called asynchronously (i.e. in a separate task) by the C++ code inside the
// trace processor to return data for a RPC method call.
// The function is generic and thankfully we need just one for all methods
// because the output is always a protobuf buffer.
// Args:
//  RequestID: the ID passed by the embedder when invoking the RPC method (e.g.,
//             the first argument passed to sched_getSchedEvents()).
using ReplyFunction = void (*)(RequestID,
                               bool success,
                               const char* /*proto_reply_data*/,
                               uint32_t /*len*/);

namespace {
TraceProcessor* g_trace_processor;
ReplyFunction g_reply;
}  // namespace
// +---------------------------------------------------------------------------+
// | Exported functions called by the JS/TS running in the worker.             |
// +---------------------------------------------------------------------------+
extern "C" {

void EMSCRIPTEN_KEEPALIVE Initialize(ReplyFunction);
void Initialize(ReplyFunction reply_function) {
  PERFETTO_ILOG("Initializing WASM bridge");
  Config config;
  g_trace_processor = TraceProcessor::CreateInstance(config).release();
  g_reply = reply_function;
}

void EMSCRIPTEN_KEEPALIVE trace_processor_parse(RequestID,
                                                const uint8_t*,
                                                uint32_t);
void trace_processor_parse(RequestID id, const uint8_t* data, size_t size) {
  // TODO(primiano): This copy is extremely unfortunate. Ideally there should be
  // a way to take the Blob coming from JS (either from FileReader or from th
  // fetch() stream) and move into WASM.
  // See https://github.com/WebAssembly/design/issues/1162.
  std::unique_ptr<uint8_t[]> buf(new uint8_t[size]);
  memcpy(buf.get(), data, size);
  g_trace_processor->Parse(std::move(buf), size);
  g_reply(id, true, "", 0);
}

// We keep the same signature as other methods even though we don't take input
// arguments for simplicity.
void EMSCRIPTEN_KEEPALIVE trace_processor_notifyEof(RequestID,
                                                    const uint8_t*,
                                                    uint32_t);
void trace_processor_notifyEof(RequestID id, const uint8_t*, uint32_t size) {
  PERFETTO_DCHECK(!size);
  g_trace_processor->NotifyEndOfFile();
  g_reply(id, true, "", 0);
}

void EMSCRIPTEN_KEEPALIVE trace_processor_rawQuery(RequestID,
                                                   const uint8_t*,
                                                   int);
void trace_processor_rawQuery(RequestID id,
                              const uint8_t* query_data,
                              int len) {
  protos::RawQueryArgs query;
  bool parsed = query.ParseFromArray(query_data, len);
  if (!parsed) {
    std::string err = "Failed to parse input request";
    g_reply(id, false, err.data(), err.size());
    return;
  }

  using ColumnDesc = protos::RawQueryResult::ColumnDesc;
  protos::RawQueryResult result;
  auto it = g_trace_processor->ExecuteQuery(query.sql_query().c_str());
  for (uint32_t col = 0; col < it.ColumnCount(); ++col) {
    // Setup the descriptors.
    auto* descriptor = result.add_column_descriptors();
    descriptor->set_name(it.GetColumName(col));
    descriptor->set_type(ColumnDesc::UNKNOWN);

    // Add an empty column.
    result.add_columns();
  }

  for (uint32_t rows = 0; it.Next(); ++rows) {
    for (uint32_t col = 0; col < it.ColumnCount(); ++col) {
      auto* column = result.mutable_columns(static_cast<int>(col));
      auto* desc = result.mutable_column_descriptors(static_cast<int>(col));

      using SqlValue = trace_processor::SqlValue;
      auto cell = it.Get(col);
      if (desc->type() == ColumnDesc::UNKNOWN) {
        switch (cell.type) {
          case SqlValue::Type::kLong:
            desc->set_type(ColumnDesc::LONG);
            break;
          case SqlValue::Type::kString:
            desc->set_type(ColumnDesc::STRING);
            break;
          case SqlValue::Type::kDouble:
            desc->set_type(ColumnDesc::DOUBLE);
            break;
          case SqlValue::Type::kNull:
            break;
        }
      }

      // If either the column type is null or we still don't know the type,
      // just add null values to all the columns.
      if (cell.type == SqlValue::Type::kNull ||
          desc->type() == ColumnDesc::UNKNOWN) {
        column->add_long_values(0);
        column->add_string_values("[NULL]");
        column->add_double_values(0);
        column->add_is_nulls(true);
        continue;
      }

      // Cast the sqlite value to the type of the column.
      switch (desc->type()) {
        case ColumnDesc::LONG:
          PERFETTO_CHECK(cell.type == SqlValue::Type::kLong ||
                         cell.type == SqlValue::Type::kDouble);
          if (cell.type == SqlValue::Type::kLong) {
            column->add_long_values(cell.long_value);
          } else /* if (cell.type == SqlValue::Type::kDouble) */ {
            column->add_long_values(static_cast<int64_t>(cell.double_value));
          }
          column->add_is_nulls(false);
          break;
        case ColumnDesc::STRING: {
          PERFETTO_CHECK(cell.type == SqlValue::Type::kString);
          column->add_string_values(cell.string_value);
          column->add_is_nulls(false);
          break;
        }
        case ColumnDesc::DOUBLE:
          PERFETTO_CHECK(cell.type == SqlValue::Type::kLong ||
                         cell.type == SqlValue::Type::kDouble);
          if (cell.type == SqlValue::Type::kLong) {
            column->add_double_values(static_cast<double>(cell.long_value));
          } else /* if (cell.type == SqlValue::Type::kDouble) */ {
            column->add_double_values(cell.double_value);
          }
          column->add_is_nulls(false);
          break;
        case ColumnDesc::UNKNOWN:
          PERFETTO_FATAL("Handled in if statement above.");
      }
    }
    result.set_num_records(rows + 1);
  }
  if (auto opt_error = it.GetLastError()) {
    result.set_error(*opt_error);
  }

  std::string encoded;
  result.SerializeToString(&encoded);
  g_reply(id, true, encoded.data(), static_cast<uint32_t>(encoded.size()));
}

}  // extern "C"

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


<commit_before>/* medTabbedViewContainers.cpp ---
 *
 * Author: Julien Wintz
 * Copyright (C) 2008 - Julien Wintz, Inria.
 * Created: Thu May 13 12:39:09 2010 (+0200)
 * Version: $Id$
 * Last-Updated: Tue Jun 15 22:12:57 2010 (+0200)
 *           By: Julien Wintz
 *     Update #: 8
 */

/* Commentary:
 *
 */

/* Change log:
 *
 */

#include <QtCore>

#include "medTabbedViewContainers.h"

#include "medViewContainer.h"
#include "medViewContainerCustom.h"
#include "medViewContainerMulti.h"
#include "medViewContainerSingle.h"

class medTabbedViewContainersPrivate
{
public:
   QHash<QString, medViewContainer*> containers;
   QString currentName;

   QPushButton *addButton;
};

medTabbedViewContainers::medTabbedViewContainers(QWidget *parent) : QTabWidget(parent), d(new medTabbedViewContainersPrivate)
{
    this->setTabsClosable(true);
    this->setMovable(true);

    connect(this,SIGNAL(tabCloseRequested(int)),this,SLOT(deleteContainerClicked(int)));
    connect(this,SIGNAL(currentChanged(int)),this,SLOT(onCurrentContainerChanged(int)));

    d->addButton = new QPushButton();
    d->addButton->setStyleSheet("background-image: url(:medGui/pixmaps/plus_button.png);background-position: center;background-repeat: no-repeat;");
    this->setCornerWidget(d->addButton);

    connect(d->addButton,SIGNAL(clicked()),this,SIGNAL(addTabButtonClicked()));
}

medTabbedViewContainers::~medTabbedViewContainers(void)
{
    delete d;

    d = NULL;
}

void medTabbedViewContainers::lockTabs()
{
    this->setTabsClosable(false);
    this->setMovable(false);
    d->addButton->hide();
}

void medTabbedViewContainers::unlockTabs()
{
    this->setTabsClosable(true);
    this->setMovable(true);
    d->addButton->show();
}

/*
void medTabbedViewContainers::addNewTabContainer()
{
    // This slot should disappear, instead the creation signal should be sent to the parent who should call for the creation of a new tab
    QString name = "Tab ";
    name += QString::number(this->count());

    if (!this->container(name))
    {
        medViewContainer *new_container = new medViewContainerMulti();
        addContainer(name, new_container);
        this->setContainer(name);
    }
    else
        qDebug() << "Container" << name << "already exists in this configurations";
}
*/

void medTabbedViewContainers::deleteContainerClicked(int index)
{
    if (this->count() > 1)
    {
        d->containers.remove(this->tabText(index));
        this->removeTab(index);
    }
}

void medTabbedViewContainers::addContainer(const QString &name, medViewContainer *container)
{
    if (!container)
        return;

    d->containers[name] = container;

    connect( container, SIGNAL( focused( dtkAbstractView * ) ),
             this,      SIGNAL( focused( dtkAbstractView * ) ) );
    connect( container, SIGNAL( dropped( const medDataIndex & ) ),
             this,      SIGNAL( dropped( const medDataIndex & ) ) );
    connect( container, SIGNAL( viewAdded( dtkAbstractView * ) ),
             this,      SIGNAL( viewAdded( dtkAbstractView * ) ) );
    connect( container, SIGNAL( viewRemoved( dtkAbstractView * ) ),
             this,      SIGNAL( viewRemoved( dtkAbstractView * ) ) );

    if (!this->count())
        d->currentName = name;
    this->addTab(container, name);
}

void medTabbedViewContainers::insertContainer(int index, const QString &name, medViewContainer *container)
{
    if (!container)
        return;

    d->containers[name] = container;

    connect( container, SIGNAL( focused( dtkAbstractView * ) ),
             this,      SIGNAL( focused( dtkAbstractView * ) ) );
    connect( container, SIGNAL( dropped( const medDataIndex & ) ),
             this,      SIGNAL( dropped( const medDataIndex & ) ) );

    connect( container, SIGNAL( viewAdded( dtkAbstractView * ) ),
             this,      SIGNAL( viewAdded( dtkAbstractView * ) ) );
    connect( container, SIGNAL( viewRemoved( dtkAbstractView * ) ),
             this,      SIGNAL( viewRemoved( dtkAbstractView * ) ) );

    if (!this->count())
        d->currentName = name;
    this->insertTab(index,container, name);
}

void medTabbedViewContainers::changeCurrentContainerType(const QString &name)
{
    //qDebug() << "Changing container type to " << name << " from " << this->current()->description();
    //qDebug() << "Current index is " << this->currentIndex() << " and tab name " << this->tabText(this->currentIndex());

    if ((!this->current()->views().isEmpty()) && (name != this->current()->description()))
    {
        QMessageBox msgBox ( this );
        msgBox.setIcon ( QMessageBox::Warning );
        msgBox.setText(tr("Current tab is not empty. Changing tab type will delete current views."));
        msgBox.setInformativeText(tr("Are you sure you wish to change tab type?"));
        msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
        msgBox.setDefaultButton(QMessageBox::No);
        int reply = msgBox.exec();

        if( reply == QMessageBox::No )
            return;
    }

    if (name != this->current()->description())
    {
        medViewContainer *newTab = NULL;
        if (name == "Single")
            newTab = new medViewContainerSingle();
        else if (name == "Custom")
            newTab = new medViewContainerCustom();
        else if (name == "Multi")
            newTab = new medViewContainerMulti();

        if (newTab != NULL)
        {
            this->blockSignals(true);
            int index = this->currentIndex();
            QString tabName = this->tabText(index);
            this->removeTab(index);
            this->insertContainer(index,tabName,newTab);
            this->setCurrentIndex(index);
            this->blockSignals(false);

            this->onCurrentContainerChanged(index);
        }
    }
}

medViewContainer* medTabbedViewContainers::container(const QString &name) const
{
    if (!d->containers.contains(name))
        return NULL;

    return d->containers[name];
}

void medTabbedViewContainers::setContainer(const QString &name)
{
    if (!d->containers.contains(name))
    {
        qWarning()<<"container does not contain any container of name:" << name;
        return;
    }

    d->currentName = name;
    this->setCurrentWidget(d->containers[name]);
}

medViewContainer *medTabbedViewContainers::current(void) const
{
    return dynamic_cast<medViewContainer*> (currentWidget());
}

QString medTabbedViewContainers::currentName(void) const
{
    return d->currentName;
}

QList<QString> medTabbedViewContainers::keys()
{
    return d->containers.keys();
}

void medTabbedViewContainers::removeContainer(const QString& name)
{
    if (d->containers.contains(name))
    {
        medViewContainer* container = d->containers[name];
        //removeWidget(container);
        delete container;
        d->containers.remove(name);
    }
}

void medTabbedViewContainers::onCurrentContainerChanged(int index)
{
    QString name = this->tabText(index);
    emit currentChanged(name);
}
<commit_msg>Refs #91 . When refusing to delete, the selected layout in the layout toolbox was becoming wrong. Fixed.<commit_after>/* medTabbedViewContainers.cpp ---
 *
 * Author: Julien Wintz
 * Copyright (C) 2008 - Julien Wintz, Inria.
 * Created: Thu May 13 12:39:09 2010 (+0200)
 * Version: $Id$
 * Last-Updated: Tue Jun 15 22:12:57 2010 (+0200)
 *           By: Julien Wintz
 *     Update #: 8
 */

/* Commentary:
 *
 */

/* Change log:
 *
 */

#include <QtCore>

#include "medTabbedViewContainers.h"

#include "medViewContainer.h"
#include "medViewContainerCustom.h"
#include "medViewContainerMulti.h"
#include "medViewContainerSingle.h"

class medTabbedViewContainersPrivate
{
public:
   QHash<QString, medViewContainer*> containers;
   QString currentName;

   QPushButton *addButton;
};

medTabbedViewContainers::medTabbedViewContainers(QWidget *parent) : QTabWidget(parent), d(new medTabbedViewContainersPrivate)
{
    this->setTabsClosable(true);
    this->setMovable(true);

    connect(this,SIGNAL(tabCloseRequested(int)),this,SLOT(deleteContainerClicked(int)));
    connect(this,SIGNAL(currentChanged(int)),this,SLOT(onCurrentContainerChanged(int)));

    d->addButton = new QPushButton();
    d->addButton->setStyleSheet("background-image: url(:medGui/pixmaps/plus_button.png);background-position: center;background-repeat: no-repeat;");
    this->setCornerWidget(d->addButton);

    connect(d->addButton,SIGNAL(clicked()),this,SIGNAL(addTabButtonClicked()));
}

medTabbedViewContainers::~medTabbedViewContainers(void)
{
    delete d;

    d = NULL;
}

void medTabbedViewContainers::lockTabs()
{
    this->setTabsClosable(false);
    this->setMovable(false);
    d->addButton->hide();
}

void medTabbedViewContainers::unlockTabs()
{
    this->setTabsClosable(true);
    this->setMovable(true);
    d->addButton->show();
}

/*
void medTabbedViewContainers::addNewTabContainer()
{
    // This slot should disappear, instead the creation signal should be sent to the parent who should call for the creation of a new tab
    QString name = "Tab ";
    name += QString::number(this->count());

    if (!this->container(name))
    {
        medViewContainer *new_container = new medViewContainerMulti();
        addContainer(name, new_container);
        this->setContainer(name);
    }
    else
        qDebug() << "Container" << name << "already exists in this configurations";
}
*/

void medTabbedViewContainers::deleteContainerClicked(int index)
{
    if (this->count() > 1)
    {
        d->containers.remove(this->tabText(index));
        this->removeTab(index);
    }
}

void medTabbedViewContainers::addContainer(const QString &name, medViewContainer *container)
{
    if (!container)
        return;

    d->containers[name] = container;

    connect( container, SIGNAL( focused( dtkAbstractView * ) ),
             this,      SIGNAL( focused( dtkAbstractView * ) ) );
    connect( container, SIGNAL( dropped( const medDataIndex & ) ),
             this,      SIGNAL( dropped( const medDataIndex & ) ) );
    connect( container, SIGNAL( viewAdded( dtkAbstractView * ) ),
             this,      SIGNAL( viewAdded( dtkAbstractView * ) ) );
    connect( container, SIGNAL( viewRemoved( dtkAbstractView * ) ),
             this,      SIGNAL( viewRemoved( dtkAbstractView * ) ) );

    if (!this->count())
        d->currentName = name;
    this->addTab(container, name);
}

void medTabbedViewContainers::insertContainer(int index, const QString &name, medViewContainer *container)
{
    if (!container)
        return;

    d->containers[name] = container;

    connect( container, SIGNAL( focused( dtkAbstractView * ) ),
             this,      SIGNAL( focused( dtkAbstractView * ) ) );
    connect( container, SIGNAL( dropped( const medDataIndex & ) ),
             this,      SIGNAL( dropped( const medDataIndex & ) ) );

    connect( container, SIGNAL( viewAdded( dtkAbstractView * ) ),
             this,      SIGNAL( viewAdded( dtkAbstractView * ) ) );
    connect( container, SIGNAL( viewRemoved( dtkAbstractView * ) ),
             this,      SIGNAL( viewRemoved( dtkAbstractView * ) ) );

    if (!this->count())
        d->currentName = name;
    this->insertTab(index,container, name);
}

void medTabbedViewContainers::changeCurrentContainerType(const QString &name)
{
    //qDebug() << "Changing container type to " << name << " from " << this->current()->description();
    //qDebug() << "Current index is " << this->currentIndex() << " and tab name " << this->tabText(this->currentIndex());

    if ((!this->current()->views().isEmpty()) && (name != this->current()->description()))
    {
        QMessageBox msgBox ( this );
        msgBox.setIcon ( QMessageBox::Warning );
        msgBox.setText(tr("Current tab is not empty. Changing tab type will delete current views."));
        msgBox.setInformativeText(tr("Are you sure you wish to change tab type?"));
        msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
        msgBox.setDefaultButton(QMessageBox::No);
        int reply = msgBox.exec();

        if( reply == QMessageBox::No )
        {
            this->onCurrentContainerChanged(this->currentIndex());
            return;
        }
    }

    if (name != this->current()->description())
    {
        medViewContainer *newTab = NULL;
        if (name == "Single")
            newTab = new medViewContainerSingle();
        else if (name == "Custom")
            newTab = new medViewContainerCustom();
        else if (name == "Multi")
            newTab = new medViewContainerMulti();

        if (newTab != NULL)
        {
            this->blockSignals(true);
            int index = this->currentIndex();
            QString tabName = this->tabText(index);
            this->removeTab(index);
            this->insertContainer(index,tabName,newTab);
            this->setCurrentIndex(index);
            this->blockSignals(false);

            this->onCurrentContainerChanged(index);
        }
    }
}

medViewContainer* medTabbedViewContainers::container(const QString &name) const
{
    if (!d->containers.contains(name))
        return NULL;

    return d->containers[name];
}

void medTabbedViewContainers::setContainer(const QString &name)
{
    if (!d->containers.contains(name))
    {
        qWarning()<<"container does not contain any container of name:" << name;
        return;
    }

    d->currentName = name;
    this->setCurrentWidget(d->containers[name]);
}

medViewContainer *medTabbedViewContainers::current(void) const
{
    return dynamic_cast<medViewContainer*> (currentWidget());
}

QString medTabbedViewContainers::currentName(void) const
{
    return d->currentName;
}

QList<QString> medTabbedViewContainers::keys()
{
    return d->containers.keys();
}

void medTabbedViewContainers::removeContainer(const QString& name)
{
    if (d->containers.contains(name))
    {
        medViewContainer* container = d->containers[name];
        //removeWidget(container);
        delete container;
        d->containers.remove(name);
    }
}

void medTabbedViewContainers::onCurrentContainerChanged(int index)
{
    QString name = this->tabText(index);
    emit currentChanged(name);
}
<|endoftext|>


<commit_before>#include "kvazaarfilter.h"

#include "statisticsinterface.h"

#include "common.h"
#include "settingskeys.h"
#include "logger.h"

#include <kvazaar.h>

#include <QtDebug>
#include <QTime>
#include <QSize>

enum RETURN_STATUS {C_SUCCESS = 0, C_FAILURE = -1};

KvazaarFilter::KvazaarFilter(QString id, StatisticsInterface *stats,
                             std::shared_ptr<ResourceAllocator> hwResources):
  Filter(id, "Kvazaar", stats, hwResources, DT_YUV420VIDEO, DT_HEVCVIDEO),
  api_(nullptr),
  config_(nullptr),
  enc_(nullptr),
  pts_(0),
  input_pic_(nullptr),
  framerate_num_(30),
  framerate_denom_(1),
  encodingFrames_()
{
  maxBufferSize_ = 3;
}

void KvazaarFilter::updateSettings()
{
  Logger::getLogger()->printNormal(this, "Updating kvazaar settings");

  stop();

  while(isRunning())
  {
    sleep(1);
  }

  close();
  encodingFrames_.clear();

  if(init())
  {
    Logger::getLogger()->printNormal(this, "Resolution change successful");
  }
  else
  {
    Logger::getLogger()->printNormal(this, "Failed to change resolution");
  }

  start();

  Filter::updateSettings();
}

bool KvazaarFilter::init()
{
  Logger::getLogger()->printNormal(this, "Iniating Kvazaar");

  // input picture should not exist at this point
  if(!input_pic_ && !api_)
  {

    api_ = kvz_api_get(8);
    if(!api_)
    {
      Logger::getLogger()->printDebug(DEBUG_PROGRAM_ERROR, this, "Failed to retrieve Kvazaar API.");
      return false;
    }
    config_ = api_->config_alloc();
    enc_ = nullptr;

    if(!config_)
    {
      Logger::getLogger()->printDebug(DEBUG_PROGRAM_ERROR, this, "Failed to allocate Kvazaar config.");
      return false;
    }

    api_->config_init(config_);

    QSettings settings(settingsFile, settingsFileFormat);

    QString preset = settings.value(SettingsKey::videoPreset).toString().toUtf8();

    QString resolutionStr = settings.value(SettingsKey::videoResultionWidth).toString() + "x" +
        settings.value(SettingsKey::videoResultionHeight).toString();

    convertFramerate(settings.value(SettingsKey::videoFramerate).toReal());
    QString framerate = QString::number(framerate_num_) + "/" + QString::number(framerate_denom_);

#ifdef __linux__
    if (!settingEnabled(SettingsKey::screenShareStatus))
    {
      // On Linux the QCamera doesn't seem to work correctly, expect with these values
      resolutionStr = QString::number(640) + "x" + QString::number(480);
      framerate = QString::number(30) + "/" + QString::number(1);
    }
#endif

    // Input

    api_->config_parse(config_, "preset",    preset.toLocal8Bit());
    api_->config_parse(config_, "input-res", resolutionStr.toLocal8Bit());
    api_->config_parse(config_, "input-fps", framerate.toLocal8Bit());

    QString threads = "0";

    // parallelization
    if (settings.value(SettingsKey::videoKvzThreads) == "auto")
    {
      threads = QString::number(QThread::idealThreadCount());
    }
    else if (settings.value(SettingsKey::videoKvzThreads) == "Main")
    {
      threads = QString::number(0);
    }
    else
    {
      threads = settings.value(SettingsKey::videoKvzThreads).toString();
    }

    api_->config_parse(config_, "threads", threads.toLocal8Bit());
    api_->config_parse(config_, "owf", settings.value(SettingsKey::videoOWF).toString().toLocal8Bit());
    api_->config_parse(config_, "wpp", settings.value(SettingsKey::videoWPP).toString().toLocal8Bit());

    bool tiles = settings.value(SettingsKey::videoTiles).toBool();

    if (tiles)
    {
      std::string dimensions = settings.value(SettingsKey::videoTileDimensions).toString().toStdString();
      api_->config_parse(config_, "tiles", dimensions.c_str());
    }

    // this does not work with uvgRTP at the moment. Avoid using slices.
    if(settings.value(SettingsKey::videoSlices).toInt() == 1)
    {
      if(config_->wpp)
      {
        api_->config_parse(config_, "slices", "wpp");
      }
      else if (tiles)
      {
        api_->config_parse(config_, "slices", "tiles");
      }
    }

    // Video structure

    api_->config_parse(config_, "qp",         settings.value(SettingsKey::videoQP).toString().toLocal8Bit());
    api_->config_parse(config_, "period",     settings.value(SettingsKey::videoIntra).toString().toLocal8Bit());
    api_->config_parse(config_, "vps-period", settings.value(SettingsKey::videoVPS).toString().toLocal8Bit());

    config_->target_bitrate = settings.value(SettingsKey::videoBitrate).toInt();

    if (config_->target_bitrate != 0)
    {
      api_->config_parse(config_, "rc-algorithm",    settings.value(SettingsKey::videoRCAlgorithm).toString().toLocal8Bit());
    }

    // TODO: Move to settings
    api_->config_parse(config_, "gop", "lp-g4d3t1");

    if (settings.value(SettingsKey::videoScalingList).toInt() == 0)
    {
      api_->config_parse(config_, "scaling-list", "off");
    }
    else
    {
      api_->config_parse(config_, "scaling-list", "default");
    }

    config_->lossless = settings.value(SettingsKey::videoLossless).toInt();

    QString constraint = settings.value(SettingsKey::videoMVConstraint).toString();

    if (constraint == "frame" || constraint == "frametile" || constraint == "frametilemargin")
    {
      api_->config_parse(config_, "mv-constraint", "");
    }
    else
    {
      api_->config_parse(config_, "mv-constraint", "none");
    }

    if (constraint == "frame")
    {
      config_->mv_constraint = KVZ_MV_CONSTRAIN_FRAME;
    }
    else if (constraint == "tile")
    {
      config_->mv_constraint = KVZ_MV_CONSTRAIN_TILE;
    }
    else if (constraint == "frametile")
    {
      config_->mv_constraint = KVZ_MV_CONSTRAIN_FRAME_AND_TILE;
    }
    else if (constraint == "frametilemargin")
    {
      config_->mv_constraint = KVZ_MV_CONSTRAIN_FRAME_AND_TILE_MARGIN;
    }
    else
    {
      config_->mv_constraint = KVZ_MV_CONSTRAIN_NONE;
    }

    config_->set_qp_in_cu = settings.value(SettingsKey::videoQPInCU).toInt();

    int vaq = settings.value(SettingsKey::videoVAQ).toInt();
    if (vaq > 0 && vaq <= 20)
    {
      api_->config_parse(config_, "vaq", settings.value(SettingsKey::videoVAQ).toString().toLocal8Bit());
    }

    // compression-tab
    customParameters(settings);

    config_->hash = KVZ_HASH_NONE;

    enc_ = api_->encoder_open(config_);

    if(!enc_)
    {
      Logger::getLogger()->printDebug(DEBUG_PROGRAM_ERROR, this, "Failed to open Kvazaar encoder.");
      return false;
    }

    input_pic_ = api_->picture_alloc(config_->width, config_->height);

    if(!input_pic_)
    {
      Logger::getLogger()->printDebug(DEBUG_PROGRAM_ERROR, this, "Could not allocate input picture.");
      return false;
    }

    Logger::getLogger()->printNormal(this, "Kvazaar iniation succeeded");
  }

  return true;
}

void KvazaarFilter::close()
{
  if(api_)
  {
    api_->encoder_close(enc_);
    api_->config_destroy(config_);
    enc_ = nullptr;
    config_ = nullptr;

    api_->picture_free(input_pic_);
    input_pic_ = nullptr;
    api_ = nullptr;
  }

  pts_ = 0;

  Logger::getLogger()->printNormal(this, "Closed Kvazaar");
}

void KvazaarFilter::process()
{
  Q_ASSERT(enc_);
  Q_ASSERT(config_);

  std::unique_ptr<Data> input = getInput();

  while(input)
  {
    if(!input_pic_)
    {
      Logger::getLogger()->printDebug(DEBUG_PROGRAM_ERROR, this,
                                      "Input picture was not allocated correctly.");
      break;
    }

    feedInput(std::move(input));

    input = getInput();
  }
}

void KvazaarFilter::customParameters(QSettings& settings)
{
  int size = settings.beginReadArray(SettingsKey::videoCustomParameters);

  Logger::getLogger()->printNormal(this, "Getting custom Kvazaar parameters",
                                   "Amount", QString::number(size));

  for(int i = 0; i < size; ++i)
  {
    settings.setArrayIndex(i);
    QString name = settings.value("Name").toString();
    QString value = settings.value("Value").toString();
    if (api_->config_parse(config_, name.toStdString().c_str(),
                           value.toStdString().c_str()) != 1)
    {
      Logger::getLogger()->printWarning(this, "Invalid custom parameter for kvazaar",
                                        "Amount", QString::number(size));
    }
  }
  settings.endArray();
}

void KvazaarFilter::feedInput(std::unique_ptr<Data> input)
{
  kvz_picture *recon_pic = nullptr;
  kvz_frame_info frame_info;
  kvz_data_chunk *data_out = nullptr;
  uint32_t len_out = 0;

  if (config_->width != input->vInfo->width
      || config_->height != input->vInfo->height
      || (double)(config_->framerate_num/config_->framerate_denom) != input->vInfo->framerate)
  {
    // This should not happen.
    Logger::getLogger()->printDebug(DEBUG_PROGRAM_ERROR, this,
                                    "Input resolution or framerate differs from settings",
                                    {"Settings", "Input"},
                                    {QString::number(config_->width) + "x" +
                                     QString::number(config_->height) + "p" +
                                     QString::number(config_->framerate_num),
                                     QString::number(input->vInfo->width) + "x" +
                                     QString::number(input->vInfo->height) + "p" +
                                     QString::number(input->vInfo->framerate)});

    return;
  }

  // copy input to kvazaar picture
  memcpy(input_pic_->y,
         input->data.get(),
         input->vInfo->width*input->vInfo->height);
  memcpy(input_pic_->u,
         &(input->data.get()[input->vInfo->width*input->vInfo->height]),
         input->vInfo->width*input->vInfo->height/4);
  memcpy(input_pic_->v,
         &(input->data.get()[input->vInfo->width*input->vInfo->height + input->vInfo->width*input->vInfo->height/4]),
         input->vInfo->width*input->vInfo->height/4);

  input_pic_->pts = pts_;
  ++pts_;

  encodingFrames_.push_front(std::move(input));

  api_->encoder_encode(enc_, input_pic_,
                       &data_out, &len_out,
                       &recon_pic, nullptr,
                       &frame_info );

  while(data_out != nullptr)
  {
    parseEncodedFrame(data_out, len_out, recon_pic);

    // see if there is more output ready
    api_->encoder_encode(enc_, nullptr,
                         &data_out, &len_out,
                         &recon_pic, nullptr,
                         &frame_info );
  }
}

void KvazaarFilter::parseEncodedFrame(kvz_data_chunk *data_out,
                                      uint32_t len_out, kvz_picture *recon_pic)
{
  std::unique_ptr<Data> encodedFrame = std::move(encodingFrames_.back());
  encodingFrames_.pop_back();

  std::unique_ptr<uchar[]> hevc_frame(new uchar[len_out]);
  uint8_t* writer = hevc_frame.get();
  uint32_t dataWritten = 0;

  for (kvz_data_chunk *chunk = data_out; chunk != nullptr; chunk = chunk->next)
  {
    if(chunk->len > 3 && chunk->data[0] == 0 && chunk->data[1] == 0
       && ( chunk->data[2] == 1 || (chunk->data[2] == 0 && chunk->data[3] == 1 ))
       && dataWritten != 0 && config_->slices != KVZ_SLICES_NONE)
    {
      // send previous packet if this is not the first
      std::unique_ptr<Data> slice(shallowDataCopy(encodedFrame.get()));

      sendEncodedFrame(std::move(slice), std::move(hevc_frame), dataWritten);

      hevc_frame = std::unique_ptr<uchar[]>(new uchar[len_out - dataWritten]);
      writer = hevc_frame.get();
      dataWritten = 0;
    }

    memcpy(writer, chunk->data, chunk->len);
    writer += chunk->len;
    dataWritten += chunk->len;
  }
  api_->chunk_free(data_out);
  api_->picture_free(recon_pic);

  uint32_t delay = QDateTime::currentMSecsSinceEpoch() - encodedFrame->presentationTime;
  getStats()->sendDelay("video", delay);
  getStats()->addEncodedPacket("video", len_out);

  // send last packet reusing input structure
  sendEncodedFrame(std::move(encodedFrame), std::move(hevc_frame), dataWritten);
}

void KvazaarFilter::sendEncodedFrame(std::unique_ptr<Data> input,
                                     std::unique_ptr<uchar[]> hevc_frame,
                                     uint32_t dataWritten)
{
  input->type = DT_HEVCVIDEO;
  input->data_size = dataWritten;
  input->data = std::move(hevc_frame);
  sendOutput(std::move(input));
}

void KvazaarFilter::convertFramerate(double framerate)
{
  uint32_t wholeNumber = (uint32_t)framerate;

  double remainder = framerate - wholeNumber;

  if (remainder > 0.0)
  {
    uint32_t multiplier = 1.0 /remainder;
    framerate_num_ = framerate*multiplier;
    framerate_denom_ = multiplier;
  }
  else
  {
    framerate_num_ = wholeNumber;
    framerate_denom_ = 1;
  }

  Logger::getLogger()->printNormal(this, "Got framerate num and denum", "Framerate",
                                   {QString::number(framerate_num_) + "/" +
                                    QString::number(framerate_denom_) });
}
<commit_msg>refactor(Processing): Add check for sensible Settings values<commit_after>#include "kvazaarfilter.h"

#include "statisticsinterface.h"

#include "common.h"
#include "settingskeys.h"
#include "logger.h"

#include <kvazaar.h>

#include <QtDebug>
#include <QTime>
#include <QSize>

enum RETURN_STATUS {C_SUCCESS = 0, C_FAILURE = -1};

KvazaarFilter::KvazaarFilter(QString id, StatisticsInterface *stats,
                             std::shared_ptr<ResourceAllocator> hwResources):
  Filter(id, "Kvazaar", stats, hwResources, DT_YUV420VIDEO, DT_HEVCVIDEO),
  api_(nullptr),
  config_(nullptr),
  enc_(nullptr),
  pts_(0),
  input_pic_(nullptr),
  framerate_num_(30),
  framerate_denom_(1),
  encodingFrames_()
{
  maxBufferSize_ = 3;
}

void KvazaarFilter::updateSettings()
{
  Logger::getLogger()->printNormal(this, "Updating kvazaar settings");

  stop();

  while(isRunning())
  {
    sleep(1);
  }

  close();
  encodingFrames_.clear();

  if(init())
  {
    Logger::getLogger()->printNormal(this, "Resolution change successful");
  }
  else
  {
    Logger::getLogger()->printNormal(this, "Failed to change resolution");
  }

  start();

  Filter::updateSettings();
}

bool KvazaarFilter::init()
{
  Logger::getLogger()->printNormal(this, "Iniating Kvazaar");

  // input picture should not exist at this point
  if(!input_pic_ && !api_)
  {
    QSettings settings(settingsFile, settingsFileFormat);

    if (settings.value(SettingsKey::videoResultionWidth).toInt() == 0 ||
        settings.value(SettingsKey::videoResultionHeight).toInt() == 0 ||
        settings.value(SettingsKey::videoFramerate).toReal() == 0.0)
    {
      Logger::getLogger()->printDebug(DEBUG_PROGRAM_ERROR, this, "Invalid values in settings",
                                      {"Width", "Height", "Framerate"},
                                      {settings.value(SettingsKey::videoResultionWidth).toString(),
                                       settings.value(SettingsKey::videoResultionHeight).toString(),
                                       settings.value(SettingsKey::videoFramerate).toString()});
      return false;
    }

    api_ = kvz_api_get(8);
    if(!api_)
    {
      Logger::getLogger()->printDebug(DEBUG_PROGRAM_ERROR, this, "Failed to retrieve Kvazaar API.");
      return false;
    }
    config_ = api_->config_alloc();
    enc_ = nullptr;

    if(!config_)
    {
      Logger::getLogger()->printDebug(DEBUG_PROGRAM_ERROR, this, "Failed to allocate Kvazaar config.");
      return false;
    }

    api_->config_init(config_);

    QString preset = settings.value(SettingsKey::videoPreset).toString().toUtf8();

    QString resolutionStr = settings.value(SettingsKey::videoResultionWidth).toString() + "x" +
        settings.value(SettingsKey::videoResultionHeight).toString();

    convertFramerate(settings.value(SettingsKey::videoFramerate).toReal());
    QString framerate = QString::number(framerate_num_) + "/" + QString::number(framerate_denom_);

#ifdef __linux__
    if (!settingEnabled(SettingsKey::screenShareStatus))
    {
      // On Linux the QCamera doesn't seem to work correctly, expect with these values
      resolutionStr = QString::number(640) + "x" + QString::number(480);
      framerate = QString::number(30) + "/" + QString::number(1);
    }
#endif

    // Input

    api_->config_parse(config_, "preset",    preset.toLocal8Bit());
    api_->config_parse(config_, "input-res", resolutionStr.toLocal8Bit());
    api_->config_parse(config_, "input-fps", framerate.toLocal8Bit());

    QString threads = "0";

    // parallelization
    if (settings.value(SettingsKey::videoKvzThreads) == "auto")
    {
      threads = QString::number(QThread::idealThreadCount());
    }
    else if (settings.value(SettingsKey::videoKvzThreads) == "Main")
    {
      threads = QString::number(0);
    }
    else
    {
      threads = settings.value(SettingsKey::videoKvzThreads).toString();
    }

    api_->config_parse(config_, "threads", threads.toLocal8Bit());
    api_->config_parse(config_, "owf", settings.value(SettingsKey::videoOWF).toString().toLocal8Bit());
    api_->config_parse(config_, "wpp", settings.value(SettingsKey::videoWPP).toString().toLocal8Bit());

    bool tiles = settings.value(SettingsKey::videoTiles).toBool();

    if (tiles)
    {
      std::string dimensions = settings.value(SettingsKey::videoTileDimensions).toString().toStdString();
      api_->config_parse(config_, "tiles", dimensions.c_str());
    }

    // this does not work with uvgRTP at the moment. Avoid using slices.
    if(settings.value(SettingsKey::videoSlices).toInt() == 1)
    {
      if(config_->wpp)
      {
        api_->config_parse(config_, "slices", "wpp");
      }
      else if (tiles)
      {
        api_->config_parse(config_, "slices", "tiles");
      }
    }

    // Video structure

    api_->config_parse(config_, "qp",         settings.value(SettingsKey::videoQP).toString().toLocal8Bit());
    api_->config_parse(config_, "period",     settings.value(SettingsKey::videoIntra).toString().toLocal8Bit());
    api_->config_parse(config_, "vps-period", settings.value(SettingsKey::videoVPS).toString().toLocal8Bit());

    config_->target_bitrate = settings.value(SettingsKey::videoBitrate).toInt();

    if (config_->target_bitrate != 0)
    {
      api_->config_parse(config_, "rc-algorithm",    settings.value(SettingsKey::videoRCAlgorithm).toString().toLocal8Bit());
    }

    // TODO: Move to settings
    api_->config_parse(config_, "gop", "lp-g4d3t1");

    if (settings.value(SettingsKey::videoScalingList).toInt() == 0)
    {
      api_->config_parse(config_, "scaling-list", "off");
    }
    else
    {
      api_->config_parse(config_, "scaling-list", "default");
    }

    config_->lossless = settings.value(SettingsKey::videoLossless).toInt();

    QString constraint = settings.value(SettingsKey::videoMVConstraint).toString();

    if (constraint == "frame" || constraint == "frametile" || constraint == "frametilemargin")
    {
      api_->config_parse(config_, "mv-constraint", "");
    }
    else
    {
      api_->config_parse(config_, "mv-constraint", "none");
    }

    if (constraint == "frame")
    {
      config_->mv_constraint = KVZ_MV_CONSTRAIN_FRAME;
    }
    else if (constraint == "tile")
    {
      config_->mv_constraint = KVZ_MV_CONSTRAIN_TILE;
    }
    else if (constraint == "frametile")
    {
      config_->mv_constraint = KVZ_MV_CONSTRAIN_FRAME_AND_TILE;
    }
    else if (constraint == "frametilemargin")
    {
      config_->mv_constraint = KVZ_MV_CONSTRAIN_FRAME_AND_TILE_MARGIN;
    }
    else
    {
      config_->mv_constraint = KVZ_MV_CONSTRAIN_NONE;
    }

    config_->set_qp_in_cu = settings.value(SettingsKey::videoQPInCU).toInt();

    int vaq = settings.value(SettingsKey::videoVAQ).toInt();
    if (vaq > 0 && vaq <= 20)
    {
      api_->config_parse(config_, "vaq", settings.value(SettingsKey::videoVAQ).toString().toLocal8Bit());
    }

    // compression-tab
    customParameters(settings);

    config_->hash = KVZ_HASH_NONE;

    enc_ = api_->encoder_open(config_);

    if(!enc_)
    {
      Logger::getLogger()->printDebug(DEBUG_PROGRAM_ERROR, this, "Failed to open Kvazaar encoder.");
      return false;
    }

    input_pic_ = api_->picture_alloc(config_->width, config_->height);

    if(!input_pic_)
    {
      Logger::getLogger()->printDebug(DEBUG_PROGRAM_ERROR, this, "Could not allocate input picture.");
      return false;
    }

    Logger::getLogger()->printNormal(this, "Kvazaar iniation succeeded");
  }

  return true;
}

void KvazaarFilter::close()
{
  if(api_)
  {
    api_->encoder_close(enc_);
    api_->config_destroy(config_);
    enc_ = nullptr;
    config_ = nullptr;

    api_->picture_free(input_pic_);
    input_pic_ = nullptr;
    api_ = nullptr;
  }

  pts_ = 0;

  Logger::getLogger()->printNormal(this, "Closed Kvazaar");
}

void KvazaarFilter::process()
{
  Q_ASSERT(enc_);
  Q_ASSERT(config_);

  std::unique_ptr<Data> input = getInput();

  while(input)
  {
    if(!input_pic_)
    {
      Logger::getLogger()->printDebug(DEBUG_PROGRAM_ERROR, this,
                                      "Input picture was not allocated correctly.");
      break;
    }

    feedInput(std::move(input));

    input = getInput();
  }
}

void KvazaarFilter::customParameters(QSettings& settings)
{
  int size = settings.beginReadArray(SettingsKey::videoCustomParameters);

  Logger::getLogger()->printNormal(this, "Getting custom Kvazaar parameters",
                                   "Amount", QString::number(size));

  for(int i = 0; i < size; ++i)
  {
    settings.setArrayIndex(i);
    QString name = settings.value("Name").toString();
    QString value = settings.value("Value").toString();
    if (api_->config_parse(config_, name.toStdString().c_str(),
                           value.toStdString().c_str()) != 1)
    {
      Logger::getLogger()->printWarning(this, "Invalid custom parameter for kvazaar",
                                        "Amount", QString::number(size));
    }
  }
  settings.endArray();
}

void KvazaarFilter::feedInput(std::unique_ptr<Data> input)
{
  kvz_picture *recon_pic = nullptr;
  kvz_frame_info frame_info;
  kvz_data_chunk *data_out = nullptr;
  uint32_t len_out = 0;

  if (config_->width != input->vInfo->width
      || config_->height != input->vInfo->height
      || (double)(config_->framerate_num/config_->framerate_denom) != input->vInfo->framerate)
  {
    // This should not happen.
    Logger::getLogger()->printDebug(DEBUG_PROGRAM_ERROR, this,
                                    "Input resolution or framerate differs from settings",
                                    {"Settings", "Input"},
                                    {QString::number(config_->width) + "x" +
                                     QString::number(config_->height) + "p" +
                                     QString::number(config_->framerate_num),
                                     QString::number(input->vInfo->width) + "x" +
                                     QString::number(input->vInfo->height) + "p" +
                                     QString::number(input->vInfo->framerate)});

    return;
  }

  // copy input to kvazaar picture
  memcpy(input_pic_->y,
         input->data.get(),
         input->vInfo->width*input->vInfo->height);
  memcpy(input_pic_->u,
         &(input->data.get()[input->vInfo->width*input->vInfo->height]),
         input->vInfo->width*input->vInfo->height/4);
  memcpy(input_pic_->v,
         &(input->data.get()[input->vInfo->width*input->vInfo->height + input->vInfo->width*input->vInfo->height/4]),
         input->vInfo->width*input->vInfo->height/4);

  input_pic_->pts = pts_;
  ++pts_;

  encodingFrames_.push_front(std::move(input));

  api_->encoder_encode(enc_, input_pic_,
                       &data_out, &len_out,
                       &recon_pic, nullptr,
                       &frame_info );

  while(data_out != nullptr)
  {
    parseEncodedFrame(data_out, len_out, recon_pic);

    // see if there is more output ready
    api_->encoder_encode(enc_, nullptr,
                         &data_out, &len_out,
                         &recon_pic, nullptr,
                         &frame_info );
  }
}

void KvazaarFilter::parseEncodedFrame(kvz_data_chunk *data_out,
                                      uint32_t len_out, kvz_picture *recon_pic)
{
  std::unique_ptr<Data> encodedFrame = std::move(encodingFrames_.back());
  encodingFrames_.pop_back();

  std::unique_ptr<uchar[]> hevc_frame(new uchar[len_out]);
  uint8_t* writer = hevc_frame.get();
  uint32_t dataWritten = 0;

  for (kvz_data_chunk *chunk = data_out; chunk != nullptr; chunk = chunk->next)
  {
    if(chunk->len > 3 && chunk->data[0] == 0 && chunk->data[1] == 0
       && ( chunk->data[2] == 1 || (chunk->data[2] == 0 && chunk->data[3] == 1 ))
       && dataWritten != 0 && config_->slices != KVZ_SLICES_NONE)
    {
      // send previous packet if this is not the first
      std::unique_ptr<Data> slice(shallowDataCopy(encodedFrame.get()));

      sendEncodedFrame(std::move(slice), std::move(hevc_frame), dataWritten);

      hevc_frame = std::unique_ptr<uchar[]>(new uchar[len_out - dataWritten]);
      writer = hevc_frame.get();
      dataWritten = 0;
    }

    memcpy(writer, chunk->data, chunk->len);
    writer += chunk->len;
    dataWritten += chunk->len;
  }
  api_->chunk_free(data_out);
  api_->picture_free(recon_pic);

  uint32_t delay = QDateTime::currentMSecsSinceEpoch() - encodedFrame->presentationTime;
  getStats()->sendDelay("video", delay);
  getStats()->addEncodedPacket("video", len_out);

  // send last packet reusing input structure
  sendEncodedFrame(std::move(encodedFrame), std::move(hevc_frame), dataWritten);
}

void KvazaarFilter::sendEncodedFrame(std::unique_ptr<Data> input,
                                     std::unique_ptr<uchar[]> hevc_frame,
                                     uint32_t dataWritten)
{
  input->type = DT_HEVCVIDEO;
  input->data_size = dataWritten;
  input->data = std::move(hevc_frame);
  sendOutput(std::move(input));
}

void KvazaarFilter::convertFramerate(double framerate)
{
  uint32_t wholeNumber = (uint32_t)framerate;

  double remainder = framerate - wholeNumber;

  if (remainder > 0.0)
  {
    uint32_t multiplier = 1.0 /remainder;
    framerate_num_ = framerate*multiplier;
    framerate_denom_ = multiplier;
  }
  else
  {
    framerate_num_ = wholeNumber;
    framerate_denom_ = 1;
  }

  Logger::getLogger()->printNormal(this, "Got framerate num and denum", "Framerate",
                                   {QString::number(framerate_num_) + "/" +
                                    QString::number(framerate_denom_) });
}
<|endoftext|>


<commit_before>/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

 Module:       FGAccelerometer.cpp
 Author:       Jon Berndt
 Date started: 9 July 2005

 ------------- Copyright (C) 2005 -------------

 This program is free software; you can redistribute it and/or modify it under
 the terms of the GNU Lesser General Public License as published by the Free Software
 Foundation; either version 2 of the License, or (at your option) any later
 version.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
 details.

 You should have received a copy of the GNU Lesser General Public License along with
 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 Place - Suite 330, Boston, MA  02111-1307, USA.

 Further information about the GNU Lesser General Public License can also be found on
 the world wide web at http://www.gnu.org.

FUNCTIONAL DESCRIPTION
--------------------------------------------------------------------------------

HISTORY
--------------------------------------------------------------------------------

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
COMMENTS, REFERENCES,  and NOTES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/

#include <iostream>
#include <cstdlib>

#include "FGAccelerometer.h"
#include "models/FGPropagate.h"
#include "models/FGAccelerations.h"
#include "models/FGMassBalance.h"
#include "input_output/FGXMLElement.h"
#include "models/FGFCS.h"

using namespace std;

namespace JSBSim {

IDENT(IdSrc,"$Id: FGAccelerometer.cpp,v 1.16 2015/07/12 19:34:08 bcoconni Exp $");
IDENT(IdHdr,ID_ACCELEROMETER);

/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS IMPLEMENTATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/

FGAccelerometer::FGAccelerometer(FGFCS* fcs, Element* element)
  : FGSensor(fcs, element),
    FGSensorOrientation(element)
{
  Propagate = fcs->GetExec()->GetPropagate();
  Accelerations = fcs->GetExec()->GetAccelerations();
  MassBalance = fcs->GetExec()->GetMassBalance();

  Element* location_element = element->FindElement("location");
  if (location_element) vLocation = location_element->FindElementTripletConvertTo("IN");
  else {cerr << "No location given for accelerometer. " << endl; exit(-1);}

  vRadius = MassBalance->StructuralToBody(vLocation);

  Debug(0);
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

FGAccelerometer::~FGAccelerometer()
{
  Debug(1);
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

bool FGAccelerometer::Run(void )
{
  // There is no input assumed. This is a dedicated acceleration sensor.

  vRadius = MassBalance->StructuralToBody(vLocation);

  //aircraft forces
  vAccel = (Accelerations->GetBodyAccel()
              + Propagate->GetTi2b() * Accelerations->GetGravAccel()
              + Accelerations->GetPQRdot() * vRadius
              + Propagate->GetPQR() * (Propagate->GetPQR() * vRadius));

  // transform to the specified orientation
  vAccel = mT * vAccel;

  Input = vAccel(axis);

  ProcessSensorSignal();

  if (IsOutput) SetOutput();

  return true;
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//    The bitmasked value choices are as follows:
//    unset: In this case (the default) JSBSim would only print
//       out the normally expected messages, essentially echoing
//       the config files as they are read. If the environment
//       variable is not set, debug_lvl is set to 1 internally
//    0: This requests JSBSim not to output any messages
//       whatsoever.
//    1: This value explicity requests the normal JSBSim
//       startup messages
//    2: This value asks for a message to be printed out when
//       a class is instantiated
//    4: When this value is set, a message is displayed when a
//       FGModel object executes its Run() method
//    8: When this value is set, various runtime state variables
//       are printed out periodically
//    16: When set various parameters are sanity checked and
//       a message is printed out when they go out of bounds

void FGAccelerometer::Debug(int from)
{
  string ax[4] = {"none", "X", "Y", "Z"};

  if (debug_lvl <= 0) return;

  if (debug_lvl & 1) { // Standard console startup message output
    if (from == 0) { // Constructor
      cout << "        Axis: " << ax[axis] << endl;
    }
  }
  if (debug_lvl & 2 ) { // Instantiation/Destruction notification
    if (from == 0) cout << "Instantiated: FGAccelerometer" << endl;
    if (from == 1) cout << "Destroyed:    FGAccelerometer" << endl;
  }
  if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
  }
  if (debug_lvl & 8 ) { // Runtime state variables
  }
  if (debug_lvl & 16) { // Sanity checking
  }
  if (debug_lvl & 64) {
    if (from == 0) { // Constructor
      cout << IdSrc << endl;
      cout << IdHdr << endl;
    }
  }
}
}
<commit_msg>Fixed the accelerometer that wrongly summed the gravity twice. It also overlooked the fact that (p,q,r) == (0,0,0) does not mean that (pi,qi,ri) == (0,0,0). As a consequence a centrifugal acceleration exists (albeit small) when (p,q,r) == (0,0,0). Bonus : the formula is now very similar to the acceleration at the pilot location (see FGAuxiliary.cpp)<commit_after>/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

 Module:       FGAccelerometer.cpp
 Author:       Jon Berndt
 Date started: 9 July 2005

 ------------- Copyright (C) 2005 -------------

 This program is free software; you can redistribute it and/or modify it under
 the terms of the GNU Lesser General Public License as published by the Free Software
 Foundation; either version 2 of the License, or (at your option) any later
 version.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
 details.

 You should have received a copy of the GNU Lesser General Public License along with
 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 Place - Suite 330, Boston, MA  02111-1307, USA.

 Further information about the GNU Lesser General Public License can also be found on
 the world wide web at http://www.gnu.org.

FUNCTIONAL DESCRIPTION
--------------------------------------------------------------------------------

HISTORY
--------------------------------------------------------------------------------

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
COMMENTS, REFERENCES,  and NOTES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/

#include <iostream>
#include <cstdlib>

#include "FGAccelerometer.h"
#include "models/FGPropagate.h"
#include "models/FGAccelerations.h"
#include "models/FGMassBalance.h"
#include "input_output/FGXMLElement.h"
#include "models/FGFCS.h"

using namespace std;

namespace JSBSim {

IDENT(IdSrc,"$Id: FGAccelerometer.cpp,v 1.17 2015/08/09 17:29:48 bcoconni Exp $");
IDENT(IdHdr,ID_ACCELEROMETER);

/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS IMPLEMENTATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/

FGAccelerometer::FGAccelerometer(FGFCS* fcs, Element* element)
  : FGSensor(fcs, element),
    FGSensorOrientation(element)
{
  Propagate = fcs->GetExec()->GetPropagate();
  Accelerations = fcs->GetExec()->GetAccelerations();
  MassBalance = fcs->GetExec()->GetMassBalance();

  Element* location_element = element->FindElement("location");
  if (location_element) vLocation = location_element->FindElementTripletConvertTo("IN");
  else {cerr << "No location given for accelerometer. " << endl; exit(-1);}

  vRadius = MassBalance->StructuralToBody(vLocation);

  Debug(0);
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

FGAccelerometer::~FGAccelerometer()
{
  Debug(1);
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

bool FGAccelerometer::Run(void )
{
  // There is no input assumed. This is a dedicated acceleration sensor.

  vRadius = MassBalance->StructuralToBody(vLocation);

  //aircraft forces
  vAccel = (Accelerations->GetBodyAccel()
            + Accelerations->GetPQRidot() * vRadius
            + Propagate->GetPQRi() * (Propagate->GetPQRi() * vRadius));

  // transform to the specified orientation
  vAccel = mT * vAccel;

  Input = vAccel(axis);

  ProcessSensorSignal();

  if (IsOutput) SetOutput();

  return true;
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//    The bitmasked value choices are as follows:
//    unset: In this case (the default) JSBSim would only print
//       out the normally expected messages, essentially echoing
//       the config files as they are read. If the environment
//       variable is not set, debug_lvl is set to 1 internally
//    0: This requests JSBSim not to output any messages
//       whatsoever.
//    1: This value explicity requests the normal JSBSim
//       startup messages
//    2: This value asks for a message to be printed out when
//       a class is instantiated
//    4: When this value is set, a message is displayed when a
//       FGModel object executes its Run() method
//    8: When this value is set, various runtime state variables
//       are printed out periodically
//    16: When set various parameters are sanity checked and
//       a message is printed out when they go out of bounds

void FGAccelerometer::Debug(int from)
{
  string ax[4] = {"none", "X", "Y", "Z"};

  if (debug_lvl <= 0) return;

  if (debug_lvl & 1) { // Standard console startup message output
    if (from == 0) { // Constructor
      cout << "        Axis: " << ax[axis] << endl;
    }
  }
  if (debug_lvl & 2 ) { // Instantiation/Destruction notification
    if (from == 0) cout << "Instantiated: FGAccelerometer" << endl;
    if (from == 1) cout << "Destroyed:    FGAccelerometer" << endl;
  }
  if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
  }
  if (debug_lvl & 8 ) { // Runtime state variables
  }
  if (debug_lvl & 16) { // Sanity checking
  }
  if (debug_lvl & 64) {
    if (from == 0) { // Constructor
      cout << IdSrc << endl;
      cout << IdHdr << endl;
    }
  }
}
}
<|endoftext|>