<commit_before>
#pragma once

#include <iostream>
#include <thread>
#include <chrono>
#include <boost/asio.hpp>

#include "common.h"

#define MAX_PACKET_SIZE	65536

using namespace boost::asio;
using namespace std::chrono;

class test_latency_client
{
private:
    enum { PACKET_SIZE = MAX_PACKET_SIZE };

    boost::asio::io_service & io_service_;
    ip::tcp::socket socket_;
    std::uint32_t packet_size_;

    uint64_t last_query_count_;
    uint64_t total_query_count_;
    double last_total_latency_;
    double total_latency_;

    duration<double> elapsed_time_;
    time_point<high_resolution_clock> send_time_;
    time_point<high_resolution_clock> recieve_time_;
    time_point<high_resolution_clock> last_time_;

    char data_[PACKET_SIZE];

public:
    test_latency_client(boost::asio::io_service & io_service,
        ip::tcp::resolver::iterator endpoint_iterator, std::uint32_t packet_size)
        : io_service_(io_service),
          socket_(io_service), packet_size_(packet_size),
          last_query_count_(0), total_query_count_(0), last_total_latency_(0.0), total_latency_(0.0)
    {
        ::memset(data_, 'h', sizeof(data_));
        last_time_ = high_resolution_clock::now();
        do_connect(endpoint_iterator);
    }

    ~test_latency_client()
    {
        time_point<high_resolution_clock> startime = high_resolution_clock::now();

        time_point<high_resolution_clock> endtime = high_resolution_clock::now();
        duration<double> elapsed_time = duration_cast< duration<double> >(endtime - startime);
    }

private:
    void display_counters()
    {
        elapsed_time_ = duration_cast< duration<double> >(recieve_time_ - send_time_);
        last_query_count_++;
        total_query_count_++;
        last_total_latency_ += elapsed_time_.count();
        total_latency_ += elapsed_time_.count();
        time_point<high_resolution_clock> now_time = high_resolution_clock::now();
        duration<double> interval_time = duration_cast< duration<double> >(now_time - last_time_);
        double avg_latency, avg_total_latency;
        if (interval_time.count() > 1.0) {
            std::cout << "packet_size =" << packet_size_ << " B, latency total = " << last_total_latency_ << " ms" <<  std::endl;
            // average latency (one second interval)
            if (last_query_count_ != 0)
                avg_latency = (last_total_latency_ * 1000.0) / (double)last_query_count_;
            else
                avg_latency = 0.0;
            std::cout << "average latency       = " << avg_latency
                      << " ms, query count       = " << last_query_count_ << std::endl;

            // average latency total
            if (total_query_count_ != 0)
                avg_total_latency = (total_latency_ * 1000.0) / (double)total_query_count_;
            else
                avg_total_latency = 0.0;
            std::cout << "average latency total = " << avg_total_latency
                      << " ms, query count total = " << total_query_count_ << std::endl;
            std::cout << std::endl;

            // Reset the counters
            last_time_ = high_resolution_clock::now();
            last_query_count_ = 0;
            last_total_latency_ = 0.0;
        }
    }

    void do_connect(ip::tcp::resolver::iterator endpoint_iterator)
    {
        boost::asio::async_connect(socket_, endpoint_iterator,
            [this](boost::system::error_code ec, ip::tcp::resolver::iterator)
            {
                if (!ec)
                {
                    //do_read();
                    do_write();
                }
            });
    }

    void do_read()
    {
        boost::asio::async_read(socket_,
            boost::asio::buffer(data_, packet_size_),
            [this](boost::system::error_code ec, std::size_t bytes_transferred)
            {
                if ((uint32_t)bytes_transferred != packet_size_) {
                    std::cout << "test_latency_client::do_read(): async_read(), bytes_transferred = "
                              << bytes_transferred << " bytes." << std::endl;
                }
                if (!ec)
                {
                    // Have recieved the response message
                    recieve_time_ = high_resolution_clock::now();
                    display_counters();
                    do_write();
                }
            });
    }

    void do_write()
    {
        // Prepare to send the request message
        send_time_ = high_resolution_clock::now();
        boost::asio::async_write(socket_,
            boost::asio::buffer(data_, packet_size_),
            [this](boost::system::error_code ec, std::size_t bytes_transferred)
            {
                if ((uint32_t)bytes_transferred != packet_size_) {
                    std::cout << "test_latency_client::do_write(): async_write(), bytes_transferred = "
                              << bytes_transferred << " bytes." << std::endl;
                }
                if (!ec)
                {
                    do_read();
                }
            });
    }
};
<commit_msg>小改动.<commit_after>
#pragma once

#include <iostream>
#include <thread>
#include <chrono>
#include <boost/asio.hpp>

#include "common.h"

#define MAX_PACKET_SIZE	65536

using namespace boost::asio;
using namespace std::chrono;

class test_latency_client
{
private:
    enum { PACKET_SIZE = MAX_PACKET_SIZE };

    boost::asio::io_service & io_service_;
    ip::tcp::socket socket_;
    std::uint32_t packet_size_;

    uint64_t last_query_count_;
    uint64_t total_query_count_;
    double last_total_latency_;
    double total_latency_;

    duration<double> elapsed_time_;
    time_point<high_resolution_clock> send_time_;
    time_point<high_resolution_clock> recieve_time_;
    time_point<high_resolution_clock> last_time_;

    char data_[PACKET_SIZE];

public:
    test_latency_client(boost::asio::io_service & io_service,
        ip::tcp::resolver::iterator endpoint_iterator, std::uint32_t packet_size)
        : io_service_(io_service),
          socket_(io_service), packet_size_(packet_size),
          last_query_count_(0), total_query_count_(0), last_total_latency_(0.0), total_latency_(0.0)
    {
        ::memset(data_, 'h', sizeof(data_));
        last_time_ = high_resolution_clock::now();
        do_connect(endpoint_iterator);
    }

    ~test_latency_client()
    {
        time_point<high_resolution_clock> startime = high_resolution_clock::now();

        time_point<high_resolution_clock> endtime = high_resolution_clock::now();
        duration<double> elapsed_time = duration_cast< duration<double> >(endtime - startime);
    }

private:
    void display_counters()
    {
        elapsed_time_ = duration_cast< duration<double> >(recieve_time_ - send_time_);
        last_query_count_++;
        total_query_count_++;
        last_total_latency_ += elapsed_time_.count();
        total_latency_ += elapsed_time_.count();
        time_point<high_resolution_clock> now_time = high_resolution_clock::now();
        duration<double> interval_time = duration_cast< duration<double> >(now_time - last_time_);
        double avg_latency, avg_total_latency;
        if (interval_time.count() > 1.0) {
            std::cout << "packet_size = " << packet_size_ << " B,                 latency total = "
                      << last_total_latency_ << " ms" <<  std::endl;
            // average latency (one second interval)
            if (last_query_count_ != 0)
                avg_latency = (last_total_latency_ * 1000.0) / (double)last_query_count_;
            else
                avg_latency = 0.0;
            std::cout << "average latency       = " << avg_latency
                      << " ms, query count       = " << last_query_count_ << std::endl;

            // average latency total
            if (total_query_count_ != 0)
                avg_total_latency = (total_latency_ * 1000.0) / (double)total_query_count_;
            else
                avg_total_latency = 0.0;
            std::cout << "average latency total = " << avg_total_latency
                      << " ms, query count total = " << total_query_count_ << std::endl;
            std::cout << std::endl;

            // Reset the counters
            last_time_ = high_resolution_clock::now();
            last_query_count_ = 0;
            last_total_latency_ = 0.0;
        }
    }

    void do_connect(ip::tcp::resolver::iterator endpoint_iterator)
    {
        boost::asio::async_connect(socket_, endpoint_iterator,
            [this](boost::system::error_code ec, ip::tcp::resolver::iterator)
            {
                if (!ec)
                {
                    //do_read();
                    do_write();
                }
            });
    }

    void do_read()
    {
        boost::asio::async_read(socket_,
            boost::asio::buffer(data_, packet_size_),
            [this](boost::system::error_code ec, std::size_t bytes_transferred)
            {
                if ((uint32_t)bytes_transferred != packet_size_) {
                    std::cout << "test_latency_client::do_read(): async_read(), bytes_transferred = "
                              << bytes_transferred << " bytes." << std::endl;
                }
                if (!ec)
                {
                    // Have recieved the response message
                    recieve_time_ = high_resolution_clock::now();
                    display_counters();
                    do_write();
                }
            });
    }

    void do_write()
    {
        // Prepare to send the request message
        send_time_ = high_resolution_clock::now();
        boost::asio::async_write(socket_,
            boost::asio::buffer(data_, packet_size_),
            [this](boost::system::error_code ec, std::size_t bytes_transferred)
            {
                if ((uint32_t)bytes_transferred != packet_size_) {
                    std::cout << "test_latency_client::do_write(): async_write(), bytes_transferred = "
                              << bytes_transferred << " bytes." << std::endl;
                }
                if (!ec)
                {
                    do_read();
                }
            });
    }
};
<|endoftext|>


<commit_before>#ifndef MJOLNIR_CORE_ENERGY_CALCULATION_SIMULATOR_HPP
#define MJOLNIR_CORE_ENERGY_CALCULATION_SIMULATOR_HPP
#include <mjolnir/core/SimulatorBase.hpp>
#include <mjolnir/core/ObserverContainer.hpp>
#include <mjolnir/core/System.hpp>
#include <mjolnir/core/ForceFieldBase.hpp>
#include <mjolnir/core/LoaderBase.hpp>
#include <mjolnir/core/XYZLoader.hpp>
#include <mjolnir/core/DCDLoader.hpp>
#include <mjolnir/core/TRRLoader.hpp>

namespace mjolnir
{

template<typename traitsT>
class EnergyCalculationSimulator final : public SimulatorBase
{
  public:
    using traits_type      = traitsT;
    using real_type        = typename traits_type::real_type;
    using coordinate_type  = typename traits_type::coordinate_type;
    using system_type      = System<traits_type>;
    using forcefield_type  = std::unique_ptr<ForceFieldBase<traits_type>>;
    using observer_type    = ObserverContainer<traits_type>;
    using loader_base_type = LoaderBase<traits_type>;
    using loader_type      = std::unique_ptr<loader_base_type>;

  public:

    EnergyCalculationSimulator(const std::size_t total_step, loader_type&& ld,
            system_type&& sys, forcefield_type&& ff, observer_type&& obs)
        : step_count_(0),     total_step_(total_step),
          ld_(std::move(ld)), sys_(std::move(sys)),
          ff_(std::move(ff)), obs_(std::move(obs)),
          old_position_(sys_.size())
    {}
    ~EnergyCalculationSimulator() override {}

    void initialize() override;
    bool step()       override;
    void run()        override;
    void finalize()   override;

    system_type&       system()       noexcept {return sys_;}
    system_type const& system() const noexcept {return sys_;}

    forcefield_type&       forcefields()       noexcept {return ff_;}
    forcefield_type const& forcefields() const noexcept {return ff_;}

    loader_type&       loader()       noexcept {return ld_;}
    loader_type const& loader() const noexcept {return ld_;}

  protected:

