<commit_before>/**
* C S O U N D   V S T
*
* A VST plugin version of Csound, with Python scripting.
*
* L I C E N S E
*
* This software is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/
#include "CppSound.hpp"
#include "ImageToScore.hpp"
#include "System.hpp"
#include <FL/Fl_Image.H>
#include <FL/Fl_PNM_Image.H>
#include <FL/Fl_XPM_Image.H>
#include <FL/Fl_GIF_Image.H>
#include <FL/Fl_BMP_Image.H>
#include <cmath>
#include <set>
#include <functional>

namespace csound
{

        ImageToScore::ImageToScore(void) : image(0), maximumVoiceCount(4), minimumValue(0)
        {
        }

        ImageToScore::~ImageToScore(void)
        {
        }

        void ImageToScore::setImageFilename(std::string imageFilename)
        {
                this->imageFilename = imageFilename;
        }

        std::string ImageToScore::getImageFilename() const
        {
                return imageFilename;
        }

        void ImageToScore::translate(double x, double y, double hue, double value, Event &event) const
        {
                event[Event::STATUS] = 144;
                event[Event::TIME] = ((x / double(image->w())) * score.scaleTargetRanges[Event::TIME]) + score.scaleTargetMinima[Event::TIME];
                event[Event::INSTRUMENT] = int(hue * score.scaleTargetRanges[Event::INSTRUMENT] + score.scaleTargetMinima[Event::INSTRUMENT] + 0.5);
                event[Event::KEY] = int((((image->h() - y) / double(image->h())) * score.scaleTargetRanges[Event::KEY]) + score.scaleTargetMinima[Event::KEY] + 0.5);
                event[Event::VELOCITY] = value * score.scaleTargetRanges[Event::VELOCITY] + score.scaleTargetRanges[Event::VELOCITY];
                // static char buffer[0x100];
                // sprintf(buffer, "Translate: x %d y %d  %s\n", int(x), int(y), event.toString().c_str());
        }

        void ImageToScore::rgbToHsv(double r, double g, double b, double &h, double &s, double &v)
        {
                double maxc = std::max(std::max(r, g), b);
                double minc = std::min(std::min(r, g), b);
                v = maxc;
                if (minc == maxc)
                {
                        h = 0;
                        s = 0;
                        return;
                }
                s = (maxc-minc) / maxc;
                double rc = (maxc-r) / (maxc-minc);
                double gc = (maxc-g) / (maxc-minc);
                double bc = (maxc-b) / (maxc-minc);
                if (r == maxc)
                {
                        h = bc-gc;
                }
                else if( g == maxc)
                {
                        h = 2.0+rc-bc;
                }
                else
                {
                        h = 4.0+gc-rc;
                }
                h = std::fmod(h/6.0, 1.0);
        }

        void ImageToScore::getPixel(size_t x, size_t y, double &hue, double &saturation, double &value) const
        {
                if(image)
                {
                        unsigned char *data = *(unsigned char **)image->data();
                        unsigned char *line = data + (y * image->w() * image->d());
                        unsigned char *pixel = line + (x * image->d());
                        double red   = pixel[0];
                        double green = pixel[1];
                        double blue  = pixel[2];
                        rgbToHsv(red / 255.0, green / 255.0, blue / 255.0, hue, saturation, value);
                        // System::debug("x %d y %d  pixel %d  r %f g %f b %f  h %f s %f v %f\n", x, y, pixel, red, green, blue, hue, saturation, value);
                }
        }

        void ImageToScore::setMaximumVoiceCount(size_t maximumVoiceCount)
        {
                this->maximumVoiceCount = maximumVoiceCount;
        }

        size_t ImageToScore::getMaximumVoiceCount() const
        {
                return maximumVoiceCount;
        }

        void ImageToScore::setMinimumValue(double minimumValue)
        {
                this->minimumValue = minimumValue;
        }

        double ImageToScore::getMinimumValue() const
        {
                return minimumValue;
        }

        struct EventLess
        {
                bool operator()(const csound::Event& a, const csound::Event& b) const
                {
                        return a[Event::VELOCITY] < b[Event::VELOCITY];
                }
        };

        void ImageToScore::generate()
        {
                if(image)
                {
                        delete image;
                        image = 0;
                }
                if(imageFilename.find(".gif") != std::string::npos || imageFilename.find(".GIF") != std::string::npos)
                {
                        image = new Fl_GIF_Image(imageFilename.c_str());
                }
                else if(imageFilename.find(".xpm") != std::string::npos || imageFilename.find(".XPM") != std::string::npos)
                {
                        image = new Fl_XPM_Image(imageFilename.c_str());
                }
                else if(imageFilename.find(".pnm") != std::string::npos || imageFilename.find(".PNM") != std::string::npos)
                {
                        image = new Fl_PNM_Image(imageFilename.c_str());
                }
                else if(imageFilename.find(".bmp") != std::string::npos || imageFilename.find(".BMP") != std::string::npos)
                {
                        image = new Fl_BMP_Image(imageFilename.c_str());
                }
                else
                {
                        System::error("Image file '%s' not found, or unsupported image format.\n", getImageFilename().c_str());
                }
                if(!image)
                {
                        return;
                }
                double x;
                double y;
                double w = image->w();
                double h = image->h();
                System::inform("Image width  = %d\n", int(w));
                System::inform("Image height = %d\n", int(h));
                System::inform("Image depth  = %d\n", image->d());
                System::inform("Image count  = %d\n", image->count());
                double saturation;
                double hue;
                double value;
                double previousHue;
                double previousValue;
                double nextHue;
                double nextValue;
                Event startingEvent;
                Event endingEvent;
                std::map<size_t, Event> pendingEvents;
                std::multiset<Event, EventLess> startingEvents;
                for(x = 0; x < w; ++x)
                {
                        // Insert starting events into the starting event list,
                        // but only if they are not already there.
                        startingEvents.erase(startingEvents.begin(), startingEvents.end());
                        for(y = 0; y < h; ++y)
                        {
                                getPixel(size_t(x), size_t(y), hue, saturation, value);
                                if(x == 0)
                                {
                                        if(value > minimumValue)
                                        {
                                                previousHue = 0;
                                                previousValue = 0;
                                        }
                                        else
                                        {
                                                previousHue = hue;
                                                previousValue = value;
                                        }
                                }
                                else
                                {
                                        getPixel(size_t(x - 1), size_t(y), previousHue, saturation, previousValue);
                                }
                                // Is the event starting?
                                if(previousValue <= minimumValue && value > minimumValue)
                                {
                                        translate(x, y, hue, value, startingEvent);
                                        startingEvents.insert(startingEvent);
                                }
                        }
                        // Insert starting events into the pending event list, in order of decreasing loudness,
                        // until the pending event list has no more than maximumCount events.
                        for(std::multiset<Event, EventLess>::iterator nt = startingEvents.begin(); nt != startingEvents.end(); ++nt)
                        {
                                if(pendingEvents.size() < maximumVoiceCount)
                                {
                                        startingEvent = *nt;
                                        size_t eventIndex = size_t(startingEvent[Event::INSTRUMENT] * 1000 + startingEvent[Event::KEY]);
                                        if(pendingEvents.find(eventIndex) == pendingEvents.end())
                                        {
                                                pendingEvents[eventIndex] = startingEvent;
                                        }
                                }
                                else
                                {
                                        break;
                                }
                        }
                        // Remove ending events from the pending event list,
                        // and put them in the score.
                        for(y = 0; y < h; ++y)
                        {
                                getPixel(size_t(x), size_t(y), hue, saturation, value);
                                if(x < (w - 1))
                                {
                                        getPixel(size_t(x + 1), size_t(y), nextHue, saturation, nextValue);
                                }
                                else
                                {
                                        nextHue = 0;
                                        nextValue = 0;
                                }
                                //      Is the event ending?
                                if(value > minimumValue && nextValue <= minimumValue)
                                {
                                        translate(x, y, hue, value, endingEvent);
                                        size_t eventIndex = size_t(endingEvent[Event::INSTRUMENT] * 1000 + endingEvent[Event::KEY]);
                                        if(pendingEvents.find(eventIndex) != pendingEvents.end())
                                        {
                                                startingEvent = pendingEvents[eventIndex];
                                                startingEvent[Event::DURATION] = endingEvent[Event::TIME] - startingEvent[Event::TIME];
                                                score.push_back(startingEvent);
                                                System::debug("Inserting: %s\n", startingEvent.toString().c_str());
                                                pendingEvents.erase(eventIndex);
                                        }
                                }
                        }
                }
                System::debug("Remaining events...\n");
                // Insert any remaining events.
                double endingTime = score.scaleTargetMinima[Event::TIME] + score.scaleTargetRanges[Event::TIME];
                for(std::map<size_t, Event>::iterator it = pendingEvents.begin(); it != pendingEvents.end(); ++it)
                {
                        startingEvent = it->second;
                        size_t eventIndex = size_t(startingEvent[Event::INSTRUMENT] * 1000 + startingEvent[Event::KEY]);
                        startingEvent[Event::DURATION] = endingTime - startingEvent[Event::TIME];
                        score.push_back(startingEvent);
                        System::debug("Ending:   %d  %s\n", eventIndex, startingEvent.toString().c_str());
                }
        }
}
<commit_msg>Added some FLTK libraries to Windows build to enable using PNG and JPEG images in ImageToScore. Also improved logic of ImageToScore translation.<commit_after>/**
* C S O U N D   V S T
*
* A VST plugin version of Csound, with Python scripting.
*
* L I C E N S E
*
* This software is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/
#include "CppSound.hpp"
#include "ImageToScore.hpp"
#include "System.hpp"
#include <FL/Fl_Image.H>
#include <FL/Fl_PNM_Image.H>
#include <FL/Fl_XPM_Image.H>
#include <FL/Fl_GIF_Image.H>
#include <FL/Fl_BMP_Image.H>
#include <FL/Fl_PNG_Image.H>
#include <FL/Fl_JPEG_Image.H>
#include <cmath>
#include <set>
#include <functional>

namespace csound
{

        ImageToScore::ImageToScore(void) : image(0), maximumVoiceCount(4), minimumValue(0)
        {
        }

        ImageToScore::~ImageToScore(void)
        {
        }

        void ImageToScore::setImageFilename(std::string imageFilename)
        {
                this->imageFilename = imageFilename;
        }

        std::string ImageToScore::getImageFilename() const
        {
                return imageFilename;
        }

        void ImageToScore::translate(double x, double y, double hue, double value, Event &event) const
        {
                event[Event::STATUS] = 144;
                event[Event::TIME] = ((x / double(image->w())) * score.scaleTargetRanges[Event::TIME]) + score.scaleTargetMinima[Event::TIME];
                event[Event::INSTRUMENT] = int(hue * score.scaleTargetRanges[Event::INSTRUMENT] + score.scaleTargetMinima[Event::INSTRUMENT] + 0.5);
                event[Event::KEY] = int((((image->h() - y) / double(image->h())) * score.scaleTargetRanges[Event::KEY]) + score.scaleTargetMinima[Event::KEY] + 0.5);
                event[Event::VELOCITY] = value * score.scaleTargetRanges[Event::VELOCITY] + score.scaleTargetRanges[Event::VELOCITY];
                // static char buffer[0x100];
                // sprintf(buffer, "Translate: x %d y %d  %s\n", int(x), int(y), event.toString().c_str());
        }

        void ImageToScore::rgbToHsv(double r, double g, double b, double &h, double &s, double &v)
        {
                double maxc = std::max(std::max(r, g), b);
                double minc = std::min(std::min(r, g), b);
                v = maxc;
                if (minc == maxc)
                {
                        h = 0;
                        s = 0;
                        return;
                }
                s = (maxc-minc) / maxc;
                double rc = (maxc-r) / (maxc-minc);
                double gc = (maxc-g) / (maxc-minc);
                double bc = (maxc-b) / (maxc-minc);
                if (r == maxc)
                {
                        h = bc-gc;
                }
                else if( g == maxc)
                {
                        h = 2.0+rc-bc;
                }
                else
                {
                        h = 4.0+gc-rc;
                }
                h = std::fmod(h/6.0, 1.0);
        }

        void ImageToScore::getPixel(size_t x, size_t y, double &hue, double &saturation, double &value) const
        {
                if(image)
                {
                        unsigned char *data = *(unsigned char **)image->data();
                        unsigned char *line = data + (y * image->w() * image->d());
                        unsigned char *pixel = line + (x * image->d());
                        double red   = pixel[0];
                        double green = pixel[1];
                        double blue  = pixel[2];
                        rgbToHsv(red / 255.0, green / 255.0, blue / 255.0, hue, saturation, value);
                        // System::debug("x %d y %d  pixel %d  r %f g %f b %f  h %f s %f v %f\n", x, y, pixel, red, green, blue, hue, saturation, value);
                }
        }

        void ImageToScore::setMaximumVoiceCount(size_t maximumVoiceCount)
        {
                this->maximumVoiceCount = maximumVoiceCount;
        }

        size_t ImageToScore::getMaximumVoiceCount() const
        {
                return maximumVoiceCount;
        }

        void ImageToScore::setMinimumValue(double minimumValue)
        {
                this->minimumValue = minimumValue;
        }

        double ImageToScore::getMinimumValue() const
        {
                return minimumValue;
        }

        struct StartingEventLess
        {
                bool operator()(const csound::Event& a, const csound::Event& b) const {
                        return a.getVelocity() < b.getVelocity();
                }
        };

        struct PendingEventLess
        {
                bool operator()(const csound::Event& a, const csound::Event& b) const {
                        if (a.getKeyNumber() < b.getKeyNumber()) {
                            return true;
                        } else if (a.getChannel() < b.getChannel()) {
                            return true;
                        } else {
                            return false;
                        }
                }
        };

        /**
        * Generate a score with up to N voices,
        * based on the pixels in an image file.
        * The horizontal (x) dimension is time,
        * the vertical (y) dimension is pitch (MIDI key),
        * the value (brightness or v) of the pixel is loudness (MIDI velocity),
        * and the hue (color or h) of the pixel is instrument number.
        * The translation algorithm is:
        * for each column of pixels,
        * compare the value of the pixel in each row
        * to the value in the previous column
        * and the value in the next column.
        * If the current value is greater than the previous value or some minimum value V,
        * begin an event for the pitch of that row;
        * if the current value is less than V, end the event;
        * otherwise, continue the event.
        */
        void ImageToScore::generate()
        {
                if (image) {
                        delete image;
                        image = 0;
                }
                if (imageFilename.find(".jpg") != std::string::npos || imageFilename.find(".JPG") != std::string::npos ||
                    imageFilename.find(".jpeg") != std::string::npos || imageFilename.find(".JPEG") != std::string::npos) {
                        image = new Fl_JPEG_Image(imageFilename.c_str());
                } else if (imageFilename.find(".png") != std::string::npos || imageFilename.find(".PNG") != std::string::npos) {
                        image = new Fl_PNG_Image(imageFilename.c_str());
                } else if (imageFilename.find(".gif") != std::string::npos || imageFilename.find(".GIF") != std::string::npos) {
                        image = new Fl_GIF_Image(imageFilename.c_str());
                } else if(imageFilename.find(".xpm") != std::string::npos || imageFilename.find(".XPM") != std::string::npos) {
                        image = new Fl_XPM_Image(imageFilename.c_str());
                } else if(imageFilename.find(".pnm") != std::string::npos || imageFilename.find(".PNM") != std::string::npos) {
                        image = new Fl_PNM_Image(imageFilename.c_str());
                } else if(imageFilename.find(".bmp") != std::string::npos || imageFilename.find(".BMP") != std::string::npos) {
                        image = new Fl_BMP_Image(imageFilename.c_str());
                } else {
                        System::error("Image file '%s' not found, or unsupported image format.\n", getImageFilename().c_str());
                }
                if (!image)
                {
                        return;
                }
                double x = 0.0;
                double y = 0.0;
                double w = image->w();
                double h = image->h();
                System::inform("Image width  = %d\n", int(w));
                System::inform("Image height = %d\n", int(h));
                System::inform("Image depth  = %d\n", image->d());
                System::inform("Image count  = %d\n", image->count());
                double saturation;
                double previousValue;
                double previousHue;
                double currentValue;
                double currentHue;
                double nextValue;
                double nextHue;
                Event startingEvent;
                Event endingEvent;
                std::multiset<Event, StartingEventLess> startingEvents;
                std::set<Event, PendingEventLess> pendingEvents;
                for (x = 0; x < w; ++x) {
                        startingEvents.clear();
                        // Detect starting events.
                        for (y = 0; y < h; ++y) {
                                getPixel(size_t(x), size_t(y), currentHue, saturation, currentValue);
                                if (x == 0) {
                                        if (currentValue > minimumValue) {
                                                previousValue = 0;
                                                previousHue = 0;
                                        } else {
                                                previousValue = currentValue;
                                                previousHue = currentHue;
                                        }
                                } else {
                                        getPixel(size_t(x - 1), size_t(y), previousHue, saturation, previousValue);
                                }
                                if (previousValue <= minimumValue && currentValue > minimumValue) {
                                        translate(x, y, currentHue, currentValue, startingEvent);
                                        startingEvents.insert(startingEvent);
                                }
                        }
                        // Insert starting events into the pending event list, in order of decreasing loudness,
                        // until the pending event list has no more than maximumCount events.
                        for (std::multiset<Event, StartingEventLess>::iterator si = startingEvents.begin(); si != startingEvents.end(); ++si) {
                                if (pendingEvents.size() < maximumVoiceCount) {
                                        startingEvent = *si;
                                        if (pendingEvents.find(startingEvent) == pendingEvents.end()) {
                                                pendingEvents.insert(startingEvent);
                                        }
                                }
                        }
                        // Remove ending events from the pending event list and put them in the score.
                        for (y = 0; y < h; ++y) {
                                getPixel(size_t(x), size_t(y), currentHue, saturation, currentValue);
                                if (x < (w - 1)) {
                                        getPixel(size_t(x + 1), size_t(y), nextHue, saturation, nextValue);
                                } else {
                                        nextValue = 0;
                                        nextHue = 0;
                                }
                                if (currentValue > minimumValue && nextValue <= minimumValue) {
                                        translate(x, y, currentHue, currentValue, endingEvent);
                                        if (pendingEvents.find(endingEvent) != pendingEvents.end()) {
                                                std::set<Event, PendingEventLess>::iterator pi = pendingEvents.find(endingEvent);
                                                startingEvent = *pi;
                                                startingEvent[Event::DURATION] = endingEvent[Event::TIME] - startingEvent[Event::TIME];
                                                if (startingEvent.getDuration() > 0.0) {
                                                    score.push_back(startingEvent);
                                                    System::debug("Inserting at (x =%5d, y =%5d): %s\n", size_t(x), size_t(y), startingEvent.toString().c_str());
                                                }
                                                pendingEvents.erase(pi);
                                        }
                                }
                        }
                }
                System::debug("Remaining events...\n");
                // Insert any remaining events.
                double endingTime = score.scaleTargetMinima[Event::TIME] + score.scaleTargetRanges[Event::TIME];
                for (std::set<Event, PendingEventLess>::iterator it = pendingEvents.begin(); it != pendingEvents.end(); ++it) {
                        startingEvent = *it;
                        startingEvent[Event::DURATION] = endingTime - startingEvent[Event::TIME];
                        score.push_back(startingEvent);
                        System::debug("Ending:   %s\n", startingEvent.toString().c_str());
                }
        }
}
<|endoftext|>


