<commit_before>#pragma once

#include "physics/barycentric_rotating_dynamic_frame.hpp"

#include "geometry/named_quantities.hpp"
#include "geometry/r3x3_matrix.hpp"
#include "quantities/quantities.hpp"
#include "quantities/si.hpp"

namespace principia {

using geometry::Displacement;
using geometry::R3x3Matrix;
using geometry::Velocity;
using geometry::Wedge;
using quantities::Length;
using quantities::Pow;
using quantities::Product;
using quantities::Speed;

namespace physics {

template<typename InertialFrame, typename ThisFrame>
BarycentricRotatingDynamicFrame<InertialFrame, ThisFrame>::
BarycentricRotatingDynamicFrame(
    not_null<Ephemeris<InertialFrame> const*> const ephemeris,
    not_null<MassiveBody const*> const primary,
    not_null<MassiveBody const*> const secondary)
    : ephemeris_(ephemeris),
      primary_(primary),
      secondary_(secondary),
      primary_trajectory_(ephemeris_->trajectory(primary_)),
      secondary_trajectory_(ephemeris_->trajectory(secondary_)) {}

template<typename InertialFrame, typename ThisFrame>
RigidMotion<InertialFrame, ThisFrame>
BarycentricRotatingDynamicFrame<InertialFrame, ThisFrame>::ToThisFrameAtTime(
    Instant const& t) const {
  DegreesOfFreedom<InertialFrame> const primary_degrees_of_freedom =
      primary_trajectory_->EvaluateDegreesOfFreedom(t, &primary_hint_);
  DegreesOfFreedom<InertialFrame> const secondary_degrees_of_freedom =
      secondary_trajectory_->EvaluateDegreesOfFreedom(t, &secondary_hint_);
  DegreesOfFreedom<InertialFrame> const barycentre_degrees_of_freedom =
      Barycentre<InertialFrame, GravitationalParameter>(
          {primary_degrees_of_freedom,
           secondary_degrees_of_freedom},
          {primary_->gravitational_parameter(),
           secondary_->gravitational_parameter()});

  Rotation<InertialFrame, ThisFrame> rotation =
          Rotation<InertialFrame, ThisFrame>::Identity();
  AngularVelocity<InertialFrame> angular_velocity;
  ComputeAngularDegreesOfFreedom(primary_degrees_of_freedom,
                                 secondary_degrees_of_freedom,
                                 &rotation,
                                 &angular_velocity);

  RigidTransformation<InertialFrame, ThisFrame> const
      rigid_transformation(barycentre_degrees_of_freedom.position(),
                           ThisFrame::origin,
                           rotation.Forget());
  return RigidMotion<InertialFrame, ThisFrame>(
             rigid_transformation,
             angular_velocity,
             barycentre_degrees_of_freedom.velocity());
}

template<typename InertialFrame, typename ThisFrame>
RigidMotion<ThisFrame, InertialFrame>
BarycentricRotatingDynamicFrame<InertialFrame, ThisFrame>::
FromThisFrameAtTime(Instant const& t) const {
  return ToThisFrameAtTime(t).Inverse();
}

template<typename InertialFrame, typename ThisFrame>
Vector<Acceleration, ThisFrame>
BarycentricRotatingDynamicFrame<InertialFrame, ThisFrame>::
GeometricAcceleration(
    Instant const& t,
    DegreesOfFreedom<ThisFrame> const& degrees_of_freedom) const {
  auto const to_this_frame = ToThisFrameAtTime(t);
  auto const from_this_frame = to_this_frame.Inverse();

  DegreesOfFreedom<InertialFrame> const primary_degrees_of_freedom =
      primary_trajectory_->EvaluateDegreesOfFreedom(t, &primary_hint_);
  DegreesOfFreedom<InertialFrame> const secondary_degrees_of_freedom =
      secondary_trajectory_->EvaluateDegreesOfFreedom(t, &secondary_hint_);
  DegreesOfFreedom<InertialFrame> const barycentre_degrees_of_freedom =
      Barycentre<InertialFrame, GravitationalParameter>(
          {primary_degrees_of_freedom,
           secondary_degrees_of_freedom},
          {primary_->gravitational_parameter(),
           secondary_->gravitational_parameter()});

  // Beware, we want the angular velocity of ThisFrame as seen in the
  // InertialFrame, but pushed to ThisFrame.  Otherwise the sign is wrong.
  AngularVelocity<InertialFrame> const Ω_inertial =
      to_this_frame.angular_velocity_of_to_frame();
  AngularVelocity<ThisFrame> const Ω =
      to_this_frame.orthogonal_map()(Ω_inertial);

  RelativeDegreesOfFreedom<InertialFrame> const primary_secondary =
      primary_degrees_of_freedom - secondary_degrees_of_freedom;
  Vector<Acceleration, InertialFrame> const primary_acceleration =
      ephemeris_->ComputeGravitationalAcceleration(
          primary_degrees_of_freedom.position(), t);
  Vector<Acceleration, InertialFrame> const secondary_acceleration =
      ephemeris_->ComputeGravitationalAcceleration(
          secondary_degrees_of_freedom.position(), t);

  // TODO(egg): TeX and reference.
  Variation<AngularVelocity<ThisFrame>> const dΩ_over_dt =
      to_this_frame.orthogonal_map()
          (Wedge(primary_secondary.displacement(),
                 (primary_acceleration - secondary_acceleration)) * Radian -
           2 * Ω_inertial * InnerProduct(primary_secondary.displacement(),
                                         primary_secondary.velocity())) /
               InnerProduct(primary_secondary.displacement(),
                            primary_secondary.displacement());

  Displacement<ThisFrame> const r =
      degrees_of_freedom.position() - ThisFrame::origin;
  Vector<Acceleration, ThisFrame> const gravitational_acceleration_at_point =
      to_this_frame.orthogonal_map()(
          ephemeris_->ComputeGravitationalAcceleration(
              from_this_frame.rigid_transformation()(
                  degrees_of_freedom.position()), t));
  Vector<Acceleration, ThisFrame> const linear_acceleration =
      to_this_frame.orthogonal_map()(
          -ephemeris_->ComputeGravitationalAcceleration(
              barycentre_degrees_of_freedom.position(), t));
  Vector<Acceleration, ThisFrame> coriolis_acceleration_at_point =
      -2 * Ω * degrees_of_freedom.velocity() / Radian;
  Vector<Acceleration, ThisFrame> centrifugal_acceleration_at_point =
      -Ω * (Ω * r) / Pow<2>(Radian);
  Vector<Acceleration, ThisFrame> const euler_acceleration_at_point =
      -dΩ_over_dt * r / Radian;

  Vector<Acceleration, ThisFrame> const& fictitious_acceleration =
      linear_acceleration +
      coriolis_acceleration_at_point +
      centrifugal_acceleration_at_point +
      euler_acceleration_at_point;
  return gravitational_acceleration_at_point + fictitious_acceleration;
}

template<typename InertialFrame, typename ThisFrame>
void BarycentricRotatingDynamicFrame<InertialFrame, ThisFrame>::
ComputeAngularDegreesOfFreedom(
    DegreesOfFreedom<InertialFrame> const& primary_degrees_of_freedom,
    DegreesOfFreedom<InertialFrame> const& secondary_degrees_of_freedom,
    not_null<Rotation<InertialFrame, ThisFrame>*> const rotation,
    not_null<AngularVelocity<InertialFrame>*> const angular_velocity) {
  RelativeDegreesOfFreedom<InertialFrame> const reference =
      primary_degrees_of_freedom - secondary_degrees_of_freedom;
  Displacement<InertialFrame> const& reference_direction =
      reference.displacement();
  Velocity<InertialFrame> reference_normal = reference.velocity();
  reference_direction.template Orthogonalize<Speed>(&reference_normal);
  Bivector<Product<Length, Speed>, InertialFrame> const reference_binormal =
      Wedge(reference_direction, reference_normal);
  *rotation = Rotation<InertialFrame, ThisFrame>(
                  R3x3Matrix(Normalize(reference_direction).coordinates(),
                             Normalize(reference_normal).coordinates(),
                             Normalize(reference_binormal).coordinates()));
  *angular_velocity = reference_binormal * Radian /
                      InnerProduct(reference_direction, reference_direction);
}

}  // namespace physics
}  // namespace principia
<commit_msg>Const<commit_after>#pragma once

#include "physics/barycentric_rotating_dynamic_frame.hpp"

#include "geometry/named_quantities.hpp"
#include "geometry/r3x3_matrix.hpp"
#include "quantities/quantities.hpp"
#include "quantities/si.hpp"

namespace principia {

using geometry::Displacement;
using geometry::R3x3Matrix;
using geometry::Velocity;
using geometry::Wedge;
using quantities::Length;
using quantities::Pow;
using quantities::Product;
using quantities::Speed;

namespace physics {

template<typename InertialFrame, typename ThisFrame>
BarycentricRotatingDynamicFrame<InertialFrame, ThisFrame>::
BarycentricRotatingDynamicFrame(
    not_null<Ephemeris<InertialFrame> const*> const ephemeris,
    not_null<MassiveBody const*> const primary,
    not_null<MassiveBody const*> const secondary)
    : ephemeris_(ephemeris),
      primary_(primary),
      secondary_(secondary),
      primary_trajectory_(ephemeris_->trajectory(primary_)),
      secondary_trajectory_(ephemeris_->trajectory(secondary_)) {}

template<typename InertialFrame, typename ThisFrame>
RigidMotion<InertialFrame, ThisFrame>
BarycentricRotatingDynamicFrame<InertialFrame, ThisFrame>::ToThisFrameAtTime(
    Instant const& t) const {
  DegreesOfFreedom<InertialFrame> const primary_degrees_of_freedom =
      primary_trajectory_->EvaluateDegreesOfFreedom(t, &primary_hint_);
  DegreesOfFreedom<InertialFrame> const secondary_degrees_of_freedom =
      secondary_trajectory_->EvaluateDegreesOfFreedom(t, &secondary_hint_);
  DegreesOfFreedom<InertialFrame> const barycentre_degrees_of_freedom =
      Barycentre<InertialFrame, GravitationalParameter>(
          {primary_degrees_of_freedom,
           secondary_degrees_of_freedom},
          {primary_->gravitational_parameter(),
           secondary_->gravitational_parameter()});

  Rotation<InertialFrame, ThisFrame> rotation =
          Rotation<InertialFrame, ThisFrame>::Identity();
  AngularVelocity<InertialFrame> angular_velocity;
  ComputeAngularDegreesOfFreedom(primary_degrees_of_freedom,
                                 secondary_degrees_of_freedom,
                                 &rotation,
                                 &angular_velocity);

  RigidTransformation<InertialFrame, ThisFrame> const
      rigid_transformation(barycentre_degrees_of_freedom.position(),
                           ThisFrame::origin,
                           rotation.Forget());
  return RigidMotion<InertialFrame, ThisFrame>(
             rigid_transformation,
             angular_velocity,
             barycentre_degrees_of_freedom.velocity());
}

template<typename InertialFrame, typename ThisFrame>
RigidMotion<ThisFrame, InertialFrame>
BarycentricRotatingDynamicFrame<InertialFrame, ThisFrame>::
FromThisFrameAtTime(Instant const& t) const {
  return ToThisFrameAtTime(t).Inverse();
}

template<typename InertialFrame, typename ThisFrame>
Vector<Acceleration, ThisFrame>
BarycentricRotatingDynamicFrame<InertialFrame, ThisFrame>::
GeometricAcceleration(
    Instant const& t,
    DegreesOfFreedom<ThisFrame> const& degrees_of_freedom) const {
  auto const to_this_frame = ToThisFrameAtTime(t);
  auto const from_this_frame = to_this_frame.Inverse();

  DegreesOfFreedom<InertialFrame> const primary_degrees_of_freedom =
      primary_trajectory_->EvaluateDegreesOfFreedom(t, &primary_hint_);
  DegreesOfFreedom<InertialFrame> const secondary_degrees_of_freedom =
      secondary_trajectory_->EvaluateDegreesOfFreedom(t, &secondary_hint_);
  DegreesOfFreedom<InertialFrame> const barycentre_degrees_of_freedom =
      Barycentre<InertialFrame, GravitationalParameter>(
          {primary_degrees_of_freedom,
           secondary_degrees_of_freedom},
          {primary_->gravitational_parameter(),
           secondary_->gravitational_parameter()});

  // Beware, we want the angular velocity of ThisFrame as seen in the
  // InertialFrame, but pushed to ThisFrame.  Otherwise the sign is wrong.
  AngularVelocity<InertialFrame> const Ω_inertial =
      to_this_frame.angular_velocity_of_to_frame();
  AngularVelocity<ThisFrame> const Ω =
      to_this_frame.orthogonal_map()(Ω_inertial);

  RelativeDegreesOfFreedom<InertialFrame> const primary_secondary =
      primary_degrees_of_freedom - secondary_degrees_of_freedom;
  Vector<Acceleration, InertialFrame> const primary_acceleration =
      ephemeris_->ComputeGravitationalAcceleration(
          primary_degrees_of_freedom.position(), t);
  Vector<Acceleration, InertialFrame> const secondary_acceleration =
      ephemeris_->ComputeGravitationalAcceleration(
          secondary_degrees_of_freedom.position(), t);

  // TODO(egg): TeX and reference.
  Variation<AngularVelocity<ThisFrame>> const dΩ_over_dt =
      to_this_frame.orthogonal_map()
          (Wedge(primary_secondary.displacement(),
                 (primary_acceleration - secondary_acceleration)) * Radian -
           2 * Ω_inertial * InnerProduct(primary_secondary.displacement(),
                                         primary_secondary.velocity())) /
               InnerProduct(primary_secondary.displacement(),
                            primary_secondary.displacement());

  Displacement<ThisFrame> const r =
      degrees_of_freedom.position() - ThisFrame::origin;
  Vector<Acceleration, ThisFrame> const gravitational_acceleration_at_point =
      to_this_frame.orthogonal_map()(
          ephemeris_->ComputeGravitationalAcceleration(
              from_this_frame.rigid_transformation()(
                  degrees_of_freedom.position()), t));
  Vector<Acceleration, ThisFrame> const linear_acceleration =
      to_this_frame.orthogonal_map()(
          -ephemeris_->ComputeGravitationalAcceleration(
              barycentre_degrees_of_freedom.position(), t));
  Vector<Acceleration, ThisFrame> const coriolis_acceleration_at_point =
      -2 * Ω * degrees_of_freedom.velocity() / Radian;
  Vector<Acceleration, ThisFrame> const centrifugal_acceleration_at_point =
      -Ω * (Ω * r) / Pow<2>(Radian);
  Vector<Acceleration, ThisFrame> const euler_acceleration_at_point =
      -dΩ_over_dt * r / Radian;

  Vector<Acceleration, ThisFrame> const fictitious_acceleration =
      linear_acceleration +
      coriolis_acceleration_at_point +
      centrifugal_acceleration_at_point +
      euler_acceleration_at_point;
  return gravitational_acceleration_at_point + fictitious_acceleration;
}

template<typename InertialFrame, typename ThisFrame>
void BarycentricRotatingDynamicFrame<InertialFrame, ThisFrame>::
ComputeAngularDegreesOfFreedom(
    DegreesOfFreedom<InertialFrame> const& primary_degrees_of_freedom,
    DegreesOfFreedom<InertialFrame> const& secondary_degrees_of_freedom,
    not_null<Rotation<InertialFrame, ThisFrame>*> const rotation,
    not_null<AngularVelocity<InertialFrame>*> const angular_velocity) {
  RelativeDegreesOfFreedom<InertialFrame> const reference =
      primary_degrees_of_freedom - secondary_degrees_of_freedom;
  Displacement<InertialFrame> const& reference_direction =
      reference.displacement();
  Velocity<InertialFrame> reference_normal = reference.velocity();
  reference_direction.template Orthogonalize<Speed>(&reference_normal);
  Bivector<Product<Length, Speed>, InertialFrame> const reference_binormal =
      Wedge(reference_direction, reference_normal);
  *rotation = Rotation<InertialFrame, ThisFrame>(
                  R3x3Matrix(Normalize(reference_direction).coordinates(),
                             Normalize(reference_normal).coordinates(),
                             Normalize(reference_binormal).coordinates()));
  *angular_velocity = reference_binormal * Radian /
                      InnerProduct(reference_direction, reference_direction);
}

}  // namespace physics
}  // namespace principia
<|endoftext|>