    std::size_t     step_count_, total_step_;
    loader_type     ld_;
    system_type     sys_;
    forcefield_type ff_;
    observer_type   obs_;
    std::vector<coordinate_type> old_position_;
};

template<typename traitsT>
inline void EnergyCalculationSimulator<traitsT>::initialize()
{
    // instead of initializing simulator (it generate velocities), read the
    // current state from the loader.
    //
    // To obtain the total number of snapshots, the loader is already initialized.
    ld_->load_next(this->sys_);

    // sys.initialize() generates the initial velocity, so here it is not needed

    this->ff_->initialize(this->sys_);

    // Since neither save_step nor delta_t are not saved, we add some dummy value.
    this->obs_.initialize(this->total_step_, 1, 1.0, this->sys_, this->ff_);
    return;
}

template<typename traitsT>
inline bool EnergyCalculationSimulator<traitsT>::step()
{
    // this calculates the energy.
    obs_.output(this->step_count_, 0.0, this->sys_, this->ff_);

    // backup current configuration to calculate displacement to determine
    // whether we need to update the neighboring list or not
    for(std::size_t i=0; i<sys_.size(); ++i)
    {
        old_position_[i] = sys_.position(i);
    }

    if(!ld_->load_next(sys_))
    {
        // if loader returns false, it means it fails to read the next traj.
        return false;
    }

    // Here, calling forcefield.update() is not a good idea. It outputs logs
    // because it considers all the state including both system and forcefield
    // has been changed. But, in this simulator, forcefield does not change.
    real_type max_displacement_sq = 0.0;
    for(std::size_t i=0; i<sys_.size(); ++i)
    {
        max_displacement_sq = std::max(max_displacement_sq, math::length_sq(
                    sys_.adjust_direction(sys_.position(i), old_position_[i])));
    }
    // update neighboring list if needed
    ff_->reduce_margin(2 * std::sqrt(max_displacement_sq), sys_);

    ++step_count_;

    return step_count_ < total_step_;
}

template<typename traitsT>
inline void EnergyCalculationSimulator<traitsT>::run()
{
    while(this->step()) {};
    return;
}

template<typename traitsT>
inline void EnergyCalculationSimulator<traitsT>::finalize()
{
    obs_.finalize(this->total_step_, 0.0, this->sys_, this->ff_);
    return;
}

} // mjolnir
#endif// MJOLNIR_CORE_ENERGY_CALCULATION_SIMULATOR_HPP
<commit_msg>feat: calc pressure in EnergyCalculationSimulator<commit_after>#ifndef MJOLNIR_CORE_ENERGY_CALCULATION_SIMULATOR_HPP
#define MJOLNIR_CORE_ENERGY_CALCULATION_SIMULATOR_HPP
#include <mjolnir/core/SimulatorBase.hpp>
#include <mjolnir/core/ObserverContainer.hpp>
#include <mjolnir/core/System.hpp>
#include <mjolnir/core/ForceFieldBase.hpp>
#include <mjolnir/core/LoaderBase.hpp>
#include <mjolnir/core/XYZLoader.hpp>
#include <mjolnir/core/DCDLoader.hpp>
#include <mjolnir/core/TRRLoader.hpp>

namespace mjolnir
{

template<typename traitsT>
class EnergyCalculationSimulator final : public SimulatorBase
{
  public:
    using traits_type      = traitsT;
    using real_type        = typename traits_type::real_type;
    using coordinate_type  = typename traits_type::coordinate_type;
    using system_type      = System<traits_type>;
    using forcefield_type  = std::unique_ptr<ForceFieldBase<traits_type>>;
    using observer_type    = ObserverContainer<traits_type>;
    using loader_base_type = LoaderBase<traits_type>;
    using loader_type      = std::unique_ptr<loader_base_type>;

  public:

    EnergyCalculationSimulator(const std::size_t total_step, loader_type&& ld,
            system_type&& sys, forcefield_type&& ff, observer_type&& obs)
        : step_count_(0),     total_step_(total_step),
          ld_(std::move(ld)), sys_(std::move(sys)),
          ff_(std::move(ff)), obs_(std::move(obs)),
          old_position_(sys_.size())
    {}
    ~EnergyCalculationSimulator() override {}

    void initialize() override;
    bool step()       override;
    void run()        override;
    void finalize()   override;

    system_type&       system()       noexcept {return sys_;}
    system_type const& system() const noexcept {return sys_;}

    forcefield_type&       forcefields()       noexcept {return ff_;}
    forcefield_type const& forcefields() const noexcept {return ff_;}

    loader_type&       loader()       noexcept {return ld_;}
    loader_type const& loader() const noexcept {return ld_;}

  protected:

    std::size_t     step_count_, total_step_;
    loader_type     ld_;
    system_type     sys_;
    forcefield_type ff_;
    observer_type   obs_;
    std::vector<coordinate_type> old_position_;
};

template<typename traitsT>
inline void EnergyCalculationSimulator<traitsT>::initialize()
{
    // instead of initializing simulator (it generate velocities), read the
    // current state from the loader.
    //
    // To obtain the total number of snapshots, the loader is already initialized.
    ld_->load_next(this->sys_);

    // sys.initialize() generates the initial velocity, so here it is not needed

    this->ff_->initialize(this->sys_);

    this->ff_->calc_force_and_virial(this->sys_);

    auto Pins = this->sys_.virial();
    for(std::size_t i=0; i<sys_.size(); ++i)
    {
        const auto m = sys_.mass(i);
        const auto v = sys_.velocity(i);
        Pins += m * math::tensor_product(v, v);
    }

    sys_.attribute("pressure_xx") = Pins(0, 0);
    sys_.attribute("pressure_yy") = Pins(1, 1);
    sys_.attribute("pressure_zz") = Pins(2, 2);
    sys_.attribute("pressure_xy") = Pins(0, 1);
    sys_.attribute("pressure_yz") = Pins(1, 2);
    sys_.attribute("pressure_zx") = Pins(2, 0);

    // Since neither save_step nor delta_t are not saved, we add some dummy value.
    this->obs_.initialize(this->total_step_, 1, 1.0, this->sys_, this->ff_);
    return;
}

template<typename traitsT>
inline bool EnergyCalculationSimulator<traitsT>::step()
{
    this->ff_->calc_force_and_virial(this->sys_);

    auto Pins = this->sys_.virial();
    for(std::size_t i=0; i<sys_.size(); ++i)
    {
        const auto m = sys_.mass(i);
        const auto v = sys_.velocity(i);
        Pins += m * math::tensor_product(v, v);
    }

    sys_.attribute("pressure_xx") = Pins(0, 0);
    sys_.attribute("pressure_yy") = Pins(1, 1);
    sys_.attribute("pressure_zz") = Pins(2, 2);
    sys_.attribute("pressure_xy") = Pins(0, 1);
    sys_.attribute("pressure_yz") = Pins(1, 2);
    sys_.attribute("pressure_zx") = Pins(2, 0);

    // this calculates the energy.
    obs_.output(this->step_count_, 0.0, this->sys_, this->ff_);

    // backup current configuration to calculate displacement to determine
    // whether we need to update the neighboring list or not
    for(std::size_t i=0; i<sys_.size(); ++i)
    {
        old_position_[i] = sys_.position(i);
    }

    if(!ld_->load_next(sys_))
    {
        // if loader returns false, it means it fails to read the next traj.
        return false;
    }

    // Here, calling forcefield.update() is not a good idea. It outputs logs
    // because it considers all the state including both system and forcefield
    // has been changed. But, in this simulator, forcefield does not change.
    real_type max_displacement_sq = 0.0;
    for(std::size_t i=0; i<sys_.size(); ++i)
    {
        max_displacement_sq = std::max(max_displacement_sq, math::length_sq(
                    sys_.adjust_direction(sys_.position(i), old_position_[i])));
    }
    // update neighboring list if needed
    ff_->reduce_margin(2 * std::sqrt(max_displacement_sq), sys_);

    ++step_count_;

    return step_count_ < total_step_;
}

template<typename traitsT>
inline void EnergyCalculationSimulator<traitsT>::run()
{
    while(this->step()) {};
    return;
}

template<typename traitsT>
inline void EnergyCalculationSimulator<traitsT>::finalize()
{
    obs_.finalize(this->total_step_, 0.0, this->sys_, this->ff_);
    return;
}

} // mjolnir
#endif// MJOLNIR_CORE_ENERGY_CALCULATION_SIMULATOR_HPP
<|endoftext|>


<commit_before>/**
 *  @copyright Copyright 2016 The J-PET Framework Authors. All rights reserved.
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may find a copy of the License in the LICENCE file.
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 *  @file TaskC.cpp
 */

#include <iostream>
#include <JPetWriter/JPetWriter.h>
#include <JPetAnalysisTools/JPetAnalysisTools.h>
#include "TaskC.h"
#include <algorithm>

using namespace std;

TaskC::TaskC(const char* name, const char* description): JPetTask(name, description) {}
TaskC::~TaskC() {}

void TaskC::init(const JPetTaskInterface::Options& opts)
{
}

void TaskC::exec()
{
  //getting the data from event in propriate format
  if (auto currSignal = dynamic_cast<const JPetRawSignal* const>(getEvent())) {
    getStatistics().getCounter("No. initial signals")++;
    if (fSignals.empty()) {
      fSignals.push_back(*currSignal);
    } else {
      if (fSignals[0].getTimeWindowIndex() == currSignal->getTimeWindowIndex()) {
        fSignals.push_back(*currSignal);
      } else {

        vector<JPetHit> hits = createHits(fSignals);
        hits = JPetAnalysisTools::getHitsOrderedByTime(hits);
        // uncomment this in order to fill histograms
        // of time differences for subsequent hist
        studyTimeWindow(hits);
        saveHits(hits);

        fSignals.clear();
        fSignals.push_back(*currSignal);
      }
    }
  }
}

void TaskC::exec()
{
  //getting the data from event in propriate format
  if (auto currSignal = dynamic_cast<const JPetRawSignal* const>(getEvent())) {
    getStatistics().getCounter("No. initial signals")++;
    if (fSignals.empty()) {
      fSignals.push_back(*currSignal);
    } else {
      if (fSignals[0].getTimeWindowIndex() == currSignal->getTimeWindowIndex()) {
        fSignals.push_back(*currSignal);
      } else {

        vector<JPetHit> hits = createHits(fSignals);
        hits = JPetAnalysisTools::getHitsOrderedByTime(hits);
        // uncomment this in order to fill histograms
        // of time differences for subsequent hist
        studyTimeWindow(hits);

        saveHits(hits);

        fSignals.clear();
        fSignals.push_back(*currSignal);
      }
    }
  }
}
vector<JPetHit> TaskC::createHits(const vector<JPetRawSignal>& signals)
{
  vector<JPetHit> hits;
  for (auto i = signals.begin(); i != signals.end(); ++i) {
    for (auto j = i; ++j != signals.end();) {
      if (i->getPM().getScin() == j->getPM().getScin()) {
        // found 2 signals from the same scintillator
        // wrap the RawSignal objects into RecoSignal and PhysSignal
        // for now this is just wrapping opne object into another
        // in the future analyses it will involve more logic like
        // reconstructing the signal's shape, charge, amplitude etc.
        JPetRecoSignal recoSignalA;
        JPetRecoSignal recoSignalB;
        JPetPhysSignal physSignalA;
        JPetPhysSignal physSignalB;
        // assign sides A and B properly
        if (
          (i->getPM().getSide() == JPetPM::SideA)
          && (j->getPM().getSide() == JPetPM::SideB)
        ) {
          recoSignalA.setRawSignal(*i);
          recoSignalB.setRawSignal(*j);
        } else if (
          (j->getPM().getSide() == JPetPM::SideA)
          && (i->getPM().getSide() == JPetPM::SideB)
        ) {
          recoSignalA.setRawSignal(*j);
          recoSignalB.setRawSignal(*i);
        } else {
          // if two hits on the same side, ignore
          WARNING("TWO hits on the same scintillator side we ignore it");
          continue;
        }

        if ( recoSignalA.getRawSignal().getNumberOfPoints(JPetSigCh::Leading) < 4 ) continue;
        if ( recoSignalB.getRawSignal().getNumberOfPoints(JPetSigCh::Leading) < 4 ) continue;

        bool thresholds_ok = true;
        for (int i = 1; i <= 4; ++i) {
          if ( recoSignalA.getRawSignal().getTimesVsThresholdNumber(JPetSigCh::Leading).count(i) < 1 ) {
            thresholds_ok = false;
          }
          if ( recoSignalB.getRawSignal().getTimesVsThresholdNumber(JPetSigCh::Leading).count(i) < 1 ) {
            thresholds_ok = false;
          }
        }
        if (thresholds_ok == false) {
          continue;
        }

        physSignalA.setRecoSignal(recoSignalA);
        physSignalB.setRecoSignal(recoSignalB);
        auto leading_points_a = physSignalA.getRecoSignal().getRawSignal().getTimesVsThresholdNumber(JPetSigCh::Leading);
        auto leading_points_b = physSignalB.getRecoSignal().getRawSignal().getTimesVsThresholdNumber(JPetSigCh::Leading);

        //skip signals with no information on 1st threshold
        // if(leading_points_a.count(1) == 0) continue;
        // if(leading_points_b.count(1) == 0) continue;

        physSignalA.setTime(leading_points_a.at(1));
        physSignalB.setTime(leading_points_b.at(1));

        JPetHit hit;
        hit.setSignalA(physSignalA);
        hit.setSignalB(physSignalB);
        hit.setScintillator(i->getPM().getScin());
        hit.setBarrelSlot(i->getPM().getScin().getBarrelSlot());

        physSignalA.setTime(physSignalA.getRecoSignal().getRawSignal().getTimesVsThresholdNumber(JPetSigCh::Leading).at(1));
        physSignalB.setTime(physSignalB.getRecoSignal().getRawSignal().getTimesVsThresholdNumber(JPetSigCh::Leading).at(1));

        hit.setTime( 0.5 * ( hit.getSignalA().getTime() + hit.getSignalB().getTime()) );

        hits.push_back(hit);
        getStatistics().getCounter("No. found hits")++;
      }
    }
  }
  return hits;
}