<commit_before>// -*- c-basic-offset: 2; related-file-name: "element.C" -*-
/*
 * @(#)$Id$
 *
 * This file is distributed under the terms in the attached INTEL-LICENSE file.
 * If you do not find these files, copies can be found by writing to:
 * Intel Research Berkeley, 2150 Shattuck Avenue, Suite 1300,
 * Berkeley, CA, 94704.  Attention:  Intel License Inquiry.
 *
 * DESCRIPTION: Element which simply prints any tuple pulled by it
 */

#include "pullprint.h"

#include <iostream>

PullPrint::PullPrint() :
  Element(1,0),
  _wakeup_cb(wrap(this, &PullPrint::wakeup)),
  _run_cb(wrap(this, &PullPrint::run))
{
}

void PullPrint::run()
{
  TuplePtr t = input(0).pull(_wakeup_cb);
  if (t != NULL) {
    // Ensure element is still runnable
    std::cout << "PullPrint: " << (t->toString()) << "\n";
  } else {
    // Element is no longer runnable
  }
}

void PullPrint::wakeup()
{
  lazycb(0, _run_cb);
}
<commit_msg>Reshaped async-friendly wakeup to fit click-ish scheduler<commit_after>// -*- c-basic-offset: 2; related-file-name: "element.C" -*-
/*
 * @(#)$Id$
 *
 * This file is distributed under the terms in the attached INTEL-LICENSE file.
 * If you do not find these files, copies can be found by writing to:
 * Intel Research Berkeley, 2150 Shattuck Avenue, Suite 1300,
 * Berkeley, CA, 94704.  Attention:  Intel License Inquiry.
 *
 * DESCRIPTION: Element which simply prints any tuple pulled by it
 */

#include "pullprint.h"

#include <iostream>

PullPrint::PullPrint() :
  Element(1,0),
  _wakeup_cb(wrap(this, &PullPrint::wakeup)),
  _run_cb(wrap(this, &PullPrint::run)),
  _task(this)
{
}

void PullPrint::wakeup()
{
  // I was signalled from my input that it's OK to pull some more.
  // Schedule myself.  This is only called from someone's callback so
  // it's OK to invoke fast reschedule.

  _task.fast_reschedule();

  //  lazycb(0, _run_cb);
}

int PullPrint::initialize()
{
  // Schedule my task to run
  _task.initialize(this, true);
}

bool PullPrint::run_task()
{
  // Doesn't care if it receives pull failure.

  // Pull and print.  If pull fails, don't schedule yourself.  If pull
  // succeeds, schedule yourself again.
  TuplePtr t = input(0).pull(_wakeup_cb);
  if (t != NULL) {
    // Print tuple
    std::cout << "PullPrint: " << (t->toString()) << "\n";

    // Reschedule
    _task.fast_reschedule();
    return true;
  } else {
    // Didn't get anything

    // Do nothing
    return false;
  }
}

void PullPrint::run()
{
  TuplePtr t = input(0).pull(_wakeup_cb);
  if (t != NULL) {
    // Ensure element is still runnable
    std::cout << "PullPrint: " << (t->toString()) << "\n";
  } else {
    // Element is no longer runnable
  }
}

<|endoftext|>


<commit_before>#include "mitkHierarchicalInteractor.h"
#include "mitkAction.h"
#include "mitkInteractionConst.h"
#include <mitkProperties.h>

mitk::HierarchicalInteractor::HierarchicalInteractor(const char * type, DataTreeNode* dataTreeNode)
:Interactor(type,dataTreeNode)
{
  m_SelectedInteractors.clear();
  m_AllInteractors.clear();
}