<commit_before>#include "ganttitem.h"
#include "ganttview.h"
#include <QtGui>
#include <QStyleOption>

namespace gantt {

BarTextItem::BarTextItem (QGraphicsItem * parent, GanttViewConfig const & gvcfg, Data & d, QColor const & color, int x, int y, int w, int h, int ctx, int ctx_offs)
	: m_gvcfg(gvcfg)
    , m_data(d)
	, m_x(x), m_y(y), m_w(w), m_h(h), m_color(color)
	, m_ctx(ctx), m_ctx_offs(ctx_offs)
{
	setZValue(1);
	setParentItem(parent);
	//setFlags(ItemIsSelectable);
	//setAcceptHoverEvents(true);
}

QRectF BarTextItem::boundingRect () const
{
	return QRectF(0, 0, m_w, m_h);
}

QPainterPath BarTextItem::shape () const
{
	QPainterPath path;
	path.addRect(0, 0, m_w, m_h);
	return path;
}

void BarTextItem::paint (QPainter * painter, QStyleOptionGraphicsItem const * option, QWidget * widget)
{
	Q_UNUSED(widget);

	BarItem const * b = static_cast<BarItem const *>(parentItem());
	qreal const lod = b ? b->lod() : 1.0f;

	if (lod < 0.2f)
		return;

	QRectF const rect = boundingRect();
	QPointF const pt = rect.translated(+1, +1).topLeft();

	if (lod > 0.7f)
	{
		painter->save();
		setFlag(QGraphicsItem::ItemIgnoresTransformations, true);
		QFont font(m_gvcfg.m_font, m_gvcfg.m_fontsize);
		//QTransform identity;
		font.setStyleStrategy(QFont::ForceOutline);
		QString text = QString("%1 %2\n[ %3 ms]").arg(m_data.m_tag).arg(m_data.m_msg).arg(m_data.m_delta_t);
		painter->setFont(font);
		painter->setPen(Qt::black);
		painter->drawStaticText(pt, text);
		painter->restore();
	}
	else if (0.4f <= lod && lod < 0.7f)
	{
		painter->save();
		QFont font(m_gvcfg.m_font, m_gvcfg.m_fontsize - 1);
		font.setStyleStrategy(QFont::ForceOutline);
		painter->setFont(font);
		painter->setPen(Qt::black);
		painter->drawStaticText(pt, QString("%1 %2").arg(m_data.m_tag).arg(m_data.m_msg));
		painter->restore();
	}
	else if (0.2f <= lod && lod < 0.4f)
	{
		painter->save();
		QFont font(m_gvcfg.m_font, m_gvcfg.m_fontsize - 2);
		font.setStyleStrategy(QFont::ForceOutline);
		QString text = QString("%1").arg(m_data.m_tag);
		painter->setFont(font);
		painter->setPen(Qt::black);
		painter->drawText(pt, text);
		painter->restore();
	}
	else
	{
	}
}

BarItem::BarItem (GanttViewConfig const & cfg, Data & d, QColor const & color, int x, int y, int w, int h, int ctx, int ctx_offs)
	: m_gvcfg(cfg)
	, m_data(d)
	, m_x(x), m_y(y), m_w(w), m_h(h), m_color(color)
	, m_ctx(ctx), m_ctx_offs(ctx_offs)
	, m_lod(1.0f)
{
	setZValue(0);
	//setFlags(ItemIsSelectable | ItemIsMovable);
	setFlags(ItemIsSelectable);
	setAcceptHoverEvents(true);
}

QRectF BarItem::boundingRect () const
{
	return QRectF(0, 0, m_w, m_h);
}

QPainterPath BarItem::shape () const
{
	QPainterPath path;
	path.addRect(0, 0, m_w, m_h);
	return path;
}

void BarItem::paint (QPainter * painter, QStyleOptionGraphicsItem const * option, QWidget * widget)
{
	QColor fillColor = (option->state & QStyle::State_Selected) ? m_color.dark(150) : m_color;
	if (option->state & QStyle::State_MouseOver)
	{
		fillColor = fillColor.light(125);
	}

	QRectF rect = boundingRect();
	painter->fillRect(QRectF(0, 0, m_w, m_h), fillColor);

	m_lod = option->levelOfDetailFromTransform(painter->worldTransform());
}

void BarItem::mousePressEvent (QGraphicsSceneMouseEvent * event)
{
}

void BarItem::mouseMoveEvent (QGraphicsSceneMouseEvent * event)
{
	QGraphicsItem::mouseMoveEvent(event);
}

void BarItem::mouseReleaseEvent (QGraphicsSceneMouseEvent * event)
{
}

/*void BarItem::hoverEnterEvent (QGraphicsSceneHoverEvent *event)
{
	qDebug("+");
}
void BarItem::hoverLeaveEvent (QGraphicsSceneHoverEvent *event)
{
	qDebug("-");
}*/

}

<commit_msg>+ bit of lodding<commit_after>#include "ganttitem.h"
#include "ganttview.h"
#include <QtGui>
#include <QStyleOption>

namespace gantt {

BarTextItem::BarTextItem (QGraphicsItem * parent, GanttViewConfig const & gvcfg, Data & d, QColor const & color, int x, int y, int w, int h, int ctx, int ctx_offs)
	: m_gvcfg(gvcfg)
    , m_data(d)
	, m_x(x), m_y(y), m_w(w), m_h(h), m_color(color)
	, m_ctx(ctx), m_ctx_offs(ctx_offs)
{
	setZValue(1);
	setParentItem(parent);
	//setFlags(ItemIsSelectable);
	//setAcceptHoverEvents(true);
	setFlag(QGraphicsItem::ItemIgnoresTransformations, true);
}

QRectF BarTextItem::boundingRect () const
{
	return QRectF(0, 0, m_w, m_h);
}

QPainterPath BarTextItem::shape () const
{
	QPainterPath path;
	path.addRect(0, 0, m_w, m_h);
	return path;
}

void BarTextItem::paint (QPainter * painter, QStyleOptionGraphicsItem const * option, QWidget * widget)
{
	Q_UNUSED(widget);

	BarItem const * b = static_cast<BarItem const *>(parentItem());
	qreal const lod = b ? b->lod() : 1.0f;

	if (lod < 0.2f)
		return;

	QRectF const rect = boundingRect();
	QPointF const pt = rect.translated(+1, +1).topLeft();

	if (lod > 0.7f)
	{
		painter->save();
		QFont font(m_gvcfg.m_font, m_gvcfg.m_fontsize);
		font.setStyleStrategy(QFont::ForceOutline);
		QString text = QString("%1 %2\n[ %3 ms]").arg(m_data.m_tag).arg(m_data.m_msg).arg(m_data.m_delta_t);
		painter->setFont(font);
		painter->setPen(Qt::black);
		painter->drawStaticText(pt, text);
		painter->restore();
	}
	else if (0.4f <= lod && lod < 0.7f)
	{
		painter->save();
		QFont font(m_gvcfg.m_font, m_gvcfg.m_fontsize - 1);
		font.setStyleStrategy(QFont::ForceOutline);
		painter->setFont(font);
		painter->setPen(Qt::black);
		painter->drawStaticText(pt, QString("%1 %2").arg(m_data.m_tag).arg(m_data.m_msg));
		painter->restore();
	}
	else if (0.2f <= lod && lod < 0.4f)
	{
		painter->save();
		QFont font(m_gvcfg.m_font, m_gvcfg.m_fontsize - 2);
		font.setStyleStrategy(QFont::ForceOutline);
		QString text = QString("%1").arg(m_data.m_tag);
		painter->setFont(font);
		painter->setPen(Qt::black);
		painter->drawText(pt, text);
		painter->restore();
	}
	else
	{
	}
}

BarItem::BarItem (GanttViewConfig const & cfg, Data & d, QColor const & color, int x, int y, int w, int h, int ctx, int ctx_offs)
	: m_gvcfg(cfg)
	, m_data(d)
	, m_x(x), m_y(y), m_w(w), m_h(h), m_color(color)
	, m_ctx(ctx), m_ctx_offs(ctx_offs)
	, m_lod(1.0f)
{
	setZValue(0);
	//setFlags(ItemIsSelectable | ItemIsMovable);
	setFlags(ItemIsSelectable);
	setAcceptHoverEvents(true);
}

QRectF BarItem::boundingRect () const
{
	return QRectF(0, 0, m_w, m_h);
}

QPainterPath BarItem::shape () const
{
	QPainterPath path;
	path.addRect(0, 0, m_w, m_h);
	return path;
}

void BarItem::paint (QPainter * painter, QStyleOptionGraphicsItem const * option, QWidget * widget)
{
	QColor fillColor = (option->state & QStyle::State_Selected) ? m_color.dark(150) : m_color;
	if (option->state & QStyle::State_MouseOver)
	{
		fillColor = fillColor.light(125);
	}

	QRectF rect = boundingRect();
	painter->fillRect(QRectF(0, 0, m_w, m_h), fillColor);

	m_lod = option->levelOfDetailFromTransform(painter->worldTransform());
}

void BarItem::mousePressEvent (QGraphicsSceneMouseEvent * event)
{
}

void BarItem::mouseMoveEvent (QGraphicsSceneMouseEvent * event)
{
	QGraphicsItem::mouseMoveEvent(event);
}

void BarItem::mouseReleaseEvent (QGraphicsSceneMouseEvent * event)
{
}

/*void BarItem::hoverEnterEvent (QGraphicsSceneHoverEvent *event)
{
	qDebug("+");
}
void BarItem::hoverLeaveEvent (QGraphicsSceneHoverEvent *event)
{
	qDebug("-");
}*/

}