void TaskC::terminate()
{
  //	saveHits(createHits(fSignals)); //if there is something left
  INFO( Form("From %d initial signals %d hits were paired.",
             static_cast<int>(getStatistics().getCounter("No. initial signals")),
             static_cast<int>(getStatistics().getCounter("No. found hits")) )
      );
}

void TaskC::studyTimeWindow(const vector<JPetHit>& hits)
{

  // plot time differences for subsequent hits at each threshold separately
  for (int i = 1; i < hits.size(); ++i) {
    >>> >>> > Use hit sorting from framework library
    for (int k = 1; k <= 4; ++k) {
      double t2 = 0.5 * (hits.at(i).getSignalA().getRecoSignal().getRawSignal().getTimesVsThresholdNumber(JPetSigCh::Leading).at(k) + hits.at(i).getSignalB().getRecoSignal().getRawSignal().getTimesVsThresholdNumber(JPetSigCh::Leading).at(k));
      double t1 = 0.5 * (hits.at(i - 1).getSignalA().getRecoSignal().getRawSignal().getTimesVsThresholdNumber(JPetSigCh::Leading).at(k) + hits.at(i - 1).getSignalB().getRecoSignal().getRawSignal().getTimesVsThresholdNumber(JPetSigCh::Leading).at(k));
      double dt = t2 - t1;
      getStatistics().getHisto1D(Form("timeSepSmall_thr_%d", k)).Fill(dt / 1000.); // we fill the histo in [ns]
      getStatistics().getHisto1D(Form("timeSepLarge_thr_%d", k)).Fill(dt / 1000.); // we fill the histo in [ns]
    }
  }
}

void TaskC::saveHits(const vector<JPetHit>& hits)
{
  assert(fWriter);
  for (auto hit : hits) {
    // here one can impose any conditions on hits that should be
    // saved or skipped
    // for now, all hits are written to the output file
    // without checking anything
    fWriter->write(hit);
  }
}
<commit_msg>Added setWriter method which was removed by mistake<commit_after>/**
 *  @copyright Copyright 2016 The J-PET Framework Authors. All rights reserved.
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may find a copy of the License in the LICENCE file.
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 *  @file TaskC.cpp
 */

#include <iostream>
#include <JPetWriter/JPetWriter.h>
#include <JPetAnalysisTools/JPetAnalysisTools.h>
#include "TaskC.h"
#include <algorithm>

using namespace std;

TaskC::TaskC(const char* name, const char* description): JPetTask(name, description) {}
TaskC::~TaskC() {}

void TaskC::init(const JPetTaskInterface::Options& opts)
{
}

void TaskC::exec()
{
  //getting the data from event in propriate format
  if (auto currSignal = dynamic_cast<const JPetRawSignal* const>(getEvent())) {
    getStatistics().getCounter("No. initial signals")++;
    if (fSignals.empty()) {
      fSignals.push_back(*currSignal);
    } else {
      if (fSignals[0].getTimeWindowIndex() == currSignal->getTimeWindowIndex()) {
        fSignals.push_back(*currSignal);
      } else {

        vector<JPetHit> hits = createHits(fSignals);
        hits = JPetAnalysisTools::getHitsOrderedByTime(hits);
        // uncomment this in order to fill histograms
        // of time differences for subsequent hist
        studyTimeWindow(hits);

        saveHits(hits);

        fSignals.clear();
        fSignals.push_back(*currSignal);
      }
    }
  }
}
vector<JPetHit> TaskC::createHits(const vector<JPetRawSignal>& signals)
{
  vector<JPetHit> hits;
  for (auto i = signals.begin(); i != signals.end(); ++i) {
    for (auto j = i; ++j != signals.end();) {
      if (i->getPM().getScin() == j->getPM().getScin()) {
        // found 2 signals from the same scintillator
        // wrap the RawSignal objects into RecoSignal and PhysSignal
        // for now this is just wrapping opne object into another
        // in the future analyses it will involve more logic like
        // reconstructing the signal's shape, charge, amplitude etc.
        JPetRecoSignal recoSignalA;
        JPetRecoSignal recoSignalB;
        JPetPhysSignal physSignalA;
        JPetPhysSignal physSignalB;
        // assign sides A and B properly
        if (
          (i->getPM().getSide() == JPetPM::SideA)
          && (j->getPM().getSide() == JPetPM::SideB)
        ) {
          recoSignalA.setRawSignal(*i);
          recoSignalB.setRawSignal(*j);
        } else if (
          (j->getPM().getSide() == JPetPM::SideA)
          && (i->getPM().getSide() == JPetPM::SideB)
        ) {
          recoSignalA.setRawSignal(*j);
          recoSignalB.setRawSignal(*i);
        } else {
          // if two hits on the same side, ignore
          WARNING("TWO hits on the same scintillator side we ignore it");
          continue;
        }

        if ( recoSignalA.getRawSignal().getNumberOfPoints(JPetSigCh::Leading) < 4 ) continue;
        if ( recoSignalB.getRawSignal().getNumberOfPoints(JPetSigCh::Leading) < 4 ) continue;

        bool thresholds_ok = true;
        for (int i = 1; i <= 4; ++i) {
          if ( recoSignalA.getRawSignal().getTimesVsThresholdNumber(JPetSigCh::Leading).count(i) < 1 ) {
            thresholds_ok = false;
          }
          if ( recoSignalB.getRawSignal().getTimesVsThresholdNumber(JPetSigCh::Leading).count(i) < 1 ) {
            thresholds_ok = false;
          }
        }
        if (thresholds_ok == false) {
          continue;
        }

        physSignalA.setRecoSignal(recoSignalA);
        physSignalB.setRecoSignal(recoSignalB);
        auto leading_points_a = physSignalA.getRecoSignal().getRawSignal().getTimesVsThresholdNumber(JPetSigCh::Leading);
        auto leading_points_b = physSignalB.getRecoSignal().getRawSignal().getTimesVsThresholdNumber(JPetSigCh::Leading);

        //skip signals with no information on 1st threshold
        // if(leading_points_a.count(1) == 0) continue;
        // if(leading_points_b.count(1) == 0) continue;

        physSignalA.setTime(leading_points_a.at(1));
        physSignalB.setTime(leading_points_b.at(1));

        JPetHit hit;
        hit.setSignalA(physSignalA);
        hit.setSignalB(physSignalB);
        hit.setScintillator(i->getPM().getScin());
        hit.setBarrelSlot(i->getPM().getScin().getBarrelSlot());

        physSignalA.setTime(physSignalA.getRecoSignal().getRawSignal().getTimesVsThresholdNumber(JPetSigCh::Leading).at(1));
        physSignalB.setTime(physSignalB.getRecoSignal().getRawSignal().getTimesVsThresholdNumber(JPetSigCh::Leading).at(1));

        hit.setTime( 0.5 * ( hit.getSignalA().getTime() + hit.getSignalB().getTime()) );

        hits.push_back(hit);
        getStatistics().getCounter("No. found hits")++;
      }
    }
  }
  return hits;
}

void TaskC::terminate()
{
  //	saveHits(createHits(fSignals)); //if there is something left
  INFO( Form("From %d initial signals %d hits were paired.",
             static_cast<int>(getStatistics().getCounter("No. initial signals")),
             static_cast<int>(getStatistics().getCounter("No. found hits")) )
      );
}

void TaskC::studyTimeWindow(const vector<JPetHit>& hits)
{

  // plot time differences for subsequent hits at each threshold separately
  for (int i = 1; i < hits.size(); ++i) {
    for (int k = 1; k <= 4; ++k) {
      double t2 = 0.5 * (hits.at(i).getSignalA().getRecoSignal().getRawSignal().getTimesVsThresholdNumber(JPetSigCh::Leading).at(k) + hits.at(i).getSignalB().getRecoSignal().getRawSignal().getTimesVsThresholdNumber(JPetSigCh::Leading).at(k));
      double t1 = 0.5 * (hits.at(i - 1).getSignalA().getRecoSignal().getRawSignal().getTimesVsThresholdNumber(JPetSigCh::Leading).at(k) + hits.at(i - 1).getSignalB().getRecoSignal().getRawSignal().getTimesVsThresholdNumber(JPetSigCh::Leading).at(k));
      double dt = t2 - t1;
      getStatistics().getHisto1D(Form("timeSepSmall_thr_%d", k)).Fill(dt / 1000.); // we fill the histo in [ns]
      getStatistics().getHisto1D(Form("timeSepLarge_thr_%d", k)).Fill(dt / 1000.); // we fill the histo in [ns]
    }
  }
}

void TaskC::saveHits(const vector<JPetHit>& hits)
{
  assert(fWriter);
  for (auto hit : hits) {
    // here one can impose any conditions on hits that should be
    // saved or skipped
    // for now, all hits are written to the output file
    // without checking anything
    fWriter->write(hit);
  }
}

void TaskC::setWriter(JPetWriter* writer)
{
  fWriter = writer;
}
<|endoftext|>


<commit_before>#include "drape/overlay_tree.hpp"

#include "drape/constants.hpp"
#include "drape/debug_rect_renderer.hpp"

#include <algorithm>

namespace dp
{
int const kMinFrameUpdatePeriod = 5;
int const kAvgFrameUpdatePeriod = 10;
int const kMaxFrameUpdatePeriod = 15;
uint32_t const kMinHandlesCount = 100;
uint32_t const kMaxHandlesCount = 1000;

size_t const kAverageHandlesCount[dp::OverlayRanksCount] = { 300, 200, 50 };
int const kInvalidFrame = -1;

namespace
{
class HandleComparator
{
public:
  explicit HandleComparator(bool enableMask)
    : m_enableMask(enableMask)
  {}

  bool operator()(ref_ptr<OverlayHandle> const & l, ref_ptr<OverlayHandle> const & r) const
  {
    return IsGreater(l, r);
  }