bool mitk::HierarchicalInteractor::IsSubSelected() const
{
  return (m_Mode==SMSUBSELECTED);
}

bool mitk::HierarchicalInteractor::HandleEvent(StateEvent const* stateEvent, int objectEventId, int groupEventId)
{
  bool ok = Interactor::HandleEvent( stateEvent, objectEventId, groupEventId );

  if ( IsSubSelected() )
  {
    ok = TransmitEvent( stateEvent, objectEventId, groupEventId ) || ok ;
  }

  return ok;
}

bool mitk::HierarchicalInteractor::TransmitEvent( StateEvent const* stateEvent, int objectEventId, int groupEventId )
{
  InteractorListIter i = m_SelectedInteractors.begin();
  const InteractorListIter end = m_SelectedInteractors.end();
  bool ok = false;
  bool subSelected = false;

  while ( i != end )
  {

    ok = (*i)->HandleEvent( stateEvent, objectEventId, groupEventId ) || ok;
    subSelected = (*i)->IsSelected() || subSelected;
    i++;
  }

  if ( !subSelected )
  {
    StateEvent sd( EIDSUBDESELCT, stateEvent->GetEvent() );
    HandleEvent( &sd, objectEventId, groupEventId );
  }

  return ok;
}

bool mitk::HierarchicalInteractor::ExecuteAction(Action* action, mitk::StateEvent const* stateEvent, int objectEventId, int groupEventId)
{
  switch (action->GetActionId())
  {
    case AcMODEDESELECT:
      {
        //declare operations for modechange:
        this->CreateModeOperation(SMDESELECTED, objectEventId, groupEventId);
        m_SelectedInteractors.clear();
        return true;
      }
    case AcMODESELECT:
      {
        //declare operations for modechange:
        this->CreateModeOperation(SMSELECTED, objectEventId, groupEventId);
        m_SelectedInteractors.clear();
        return true;
      }
    case AcMODESUBSELECT:
      {
        //declare operations for modechange:
        this->CreateModeOperation(SMSUBSELECTED, objectEventId, groupEventId);
        return true;
      }
    case AcCHECKONESUBINTERACTOR:
      {
        m_SelectedInteractors.clear();
        InteractorListIter i = m_AllInteractors.begin();
        InteractorListIter bestInteractor = m_AllInteractors.end();
        const InteractorListIter end = m_AllInteractors.end();
        float jurisdiction = 0.0f;

        while ( i != end )
        {
          float currentJurisdiction = CalculateJurisdiction( stateEvent );

          if ( jurisdiction > currentJurisdiction )
          {
            jurisdiction = currentJurisdiction;
            bestInteractor = i;
          }

          i++;
        }

        FloatProperty* thresholdProperty = dynamic_cast<FloatProperty*>(action->GetProperty("threshold"));
        float threshold;

        if ( thresholdProperty )
          threshold = thresholdProperty->GetValue();
        else
          threshold = 0.5;

        if ( jurisdiction >= threshold )
        {
          m_SelectedInteractors.push_back( *i );
          mitk::StateEvent* newStateEvent = new mitk::StateEvent(StYES, stateEvent->GetEvent());
          this->HandleEvent( newStateEvent, objectEventId, groupEventId );
        }
        else
        {
          mitk::StateEvent* newStateEvent = new mitk::StateEvent(StNO, stateEvent->GetEvent());
          this->HandleEvent( newStateEvent, objectEventId, groupEventId );
        }

        return true;
      }
    case AcCHECKSUBINTERACTORS:
      {

        FloatProperty* thresholdProperty = dynamic_cast<FloatProperty*>(action->GetProperty("threshold"));
        float threshold;

        if ( thresholdProperty )
          threshold = thresholdProperty->GetValue();
        else
          threshold = 0.5;

        m_SelectedInteractors.clear();
        InteractorListIter i = m_AllInteractors.begin();
        InteractorListIter bestInteractor = m_AllInteractors.end();
        const InteractorListIter end = m_AllInteractors.end();
        float jurisdiction = 0.0f;

        while ( i != end )
        {
          float jurisdiction = CalculateJurisdiction( stateEvent );

          if ( jurisdiction > threshold )
            m_SelectedInteractors.push_back( *i );

          i++;
        }

        if ( !m_SelectedInteractors.empty() )
        {
          mitk::StateEvent* newStateEvent = new mitk::StateEvent(StYES, stateEvent->GetEvent());
          this->HandleEvent( newStateEvent, objectEventId, groupEventId );
        }
        else
        {
          mitk::StateEvent* newStateEvent = new mitk::StateEvent(StNO, stateEvent->GetEvent());
          this->HandleEvent( newStateEvent, objectEventId, groupEventId );
        }

        return true;
      }
    default:
      return Superclass::ExecuteAction( action, stateEvent, objectEventId, groupEventId);
  }
}

bool mitk::HierarchicalInteractor::AddInteractor(mitk::Interactor::Pointer interactor)
{
  if (interactor.IsNotNull())
  {
    m_AllInteractors.push_back(interactor);
    return true;
  }
  else
    return false;
}<commit_msg>working on hierarchy<commit_after>#include "mitkHierarchicalInteractor.h"
#include "mitkAction.h"
#include "mitkInteractionConst.h"
#include <mitkProperties.h>

mitk::HierarchicalInteractor::HierarchicalInteractor(const char * type, DataTreeNode* dataTreeNode)
:Interactor(type,dataTreeNode)
{
  m_SelectedInteractors.clear();
  m_AllInteractors.clear();
}

bool mitk::HierarchicalInteractor::IsSubSelected() const
{
  return (m_Mode==SMSUBSELECTED);
}

//##Documentation
//## first we look if the event can be handled by this interactor.
//## if it could not be handled, then check if we are in subselected mode.
//## Then send the event to lower statemachines and afterwards check if they are still sub/selected
bool mitk::HierarchicalInteractor::HandleEvent(StateEvent const* stateEvent, int objectEventId, int groupEventId)
{
  bool ok = Interactor::HandleEvent( stateEvent, objectEventId, groupEventId );

  if (!ok)
  {
    if ( IsSubSelected() )
    {
      ok = TransmitEvent( stateEvent, objectEventId, groupEventId );

      //check if we still have a selected subinteractor. if not, then send deselectEvent
      bool subSelected = false;
      InteractorListIter i = m_SelectedInteractors.begin();
      const InteractorListIter end = m_SelectedInteractors.end();

      while ( i != end )
      {
        subSelected = ( (*i)->IsSelected() || subSelected );
        ++i;
      }

      if ( !subSelected )
      {
        StateEvent sd( EIDSUBDESELECT, stateEvent->GetEvent() );
        ok = Interactor::HandleEvent( &sd, objectEventId, groupEventId );
        if (!ok)
          itkWarningMacro("No SSD Transition defined! Redesign Interaction!!!");
      }
    }
  }
  return ok;
}

bool mitk::HierarchicalInteractor::TransmitEvent( StateEvent const* stateEvent, int objectEventId, int groupEventId )
{
  bool ok = false;
  InteractorListIter i = m_SelectedInteractors.begin();
  const InteractorListIter end = m_SelectedInteractors.end();

  while ( i != end )
  {
    //safety!
    if ((*i) == NULL)
      break;

    ok = (*i)->HandleEvent( stateEvent, objectEventId, groupEventId ) || ok;

    if (!(*i)->IsSelected())
    {
      i = m_SelectedInteractors.erase(i);
      if (m_SelectedInteractors.empty())
        break;
    }
    else
      i++;
  }
  return ok;
}

bool mitk::HierarchicalInteractor::ExecuteAction(Action* action, mitk::StateEvent const* stateEvent, int objectEventId, int groupEventId)
{
  switch (action->GetActionId())
  {
    case AcMODEDESELECT:
      {
        //declare operations for modechange:
        this->CreateModeOperation(SMDESELECTED, objectEventId, groupEventId);
        m_SelectedInteractors.clear();
        return true;
      }
    case AcMODESELECT:
      {
        //declare operations for modechange:
        this->CreateModeOperation(SMSELECTED, objectEventId, groupEventId);
        m_SelectedInteractors.clear();
        return true;
      }
    case AcMODESUBSELECT:
      {
        //declare operations for modechange:
        this->CreateModeOperation(SMSUBSELECTED, objectEventId, groupEventId);
        return true;
      }
    case AcCHECKONESUBINTERACTOR:
      {
        m_SelectedInteractors.clear();
        InteractorListIter i = m_AllInteractors.begin();
        InteractorListIter bestInteractor = m_AllInteractors.end();
        const InteractorListIter end = m_AllInteractors.end();
        float jurisdiction = 0.0f;

        while ( i != end )
        {
          float currentJurisdiction = (*i)->CalculateJurisdiction( stateEvent );

          if ( jurisdiction > currentJurisdiction )
          {
            jurisdiction = currentJurisdiction;
            bestInteractor = i;
          }

          i++;
        }

        FloatProperty* thresholdProperty = dynamic_cast<FloatProperty*>(action->GetProperty("threshold"));
        float threshold;

        if ( thresholdProperty )
          threshold = thresholdProperty->GetValue();
        else
          threshold = 0.5;

        if ( jurisdiction >= threshold )
        {
          m_SelectedInteractors.push_back( *i );
          mitk::StateEvent* newStateEvent = new mitk::StateEvent(EIDYES, stateEvent->GetEvent());
          this->HandleEvent( newStateEvent, objectEventId, groupEventId );
        }
        else
        {
          mitk::StateEvent* newStateEvent = new mitk::StateEvent(EIDNO, stateEvent->GetEvent());
          this->HandleEvent( newStateEvent, objectEventId, groupEventId );
        }

        return true;
      }
    case AcCHECKSUBINTERACTORS:
      {
        FloatProperty* thresholdProperty = dynamic_cast<FloatProperty*>(action->GetProperty("threshold"));
        float threshold;

        if ( thresholdProperty )
          threshold = thresholdProperty->GetValue();
        else
          threshold = 0.5;

        m_SelectedInteractors.clear();
        InteractorListIter i = m_AllInteractors.begin();
        InteractorListIter bestInteractor = m_AllInteractors.end();
        const InteractorListIter end = m_AllInteractors.end();
        float jurisdiction = 0.0f;

        while ( i != end )
        {
          float jurisdiction = CalculateJurisdiction( stateEvent );

          if ( jurisdiction > threshold )
            m_SelectedInteractors.push_back( *i );

          i++;
        }

        if ( !m_SelectedInteractors.empty() )
        {
          mitk::StateEvent* newStateEvent = new mitk::StateEvent(EIDYES, stateEvent->GetEvent());
          this->HandleEvent( newStateEvent, objectEventId, groupEventId );
        }
        else
        {
          mitk::StateEvent* newStateEvent = new mitk::StateEvent(EIDNO, stateEvent->GetEvent());
          this->HandleEvent( newStateEvent, objectEventId, groupEventId );
        }

        return true;
      }
    case AcFORCESUBINTERACTORS:
      {
        m_SelectedInteractors = m_AllInteractors;
        return true;
      }
    case AcTRANSMITEVENT:
      {
        if ( IsSubSelected() )
        {
          TransmitEvent( stateEvent, objectEventId, groupEventId );
        }
        return true;
      }
    default:
      return Superclass::ExecuteAction( action, stateEvent, objectEventId, groupEventId);
  }
}