<|endoftext|>


<commit_before>#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <queue>
#include <unordered_set>
#include <map>
#include <ctime>

#define IB_Z 0
#define IB_Y 1
#define IB_X 2

static long nentries;
static long row_size;
static long sheet_size;

static void IndexToIndicies(long iv, long &ix, long &iy, long &iz)
{
    iz = iv / sheet_size;
    iy = (iv - iz * sheet_size) / row_size;
    ix = iv % row_size;
}

static long IndicesToIndex(long ix, long iy, long iz)
{
    return iz * sheet_size + iy * row_size + ix;
}

void CppMapLabels(long *segmentation, long *mapping, unsigned long input_nentries)
{
    for (unsigned long iv = 0; iv < input_nentries; ++iv) {
        segmentation[iv] = mapping[segmentation[iv]];
    }
}

void CppRemoveSmallConnectedComponents(long *segmentation, int threshold, unsigned long input_nentries)
{
    if (threshold == 0) return;

    // find the maximum label
    long max_segment_label = 0;
    for (unsigned long iv = 0; iv < input_nentries; ++iv) {
        if (segmentation[iv] > max_segment_label) max_segment_label = segmentation[iv];
    }
    max_segment_label++;

    // create a counter array for the number of voxels
    int *nvoxels_per_segment = new int[max_segment_label];
    for (long iv = 0; iv < max_segment_label; ++iv) {
        nvoxels_per_segment[iv] = 0;
    }

    // count the number of voxels per segment
    for (unsigned long iv = 0; iv < input_nentries; ++iv) {
        nvoxels_per_segment[segmentation[iv]]++;
    }

    // create the array for the updated segmentation
    for (unsigned long iv = 0; iv < input_nentries; ++iv) {
        if (nvoxels_per_segment[segmentation[iv]] < threshold) segmentation[iv] = 0;
    }

    // free memory
    delete[] nvoxels_per_segment;
}

void CppForceConnectivity(char *segmentation, long grid_size[3])
{
    // create the new components array
    nentries = grid_size[IB_Z] * grid_size[IB_Y] * grid_size[IB_X];
    sheet_size = grid_size[IB_Y] * grid_size[IB_X];
    row_size = grid_size[IB_X];

    short *components = new short[nentries];
    for (long iv = 0; iv < nentries; ++iv)
        components[iv] = 0;

    // create the queue of labels
    std::queue<unsigned long> pixels = std::queue<unsigned long>();

    long current_index = 0;
    long current_label = 1;

    while (current_index < nentries) {
        // set this component and add to the queue
        components[current_index] = current_label;
        pixels.push(current_index);

        // iterate over all pixels in the queue
        while (pixels.size()) {
            // remove this pixel from the queue
            unsigned long pixel = pixels.front();
            pixels.pop();

            // add the six neighbors to the queue
            long iz, iy, ix;
            IndexToIndicies(pixel, ix, iy, iz);

            for (long iw = iz - 1; iw <= iz + 1; ++iw) {
                if (iw < 0 or iw >= grid_size[IB_Z]) continue;
                for (long iv = iy - 1; iv <= iy + 1; ++iv) {
                    if (iv < 0 or iv >= grid_size[IB_Y]) continue;
                    for (long iu = ix - 1; iu <= ix + 1; ++iu) {
                        if (iu < 0 or iu >= grid_size[IB_X]) continue;
                        long neighbor = IndicesToIndex(iu, iv, iw);

                        if (segmentation[pixel] == segmentation[neighbor] && !components[neighbor]) {
                            components[neighbor] = current_label;
                            pixels.push(neighbor);
                        }
                    }
                }
            }
        }
        current_label++;

        // if the current index is already labeled, continue
        while (current_index < nentries && components[current_index]) current_index++;
    }

    // create a list of mappings
    long max_segment = 0;
    long max_component = 0;
    for (long iv = 0; iv < nentries; ++iv) {
        if (segmentation[iv] > max_segment) max_segment = segmentation[iv];
        if (components[iv] > max_component) max_component = components[iv];
    }
    max_segment++;
    max_component++;

    std::unordered_set<long> *seg2comp = new std::unordered_set<long>[max_segment];
    for (long iv = 0; iv < max_segment; ++iv)
        seg2comp[iv] = std::unordered_set<long>();

    // see if any segments have multiple components
    for (long iv = 0; iv < nentries; ++iv) {
        seg2comp[segmentation[iv]].insert(components[iv]);
    }

    long overflow = max_segment;
    long *comp2seg = new long[max_component];
    for (long iv = 1; iv < max_segment; ++iv) {
        if (seg2comp[iv].size() == 1) {
            // get the component for this segment
            long component = *(seg2comp[iv].begin());
            comp2seg[component] = iv;
        }
        else {
            // iterate over the set
            for (std::unordered_set<long>::iterator it = seg2comp[iv].begin(); it != seg2comp[iv].end(); ++it) {
                long component = *it;

                // one of the components keeps the label
                if (it == seg2comp[iv].begin()) comp2seg[component] = iv;
                // set the component to start at max_segment and increment
                else {
                    comp2seg[component] = overflow;
                    ++overflow;
                }
            }
        }
    }

    // update the segmentation
    for (long iv = 0; iv < nentries; ++iv) {
        if (!segmentation[iv]) segmentation[iv] = 0;
        else segmentation[iv] = comp2seg[components[iv]];
    }

    // free memory
    delete[] seg2comp;
    delete[] comp2seg;
    delete[] components;
}

void CppDownsampleMapping(const char *prefix, long *segmentation, float input_resolution[3], long output_resolution[3], long input_grid_size[3], bool benchmark)
{
    // get the number of entries
    long input_nentries = input_grid_size[IB_Z] * input_grid_size[IB_Y] * input_grid_size[IB_X];

    // get downsample ratios
    float zdown = ((float) output_resolution[IB_Z]) / input_resolution[IB_Z];
    float ydown = ((float) output_resolution[IB_Y]) / input_resolution[IB_Y];
    float xdown = ((float) output_resolution[IB_X]) / input_resolution[IB_X];

    // get the output resolution size
    long output_grid_size[3];
    output_grid_size[IB_Z] = (long) ceil(input_grid_size[IB_Z] / zdown);
    output_grid_size[IB_Y] = (long) ceil(input_grid_size[IB_Y] / ydown);
    output_grid_size[IB_X] = (long) ceil(input_grid_size[IB_X] / xdown);
    long output_sheet_size = output_grid_size[IB_Y] * output_grid_size[IB_X];
    long output_row_size = output_grid_size[IB_X];

    long max_segment = 0;
    for (long iv = 0; iv < input_nentries; ++iv)
        if (segmentation[iv] > max_segment) max_segment = segmentation[iv];
    max_segment++;

    // create a set for each segment of downsampled locations
    std::unordered_set<long> *downsample_sets = new std::unordered_set<long>[max_segment];
    for (long iv = 0; iv < max_segment; ++iv)
        downsample_sets[iv] = std::unordered_set<long>();

    long index = 0;
    for (long iz = 0; iz < input_grid_size[IB_Z]; ++iz) {
        for (long iy = 0; iy < input_grid_size[IB_Y]; ++iy) {
            for (long ix = 0; ix < input_grid_size[IB_X]; ++ix, ++index) {
                long segment = segmentation[index];
                if (!segment) continue;

                long iw = (long) (iz / zdown);
                long iv = (long) (iy / ydown);
                long iu = (long) (ix / xdown);

                long downsample_index = iw * output_sheet_size + iv * output_row_size + iu;
                downsample_sets[segment].insert(downsample_index);
            }
        }
    }

    // write the downsampling information
    char downsample_filename[4096];
    if (benchmark) sprintf(downsample_filename, "benchmarks/skeleton/%s-downsample-%03ldx%03ldx%03ld.bytes", prefix, output_resolution[IB_X], output_resolution[IB_Y], output_resolution[IB_Z]);
    else sprintf(downsample_filename, "skeletons/%s/downsample-%03ldx%03ldx%03ld.bytes", prefix, output_resolution[IB_X], output_resolution[IB_Y], output_resolution[IB_Z]);

    // open the output file
    FILE *dfp = fopen(downsample_filename, "wb");
    if (!dfp) { fprintf(stderr, "Failed to write to %s\n", downsample_filename); exit(-1); }

    // write the upsampling information
    char upsample_filename[4096];
    if (benchmark) sprintf(upsample_filename, "benchmarks/skeleton/%s-upsample-%03ldx%03ldx%03ld.bytes", prefix, output_resolution[IB_X], output_resolution[IB_Y], output_resolution[IB_Z]);
    else sprintf(upsample_filename, "skeletons/%s/upsample-%03ldx%03ldx%03ld.bytes", prefix, output_resolution[IB_X], output_resolution[IB_Y], output_resolution[IB_Z]);

    // open the output file
    FILE *ufp = fopen(upsample_filename, "wb");
    if (!ufp) { fprintf(stderr, "Failed to write to %s\n", upsample_filename); exit(-1); }

    // write the number of segments
    fwrite(&output_grid_size[IB_Z], sizeof(long), 1, dfp);
    fwrite(&output_grid_size[IB_Y], sizeof(long), 1, dfp);
    fwrite(&output_grid_size[IB_X], sizeof(long), 1, dfp);
    fwrite(&max_segment, sizeof(long), 1, dfp);

    // write the output file size of the upsample version
    fwrite(&(input_grid_size[IB_Z]), sizeof(long), 1, ufp);
    fwrite(&(input_grid_size[IB_Y]), sizeof(long), 1, ufp);
    fwrite(&(input_grid_size[IB_X]), sizeof(long), 1, ufp);
    fwrite(&max_segment, sizeof(long), 1, ufp);

    // output values for downsampling
    for (long label = 0; label < max_segment; ++label) {
        // write the size for this set
        long nelements = downsample_sets[label].size();
        fwrite(&nelements, sizeof(long), 1, dfp);
        fwrite(&nelements, sizeof(long), 1, ufp);
        for (std::unordered_set<long>::iterator it = downsample_sets[label].begin(); it != downsample_sets[label].end(); ++it) {
            long element = *it;
            fwrite(&element, sizeof(long), 1, dfp);

            long iz = element / (output_grid_size[IB_Y] * output_grid_size[IB_X]);
            long iy = (element - iz * output_grid_size[IB_Y] * output_grid_size[IB_X]) / output_grid_size[IB_X];
            long ix = element % output_grid_size[IB_X];

            long zmin = (long) (zdown * iz);
            long ymin = (long) (ydown * iy);
            long xmin = (long) (xdown * ix);

            long zmax = std::min((long) ceil(zdown * (iz + 1) + 1), input_grid_size[IB_Z]);
            long ymax = std::min((long) ceil(ydown * (iy + 1) + 1), input_grid_size[IB_Y]);
            long xmax = std::min((long) ceil(xdown * (ix + 1) + 1), input_grid_size[IB_X]);

            double closest_to_center = input_grid_size[IB_Z] * input_grid_size[IB_Y] * input_grid_size[IB_X];
            long upsample_index = -1;

            long zcenter = (zmax + zmin) / 2;
            long ycenter = (ymax + ymin) / 2;
            long xcenter = (xmax + xmin) / 2;

            for (long iw = zmin; iw < zmax; ++iw) {
                for (long iv = ymin; iv < ymax; ++iv) {
                    for (long iu = xmin; iu < xmax; ++iu) {
                        long linear_index = iw * input_grid_size[IB_Y] * input_grid_size[IB_X] + iv * input_grid_size[IB_X] + iu;

                        // find the closest point to the center
                        if (segmentation[linear_index] != label) continue;

                        double distance = abs(iw - zcenter) + abs(iv - ycenter) + abs(iu - xcenter);
                        if (distance < closest_to_center) {
                            closest_to_center = distance;
                            upsample_index = linear_index;
                        }
                    }
                }
            }

            fwrite(&upsample_index, sizeof(long), 1, ufp);
        }
    }

    // close the file
    fclose(dfp);
    fclose(ufp);

    // free memory
    delete[] downsample_sets;
}
<commit_msg>Merging<commit_after>#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <queue>
#include <unordered_set>
#include <map>
#include <ctime>

