<commit_before>#include "evpp/inner_pre.h"

#include <string.h>

#include "evpp/libevent_watcher.h"
#include "evpp/libevent_headers.h"
#include "evpp/event_loop.h"

namespace evpp {

    EventWatcher::EventWatcher(struct event_base* evbase, const Handler& handler)
        : evbase_(evbase), handler_(handler), attached_to_loop_(false) {
        event_ = new event;
        memset(event_, 0, sizeof(struct event));
    }

    EventWatcher::~EventWatcher() {
        FreeEvent();
        Close();
    }

    bool EventWatcher::Init() {
        if (!DoInit()) {
            goto failed;
        }
        ::event_base_set(evbase_, event_);
        return true;

    failed:
        Close();
        return false;
    }

    void EventWatcher::Close() {
        DoClose();
    }

    bool EventWatcher::Watch(Duration timeout) {
        struct timeval tv;
        struct timeval* timeoutval = NULL;

        if (timeout.Nanoseconds() > 0) {
            timeout.To(&tv);
            timeoutval = &tv;
        }

        if (attached_to_loop_) {
            // ԵInvokerTimerУEventWatcher::Watch ᱻöΣͿԱ event_add öΡ
            ::event_del(event_);
            attached_to_loop_ = false;
        }

        if (::event_add(event_, timeoutval) != 0) {
            return false;
        }
        attached_to_loop_ = true;
        return true;
    }

    void EventWatcher::FreeEvent() {
        if (event_) {
            if (event_initialized(event_)) {
                ::event_del(event_);
            }
            delete (event_);
            event_ = NULL;
        }
    }

    void EventWatcher::Cancel() {
        FreeEvent();
        if (cancel_callback_) {
            cancel_callback_();
        }
    }

    void EventWatcher::set_cancel_callback(const Handler& cb) {
        cancel_callback_ = cb;
    }

    //////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////

    PipeEventWatcher::PipeEventWatcher(struct event_base *event_base,
                                       const Handler& handler)
                                       : EventWatcher(event_base, handler) {
        memset(pipe_, 0, sizeof(pipe_[0] * 2));
    }

    PipeEventWatcher::PipeEventWatcher(EventLoop* loop,
                                       const Handler& handler)
                                       : EventWatcher(loop->event_base(), handler) {
        memset(pipe_, 0, sizeof(pipe_[0] * 2));
    }

    bool PipeEventWatcher::DoInit() {
        assert(pipe_[0] == 0);

        if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, pipe_) < 0) {
            LOG_ERROR << "create socketpair ERROR";
            goto failed;
        }

        if (evutil_make_socket_nonblocking(pipe_[0]) < 0 ||
            evutil_make_socket_nonblocking(pipe_[1]) < 0) {
            goto failed;
        }

        ::event_set(event_, pipe_[1], EV_READ | EV_PERSIST,
                  PipeEventWatcher::HandlerFn, this);
        return true;
    failed:
        Close();
        return false;
    }

    void PipeEventWatcher::DoClose() {
        if (pipe_[0] > 0) {
            EVUTIL_CLOSESOCKET(pipe_[0]);
            EVUTIL_CLOSESOCKET(pipe_[1]);
            memset(pipe_, 0, sizeof(pipe_[0]) * 2);
        }
    }

    void PipeEventWatcher::HandlerFn(int fd, short which, void *v) {
        PipeEventWatcher *e = (PipeEventWatcher*)v;
        char buf[128];
        int n = 0;
        if ((n = ::recv(e->pipe_[1], buf, sizeof(buf), 0)) > 0) {
            e->handler_();
        }
    }

    void PipeEventWatcher::AsyncWait() {
        Watch(Duration());
    }

    void PipeEventWatcher::Notify() {
        char buf[1] = {};
        if (::send(pipe_[0], buf, sizeof(buf), 0) < 0) {
            return;
        }
    }

    //////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////

    TimerEventWatcher::TimerEventWatcher(struct event_base *event_base,
                                         const Handler& handler,
                                         Duration timeout)
        : EventWatcher(event_base, handler)
        , timeout_(timeout) {}

    TimerEventWatcher::TimerEventWatcher(EventLoop* loop,
                                         const Handler& handler,
                                         Duration timeout)
        : EventWatcher(loop->event_base(), handler)
        , timeout_(timeout) {}

    bool TimerEventWatcher::DoInit() {
        ::event_set(event_, -1, 0, TimerEventWatcher::HandlerFn, this);
        return true;
    }

    void TimerEventWatcher::HandlerFn(int fd, short which, void *v) {
        TimerEventWatcher *h = (TimerEventWatcher*)v;
        h->handler_();
    }

    bool TimerEventWatcher::AsyncWait() {
        return Watch(timeout_);
    }

    //////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////
#ifndef H_OS_WINDOWS
    SignalEventWatcher::SignalEventWatcher(int signo, struct event_base *event_base,
                                           const Handler& handler)
                                           : EventWatcher(event_base, handler)
                                           , signo_(signo) {
        assert(signo_);
    }

    SignalEventWatcher::SignalEventWatcher(int signo, EventLoop* loop,
                                           const Handler& handler)
                                           : EventWatcher(loop->event_base(), handler)
                                           , signo_(signo) {
        assert(signo_);
    }

    bool SignalEventWatcher::DoInit() {
        assert(signo_);
        signal_set(event_, signo_, SignalEventWatcher::HandlerFn, this);
        return true;
    }

    void SignalEventWatcher::HandlerFn(int sn, short which, void *v) {
        SignalEventWatcher *h = (SignalEventWatcher*)v;
        h->handler_();
    }
#endif
}

<commit_msg>Fix bool evpp::EventWatcher::attached_to_loop_ compile warning<commit_after>#include "evpp/inner_pre.h"

#include <string.h>

#include "evpp/libevent_watcher.h"
#include "evpp/libevent_headers.h"
#include "evpp/event_loop.h"

namespace evpp {

    EventWatcher::EventWatcher(struct event_base* evbase, const Handler& handler)
        : evbase_(evbase), attached_to_loop_(false), handler_(handler) {
        event_ = new event;
        memset(event_, 0, sizeof(struct event));
    }

    EventWatcher::~EventWatcher() {
        FreeEvent();
        Close();
    }

    bool EventWatcher::Init() {
        if (!DoInit()) {
            goto failed;
        }
        ::event_base_set(evbase_, event_);
        return true;

    failed:
        Close();
        return false;
    }

    void EventWatcher::Close() {
        DoClose();
    }

    bool EventWatcher::Watch(Duration timeout) {
        struct timeval tv;
        struct timeval* timeoutval = NULL;

        if (timeout.Nanoseconds() > 0) {
            timeout.To(&tv);
            timeoutval = &tv;
        }

        if (attached_to_loop_) {
            // ԵInvokerTimerУEventWatcher::Watch ᱻöΣͿԱ event_add öΡ
            ::event_del(event_);
            attached_to_loop_ = false;
        }

        if (::event_add(event_, timeoutval) != 0) {
            return false;
        }
        attached_to_loop_ = true;
        return true;
    }

    void EventWatcher::FreeEvent() {
        if (event_) {
            if (event_initialized(event_)) {
                ::event_del(event_);
            }
            delete (event_);
            event_ = NULL;
        }
    }

    void EventWatcher::Cancel() {
        FreeEvent();
        if (cancel_callback_) {
            cancel_callback_();
        }
    }

    void EventWatcher::set_cancel_callback(const Handler& cb) {
        cancel_callback_ = cb;
    }

    //////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////

    PipeEventWatcher::PipeEventWatcher(struct event_base *event_base,
                                       const Handler& handler)
                                       : EventWatcher(event_base, handler) {
        memset(pipe_, 0, sizeof(pipe_[0] * 2));
    }

    PipeEventWatcher::PipeEventWatcher(EventLoop* loop,
                                       const Handler& handler)
                                       : EventWatcher(loop->event_base(), handler) {
        memset(pipe_, 0, sizeof(pipe_[0] * 2));
    }

    bool PipeEventWatcher::DoInit() {
        assert(pipe_[0] == 0);

        if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, pipe_) < 0) {
            LOG_ERROR << "create socketpair ERROR";
            goto failed;
        }

        if (evutil_make_socket_nonblocking(pipe_[0]) < 0 ||
            evutil_make_socket_nonblocking(pipe_[1]) < 0) {
            goto failed;
        }

        ::event_set(event_, pipe_[1], EV_READ | EV_PERSIST,
                  PipeEventWatcher::HandlerFn, this);
        return true;
    failed:
        Close();
        return false;
    }

    void PipeEventWatcher::DoClose() {
        if (pipe_[0] > 0) {
            EVUTIL_CLOSESOCKET(pipe_[0]);
            EVUTIL_CLOSESOCKET(pipe_[1]);
            memset(pipe_, 0, sizeof(pipe_[0]) * 2);
        }
    }

    void PipeEventWatcher::HandlerFn(int fd, short which, void *v) {
        PipeEventWatcher *e = (PipeEventWatcher*)v;
        char buf[128];
        int n = 0;
        if ((n = ::recv(e->pipe_[1], buf, sizeof(buf), 0)) > 0) {
            e->handler_();
        }
    }

    void PipeEventWatcher::AsyncWait() {
        Watch(Duration());
    }

    void PipeEventWatcher::Notify() {
        char buf[1] = {};
        if (::send(pipe_[0], buf, sizeof(buf), 0) < 0) {
            return;
        }
    }

    //////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////

    TimerEventWatcher::TimerEventWatcher(struct event_base *event_base,
                                         const Handler& handler,
                                         Duration timeout)
        : EventWatcher(event_base, handler)
        , timeout_(timeout) {}

    TimerEventWatcher::TimerEventWatcher(EventLoop* loop,
                                         const Handler& handler,
                                         Duration timeout)
        : EventWatcher(loop->event_base(), handler)
        , timeout_(timeout) {}

    bool TimerEventWatcher::DoInit() {
        ::event_set(event_, -1, 0, TimerEventWatcher::HandlerFn, this);
        return true;
    }

    void TimerEventWatcher::HandlerFn(int fd, short which, void *v) {
        TimerEventWatcher *h = (TimerEventWatcher*)v;
        h->handler_();
    }

    bool TimerEventWatcher::AsyncWait() {
        return Watch(timeout_);
    }

    //////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////