  bool IsGreater(ref_ptr<OverlayHandle> const & l, ref_ptr<OverlayHandle> const & r) const
  {
    bool const displayFlagLeft = ((!m_enableMask || l->IsUserMarkOverlay()) ? true : l->GetDisplayFlag());
    bool const displayFlagRight = ((!m_enableMask || r->IsUserMarkOverlay()) ? true : r->GetDisplayFlag());
    if (displayFlagLeft > displayFlagRight)
      return true;

    if (displayFlagLeft == displayFlagRight)
    {
      uint64_t const mask = m_enableMask ? l->GetPriorityMask() & r->GetPriorityMask() :
                            dp::kPriorityMaskAll;
      uint64_t const priorityLeft = l->GetPriority() & mask;
      uint64_t const priorityRight = r->GetPriority() & mask;
      if (priorityLeft > priorityRight)
        return true;

      if (priorityLeft == priorityRight)
      {
        auto const & hashLeft = l->GetOverlayID();
        auto const & hashRight = r->GetOverlayID();

        if (hashLeft > hashRight)
          return true;

        if (hashLeft == hashRight)
          return l.get() > r.get();
      }
    }
    return false;
  }

private:
  bool m_enableMask;
};
}  // namespace

OverlayTree::OverlayTree(double visualScale)
  : m_frameCounter(kInvalidFrame)
  , m_isDisplacementEnabled(true)
  , m_frameUpdatePeriod(kMinFrameUpdatePeriod)
{
  m_traits.SetVisualScale(visualScale);
  for (size_t i = 0; i < m_handles.size(); i++)
    m_handles[i].reserve(kAverageHandlesCount[i]);
}

void OverlayTree::Clear()
{
  m_frameCounter = kInvalidFrame;
  TBase::Clear();
  m_handlesCache.clear();
  for (auto & handles : m_handles)
    handles.clear();
  m_displacers.clear();
}

bool OverlayTree::Frame()
{
  if (IsNeedUpdate())
    return true;

  // Choose optimal frame update period.
  if (m_frameCounter == 0)
  {
    auto const handlesCount = m_handlesCache.size();
    if (handlesCount > kMaxHandlesCount)
      m_frameUpdatePeriod = kMaxFrameUpdatePeriod;
    else if (handlesCount < kMinHandlesCount)
      m_frameUpdatePeriod = kMinFrameUpdatePeriod;
    else
      m_frameUpdatePeriod = kAvgFrameUpdatePeriod;
  }

  m_frameCounter++;
  if (m_frameCounter >= m_frameUpdatePeriod)
    m_frameCounter = kInvalidFrame;

  return IsNeedUpdate();
}

bool OverlayTree::IsNeedUpdate() const
{
  return m_frameCounter == kInvalidFrame;
}

void OverlayTree::StartOverlayPlacing(ScreenBase const & screen)
{
  ASSERT(IsNeedUpdate(), ());
  TBase::Clear();
  m_handlesCache.clear();
  m_traits.SetModelView(screen);
  m_displacementInfo.clear();
}

void OverlayTree::Remove(ref_ptr<OverlayHandle> handle)
{
  if (m_frameCounter == kInvalidFrame)
    return;

  if (m_handlesCache.find(handle) != m_handlesCache.end())
    m_frameCounter = kInvalidFrame;
}

void OverlayTree::Add(ref_ptr<OverlayHandle> handle)
{
  ASSERT(IsNeedUpdate(), ());

  ScreenBase const & modelView = GetModelView();

  handle->SetIsVisible(false);
  handle->SetCachingEnable(true);

  // Skip duplicates.
  if (m_handlesCache.find(handle) != m_handlesCache.end())
    return;

  // Skip not-ready handles.
  if (!handle->Update(modelView))
  {
    m_frameCounter == kInvalidFrame;
    handle->SetReady(false);
    return;
  }
  else
  {
    handle->SetReady(true);
  }

  // Clip handles which are out of screen if these handles were not displacers
  // last time. Also clip all handles in reverse projection.
  m2::RectD const pixelRect = handle->GetExtendedPixelRect(modelView);
  if (modelView.IsReverseProjection3d(pixelRect.Center()) ||
      (m_displacers.find(handle) == m_displacers.end() &&
       !m_traits.GetExtendedScreenRect().IsIntersect(pixelRect)))
  {
    handle->SetIsVisible(false);
    return;
  }

  ASSERT_GREATER_OR_EQUAL(handle->GetOverlayRank(), 0, ());
  size_t const rank = static_cast<size_t>(handle->GetOverlayRank());
  ASSERT_LESS(rank, m_handles.size(), ());
  m_handles[rank].emplace_back(handle);
}

void OverlayTree::InsertHandle(ref_ptr<OverlayHandle> handle, int currentRank,
                               ref_ptr<OverlayHandle> const & parentOverlay)
{
  ASSERT(IsNeedUpdate(), ());

#ifdef DEBUG_OVERLAYS_OUTPUT
  string str = handle->GetOverlayDebugInfo();
  if (!str.empty())
    LOG(LINFO, (str));
#endif

  ScreenBase const & modelView = GetModelView();
  m2::RectD const pixelRect = handle->GetExtendedPixelRect(modelView);
  if (!m_isDisplacementEnabled)
  {
    m_handlesCache.insert(handle);
    TBase::Add(handle, pixelRect);
    return;
  }

  TOverlayContainer rivals;
  HandleComparator comparator(true /* enableMask */);

  // Find elements that already on OverlayTree and it's pixel rect
  // intersect with handle pixel rect ("Intersected elements").
  ForEachInRect(pixelRect, [&] (ref_ptr<OverlayHandle> const & h)
  {
    bool const isParent = (h == parentOverlay) ||
                          (h->GetOverlayID() == handle->GetOverlayID() &&
                           h->GetOverlayRank() < handle->GetOverlayRank());
    if (!isParent && handle->IsIntersect(modelView, h))
      rivals.push_back(h);
  });

  // If handle is bound to its parent, parent's handle will be used.
  ref_ptr<OverlayHandle> handleToCompare = handle;
  bool const boundToParent = (parentOverlay != nullptr && handle->IsBound());
  if (boundToParent)
    handleToCompare = parentOverlay;

  bool const selected = m_selectedFeatureID.IsValid() &&
                        handleToCompare->GetOverlayID().m_featureId == m_selectedFeatureID;

  if (!selected)
  {
    // In this loop we decide which element must be visible.
    // If input element "handle" has more priority than all "Intersected elements",
    // then we remove all "Intersected elements" and insert input element "handle".
    // But if some of already inserted elements have more priority, then we don't insert "handle".
    for (auto const & rivalHandle : rivals)
    {
      bool const rejectBySelected = m_selectedFeatureID.IsValid() &&
                                    rivalHandle->GetOverlayID().m_featureId == m_selectedFeatureID;

      bool rejectByDepth = false;
      if (!rejectBySelected && modelView.isPerspective())
      {
        bool const pathTextComparation = handle->HasLinearFeatureShape() || rivalHandle->HasLinearFeatureShape();
        rejectByDepth = !pathTextComparation &&
                        handleToCompare->GetPivot(modelView, true).y > rivalHandle->GetPivot(modelView, true).y;
      }

      if (rejectBySelected || rejectByDepth || comparator.IsGreater(rivalHandle, handleToCompare))
      {
        // Handle is displaced and bound to its parent, parent will be displaced too.
        if (boundToParent)
        {
          DeleteHandleWithParents(parentOverlay, currentRank - 1);
          StoreDisplacementInfo(0 /* case index */, handle, parentOverlay);
        }
        StoreDisplacementInfo(1 /* case index */, rivalHandle, handle);
        return;
      }
    }
  }

  // Current overlay displaces other overlay, delete them.
  for (auto const & rivalHandle : rivals)
  {
    if (rivalHandle->IsBound())
    {
      // Delete rival handle and all handles bound to it.
      for (auto it = m_handlesCache.begin(); it != m_handlesCache.end();)
      {
        if ((*it)->GetOverlayID() == rivalHandle->GetOverlayID())
        {
          Erase(*it);
          StoreDisplacementInfo(2 /* case index */, handle, *it);
          it = m_handlesCache.erase(it);
        }
        else
        {
          ++it;
        }
      }
    }
    else
    {
      DeleteHandle(rivalHandle);
      StoreDisplacementInfo(3 /* case index */, handle, rivalHandle);
    }
  }

  m_handlesCache.insert(handle);
  TBase::Add(handle, pixelRect);
}

void OverlayTree::EndOverlayPlacing()
{
  ASSERT(IsNeedUpdate(), ());

  m_displacers.clear();

#ifdef DEBUG_OVERLAYS_OUTPUT
  LOG(LINFO, ("- BEGIN OVERLAYS PLACING"));
#endif

  HandleComparator comparator(false /* enableMask */);

  for (int rank = 0; rank < dp::OverlayRanksCount; rank++)
  {
    std::sort(m_handles[rank].begin(), m_handles[rank].end(), comparator);
    for (auto const & handle : m_handles[rank])
    {
      ref_ptr<OverlayHandle> parentOverlay;
      if (!CheckHandle(handle, rank, parentOverlay))
        continue;

      InsertHandle(handle, rank, parentOverlay);
    }
  }

  for (int rank = 0; rank < dp::OverlayRanksCount; rank++)
  {
    for (auto const & handle : m_handles[rank])
      handle->SetDisplayFlag(false);
    m_handles[rank].clear();
  }

  for (auto const & handle : m_handlesCache)
  {
    handle->SetDisplayFlag(true);
    handle->SetIsVisible(true);
    handle->SetCachingEnable(false);
  }

  m_frameCounter = 0;

#ifdef DEBUG_OVERLAYS_OUTPUT
  LOG(LINFO, ("- END OVERLAYS PLACING"));
#endif
}

bool OverlayTree::CheckHandle(ref_ptr<OverlayHandle> handle, int currentRank,
                              ref_ptr<OverlayHandle> & parentOverlay) const
{
  if (currentRank == dp::OverlayRank0)
    return true;

  parentOverlay = FindParent(handle, currentRank - 1);
  return parentOverlay != nullptr;
}

ref_ptr<OverlayHandle> OverlayTree::FindParent(ref_ptr<OverlayHandle> handle, int searchingRank) const
{
  ASSERT_GREATER_OR_EQUAL(searchingRank, 0, ());
  ASSERT_LESS(searchingRank, static_cast<int>(m_handles.size()), ());
  for (auto const & h : m_handles[searchingRank])
  {
    if (h->GetOverlayID() == handle->GetOverlayID() && m_handlesCache.find(h) != m_handlesCache.end())
      return h;
  }
  return nullptr;
}

void OverlayTree::DeleteHandle(ref_ptr<OverlayHandle> const & handle)
{
  size_t const deletedCount = m_handlesCache.erase(handle);
  if (deletedCount != 0)
    Erase(handle);
}

void OverlayTree::DeleteHandleWithParents(ref_ptr<OverlayHandle> handle, int currentRank)
{
  currentRank--;
  while (currentRank >= dp::OverlayRank0)
  {
    auto parent = FindParent(handle, currentRank);
    if (parent != nullptr && parent->IsBound())
      DeleteHandle(parent);
    currentRank--;
  }
  DeleteHandle(handle);
}

bool OverlayTree::GetSelectedFeatureRect(ScreenBase const & screen, m2::RectD & featureRect)
{
  if (!m_selectedFeatureID.IsValid())
    return false;

  featureRect.MakeEmpty();
  for (auto const & handle : m_handlesCache)
  {
    if (handle->IsVisible() && handle->GetOverlayID().m_featureId == m_selectedFeatureID)
    {
      m2::RectD rect = handle->GetPixelRect(screen, screen.isPerspective());
      featureRect.Add(rect);
    }
  }
  return true;
}

void OverlayTree::Select(m2::PointD const & glbPoint, TOverlayContainer & result) const
{
  ScreenBase const & screen = GetModelView();
  m2::PointD const pxPoint = screen.GtoP(glbPoint);

  double const kSearchRectHalfSize = 10.0;
  m2::RectD rect(pxPoint, pxPoint);
  rect.Inflate(kSearchRectHalfSize, kSearchRectHalfSize);

  for (auto const & handle : m_handlesCache)
  {
    if (!handle->HasLinearFeatureShape() && rect.IsPointInside(handle->GetPivot(screen, false)))
      result.push_back(handle);
  }
}

void OverlayTree::Select(m2::RectD const & rect, TOverlayContainer & result) const
{
  ScreenBase screen = GetModelView();
  ForEachInRect(rect, [&](ref_ptr<OverlayHandle> const & h)
  {
    if (!h->HasLinearFeatureShape() && h->IsVisible() && h->GetOverlayID().m_featureId.IsValid())
    {
      OverlayHandle::Rects shape;
      h->GetPixelShape(screen, screen.isPerspective(), shape);
      for (m2::RectF const & rShape : shape)
      {
        if (rShape.IsIntersect(m2::RectF(rect)))
        {
          result.push_back(h);
          break;
        }
      }
    }
  });
}

void OverlayTree::SetDisplacementEnabled(bool enabled)
{
  if (m_isDisplacementEnabled == enabled)
    return;
  m_isDisplacementEnabled = enabled;
  m_frameCounter = kInvalidFrame;
}

void OverlayTree::SetSelectedFeature(FeatureID const & featureID)
{
  m_selectedFeatureID = featureID;
}

OverlayTree::TDisplacementInfo const & OverlayTree::GetDisplacementInfo() const
{
  return m_displacementInfo;
}

void OverlayTree::StoreDisplacementInfo(int caseIndex, ref_ptr<OverlayHandle> displacerHandle,
                                        ref_ptr<OverlayHandle> displacedHandle)
{
  ScreenBase const & modelView = GetModelView();
  m2::RectD const pixelRect = displacerHandle->GetExtendedPixelRect(modelView);
  if (!m_traits.GetDisplacersFreeRect().IsRectInside(pixelRect))
    m_displacers.insert(displacerHandle);

#ifdef DEBUG_OVERLAYS_OUTPUT
    LOG(LINFO, ("Displace (", caseIndex, "):", displacerHandle->GetOverlayDebugInfo(),
                "->", displacedHandle->GetOverlayDebugInfo()));
#else
  UNUSED_VALUE(caseIndex);
#endif

  if (!dp::DebugRectRenderer::Instance().IsEnabled())
    return;
  m_displacementInfo.emplace_back(displacerHandle->GetExtendedPixelRect(modelView).Center(),
                                  displacedHandle->GetExtendedPixelRect(modelView).Center(),
                                  dp::Color(0, 0, 255, 255));
}

void detail::OverlayTraits::SetVisualScale(double visualScale)
{
  m_visualScale = visualScale;
}

void detail::OverlayTraits::SetModelView(ScreenBase const & modelView)
{
  m_modelView = modelView;

  double const extension = m_visualScale * kScreenPixelRectExtension;
  double const doubleExtension = 2.0 * extension;
  m_extendedScreenRect = modelView.PixelRectIn3d();
  m_extendedScreenRect.Inflate(extension, extension);

  m_displacersFreeRect = modelView.PixelRectIn3d();
  if (m_displacersFreeRect.SizeX() > doubleExtension && m_displacersFreeRect.SizeY() > doubleExtension)
    m_displacersFreeRect.Inflate(-extension, -extension);
  else
    m_displacersFreeRect.SetSizes(1e-7, 1e-7);
}
}  // namespace dp
<commit_msg>Drape warning fix.<commit_after>#include "drape/overlay_tree.hpp"