#define IB_Z 0
#define IB_Y 1
#define IB_X 2

static long nentries;
static long row_size;
static long sheet_size;

static void IndexToIndicies(long iv, long &ix, long &iy, long &iz)
{
    iz = iv / sheet_size;
    iy = (iv - iz * sheet_size) / row_size;
    ix = iv % row_size;
}

static long IndicesToIndex(long ix, long iy, long iz)
{
    return iz * sheet_size + iy * row_size + ix;
}

void CppMapLabels(long *segmentation, long *mapping, unsigned long input_nentries)
{
    for (unsigned long iv = 0; iv < input_nentries; ++iv) {
        segmentation[iv] = mapping[segmentation[iv]];
    }
}

void CppRemoveSmallConnectedComponents(long *segmentation, int threshold, unsigned long input_nentries)
{
    if (threshold == 0) return;

    // find the maximum label
    long max_segment_label = 0;
    for (unsigned long iv = 0; iv < input_nentries; ++iv) {
        if (segmentation[iv] > max_segment_label) max_segment_label = segmentation[iv];
    }
    max_segment_label++;

    // create a counter array for the number of voxels
    int *nvoxels_per_segment = new int[max_segment_label];
    for (long iv = 0; iv < max_segment_label; ++iv) {
        nvoxels_per_segment[iv] = 0;
    }

    // count the number of voxels per segment
    for (unsigned long iv = 0; iv < input_nentries; ++iv) {
        nvoxels_per_segment[segmentation[iv]]++;
    }

    // create the array for the updated segmentation
    for (unsigned long iv = 0; iv < input_nentries; ++iv) {
        if (nvoxels_per_segment[segmentation[iv]] < threshold) segmentation[iv] = 0;
    }

    // free memory
    delete[] nvoxels_per_segment;
}

void CppForceConnectivity(char *segmentation, long grid_size[3])
{
    // create the new components array
    nentries = grid_size[IB_Z] * grid_size[IB_Y] * grid_size[IB_X];
    sheet_size = grid_size[IB_Y] * grid_size[IB_X];
    row_size = grid_size[IB_X];

    short *components = new short[nentries];
    for (long iv = 0; iv < nentries; ++iv)
        components[iv] = 0;

    // create the queue of labels
    std::queue<unsigned long> pixels = std::queue<unsigned long>();

    long current_index = 0;
    long current_label = 1;

    while (current_index < nentries) {
        // set this component and add to the queue
        components[current_index] = current_label;
        pixels.push(current_index);

        // iterate over all pixels in the queue
        while (pixels.size()) {
            // remove this pixel from the queue
            unsigned long pixel = pixels.front();
            pixels.pop();

            // add the six neighbors to the queue
            long iz, iy, ix;
            IndexToIndicies(pixel, ix, iy, iz);

            for (long iw = iz - 1; iw <= iz + 1; ++iw) {
                if (iw < 0 or iw >= grid_size[IB_Z]) continue;
                for (long iv = iy - 1; iv <= iy + 1; ++iv) {
                    if (iv < 0 or iv >= grid_size[IB_Y]) continue;
                    for (long iu = ix - 1; iu <= ix + 1; ++iu) {
                        if (iu < 0 or iu >= grid_size[IB_X]) continue;
                        long neighbor = IndicesToIndex(iu, iv, iw);

                        if (segmentation[pixel] == segmentation[neighbor] && !components[neighbor]) {
                            components[neighbor] = current_label;
                            pixels.push(neighbor);
                        }
                    }
                }
            }
        }
        current_label++;

        // if the current index is already labeled, continue
        while (current_index < nentries && components[current_index]) current_index++;
    }

    // create a list of mappings
    long max_segment = 0;
    long max_component = 0;
    for (long iv = 0; iv < nentries; ++iv) {
        if (segmentation[iv] > max_segment) max_segment = segmentation[iv];
        if (components[iv] > max_component) max_component = components[iv];
    }
    max_segment++;
    max_component++;

    std::unordered_set<long> *seg2comp = new std::unordered_set<long>[max_segment];
    for (long iv = 0; iv < max_segment; ++iv)
        seg2comp[iv] = std::unordered_set<long>();

    // see if any segments have multiple components
    for (long iv = 0; iv < nentries; ++iv) {
        seg2comp[segmentation[iv]].insert(components[iv]);
    }

    long overflow = max_segment;
    long *comp2seg = new long[max_component];
    for (long iv = 1; iv < max_segment; ++iv) {
        if (seg2comp[iv].size() == 1) {
            // get the component for this segment
            long component = *(seg2comp[iv].begin());
            comp2seg[component] = iv;
        }
        else {
            // iterate over the set
            for (std::unordered_set<long>::iterator it = seg2comp[iv].begin(); it != seg2comp[iv].end(); ++it) {
                long component = *it;

                // one of the components keeps the label
                if (it == seg2comp[iv].begin()) comp2seg[component] = iv;
                // set the component to start at max_segment and increment
                else {
                    comp2seg[component] = overflow;
                    ++overflow;
                }
            }
        }
    }

    // update the segmentation
    for (long iv = 0; iv < nentries; ++iv) {
        if (!segmentation[iv]) segmentation[iv] = 0;
        else segmentation[iv] = comp2seg[components[iv]];
    }

    // free memory
    delete[] seg2comp;
    delete[] comp2seg;
    delete[] components;
}

void CppDownsampleMapping(const char *prefix, long *segmentation, float input_resolution[3], long output_resolution[3], long input_grid_size[3], bool benchmark)
{
    // get the number of entries
    long input_nentries = input_grid_size[IB_Z] * input_grid_size[IB_Y] * input_grid_size[IB_X];

    // get downsample ratios
    float zdown = ((float) output_resolution[IB_Z]) / input_resolution[IB_Z];
    float ydown = ((float) output_resolution[IB_Y]) / input_resolution[IB_Y];
    float xdown = ((float) output_resolution[IB_X]) / input_resolution[IB_X];

    // get the output resolution size
    long output_grid_size[3];
    output_grid_size[IB_Z] = (long) ceil(input_grid_size[IB_Z] / zdown);
    output_grid_size[IB_Y] = (long) ceil(input_grid_size[IB_Y] / ydown);
    output_grid_size[IB_X] = (long) ceil(input_grid_size[IB_X] / xdown);
    long output_sheet_size = output_grid_size[IB_Y] * output_grid_size[IB_X];
    long output_row_size = output_grid_size[IB_X];

    long max_segment = 0;
    for (long iv = 0; iv < input_nentries; ++iv)
        if (segmentation[iv] > max_segment) max_segment = segmentation[iv];
    max_segment++;

    // create a set for each segment of downsampled locations
    std::unordered_set<long> *downsample_sets = new std::unordered_set<long>[max_segment];
    for (long iv = 0; iv < max_segment; ++iv)
        downsample_sets[iv] = std::unordered_set<long>();

    long index = 0;
    for (long iz = 0; iz < input_grid_size[IB_Z]; ++iz) {
        for (long iy = 0; iy < input_grid_size[IB_Y]; ++iy) {
            for (long ix = 0; ix < input_grid_size[IB_X]; ++ix, ++index) {
                long segment = segmentation[index];
                if (!segment) continue;

                long iw = (long) (iz / zdown);
                long iv = (long) (iy / ydown);
                long iu = (long) (ix / xdown);

                long downsample_index = iw * output_sheet_size + iv * output_row_size + iu;
                downsample_sets[segment].insert(downsample_index);
            }
        }
    }

    // write the downsampling information
    char downsample_filename[4096];
    if (benchmark) sprintf(downsample_filename, "benchmarks/skeleton/%s-downsample-%03ldx%03ldx%03ld.bytes", prefix, output_resolution[IB_X], output_resolution[IB_Y], output_resolution[IB_Z]);
    else sprintf(downsample_filename, "skeletons/%s/downsample-%03ldx%03ldx%03ld.bytes", prefix, output_resolution[IB_X], output_resolution[IB_Y], output_resolution[IB_Z]);

    // open the output file
    FILE *dfp = fopen(downsample_filename, "wb");
    if (!dfp) { fprintf(stderr, "Failed to write to %s\n", downsample_filename); exit(-1); }

    // write the upsampling information
    char upsample_filename[4096];
    if (benchmark) sprintf(upsample_filename, "benchmarks/skeleton/%s-upsample-%03ldx%03ldx%03ld.bytes", prefix, output_resolution[IB_X], output_resolution[IB_Y], output_resolution[IB_Z]);
    else sprintf(upsample_filename, "skeletons/%s/upsample-%03ldx%03ldx%03ld.bytes", prefix, output_resolution[IB_X], output_resolution[IB_Y], output_resolution[IB_Z]);

    // open the output file
    FILE *ufp = fopen(upsample_filename, "wb");
    if (!ufp) { fprintf(stderr, "Failed to write to %s\n", upsample_filename); exit(-1); }

    // write the number of segments
    fwrite(&output_grid_size[IB_Z], sizeof(long), 1, dfp);
    fwrite(&output_grid_size[IB_Y], sizeof(long), 1, dfp);
    fwrite(&output_grid_size[IB_X], sizeof(long), 1, dfp);
    fwrite(&max_segment, sizeof(long), 1, dfp);

    // write the output file size of the upsample version
    fwrite(&(input_grid_size[IB_Z]), sizeof(long), 1, ufp);
    fwrite(&(input_grid_size[IB_Y]), sizeof(long), 1, ufp);
    fwrite(&(input_grid_size[IB_X]), sizeof(long), 1, ufp);
    fwrite(&max_segment, sizeof(long), 1, ufp);

    // output values for downsampling
    for (long label = 0; label < max_segment; ++label) {
        // write the size for this set
        long nelements = downsample_sets[label].size();
        fwrite(&nelements, sizeof(long), 1, dfp);
        fwrite(&nelements, sizeof(long), 1, ufp);
        for (std::unordered_set<long>::iterator it = downsample_sets[label].begin(); it != downsample_sets[label].end(); ++it) {
            long element = *it;
            fwrite(&element, sizeof(long), 1, dfp);

            long iz = element / (output_grid_size[IB_Y] * output_grid_size[IB_X]);
            long iy = (element - iz * output_grid_size[IB_Y] * output_grid_size[IB_X]) / output_grid_size[IB_X];
            long ix = element % output_grid_size[IB_X];

            long zmin = (long) (zdown * iz);
            long ymin = (long) (ydown * iy);
            long xmin = (long) (xdown * ix);

            long zmax = std::min((long) ceil(zdown * (iz + 1) + 1), input_grid_size[IB_Z]);
            long ymax = std::min((long) ceil(ydown * (iy + 1) + 1), input_grid_size[IB_Y]);
            long xmax = std::min((long) ceil(xdown * (ix + 1) + 1), input_grid_size[IB_X]);

            double closest_to_center = input_grid_size[IB_Z] * input_grid_size[IB_Y] * input_grid_size[IB_X];
            long upsample_index = -1;

            long zcenter = (zmax + zmin) / 2;
            long ycenter = (ymax + ymin) / 2;
            long xcenter = (xmax + xmin) / 2;

            for (long iw = zmin; iw < zmax; ++iw) {
                for (long iv = ymin; iv < ymax; ++iv) {
                    for (long iu = xmin; iu < xmax; ++iu) {
                        long linear_index = iw * input_grid_size[IB_Y] * input_grid_size[IB_X] + iv * input_grid_size[IB_X] + iu;

                        // find the closest point to the center
                        if (segmentation[linear_index] != label) continue;

                        double distance = abs(iw - zcenter) + abs(iv - ycenter) + abs(iu - xcenter);
                        if (distance < closest_to_center) {
                            closest_to_center = distance;
                            upsample_index = linear_index;
                        }
                    }
                }
            }

            fwrite(&upsample_index, sizeof(long), 1, ufp);
        }
    }

    // close the file
    fclose(dfp);
    fclose(ufp);

    // free memory
    delete[] downsample_sets;
}
<|endoftext|>


<commit_before>// @(#)root/tree:$Id$
// Author: Fons Rademakers   30/11/99

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

/** \class TTreeRow
\ingroup tree

Class defining interface to a row of a TTree query result.
Objects of this class are created by TTreeResult methods.

Related classes are TTreeResult.
*/

#include "TTreeRow.h"
#include "TBuffer.h"
#include "TObjArray.h"

ClassImp(TTreeRow)

////////////////////////////////////////////////////////////////////////////////
/// Single row of a query result.

TTreeRow::TTreeRow()
{
   fColumnCount = 0;
   fFields      = 0;
   fOriginal    = 0;
   fRow         = 0;

}

////////////////////////////////////////////////////////////////////////////////
/// Single row of a query result.