#ifndef H_OS_WINDOWS
    SignalEventWatcher::SignalEventWatcher(int signo, struct event_base *event_base,
                                           const Handler& handler)
                                           : EventWatcher(event_base, handler)
                                           , signo_(signo) {
        assert(signo_);
    }

    SignalEventWatcher::SignalEventWatcher(int signo, EventLoop* loop,
                                           const Handler& handler)
                                           : EventWatcher(loop->event_base(), handler)
                                           , signo_(signo) {
        assert(signo_);
    }

    bool SignalEventWatcher::DoInit() {
        assert(signo_);
        signal_set(event_, signo_, SignalEventWatcher::HandlerFn, this);
        return true;
    }

    void SignalEventWatcher::HandlerFn(int sn, short which, void *v) {
        SignalEventWatcher *h = (SignalEventWatcher*)v;
        h->handler_();
    }
#endif
}

<|endoftext|>


<commit_before>#include "StableHeaders.h"
#include "Session.h"
//#include "MemoryLeakCheck.h"
#include "ServerInfo.h"
#include "PCMAudioFrame.h"
#include "Vector3D.h"
#include "EC_OgrePlaceable.h" // for avatar position
#include "EC_OpenSimPresence.h" // for avatar position
#include "ModuleManager.h"    // for avatar info
#include "WorldLogicInterface.h" // for avatar position
#include "Entity.h" // for avatar position
#include "SceneManager.h"
#include "WorldStream.h"
#include "User.h"
#include "Channel.h"
#include "Connection.h"
#include "Participant.h"
#include "MumbleLibrary.h"
#include "MumbleVoipModule.h"

//#define BUILDING_DLL // for dll import/export declarations
//#define CreateEvent  CreateEventW // for \boost\asio\detail\win_event.hpp and \boost\asio\detail\win_iocp_handle_service.hpp
////#include <mumbleclient/client_lib.h>
//#undef BUILDING_DLL // for dll import/export declarations
////#include "LibMumbleThread.h"

namespace MumbleVoip
{
    namespace InWorldVoice
    {
        Session::Session(Foundation::Framework* framework, const ServerInfo &server_info) :
            state_(STATE_INITIALIZING),
            reason_(""),
            framework_(framework),
            description_(""),
            sending_audio_(false),
            receiving_audio_(false),
            audio_sending_enabled_(false),
            audio_receiving_enabled_(false),
            speaker_voice_activity_(0),
//            connection_manager_(new ConnectionManager(framework)),
            server_info_(server_info),
            connection_(0)
        {
            channel_name_ = server_info.channel;
            OpenConnection(server_info);

            //connection_manager_->OpenConnection(server_info);
            //if (connection_manager_->GetState() != ConnectionManager::STATE_CONNECTION_OPEN)
            //{
            //    state_ = STATE_ERROR;
            //    reason_ = connection_manager_->GetReason();
            //    return;
            //}
        }

        Session::~Session()
        {
            foreach(Participant* p, participants_)
            {
                SAFE_DELETE(p);
            }
            participants_.clear();
            foreach(Participant* p, left_participants_)
            {
                SAFE_DELETE(p);
            }
            left_participants_.clear();
            if (connection_)
                SAFE_DELETE(connection_);
        }

        void Session::OpenConnection(ServerInfo server_info)
        {
            connection_ = new Connection(server_info);
            if (connection_->GetState() == Connection::STATE_ERROR)
            {
                state_ = STATE_ERROR;
                reason_ = connection_->GetReason();
                return;
            }
            state_ = STATE_OPEN;

            connect(connection_, SIGNAL(UserJoined(User*)), SLOT(CreateNewParticipant(User*)) );
            connect(connection_, SIGNAL(UserLeft(User*)), SLOT(UpdateUserList()) );
//            connections_[info.server] = connection;
            connection_->Join(server_info.channel);
            connection_->SendAudio(sending_audio_);
            connection_->SetEncodingQuality(0.5);
            connection_->SendPosition(true);
            MumbleLibrary::Start();
            MumbleLibrary::Stop();
            //connect(MumbleLibrary::Instance(), SIGNAL(InteralError()), SLOT(HandleMumbleLibraryError()) );
//            connect(connection_manager_, SIGNAL(AudioFrameSent(PCMAudioFrame*)), SLOT(UpdateSpeakerActivity(PCMAudioFrame*)) );
        }

        void Session::Close()
        {
            connection_->Close();
            SAFE_DELETE(connection_);
            state_ = STATE_CLOSED;
            emit StateChanged(state_);
        }

        Communications::InWorldVoice::SessionInterface::State Session::GetState() const
        {
            return state_;
        }

        QString Session::Reason() const
        {
            return reason_;
        }

        QString Session::Description() const
        {
            return description_;
        }

        bool Session::IsSendingAudio() const
        {
            return sending_audio_;
        }

        bool Session::IsReceivingAudio() const
        {
            return receiving_audio_;
        }

        void Session::EnableAudioSending()
        {
            if (connection_)
                connection_->SendAudio(true);
            bool audio_sending_was_enabled = audio_sending_enabled_;
            audio_sending_enabled_ = true;
            if (!audio_sending_was_enabled)
            {
                boost::shared_ptr<Foundation::SoundServiceInterface> sound_service = SoundService();
                if (sound_service.get())
                {
                    int frequency = SAMPLE_RATE;
                    bool sixteenbit = true;
                    bool stereo = false;
                    int buffer_size = SAMPLE_WIDTH/8*frequency*AUDIO_RECORDING_BUFFER_MS/1000;
                    sound_service->StartRecording(recording_device_, frequency, sixteenbit, stereo, buffer_size);
                }

                emit StartSendingAudio();
            }
        }

        void Session::DisableAudioSending()
        {
            if (connection_)
                connection_->SendAudio(false);
            bool audio_sending_was_enabled = audio_sending_enabled_;
            audio_sending_enabled_ = false;
            if (audio_sending_was_enabled)
            {
                boost::shared_ptr<Foundation::SoundServiceInterface> sound_service = SoundService();
                if (sound_service.get())
                    sound_service->StopRecording();

                emit StopSendingAudio();
            }
        }

        bool Session::IsAudioSendingEnabled() const
        {
            return audio_sending_enabled_;
        }

        void Session::EnableAudioReceiving()
        {
            if (connection_)
                connection_->ReceiveAudio(true);
            audio_receiving_enabled_ = true;
        }

        void Session::DisableAudioReceiving()
        {
            if (connection_)
                connection_->ReceiveAudio(false);
            audio_receiving_enabled_ = false;
        }

        bool Session::IsAudioReceivingEnabled() const
        {
            return audio_receiving_enabled_;
        }

        double Session::SpeakerVoiceActivity() const
        {
            return speaker_voice_activity_;
        }

        QList<Communications::InWorldVoice::ParticipantInterface*> Session::Participants() const
        {
            QList<Communications::InWorldVoice::ParticipantInterface*> list;
            for(ParticipantList::const_iterator i = participants_.begin(); i != participants_.end(); ++i)
            {
                Participant* p = *i;
                list.append(static_cast<Communications::InWorldVoice::ParticipantInterface*>(p));
            }
            return list;
        }

        void Session::Update(f64 frametime)
        {
//                connection_manager_->Update(frametime);
            PlaybackReceivedAudio();
            SendRecordedAudio();
        }

        void Session::CreateNewParticipant(User* user)
        {
            if (user->Name() == OwnAvatarId())
            {
                self_user_ = user;
                return;
            }

            if (user->Channel()->FullName() != channel_name_)
                return;

            QString uuid = user->Name();
            QString name = GetAvatarFullName(uuid);
            if (name.size() == 0)
                name = QString("(Unknow) %0").arg(user->Name());
            Participant* p = new Participant(name, user);
            participants_.append(p);
            connect(p, SIGNAL(StartSpeaking()), SLOT(OnUserStartSpeaking()) );
            connect(p, SIGNAL(StopSpeaking()), SLOT(OnUserStopSpeaking()) );
            connect(p, SIGNAL(Left()), SLOT(UpdateParticipantList()) );

            emit ParticipantJoined((Communications::InWorldVoice::ParticipantInterface*)p);
        }

        void Session::UpdateParticipantList()
        {
            foreach(Participant* p, participants_)
            {
                if (p->UserPtr()->IsLeft())
                {
                    participants_.removeOne(p);
                    left_participants_.push_back(p);
                    emit ParticipantLeft(p);
                }
            }
        }

        void Session::OnUserStartSpeaking()
        {
            bool was_receiving_audio = receiving_audio_;
            receiving_audio_ = true;
            if (!was_receiving_audio)
                emit StartReceivingAudio();
        }

        void Session::OnUserStopSpeaking()
        {
            bool was_receiving_audio = receiving_audio_;
            foreach(Participant* p, participants_)
            {
                if (p->IsSpeaking())
                {
                    receiving_audio_ = true;
                    return;
                }
            }
            receiving_audio_ = false;
            if (was_receiving_audio)
                emit StopReceivingAudio();
        }

        void Session::UpdateSpeakerActivity(PCMAudioFrame* frame)
        {
            static int counter;
            counter++;
            counter = counter % 10;
            if (counter != 0)
                return;

            short top = 0;
            const short max = 100; //! \todo Use more proper treshold value
            for(int i = 0; i < frame->SampleCount(); ++i)
            {
                int sample = abs(frame->SampleAt(i));
                if (sample > top)
                    top = sample;
            }

            double activity = top / max;
            if (activity > 1.0)
                activity = 1.0;

            double old_activity = speaker_voice_activity_;
            speaker_voice_activity_ = activity;
            if (old_activity != activity)
                emit Communications::InWorldVoice::SessionInterface::SpeakerVoiceActivityChanged(activity);
        }

        bool Session::GetOwnAvatarPosition(Vector3df& position, Vector3df& direction)
        {
            using namespace Foundation;
            boost::shared_ptr<WorldLogicInterface> world_logic = framework_->GetServiceManager()->GetService<WorldLogicInterface>(Service::ST_WorldLogic).lock();
            if (!world_logic)
                return false;

            Scene::EntityPtr user_avatar = world_logic->GetUserAvatarEntity();
            if (!user_avatar)
                return false;

            boost::shared_ptr<OgreRenderer::EC_OgrePlaceable> ogre_placeable = user_avatar->GetComponent<OgreRenderer::EC_OgrePlaceable>();
            if (!ogre_placeable)
                return false;

            Quaternion q = ogre_placeable->GetOrientation();
            position = ogre_placeable->GetPosition();
            direction = q*Vector3df::UNIT_Z;

            return true;
        }

        QString Session::OwnAvatarId()
        {
            using namespace Foundation;
            boost::shared_ptr<WorldLogicInterface> world_logic = framework_->GetServiceManager()->GetService<WorldLogicInterface>(Service::ST_WorldLogic).lock();
            if (!world_logic)
                return "";

            Scene::EntityPtr user_avatar = world_logic->GetUserAvatarEntity();
            if (!user_avatar)
                return "";

            boost::shared_ptr<EC_OpenSimPresence> opensim_presence = user_avatar->GetComponent<EC_OpenSimPresence>();
            if (!opensim_presence)
                return "";

            return opensim_presence->agentId.ToQString();
        }