#include "drape/constants.hpp"
#include "drape/debug_rect_renderer.hpp"

#include <algorithm>

namespace dp
{
int const kMinFrameUpdatePeriod = 5;
int const kAvgFrameUpdatePeriod = 10;
int const kMaxFrameUpdatePeriod = 15;
uint32_t const kMinHandlesCount = 100;
uint32_t const kMaxHandlesCount = 1000;

size_t const kAverageHandlesCount[dp::OverlayRanksCount] = { 300, 200, 50 };
int const kInvalidFrame = -1;

namespace
{
class HandleComparator
{
public:
  explicit HandleComparator(bool enableMask)
    : m_enableMask(enableMask)
  {}

  bool operator()(ref_ptr<OverlayHandle> const & l, ref_ptr<OverlayHandle> const & r) const
  {
    return IsGreater(l, r);
  }

  bool IsGreater(ref_ptr<OverlayHandle> const & l, ref_ptr<OverlayHandle> const & r) const
  {
    bool const displayFlagLeft = ((!m_enableMask || l->IsUserMarkOverlay()) ? true : l->GetDisplayFlag());
    bool const displayFlagRight = ((!m_enableMask || r->IsUserMarkOverlay()) ? true : r->GetDisplayFlag());
    if (displayFlagLeft > displayFlagRight)
      return true;

    if (displayFlagLeft == displayFlagRight)
    {
      uint64_t const mask = m_enableMask ? l->GetPriorityMask() & r->GetPriorityMask() :
                            dp::kPriorityMaskAll;
      uint64_t const priorityLeft = l->GetPriority() & mask;
      uint64_t const priorityRight = r->GetPriority() & mask;
      if (priorityLeft > priorityRight)
        return true;

      if (priorityLeft == priorityRight)
      {
        auto const & hashLeft = l->GetOverlayID();
        auto const & hashRight = r->GetOverlayID();

        if (hashLeft > hashRight)
          return true;

        if (hashLeft == hashRight)
          return l.get() > r.get();
      }
    }
    return false;
  }

private:
  bool m_enableMask;
};
}  // namespace

OverlayTree::OverlayTree(double visualScale)
  : m_frameCounter(kInvalidFrame)
  , m_isDisplacementEnabled(true)
  , m_frameUpdatePeriod(kMinFrameUpdatePeriod)
{
  m_traits.SetVisualScale(visualScale);
  for (size_t i = 0; i < m_handles.size(); i++)
    m_handles[i].reserve(kAverageHandlesCount[i]);
}

void OverlayTree::Clear()
{
  m_frameCounter = kInvalidFrame;
  TBase::Clear();
  m_handlesCache.clear();
  for (auto & handles : m_handles)
    handles.clear();
  m_displacers.clear();
}

bool OverlayTree::Frame()
{
  if (IsNeedUpdate())
    return true;

  // Choose optimal frame update period.
  if (m_frameCounter == 0)
  {
    auto const handlesCount = m_handlesCache.size();
    if (handlesCount > kMaxHandlesCount)
      m_frameUpdatePeriod = kMaxFrameUpdatePeriod;
    else if (handlesCount < kMinHandlesCount)
      m_frameUpdatePeriod = kMinFrameUpdatePeriod;
    else
      m_frameUpdatePeriod = kAvgFrameUpdatePeriod;
  }

  m_frameCounter++;
  if (m_frameCounter >= m_frameUpdatePeriod)
    m_frameCounter = kInvalidFrame;

  return IsNeedUpdate();
}

bool OverlayTree::IsNeedUpdate() const
{
  return m_frameCounter == kInvalidFrame;
}

void OverlayTree::StartOverlayPlacing(ScreenBase const & screen)
{
  ASSERT(IsNeedUpdate(), ());
  TBase::Clear();
  m_handlesCache.clear();
  m_traits.SetModelView(screen);
  m_displacementInfo.clear();
}

void OverlayTree::Remove(ref_ptr<OverlayHandle> handle)
{
  if (m_frameCounter == kInvalidFrame)
    return;

  if (m_handlesCache.find(handle) != m_handlesCache.end())
    m_frameCounter = kInvalidFrame;
}

void OverlayTree::Add(ref_ptr<OverlayHandle> handle)
{
  ASSERT(IsNeedUpdate(), ());

  ScreenBase const & modelView = GetModelView();

  handle->SetIsVisible(false);
  handle->SetCachingEnable(true);

  // Skip duplicates.
  if (m_handlesCache.find(handle) != m_handlesCache.end())
    return;

  // Skip not-ready handles.
  if (!handle->Update(modelView))
  {
    m_frameCounter = kInvalidFrame;
    handle->SetReady(false);
    return;
  }
  else
  {
    handle->SetReady(true);
  }

  // Clip handles which are out of screen if these handles were not displacers
  // last time. Also clip all handles in reverse projection.
  m2::RectD const pixelRect = handle->GetExtendedPixelRect(modelView);
  if (modelView.IsReverseProjection3d(pixelRect.Center()) ||
      (m_displacers.find(handle) == m_displacers.end() &&
       !m_traits.GetExtendedScreenRect().IsIntersect(pixelRect)))
  {
    handle->SetIsVisible(false);
    return;
  }

  ASSERT_GREATER_OR_EQUAL(handle->GetOverlayRank(), 0, ());
  size_t const rank = static_cast<size_t>(handle->GetOverlayRank());
  ASSERT_LESS(rank, m_handles.size(), ());
  m_handles[rank].emplace_back(handle);
}

void OverlayTree::InsertHandle(ref_ptr<OverlayHandle> handle, int currentRank,
                               ref_ptr<OverlayHandle> const & parentOverlay)
{
  ASSERT(IsNeedUpdate(), ());

#ifdef DEBUG_OVERLAYS_OUTPUT
  string str = handle->GetOverlayDebugInfo();
  if (!str.empty())
    LOG(LINFO, (str));
#endif

  ScreenBase const & modelView = GetModelView();
  m2::RectD const pixelRect = handle->GetExtendedPixelRect(modelView);
  if (!m_isDisplacementEnabled)
  {
    m_handlesCache.insert(handle);
    TBase::Add(handle, pixelRect);
    return;
  }

  TOverlayContainer rivals;
  HandleComparator comparator(true /* enableMask */);

  // Find elements that already on OverlayTree and it's pixel rect
  // intersect with handle pixel rect ("Intersected elements").
  ForEachInRect(pixelRect, [&] (ref_ptr<OverlayHandle> const & h)
  {
    bool const isParent = (h == parentOverlay) ||
                          (h->GetOverlayID() == handle->GetOverlayID() &&
                           h->GetOverlayRank() < handle->GetOverlayRank());
    if (!isParent && handle->IsIntersect(modelView, h))
      rivals.push_back(h);
  });

  // If handle is bound to its parent, parent's handle will be used.
  ref_ptr<OverlayHandle> handleToCompare = handle;
  bool const boundToParent = (parentOverlay != nullptr && handle->IsBound());
  if (boundToParent)
    handleToCompare = parentOverlay;

  bool const selected = m_selectedFeatureID.IsValid() &&
                        handleToCompare->GetOverlayID().m_featureId == m_selectedFeatureID;

  if (!selected)
  {
    // In this loop we decide which element must be visible.
    // If input element "handle" has more priority than all "Intersected elements",
    // then we remove all "Intersected elements" and insert input element "handle".
    // But if some of already inserted elements have more priority, then we don't insert "handle".
    for (auto const & rivalHandle : rivals)
    {
      bool const rejectBySelected = m_selectedFeatureID.IsValid() &&
                                    rivalHandle->GetOverlayID().m_featureId == m_selectedFeatureID;

      bool rejectByDepth = false;
      if (!rejectBySelected && modelView.isPerspective())
      {
        bool const pathTextComparation = handle->HasLinearFeatureShape() || rivalHandle->HasLinearFeatureShape();
        rejectByDepth = !pathTextComparation &&
                        handleToCompare->GetPivot(modelView, true).y > rivalHandle->GetPivot(modelView, true).y;
      }

      if (rejectBySelected || rejectByDepth || comparator.IsGreater(rivalHandle, handleToCompare))
      {
        // Handle is displaced and bound to its parent, parent will be displaced too.
        if (boundToParent)
        {
          DeleteHandleWithParents(parentOverlay, currentRank - 1);
          StoreDisplacementInfo(0 /* case index */, handle, parentOverlay);
        }
        StoreDisplacementInfo(1 /* case index */, rivalHandle, handle);
        return;
      }
    }
  }

  // Current overlay displaces other overlay, delete them.
  for (auto const & rivalHandle : rivals)
  {
    if (rivalHandle->IsBound())
    {
      // Delete rival handle and all handles bound to it.
      for (auto it = m_handlesCache.begin(); it != m_handlesCache.end();)
      {
        if ((*it)->GetOverlayID() == rivalHandle->GetOverlayID())
        {
          Erase(*it);
          StoreDisplacementInfo(2 /* case index */, handle, *it);
          it = m_handlesCache.erase(it);
        }
        else
        {
          ++it;
        }
      }
    }
    else
    {
      DeleteHandle(rivalHandle);
      StoreDisplacementInfo(3 /* case index */, handle, rivalHandle);
    }
  }

  m_handlesCache.insert(handle);
  TBase::Add(handle, pixelRect);
}

void OverlayTree::EndOverlayPlacing()
{
  ASSERT(IsNeedUpdate(), ());

  m_displacers.clear();

#ifdef DEBUG_OVERLAYS_OUTPUT
  LOG(LINFO, ("- BEGIN OVERLAYS PLACING"));
#endif

  HandleComparator comparator(false /* enableMask */);

  for (int rank = 0; rank < dp::OverlayRanksCount; rank++)
  {
    std::sort(m_handles[rank].begin(), m_handles[rank].end(), comparator);
    for (auto const & handle : m_handles[rank])
    {
      ref_ptr<OverlayHandle> parentOverlay;
      if (!CheckHandle(handle, rank, parentOverlay))
        continue;

      InsertHandle(handle, rank, parentOverlay);
    }
  }

  for (int rank = 0; rank < dp::OverlayRanksCount; rank++)
  {
    for (auto const & handle : m_handles[rank])
      handle->SetDisplayFlag(false);
    m_handles[rank].clear();
  }

  for (auto const & handle : m_handlesCache)
  {
    handle->SetDisplayFlag(true);
    handle->SetIsVisible(true);
    handle->SetCachingEnable(false);
  }

  m_frameCounter = 0;

#ifdef DEBUG_OVERLAYS_OUTPUT
  LOG(LINFO, ("- END OVERLAYS PLACING"));
#endif
}

bool OverlayTree::CheckHandle(ref_ptr<OverlayHandle> handle, int currentRank,
                              ref_ptr<OverlayHandle> & parentOverlay) const
{
  if (currentRank == dp::OverlayRank0)
    return true;

  parentOverlay = FindParent(handle, currentRank - 1);
  return parentOverlay != nullptr;
}

ref_ptr<OverlayHandle> OverlayTree::FindParent(ref_ptr<OverlayHandle> handle, int searchingRank) const
{
  ASSERT_GREATER_OR_EQUAL(searchingRank, 0, ());
  ASSERT_LESS(searchingRank, static_cast<int>(m_handles.size()), ());
  for (auto const & h : m_handles[searchingRank])
  {
    if (h->GetOverlayID() == handle->GetOverlayID() && m_handlesCache.find(h) != m_handlesCache.end())
      return h;
  }
  return nullptr;
}

void OverlayTree::DeleteHandle(ref_ptr<OverlayHandle> const & handle)
{
  size_t const deletedCount = m_handlesCache.erase(handle);
  if (deletedCount != 0)
    Erase(handle);
}

void OverlayTree::DeleteHandleWithParents(ref_ptr<OverlayHandle> handle, int currentRank)
{
  currentRank--;
  while (currentRank >= dp::OverlayRank0)
  {
    auto parent = FindParent(handle, currentRank);
    if (parent != nullptr && parent->IsBound())
      DeleteHandle(parent);
    currentRank--;
  }
  DeleteHandle(handle);
}

bool OverlayTree::GetSelectedFeatureRect(ScreenBase const & screen, m2::RectD & featureRect)
{
  if (!m_selectedFeatureID.IsValid())
    return false;

  featureRect.MakeEmpty();
  for (auto const & handle : m_handlesCache)
  {
    if (handle->IsVisible() && handle->GetOverlayID().m_featureId == m_selectedFeatureID)
    {
      m2::RectD rect = handle->GetPixelRect(screen, screen.isPerspective());
      featureRect.Add(rect);
    }
  }
  return true;
}

void OverlayTree::Select(m2::PointD const & glbPoint, TOverlayContainer & result) const
{
  ScreenBase const & screen = GetModelView();
  m2::PointD const pxPoint = screen.GtoP(glbPoint);

  double const kSearchRectHalfSize = 10.0;
  m2::RectD rect(pxPoint, pxPoint);
  rect.Inflate(kSearchRectHalfSize, kSearchRectHalfSize);

  for (auto const & handle : m_handlesCache)
  {
    if (!handle->HasLinearFeatureShape() && rect.IsPointInside(handle->GetPivot(screen, false)))
      result.push_back(handle);
  }
}

void OverlayTree::Select(m2::RectD const & rect, TOverlayContainer & result) const
{
  ScreenBase screen = GetModelView();
  ForEachInRect(rect, [&](ref_ptr<OverlayHandle> const & h)
  {
    if (!h->HasLinearFeatureShape() && h->IsVisible() && h->GetOverlayID().m_featureId.IsValid())
    {
      OverlayHandle::Rects shape;
      h->GetPixelShape(screen, screen.isPerspective(), shape);
      for (m2::RectF const & rShape : shape)
      {
        if (rShape.IsIntersect(m2::RectF(rect)))
        {
          result.push_back(h);
          break;
        }
      }
    }
  });
}

void OverlayTree::SetDisplacementEnabled(bool enabled)
{
  if (m_isDisplacementEnabled == enabled)
    return;
  m_isDisplacementEnabled = enabled;
  m_frameCounter = kInvalidFrame;
}

void OverlayTree::SetSelectedFeature(FeatureID const & featureID)
{
  m_selectedFeatureID = featureID;
}

OverlayTree::TDisplacementInfo const & OverlayTree::GetDisplacementInfo() const
{
  return m_displacementInfo;
}

void OverlayTree::StoreDisplacementInfo(int caseIndex, ref_ptr<OverlayHandle> displacerHandle,
                                        ref_ptr<OverlayHandle> displacedHandle)
{
  ScreenBase const & modelView = GetModelView();
  m2::RectD const pixelRect = displacerHandle->GetExtendedPixelRect(modelView);
  if (!m_traits.GetDisplacersFreeRect().IsRectInside(pixelRect))
    m_displacers.insert(displacerHandle);

#ifdef DEBUG_OVERLAYS_OUTPUT
    LOG(LINFO, ("Displace (", caseIndex, "):", displacerHandle->GetOverlayDebugInfo(),
                "->", displacedHandle->GetOverlayDebugInfo()));
#else
  UNUSED_VALUE(caseIndex);
#endif

  if (!dp::DebugRectRenderer::Instance().IsEnabled())
    return;
  m_displacementInfo.emplace_back(displacerHandle->GetExtendedPixelRect(modelView).Center(),
                                  displacedHandle->GetExtendedPixelRect(modelView).Center(),
                                  dp::Color(0, 0, 255, 255));
}

void detail::OverlayTraits::SetVisualScale(double visualScale)
{
  m_visualScale = visualScale;
}

void detail::OverlayTraits::SetModelView(ScreenBase const & modelView)
{
  m_modelView = modelView;

  double const extension = m_visualScale * kScreenPixelRectExtension;
  double const doubleExtension = 2.0 * extension;
  m_extendedScreenRect = modelView.PixelRectIn3d();
  m_extendedScreenRect.Inflate(extension, extension);

  m_displacersFreeRect = modelView.PixelRectIn3d();
  if (m_displacersFreeRect.SizeX() > doubleExtension && m_displacersFreeRect.SizeY() > doubleExtension)
    m_displacersFreeRect.Inflate(-extension, -extension);
  else
    m_displacersFreeRect.SetSizes(1e-7, 1e-7);
}
}  // namespace dp
<|endoftext|>