TTreeRow::TTreeRow(Int_t nfields)
{
   fColumnCount = nfields;
   fFields      = 0;
   fOriginal    = 0;
   fRow         = 0;

}

////////////////////////////////////////////////////////////////////////////////
/// Single row of a query result.

TTreeRow::TTreeRow(Int_t nfields, const Int_t *fields, const char *row)
{
   fColumnCount = nfields;
   fFields      = 0;
   fOriginal    = 0;
   fRow         = 0;
   SetRow(fields,row);
}

////////////////////////////////////////////////////////////////////////////////
/// This is a shallow copy of a real row, i.e. it only contains
/// a pointer to the original.

TTreeRow::TTreeRow(TSQLRow *original)
{
   fFields      = 0;
   fOriginal    = 0;
   fColumnCount = 0;
   fRow         = 0;

   if (!original) {
      Error("TTreeRow", "original may not be 0");
      return;
   }
   if (original->IsA() != TTreeRow::Class()) {
      Error("TTreeRow", "original must be a TTreeRow");
      return;
   }

   fOriginal = (TTreeRow*) original;
   fColumnCount = fOriginal->fColumnCount;
}

////////////////////////////////////////////////////////////////////////////////
/// Destroy row object.

TTreeRow::~TTreeRow()
{
   if (fFields)
      Close();
}

////////////////////////////////////////////////////////////////////////////////
/// Close row.

void TTreeRow::Close(Option_t *)
{
   if (fRow)    delete [] fRow;
   if (fFields) delete [] fFields;
   fColumnCount = 0;
   fOriginal = 0;
}

////////////////////////////////////////////////////////////////////////////////
/// Check if row is open and field index within range.

Bool_t TTreeRow::IsValid(Int_t field)
{
   if (!fFields && !fOriginal) {
      Error("IsValid", "row closed");
      return kFALSE;
   }
   if (field < 0 || field >= fColumnCount) {
      Error("IsValid", "field index out of bounds");
      return kFALSE;
   }
   return kTRUE;
}

////////////////////////////////////////////////////////////////////////////////
/// Get length in bytes of specified field.

ULong_t TTreeRow::GetFieldLength(Int_t field)
{
   if (!IsValid(field))
      return 0;

   if (fOriginal)
      return fOriginal->GetFieldLength(field);

   if (field > 0) return fFields[field] - fFields[field-1] -1;
   else           return fFields[0] -1;
}

////////////////////////////////////////////////////////////////////////////////
/// Get specified field from row (0 <= field < GetFieldCount()).

const char *TTreeRow::GetField(Int_t field)
{
   if (!IsValid(field))
      return 0;

   if (fOriginal)
      return fOriginal->GetField(field);

   if (field > 0) return fRow +fFields[field-1];
   else           return fRow;
}

////////////////////////////////////////////////////////////////////////////////
/// The field and row information.

void TTreeRow::SetRow(const Int_t *fields, const char *row)
{
   if (!fColumnCount) return;
   if (fFields) delete [] fFields;
   Int_t nch    = fields[fColumnCount-1];
   fFields      = new Int_t[fColumnCount];
   fOriginal    = 0;
   fRow         = new char[nch];
   for (Int_t i=0;i<fColumnCount;i++) fFields[i] = fields[i];
   memcpy(fRow,row,nch);
}

////////////////////////////////////////////////////////////////////////////////
/// Stream an object of class TTreeRow.

void TTreeRow::Streamer(TBuffer &R__b)
{
   UInt_t R__s, R__c;
   if (R__b.IsReading()) {
      R__b.ReadVersion(&R__s, &R__c);
      TSQLRow::Streamer(R__b);
      R__b >> fColumnCount;
      fFields = new Int_t[fColumnCount];
      R__b.ReadFastArray(fFields,fColumnCount);
      Int_t nch;
      R__b >> nch;
      fRow = new char[nch];
      R__b.ReadFastArray(fRow,nch);
      R__b.CheckByteCount(R__s, R__c, TTreeRow::IsA());
   } else {
      R__c = R__b.WriteVersion(TTreeRow::Class(),kTRUE);
      TSQLRow::Streamer(R__b);
      R__b << fColumnCount;
      R__b.WriteFastArray(fFields,fColumnCount);
      Int_t nch = fFields[fColumnCount-1];
      R__b << nch;
      R__b.WriteFastArray(fRow,nch);
      R__b.SetByteCount(R__c,kTRUE);
   }
}
<commit_msg>Protect TTreeRow::Streamer against null pointer<commit_after>// @(#)root/tree:$Id$
// Author: Fons Rademakers   30/11/99

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

/** \class TTreeRow
\ingroup tree

Class defining interface to a row of a TTree query result.
Objects of this class are created by TTreeResult methods.

Related classes are TTreeResult.
*/

#include "TTreeRow.h"
#include "TBuffer.h"
#include "TObjArray.h"

ClassImp(TTreeRow)

////////////////////////////////////////////////////////////////////////////////
/// Single row of a query result.

TTreeRow::TTreeRow()
{
   fColumnCount = 0;
   fFields      = 0;
   fOriginal    = 0;
   fRow         = 0;

}

////////////////////////////////////////////////////////////////////////////////
/// Single row of a query result.

TTreeRow::TTreeRow(Int_t nfields)
{
   fColumnCount = nfields;
   fFields      = 0;
   fOriginal    = 0;
   fRow         = 0;

}

////////////////////////////////////////////////////////////////////////////////
/// Single row of a query result.

TTreeRow::TTreeRow(Int_t nfields, const Int_t *fields, const char *row)
{
   fColumnCount = nfields;
   fFields      = 0;
   fOriginal    = 0;
   fRow         = 0;
   SetRow(fields,row);
}

////////////////////////////////////////////////////////////////////////////////
/// This is a shallow copy of a real row, i.e. it only contains
/// a pointer to the original.

TTreeRow::TTreeRow(TSQLRow *original)
{
   fFields      = 0;
   fOriginal    = 0;
   fColumnCount = 0;
   fRow         = 0;

   if (!original) {
      Error("TTreeRow", "original may not be 0");
      return;
   }
   if (original->IsA() != TTreeRow::Class()) {
      Error("TTreeRow", "original must be a TTreeRow");
      return;
   }

   fOriginal = (TTreeRow*) original;
   fColumnCount = fOriginal->fColumnCount;
}

////////////////////////////////////////////////////////////////////////////////
/// Destroy row object.

TTreeRow::~TTreeRow()
{
   if (fFields)
      Close();
}

////////////////////////////////////////////////////////////////////////////////
/// Close row.

void TTreeRow::Close(Option_t *)
{
   if (fRow)    delete [] fRow;
   if (fFields) delete [] fFields;
   fColumnCount = 0;
   fOriginal = 0;
}

////////////////////////////////////////////////////////////////////////////////
/// Check if row is open and field index within range.

Bool_t TTreeRow::IsValid(Int_t field)
{
   if (!fFields && !fOriginal) {
      Error("IsValid", "row closed");
      return kFALSE;
   }
   if (field < 0 || field >= fColumnCount) {
      Error("IsValid", "field index out of bounds");
      return kFALSE;
   }
   return kTRUE;
}

////////////////////////////////////////////////////////////////////////////////
/// Get length in bytes of specified field.

ULong_t TTreeRow::GetFieldLength(Int_t field)
{
   if (!IsValid(field))
      return 0;

   if (fOriginal)
      return fOriginal->GetFieldLength(field);

   if (field > 0) return fFields[field] - fFields[field-1] -1;
   else           return fFields[0] -1;
}

////////////////////////////////////////////////////////////////////////////////
/// Get specified field from row (0 <= field < GetFieldCount()).

const char *TTreeRow::GetField(Int_t field)
{
   if (!IsValid(field))
      return 0;

   if (fOriginal)
      return fOriginal->GetField(field);

   if (field > 0) return fRow +fFields[field-1];
   else           return fRow;
}

////////////////////////////////////////////////////////////////////////////////
/// The field and row information.

void TTreeRow::SetRow(const Int_t *fields, const char *row)
{
   if (!fColumnCount) return;
   if (fFields) delete [] fFields;
   Int_t nch    = fields[fColumnCount-1];
   fFields      = new Int_t[fColumnCount];
   fOriginal    = 0;
   fRow         = new char[nch];
   for (Int_t i=0;i<fColumnCount;i++) fFields[i] = fields[i];
   memcpy(fRow,row,nch);
}

////////////////////////////////////////////////////////////////////////////////
/// Stream an object of class TTreeRow.

void TTreeRow::Streamer(TBuffer &R__b)
{
   UInt_t R__s, R__c;
   if (R__b.IsReading()) {
      R__b.ReadVersion(&R__s, &R__c);
      TSQLRow::Streamer(R__b);
      R__b >> fColumnCount;
      fFields = new Int_t[fColumnCount];
      R__b.ReadFastArray(fFields,fColumnCount);
      Int_t nch;
      R__b >> nch;
      fRow = new char[nch];
      R__b.ReadFastArray(fRow,nch);
      R__b.CheckByteCount(R__s, R__c, TTreeRow::IsA());
   } else {
      R__c = R__b.WriteVersion(TTreeRow::Class(),kTRUE);
      TSQLRow::Streamer(R__b);
      R__b << fColumnCount;
      R__b.WriteFastArray(fFields,fColumnCount);
      Int_t nch = fFields ? fFields[fColumnCount-1] : 0;
      R__b << nch;
      R__b.WriteFastArray(fRow,nch);
      R__b.SetByteCount(R__c,kTRUE);
   }
}
<|endoftext|>


<commit_before>/*
   Copyright (C) 2018 Alexandr Akulich <akulichalexander@gmail.com>

   This file is a part of TelegramQt library.

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

   This library 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.

 */

#include "ClientRpcLayerExtension.hpp"
#include "CTelegramStream.hpp"
#include "PendingRpcOperation.hpp"
#include "Utils.hpp"

#include <QLoggingCategory>

Q_LOGGING_CATEGORY(c_clientRpcLayerExtensionCategory, "telegram.client.rpclayer.ext", QtWarningMsg)

namespace Telegram {

namespace Client {

BaseRpcLayerExtension::BaseRpcLayerExtension(QObject *parent) :
    QObject(parent)
{
}

void BaseRpcLayerExtension::prepareReplyStream(TelegramStream *stream, PendingRpcOperation *operation)
{
    // TODO: Implement static isValid(TLValue::Value) method for TLTypes and
    // add a generated check that TLType is valid type for the RPC request.
    // Probably it would be better to hide this method from subclasses by adding a processReply()
    // reimpl with type-specific code (check for TLType::isValid() and call this method)

    QByteArray data = operation->replyData();

    if (data.size() > 4) {
        if (TLValue::firstFromArray(data) == TLValue::GzipPacked) {
            TelegramStream packedStream(data);
            TLValue gzipValue;
            packedStream >> gzipValue;
            packedStream >> data;
            data = Utils::unpackGZip(data);
        }
    }
#ifdef DUMP_CLIENT_RPC_PACKETS
    qCDebug(c_clientRpcLayerExtensionCategory).noquote() << "BaseRpcLayerExtension: RPC Reply bytes:" << data.size() << data.toHex();
#endif
    stream->setData(data);
}

void BaseRpcLayerExtension::setRpcProcessingMethod(RpcProcessingMethod sendMethod)
{
    qCDebug(c_clientRpcLayerExtensionCategory) << this << "update processing method";
    m_processingMethod = sendMethod;
}

void BaseRpcLayerExtension::processRpcCall(PendingRpcOperation *operation)
{
    qCDebug(c_clientRpcLayerExtensionCategory) << this << "process" << operation << TLValue::firstFromArray(operation->requestData());
    if (m_processingMethod) {
        m_processingMethod(operation);
    } else {
        qCWarning(c_clientRpcLayerExtensionCategory) << Q_FUNC_INFO << this << operation << TLValue::firstFromArray(operation->requestData()) << "is not processed";
    }
}

} // Client namespace

} // Telegram namespace
<commit_msg>Client/RpcLayerExtension: Instantiate bool reply<commit_after>/*
   Copyright (C) 2018 Alexandr Akulich <akulichalexander@gmail.com>

   This file is a part of TelegramQt library.

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

   This library 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.

 */

#include "ClientRpcLayerExtension_p.hpp"
#include "CTelegramStream.hpp"
#include "PendingRpcOperation.hpp"
#include "Utils.hpp"

#include <QLoggingCategory>

Q_LOGGING_CATEGORY(c_clientRpcLayerExtensionCategory, "telegram.client.rpclayer.ext", QtWarningMsg)