        QString Session::GetAvatarFullName(QString uuid) const
        {
            Scene::ScenePtr current_scene = framework_->GetDefaultWorldScene();
            if (current_scene.get())
            {
                for(Scene::SceneManager::iterator iter = current_scene->begin(); iter != current_scene->end(); ++iter)
                {
                    Scene::Entity &entity = **iter;
                    EC_OpenSimPresence *presence_component = entity.GetComponent<EC_OpenSimPresence>().get();
                    if (presence_component)
                        if (presence_component->agentId.ToQString() == uuid)
                            return QString(presence_component->GetFullName().c_str());
                }
            }
            return "";
        }

        void Session::SendRecordedAudio()
        {
            if (!audio_sending_enabled_)
                return;

            Vector3df avatar_position;
            Vector3df avatar_direction;

            boost::shared_ptr<Foundation::SoundServiceInterface> sound_service = SoundService();
            if (!sound_service)
            {
                MumbleVoipModule::LogDebug("Cannot record audio: Soundservice cannot be found.");
                return;
            }

            while (sound_service->GetRecordedSoundSize() > SAMPLES_IN_FRAME*SAMPLE_WIDTH/8)
            {
                int bytes_to_read = SAMPLES_IN_FRAME*SAMPLE_WIDTH/8;
                PCMAudioFrame* frame = new PCMAudioFrame(SAMPLE_RATE, SAMPLE_WIDTH, NUMBER_OF_CHANNELS, bytes_to_read );
                int bytes = sound_service->GetRecordedSoundData(frame->DataPtr(), bytes_to_read);
                assert(bytes_to_read == bytes);

                //if (voice_indicator_)
                //{
                //    voice_indicator_->AnalyzeAudioFrame(frame);
                //    if (!voice_indicator_->IsSpeaking())
                //    {
                //        delete frame;
                //        continue;
                //    }
                //}
                connection_->SendAudioFrame(frame, avatar_position);
//                emit AudioFrameSent(frame);
                delete frame;
            }
        }

        void Session::PlaybackReceivedAudio()
        {
            for(;;)
            {
                AudioPacket packet = connection_->GetAudioPacket();
                if (packet.second == 0)
                    break; // nothing to play anymore
                PlaybackAudioFrame(packet.first, packet.second);
            }
        }

        void Session::PlaybackAudioFrame(User* user, PCMAudioFrame* frame)
        {
            boost::shared_ptr<Foundation::SoundServiceInterface> sound_service = SoundService();
            if (!sound_service.get())
                return;

            Foundation::SoundServiceInterface::SoundBuffer sound_buffer;

            sound_buffer.data_.resize(frame->DataSize());
            memcpy(&sound_buffer.data_[0], frame->DataPtr(), frame->DataSize());

            sound_buffer.frequency_ = frame->SampleRate();
            if (frame->SampleWidth() == 16)
                sound_buffer.sixteenbit_ = true;
            else
                sound_buffer.sixteenbit_ = false;

            if (frame->Channels() == 2)
                sound_buffer.stereo_ = true;
            else
                sound_buffer.stereo_ = false;

            QMutexLocker user_locker(user);
            if (audio_playback_channels_.contains(user->Session()))
                if (user->PositionKnown())
                    sound_service->PlaySoundBuffer3D(sound_buffer, Foundation::SoundServiceInterface::Voice, user->Position(), audio_playback_channels_[user->Session()]);
                else
                    sound_service->PlaySoundBuffer(sound_buffer,  Foundation::SoundServiceInterface::Voice, audio_playback_channels_[user->Session()]);
            else
                if (user->PositionKnown())
                    audio_playback_channels_[user->Session()] = sound_service->PlaySoundBuffer3D(sound_buffer, Foundation::SoundServiceInterface::Voice, user->Position(), 0);
                else
                    audio_playback_channels_[user->Session()] = sound_service->PlaySoundBuffer(sound_buffer,  Foundation::SoundServiceInterface::Voice, 0);

            delete frame;
        }

        boost::shared_ptr<Foundation::SoundServiceInterface> Session::SoundService()
        {
            if (!framework_)
                return boost::shared_ptr<Foundation::SoundServiceInterface>();

            Foundation::ServiceManagerPtr service_manager = framework_->GetServiceManager();

            if (!service_manager.get())
                return boost::shared_ptr<Foundation::SoundServiceInterface>();

            boost::shared_ptr<Foundation::SoundServiceInterface> sound_service = service_manager->GetService<Foundation::SoundServiceInterface>(Foundation::Service::ST_Sound).lock();

            if (!sound_service.get())
                return boost::shared_ptr<Foundation::SoundServiceInterface>();

            return sound_service;
        }

    } // InWorldVoice

} // MumbleVoip
<commit_msg>Fix session close error.<commit_after>#include "StableHeaders.h"
#include "Session.h"
//#include "MemoryLeakCheck.h"
#include "ServerInfo.h"
#include "PCMAudioFrame.h"
#include "Vector3D.h"
#include "EC_OgrePlaceable.h" // for avatar position
#include "EC_OpenSimPresence.h" // for avatar position
#include "ModuleManager.h"    // for avatar info
#include "WorldLogicInterface.h" // for avatar position
#include "Entity.h" // for avatar position
#include "SceneManager.h"
#include "WorldStream.h"
#include "User.h"
#include "Channel.h"
#include "Connection.h"
#include "Participant.h"
#include "MumbleLibrary.h"
#include "MumbleVoipModule.h"

//#define BUILDING_DLL // for dll import/export declarations
//#define CreateEvent  CreateEventW // for \boost\asio\detail\win_event.hpp and \boost\asio\detail\win_iocp_handle_service.hpp
////#include <mumbleclient/client_lib.h>
//#undef BUILDING_DLL // for dll import/export declarations
////#include "LibMumbleThread.h"

namespace MumbleVoip
{
    namespace InWorldVoice
    {
        Session::Session(Foundation::Framework* framework, const ServerInfo &server_info) :
            state_(STATE_INITIALIZING),
            reason_(""),
            framework_(framework),
            description_(""),
            sending_audio_(false),
            receiving_audio_(false),
            audio_sending_enabled_(false),
            audio_receiving_enabled_(false),
            speaker_voice_activity_(0),
//            connection_manager_(new ConnectionManager(framework)),
            server_info_(server_info),
            connection_(0)
        {
            channel_name_ = server_info.channel;
            OpenConnection(server_info);

            //connection_manager_->OpenConnection(server_info);
            //if (connection_manager_->GetState() != ConnectionManager::STATE_CONNECTION_OPEN)
            //{
            //    state_ = STATE_ERROR;
            //    reason_ = connection_manager_->GetReason();
            //    return;
            //}
        }

        Session::~Session()
        {
            foreach(Participant* p, participants_)
            {
                SAFE_DELETE(p);
            }
            participants_.clear();
            foreach(Participant* p, left_participants_)
            {
                SAFE_DELETE(p);
            }
            left_participants_.clear();
            if (connection_)
                SAFE_DELETE(connection_);
        }

        void Session::OpenConnection(ServerInfo server_info)
        {
            connection_ = new Connection(server_info);
            if (connection_->GetState() == Connection::STATE_ERROR)
            {
                state_ = STATE_ERROR;
                reason_ = connection_->GetReason();
                return;
            }
            state_ = STATE_OPEN;

            connect(connection_, SIGNAL(UserJoined(User*)), SLOT(CreateNewParticipant(User*)) );
            connect(connection_, SIGNAL(UserLeft(User*)), SLOT(UpdateUserList()) );
//            connections_[info.server] = connection;
            connection_->Join(server_info.channel);
            connection_->SendAudio(sending_audio_);
            connection_->SetEncodingQuality(0.5);
            connection_->SendPosition(true);
            MumbleLibrary::Start();
            MumbleLibrary::Stop();
            //connect(MumbleLibrary::Instance(), SIGNAL(InteralError()), SLOT(HandleMumbleLibraryError()) );
//            connect(connection_manager_, SIGNAL(AudioFrameSent(PCMAudioFrame*)), SLOT(UpdateSpeakerActivity(PCMAudioFrame*)) );
        }

        void Session::Close()
        {
            connection_->Close();
            SAFE_DELETE(connection_);
            state_ = STATE_CLOSED;
            emit StateChanged(state_);
        }

        Communications::InWorldVoice::SessionInterface::State Session::GetState() const
        {
            return state_;
        }

        QString Session::Reason() const
        {
            return reason_;
        }

        QString Session::Description() const
        {
            return description_;
        }

        bool Session::IsSendingAudio() const
        {
            return sending_audio_;
        }

        bool Session::IsReceivingAudio() const
        {
            return receiving_audio_;
        }

        void Session::EnableAudioSending()
        {
            if (connection_)
                connection_->SendAudio(true);
            bool audio_sending_was_enabled = audio_sending_enabled_;
            audio_sending_enabled_ = true;
            if (!audio_sending_was_enabled)
            {
                boost::shared_ptr<Foundation::SoundServiceInterface> sound_service = SoundService();
                if (sound_service.get())
                {
                    int frequency = SAMPLE_RATE;
                    bool sixteenbit = true;
                    bool stereo = false;
                    int buffer_size = SAMPLE_WIDTH/8*frequency*AUDIO_RECORDING_BUFFER_MS/1000;
                    sound_service->StartRecording(recording_device_, frequency, sixteenbit, stereo, buffer_size);
                }

                emit StartSendingAudio();
            }
        }

        void Session::DisableAudioSending()
        {
            if (connection_)
                connection_->SendAudio(false);
            bool audio_sending_was_enabled = audio_sending_enabled_;
            audio_sending_enabled_ = false;
            if (audio_sending_was_enabled)
            {
                boost::shared_ptr<Foundation::SoundServiceInterface> sound_service = SoundService();
                if (sound_service.get())
                    sound_service->StopRecording();

                emit StopSendingAudio();
            }
        }

        bool Session::IsAudioSendingEnabled() const
        {
            return audio_sending_enabled_;
        }

        void Session::EnableAudioReceiving()
        {
            if (connection_)
                connection_->ReceiveAudio(true);
            audio_receiving_enabled_ = true;
        }

        void Session::DisableAudioReceiving()
        {
            if (connection_)
                connection_->ReceiveAudio(false);
            audio_receiving_enabled_ = false;
        }

        bool Session::IsAudioReceivingEnabled() const
        {
            return audio_receiving_enabled_;
        }