bool mitk::HierarchicalInteractor::AddInteractor(mitk::Interactor::Pointer interactor)
{
  if (interactor.IsNotNull())
  {
    m_AllInteractors.push_back(interactor);
    return true;
  }
  else
    return false;
}<|endoftext|>


<commit_before>/**
  * Touhou Community Reliant Automatic Patcher
  * Main DLL
  *
  * ----
  *
  * Globals, compile-time constants and runconfig abstractions.
  */

#include "thcrap.h"

json_t* run_cfg = NULL;

const char* PROJECT_NAME(void)
{
	return "Touhou Community Reliant Automatic Patcher";
}
const char* PROJECT_NAME_SHORT(void)
{
	return "thcrap";
}
DWORD PROJECT_VERSION(void)
{
	return 0x20181022;
}
const char* PROJECT_VERSION_STRING(void)
{
	static char ver_str[11] = {0};
	if(!ver_str[0]) {
		str_hexdate_format(ver_str, PROJECT_VERSION());
	}
	return ver_str;
}
json_t* runconfig_get(void)
{
	return run_cfg;
}
void runconfig_set(json_t *new_run_cfg)
{
	json_decref(run_cfg);
	run_cfg = json_incref(new_run_cfg);
}

const json_t *runconfig_title_get(void)
{
	const json_t *id = json_object_get(run_cfg, "game");
	const json_t *title = strings_get(json_string_value(id));
	if(!title) {
		title = json_object_get(run_cfg, "title");
	}
	return title ? title : (id ? id : NULL);
}
<commit_msg>Update version number<commit_after>/**
  * Touhou Community Reliant Automatic Patcher
  * Main DLL
  *
  * ----
  *
  * Globals, compile-time constants and runconfig abstractions.
  */

#include "thcrap.h"

json_t* run_cfg = NULL;

const char* PROJECT_NAME(void)
{
	return "Touhou Community Reliant Automatic Patcher";
}
const char* PROJECT_NAME_SHORT(void)
{
	return "thcrap";
}
DWORD PROJECT_VERSION(void)
{
	return 0x20181203;
}
const char* PROJECT_VERSION_STRING(void)
{
	static char ver_str[11] = {0};
	if(!ver_str[0]) {
		str_hexdate_format(ver_str, PROJECT_VERSION());
	}
	return ver_str;
}
json_t* runconfig_get(void)
{
	return run_cfg;
}
void runconfig_set(json_t *new_run_cfg)
{
	json_decref(run_cfg);
	run_cfg = json_incref(new_run_cfg);
}

const json_t *runconfig_title_get(void)
{
	const json_t *id = json_object_get(run_cfg, "game");
	const json_t *title = strings_get(json_string_value(id));
	if(!title) {
		title = json_object_get(run_cfg, "title");
	}
	return title ? title : (id ? id : NULL);
}
<|endoftext|>


<commit_before>/**
  * Touhou Community Reliant Automatic Patcher
  * Main DLL
  *
  * ----
  *
  * Globals, compile-time constants and runconfig abstractions.
  */

#include "thcrap.h"

CRITICAL_SECTION cs_file_access;
json_t* run_cfg = NULL;

const char* PROJECT_NAME(void)
{
	return "Touhou Community Reliant Automatic Patcher";
}
const char* PROJECT_NAME_SHORT(void)
{
	return "thcrap";
}
DWORD PROJECT_VERSION(void)
{
	return 0x20171118;
}
const char* PROJECT_VERSION_STRING(void)
{
	static char ver_str[11] = {0};
	if(!ver_str[0]) {
		str_hexdate_format(ver_str, PROJECT_VERSION());
	}
	return ver_str;
}
json_t* runconfig_get(void)
{
	return run_cfg;
}
void runconfig_set(json_t *new_run_cfg)
{
	json_decref(run_cfg);
	run_cfg = json_incref(new_run_cfg);
}

const json_t *runconfig_title_get(void)
{
	const json_t *id = json_object_get(run_cfg, "game");
	const json_t *title = strings_get(json_string_value(id));
	if(!title) {
		title = json_object_get(run_cfg, "title");
	}
	return title ? title : (id ? id : NULL);
}
<commit_msg>Update version number<commit_after>/**
  * Touhou Community Reliant Automatic Patcher
  * Main DLL
  *
  * ----
  *
  * Globals, compile-time constants and runconfig abstractions.
  */

#include "thcrap.h"

CRITICAL_SECTION cs_file_access;
json_t* run_cfg = NULL;

const char* PROJECT_NAME(void)
{
	return "Touhou Community Reliant Automatic Patcher";
}
const char* PROJECT_NAME_SHORT(void)
{
	return "thcrap";
}
DWORD PROJECT_VERSION(void)
{
	return 0x20171119;
}
const char* PROJECT_VERSION_STRING(void)
{
	static char ver_str[11] = {0};
	if(!ver_str[0]) {
		str_hexdate_format(ver_str, PROJECT_VERSION());
	}
	return ver_str;
}
json_t* runconfig_get(void)
{
	return run_cfg;
}
void runconfig_set(json_t *new_run_cfg)
{
	json_decref(run_cfg);
	run_cfg = json_incref(new_run_cfg);
}

const json_t *runconfig_title_get(void)
{
	const json_t *id = json_object_get(run_cfg, "game");
	const json_t *title = strings_get(json_string_value(id));
	if(!title) {
		title = json_object_get(run_cfg, "title");
	}
	return title ? title : (id ? id : NULL);
}
<|endoftext|>


<commit_before>/**
  * Touhou Community Reliant Automatic Patcher
  * Main DLL
  *
  * ----
  *
  * Globals, compile-time constants and runconfig abstractions.
  */

#include "thcrap.h"

json_t* global_cfg = NULL;

const char* PROJECT_NAME(void)
{
	return "Touhou Community Reliant Automatic Patcher";
}
const char* PROJECT_NAME_SHORT(void)
{
	return "thcrap";
}
const char* PROJECT_URL(void)
{
	return "https://www.thpatch.net/wiki/Touhou_Patch_Center:Download";
}
DWORD PROJECT_VERSION(void)
{
	return 0x20200606;
}
const char* PROJECT_VERSION_STRING(void)
{
	static char ver_str[11] = {0};
	if(!ver_str[0]) {
		str_hexdate_format(ver_str, PROJECT_VERSION());
	}
	return ver_str;
}
const char* PROJECT_BRANCH(void)
{
	return "stable";
}

void globalconfig_init(void)
{
	json_decref(global_cfg);
	global_cfg = json_load_file_report("config/config.js");
	if (!global_cfg) {
		global_cfg = json_object();
	}
}

int globalconfig_dump(void)
{
	return json_dump_file(global_cfg, "config/config.js", JSON_INDENT(2) | JSON_SORT_KEYS);
}

BOOL globalconfig_get_boolean(char* key, const BOOL default_value)
{
	if (!global_cfg) {
		globalconfig_init();
	}
	errno = 0;
	json_t* value_json = json_object_get(global_cfg, key);
	if (!value_json) {
		errno = ENOENT;
		return default_value;
	}
	return json_boolean_value(value_json);
}

int globalconfig_set_boolean(char* key, const BOOL value)
{
	if (!global_cfg) {
		globalconfig_init();
	}
	json_t* j_value = json_boolean(value);
	if (json_equal(j_value, json_object_get(global_cfg, key))) {
		json_decref(j_value);
		return 0;
	}
	json_object_set_new(global_cfg, key, j_value);
	return globalconfig_dump();
}

long long globalconfig_get_integer(char* key, const long long default_value)
{
	if (!global_cfg) {
		globalconfig_init();
	}
	errno = 0;
	json_t* value_json = json_object_get(global_cfg, key);
	if (!value_json) {
		errno = ENOENT;
		return default_value;
	}
	return json_integer_value(value_json);
}

int globalconfig_set_integer(char* key, const long long value)
{
	if (!global_cfg) {
		globalconfig_init();
	}
	json_t* j_value = json_integer(value);
	if (json_equal(j_value, json_object_get(global_cfg, key))) {
		json_decref(j_value);
		return 0;
	}
	json_object_set_new(global_cfg, key, j_value);
	return globalconfig_dump();
}

void globalconfig_release(void)
{
	json_decref(global_cfg);
	global_cfg = json_incref(NULL);
}

void* __cdecl thcrap_alloc(size_t size) {
	return malloc(size);
}

void __cdecl thcrap_free(void *mem) {
	free(mem);
}
<commit_msg>Update version number<commit_after>/**
  * Touhou Community Reliant Automatic Patcher
  * Main DLL
  *
  * ----
  *
  * Globals, compile-time constants and runconfig abstractions.
  */

#include "thcrap.h"

json_t* global_cfg = NULL;

const char* PROJECT_NAME(void)
{
	return "Touhou Community Reliant Automatic Patcher";
}
const char* PROJECT_NAME_SHORT(void)
{
	return "thcrap";
}
const char* PROJECT_URL(void)
{
	return "https://www.thpatch.net/wiki/Touhou_Patch_Center:Download";
}
DWORD PROJECT_VERSION(void)
{
	return 0x20201012;
}
const char* PROJECT_VERSION_STRING(void)
{
	static char ver_str[11] = {0};
	if(!ver_str[0]) {
		str_hexdate_format(ver_str, PROJECT_VERSION());
	}
	return ver_str;
}
const char* PROJECT_BRANCH(void)
{
	return "stable";
}

void globalconfig_init(void)
{
	json_decref(global_cfg);
	global_cfg = json_load_file_report("config/config.js");
	if (!global_cfg) {
		global_cfg = json_object();
	}
}

int globalconfig_dump(void)
{
	return json_dump_file(global_cfg, "config/config.js", JSON_INDENT(2) | JSON_SORT_KEYS);
}

BOOL globalconfig_get_boolean(char* key, const BOOL default_value)
{
	if (!global_cfg) {
		globalconfig_init();
	}
	errno = 0;
	json_t* value_json = json_object_get(global_cfg, key);
	if (!value_json) {
		errno = ENOENT;
		return default_value;
	}
	return json_boolean_value(value_json);
}

int globalconfig_set_boolean(char* key, const BOOL value)
{
	if (!global_cfg) {
		globalconfig_init();
	}
	json_t* j_value = json_boolean(value);
	if (json_equal(j_value, json_object_get(global_cfg, key))) {
		json_decref(j_value);
		return 0;
	}
	json_object_set_new(global_cfg, key, j_value);
	return globalconfig_dump();
}

long long globalconfig_get_integer(char* key, const long long default_value)
{
	if (!global_cfg) {
		globalconfig_init();
	}
	errno = 0;
	json_t* value_json = json_object_get(global_cfg, key);
	if (!value_json) {
		errno = ENOENT;
		return default_value;
	}
	return json_integer_value(value_json);
}

int globalconfig_set_integer(char* key, const long long value)
{
	if (!global_cfg) {
		globalconfig_init();
	}
	json_t* j_value = json_integer(value);
	if (json_equal(j_value, json_object_get(global_cfg, key))) {
		json_decref(j_value);
		return 0;
	}
	json_object_set_new(global_cfg, key, j_value);
	return globalconfig_dump();
}

void globalconfig_release(void)
{
	json_decref(global_cfg);
	global_cfg = json_incref(NULL);
}

void* __cdecl thcrap_alloc(size_t size) {
	return malloc(size);
}

void __cdecl thcrap_free(void *mem) {
	free(mem);
}
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2018-present, Facebook, Inc.
 *
 *  This source code is licensed under the MIT license found in the LICENSE
 *  file in the root directory of this source tree.
 *
 */