namespace Telegram {

namespace Client {

template bool BaseRpcLayerExtension::processReply(PendingRpcOperation *operation, TLBool *output);

BaseRpcLayerExtension::BaseRpcLayerExtension(QObject *parent) :
    QObject(parent)
{
}

void BaseRpcLayerExtension::prepareReplyStream(TelegramStream *stream, PendingRpcOperation *operation)
{
    // TODO: Implement static isValid(TLValue::Value) method for TLTypes and
    // add a generated check that TLType is valid type for the RPC request.
    // Probably it would be better to hide this method from subclasses by adding a processReply()
    // reimpl with type-specific code (check for TLType::isValid() and call this method)

    QByteArray data = operation->replyData();

    if (data.size() > 4) {
        if (TLValue::firstFromArray(data) == TLValue::GzipPacked) {
            TelegramStream packedStream(data);
            TLValue gzipValue;
            packedStream >> gzipValue;
            packedStream >> data;
            data = Utils::unpackGZip(data);
        }
    }
#ifdef DUMP_CLIENT_RPC_PACKETS
    qCDebug(c_clientRpcLayerExtensionCategory).noquote() << "BaseRpcLayerExtension: RPC Reply bytes:" << data.size() << data.toHex();
#endif
    stream->setData(data);
}

void BaseRpcLayerExtension::setRpcProcessingMethod(RpcProcessingMethod sendMethod)
{
    qCDebug(c_clientRpcLayerExtensionCategory) << this << "update processing method";
    m_processingMethod = sendMethod;
}

void BaseRpcLayerExtension::processRpcCall(PendingRpcOperation *operation)
{
    qCDebug(c_clientRpcLayerExtensionCategory) << this << "process" << operation << TLValue::firstFromArray(operation->requestData());
    if (m_processingMethod) {
        m_processingMethod(operation);
    } else {
        qCWarning(c_clientRpcLayerExtensionCategory) << Q_FUNC_INFO << this << operation << TLValue::firstFromArray(operation->requestData()) << "is not processed";
    }
}

} // Client namespace

} // Telegram namespace
<|endoftext|>


<commit_before>/*
 * This file is part of TelepathyQt4
 *
 * Copyright (C) 2008 Collabora Ltd. <http://www.collabora.co.uk/>
 * Copyright (C) 2008 Nokia Corporation
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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 library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "cli-pending-operation.h"

#include <QTimer>

#include <QDBusPendingCall>
#include <QDBusPendingCallWatcher>

#include "cli-pending-operation.moc.hpp"
#include "debug-internal.hpp"

namespace Telepathy
{
namespace Client
{

struct PendingOperation::Private
{
    inline Private()
      : errorName(QString()),
        errorMessage(QString()),
        finished(false)
    { }

    QString errorName;
    QString errorMessage;
    bool finished;
};

PendingOperation::PendingOperation(QObject* parent)
  : QObject(parent),
    mPriv(new Private())
{
}

PendingOperation::~PendingOperation()
{
    if (!mPriv->finished) {
        qWarning() << this
                << "still pending when it was deleted - finished will "
                   "never be emitted";
    }

    delete mPriv;
}

void PendingOperation::emitFinished()
{
    Q_ASSERT(mPriv->finished);
    emit finished(this);
    deleteLater();
}

void PendingOperation::setFinished()
{
    if (mPriv->finished) {
        if (mPriv->errorName.isEmpty())
            qWarning() << this << "trying to finish with success, but already"
              " failed with" << errorName() << ":" << errorMessage();
        else
            qWarning() << this << "trying to finish with success, but already"
              " succeeded";
        return;
    }

    mPriv->finished = true;
    Q_ASSERT(isValid());
    QTimer::singleShot(0, this, SLOT(emitFinished()));
}

void PendingOperation::setFinishedWithError(const QString& name,
        const QString& message)
{
    if (mPriv->finished) {
        if (mPriv->errorName.isEmpty())
            qWarning() << this << "trying to fail with" << name <<
              "but already failed with" << errorName() << ":" <<
              errorMessage();
        else
            qWarning() << this << "trying to fail with" << name <<
              "but already succeeded";
        return;
    }

    if (name.isEmpty()) {
        qWarning() << this << "should be given a non-empty error name";
        mPriv->errorName = "org.freedesktop.Telepathy.Qt4.ErrorHandlingError";
    }
    else {
        mPriv->errorName = name;
    }

    mPriv->errorMessage = message;
    mPriv->finished = true;
    Q_ASSERT(isError());
    QTimer::singleShot(0, this, SLOT(emitFinished()));
}

void PendingOperation::setFinishedWithError(const QDBusError& error)
{
    setFinishedWithError(error.name(), error.message());
}

bool PendingOperation::isValid() const
{
    return (mPriv->finished && mPriv->errorName.isEmpty());
}

bool PendingOperation::isFinished() const
{
    return mPriv->finished;
}

bool PendingOperation::isError() const
{
    return (mPriv->finished && !mPriv->errorName.isEmpty());
}

QString PendingOperation::errorName() const
{
    return mPriv->errorName;
}

QString PendingOperation::errorMessage() const
{
    return mPriv->errorMessage;
}

PendingVoidMethodCall::PendingVoidMethodCall(QObject* proxy,
    QDBusPendingCall call)
  : PendingOperation(proxy),
    mPriv(0)
{
    connect(new QDBusPendingCallWatcher(call),
        SIGNAL(finished(QDBusPendingCallWatcher*)),
        this,
        SLOT(watcherFinished(QDBusPendingCallWatcher*)));
}

void PendingVoidMethodCall::watcherFinished(QDBusPendingCallWatcher* watcher)
{
    if (watcher->isError())
    {
        setFinishedWithError(watcher->error());
    }
    else
    {
        setFinished();
    }
}

} // Telepathy::Client
} // Telepathy
<commit_msg>PendingOperation: use the telepathy-qt4 debug system<commit_after>/*
 * This file is part of TelepathyQt4
 *
 * Copyright (C) 2008 Collabora Ltd. <http://www.collabora.co.uk/>
 * Copyright (C) 2008 Nokia Corporation
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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 library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "cli-pending-operation.h"

#include <QTimer>

#include <QDBusPendingCall>
#include <QDBusPendingCallWatcher>

#include "cli-pending-operation.moc.hpp"
#include "debug-internal.hpp"

namespace Telepathy
{
namespace Client
{

struct PendingOperation::Private
{
    inline Private()
      : errorName(QString()),
        errorMessage(QString()),
        finished(false)
    { }

    QString errorName;
    QString errorMessage;
    bool finished;
};

PendingOperation::PendingOperation(QObject* parent)
  : QObject(parent),
    mPriv(new Private())
{
}

PendingOperation::~PendingOperation()
{
    if (!mPriv->finished) {
        warning() << this
                << "still pending when it was deleted - finished will "
                   "never be emitted";
    }

    delete mPriv;
}

void PendingOperation::emitFinished()
{
    Q_ASSERT(mPriv->finished);
    emit finished(this);
    deleteLater();
}

void PendingOperation::setFinished()
{
    if (mPriv->finished) {
        if (mPriv->errorName.isEmpty())
            warning() << this << "trying to finish with success, but already"
              " failed with" << errorName() << ":" << errorMessage();
        else
            warning() << this << "trying to finish with success, but already"
              " succeeded";
        return;
    }

    mPriv->finished = true;
    Q_ASSERT(isValid());
    QTimer::singleShot(0, this, SLOT(emitFinished()));
}

void PendingOperation::setFinishedWithError(const QString& name,
        const QString& message)
{
    if (mPriv->finished) {
        if (mPriv->errorName.isEmpty())
            warning() << this << "trying to fail with" << name <<
              "but already failed with" << errorName() << ":" <<
              errorMessage();
        else
            warning() << this << "trying to fail with" << name <<
              "but already succeeded";
        return;
    }

    if (name.isEmpty()) {
        warning() << this << "should be given a non-empty error name";
        mPriv->errorName = "org.freedesktop.Telepathy.Qt4.ErrorHandlingError";
    }
    else {
        mPriv->errorName = name;
    }

    mPriv->errorMessage = message;
    mPriv->finished = true;
    Q_ASSERT(isError());
    QTimer::singleShot(0, this, SLOT(emitFinished()));
}

void PendingOperation::setFinishedWithError(const QDBusError& error)
{
    setFinishedWithError(error.name(), error.message());
}

bool PendingOperation::isValid() const
{
    return (mPriv->finished && mPriv->errorName.isEmpty());
}

bool PendingOperation::isFinished() const
{
    return mPriv->finished;
}

bool PendingOperation::isError() const
{
    return (mPriv->finished && !mPriv->errorName.isEmpty());
}

QString PendingOperation::errorName() const
{
    return mPriv->errorName;
}

QString PendingOperation::errorMessage() const
{
    return mPriv->errorMessage;
}

PendingVoidMethodCall::PendingVoidMethodCall(QObject* proxy,
    QDBusPendingCall call)
  : PendingOperation(proxy),
    mPriv(0)
{
    connect(new QDBusPendingCallWatcher(call),
        SIGNAL(finished(QDBusPendingCallWatcher*)),
        this,
        SLOT(watcherFinished(QDBusPendingCallWatcher*)));
}

void PendingVoidMethodCall::watcherFinished(QDBusPendingCallWatcher* watcher)
{
    if (watcher->isError())
    {
        setFinishedWithError(watcher->error());
    }
    else
    {
        setFinished();
    }
}

} // Telepathy::Client
} // Telepathy
<|endoftext|>


<commit_before>#include "ofApp.h"

//--------------------------------------------------------------
void ofApp::setup(){
    SM.setup();

}

//--------------------------------------------------------------
void ofApp::update(){
    SM.update();

    cout << ofGetFrameRate() << endl;
}

//--------------------------------------------------------------
void ofApp::draw(){
    ofBackground(40);

    ofPushMatrix();

    // if draw two up:

#ifdef DRAW_TWO_UP
    float h = 504 * 1920.0/(float)(504+504);
    ofTranslate(0,(1080-h)*0.5);
    ofScale(1920.0/(float)(504+504), 1920.0/(float)(504+504));
    SM.draw();
#elif defined DRAW_ONE_BIG
    float scale = 1080.0/(float)(504);
    float w = scale * 504;
    ofTranslate((1920-w)*0.5, 0);
    ofScale(scale, scale);
    SM.draw();
#else
    SM.draw();
#endif

    ofPopMatrix();
}

//--------------------------------------------------------------
void ofApp::keyPressed(int key){

    if (key == ' '){
        SM.advanceScene();
    } else if (key == '.'){
		SM.regressScene();
	}

    if (key == 'f'){
        ofToggleFullscreen();
    }

    if (key == 's') {
        SM.screenGrab();
    }
}

//--------------------------------------------------------------
void ofApp::keyReleased(int key){

}

//--------------------------------------------------------------
void ofApp::mouseMoved(int x, int y ){

}

//--------------------------------------------------------------
void ofApp::mouseDragged(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mousePressed(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mouseReleased(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mouseEntered(int x, int y){

}

//--------------------------------------------------------------
void ofApp::mouseExited(int x, int y){

}

//--------------------------------------------------------------
void ofApp::windowResized(int w, int h){

}

//--------------------------------------------------------------
void ofApp::gotMessage(ofMessage msg){

}

//--------------------------------------------------------------
void ofApp::dragEvent(ofDragInfo dragInfo){

}
<commit_msg>Make app background black<commit_after>#include "ofApp.h"

//--------------------------------------------------------------
void ofApp::setup(){
    SM.setup();

}

//--------------------------------------------------------------
void ofApp::update(){
    SM.update();

    cout << ofGetFrameRate() << endl;
}

//--------------------------------------------------------------
void ofApp::draw(){
    ofBackground(0);

    ofPushMatrix();

    // if draw two up:

#ifdef DRAW_TWO_UP
    float h = 504 * 1920.0/(float)(504+504);
    ofTranslate(0,(1080-h)*0.5);
    ofScale(1920.0/(float)(504+504), 1920.0/(float)(504+504));
    SM.draw();
#elif defined DRAW_ONE_BIG
    float scale = 1080.0/(float)(504);
    float w = scale * 504;
    ofTranslate((1920-w)*0.5, 0);
    ofScale(scale, scale);
    SM.draw();
#else
    SM.draw();
#endif

    ofPopMatrix();
}

//--------------------------------------------------------------
void ofApp::keyPressed(int key){

    if (key == ' '){
        SM.advanceScene();
    } else if (key == '.'){
		SM.regressScene();
	}

    if (key == 'f'){
        ofToggleFullscreen();
    }

    if (key == 's') {
        SM.screenGrab();
    }
}

//--------------------------------------------------------------
void ofApp::keyReleased(int key){

}

//--------------------------------------------------------------
void ofApp::mouseMoved(int x, int y ){

}

//--------------------------------------------------------------
void ofApp::mouseDragged(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mousePressed(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mouseReleased(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mouseEntered(int x, int y){

}

//--------------------------------------------------------------
void ofApp::mouseExited(int x, int y){

}

//--------------------------------------------------------------
void ofApp::windowResized(int w, int h){

}

//--------------------------------------------------------------
void ofApp::gotMessage(ofMessage msg){

}

//--------------------------------------------------------------
void ofApp::dragEvent(ofDragInfo dragInfo){

}
<|endoftext|>


<commit_before>/*
 * Multi-carrier radio interface
 *
 * Copyright (C) 2016 Ettus Research LLC
 *
 * Author: Tom Tsou <tom.tsou@ettus.com>
 *
 * SPDX-License-Identifier: AGPL-3.0+
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * See the COPYING file in the main directory for details.
 */