        double Session::SpeakerVoiceActivity() const
        {
            return speaker_voice_activity_;
        }

        QList<Communications::InWorldVoice::ParticipantInterface*> Session::Participants() const
        {
            QList<Communications::InWorldVoice::ParticipantInterface*> list;
            for(ParticipantList::const_iterator i = participants_.begin(); i != participants_.end(); ++i)
            {
                Participant* p = *i;
                list.append(static_cast<Communications::InWorldVoice::ParticipantInterface*>(p));
            }
            return list;
        }

        void Session::Update(f64 frametime)
        {
//                connection_manager_->Update(frametime);
            PlaybackReceivedAudio();
            SendRecordedAudio();
        }

        void Session::CreateNewParticipant(User* user)
        {
            if (user->Name() == OwnAvatarId())
            {
                self_user_ = user;
                return;
            }

            if (user->Channel()->FullName() != channel_name_)
                return;

            QString uuid = user->Name();
            QString name = GetAvatarFullName(uuid);
            if (name.size() == 0)
                name = QString("(Unknow) %0").arg(user->Name());
            Participant* p = new Participant(name, user);
            participants_.append(p);
            connect(p, SIGNAL(StartSpeaking()), SLOT(OnUserStartSpeaking()) );
            connect(p, SIGNAL(StopSpeaking()), SLOT(OnUserStopSpeaking()) );
            connect(p, SIGNAL(Left()), SLOT(UpdateParticipantList()) );

            emit ParticipantJoined((Communications::InWorldVoice::ParticipantInterface*)p);
        }

        void Session::UpdateParticipantList()
        {
            foreach(Participant* p, participants_)
            {
                if (p->UserPtr()->IsLeft())
                {
                    participants_.removeOne(p);
                    left_participants_.push_back(p);
                    emit ParticipantLeft(p);
                }
            }
        }

        void Session::OnUserStartSpeaking()
        {
            bool was_receiving_audio = receiving_audio_;
            receiving_audio_ = true;
            if (!was_receiving_audio)
                emit StartReceivingAudio();
        }

        void Session::OnUserStopSpeaking()
        {
            bool was_receiving_audio = receiving_audio_;
            foreach(Participant* p, participants_)
            {
                if (p->IsSpeaking())
                {
                    receiving_audio_ = true;
                    return;
                }
            }
            receiving_audio_ = false;
            if (was_receiving_audio)
                emit StopReceivingAudio();
        }

        void Session::UpdateSpeakerActivity(PCMAudioFrame* frame)
        {
            static int counter;
            counter++;
            counter = counter % 10;
            if (counter != 0)
                return;

            short top = 0;
            const short max = 100; //! \todo Use more proper treshold value
            for(int i = 0; i < frame->SampleCount(); ++i)
            {
                int sample = abs(frame->SampleAt(i));
                if (sample > top)
                    top = sample;
            }

            double activity = top / max;
            if (activity > 1.0)
                activity = 1.0;

            double old_activity = speaker_voice_activity_;
            speaker_voice_activity_ = activity;
            if (old_activity != activity)
                emit Communications::InWorldVoice::SessionInterface::SpeakerVoiceActivityChanged(activity);
        }

        bool Session::GetOwnAvatarPosition(Vector3df& position, Vector3df& direction)
        {
            using namespace Foundation;
            boost::shared_ptr<WorldLogicInterface> world_logic = framework_->GetServiceManager()->GetService<WorldLogicInterface>(Service::ST_WorldLogic).lock();
            if (!world_logic)
                return false;

            Scene::EntityPtr user_avatar = world_logic->GetUserAvatarEntity();
            if (!user_avatar)
                return false;

            boost::shared_ptr<OgreRenderer::EC_OgrePlaceable> ogre_placeable = user_avatar->GetComponent<OgreRenderer::EC_OgrePlaceable>();
            if (!ogre_placeable)
                return false;

            Quaternion q = ogre_placeable->GetOrientation();
            position = ogre_placeable->GetPosition();
            direction = q*Vector3df::UNIT_Z;

            return true;
        }

        QString Session::OwnAvatarId()
        {
            using namespace Foundation;
            boost::shared_ptr<WorldLogicInterface> world_logic = framework_->GetServiceManager()->GetService<WorldLogicInterface>(Service::ST_WorldLogic).lock();
            if (!world_logic)
                return "";

            Scene::EntityPtr user_avatar = world_logic->GetUserAvatarEntity();
            if (!user_avatar)
                return "";

            boost::shared_ptr<EC_OpenSimPresence> opensim_presence = user_avatar->GetComponent<EC_OpenSimPresence>();
            if (!opensim_presence)
                return "";

            return opensim_presence->agentId.ToQString();
        }

        QString Session::GetAvatarFullName(QString uuid) const
        {
            Scene::ScenePtr current_scene = framework_->GetDefaultWorldScene();
            if (current_scene.get())
            {
                for(Scene::SceneManager::iterator iter = current_scene->begin(); iter != current_scene->end(); ++iter)
                {
                    Scene::Entity &entity = **iter;
                    EC_OpenSimPresence *presence_component = entity.GetComponent<EC_OpenSimPresence>().get();
                    if (presence_component)
                        if (presence_component->agentId.ToQString() == uuid)
                            return QString(presence_component->GetFullName().c_str());
                }
            }
            return "";
        }

        void Session::SendRecordedAudio()
        {
			if (!connection_)
				return;

            if (!audio_sending_enabled_)
                return;

            Vector3df avatar_position;
            Vector3df avatar_direction;

            boost::shared_ptr<Foundation::SoundServiceInterface> sound_service = SoundService();
            if (!sound_service)
            {
                MumbleVoipModule::LogDebug("Cannot record audio: Soundservice cannot be found.");
                return;
            }

            while (sound_service->GetRecordedSoundSize() > SAMPLES_IN_FRAME*SAMPLE_WIDTH/8)
            {
                int bytes_to_read = SAMPLES_IN_FRAME*SAMPLE_WIDTH/8;
                PCMAudioFrame* frame = new PCMAudioFrame(SAMPLE_RATE, SAMPLE_WIDTH, NUMBER_OF_CHANNELS, bytes_to_read );
                int bytes = sound_service->GetRecordedSoundData(frame->DataPtr(), bytes_to_read);
                assert(bytes_to_read == bytes);

                //if (voice_indicator_)
                //{
                //    voice_indicator_->AnalyzeAudioFrame(frame);
                //    if (!voice_indicator_->IsSpeaking())
                //    {
                //        delete frame;
                //        continue;
                //    }
                //}
                connection_->SendAudioFrame(frame, avatar_position);
//                emit AudioFrameSent(frame);
                delete frame;
            }
        }

        void Session::PlaybackReceivedAudio()
        {
			if (!connection_)
				return;

			if (!audio_sending_enabled_)
				return;

            for(;;)
            {
                AudioPacket packet = connection_->GetAudioPacket();
                if (packet.second == 0)
                    break; // nothing to play anymore
                PlaybackAudioFrame(packet.first, packet.second);
            }
        }

        void Session::PlaybackAudioFrame(User* user, PCMAudioFrame* frame)
        {
            boost::shared_ptr<Foundation::SoundServiceInterface> sound_service = SoundService();
            if (!sound_service.get())
                return;

            Foundation::SoundServiceInterface::SoundBuffer sound_buffer;

            sound_buffer.data_.resize(frame->DataSize());
            memcpy(&sound_buffer.data_[0], frame->DataPtr(), frame->DataSize());

            sound_buffer.frequency_ = frame->SampleRate();
            if (frame->SampleWidth() == 16)
                sound_buffer.sixteenbit_ = true;
            else
                sound_buffer.sixteenbit_ = false;

            if (frame->Channels() == 2)
                sound_buffer.stereo_ = true;
            else
                sound_buffer.stereo_ = false;

            QMutexLocker user_locker(user);
            if (audio_playback_channels_.contains(user->Session()))
                if (user->PositionKnown())
                    sound_service->PlaySoundBuffer3D(sound_buffer, Foundation::SoundServiceInterface::Voice, user->Position(), audio_playback_channels_[user->Session()]);
                else
                    sound_service->PlaySoundBuffer(sound_buffer,  Foundation::SoundServiceInterface::Voice, audio_playback_channels_[user->Session()]);
            else
                if (user->PositionKnown())
                    audio_playback_channels_[user->Session()] = sound_service->PlaySoundBuffer3D(sound_buffer, Foundation::SoundServiceInterface::Voice, user->Position(), 0);
                else
                    audio_playback_channels_[user->Session()] = sound_service->PlaySoundBuffer(sound_buffer,  Foundation::SoundServiceInterface::Voice, 0);

            delete frame;
        }

        boost::shared_ptr<Foundation::SoundServiceInterface> Session::SoundService()
        {
            if (!framework_)
                return boost::shared_ptr<Foundation::SoundServiceInterface>();

            Foundation::ServiceManagerPtr service_manager = framework_->GetServiceManager();

            if (!service_manager.get())
                return boost::shared_ptr<Foundation::SoundServiceInterface>();

            boost::shared_ptr<Foundation::SoundServiceInterface> sound_service = service_manager->GetService<Foundation::SoundServiceInterface>(Foundation::Service::ST_Sound).lock();

            if (!sound_service.get())
                return boost::shared_ptr<Foundation::SoundServiceInterface>();

            return sound_service;
        }

    } // InWorldVoice

} // MumbleVoip
<|endoftext|>


<commit_before>
#pragma once

namespace principia {
namespace base {

extern char const BuildDate[];
extern char const Version[];

}  // namespace base
}  // namespace principia
<commit_msg>Emit a message with the compiler version at compile time; this will help maintaining the Windows pipeline.<commit_after>
#pragma once

#include "base/macros.hpp"