#include "SonarWebSocketImpl.h"
#include "SonarStep.h"
#include <folly/String.h>
#include <folly/futures/Future.h>
#include <folly/io/async/SSLContext.h>
#include <folly/json.h>
#include <rsocket/Payload.h>
#include <rsocket/RSocket.h>
#include <rsocket/transports/tcp/TcpConnectionFactory.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fstream>
#include <iostream>
#include <thread>
#include "CertificateUtils.h"

#ifdef __ANDROID__
#include <android/log.h>
#define SONAR_LOG(message) \
  __android_log_print(ANDROID_LOG_INFO, "sonar", "sonar: %s", message)
#else
#define SONAR_LOG(message) printf("sonar: %s\n", message)
#endif

#define CSR_FILE_NAME "app.csr"
#define SONAR_CA_FILE_NAME "sonarCA.crt"
#define CLIENT_CERT_FILE_NAME "device.crt"
#define PRIVATE_KEY_FILE "privateKey.pem"
#define WRONG_THREAD_EXIT_MSG \
  "ERROR: Aborting sonar initialization because it's not running in the sonar thread."

static constexpr int reconnectIntervalSeconds = 2;
static constexpr int connectionKeepaliveSeconds = 10;
static constexpr int securePort = 8088;
static constexpr int insecurePort = 8089;

namespace facebook {
namespace sonar {

bool fileExists(std::string fileName);

class ConnectionEvents : public rsocket::RSocketConnectionEvents {
 private:
  SonarWebSocketImpl* websocket_;

 public:
  ConnectionEvents(SonarWebSocketImpl* websocket) : websocket_(websocket) {}

  void onConnected() {
    websocket_->isOpen_ = true;
    if (websocket_->connectionIsTrusted_) {
      websocket_->callbacks_->onConnected();
    }
  }

  void onDisconnected(const folly::exception_wrapper&) {
    if (!websocket_->isOpen_)
      return;
    websocket_->isOpen_ = false;
    if (websocket_->connectionIsTrusted_) {
      websocket_->connectionIsTrusted_ = false;
      websocket_->callbacks_->onDisconnected();
    }
    websocket_->reconnect();
  }

  void onClosed(const folly::exception_wrapper& e) {
    onDisconnected(e);
  }
};

class Responder : public rsocket::RSocketResponder {
 private:
  SonarWebSocketImpl* websocket_;

 public:
  Responder(SonarWebSocketImpl* websocket) : websocket_(websocket) {}

  void handleFireAndForget(
      rsocket::Payload request,
      rsocket::StreamId streamId) {
    const auto payload = request.moveDataToString();
    websocket_->callbacks_->onMessageReceived(folly::parseJson(payload));
  }
};

SonarWebSocketImpl::SonarWebSocketImpl(SonarInitConfig config, std::shared_ptr<SonarState> state)
    : deviceData_(config.deviceData), sonarState_(state), sonarEventBase_(config.callbackWorker), connectionEventBase_(config.connectionWorker) {}

SonarWebSocketImpl::~SonarWebSocketImpl() {
  stop();
}

void SonarWebSocketImpl::start() {
  auto step = sonarState_->start("Start connection thread");
  folly::makeFuture()
      .via(sonarEventBase_->getEventBase())
      .delayed(std::chrono::milliseconds(0))
      .thenValue([this, step](auto&&){ step->complete(); startSync(); });
}

void SonarWebSocketImpl::startSync() {
  if (!isRunningInOwnThread()) {
    SONAR_LOG(WRONG_THREAD_EXIT_MSG);
    return;
  }
  if (isOpen()) {
    SONAR_LOG("Already connected");
    return;
  }
  try {
    if (isCertificateExchangeNeeded()) {
      doCertificateExchange();
      return;
    }

    connectSecurely();
  } catch (const std::exception&) {
    failedConnectionAttempts_++;
    reconnect();
  }
}

void SonarWebSocketImpl::doCertificateExchange() {

  rsocket::SetupParameters parameters;
  folly::SocketAddress address;

  parameters.payload = rsocket::Payload(
      folly::toJson(folly::dynamic::object("os", deviceData_.os)(
          "device", deviceData_.device)("app", deviceData_.app)));
  address.setFromHostPort(deviceData_.host, insecurePort);

  auto connectingInsecurely = sonarState_->start("Connect insecurely");
  connectionIsTrusted_ = false;
  client_ =
      rsocket::RSocket::createConnectedClient(
          std::make_unique<rsocket::TcpConnectionFactory>(
              *connectionEventBase_->getEventBase(), std::move(address)),
          std::move(parameters),
          nullptr,
          std::chrono::seconds(connectionKeepaliveSeconds), // keepaliveInterval
          nullptr, // stats
          std::make_shared<ConnectionEvents>(this))
          .get();
  connectingInsecurely->complete();

  ensureSonarDirExists();
  requestSignedCertFromSonar();
}

void SonarWebSocketImpl::connectSecurely() {
  rsocket::SetupParameters parameters;
  folly::SocketAddress address;
  parameters.payload = rsocket::Payload(folly::toJson(folly::dynamic::object(
      "os", deviceData_.os)("device", deviceData_.device)(
      "device_id", deviceData_.deviceId)("app", deviceData_.app)));
  address.setFromHostPort(deviceData_.host, securePort);

  std::shared_ptr<folly::SSLContext> sslContext =
      std::make_shared<folly::SSLContext>();
  sslContext->loadTrustedCertificates(
      absoluteFilePath(SONAR_CA_FILE_NAME).c_str());
  sslContext->setVerificationOption(
      folly::SSLContext::SSLVerifyPeerEnum::VERIFY);
  sslContext->loadCertKeyPairFromFiles(
      absoluteFilePath(CLIENT_CERT_FILE_NAME).c_str(),
      absoluteFilePath(PRIVATE_KEY_FILE).c_str());
  sslContext->authenticate(true, false);

  auto connectingSecurely = sonarState_->start("Connect securely");
  connectionIsTrusted_ = true;
  client_ =
      rsocket::RSocket::createConnectedClient(
          std::make_unique<rsocket::TcpConnectionFactory>(
              *connectionEventBase_->getEventBase(),
              std::move(address),
              std::move(sslContext)),
          std::move(parameters),
          std::make_shared<Responder>(this),
          std::chrono::seconds(connectionKeepaliveSeconds), // keepaliveInterval
          nullptr, // stats
          std::make_shared<ConnectionEvents>(this))
          .get();
  connectingSecurely->complete();
  failedConnectionAttempts_ = 0;
}

void SonarWebSocketImpl::reconnect() {
  folly::makeFuture()
      .via(sonarEventBase_->getEventBase())
      .delayed(std::chrono::seconds(reconnectIntervalSeconds))
      .thenValue([this](auto&&){ startSync(); });
}

void SonarWebSocketImpl::stop() {
  client_->disconnect();
  client_ = nullptr;
}

bool SonarWebSocketImpl::isOpen() const {
  return isOpen_ && connectionIsTrusted_;
}

void SonarWebSocketImpl::setCallbacks(Callbacks* callbacks) {
  callbacks_ = callbacks;
}

void SonarWebSocketImpl::sendMessage(const folly::dynamic& message) {
  sonarEventBase_->add([this, message]() {
    if (client_) {
      client_->getRequester()
          ->fireAndForget(rsocket::Payload(folly::toJson(message)))
          ->subscribe([]() {});
    }
  });
}

bool SonarWebSocketImpl::isCertificateExchangeNeeded() {

  if (failedConnectionAttempts_ >= 2) {
    return true;
  }

  auto step = sonarState_->start("Check required certificates are present");
  std::string caCert = loadStringFromFile(absoluteFilePath(SONAR_CA_FILE_NAME));
  std::string clientCert =
      loadStringFromFile(absoluteFilePath(CLIENT_CERT_FILE_NAME));
  std::string privateKey =
      loadStringFromFile(absoluteFilePath(PRIVATE_KEY_FILE));

  if (caCert == "" || clientCert == "" || privateKey == "") {
    return true;
  }
  step->complete();
  return false;
}

void SonarWebSocketImpl::requestSignedCertFromSonar() {
  auto generatingCSR = sonarState_->start("Generate CSR");
  generateCertSigningRequest(
      deviceData_.appId.c_str(),
      absoluteFilePath(CSR_FILE_NAME).c_str(),
      absoluteFilePath(PRIVATE_KEY_FILE).c_str());
  generatingCSR->complete();
  auto loadingCSR = sonarState_->start("Load CSR");
  std::string csr = loadStringFromFile(absoluteFilePath(CSR_FILE_NAME));
  loadingCSR->complete();

  folly::dynamic message = folly::dynamic::object("method", "signCertificate")(
      "csr", csr.c_str())("destination", absoluteFilePath("").c_str());
  auto gettingCert = sonarState_->start("Getting cert from desktop");

  sonarEventBase_->add([this, message, gettingCert]() {
    client_->getRequester()
        ->requestResponse(rsocket::Payload(folly::toJson(message)))
        ->subscribe([this, gettingCert](rsocket::Payload p) {
          gettingCert->complete();
          SONAR_LOG("Certificate exchange complete.");
          // Disconnect after message sending is complete.
          // This will trigger a reconnect which should use the secure channel.
          // TODO: Connect immediately, without waiting for reconnect
          client_ = nullptr;
        },
        [this, message](folly::exception_wrapper e) {
          e.handle(
            [&](rsocket::ErrorWithPayload& errorWithPayload) {
              std::string errorMessage = errorWithPayload.payload.moveDataToString();

             if (errorMessage.compare("not implemented")) {
               SONAR_LOG(("Desktop failed to provide certificates. Error from sonar desktop:\n" + errorMessage).c_str());
             } else {
              sendLegacyCertificateRequest(message);
             }
            },
            [e](...) {
             SONAR_LOG(("Error during certificate exchange:" + e.what()).c_str());
            }
          );
        });
  });
  failedConnectionAttempts_ = 0;
}

void SonarWebSocketImpl::sendLegacyCertificateRequest(folly::dynamic message) {
  // Desktop is using an old version of Flipper.
  // Fall back to fireAndForget, instead of requestResponse.
  auto sendingRequest = sonarState_->start("Sending fallback certificate request");
  client_->getRequester()
   ->fireAndForget(rsocket::Payload(folly::toJson(message)))
   ->subscribe([this, sendingRequest]() {
     sendingRequest->complete();
     client_ = nullptr;
   });
}

std::string SonarWebSocketImpl::loadStringFromFile(std::string fileName) {
  if (!fileExists(fileName)) {
    return "";
  }
  std::stringstream buffer;
  std::ifstream stream;
  std::string line;
  stream.open(fileName.c_str());
  if (!stream) {
    SONAR_LOG(
        std::string("ERROR: Unable to open ifstream: " + fileName).c_str());
    return "";
  }
  buffer << stream.rdbuf();
  std::string s = buffer.str();
  return s;
}

std::string SonarWebSocketImpl::absoluteFilePath(const char* filename) {
  return std::string(deviceData_.privateAppDirectory + "/sonar/" + filename);
}

bool SonarWebSocketImpl::ensureSonarDirExists() {
  std::string dirPath = absoluteFilePath("");
  struct stat info;
  if (stat(dirPath.c_str(), &info) != 0) {
    int ret = mkdir(dirPath.c_str(), S_IRUSR | S_IWUSR | S_IXUSR);
    return ret == 0;
  } else if (info.st_mode & S_IFDIR) {
    return true;
  } else {
    SONAR_LOG(std::string(
                  "ERROR: Sonar path exists but is not a directory: " + dirPath)
                  .c_str());
    return false;
  }
}

bool SonarWebSocketImpl::isRunningInOwnThread() {
  return sonarEventBase_->isInEventBaseThread();
}

bool fileExists(std::string fileName) {
  struct stat buffer;
  return stat(fileName.c_str(), &buffer) == 0;
}

} // namespace sonar
} // namespace facebook
<commit_msg>Handle socket not open error individually<commit_after>/*
 *  Copyright (c) 2018-present, Facebook, Inc.
 *
 *  This source code is licensed under the MIT license found in the LICENSE
 *  file in the root directory of this source tree.
 *
 */