#include <radioInterface.h>
#include <Logger.h>

#include "Resampler.h"

extern "C" {
#include "convert.h"
}

/* Resampling parameters for 64 MHz clocking */
#define RESAMP_INRATE			65
#define RESAMP_OUTRATE			(96 / 2)

/* Universal resampling parameters */
#define NUMCHUNKS				24

/* number of narrow-band virtual ARFCNs in this wide-band multi-ARFCN device */
#define MCHANS					4

RadioInterfaceMulti::RadioInterfaceMulti(RadioDevice *radio, size_t tx_sps,
					 size_t rx_sps, size_t chans)
	: RadioInterface(radio, tx_sps, rx_sps, chans),
	  outerSendBuffer(NULL), outerRecvBuffer(NULL),
	  dnsampler(NULL), upsampler(NULL), channelizer(NULL), synthesis(NULL)
{
}

RadioInterfaceMulti::~RadioInterfaceMulti()
{
	close();
}

void RadioInterfaceMulti::close()
{
	delete outerSendBuffer;
	delete outerRecvBuffer;
	delete dnsampler;
	delete upsampler;
	delete channelizer;
	delete synthesis;

	outerSendBuffer = NULL;
	outerRecvBuffer = NULL;
	dnsampler = NULL;
	upsampler = NULL;
	channelizer = NULL;
	synthesis = NULL;

	mReceiveFIFO.resize(0);
	powerScaling.resize(0);
	history.resize(0);
	active.resize(0);
	rx_freq_state.resize(0);
	tx_freq_state.resize(0);

	RadioInterface::close();
}

/*! we re-map the physical channels from the filter bank to logical per-TRX channels
 *  \param[in] pchan physical channel number within the channelizer
 *  \param[in] chans total number of narrow-band ARFCN channels
 *  \returns logical (TRX) channel number, or -1 in case there is none */
static int getLogicalChan(size_t pchan, size_t chans)
{
	switch (chans) {
	case 1:
		if (pchan == 0)
			return 0;
		else
			return -1;
		break;
	case 2:
		if (pchan == 0)
			return 0;
		if (pchan == 3)
			return 1;
		else
			return -1;
		break;
	case 3:
		if (pchan == 1)
			return 0;
		if (pchan == 0)
			return 1;
		if (pchan == 3)
			return 2;
		else
			return -1;
		break;
	default:
		break;
	};

	return -1;
}

/*! do we need to frequency shift our spectrum or not?
 *  \param chans total number of channels
 *  \returns 1 if we need to shift; 0 if not; -1 on error */
static int getFreqShift(size_t chans)
{
	switch (chans) {
	case 1:
		return 0;
	case 2:
		return 0;
	case 3:
		return 1;
	default:
		break;
	};

	return -1;
}

/* Initialize I/O specific objects */
bool RadioInterfaceMulti::init(int type)
{
	float cutoff = 1.0f;
	size_t inchunk = 0, outchunk = 0;

	if (mChans > MCHANS - 1) {
		LOG(ALERT) << "Invalid channel configuration " << mChans;
		return false;
	}

	close();

	sendBuffer.resize(mChans);
	recvBuffer.resize(mChans);
	convertSendBuffer.resize(1);
	convertRecvBuffer.resize(1);

	mReceiveFIFO.resize(mChans);
	powerScaling.resize(mChans);
	history.resize(mChans);
	rx_freq_state.resize(mChans);
	tx_freq_state.resize(mChans);
	active.resize(MCHANS, false);

	/* 4 == sps */
	inchunk = RESAMP_INRATE * 4;
	outchunk = RESAMP_OUTRATE * 4;

	if (inchunk  * NUMCHUNKS < 625 * 2) {
		LOG(ALERT) << "Invalid inner chunk size " << inchunk;
		return false;
	}

	dnsampler = new Resampler(RESAMP_INRATE, RESAMP_OUTRATE);
	if (!dnsampler->init(1.0)) {
		LOG(ALERT) << "Rx resampler failed to initialize";
		return false;
	}

	upsampler = new Resampler(RESAMP_OUTRATE, RESAMP_INRATE);
	if (!upsampler->init(cutoff)) {
		LOG(ALERT) << "Tx resampler failed to initialize";
		return false;
	}

	channelizer = new Channelizer(MCHANS, outchunk);
	if (!channelizer->init()) {
		LOG(ALERT) << "Rx channelizer failed to initialize";
		return false;
	}

	synthesis = new Synthesis(MCHANS, outchunk);
	if (!synthesis->init()) {
		LOG(ALERT) << "Tx synthesis filter failed to initialize";
		return false;
	}

	/*
	 * Allocate high and low rate buffers. The high rate receive
	 * buffer and low rate transmit vectors feed into the resampler
	 * and requires headroom equivalent to the filter length. Low
	 * rate buffers are allocated in the main radio interface code.
	 */
	for (size_t i = 0; i < mChans; i++) {
		sendBuffer[i] = new RadioBuffer(NUMCHUNKS, inchunk,
					        upsampler->len(), true);
		recvBuffer[i] = new RadioBuffer(NUMCHUNKS, inchunk,
		                                0, false);
		history[i] = new signalVector(dnsampler->len());

		synthesis->resetBuffer(i);
	}

	outerSendBuffer = new signalVector(synthesis->outputLen());
	outerRecvBuffer = new signalVector(channelizer->inputLen());

	convertSendBuffer[0] = new short[2 * synthesis->outputLen()];
	convertRecvBuffer[0] = new short[2 * channelizer->inputLen()];

	/* Configure channels */
	switch (mChans) {
	case 1:
		active[0] = true;
		break;
	case 2:
		active[0] = true;
		active[3] = true;
		break;
	case 3:
		active[0] = true;
		active[1] = true;
		active[3] = true;
		break;
	default:
		LOG(ALERT) << "Unsupported channel combination";
		return false;
	}

	return true;
}

/* Receive a timestamped chunk from the device */
int RadioInterfaceMulti::pullBuffer()
{
	bool local_underrun;
	size_t num;
	float *buf;
	unsigned int i;

	if (recvBuffer[0]->getFreeSegments() <= 0)
		return -1;

	/* Outer buffer access size is fixed */
	num = mDevice->readSamples(convertRecvBuffer,
				  outerRecvBuffer->size(),
				  &overrun,
				  readTimestamp,
				  &local_underrun);
	if (num != channelizer->inputLen()) {
		LOG(ALERT) << "Receive error " << num << ", " << channelizer->inputLen();
		return -1;
	}

	convert_short_float((float *) outerRecvBuffer->begin(),
			    convertRecvBuffer[0], 2 * outerRecvBuffer->size());

	osmo_trx_sync_or_and_fetch(&underrun, local_underrun);
	readTimestamp += num;

	channelizer->rotate((float *) outerRecvBuffer->begin(),
			    outerRecvBuffer->size());

	for (size_t pchan = 0; pchan < MCHANS; pchan++) {
		if (!active[pchan])
			continue;

		int lchan = getLogicalChan(pchan, mChans);
		if (lchan < 0) {
			LOG(ALERT) << "Invalid logical channel " << pchan;
			continue;
		}

		/*
		 * Update history by writing into the head portion of the
		 * channelizer output buffer. For this to work, filter length of
		 * the polyphase channelizer partition filter should be equal to
		 * or larger than the resampling filter.
		 */
		buf = channelizer->outputBuffer(pchan);
		size_t cLen = channelizer->outputLen();
		size_t hLen = dnsampler->len();

		float *fdst = &buf[2 * -hLen];
		complex *src = history[lchan]->begin();
		for (i = 0; i < hLen; i++) {
			fdst[0] = src->real();
			fdst[1] = src->imag();
			src++;
			fdst += 2;
		}
		complex *dst = history[lchan]->begin();
		float *fsrc = &buf[2 * (cLen - hLen)];
		for (i = 0; i < hLen; i++) {
			*dst = complex(fsrc[0], fsrc[1]);
			fsrc += 2;
			dst++;
		}

		float *wr_segment = recvBuffer[lchan]->getWriteSegment();

		/* Write to the end of the inner receive buffer */
		if (!dnsampler->rotate(channelizer->outputBuffer(pchan),
				       channelizer->outputLen(),
				       wr_segment,
				       recvBuffer[lchan]->getSegmentLen())) {
			LOG(ALERT) << "Sample rate upsampling error";
		}
	}
	return 0;
}

/* Send a timestamped chunk to the device */
bool RadioInterfaceMulti::pushBuffer()
{
	bool local_underrun;
	if (sendBuffer[0]->getAvailSegments() <= 0)
		return false;

	for (size_t pchan = 0; pchan < MCHANS; pchan++) {
		if (!active[pchan]) {
			synthesis->resetBuffer(pchan);
			continue;
		}

		int lchan = getLogicalChan(pchan, mChans);
		if (lchan < 0) {
			LOG(ALERT) << "Invalid logical channel " << pchan;
			continue;
		}

		if (!upsampler->rotate(sendBuffer[lchan]->getReadSegment(),
				       sendBuffer[lchan]->getSegmentLen(),
				       synthesis->inputBuffer(pchan),
				       synthesis->inputLen())) {
			LOG(ALERT) << "Sample rate downsampling error";
		}
	}

	synthesis->rotate((float *) outerSendBuffer->begin(),
			  outerSendBuffer->size());

	convert_float_short(convertSendBuffer[0],
			    (float *) outerSendBuffer->begin(),
			    1.0 / (float) mChans, 2 * outerSendBuffer->size());

	size_t num = mDevice->writeSamples(convertSendBuffer,
					  outerSendBuffer->size(),
					  &local_underrun,
					  writeTimestamp);
	if (num != outerSendBuffer->size()) {
		LOG(ALERT) << "Transmit error " << num;
	}

	osmo_trx_sync_or_and_fetch(&underrun, local_underrun);
	writeTimestamp += num;

	return true;
}

/* Frequency comparison limit */
#define FREQ_DELTA_LIMIT		10.0

static bool fltcmp(double a, double b)
{
	return fabs(a - b) < FREQ_DELTA_LIMIT ? true : false;
}

bool RadioInterfaceMulti::verify_arfcn_consistency(double freq, size_t chan, bool tx)
{
	double freq_i;
	std::string str_dir = tx ? "Tx" : "Rx";
	std::vector<struct freq_cfg_state> &v = tx ? tx_freq_state : rx_freq_state;

	for (size_t i = 0; i < mChans; i++) {
		if (i == chan)
			continue;
		if (!v[i].set)
			continue;

		freq_i = v[i].freq_hz + (double) ((int)chan - (int)i) * MCBTS_SPACING;
		if (!fltcmp(freq, freq_i)) {
			LOGCHAN(chan, DMAIN, ERROR)
				<< "Setting " << str_dir << " frequency " << freq
				<< " is incompatible: already configured channel "
				<< i << " uses frequency " << v[i].freq_hz
				<< " (expected " << freq_i << ")";
			return false;
		}
	}
	v[chan].set = true;
	v[chan].freq_hz = freq;
	return true;
}

bool RadioInterfaceMulti::tuneTx(double freq, size_t chan)
{
	double shift;

	if (chan >= mChans)
		return false;

	if (!verify_arfcn_consistency(freq, chan, true))
		return false;

	if (chan == 0) {
		shift = (double) getFreqShift(mChans);
		return mDevice->setTxFreq(freq + shift * MCBTS_SPACING);
	}

	return true;
}

bool RadioInterfaceMulti::tuneRx(double freq, size_t chan)
{
	double shift;

	if (chan >= mChans)
		return false;

	if (!verify_arfcn_consistency(freq, chan, false))
		return false;

	if (chan == 0) {
		shift = (double) getFreqShift(mChans);
		return mDevice->setRxFreq(freq + shift * MCBTS_SPACING);
	}

	return true;
}

double RadioInterfaceMulti::setRxGain(double db, size_t chan)
{
  if (chan == 0)
    return mDevice->setRxGain(db);
  else
    return mDevice->getRxGain();
}