<commit_before>#pragma once

#include "console_user_server_client.hpp"
#include "constants.hpp"
#include "local_datagram_server.hpp"
#include "types.hpp"
#include <vector>

namespace krbn {
class receiver final {
public:
  receiver(const receiver&) = delete;

  receiver(void) : exit_loop_(false) {
    const size_t buffer_length = 32 * 1024;
    buffer_.resize(buffer_length);

    auto socket_file_path = console_user_server_client::make_console_user_server_socket_file_path(getuid());

    auto path = socket_file_path.c_str();
    unlink(path);
    server_ = std::make_unique<local_datagram_server>(path);

    chmod(path, 0600);

    shell_command_execution_queue_ = dispatch_queue_create("console_user_server_receiver", nullptr);

    exit_loop_ = false;
    thread_ = std::thread([this] { this->worker(); });
  }

  ~receiver(void) {
    dispatch_sync(shell_command_execution_queue_, ^{
      dispatch_release(shell_command_execution_queue_);
      shell_command_execution_queue_ = nullptr;
    });

    unlink(socket_path_.c_str());

    exit_loop_ = true;
    if (thread_.joinable()) {
      thread_.join();
    }

    server_ = nullptr;
  }

private:
  void worker(void) {
    if (!server_) {
      return;
    }

    while (!exit_loop_) {
      boost::system::error_code ec;
      std::size_t n = server_->receive(boost::asio::buffer(buffer_), boost::posix_time::seconds(1), ec);

      if (!ec && n > 0) {
        switch (operation_type(buffer_[0])) {
          case operation_type::shell_command_execution:
            if (n != sizeof(operation_type_shell_command_execution_struct)) {
              logger::get_logger().error("invalid size for operation_type::shell_command_execution");
            } else {
              auto p = reinterpret_cast<operation_type_shell_command_execution_struct*>(&(buffer_[0]));

              // Ensure shell_command is null-terminated string even if corrupted data is sent.
              p->shell_command[sizeof(p->shell_command) - 1] = '\0';

              std::string shell_command = p->shell_command;
              dispatch_async(shell_command_execution_queue_, ^{
                system(shell_command.c_str());
              });
            }
            break;

          default:
            break;
        }
      }
    }
  }

  std::string socket_path_;
  std::vector<uint8_t> buffer_;
  std::unique_ptr<local_datagram_server> server_;
  std::thread thread_;
  std::atomic<bool> exit_loop_;

  dispatch_queue_t shell_command_execution_queue_;
};
} // namespace krbn
<commit_msg>fix shell_command_execution_queue_ handling<commit_after>#pragma once

#include "console_user_server_client.hpp"
#include "constants.hpp"
#include "local_datagram_server.hpp"
#include "types.hpp"
#include <vector>

namespace krbn {
class receiver final {
public:
  receiver(const receiver&) = delete;

  receiver(void) : exit_loop_(false),
                   shell_command_execution_queue_(nullptr) {
    const size_t buffer_length = 32 * 1024;
    buffer_.resize(buffer_length);

    auto socket_file_path = console_user_server_client::make_console_user_server_socket_file_path(getuid());

    auto path = socket_file_path.c_str();
    unlink(path);
    server_ = std::make_unique<local_datagram_server>(path);

    chmod(path, 0600);

    shell_command_execution_queue_ = dispatch_queue_create("console_user_server_receiver", nullptr);

    exit_loop_ = false;
    thread_ = std::thread([this] { this->worker(); });

    logger::get_logger().info("receiver is initialized");
  }

  ~receiver(void) {
    dispatch_release(shell_command_execution_queue_);
    shell_command_execution_queue_ = nullptr;

    unlink(socket_path_.c_str());

    exit_loop_ = true;
    if (thread_.joinable()) {
      thread_.join();
    }

    server_ = nullptr;

    logger::get_logger().info("receiver is terminated");
  }

private:
  void worker(void) {
    if (!server_) {
      return;
    }

    while (!exit_loop_) {
      boost::system::error_code ec;
      std::size_t n = server_->receive(boost::asio::buffer(buffer_), boost::posix_time::seconds(1), ec);

      if (!ec && n > 0) {
        switch (operation_type(buffer_[0])) {
          case operation_type::shell_command_execution:
            if (n != sizeof(operation_type_shell_command_execution_struct)) {
              logger::get_logger().error("invalid size for operation_type::shell_command_execution");
            } else {
              auto p = reinterpret_cast<operation_type_shell_command_execution_struct*>(&(buffer_[0]));

              // Ensure shell_command is null-terminated string even if corrupted data is sent.
              p->shell_command[sizeof(p->shell_command) - 1] = '\0';

              std::string shell_command = p->shell_command;
              if (shell_command_execution_queue_) {
                dispatch_async(shell_command_execution_queue_, ^{
                  system(shell_command.c_str());
                });
              }
            }
            break;

          default:
            break;
        }
      }
    }
  }

  std::string socket_path_;
  std::vector<uint8_t> buffer_;
  std::unique_ptr<local_datagram_server> server_;
  std::thread thread_;
  std::atomic<bool> exit_loop_;

  dispatch_queue_t shell_command_execution_queue_;
};
} // namespace krbn
<|endoftext|>


<commit_before>#ifndef _PYUNO_PYUNO_HXX_
#define _PYUNO_PYUNO_HXX_

#ifndef Py_PYTHON_H

#ifdef _DEBUG
#undef _DEBUG
#include <Python.h>
#define _DEBUG
#else
#include <Python.h>
#endif // #ifdef _DEBUG
#endif // #ifdef Py_PYTHON_H

#ifndef _COM_SUN_STAR_UNO_XCOMPONENTCONTEXT_HPP_
#include <com/sun/star/uno/XComponentContext.hpp>
#endif

#ifndef _COM_SUN_STAR_SCRIPT_CANNOTCONVERTEXCEPTION_HPP_
#include <com/sun/star/script/CannotConvertException.hpp>
#endif

#ifndef _COM_SUN_STAR_LANG_ILLEGALARGUMENTEXCEPTION_HPP_
#include <com/sun/star/lang/IllegalArgumentException.hpp>
#endif

/**
   External interface of the Python UNO bridge.

   This is a C++ interface, because the core UNO components
   invocation and proxyfactory are used to implement the bridge.

   This interface is somewhat private and my change in future.

   A scripting framework implementation may use this interface
   to do the necessary conversions.
*/

#ifdef WIN32
#define PY_DLLEXPORT __declspec(dllexport)
#else
#define PY_DLLEXPORT
#endif

/** function called by the python runtime to initialize the
    pyuno module.

    preconditions: python has been initialized before and
                   the global interpreter lock is held
*/
extern "C" PY_DLLEXPORT void SAL_CALL initpyuno();