#include "SonarWebSocketImpl.h"
#include "SonarStep.h"
#include <folly/String.h>
#include <folly/futures/Future.h>
#include <folly/io/async/SSLContext.h>
#include <folly/json.h>
#include <rsocket/Payload.h>
#include <rsocket/RSocket.h>
#include <rsocket/transports/tcp/TcpConnectionFactory.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fstream>
#include <iostream>
#include <thread>
#include <folly/io/async/AsyncSocketException.h>
#include "CertificateUtils.h"

#ifdef __ANDROID__
#include <android/log.h>
#define SONAR_LOG(message) \
  __android_log_print(ANDROID_LOG_INFO, "sonar", "sonar: %s", message)
#else
#define SONAR_LOG(message) printf("sonar: %s\n", message)
#endif

#define CSR_FILE_NAME "app.csr"
#define SONAR_CA_FILE_NAME "sonarCA.crt"
#define CLIENT_CERT_FILE_NAME "device.crt"
#define PRIVATE_KEY_FILE "privateKey.pem"
#define WRONG_THREAD_EXIT_MSG \
  "ERROR: Aborting sonar initialization because it's not running in the sonar thread."

static constexpr int reconnectIntervalSeconds = 2;
static constexpr int connectionKeepaliveSeconds = 10;
static constexpr int securePort = 8088;
static constexpr int insecurePort = 8089;

namespace facebook {
namespace sonar {

bool fileExists(std::string fileName);

class ConnectionEvents : public rsocket::RSocketConnectionEvents {
 private:
  SonarWebSocketImpl* websocket_;

 public:
  ConnectionEvents(SonarWebSocketImpl* websocket) : websocket_(websocket) {}

  void onConnected() {
    websocket_->isOpen_ = true;
    if (websocket_->connectionIsTrusted_) {
      websocket_->callbacks_->onConnected();
    }
  }

  void onDisconnected(const folly::exception_wrapper&) {
    if (!websocket_->isOpen_)
      return;
    websocket_->isOpen_ = false;
    if (websocket_->connectionIsTrusted_) {
      websocket_->connectionIsTrusted_ = false;
      websocket_->callbacks_->onDisconnected();
    }
    websocket_->reconnect();
  }

  void onClosed(const folly::exception_wrapper& e) {
    onDisconnected(e);
  }
};

class Responder : public rsocket::RSocketResponder {
 private:
  SonarWebSocketImpl* websocket_;

 public:
  Responder(SonarWebSocketImpl* websocket) : websocket_(websocket) {}

  void handleFireAndForget(
      rsocket::Payload request,
      rsocket::StreamId streamId) {
    const auto payload = request.moveDataToString();
    websocket_->callbacks_->onMessageReceived(folly::parseJson(payload));
  }
};

SonarWebSocketImpl::SonarWebSocketImpl(SonarInitConfig config, std::shared_ptr<SonarState> state)
    : deviceData_(config.deviceData), sonarState_(state), sonarEventBase_(config.callbackWorker), connectionEventBase_(config.connectionWorker) {}

SonarWebSocketImpl::~SonarWebSocketImpl() {
  stop();
}

void SonarWebSocketImpl::start() {
  auto step = sonarState_->start("Start connection thread");
  folly::makeFuture()
      .via(sonarEventBase_->getEventBase())
      .delayed(std::chrono::milliseconds(0))
      .thenValue([this, step](auto&&){ step->complete(); startSync(); });
}

void SonarWebSocketImpl::startSync() {
  if (!isRunningInOwnThread()) {
    SONAR_LOG(WRONG_THREAD_EXIT_MSG);
    return;
  }
  if (isOpen()) {
    SONAR_LOG("Already connected");
    return;
  }
  auto connect = sonarState_->start("Connect to desktop");
  try {
    if (isCertificateExchangeNeeded()) {
      doCertificateExchange();
      return;
    }
    connectSecurely();

    connect->complete();
  } catch (const folly::AsyncSocketException& e) {
    if (e.getType() == folly::AsyncSocketException::NOT_OPEN) {
      // The expected code path when flipper desktop is not running.
    } else {
      SONAR_LOG(e.what());
      failedConnectionAttempts_++;
    }
    reconnect();
  } catch (const std::exception& e) {
    SONAR_LOG(e.what());
    failedConnectionAttempts_++;
    reconnect();
  }
}

void SonarWebSocketImpl::doCertificateExchange() {

  rsocket::SetupParameters parameters;
  folly::SocketAddress address;

  parameters.payload = rsocket::Payload(
      folly::toJson(folly::dynamic::object("os", deviceData_.os)(
          "device", deviceData_.device)("app", deviceData_.app)));
  address.setFromHostPort(deviceData_.host, insecurePort);

  auto connectingInsecurely = sonarState_->start("Connect insecurely");
  connectionIsTrusted_ = false;
  client_ =
      rsocket::RSocket::createConnectedClient(
          std::make_unique<rsocket::TcpConnectionFactory>(
              *connectionEventBase_->getEventBase(), std::move(address)),
          std::move(parameters),
          nullptr,
          std::chrono::seconds(connectionKeepaliveSeconds), // keepaliveInterval
          nullptr, // stats
          std::make_shared<ConnectionEvents>(this))
          .get();
  connectingInsecurely->complete();

  ensureSonarDirExists();
  requestSignedCertFromSonar();
}

void SonarWebSocketImpl::connectSecurely() {
  rsocket::SetupParameters parameters;
  folly::SocketAddress address;
  parameters.payload = rsocket::Payload(folly::toJson(folly::dynamic::object(
      "os", deviceData_.os)("device", deviceData_.device)(
      "device_id", deviceData_.deviceId)("app", deviceData_.app)));
  address.setFromHostPort(deviceData_.host, securePort);

  std::shared_ptr<folly::SSLContext> sslContext =
      std::make_shared<folly::SSLContext>();
  sslContext->loadTrustedCertificates(
      absoluteFilePath(SONAR_CA_FILE_NAME).c_str());
  sslContext->setVerificationOption(
      folly::SSLContext::SSLVerifyPeerEnum::VERIFY);
  sslContext->loadCertKeyPairFromFiles(
      absoluteFilePath(CLIENT_CERT_FILE_NAME).c_str(),
      absoluteFilePath(PRIVATE_KEY_FILE).c_str());
  sslContext->authenticate(true, false);

  auto connectingSecurely = sonarState_->start("Connect securely");
  connectionIsTrusted_ = true;
  client_ =
      rsocket::RSocket::createConnectedClient(
          std::make_unique<rsocket::TcpConnectionFactory>(
              *connectionEventBase_->getEventBase(),
              std::move(address),
              std::move(sslContext)),
          std::move(parameters),
          std::make_shared<Responder>(this),
          std::chrono::seconds(connectionKeepaliveSeconds), // keepaliveInterval
          nullptr, // stats
          std::make_shared<ConnectionEvents>(this))
          .get();
  connectingSecurely->complete();
  failedConnectionAttempts_ = 0;
}

void SonarWebSocketImpl::reconnect() {
  folly::makeFuture()
      .via(sonarEventBase_->getEventBase())
      .delayed(std::chrono::seconds(reconnectIntervalSeconds))
      .thenValue([this](auto&&){ startSync(); });
}

void SonarWebSocketImpl::stop() {
  client_->disconnect();
  client_ = nullptr;
}

bool SonarWebSocketImpl::isOpen() const {
  return isOpen_ && connectionIsTrusted_;
}

void SonarWebSocketImpl::setCallbacks(Callbacks* callbacks) {
  callbacks_ = callbacks;
}

void SonarWebSocketImpl::sendMessage(const folly::dynamic& message) {
  sonarEventBase_->add([this, message]() {
    if (client_) {
      client_->getRequester()
          ->fireAndForget(rsocket::Payload(folly::toJson(message)))
          ->subscribe([]() {});
    }
  });
}

bool SonarWebSocketImpl::isCertificateExchangeNeeded() {

  if (failedConnectionAttempts_ >= 2) {
    return true;
  }

  auto step = sonarState_->start("Check required certificates are present");
  std::string caCert = loadStringFromFile(absoluteFilePath(SONAR_CA_FILE_NAME));
  std::string clientCert =
      loadStringFromFile(absoluteFilePath(CLIENT_CERT_FILE_NAME));
  std::string privateKey =
      loadStringFromFile(absoluteFilePath(PRIVATE_KEY_FILE));

  if (caCert == "" || clientCert == "" || privateKey == "") {
    return true;
  }
  step->complete();
  return false;
}

void SonarWebSocketImpl::requestSignedCertFromSonar() {
  auto generatingCSR = sonarState_->start("Generate CSR");
  generateCertSigningRequest(
      deviceData_.appId.c_str(),
      absoluteFilePath(CSR_FILE_NAME).c_str(),
      absoluteFilePath(PRIVATE_KEY_FILE).c_str());
  generatingCSR->complete();
  auto loadingCSR = sonarState_->start("Load CSR");
  std::string csr = loadStringFromFile(absoluteFilePath(CSR_FILE_NAME));
  loadingCSR->complete();

  folly::dynamic message = folly::dynamic::object("method", "signCertificate")(
      "csr", csr.c_str())("destination", absoluteFilePath("").c_str());
  auto gettingCert = sonarState_->start("Getting cert from desktop");

  sonarEventBase_->add([this, message, gettingCert]() {
    client_->getRequester()
        ->requestResponse(rsocket::Payload(folly::toJson(message)))
        ->subscribe([this, gettingCert](rsocket::Payload p) {
          gettingCert->complete();
          SONAR_LOG("Certificate exchange complete.");
          // Disconnect after message sending is complete.
          // This will trigger a reconnect which should use the secure channel.
          // TODO: Connect immediately, without waiting for reconnect
          client_ = nullptr;
        },
        [this, message](folly::exception_wrapper e) {
          e.handle(
            [&](rsocket::ErrorWithPayload& errorWithPayload) {
              std::string errorMessage = errorWithPayload.payload.moveDataToString();

             if (errorMessage.compare("not implemented")) {
               SONAR_LOG(("Desktop failed to provide certificates. Error from sonar desktop:\n" + errorMessage).c_str());
             } else {
              sendLegacyCertificateRequest(message);
             }
            },
            [e](...) {
             SONAR_LOG(("Error during certificate exchange:" + e.what()).c_str());
            }
          );
        });
  });
  failedConnectionAttempts_ = 0;
}

void SonarWebSocketImpl::sendLegacyCertificateRequest(folly::dynamic message) {
  // Desktop is using an old version of Flipper.
  // Fall back to fireAndForget, instead of requestResponse.
  auto sendingRequest = sonarState_->start("Sending fallback certificate request");
  client_->getRequester()
   ->fireAndForget(rsocket::Payload(folly::toJson(message)))
   ->subscribe([this, sendingRequest]() {
     sendingRequest->complete();
     client_ = nullptr;
   });
}

std::string SonarWebSocketImpl::loadStringFromFile(std::string fileName) {
  if (!fileExists(fileName)) {
    return "";
  }
  std::stringstream buffer;
  std::ifstream stream;
  std::string line;
  stream.open(fileName.c_str());
  if (!stream) {
    SONAR_LOG(
        std::string("ERROR: Unable to open ifstream: " + fileName).c_str());
    return "";
  }
  buffer << stream.rdbuf();
  std::string s = buffer.str();
  return s;
}

std::string SonarWebSocketImpl::absoluteFilePath(const char* filename) {
  return std::string(deviceData_.privateAppDirectory + "/sonar/" + filename);
}

bool SonarWebSocketImpl::ensureSonarDirExists() {
  std::string dirPath = absoluteFilePath("");
  struct stat info;
  if (stat(dirPath.c_str(), &info) != 0) {
    int ret = mkdir(dirPath.c_str(), S_IRUSR | S_IWUSR | S_IXUSR);
    return ret == 0;
  } else if (info.st_mode & S_IFDIR) {
    return true;
  } else {
    SONAR_LOG(std::string(
                  "ERROR: Sonar path exists but is not a directory: " + dirPath)
                  .c_str());
    return false;
  }
}

bool SonarWebSocketImpl::isRunningInOwnThread() {
  return sonarEventBase_->isInEventBaseThread();
}

bool fileExists(std::string fileName) {
  struct stat buffer;
  return stat(fileName.c_str(), &buffer) == 0;
}

} // namespace sonar
} // namespace facebook
<|endoftext|>