int RadioInterfaceMulti::setPowerAttenuation(int atten, size_t chan)
{
		return RadioInterface::setPowerAttenuation(atten, 0);

}
<commit_msg>[cosmetic] radioIntefaceMulti: Fix whitespace / indent<commit_after>/*
 * Multi-carrier radio interface
 *
 * Copyright (C) 2016 Ettus Research LLC
 *
 * Author: Tom Tsou <tom.tsou@ettus.com>
 *
 * SPDX-License-Identifier: AGPL-3.0+
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * See the COPYING file in the main directory for details.
 */

#include <radioInterface.h>
#include <Logger.h>

#include "Resampler.h"

extern "C" {
#include "convert.h"
}

/* Resampling parameters for 64 MHz clocking */
#define RESAMP_INRATE			65
#define RESAMP_OUTRATE			(96 / 2)

/* Universal resampling parameters */
#define NUMCHUNKS				24

/* number of narrow-band virtual ARFCNs in this wide-band multi-ARFCN device */
#define MCHANS					4

RadioInterfaceMulti::RadioInterfaceMulti(RadioDevice *radio, size_t tx_sps,
					 size_t rx_sps, size_t chans)
	: RadioInterface(radio, tx_sps, rx_sps, chans),
	  outerSendBuffer(NULL), outerRecvBuffer(NULL),
	  dnsampler(NULL), upsampler(NULL), channelizer(NULL), synthesis(NULL)
{
}

RadioInterfaceMulti::~RadioInterfaceMulti()
{
	close();
}

void RadioInterfaceMulti::close()
{
	delete outerSendBuffer;
	delete outerRecvBuffer;
	delete dnsampler;
	delete upsampler;
	delete channelizer;
	delete synthesis;

	outerSendBuffer = NULL;
	outerRecvBuffer = NULL;
	dnsampler = NULL;
	upsampler = NULL;
	channelizer = NULL;
	synthesis = NULL;

	mReceiveFIFO.resize(0);
	powerScaling.resize(0);
	history.resize(0);
	active.resize(0);
	rx_freq_state.resize(0);
	tx_freq_state.resize(0);

	RadioInterface::close();
}

/*! we re-map the physical channels from the filter bank to logical per-TRX channels
 *  \param[in] pchan physical channel number within the channelizer
 *  \param[in] chans total number of narrow-band ARFCN channels
 *  \returns logical (TRX) channel number, or -1 in case there is none */
static int getLogicalChan(size_t pchan, size_t chans)
{
	switch (chans) {
	case 1:
		if (pchan == 0)
			return 0;
		else
			return -1;
		break;
	case 2:
		if (pchan == 0)
			return 0;
		if (pchan == 3)
			return 1;
		else
			return -1;
		break;
	case 3:
		if (pchan == 1)
			return 0;
		if (pchan == 0)
			return 1;
		if (pchan == 3)
			return 2;
		else
			return -1;
		break;
	default:
		break;
	};

	return -1;
}

/*! do we need to frequency shift our spectrum or not?
 *  \param chans total number of channels
 *  \returns 1 if we need to shift; 0 if not; -1 on error */
static int getFreqShift(size_t chans)
{
	switch (chans) {
	case 1:
		return 0;
	case 2:
		return 0;
	case 3:
		return 1;
	default:
		break;
	};

	return -1;
}

/* Initialize I/O specific objects */
bool RadioInterfaceMulti::init(int type)
{
	float cutoff = 1.0f;
	size_t inchunk = 0, outchunk = 0;

	if (mChans > MCHANS - 1) {
		LOG(ALERT) << "Invalid channel configuration " << mChans;
		return false;
	}

	close();

	sendBuffer.resize(mChans);
	recvBuffer.resize(mChans);
	convertSendBuffer.resize(1);
	convertRecvBuffer.resize(1);

	mReceiveFIFO.resize(mChans);
	powerScaling.resize(mChans);
	history.resize(mChans);
	rx_freq_state.resize(mChans);
	tx_freq_state.resize(mChans);
	active.resize(MCHANS, false);

	/* 4 == sps */
	inchunk = RESAMP_INRATE * 4;
	outchunk = RESAMP_OUTRATE * 4;

	if (inchunk  * NUMCHUNKS < 625 * 2) {
		LOG(ALERT) << "Invalid inner chunk size " << inchunk;
		return false;
	}

	dnsampler = new Resampler(RESAMP_INRATE, RESAMP_OUTRATE);
	if (!dnsampler->init(1.0)) {
		LOG(ALERT) << "Rx resampler failed to initialize";
		return false;
	}

	upsampler = new Resampler(RESAMP_OUTRATE, RESAMP_INRATE);
	if (!upsampler->init(cutoff)) {
		LOG(ALERT) << "Tx resampler failed to initialize";
		return false;
	}

	channelizer = new Channelizer(MCHANS, outchunk);
	if (!channelizer->init()) {
		LOG(ALERT) << "Rx channelizer failed to initialize";
		return false;
	}

	synthesis = new Synthesis(MCHANS, outchunk);
	if (!synthesis->init()) {
		LOG(ALERT) << "Tx synthesis filter failed to initialize";
		return false;
	}

	/*
	 * Allocate high and low rate buffers. The high rate receive
	 * buffer and low rate transmit vectors feed into the resampler
	 * and requires headroom equivalent to the filter length. Low
	 * rate buffers are allocated in the main radio interface code.
	 */
	for (size_t i = 0; i < mChans; i++) {
		sendBuffer[i] = new RadioBuffer(NUMCHUNKS, inchunk,
					        upsampler->len(), true);
		recvBuffer[i] = new RadioBuffer(NUMCHUNKS, inchunk,
		                                0, false);
		history[i] = new signalVector(dnsampler->len());

		synthesis->resetBuffer(i);
	}

	outerSendBuffer = new signalVector(synthesis->outputLen());
	outerRecvBuffer = new signalVector(channelizer->inputLen());

	convertSendBuffer[0] = new short[2 * synthesis->outputLen()];
	convertRecvBuffer[0] = new short[2 * channelizer->inputLen()];

	/* Configure channels */
	switch (mChans) {
	case 1:
		active[0] = true;
		break;
	case 2:
		active[0] = true;
		active[3] = true;
		break;
	case 3:
		active[0] = true;
		active[1] = true;
		active[3] = true;
		break;
	default:
		LOG(ALERT) << "Unsupported channel combination";
		return false;
	}

	return true;
}

/* Receive a timestamped chunk from the device */
int RadioInterfaceMulti::pullBuffer()
{
	bool local_underrun;
	size_t num;
	float *buf;
	unsigned int i;

	if (recvBuffer[0]->getFreeSegments() <= 0)
		return -1;

	/* Outer buffer access size is fixed */
	num = mDevice->readSamples(convertRecvBuffer,
				  outerRecvBuffer->size(),
				  &overrun,
				  readTimestamp,
				  &local_underrun);
	if (num != channelizer->inputLen()) {
		LOG(ALERT) << "Receive error " << num << ", " << channelizer->inputLen();
		return -1;
	}

	convert_short_float((float *) outerRecvBuffer->begin(),
			    convertRecvBuffer[0], 2 * outerRecvBuffer->size());

	osmo_trx_sync_or_and_fetch(&underrun, local_underrun);
	readTimestamp += num;

	channelizer->rotate((float *) outerRecvBuffer->begin(),
			    outerRecvBuffer->size());

	for (size_t pchan = 0; pchan < MCHANS; pchan++) {
		if (!active[pchan])
			continue;

		int lchan = getLogicalChan(pchan, mChans);
		if (lchan < 0) {
			LOG(ALERT) << "Invalid logical channel " << pchan;
			continue;
		}

		/*
		 * Update history by writing into the head portion of the
		 * channelizer output buffer. For this to work, filter length of
		 * the polyphase channelizer partition filter should be equal to
		 * or larger than the resampling filter.
		 */
		buf = channelizer->outputBuffer(pchan);
		size_t cLen = channelizer->outputLen();
		size_t hLen = dnsampler->len();

		float *fdst = &buf[2 * -hLen];
		complex *src = history[lchan]->begin();
		for (i = 0; i < hLen; i++) {
			fdst[0] = src->real();
			fdst[1] = src->imag();
			src++;
			fdst += 2;
		}
		complex *dst = history[lchan]->begin();
		float *fsrc = &buf[2 * (cLen - hLen)];
		for (i = 0; i < hLen; i++) {
			*dst = complex(fsrc[0], fsrc[1]);
			fsrc += 2;
			dst++;
		}

		float *wr_segment = recvBuffer[lchan]->getWriteSegment();

		/* Write to the end of the inner receive buffer */
		if (!dnsampler->rotate(channelizer->outputBuffer(pchan),
				       channelizer->outputLen(),
				       wr_segment,
				       recvBuffer[lchan]->getSegmentLen())) {
			LOG(ALERT) << "Sample rate upsampling error";
		}
	}
	return 0;
}

/* Send a timestamped chunk to the device */
bool RadioInterfaceMulti::pushBuffer()
{
	bool local_underrun;
	if (sendBuffer[0]->getAvailSegments() <= 0)
		return false;

	for (size_t pchan = 0; pchan < MCHANS; pchan++) {
		if (!active[pchan]) {
			synthesis->resetBuffer(pchan);
			continue;
		}

		int lchan = getLogicalChan(pchan, mChans);
		if (lchan < 0) {
			LOG(ALERT) << "Invalid logical channel " << pchan;
			continue;
		}

		if (!upsampler->rotate(sendBuffer[lchan]->getReadSegment(),
				       sendBuffer[lchan]->getSegmentLen(),
				       synthesis->inputBuffer(pchan),
				       synthesis->inputLen())) {
			LOG(ALERT) << "Sample rate downsampling error";
		}
	}

	synthesis->rotate((float *) outerSendBuffer->begin(),
			  outerSendBuffer->size());

	convert_float_short(convertSendBuffer[0],
			    (float *) outerSendBuffer->begin(),
			    1.0 / (float) mChans, 2 * outerSendBuffer->size());

	size_t num = mDevice->writeSamples(convertSendBuffer,
					  outerSendBuffer->size(),
					  &local_underrun,
					  writeTimestamp);
	if (num != outerSendBuffer->size()) {
		LOG(ALERT) << "Transmit error " << num;
	}

	osmo_trx_sync_or_and_fetch(&underrun, local_underrun);
	writeTimestamp += num;

	return true;
}

/* Frequency comparison limit */
#define FREQ_DELTA_LIMIT		10.0

static bool fltcmp(double a, double b)
{
	return fabs(a - b) < FREQ_DELTA_LIMIT ? true : false;
}

bool RadioInterfaceMulti::verify_arfcn_consistency(double freq, size_t chan, bool tx)
{
	double freq_i;
	std::string str_dir = tx ? "Tx" : "Rx";
	std::vector<struct freq_cfg_state> &v = tx ? tx_freq_state : rx_freq_state;

	for (size_t i = 0; i < mChans; i++) {
		if (i == chan)
			continue;
		if (!v[i].set)
			continue;

		freq_i = v[i].freq_hz + (double) ((int)chan - (int)i) * MCBTS_SPACING;
		if (!fltcmp(freq, freq_i)) {
			LOGCHAN(chan, DMAIN, ERROR)
				<< "Setting " << str_dir << " frequency " << freq
				<< " is incompatible: already configured channel "
				<< i << " uses frequency " << v[i].freq_hz
				<< " (expected " << freq_i << ")";
			return false;
		}
	}
	v[chan].set = true;
	v[chan].freq_hz = freq;
	return true;
}

bool RadioInterfaceMulti::tuneTx(double freq, size_t chan)
{
	double shift;

	if (chan >= mChans)
		return false;

	if (!verify_arfcn_consistency(freq, chan, true))
		return false;

	if (chan == 0) {
		shift = (double) getFreqShift(mChans);
		return mDevice->setTxFreq(freq + shift * MCBTS_SPACING);
	}

	return true;
}

bool RadioInterfaceMulti::tuneRx(double freq, size_t chan)
{
	double shift;

	if (chan >= mChans)
		return false;

	if (!verify_arfcn_consistency(freq, chan, false))
		return false;

	if (chan == 0) {
		shift = (double) getFreqShift(mChans);
		return mDevice->setRxFreq(freq + shift * MCBTS_SPACING);
	}

	return true;
}

double RadioInterfaceMulti::setRxGain(double db, size_t chan)
{
	if (chan == 0)
		return mDevice->setRxGain(db);
	else
		return mDevice->getRxGain();
}

int RadioInterfaceMulti::setPowerAttenuation(int atten, size_t chan)
{
	return RadioInterface::setPowerAttenuation(atten, 0);
}
<|endoftext|>