namespace principia {
namespace base {

extern char const BuildDate[];
extern char const Version[];

#pragma message("Compiler version: " STRINGIFY_EXPANSION(_MSC_FULL_VER))

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


<commit_before>#include <assert.h>
#include <string>
#include "commutativeRExp.h"

// this creates the empty set
CommutativeRExp::CommutativeRExp()
{
	this->type = Empty;
}

CommutativeRExp::CommutativeRExp(VarPtr var)
{
	this->type = Element;
	this->elem = Var::getVar(var);
	this->str = generateString();
}

CommutativeRExp::CommutativeRExp(enum optype type, std::set<CommutativeRExp>* seta)
{
	this->type = type;
	if(this->type == Addition)
		this->seta = seta;
	else
		assert(false); // should not be called with this constructor...
	this->str = generateString();
}

CommutativeRExp::CommutativeRExp(enum optype type, std::multiset<CommutativeRExp>* setm)
{
	this->type = type;
	if(this->type == Multiplication)
		this->setm = setm;
	else
		assert(false); // should not be called with this constructor...
	this->str = generateString();
}

CommutativeRExp::CommutativeRExp(enum optype type, const CommutativeRExp& rexp)
{
	this->type = type;
	if(this->type == Star)
		this->rexp = new CommutativeRExp(rexp);
	else
		assert(false); // should not be called with this constructor...
	this->str = generateString();
}

CommutativeRExp::CommutativeRExp(const CommutativeRExp& expr)
{
	this->type = expr.type;
	if(this->type == Element)
		this->elem = expr.elem;
	else if(this->type == Addition)
		this->seta = expr.seta;
	else if(this->type == Multiplication)
		this->setm = expr.setm;
	else if(this->type == Star)
		this->rexp = expr.rexp;
	else if(this->type == Empty)
		;// Do nothing
	else
		assert(false);
	this->str = generateString();
}

CommutativeRExp::~CommutativeRExp()
{
	// do not delete static pointers!!!
/*	if(elem_null != 0)
	{
		delete elem_null;
		elem_null = 0;
	}
	if(elem_one != 0)
	{
		delete elem_one;
		elem_one = 0;
	}
	if(this->type == Element)
	{
		delete elem;
	}
	if(this->type == Addition )
	{
		delete seta;
	}
	if(this->type == Multiplication)
	{
		delete setm;
	}
	if(this->type == Star)
	{
		delete rexp;
	}
*/
}

// union operator
CommutativeRExp CommutativeRExp::operator +(const CommutativeRExp& expr) const
{
	std::set<CommutativeRExp>* retset= new std::set<CommutativeRExp>();

	if(this->type == Element || this->type == Multiplication || this->type == Star)
		retset->insert(*this);
	else if(this->type == Addition)
		retset->insert(this->seta->begin(), this->seta->end());
	else if(this->type == Empty)
		return expr; // {} + x = x
	else
		assert(false); // this should not happen

	if(expr.type == Element || expr.type == Multiplication || expr.type == Star)
		retset->insert(expr);
	else if(expr.type == Addition)
		retset->insert(expr.seta->begin(), expr.seta->end());
	else if(expr.type == Empty)
		return *this; // x + {} = x
	else
		assert(false); // this should not happen

	// degenerated case, both sets have been equal
	if(retset->size() == 1)
		return *this; // so we can just return one of the elements // TODO: check this! quick test shows this is right
	return CommutativeRExp(Addition, retset);
}

// concatenate all expressions from first set with all expressions of the second set
CommutativeRExp CommutativeRExp::operator *(const CommutativeRExp& expr) const
{
	std::multiset<CommutativeRExp>* retset= new std::multiset<CommutativeRExp>();

	if(this->type == Element || this->type == Addition || this->type == Star)
	{
		if(this->type == Element && *this == one())
			return expr; // 1 * x = x
		retset->insert(*this);
	}
	else if(this->type == Multiplication)
		retset->insert(this->setm->begin(), this->setm->end());
	else if(this->type == Empty)
		return *this; // {} * x = {}
	else
		assert(false); // this should not happen

	if(expr.type == Element || expr.type == Addition || expr.type == Star)
	{
		if(expr.type == Element && expr == one())
			return *this; // x * 1 = x
		retset->insert(expr);
	}
	else if(expr.type == Multiplication)
		retset->insert(expr.setm->begin(), expr.setm->end());
	else if(expr.type == Empty)
		return expr; // x * {} = {}
	else
		assert(false); // this should not happen

	return CommutativeRExp(Multiplication, retset);
}

//bool operator <(const CommutativeRExp& lhs, const CommutativeRExp& rhs)
bool CommutativeRExp::operator <(const CommutativeRExp& rhs) const
{
	if(this->type < rhs.type)
		return true;
	else if(this->type > rhs.type)
		return false;
	else // same type
	{
		if(this->type == Element)
			return this->elem < rhs.elem;
		else
			return this->str.compare(rhs.str) < 0;
	}
}

bool CommutativeRExp::operator ==(const CommutativeRExp& expr) const
{
	return this->str.compare(expr.str) == 0;
}

// star the whole RExp
CommutativeRExp CommutativeRExp::star() const
{
	if(this->type == Star)
		return *this; // absorb the star
	else if (this->type == Empty)
		return one(); // {}* = ε
	else
		return CommutativeRExp(Star, *this); // star the element
}

CommutativeRExp CommutativeRExp::null()
{
	if(!CommutativeRExp::elem_null)
		CommutativeRExp::elem_null = new CommutativeRExp();
	return *CommutativeRExp::elem_null;
}

CommutativeRExp CommutativeRExp::one()
{
	if(!CommutativeRExp::elem_one)
		CommutativeRExp::elem_one = new CommutativeRExp(Var::getVar("ε"));
	return *CommutativeRExp::elem_one;
}

std::ostream& operator<<(std::ostream& os, const std::set<CommutativeRExp>& set)
{
	for(std::set<CommutativeRExp>::const_iterator s = set.begin(); s != set.end(); ++s)
	{
		if(s != set.begin())
			os << "+";
		os << *s;
	}
	return os;
}
std::ostream& operator<<(std::ostream& os, const std::multiset<CommutativeRExp>& set)
{
	for(std::multiset<CommutativeRExp>::const_iterator s = set.begin(); s != set.end(); ++s)
	{
		if(s != set.begin())
			os << ".";
		os << *s;
	}
	return os;
}

std::string CommutativeRExp::generateString() const
{
	std::stringstream ss;
	if(this->type == Element)
		ss << this->elem;
	else if(this->type == Addition)
		ss << "(" << *this->seta << ")";
	else if(this->type == Multiplication)
		ss << "(" << *this->setm << ")";
	else if(this->type == Star)
		ss << "(" << *this->rexp << ")*";
	return ss.str();
}

std::string CommutativeRExp::string() const
{
	return this->str;
}

bool CommutativeRExp::is_idempotent = true;
bool CommutativeRExp::is_commutative = true;
CommutativeRExp* CommutativeRExp::elem_null = 0;
CommutativeRExp* CommutativeRExp::elem_one = 0;
<commit_msg>fixed strange output in CommutativeRExp ((a.e))* to (a.e)*<commit_after>#include <assert.h>
#include <string>
#include "commutativeRExp.h"

// this creates the empty set
CommutativeRExp::CommutativeRExp()
{
	this->type = Empty;
}

CommutativeRExp::CommutativeRExp(VarPtr var)
{
	this->type = Element;
	this->elem = Var::getVar(var);
	this->str = generateString();
}

CommutativeRExp::CommutativeRExp(enum optype type, std::set<CommutativeRExp>* seta)
{
	this->type = type;
	if(this->type == Addition)
		this->seta = seta;
	else
		assert(false); // should not be called with this constructor...
	this->str = generateString();
}

CommutativeRExp::CommutativeRExp(enum optype type, std::multiset<CommutativeRExp>* setm)
{
	this->type = type;
	if(this->type == Multiplication)
		this->setm = setm;
	else
		assert(false); // should not be called with this constructor...
	this->str = generateString();
}

CommutativeRExp::CommutativeRExp(enum optype type, const CommutativeRExp& rexp)
{
	this->type = type;
	if(this->type == Star)
		this->rexp = new CommutativeRExp(rexp);
	else
		assert(false); // should not be called with this constructor...
	this->str = generateString();
}

CommutativeRExp::CommutativeRExp(const CommutativeRExp& expr)
{
	this->type = expr.type;
	if(this->type == Element)
		this->elem = expr.elem;
	else if(this->type == Addition)
		this->seta = expr.seta;
	else if(this->type == Multiplication)
		this->setm = expr.setm;
	else if(this->type == Star)
		this->rexp = expr.rexp;
	else if(this->type == Empty)
		;// Do nothing
	else
		assert(false);
	this->str = generateString();
}

CommutativeRExp::~CommutativeRExp()
{
	// do not delete static pointers!!!
/*	if(elem_null != 0)
	{
		delete elem_null;
		elem_null = 0;
	}
	if(elem_one != 0)
	{
		delete elem_one;
		elem_one = 0;
	}
	if(this->type == Element)
	{
		delete elem;
	}
	if(this->type == Addition )
	{
		delete seta;
	}
	if(this->type == Multiplication)
	{
		delete setm;
	}
	if(this->type == Star)
	{
		delete rexp;
	}
*/
}

// union operator
CommutativeRExp CommutativeRExp::operator +(const CommutativeRExp& expr) const
{
	std::set<CommutativeRExp>* retset= new std::set<CommutativeRExp>();

	if(this->type == Element || this->type == Multiplication || this->type == Star)
		retset->insert(*this);
	else if(this->type == Addition)
		retset->insert(this->seta->begin(), this->seta->end());
	else if(this->type == Empty)
		return expr; // {} + x = x
	else
		assert(false); // this should not happen

	if(expr.type == Element || expr.type == Multiplication || expr.type == Star)
		retset->insert(expr);
	else if(expr.type == Addition)
		retset->insert(expr.seta->begin(), expr.seta->end());
	else if(expr.type == Empty)
		return *this; // x + {} = x
	else
		assert(false); // this should not happen

	// degenerated case, both sets have been equal
	if(retset->size() == 1)
		return *this; // so we can just return one of the elements // TODO: check this! quick test shows this is right
	return CommutativeRExp(Addition, retset);
}

// concatenate all expressions from first set with all expressions of the second set
CommutativeRExp CommutativeRExp::operator *(const CommutativeRExp& expr) const
{
	std::multiset<CommutativeRExp>* retset= new std::multiset<CommutativeRExp>();

	if(this->type == Element || this->type == Addition || this->type == Star)
	{
		if(this->type == Element && *this == one())
			return expr; // 1 * x = x
		retset->insert(*this);
	}
	else if(this->type == Multiplication)
		retset->insert(this->setm->begin(), this->setm->end());
	else if(this->type == Empty)
		return *this; // {} * x = {}
	else
		assert(false); // this should not happen

	if(expr.type == Element || expr.type == Addition || expr.type == Star)
	{
		if(expr.type == Element && expr == one())
			return *this; // x * 1 = x
		retset->insert(expr);
	}
	else if(expr.type == Multiplication)
		retset->insert(expr.setm->begin(), expr.setm->end());
	else if(expr.type == Empty)
		return expr; // x * {} = {}
	else
		assert(false); // this should not happen

	return CommutativeRExp(Multiplication, retset);
}

//bool operator <(const CommutativeRExp& lhs, const CommutativeRExp& rhs)
bool CommutativeRExp::operator <(const CommutativeRExp& rhs) const
{
	if(this->type < rhs.type)
		return true;
	else if(this->type > rhs.type)
		return false;
	else // same type
	{
		if(this->type == Element)
			return this->elem < rhs.elem;
		else
			return this->str.compare(rhs.str) < 0;
	}
}

bool CommutativeRExp::operator ==(const CommutativeRExp& expr) const
{
	return this->str.compare(expr.str) == 0;
}

// star the whole RExp
CommutativeRExp CommutativeRExp::star() const
{
	if(this->type == Star)
		return *this; // absorb the star
	else if (this->type == Empty)
		return one(); // {}* = ε
	else
		return CommutativeRExp(Star, *this); // star the element
}

CommutativeRExp CommutativeRExp::null()
{
	if(!CommutativeRExp::elem_null)
		CommutativeRExp::elem_null = new CommutativeRExp();
	return *CommutativeRExp::elem_null;
}

CommutativeRExp CommutativeRExp::one()
{
	if(!CommutativeRExp::elem_one)
		CommutativeRExp::elem_one = new CommutativeRExp(Var::getVar("ε"));
	return *CommutativeRExp::elem_one;
}

std::ostream& operator<<(std::ostream& os, const std::set<CommutativeRExp>& set)
{
	for(std::set<CommutativeRExp>::const_iterator s = set.begin(); s != set.end(); ++s)
	{
		if(s != set.begin())
			os << "+";
		os << *s;
	}
	return os;
}
std::ostream& operator<<(std::ostream& os, const std::multiset<CommutativeRExp>& set)
{
	for(std::multiset<CommutativeRExp>::const_iterator s = set.begin(); s != set.end(); ++s)
	{
		if(s != set.begin())
			os << ".";
		os << *s;
	}
	return os;
}

std::string CommutativeRExp::generateString() const
{
	std::stringstream ss;
	if(this->type == Element)
		ss << this->elem;
	else if(this->type == Addition)
		ss << "(" << *this->seta << ")";
	else if(this->type == Multiplication)
		ss << "(" << *this->setm << ")";
	else if(this->type == Star)
		ss << *this->rexp << "*";
	return ss.str();
}

std::string CommutativeRExp::string() const
{
	return this->str;
}

bool CommutativeRExp::is_idempotent = true;
bool CommutativeRExp::is_commutative = true;
CommutativeRExp* CommutativeRExp::elem_null = 0;
CommutativeRExp* CommutativeRExp::elem_one = 0;
<|endoftext|>


<commit_before>#ifndef utils_utils_hpp
#define utils_utils_hpp

#include <vector>
#include <opencv2/opencv.hpp>
#include <fstream>
#include <string>
#include <regex>

#include <stdio.h>      /* printf, scanf, puts, NULL */
#include <stdlib.h>     /* srand, rand */
#include <time.h>       /* time */

#include "img_hash/AverageHash.h"
#include "img_hash/BlockMeanHash.h"
#include "img_hash/PerceptualHash.h"

//#include "img_hash/FragmentHash.h"
//#include "ShapeAndPositionInvariantImage.h"
#include "Triangle.h"
#include "mainImageProcessingFunctions.hpp"
#include <boost/program_options.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <iostream>
#include "utils/utils.hpp"
#include <tuple>

using boost::property_tree::ptree;
using boost::property_tree::read_json;
using boost::property_tree::write_json;

namespace pt = boost::property_tree;

void drawSingleTriangleOntoImage(Triangle tri, cv::Mat inputImage, bool randomColours = true){
    auto keypoints = tri.toKeypoints();
    auto prevPoint = keypoints.back();
//    for (auto currentPoint: keypoints)
//    {
    for (int i = 0; i < 3; i++){
        auto currentPoint = keypoints[i];
        int r = (i==0);
        int g = (i==1);
        int b = (i==2);

        cv::line(inputImage, cv::Point(currentPoint.x, currentPoint.y), cv::Point(prevPoint.x, prevPoint.y),
                 cv::Scalar(255*b,255*g,255*r));
        cv::imshow("something", inputImage);
        cv::waitKey(0);
        prevPoint = currentPoint;
    }
}

void drawTrianglesOntoImage(vector<Triangle> tris, cv::Mat inputImage, bool randomColours = true)
{
    for (auto tri: tris){
        drawSingleTriangleOntoImage(tri, inputImage, randomColours);
    }
}

Triangle getTriangleFromRedisEntry(string redisEntry)
{
    pt::ptree root;
    std::stringstream ss;
    ss << redisEntry;
    pt::read_json(ss, root);

    vector<Keypoint> keypoints;
    for (auto pt_j: root.get_child("triangle"))
    {
        double x = pt_j.second.get<double>("x");
        double y = pt_j.second.get<double>("y");
        keypoints.push_back(Keypoint(x,y));
    }
    return Triangle(keypoints);
}

string getImageNameFromRedisEntry(string redisEntry)
{
    pt::ptree root;
    std::stringstream ss;
    ss << redisEntry;
    pt::read_json(ss, root);
    return root.get<string>("imageName");
}

string convertToRedisEntryJson(string imageName, Triangle tri){
    pt::ptree root;
    root.put("imageName", imageName);

    //add each point of the triangle
    pt::ptree points;
    for (auto pt : tri.toKeypoints())
    {
        pt::ptree point;
        point.put("x", pt.x);
        point.put("y", pt.y);
        points.push_back(std::make_pair("", point));
    }
    root.add_child("triangle", points);

    std::ostringstream buf;
    write_json(buf, root, false);
    return buf.str();
}

const std::vector<Triangle> readTheTriangles(std::ifstream *file) {
    std::vector<Triangle> triangles;
    std::string str;

    while (true) {
        if (!std::getline(*file, str)) {
            break;
        }

        double x1 = atof(str.c_str());
        std::getline(*file, str);
        double y1 = atof(str.c_str());
        Keypoint k1(x1, y1);

        std::getline(*file, str);
        double x2 = atof(str.c_str());
        std::getline(*file, str);
        double y2 = atof(str.c_str());
        Keypoint k2(x2, y2);

        std::getline(*file, str);
        double x3 = atof(str.c_str());
        std::getline(*file, str);
        double y3 = atof(str.c_str());
        Keypoint k3(x3, y3);

        Triangle t(k1, k2, k3);
        triangles.push_back(t);
    }
    return triangles;
}

vector<Keypoint> readKeypointsFromJsonFile(std::ifstream *file)
{
    vector<Keypoint> result;
    try {
        boost::property_tree::ptree pt;
        boost::property_tree::read_json(*file, pt);

        for (auto label0 : pt) {
            if (label0.first == "output") {
                for (auto label1: label0.second) {
                    if (label1.first == "keypoints") {
                        for (auto kp : label1.second){
                            double x, y;
                            for (auto pt : kp.second){
                                if(pt.first == "x"){
                                    x = pt.second.get_value<double>();
                                }else{
                                    y = pt.second.get_value<double>();
                                }
                            }
                            result.push_back(Keypoint(x, y));
                        }
                    }
                }
            }
        }
    } catch (std::exception const &e) {
        std::cerr << e.what() << std::endl;
    }
    return result;
}

vector<Keypoint> readKeypointsFromJsonFile(string filename)
{
    std::ifstream file(filename);
    return readKeypointsFromJsonFile(&file);
}

void print(boost::property_tree::ptree const &pt) {
}

double getKeypointDistance(Keypoint one, Keypoint two)
{
	return sqrt( pow( one.x-two.x, 2.0 ) + pow( one.y-two.y, 2.0 ) );
}

vector<Keypoint> findKeypointsWithInRangeFromTwoPoints(Keypoint one, Keypoint two, vector<Keypoint> otherKeypoints, double lowerThreshold, double upperThreshold)
{
	vector<Keypoint> result;
	for (auto cmpKp : otherKeypoints)
	{
        double distanceFromPointOne = getKeypointDistance(one, cmpKp);
        double distanceFromPointTwo = getKeypointDistance(two, cmpKp);
		if(distanceFromPointOne > lowerThreshold && distanceFromPointOne < upperThreshold
                && distanceFromPointTwo > lowerThreshold && distanceFromPointTwo < upperThreshold)
		{
			result.push_back(cmpKp);
		}
	}
	return result;
}

bool isInKeypointExcludeList(Keypoint keypoint, vector<Keypoint> excludeList) {
    for (auto kp : excludeList)
    {
        if(kp.x == keypoint.x && kp.y == keypoint.y){
            return true;
        }
    }
    return false;
}

bool shouldPointBeExcluded(Keypoint pt, vector<Keypoint> previouslyProcessedPoints, vector<Keypoint> currentProcessedPoints, Keypoint currentTopLevelPoint, Keypoint currentSecondLevelPoint)
{
    return isInKeypointExcludeList(pt, previouslyProcessedPoints)
           || isInKeypointExcludeList(pt, currentProcessedPoints)
           || currentTopLevelPoint == pt
           || currentSecondLevelPoint == pt
            ;
}

//NOTE: otherKeypoints may contain centerKeypoint
vector<Triangle> buildTrianglesForSingleKeypoint(Keypoint centerKeypoint, vector<Keypoint> otherKeypoints, vector<Keypoint> previouslyProcessedPoints, double lowerThreshold, double upperThreshold)
{
	vector<Triangle> result;
    vector<Keypoint> currentProcessedPoints;//a collection of points we have processed since entering this function
	for (auto iterKeypoint: otherKeypoints)
	{
        if(isInKeypointExcludeList(iterKeypoint, previouslyProcessedPoints) || iterKeypoint == centerKeypoint) {
            continue;
        }

        double distance = getKeypointDistance(iterKeypoint, centerKeypoint);
		if(distance > lowerThreshold && distance < upperThreshold)
		{
			vector<Keypoint> finalKeypoints = findKeypointsWithInRangeFromTwoPoints(iterKeypoint, centerKeypoint, otherKeypoints, lowerThreshold, upperThreshold);
			for (auto finKp : finalKeypoints)
			{
                //check if this combination of points will make a triangle we have already created
                if(shouldPointBeExcluded(finKp, previouslyProcessedPoints, currentProcessedPoints, centerKeypoint, iterKeypoint)){
                    continue;
                }
				result.push_back(Triangle(centerKeypoint, iterKeypoint, finKp));
			}
		}
        currentProcessedPoints.push_back(iterKeypoint);
	}
	return result;
}

vector<Triangle> buildTrianglesFromKeypoints(vector<Keypoint> keypoints, double lowerThreshold=150, double upperThreshold=300)
{
	vector<Triangle> outputTriangles;
//	for (auto keypoint: keypoints)
//	{
    //FIXME: this multi-threading needs to be improved
    #pragma omp parallel
    {
        vector<Triangle> vec_private;
        #pragma omp for nowait schedule(static)
        for (unsigned int i = 0; i < keypoints.size(); i++)
        {
            vector<Keypoint>::const_iterator first = keypoints.begin();
            vector<Keypoint>::const_iterator last = keypoints.begin() + i;
            vector<Keypoint> processedPoints(first, last);
            auto keypoint = keypoints[i];
            auto triangles = buildTrianglesForSingleKeypoint(keypoint, keypoints, processedPoints, lowerThreshold, upperThreshold);
            for (auto tri : triangles){
                vec_private.push_back(tri);
            }
            processedPoints.push_back(keypoint);
        }
        #pragma omp critical
        outputTriangles.insert(outputTriangles.end(), vec_private.begin(), vec_private.end());
    }
	return outputTriangles;
}

vector<Triangle> buildTrianglesFromKeypointJsonFile(string filename){
    vector<Keypoint> output = readKeypointsFromJsonFile(filename);
    vector<Triangle> ret = buildTrianglesFromKeypoints(output, 50, 400);
    return ret;
}

vector<Triangle> getTriangles(string filename){
    return buildTrianglesFromKeypointJsonFile(filename);
}

const pair<vector<Triangle>, vector<Triangle>> readMatchingTrianglesFromJsonFile(std::ifstream *file) {
    vector<Triangle> image1OutputTriangles;
    vector<Triangle> image2OutputTriangles;
    try {
        boost::property_tree::ptree pt;
        boost::property_tree::read_json(*file, pt);

        using boost::property_tree::ptree;
        for (auto it : pt) {
            if (it.first == "count") {
                //save count
                cout << "Number of triangles read: " << it.second.get_value<std::string>() << endl;
            }

            if (it.first == "triangles") {
                for (auto tri: it.second) {
                    vector<Keypoint> one, two;
                    for (auto tri_point : tri.second) {
                        vector<Keypoint> bothKp;
                        for (auto pt_u : tri_point.second) {
                            vector<double> tempPoint;
                            for (auto pt : pt_u.second) {
                                double coord = pt.second.get_value<double>();
                                tempPoint.push_back(coord);
                            }
                            Keypoint kp(tempPoint[0], tempPoint[1]);
                            bothKp.push_back(kp);
                        }
                        one.push_back(bothKp[0]);
                        two.push_back(bothKp[1]);
                    }
                    Triangle one_t(one);
                    Triangle two_t(two);
                    image1OutputTriangles.push_back(one_t);
                    image2OutputTriangles.push_back(two_t);
                }
            }
        }

        print(pt);
    }
    catch (std::exception const &e) {
        std::cerr << e.what() << std::endl;
    }

    return pair<vector<Triangle>, vector<Triangle>>(image1OutputTriangles, image2OutputTriangles);
}

const pair<vector<Triangle>, vector<Triangle>> readMatchingTrianglesFromJsonFile(const string filename) {
    std::ifstream file(filename);
    return readMatchingTrianglesFromJsonFile(&file);
}

template<typename T>
const vector<T> readJsonHashesFile(std::ifstream *file) {
    vector<T> ret;
    vector<Triangle> image1OutputTriangles;
    vector<Triangle> image2OutputTriangles;
    try {
        boost::property_tree::ptree pt;
        boost::property_tree::read_json(*file, pt);

        for (auto label0 : pt) {
            if (label0.first == "output") {
                for (auto label1: label0.second) {
                    if (label1.first == "imageName") {
                        //save the imageName
                    } else if (label1.first == "hashes") {
                        for (auto hash_item: label1.second) {
                            ret.push_back(T(hash_item.second.get_value<std::string>()));
                            //cout << "hash: " << hash_item.second.get_value<std::string>() << endl;
                        }
                    }
                }
            }
        }

        print(pt);
    }
    catch (std::exception const &e) {
        std::cerr << e.what() << std::endl;
    }

    return ret;
}

template<typename T>
const vector<T> readJsonHashesFile(const string filename) {
    std::ifstream file(filename);
    return readJsonHashesFile<T>(&file);
}

template<typename T>
void dumpHashesToJsonFile(std::ofstream *file, vector<T> hashes) {
    ptree outputTree, hashesTree;
    for(auto hash: hashes){
        hashesTree.push_back(std::make_pair( "", ptree(hash.toString()) ));
    }
    outputTree.put_child("output.hashes", hashesTree);
    std::stringstream ss;
    write_json(ss, outputTree);
    *file << ss.str();
}

template<typename T> void dumpHashesToJsonFile(const string filename, vector<T> hashes) {
    std::ofstream ofs;
    ofs.open (filename, std::ofstream::out);
    dumpHashesToJsonFile<T>(&ofs, hashes);
}

std::vector<Triangle> getTheTris(const string trisPath) {
    std::ifstream file(trisPath);
    //std::string filename = readTheName(&file);
    auto tris = readTheTriangles(&file);
    return tris;
}

std::vector<Triangle> getTheTris_random(string trisPath, int numberOfSamples = 1000) {
    std::ifstream file(trisPath);
    //std::string filename = readTheName(&file);
    auto tris = readTheTriangles(&file);
    std::vector<Triangle> ret;
    for (int i = 0; i < numberOfSamples; i++) {
        int ran = rand() % tris.size();
        ret.push_back(tris[ran]);
    }

    return ret;
}

ShapeAndPositionInvariantImage getLoadedImage(string imageFullPath) {
    cv::Mat img = cv::imread(imageFullPath);
    return ShapeAndPositionInvariantImage("", img, std::vector<Keypoint>(), "");
}

void writeHashesToFile(string fullFilePath, vector<string> hashes) {
    std::ofstream outputFile;
    outputFile.open(fullFilePath, std::ios::out);
    for (auto hash: hashes) {
        outputFile << hash << endl;
    }
}

template<typename T>
void writeHashObjectsToFile(string fullFilePath, vector<T> hashes) {
    vector<string> hashesToString;
    for (auto hash: hashes) {
        hashesToString.push_back(hash.toString());
    }
    writeHashesToFile(fullFilePath, hashesToString);
}

vector<string> loadImageNames(string filename) {
    vector<string> filenames;

    std::ifstream file(filename);
    std::string str = "";
    while (true) {
        if (!std::getline(file, str)) {
            break;
        }
        filenames.push_back(str);
    }

    return filenames;
}

vector<string> loadExcludeList(string filename) {
    vector<string> filenames;

    std::ifstream file(filename);
    std::string str = "";
    while (true) {
        if (!std::getline(file, str)) {
            break;
        }
        filenames.push_back(str);
    }

    return filenames;
}

template<typename T>
std::vector<T> loadHashesFromFile(std::string filename) {
    std::vector<T> ret;
    std::ifstream file(filename);
    std::string str = "";
    while (true) {
        if (!std::getline(file, str)) {
            break;
        }

        T fraghash(str);
        ret.push_back(fraghash);
        //std::cout << str << " should match: " << cv::convertHashToString(fraghash) << std::endl;
    }
    return ret;
}

bool isInImageNameExcludeList(string name, vector<string> excludeList, string imageName) {
    if (name == imageName) {
        return true;
    }
    for (auto e: excludeList) {
        if (name == e) {
            return true;
        }
    }
    return false;
}

#endif//utils_utils_hpp
<commit_msg>removed old triangle read code<commit_after>#ifndef utils_utils_hpp
#define utils_utils_hpp

#include <vector>
#include <opencv2/opencv.hpp>
#include <fstream>
#include <string>
#include <regex>

#include <stdio.h>      /* printf, scanf, puts, NULL */
#include <stdlib.h>     /* srand, rand */
#include <time.h>       /* time */

#include "img_hash/AverageHash.h"
#include "img_hash/BlockMeanHash.h"
#include "img_hash/PerceptualHash.h"

//#include "img_hash/FragmentHash.h"
//#include "ShapeAndPositionInvariantImage.h"
#include "Triangle.h"
#include "mainImageProcessingFunctions.hpp"
#include <boost/program_options.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <iostream>
#include "utils/utils.hpp"
#include <tuple>

using boost::property_tree::ptree;
using boost::property_tree::read_json;
using boost::property_tree::write_json;

namespace pt = boost::property_tree;

void drawSingleTriangleOntoImage(Triangle tri, cv::Mat inputImage, bool randomColours = true){
    auto keypoints = tri.toKeypoints();
    auto prevPoint = keypoints.back();
//    for (auto currentPoint: keypoints)
//    {
    for (int i = 0; i < 3; i++){
        auto currentPoint = keypoints[i];
        int r = (i==0);
        int g = (i==1);
        int b = (i==2);

        cv::line(inputImage, cv::Point(currentPoint.x, currentPoint.y), cv::Point(prevPoint.x, prevPoint.y),
                 cv::Scalar(255*b,255*g,255*r));
        cv::imshow("something", inputImage);
        cv::waitKey(0);
        prevPoint = currentPoint;
    }
}

void drawTrianglesOntoImage(vector<Triangle> tris, cv::Mat inputImage, bool randomColours = true)
{
    for (auto tri: tris){
        drawSingleTriangleOntoImage(tri, inputImage, randomColours);
    }
}

Triangle getTriangleFromRedisEntry(string redisEntry)
{
    pt::ptree root;
    std::stringstream ss;
    ss << redisEntry;
    pt::read_json(ss, root);

    vector<Keypoint> keypoints;
    for (auto pt_j: root.get_child("triangle"))
    {
        double x = pt_j.second.get<double>("x");
        double y = pt_j.second.get<double>("y");
        keypoints.push_back(Keypoint(x,y));
    }
    return Triangle(keypoints);
}

string getImageNameFromRedisEntry(string redisEntry)
{
    pt::ptree root;
    std::stringstream ss;
    ss << redisEntry;
    pt::read_json(ss, root);
    return root.get<string>("imageName");
}

string convertToRedisEntryJson(string imageName, Triangle tri){
    pt::ptree root;
    root.put("imageName", imageName);

    //add each point of the triangle
    pt::ptree points;
    for (auto pt : tri.toKeypoints())
    {
        pt::ptree point;
        point.put("x", pt.x);
        point.put("y", pt.y);
        points.push_back(std::make_pair("", point));
    }
    root.add_child("triangle", points);

    std::ostringstream buf;
    write_json(buf, root, false);
    return buf.str();
}

vector<Keypoint> readKeypointsFromJsonFile(std::ifstream *file)
{
    vector<Keypoint> result;
    try {
        boost::property_tree::ptree pt;
        boost::property_tree::read_json(*file, pt);

        for (auto label0 : pt) {
            if (label0.first == "output") {
                for (auto label1: label0.second) {
                    if (label1.first == "keypoints") {
                        for (auto kp : label1.second){
                            double x, y;
                            for (auto pt : kp.second){
                                if(pt.first == "x"){
                                    x = pt.second.get_value<double>();
                                }else{
                                    y = pt.second.get_value<double>();
                                }
                            }
                            result.push_back(Keypoint(x, y));
                        }
                    }
                }
            }
        }
    } catch (std::exception const &e) {
        std::cerr << e.what() << std::endl;
    }
    return result;
}

vector<Keypoint> readKeypointsFromJsonFile(string filename)
{
    std::ifstream file(filename);
    return readKeypointsFromJsonFile(&file);
}

void print(boost::property_tree::ptree const &pt) {
}

double getKeypointDistance(Keypoint one, Keypoint two)
{
	return sqrt( pow( one.x-two.x, 2.0 ) + pow( one.y-two.y, 2.0 ) );
}

vector<Keypoint> findKeypointsWithInRangeFromTwoPoints(Keypoint one, Keypoint two, vector<Keypoint> otherKeypoints, double lowerThreshold, double upperThreshold)
{
	vector<Keypoint> result;
	for (auto cmpKp : otherKeypoints)
	{
        double distanceFromPointOne = getKeypointDistance(one, cmpKp);
        double distanceFromPointTwo = getKeypointDistance(two, cmpKp);
		if(distanceFromPointOne > lowerThreshold && distanceFromPointOne < upperThreshold
                && distanceFromPointTwo > lowerThreshold && distanceFromPointTwo < upperThreshold)
		{
			result.push_back(cmpKp);
		}
	}
	return result;
}

bool isInKeypointExcludeList(Keypoint keypoint, vector<Keypoint> excludeList) {
    for (auto kp : excludeList)
    {
        if(kp.x == keypoint.x && kp.y == keypoint.y){
            return true;
        }
    }
    return false;
}

bool shouldPointBeExcluded(Keypoint pt, vector<Keypoint> previouslyProcessedPoints, vector<Keypoint> currentProcessedPoints, Keypoint currentTopLevelPoint, Keypoint currentSecondLevelPoint)
{
    return isInKeypointExcludeList(pt, previouslyProcessedPoints)
           || isInKeypointExcludeList(pt, currentProcessedPoints)
           || currentTopLevelPoint == pt
           || currentSecondLevelPoint == pt
            ;
}

//NOTE: otherKeypoints may contain centerKeypoint
vector<Triangle> buildTrianglesForSingleKeypoint(Keypoint centerKeypoint, vector<Keypoint> otherKeypoints, vector<Keypoint> previouslyProcessedPoints, double lowerThreshold, double upperThreshold)
{
	vector<Triangle> result;
    vector<Keypoint> currentProcessedPoints;//a collection of points we have processed since entering this function
	for (auto iterKeypoint: otherKeypoints)
	{
        if(isInKeypointExcludeList(iterKeypoint, previouslyProcessedPoints) || iterKeypoint == centerKeypoint) {
            continue;
        }

        double distance = getKeypointDistance(iterKeypoint, centerKeypoint);
		if(distance > lowerThreshold && distance < upperThreshold)
		{
			vector<Keypoint> finalKeypoints = findKeypointsWithInRangeFromTwoPoints(iterKeypoint, centerKeypoint, otherKeypoints, lowerThreshold, upperThreshold);
			for (auto finKp : finalKeypoints)
			{
                //check if this combination of points will make a triangle we have already created
                if(shouldPointBeExcluded(finKp, previouslyProcessedPoints, currentProcessedPoints, centerKeypoint, iterKeypoint)){
                    continue;
                }
				result.push_back(Triangle(centerKeypoint, iterKeypoint, finKp));
			}
		}
        currentProcessedPoints.push_back(iterKeypoint);
	}
	return result;
}

vector<Triangle> buildTrianglesFromKeypoints(vector<Keypoint> keypoints, double lowerThreshold=150, double upperThreshold=300)
{
	vector<Triangle> outputTriangles;
//	for (auto keypoint: keypoints)
//	{
    //FIXME: this multi-threading needs to be improved
    #pragma omp parallel
    {
        vector<Triangle> vec_private;
        #pragma omp for nowait schedule(static)
        for (unsigned int i = 0; i < keypoints.size(); i++)
        {
            vector<Keypoint>::const_iterator first = keypoints.begin();
            vector<Keypoint>::const_iterator last = keypoints.begin() + i;
            vector<Keypoint> processedPoints(first, last);
            auto keypoint = keypoints[i];
            auto triangles = buildTrianglesForSingleKeypoint(keypoint, keypoints, processedPoints, lowerThreshold, upperThreshold);
            for (auto tri : triangles){
                vec_private.push_back(tri);
            }
            processedPoints.push_back(keypoint);
        }
        #pragma omp critical
        outputTriangles.insert(outputTriangles.end(), vec_private.begin(), vec_private.end());
    }
	return outputTriangles;
}

vector<Triangle> buildTrianglesFromKeypointJsonFile(string filename){
    vector<Keypoint> output = readKeypointsFromJsonFile(filename);
    vector<Triangle> ret = buildTrianglesFromKeypoints(output, 50, 400);
    return ret;
}

vector<Triangle> getTriangles(string filename){
    return buildTrianglesFromKeypointJsonFile(filename);
}

const pair<vector<Triangle>, vector<Triangle>> readMatchingTrianglesFromJsonFile(std::ifstream *file) {
    vector<Triangle> image1OutputTriangles;
    vector<Triangle> image2OutputTriangles;
    try {
        boost::property_tree::ptree pt;
        boost::property_tree::read_json(*file, pt);

        using boost::property_tree::ptree;
        for (auto it : pt) {
            if (it.first == "count") {
                //save count
                cout << "Number of triangles read: " << it.second.get_value<std::string>() << endl;
            }

            if (it.first == "triangles") {
                for (auto tri: it.second) {
                    vector<Keypoint> one, two;
                    for (auto tri_point : tri.second) {
                        vector<Keypoint> bothKp;
                        for (auto pt_u : tri_point.second) {
                            vector<double> tempPoint;
                            for (auto pt : pt_u.second) {
                                double coord = pt.second.get_value<double>();
                                tempPoint.push_back(coord);
                            }
                            Keypoint kp(tempPoint[0], tempPoint[1]);
                            bothKp.push_back(kp);
                        }
                        one.push_back(bothKp[0]);
                        two.push_back(bothKp[1]);
                    }
                    Triangle one_t(one);
                    Triangle two_t(two);
                    image1OutputTriangles.push_back(one_t);
                    image2OutputTriangles.push_back(two_t);
                }
            }
        }

        print(pt);
    }
    catch (std::exception const &e) {
        std::cerr << e.what() << std::endl;
    }

    return pair<vector<Triangle>, vector<Triangle>>(image1OutputTriangles, image2OutputTriangles);
}

const pair<vector<Triangle>, vector<Triangle>> readMatchingTrianglesFromJsonFile(const string filename) {
    std::ifstream file(filename);
    return readMatchingTrianglesFromJsonFile(&file);
}

template<typename T>
const vector<T> readJsonHashesFile(std::ifstream *file) {
    vector<T> ret;
    vector<Triangle> image1OutputTriangles;
    vector<Triangle> image2OutputTriangles;
    try {
        boost::property_tree::ptree pt;
        boost::property_tree::read_json(*file, pt);

        for (auto label0 : pt) {
            if (label0.first == "output") {
                for (auto label1: label0.second) {
                    if (label1.first == "imageName") {
                        //save the imageName
                    } else if (label1.first == "hashes") {
                        for (auto hash_item: label1.second) {
                            ret.push_back(T(hash_item.second.get_value<std::string>()));
                            //cout << "hash: " << hash_item.second.get_value<std::string>() << endl;
                        }
                    }
                }
            }
        }

        print(pt);
    }
    catch (std::exception const &e) {
        std::cerr << e.what() << std::endl;
    }

    return ret;
}

template<typename T>
const vector<T> readJsonHashesFile(const string filename) {
    std::ifstream file(filename);
    return readJsonHashesFile<T>(&file);
}

template<typename T>
void dumpHashesToJsonFile(std::ofstream *file, vector<T> hashes) {
    ptree outputTree, hashesTree;
    for(auto hash: hashes){
        hashesTree.push_back(std::make_pair( "", ptree(hash.toString()) ));
    }
    outputTree.put_child("output.hashes", hashesTree);
    std::stringstream ss;
    write_json(ss, outputTree);
    *file << ss.str();
}

template<typename T> void dumpHashesToJsonFile(const string filename, vector<T> hashes) {
    std::ofstream ofs;
    ofs.open (filename, std::ofstream::out);
    dumpHashesToJsonFile<T>(&ofs, hashes);
}

ShapeAndPositionInvariantImage getLoadedImage(string imageFullPath) {
    cv::Mat img = cv::imread(imageFullPath);
    return ShapeAndPositionInvariantImage("", img, std::vector<Keypoint>(), "");
}

void writeHashesToFile(string fullFilePath, vector<string> hashes) {
    std::ofstream outputFile;
    outputFile.open(fullFilePath, std::ios::out);
    for (auto hash: hashes) {
        outputFile << hash << endl;
    }
}

template<typename T>
void writeHashObjectsToFile(string fullFilePath, vector<T> hashes) {
    vector<string> hashesToString;
    for (auto hash: hashes) {
        hashesToString.push_back(hash.toString());
    }
    writeHashesToFile(fullFilePath, hashesToString);
}

vector<string> loadImageNames(string filename) {
    vector<string> filenames;

    std::ifstream file(filename);
    std::string str = "";
    while (true) {
        if (!std::getline(file, str)) {
            break;
        }
        filenames.push_back(str);
    }

    return filenames;
}

vector<string> loadExcludeList(string filename) {
    vector<string> filenames;

    std::ifstream file(filename);
    std::string str = "";
    while (true) {
        if (!std::getline(file, str)) {
            break;
        }
        filenames.push_back(str);
    }

    return filenames;
}

template<typename T>
std::vector<T> loadHashesFromFile(std::string filename) {
    std::vector<T> ret;
    std::ifstream file(filename);
    std::string str = "";
    while (true) {
        if (!std::getline(file, str)) {
            break;
        }

        T fraghash(str);
        ret.push_back(fraghash);
        //std::cout << str << " should match: " << cv::convertHashToString(fraghash) << std::endl;
    }
    return ret;
}

bool isInImageNameExcludeList(string name, vector<string> excludeList, string imageName) {
    if (name == imageName) {
        return true;
    }
    for (auto e: excludeList) {
        if (name == e) {
            return true;
        }
    }
    return false;
}

#endif//utils_utils_hpp
<|endoftext|>