namespace pyuno
{

/** Helper class for keeping references to python objects.
    BEWARE: Look up every python function you use to check
    wether you get an acquired or not acquired object pointer
    (python terminus for a not acquired object pointer
    is 'borrowed reference'). Use in the acquired pointer cases the
    PyRef( pointer, SAL_NO_ACQUIRE) ctor.

    precondition: python has been initialized before and
    the global interpreter lock is held

*/
class PyRef
{
    PyObject *m;
public:
    PyRef () : m(0) {}
    PyRef( PyObject * p ) : m( p ) { Py_XINCREF( m ); }

    PyRef( PyObject * p, __sal_NoAcquire ) : m( p ) {}

    PyRef( const PyRef &r ) : m( r.get() ) { Py_XINCREF( m ); }

    ~PyRef() { Py_XDECREF( m ); }

    PyObject *get() const { return m; }

    PyObject * getAcquired() const
    {
        Py_XINCREF( const_cast< PyObject*> (m) );
        return m;
    }

    PyRef & operator = (  const PyRef & r )
    {
        PyObject *tmp = m;
        m = r.getAcquired();
        Py_XDECREF( tmp );
        return *this;
    }

    bool operator == (  const PyRef & r ) const
    {
        return r.get() == m;
    }

    /** clears the reference without decreasing the reference count
        only seldomly needed ! */
    void scratch()
    {
        m = 0;
    }

    /** clears the reference decreasing the refcount of the holded object.
     */
    void clear()
    {
        Py_XDECREF( m );
        m = 0;
    }

    /** returns 1 when the reference points to a python object python object,
        otherwise 0.
    */
    sal_Bool is() const
    {
        return m != 0;
    }

    struct Hash
    {
        int operator () ( const PyRef &r) const { return (int) r.get(); }
    };
};

struct stRuntimeImpl;
typedef struct stRuntimeImpl RuntimeImpl;

enum ConversionMode { ACCEPT_UNO_ANY, REJECT_UNO_ANY };

/** The pyuno::Runtime class keeps the internal state of the python UNO bridge
    for the currently in use python interpreter.

    You may keep a Runtime instance, use it from a different thread, etc. But you must
    make sure to fulfill all preconditions mentioned for the specific methods.
*/

class PY_DLLEXPORT Runtime
{
    RuntimeImpl *impl;
public:
    ~Runtime( );

    /**
        preconditions: python has been initialized before,
        the global interpreter lock is held and pyuno
        has been initialized for the currently used interpreter.

        Note: This method exists for efficiency reasons to save
        lookup costs for any2PyObject and pyObject2Any

        @throw RuntimeException in case the runtime has not been
               initialized before
     */
    Runtime() throw( com::sun::star::uno::RuntimeException );

    Runtime( const Runtime & );
    Runtime & operator = ( const Runtime & );

    /** Initializes the python-UNO bridge. May be called only once per python interpreter.

        @param ctx the component context is used to instantiate bridge services needed
        for bridging such as invocation, typeconverter, invocationadapterfactory, etc.

        preconditions: python has been initialized before and
        the global interpreter lock is held and pyuno is not
        initialized (see isInitialized() ).

        @throw RuntimeException in case the thread is not attached or the runtime
                                has not been initialized.
    */
    static void SAL_CALL initialize(
        const com::sun::star::uno::Reference< com::sun::star::uno::XComponentContext > & ctx )
        throw ( com::sun::star::uno::RuntimeException );

    /** Checks, whether the uno runtime is already initialized in the current python interpreter.
     */
    static bool SAL_CALL isInitialized() throw (com::sun::star::uno::RuntimeException);

    /** disposes the UNO bridge in this interpreter. All existing stubs/proxies
        become non-functional, using these proxies/stubs leads to runtime errors.

        preconditions: python has been initialized before and
        the global interpreter lock is held and pyuno was
        initialized before for the currently in use interpreter.
    */
    static void SAL_CALL finalize() throw(com::sun::star::uno::RuntimeException );

    /** converts something contained in an UNO Any to a Python object

        preconditions: python has been initialized before,
        the global interpreter lock is held and pyuno::Runtime
        has been initialized.
    */
    PyRef any2PyObject (const com::sun::star::uno::Any &source ) const
        throw ( com::sun::star::script::CannotConvertException,
                com::sun::star::lang::IllegalArgumentException,
                com::sun::star::uno::RuntimeException );

    /** converts a Python object to a UNO any

        preconditions: python has been initialized before,
        the global interpreter lock is held and pyuno
        has been initialized
    */
    com::sun::star::uno::Any pyObject2Any (
        const PyRef & source , enum ConversionMode mode = REJECT_UNO_ANY ) const
        throw ( com::sun::star::uno::RuntimeException);

    /** Returns the internal handle. Should only be used by the module implementation
     */
    RuntimeImpl *getImpl() const { return impl; }
};

/** helper class for attaching the current thread to the python runtime.

    Attaching is done creating a new threadstate for the given interpreter
    and acquiring the global interpreter lock.

    Usage:

    ... don't use python here
    {
        PyThreadAttach guard( PyInterpreterState_Head() );
        {
            ... do whatever python code you want
            {
               PyThreadDetach antiguard;
               ... don't use python here
            }
            ... do whatever python code you want
        }
    }
    ... don't use python here

    Note: The additional scope brackets after the PyThreadAttach are needed,
          e.g. when you would leave them away, dtors of potential pyrefs
          may be called after the thread has detached again.
 */
class PY_DLLEXPORT PyThreadAttach
{
    PyThreadState *tstate;
    PyThreadAttach ( const PyThreadAttach & ); // not implemented
    PyThreadAttach & operator = ( const PyThreadAttach & );
public:

    /** Creates a new python threadstate and acquires the global interpreter lock.
        precondition: The current thread MUST NOT hold the global interpreter lock.
        postcondition: The global interpreter lock is acquired

        @raises com::sun::star::uno::RuntimeException
             in case no pythread state could be created
     */
    PyThreadAttach( PyInterpreterState *interp) throw ( com::sun::star::uno::RuntimeException );

    /** Releases the global interpreter lock and destroys the thread state.
     */
    ~PyThreadAttach();
};

/** helper class for detaching the current thread from the python runtime
    to do some blocking, non-python related operation.

    @see PyThreadAttach
*/
class PY_DLLEXPORT PyThreadDetach
{
    PyThreadState *tstate;
    PyThreadDetach ( const PyThreadDetach & ); // not implemented
    PyThreadDetach & operator = ( const PyThreadDetach & ); // not implemented

public:
    /** Releases the global interpreter lock.

       precondition: The current thread MUST hold the global interpreter lock.
       postcondition: The current thread does not hold the global interpreter lock anymore.
    */
    PyThreadDetach() throw ( com::sun::star::uno::RuntimeException );
    /** Acquires the global interpreter lock again
    */
    ~PyThreadDetach();
};

}
#endif
<commit_msg>INTEGRATION: CWS geordi2q11 (1.2.30); FILE MERGED 2003/12/16 14:04:26 hr 1.2.30.1: #111934#: join CWS ooo111fix1<commit_after>#ifndef _PYUNO_PYUNO_HXX_
#define _PYUNO_PYUNO_HXX_

#ifndef Py_PYTHON_H

#ifdef _DEBUG
#undef _DEBUG
#include <Python.h>
#define _DEBUG
#else
#include <Python.h>
#endif // #ifdef _DEBUG
#endif // #ifdef Py_PYTHON_H

#ifndef _COM_SUN_STAR_UNO_XCOMPONENTCONTEXT_HPP_
#include <com/sun/star/uno/XComponentContext.hpp>
#endif

#ifndef _COM_SUN_STAR_SCRIPT_CANNOTCONVERTEXCEPTION_HPP_
#include <com/sun/star/script/CannotConvertException.hpp>
#endif

#ifndef _COM_SUN_STAR_LANG_ILLEGALARGUMENTEXCEPTION_HPP_
#include <com/sun/star/lang/IllegalArgumentException.hpp>
#endif

/**
   External interface of the Python UNO bridge.

   This is a C++ interface, because the core UNO components
   invocation and proxyfactory are used to implement the bridge.

   This interface is somewhat private and my change in future.

   A scripting framework implementation may use this interface
   to do the necessary conversions.
*/

#ifdef WIN32
#define PY_DLLEXPORT __declspec(dllexport)
#else
#define PY_DLLEXPORT
#endif

/** function called by the python runtime to initialize the
    pyuno module.

    preconditions: python has been initialized before and
                   the global interpreter lock is held
*/
extern "C" PY_DLLEXPORT void SAL_CALL initpyuno();

namespace pyuno
{

/** Helper class for keeping references to python objects.
    BEWARE: Look up every python function you use to check
    wether you get an acquired or not acquired object pointer
    (python terminus for a not acquired object pointer
    is 'borrowed reference'). Use in the acquired pointer cases the
    PyRef( pointer, SAL_NO_ACQUIRE) ctor.

    precondition: python has been initialized before and
    the global interpreter lock is held

*/
class PyRef
{
    PyObject *m;
public:
    PyRef () : m(0) {}
    PyRef( PyObject * p ) : m( p ) { Py_XINCREF( m ); }

    PyRef( PyObject * p, __sal_NoAcquire ) : m( p ) {}

    PyRef( const PyRef &r ) : m( r.get() ) { Py_XINCREF( m ); }

    ~PyRef() { Py_XDECREF( m ); }

    PyObject *get() const { return m; }

    PyObject * getAcquired() const
    {
        Py_XINCREF( const_cast< PyObject*> (m) );
        return m;
    }

    PyRef & operator = (  const PyRef & r )
    {
        PyObject *tmp = m;
        m = r.getAcquired();
        Py_XDECREF( tmp );
        return *this;
    }

    bool operator == (  const PyRef & r ) const
    {
        return r.get() == m;
    }

    /** clears the reference without decreasing the reference count
        only seldomly needed ! */
    void scratch()
    {
        m = 0;
    }

    /** clears the reference decreasing the refcount of the holded object.
     */
    void clear()
    {
        Py_XDECREF( m );
        m = 0;
    }

    /** returns 1 when the reference points to a python object python object,
        otherwise 0.
    */
    sal_Bool is() const
    {
        return m != 0;
    }

    struct Hash
    {
        int operator () ( const PyRef &r) const { return (int) r.get(); }
    };
};

struct stRuntimeImpl;
typedef struct stRuntimeImpl RuntimeImpl;

enum ConversionMode { ACCEPT_UNO_ANY, REJECT_UNO_ANY };

/** The pyuno::Runtime class keeps the internal state of the python UNO bridge
    for the currently in use python interpreter.

    You may keep a Runtime instance, use it from a different thread, etc. But you must
    make sure to fulfill all preconditions mentioned for the specific methods.
*/

class PY_DLLEXPORT Runtime
{
    RuntimeImpl *impl;
public:
    ~Runtime( );

    /**
        preconditions: python has been initialized before,
        the global interpreter lock is held and pyuno
        has been initialized for the currently used interpreter.

        Note: This method exists for efficiency reasons to save
        lookup costs for any2PyObject and pyObject2Any

        @throw RuntimeException in case the runtime has not been
               initialized before
     */
    Runtime() throw( com::sun::star::uno::RuntimeException );

    Runtime( const Runtime & );
    Runtime & operator = ( const Runtime & );

    /** Initializes the python-UNO bridge. May be called only once per python interpreter.

        @param ctx the component context is used to instantiate bridge services needed
        for bridging such as invocation, typeconverter, invocationadapterfactory, etc.

        preconditions: python has been initialized before and
        the global interpreter lock is held and pyuno is not
        initialized (see isInitialized() ).

        @throw RuntimeException in case the thread is not attached or the runtime
                                has not been initialized.
    */
    static void SAL_CALL initialize(
        const com::sun::star::uno::Reference< com::sun::star::uno::XComponentContext > & ctx )
        throw ( com::sun::star::uno::RuntimeException );

    /** Checks, whether the uno runtime is already initialized in the current python interpreter.
     */
    static bool SAL_CALL isInitialized() throw (com::sun::star::uno::RuntimeException);

    /** disposes the UNO bridge in this interpreter. All existing stubs/proxies
        become non-functional, using these proxies/stubs leads to runtime errors.

        preconditions: python has been initialized before and
        the global interpreter lock is held and pyuno was
        initialized before for the currently in use interpreter.
    */
    static void SAL_CALL finalize() throw(com::sun::star::uno::RuntimeException );