<commit_before>/* \author Bastian Steder */

#include <iostream>

#include <boost/thread/thread.hpp>
#include <pcl/range_image/range_image.h>
#include <pcl/io/pcd_io.h>
#include <pcl/visualization/range_image_visualizer.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/features/range_image_border_extractor.h>
#include <pcl/keypoints/narf_keypoint.h>
#include <pcl/features/narf_descriptor.h>
#include <pcl/console/parse.h>

typedef pcl::PointXYZ PointType;

// --------------------
// -----Parameters-----
// --------------------
float angular_resolution = 0.5f;
float support_size = 0.2f;
pcl::RangeImage::CoordinateFrame coordinate_frame = pcl::RangeImage::CAMERA_FRAME;
bool setUnseenToMaxRange = false;
bool rotation_invariant = true;

// --------------
// -----Help-----
// --------------
void
printUsage (const char* progName)
{
  std::cout << "\n\nUsage: "<<progName<<" [options] <scene.pcd>\n\n"
            << "Options:\n"
            << "-------------------------------------------\n"
            << "-r <float>   angular resolution in degrees (default "<<angular_resolution<<")\n"
            << "-c <int>     coordinate frame (default "<< (int)coordinate_frame<<")\n"
            << "-m           Treat all unseen points to max range\n"
            << "-s <float>   support size for the interest points (diameter of the used sphere - "
                                                                  "default "<<support_size<<")\n"
            << "-o <0/1>     switch rotational invariant version of the feature on/off"
            <<               " (default "<< (int)rotation_invariant<<")\n"
            << "-h           this help\n"
            << "\n\n";
}

void
setViewerPose (pcl::visualization::PCLVisualizer& viewer, const Eigen::Affine3f& viewer_pose)
{
  Eigen::Vector3f pos_vector = viewer_pose * Eigen::Vector3f (0, 0, 0);
  Eigen::Vector3f look_at_vector = viewer_pose.rotation () * Eigen::Vector3f (0, 0, 1) + pos_vector;
  Eigen::Vector3f up_vector = viewer_pose.rotation () * Eigen::Vector3f (0, -1, 0);
  viewer.camera_.pos[0] = pos_vector[0];
  viewer.camera_.pos[1] = pos_vector[1];
  viewer.camera_.pos[2] = pos_vector[2];
  viewer.camera_.focal[0] = look_at_vector[0];
  viewer.camera_.focal[1] = look_at_vector[1];
  viewer.camera_.focal[2] = look_at_vector[2];
  viewer.camera_.view[0] = up_vector[0];
  viewer.camera_.view[1] = up_vector[1];
  viewer.camera_.view[2] = up_vector[2];
  viewer.updateCamera ();
}

// --------------
// -----Main-----
// --------------
int
main (int argc, char** argv)
{
  // --------------------------------------
  // -----Parse Command Line Arguments-----
  // --------------------------------------
  if (pcl::console::find_argument (argc, argv, "-h") >= 0)
  {
    printUsage (argv[0]);
    return 0;
  }
  if (pcl::console::find_argument (argc, argv, "-m") >= 0)
  {
    setUnseenToMaxRange = true;
    cout << "Setting unseen values in range image to maximum range readings.\n";
  }
  if (pcl::console::parse (argc, argv, "-o", rotation_invariant) >= 0)
    cout << "Switching rotation invariant feature version "<< (rotation_invariant ? "on" : "off")<<".\n";
  int tmp_coordinate_frame;
  if (pcl::console::parse (argc, argv, "-c", tmp_coordinate_frame) >= 0)
  {
    coordinate_frame = pcl::RangeImage::CoordinateFrame (tmp_coordinate_frame);
    cout << "Using coordinate frame "<< (int)coordinate_frame<<".\n";
  }
  if (pcl::console::parse (argc, argv, "-s", support_size) >= 0)
    cout << "Setting support size to "<<support_size<<".\n";
  if (pcl::console::parse (argc, argv, "-r", angular_resolution) >= 0)
    cout << "Setting angular resolution to "<<angular_resolution<<"deg.\n";
  angular_resolution = pcl::deg2rad (angular_resolution);

  // ------------------------------------------------------------------
  // -----Read pcd file or create example point cloud if not given-----
  // ------------------------------------------------------------------
  pcl::PointCloud<PointType>::Ptr point_cloud_ptr (new pcl::PointCloud<PointType>);
  pcl::PointCloud<PointType>& point_cloud = *point_cloud_ptr;
  pcl::PointCloud<pcl::PointWithViewpoint> far_ranges;
  Eigen::Affine3f scene_sensor_pose (Eigen::Affine3f::Identity ());
  std::vector<int> pcd_filename_indices = pcl::console::parse_file_extension_argument (argc, argv, "pcd");
  if (!pcd_filename_indices.empty ())
  {
    std::string filename = argv[pcd_filename_indices[0]];
    if (pcl::io::loadPCDFile (filename, point_cloud) == -1)
    {
      cerr << "Was not able to open file \""<<filename<<"\".\n";
      printUsage (argv[0]);
      return 0;
    }
    scene_sensor_pose = Eigen::Affine3f (Eigen::Translation3f (point_cloud.sensor_origin_[0],
                                                               point_cloud.sensor_origin_[1],
                                                               point_cloud.sensor_origin_[2])) *
                        Eigen::Affine3f (point_cloud.sensor_orientation_);
    std::string far_ranges_filename = pcl::getFilenameWithoutExtension (filename)+"_far_ranges.pcd";
    if (pcl::io::loadPCDFile (far_ranges_filename.c_str (), far_ranges) == -1)
      std::cout << "Far ranges file \""<<far_ranges_filename<<"\" does not exists.\n";
  }
  else
  {
    setUnseenToMaxRange = true;
    cout << "\nNo *.pcd file given => Genarating example point cloud.\n\n";
    for (float x=-0.5f; x<=0.5f; x+=0.01f)
    {
      for (float y=-0.5f; y<=0.5f; y+=0.01f)
      {
        PointType point;  point.x = x;  point.y = y;  point.z = 2.0f - y;
        point_cloud.points.push_back (point);
      }
    }
    point_cloud.width = (int) point_cloud.points.size ();  point_cloud.height = 1;
  }

  // -----------------------------------------------
  // -----Create RangeImage from the PointCloud-----
  // -----------------------------------------------
  float noise_level = 0.0;
  float min_range = 0.0f;
  int border_size = 1;
  boost::shared_ptr<pcl::RangeImage> range_image_ptr (new pcl::RangeImage);
  pcl::RangeImage& range_image = *range_image_ptr;
  range_image.createFromPointCloud (point_cloud, angular_resolution, pcl::deg2rad (360.0f), pcl::deg2rad (180.0f),
                                   scene_sensor_pose, coordinate_frame, noise_level, min_range, border_size);
  range_image.integrateFarRanges (far_ranges);
  if (setUnseenToMaxRange)
    range_image.setUnseenToMaxRange ();

  // --------------------------------------------
  // -----Open 3D viewer and add point cloud-----
  // --------------------------------------------
  pcl::visualization::PCLVisualizer viewer ("3D Viewer");
  viewer.setBackgroundColor (1, 1, 1);
  pcl::visualization::PointCloudColorHandlerCustom<pcl::PointWithRange> range_image_color_handler (range_image_ptr, 0, 0, 0);
  viewer.addPointCloud (range_image_ptr, range_image_color_handler, "range image");
  viewer.setPointCloudRenderingProperties (pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "range image");
  //viewer.addCoordinateSystem (1.0f);
  //PointCloudColorHandlerCustom<PointType> point_cloud_color_handler (point_cloud_ptr, 150, 150, 150);
  //viewer.addPointCloud (point_cloud_ptr, point_cloud_color_handler, "original point cloud");
  viewer.initCameraParameters ();
  setViewerPose (viewer, range_image.getTransformationToWorldSystem ());

  // --------------------------
  // -----Show range image-----
  // --------------------------
  pcl::visualization::RangeImageVisualizer range_image_widget ("Range image");
  range_image_widget.showRangeImage (range_image);

  // --------------------------------
  // -----Extract NARF keypoints-----
  // --------------------------------
  pcl::RangeImageBorderExtractor range_image_border_extractor;
  pcl::NarfKeypoint narf_keypoint_detector;
  narf_keypoint_detector.setRangeImageBorderExtractor (&range_image_border_extractor);
  narf_keypoint_detector.setRangeImage (&range_image);
  narf_keypoint_detector.getParameters ().support_size = support_size;

  pcl::PointCloud<int> keypoint_indices;
  narf_keypoint_detector.compute (keypoint_indices);
  std::cout << "Found "<<keypoint_indices.points.size ()<<" key points.\n";

  // ----------------------------------------------
  // -----Show keypoints in range image widget-----
  // ----------------------------------------------
  //for (size_t i=0; i<keypoint_indices.points.size (); ++i)
    //range_image_widget.markPoint (keypoint_indices.points[i]%range_image.width,
                                  //keypoint_indices.points[i]/range_image.width);

  // -------------------------------------
  // -----Show keypoints in 3D viewer-----
  // -------------------------------------
  pcl::PointCloud<pcl::PointXYZ>::Ptr keypoints_ptr (new pcl::PointCloud<pcl::PointXYZ>);
  pcl::PointCloud<pcl::PointXYZ>& keypoints = *keypoints_ptr;
  keypoints.points.resize (keypoint_indices.points.size ());
  for (size_t i=0; i<keypoint_indices.points.size (); ++i)
    keypoints.points[i].getVector3fMap () = range_image.points[keypoint_indices.points[i]].getVector3fMap ();
  pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> keypoints_color_handler (keypoints_ptr, 0, 255, 0);
  viewer.addPointCloud<pcl::PointXYZ> (keypoints_ptr, keypoints_color_handler, "keypoints");
  viewer.setPointCloudRenderingProperties (pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 7, "keypoints");

  // ------------------------------------------------------
  // -----Extract NARF descriptors for interest points-----
  // ------------------------------------------------------
  std::vector<int> keypoint_indices2;
  keypoint_indices2.resize (keypoint_indices.points.size ());
  for (unsigned int i=0; i<keypoint_indices.size (); ++i) // This step is necessary to get the right vector type
    keypoint_indices2[i]=keypoint_indices.points[i];
  pcl::NarfDescriptor narf_descriptor (&range_image, &keypoint_indices2);
  narf_descriptor.getParameters ().support_size = support_size;
  narf_descriptor.getParameters ().rotation_invariant = rotation_invariant;
  pcl::PointCloud<pcl::Narf36> narf_descriptors;
  narf_descriptor.compute (narf_descriptors);
  cout << "Extracted "<<narf_descriptors.size ()<<" descriptors for "
                      <<keypoint_indices.points.size ()<< " keypoints.\n";

  //--------------------
  // -----Main loop-----
  //--------------------
  while (!viewer.wasStopped ())
  {
    range_image_widget.spinOnce ();  // process GUI events
    viewer.spinOnce ();
    pcl_sleep(0.01);
  }
}
<commit_msg>tutorial fix based on new PCLVisualizer changes<commit_after>/* \author Bastian Steder */