    /** converts something contained in an UNO Any to a Python object

        preconditions: python has been initialized before,
        the global interpreter lock is held and pyuno::Runtime
        has been initialized.
    */
    PyRef any2PyObject (const com::sun::star::uno::Any &source ) const
        throw ( com::sun::star::script::CannotConvertException,
                com::sun::star::lang::IllegalArgumentException,
                com::sun::star::uno::RuntimeException );

    /** converts a Python object to a UNO any

        preconditions: python has been initialized before,
        the global interpreter lock is held and pyuno
        has been initialized
    */
    com::sun::star::uno::Any pyObject2Any (
        const PyRef & source , enum ConversionMode mode = REJECT_UNO_ANY ) const
        throw ( com::sun::star::uno::RuntimeException);

    /** extracts a proper uno exception from a given python exception
     */
    com::sun::star::uno::Any extractUnoException(
        const PyRef & excType, const PyRef & excValue, const PyRef & excTraceback) const;

    /** Returns the internal handle. Should only be used by the module implementation
     */
    RuntimeImpl *getImpl() const { return impl; }
};

/** helper class for attaching the current thread to the python runtime.

    Attaching is done creating a new threadstate for the given interpreter
    and acquiring the global interpreter lock.

    Usage:

    ... don't use python here
    {
        PyThreadAttach guard( PyInterpreterState_Head() );
        {
            ... do whatever python code you want
            {
               PyThreadDetach antiguard;
               ... don't use python here
            }
            ... do whatever python code you want
        }
    }
    ... don't use python here

    Note: The additional scope brackets after the PyThreadAttach are needed,
          e.g. when you would leave them away, dtors of potential pyrefs
          may be called after the thread has detached again.
 */
class PY_DLLEXPORT PyThreadAttach
{
    PyThreadState *tstate;
    PyThreadAttach ( const PyThreadAttach & ); // not implemented
    PyThreadAttach & operator = ( const PyThreadAttach & );
public:

    /** Creates a new python threadstate and acquires the global interpreter lock.
        precondition: The current thread MUST NOT hold the global interpreter lock.
        postcondition: The global interpreter lock is acquired

        @raises com::sun::star::uno::RuntimeException
             in case no pythread state could be created
     */
    PyThreadAttach( PyInterpreterState *interp) throw ( com::sun::star::uno::RuntimeException );

    /** Releases the global interpreter lock and destroys the thread state.
     */
    ~PyThreadAttach();
};

/** helper class for detaching the current thread from the python runtime
    to do some blocking, non-python related operation.

    @see PyThreadAttach
*/
class PY_DLLEXPORT PyThreadDetach
{
    PyThreadState *tstate;
    PyThreadDetach ( const PyThreadDetach & ); // not implemented
    PyThreadDetach & operator = ( const PyThreadDetach & ); // not implemented

public:
    /** Releases the global interpreter lock.

       precondition: The current thread MUST hold the global interpreter lock.
       postcondition: The current thread does not hold the global interpreter lock anymore.
    */
    PyThreadDetach() throw ( com::sun::star::uno::RuntimeException );
    /** Acquires the global interpreter lock again
    */
    ~PyThreadDetach();
};

}
#endif
<|endoftext|>


<commit_before>#include <IOKit/IOLib.h>

#include "Config.hpp"
#include "IOLogWrapper.hpp"
#include "PointingRelativeToKey.hpp"

namespace org_pqrs_KeyRemap4MacBook {
  namespace RemapFunc {
    PointingRelativeToKey::PointingRelativeToKey(void) :
      current_keytokey_(NULL)
    {
      keyrepeat_ic_.begin();
    }

    PointingRelativeToKey::~PointingRelativeToKey(void)
    {}

    void
    PointingRelativeToKey::add(unsigned int datatype, unsigned int newval)
    {
      switch (datatype) {
        case BRIDGE_DATATYPE_POINTINGRELATIVE:
        {
          PointingRelative val(newval);
          if (val == PointingRelative::UP)    { current_keytokey_ = &(keytokey_[KEYTOKEY_UP]);    }
          if (val == PointingRelative::DOWN)  { current_keytokey_ = &(keytokey_[KEYTOKEY_DOWN]);  }
          if (val == PointingRelative::LEFT)  { current_keytokey_ = &(keytokey_[KEYTOKEY_LEFT]);  }
          if (val == PointingRelative::RIGHT) { current_keytokey_ = &(keytokey_[KEYTOKEY_RIGHT]); }
          break;
        }

        case BRIDGE_DATATYPE_KEYCODE:
        case BRIDGE_DATATYPE_CONSUMERKEYCODE:
        case BRIDGE_DATATYPE_POINTINGBUTTON:
        case BRIDGE_DATATYPE_OPTION:
        {
          if (! current_keytokey_) {
            IOLOG_ERROR("Invalid PointingRelativeToKey::add\n");
          } else {
            if (current_keytokey_->toKeysSize() == 0) {
              current_keytokey_->add(KeyCode::VK_PSEUDO_KEY);
              current_keytokey_->add(fromFlags_);
            }
            current_keytokey_->add(datatype, newval);
          }

          break;
        }

        case BRIDGE_DATATYPE_FLAGS:
        {
          if (! current_keytokey_) {
            fromFlags_ = Flags(newval);
          } else {
            current_keytokey_->add(datatype, newval);
          }
          break;
        }

        default:
          IOLOG_ERROR("PointingRelativeToKey::add invalid datatype:%d\n", datatype);
          break;
      }
    }

    bool
    PointingRelativeToKey::remap(RemapParams& remapParams)
    {
      Params_RelativePointerEventCallback* params = remapParams.paramsUnion.get_Params_RelativePointerEventCallback();
      if (! params) return false;

      // ------------------------------------------------------------
      if (remapParams.isremapped) return false;
      if (! FlagStatus::makeFlags().isOn(fromFlags_)) return false;
      // skip button press/release events.
      if (params->ex_button != PointingButton::NONE) return false;

      remapParams.isremapped = true;

      // ------------------------------------------------------------
      uint32_t detection_interval = static_cast<uint32_t>(Config::get_essential_config(BRIDGE_ESSENTIAL_CONFIG_INDEX_parameter_pointingrelativetokey_detection_interval));
      if (keyrepeat_ic_.getmillisec() > detection_interval) {
        deltaBuffer_dx_.push(params->dx);
        deltaBuffer_dy_.push(params->dy);
      }

      if (deltaBuffer_dx_.isFull() || deltaBuffer_dy_.isFull()) {
        int dx = deltaBuffer_dx_.sum();
        int dy = deltaBuffer_dy_.sum();

        size_t keytokey_index = KEYTOKEY__END__;
        PointingRelative pr = PointingRelative::getPointingRelativeFromDelta(dx, dy);
        if (pr == PointingRelative::UP)    { keytokey_index = KEYTOKEY_UP;    }
        if (pr == PointingRelative::DOWN)  { keytokey_index = KEYTOKEY_DOWN;  }
        if (pr == PointingRelative::LEFT)  { keytokey_index = KEYTOKEY_LEFT;  }
        if (pr == PointingRelative::RIGHT) { keytokey_index = KEYTOKEY_RIGHT; }

        if (keytokey_index != KEYTOKEY__END__) {
          keytokey_[keytokey_index].call_remap_with_VK_PSEUDO_KEY(EventType::DOWN);
          keytokey_[keytokey_index].call_remap_with_VK_PSEUDO_KEY(EventType::UP);
          // clear temporary flags.
          FlagStatus::set();

          deltaBuffer_dx_.clear();
          deltaBuffer_dy_.clear();
          keyrepeat_ic_.begin();
        }
      }

      return true;
    }
  }
}
<commit_msg>Call EventWatcher::on at PointingRelativeToKey<commit_after>#include <IOKit/IOLib.h>

#include "Config.hpp"
#include "EventWatcher.hpp"
#include "IOLogWrapper.hpp"
#include "PointingRelativeToKey.hpp"

namespace org_pqrs_KeyRemap4MacBook {
  namespace RemapFunc {
    PointingRelativeToKey::PointingRelativeToKey(void) :
      current_keytokey_(NULL)
    {
      keyrepeat_ic_.begin();
    }

    PointingRelativeToKey::~PointingRelativeToKey(void)
    {}

    void
    PointingRelativeToKey::add(unsigned int datatype, unsigned int newval)
    {
      switch (datatype) {
        case BRIDGE_DATATYPE_POINTINGRELATIVE:
        {
          PointingRelative val(newval);
          if (val == PointingRelative::UP)    { current_keytokey_ = &(keytokey_[KEYTOKEY_UP]);    }
          if (val == PointingRelative::DOWN)  { current_keytokey_ = &(keytokey_[KEYTOKEY_DOWN]);  }
          if (val == PointingRelative::LEFT)  { current_keytokey_ = &(keytokey_[KEYTOKEY_LEFT]);  }
          if (val == PointingRelative::RIGHT) { current_keytokey_ = &(keytokey_[KEYTOKEY_RIGHT]); }
          break;
        }

        case BRIDGE_DATATYPE_KEYCODE:
        case BRIDGE_DATATYPE_CONSUMERKEYCODE:
        case BRIDGE_DATATYPE_POINTINGBUTTON:
        case BRIDGE_DATATYPE_OPTION:
        {
          if (! current_keytokey_) {
            IOLOG_ERROR("Invalid PointingRelativeToKey::add\n");
          } else {
            if (current_keytokey_->toKeysSize() == 0) {
              current_keytokey_->add(KeyCode::VK_PSEUDO_KEY);
              current_keytokey_->add(fromFlags_);
            }
            current_keytokey_->add(datatype, newval);
          }

          break;
        }

        case BRIDGE_DATATYPE_FLAGS:
        {
          if (! current_keytokey_) {
            fromFlags_ = Flags(newval);
          } else {
            current_keytokey_->add(datatype, newval);
          }
          break;
        }

        default:
          IOLOG_ERROR("PointingRelativeToKey::add invalid datatype:%d\n", datatype);
          break;
      }
    }

    bool
    PointingRelativeToKey::remap(RemapParams& remapParams)
    {
      Params_RelativePointerEventCallback* params = remapParams.paramsUnion.get_Params_RelativePointerEventCallback();
      if (! params) return false;

      // ------------------------------------------------------------
      if (remapParams.isremapped) return false;
      if (! FlagStatus::makeFlags().isOn(fromFlags_)) return false;
      // skip button press/release events.
      if (params->ex_button != PointingButton::NONE) return false;

      remapParams.isremapped = true;

      // ------------------------------------------------------------
      uint32_t detection_interval = static_cast<uint32_t>(Config::get_essential_config(BRIDGE_ESSENTIAL_CONFIG_INDEX_parameter_pointingrelativetokey_detection_interval));
      if (keyrepeat_ic_.getmillisec() > detection_interval) {
        deltaBuffer_dx_.push(params->dx);
        deltaBuffer_dy_.push(params->dy);
      }

      if (deltaBuffer_dx_.isFull() || deltaBuffer_dy_.isFull()) {
        int dx = deltaBuffer_dx_.sum();
        int dy = deltaBuffer_dy_.sum();

        size_t keytokey_index = KEYTOKEY__END__;
        PointingRelative pr = PointingRelative::getPointingRelativeFromDelta(dx, dy);
        if (pr == PointingRelative::UP)    { keytokey_index = KEYTOKEY_UP;    }
        if (pr == PointingRelative::DOWN)  { keytokey_index = KEYTOKEY_DOWN;  }
        if (pr == PointingRelative::LEFT)  { keytokey_index = KEYTOKEY_LEFT;  }
        if (pr == PointingRelative::RIGHT) { keytokey_index = KEYTOKEY_RIGHT; }

        if (keytokey_index != KEYTOKEY__END__) {
          keytokey_[keytokey_index].call_remap_with_VK_PSEUDO_KEY(EventType::DOWN);
          keytokey_[keytokey_index].call_remap_with_VK_PSEUDO_KEY(EventType::UP);
          // clear temporary flags.
          FlagStatus::set();

          // We need to call EventWatcher::on here.
          // See the comments in EventInputQueue::fire_timer_callback.
          EventWatcher::on();

          deltaBuffer_dx_.clear();
          deltaBuffer_dy_.clear();
          keyrepeat_ic_.begin();
        }
      }

      return true;
    }
  }
}
<|endoftext|>