#include <iostream>

#include <boost/thread/thread.hpp>
#include <pcl/range_image/range_image.h>
#include <pcl/io/pcd_io.h>
#include <pcl/visualization/range_image_visualizer.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/features/range_image_border_extractor.h>
#include <pcl/keypoints/narf_keypoint.h>
#include <pcl/features/narf_descriptor.h>
#include <pcl/console/parse.h>

typedef pcl::PointXYZ PointType;

// --------------------
// -----Parameters-----
// --------------------
float angular_resolution = 0.5f;
float support_size = 0.2f;
pcl::RangeImage::CoordinateFrame coordinate_frame = pcl::RangeImage::CAMERA_FRAME;
bool setUnseenToMaxRange = false;
bool rotation_invariant = true;

// --------------
// -----Help-----
// --------------
void
printUsage (const char* progName)
{
  std::cout << "\n\nUsage: "<<progName<<" [options] <scene.pcd>\n\n"
            << "Options:\n"
            << "-------------------------------------------\n"
            << "-r <float>   angular resolution in degrees (default "<<angular_resolution<<")\n"
            << "-c <int>     coordinate frame (default "<< (int)coordinate_frame<<")\n"
            << "-m           Treat all unseen points to max range\n"
            << "-s <float>   support size for the interest points (diameter of the used sphere - "
                                                                  "default "<<support_size<<")\n"
            << "-o <0/1>     switch rotational invariant version of the feature on/off"
            <<               " (default "<< (int)rotation_invariant<<")\n"
            << "-h           this help\n"
            << "\n\n";
}

void
setViewerPose (pcl::visualization::PCLVisualizer& viewer, const Eigen::Affine3f& viewer_pose)
{
  Eigen::Vector3f pos_vector = viewer_pose * Eigen::Vector3f (0, 0, 0);
  Eigen::Vector3f look_at_vector = viewer_pose.rotation () * Eigen::Vector3f (0, 0, 1) + pos_vector;
  Eigen::Vector3f up_vector = viewer_pose.rotation () * Eigen::Vector3f (0, -1, 0);
  viewer.setCameraPosition (pos_vector[0], pos_vector[1], pos_vector[2],
                            look_at_vector[0], look_at_vector[1], look_at_vector[2],
                            up_vector[0], up_vector[1], up_vector[2]);
}

// --------------
// -----Main-----
// --------------
int
main (int argc, char** argv)
{
  // --------------------------------------
  // -----Parse Command Line Arguments-----
  // --------------------------------------
  if (pcl::console::find_argument (argc, argv, "-h") >= 0)
  {
    printUsage (argv[0]);
    return 0;
  }
  if (pcl::console::find_argument (argc, argv, "-m") >= 0)
  {
    setUnseenToMaxRange = true;
    cout << "Setting unseen values in range image to maximum range readings.\n";
  }
  if (pcl::console::parse (argc, argv, "-o", rotation_invariant) >= 0)
    cout << "Switching rotation invariant feature version "<< (rotation_invariant ? "on" : "off")<<".\n";
  int tmp_coordinate_frame;
  if (pcl::console::parse (argc, argv, "-c", tmp_coordinate_frame) >= 0)
  {
    coordinate_frame = pcl::RangeImage::CoordinateFrame (tmp_coordinate_frame);
    cout << "Using coordinate frame "<< (int)coordinate_frame<<".\n";
  }
  if (pcl::console::parse (argc, argv, "-s", support_size) >= 0)
    cout << "Setting support size to "<<support_size<<".\n";
  if (pcl::console::parse (argc, argv, "-r", angular_resolution) >= 0)
    cout << "Setting angular resolution to "<<angular_resolution<<"deg.\n";
  angular_resolution = pcl::deg2rad (angular_resolution);

  // ------------------------------------------------------------------
  // -----Read pcd file or create example point cloud if not given-----
  // ------------------------------------------------------------------
  pcl::PointCloud<PointType>::Ptr point_cloud_ptr (new pcl::PointCloud<PointType>);
  pcl::PointCloud<PointType>& point_cloud = *point_cloud_ptr;
  pcl::PointCloud<pcl::PointWithViewpoint> far_ranges;
  Eigen::Affine3f scene_sensor_pose (Eigen::Affine3f::Identity ());
  std::vector<int> pcd_filename_indices = pcl::console::parse_file_extension_argument (argc, argv, "pcd");
  if (!pcd_filename_indices.empty ())
  {
    std::string filename = argv[pcd_filename_indices[0]];
    if (pcl::io::loadPCDFile (filename, point_cloud) == -1)
    {
      cerr << "Was not able to open file \""<<filename<<"\".\n";
      printUsage (argv[0]);
      return 0;
    }
    scene_sensor_pose = Eigen::Affine3f (Eigen::Translation3f (point_cloud.sensor_origin_[0],
                                                               point_cloud.sensor_origin_[1],
                                                               point_cloud.sensor_origin_[2])) *
                        Eigen::Affine3f (point_cloud.sensor_orientation_);
    std::string far_ranges_filename = pcl::getFilenameWithoutExtension (filename)+"_far_ranges.pcd";
    if (pcl::io::loadPCDFile (far_ranges_filename.c_str (), far_ranges) == -1)
      std::cout << "Far ranges file \""<<far_ranges_filename<<"\" does not exists.\n";
  }
  else
  {
    setUnseenToMaxRange = true;
    cout << "\nNo *.pcd file given => Genarating example point cloud.\n\n";
    for (float x=-0.5f; x<=0.5f; x+=0.01f)
    {
      for (float y=-0.5f; y<=0.5f; y+=0.01f)
      {
        PointType point;  point.x = x;  point.y = y;  point.z = 2.0f - y;
        point_cloud.points.push_back (point);
      }
    }
    point_cloud.width = (int) point_cloud.points.size ();  point_cloud.height = 1;
  }

  // -----------------------------------------------
  // -----Create RangeImage from the PointCloud-----
  // -----------------------------------------------
  float noise_level = 0.0;
  float min_range = 0.0f;
  int border_size = 1;
  boost::shared_ptr<pcl::RangeImage> range_image_ptr (new pcl::RangeImage);
  pcl::RangeImage& range_image = *range_image_ptr;
  range_image.createFromPointCloud (point_cloud, angular_resolution, pcl::deg2rad (360.0f), pcl::deg2rad (180.0f),
                                   scene_sensor_pose, coordinate_frame, noise_level, min_range, border_size);
  range_image.integrateFarRanges (far_ranges);
  if (setUnseenToMaxRange)
    range_image.setUnseenToMaxRange ();

  // --------------------------------------------
  // -----Open 3D viewer and add point cloud-----
  // --------------------------------------------
  pcl::visualization::PCLVisualizer viewer ("3D Viewer");
  viewer.setBackgroundColor (1, 1, 1);
  pcl::visualization::PointCloudColorHandlerCustom<pcl::PointWithRange> range_image_color_handler (range_image_ptr, 0, 0, 0);
  viewer.addPointCloud (range_image_ptr, range_image_color_handler, "range image");
  viewer.setPointCloudRenderingProperties (pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "range image");
  //viewer.addCoordinateSystem (1.0f);
  //PointCloudColorHandlerCustom<PointType> point_cloud_color_handler (point_cloud_ptr, 150, 150, 150);
  //viewer.addPointCloud (point_cloud_ptr, point_cloud_color_handler, "original point cloud");
  viewer.initCameraParameters ();
  setViewerPose (viewer, range_image.getTransformationToWorldSystem ());

  // --------------------------
  // -----Show range image-----
  // --------------------------
  pcl::visualization::RangeImageVisualizer range_image_widget ("Range image");
  range_image_widget.showRangeImage (range_image);

  // --------------------------------
  // -----Extract NARF keypoints-----
  // --------------------------------
  pcl::RangeImageBorderExtractor range_image_border_extractor;
  pcl::NarfKeypoint narf_keypoint_detector;
  narf_keypoint_detector.setRangeImageBorderExtractor (&range_image_border_extractor);
  narf_keypoint_detector.setRangeImage (&range_image);
  narf_keypoint_detector.getParameters ().support_size = support_size;

  pcl::PointCloud<int> keypoint_indices;
  narf_keypoint_detector.compute (keypoint_indices);
  std::cout << "Found "<<keypoint_indices.points.size ()<<" key points.\n";

  // ----------------------------------------------
  // -----Show keypoints in range image widget-----
  // ----------------------------------------------
  //for (size_t i=0; i<keypoint_indices.points.size (); ++i)
    //range_image_widget.markPoint (keypoint_indices.points[i]%range_image.width,
                                  //keypoint_indices.points[i]/range_image.width);

  // -------------------------------------
  // -----Show keypoints in 3D viewer-----
  // -------------------------------------
  pcl::PointCloud<pcl::PointXYZ>::Ptr keypoints_ptr (new pcl::PointCloud<pcl::PointXYZ>);
  pcl::PointCloud<pcl::PointXYZ>& keypoints = *keypoints_ptr;
  keypoints.points.resize (keypoint_indices.points.size ());
  for (size_t i=0; i<keypoint_indices.points.size (); ++i)
    keypoints.points[i].getVector3fMap () = range_image.points[keypoint_indices.points[i]].getVector3fMap ();
  pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> keypoints_color_handler (keypoints_ptr, 0, 255, 0);
  viewer.addPointCloud<pcl::PointXYZ> (keypoints_ptr, keypoints_color_handler, "keypoints");
  viewer.setPointCloudRenderingProperties (pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 7, "keypoints");

  // ------------------------------------------------------
  // -----Extract NARF descriptors for interest points-----
  // ------------------------------------------------------
  std::vector<int> keypoint_indices2;
  keypoint_indices2.resize (keypoint_indices.points.size ());
  for (unsigned int i=0; i<keypoint_indices.size (); ++i) // This step is necessary to get the right vector type
    keypoint_indices2[i]=keypoint_indices.points[i];
  pcl::NarfDescriptor narf_descriptor (&range_image, &keypoint_indices2);
  narf_descriptor.getParameters ().support_size = support_size;
  narf_descriptor.getParameters ().rotation_invariant = rotation_invariant;
  pcl::PointCloud<pcl::Narf36> narf_descriptors;
  narf_descriptor.compute (narf_descriptors);
  cout << "Extracted "<<narf_descriptors.size ()<<" descriptors for "
                      <<keypoint_indices.points.size ()<< " keypoints.\n";

  //--------------------
  // -----Main loop-----
  //--------------------
  while (!viewer.wasStopped ())
  {
    range_image_widget.spinOnce ();  // process GUI events
    viewer.spinOnce ();
    pcl_sleep(0.01);
  }
}
<|endoftext|>