<commit_before>/*
* this file is part of the oxygen gtk engine
* Copyright (c) 2010 Hugo Pereira Da Costa <hugo@oxygen-icons.org>
* Copyright (c) 2010 Ruslan Kabatsayev <b7.10110111@gmail.com>
*
* This  library is free  software; you can  redistribute it and/or
* modify it  under  the terms  of the  GNU Lesser  General  Public
* License  as published  by the Free  Software  Foundation; either
* version 2 of the License, or(at your option ) any later version.
*
* This library is distributed  in the hope that it will be useful,
* but  WITHOUT ANY WARRANTY; without even  the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License  along  with  this library;  if not,  write to  the Free
* Software Foundation, Inc., 51  Franklin St, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/

#include <gtk/gtk.h>
#include "oxygeninnershadowdata.h"
#include "../oxygengtkutils.h"
#include "../config.h"
#include "../oxygencairocontext.h"
#include "oxygenanimations.h"
#include "../oxygenstyle.h"
#include "../oxygenmetrics.h"
#include <stdlib.h>

#include <cassert>
#include <iostream>

namespace Oxygen
{

    //_____________________________________________
    void InnerShadowData::connect( GtkWidget* widget )
    {

        assert( GTK_IS_SCROLLED_WINDOW( widget ) );
        assert( !_target );

        // store target
        _target = widget;

        if( gdk_display_supports_composite( gtk_widget_get_display( widget ) ) && G_OBJECT_TYPE_NAME(widget) != std::string("GtkPizza") )
        {
            _compositeEnabled = true;
            _exposeId.connect( G_OBJECT(_target), "expose-event", G_CALLBACK( targetExposeEvent ), this, true );
        }

        // check child
        GtkWidget* child( gtk_bin_get_child( GTK_BIN( widget ) ) );
        if( !child ) return;

        #if OXYGEN_DEBUG
        std::cerr
            << "Oxygen::InnerShadowData::connect -"
            << " widget: " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")"
            << " child: " << child << " (" << G_OBJECT_TYPE_NAME( child ) << ")"
            << std::endl;
        #endif

        registerChild( child );

    }

    //_____________________________________________
    void InnerShadowData::disconnect( GtkWidget* widget )
    {
        _target = 0;
        for( ChildDataMap::iterator iter = _childrenData.begin(); iter != _childrenData.end(); ++iter )
        { iter->second.disconnect( iter->first ); }

        // disconnect signals
        _exposeId.disconnect();

        // clear child data
        _childrenData.clear();
    }

    //_____________________________________________
    void InnerShadowData::registerChild( GtkWidget* widget )
    {

        #if GTK_CHECK_VERSION(2,22,0)

        // make sure widget is not already in map
        if( _childrenData.find( widget ) == _childrenData.end() )
        {

            #if OXYGEN_DEBUG
            std::cerr
                << "Oxygen::InnerShadowData::registerChild -"
                << " " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")"
                << std::endl;
            #endif

            ChildData data;
            data._unrealizeId.connect( G_OBJECT(widget), "unrealize", G_CALLBACK( childUnrealizeNotifyEvent ), this );

            GdkWindow* window(gtk_widget_get_window(widget));
            if(

                // check window
                window &&
                gdk_window_get_window_type( window ) == GDK_WINDOW_CHILD &&

                // check compositing
                gdk_display_supports_composite( gtk_widget_get_display( widget ) ) &&

                // check widget type (might move to blacklist method)
                ( G_OBJECT_TYPE_NAME(widget) != std::string("GtkPizza") ) &&

                // make sure widget is scrollable
                GTK_WIDGET_GET_CLASS( widget )->set_scroll_adjustments_signal )
            {
                data.initiallyComposited=gdk_window_get_composited(window);
                gdk_window_set_composited(window,TRUE);
            }

            _childrenData.insert( std::make_pair( widget, data ) );

        }

        #endif

    }

    //________________________________________________________________________________
    void InnerShadowData::unregisterChild( GtkWidget* widget )
    {

        ChildDataMap::iterator iter( _childrenData.find( widget ) );
        if( iter == _childrenData.end() ) return;

        #if OXYGEN_DEBUG
        std::cerr
            << "Oxygen::InnerShadowData::unregisterChild -"
            << " " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")"
            << std::endl;
        #endif

        iter->second.disconnect( widget );
        _childrenData.erase( iter );

    }

    //________________________________________________________________________________
    void InnerShadowData::ChildData::disconnect( GtkWidget* widget )
    {

        #if OXYGEN_DEBUG
        std::cerr
            << "Oxygen::InnerShadowData::ChildData::disconnect -"
            << " " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")"
            << std::endl;
        #endif

        // disconnect signals
        _unrealizeId.disconnect();

        // remove compositing flag
        GdkWindow* window( gtk_widget_get_window( widget ) );
        if( GTK_IS_WINDOW( window ) && G_OBJECT_TYPE_NAME( widget ) != std::string("GtkPizza") )
        { gdk_window_set_composited(window,initiallyComposited); }
    }

    //____________________________________________________________________________________________
    gboolean InnerShadowData::childUnrealizeNotifyEvent( GtkWidget* widget, gpointer data )
    {
        #if OXYGEN_DEBUG
        std::cerr
            << "Oxygen::InnerShadowData::childUnrealizeNotifyEvent -"
            << " " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")"
            << std::endl;
        #endif
        static_cast<InnerShadowData*>(data)->unregisterChild( widget );
        return FALSE;
    }

    //_________________________________________________________________________________________
    gboolean InnerShadowData::targetExposeEvent( GtkWidget* widget, GdkEventExpose* event, gpointer )
    {

        #if GTK_CHECK_VERSION(2,24,0)
        GtkWidget* child=gtk_bin_get_child(GTK_BIN(widget));
        GdkWindow* window=gtk_widget_get_window(child);

        #if OXYGEN_DEBUG
        std::cerr << "Oxygen::InnerShadowData::targetExposeEvent -"
            << " widget: " << widget << " (" << G_OBJECT_TYPE_NAME(widget) << ")"
            << " child: " << child << " (" << G_OBJECT_TYPE_NAME(widget) << ")"
            << " path: " << Gtk::gtk_widget_path( child )
            << " area: " << event->area
            << std::endl;
        #endif

        if(!gdk_window_get_composited(window))
        {
            #if OXYGEN_DEBUG
            std::cerr << "Oxygen::InnerShadowData::targetExposeEvent - Window isn't composite. Doing nohing\n";
            #endif
            return FALSE;
        }

        // make sure the child window doesn't contain garbage
        gdk_window_process_updates(window,TRUE);

        // get window geometry
        GtkAllocation allocation( Gtk::gdk_rectangle() );
        gdk_window_get_geometry( window, &allocation.x, &allocation.y, &allocation.width, &allocation.height, 0L );

        // create context with clipping
        Cairo::Context context(gtk_widget_get_window(widget), &allocation );

        // add event region
        gdk_cairo_region(context,event->region);
        cairo_clip(context);

        // draw child
        gdk_cairo_set_source_window( context, window, allocation.x, allocation.y );
        cairo_paint(context);

        #if OXYGEN_DEBUG_INNERSHADOWS
        // Show updated parts in random color
        cairo_rectangle(context,allocation.x,allocation.y,allocation.width,allocation.height);
        double red=((double)rand())/RAND_MAX;
        double green=((double)rand())/RAND_MAX;
        double blue=((double)rand())/RAND_MAX;
        cairo_set_source_rgba(context,red,green,blue,0.5);
        cairo_fill(context);
        #endif

        // draw the shadow
        /*
        TODO: here child widget's allocation is used instead of window geometry.
        I think this is the correct thing to do (unlike above), but this is to be double check
        */
        allocation = Gtk::gtk_widget_get_allocation( child );
        int basicOffset=2;

        // we only draw SHADOW_IN here
        if(gtk_scrolled_window_get_shadow_type(GTK_SCROLLED_WINDOW(widget)) != GTK_SHADOW_IN )
        {
            if( GTK_IS_VIEWPORT(child) && gtk_viewport_get_shadow_type(GTK_VIEWPORT(child)) == GTK_SHADOW_IN )
            {

                basicOffset=0;

            } else {

                // FIXME: do we need this special case?
                // special_case {
                // we still want to draw shadow on GtkFrames with shadow containing GtkScrolledWindow without shadow
                GtkWidget* box=gtk_widget_get_parent(widget);
                GtkWidget* frame=0;
                if(GTK_IS_BOX(box) && GTK_IS_FRAME(frame=gtk_widget_get_parent(box)) &&
                       gtk_frame_get_shadow_type(GTK_FRAME(frame))==GTK_SHADOW_IN)
                {
                    #if OXYGEN_DEBUG
                    std::cerr << "Oxygen::InnerShadowData::targetExposeEvent: Box children: " << GTK_CONTAINER(box) << std::endl;
                    #endif
                    // make sure GtkScrolledWindow is the only visible child
                    GList* children=gtk_container_get_children(GTK_CONTAINER(box));
                    for(GList* child=g_list_first(children); child; child=g_list_next(child))
                    {
                        GtkWidget* childWidget(GTK_WIDGET(child->data));
                        if(gtk_widget_get_visible(childWidget) && !GTK_IS_SCROLLED_WINDOW(childWidget))
                        {
                            g_list_free(children);
                            return FALSE;
                        }
                    }
                    int frameX, frameY;
                    GtkAllocation frameAlloc;
                    if(gtk_widget_translate_coordinates(frame,widget,0,0,&frameX,&frameY))
                    {
                        #if OXYGEN_DEBUG
                        std::cerr << "coords translation: x=" << frameX << "; y=" << frameY << std::endl;
                        #endif
                        gtk_widget_get_allocation(frame,&frameAlloc);
                        allocation.x+=frameX;
                        allocation.y+=frameY;
                        allocation.width=frameAlloc.width;
                        allocation.height=frameAlloc.height;
                        basicOffset=0;
                    }

                } else {

                    #if OXYGEN_DEBUG
                    std::cerr << "Oxygen::InnerShadowData::targetExposeEvent - Shadow type isn't GTK_SHADOW_IN, so not drawing the shadow in expose-event handler\n";
                    #endif
                    return FALSE;

                }

            }
        }

        StyleOptions options(widget,gtk_widget_get_state(widget));
        options|=NoFill;
        options &= ~(Hover|Focus);
        if( Style::instance().animations().scrolledWindowEngine().contains( widget ) )
        {
            if( Style::instance().animations().scrolledWindowEngine().focused( widget ) ) options |= Focus;
            if( Style::instance().animations().scrolledWindowEngine().hovered( widget ) ) options |= Hover;
        }

        const AnimationData data( Style::instance().animations().widgetStateEngine().get( widget, options, AnimationHover|AnimationFocus, AnimationFocus ) );

        int offsetX=basicOffset+Entry_SideMargin;
        int offsetY=basicOffset;

        // clipRect
        GdkRectangle clipRect( allocation );

        // hole background
        Style::instance().renderHoleBackground(
            gtk_widget_get_window(widget), widget, &clipRect,
            allocation.x-offsetX, allocation.y-offsetY, allocation.width+offsetX*2, allocation.height+offsetY*2 );

        // adjust offset and render hole
        offsetX -= Entry_SideMargin;
        Style::instance().renderHole(
            gtk_widget_get_window(widget), &clipRect,
            allocation.x-offsetX, allocation.y-offsetY, allocation.width+offsetX*2, allocation.height+offsetY*2,
            options, data );

        #endif // Gtk version

        // let the event propagate
        return FALSE;
    }

}
<commit_msg>Fix typo which lead failure of reverting composited state of various widgets on theme switch from oxygen-gtk to any other<commit_after>/*
* this file is part of the oxygen gtk engine
* Copyright (c) 2010 Hugo Pereira Da Costa <hugo@oxygen-icons.org>
* Copyright (c) 2010 Ruslan Kabatsayev <b7.10110111@gmail.com>
*
* This  library is free  software; you can  redistribute it and/or
* modify it  under  the terms  of the  GNU Lesser  General  Public
* License  as published  by the Free  Software  Foundation; either
* version 2 of the License, or(at your option ) any later version.
*
* This library is distributed  in the hope that it will be useful,
* but  WITHOUT ANY WARRANTY; without even  the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License  along  with  this library;  if not,  write to  the Free
* Software Foundation, Inc., 51  Franklin St, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/

#include <gtk/gtk.h>
#include "oxygeninnershadowdata.h"
#include "../oxygengtkutils.h"
#include "../config.h"
#include "../oxygencairocontext.h"
#include "oxygenanimations.h"
#include "../oxygenstyle.h"
#include "../oxygenmetrics.h"
#include <stdlib.h>

#include <cassert>
#include <iostream>

namespace Oxygen
{

    //_____________________________________________
    void InnerShadowData::connect( GtkWidget* widget )
    {

        assert( GTK_IS_SCROLLED_WINDOW( widget ) );
        assert( !_target );

        // store target
        _target = widget;

        if( gdk_display_supports_composite( gtk_widget_get_display( widget ) ) && G_OBJECT_TYPE_NAME(widget) != std::string("GtkPizza") )
        {
            _compositeEnabled = true;
            _exposeId.connect( G_OBJECT(_target), "expose-event", G_CALLBACK( targetExposeEvent ), this, true );
        }

        // check child
        GtkWidget* child( gtk_bin_get_child( GTK_BIN( widget ) ) );
        if( !child ) return;

        #if OXYGEN_DEBUG
        std::cerr
            << "Oxygen::InnerShadowData::connect -"
            << " widget: " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")"
            << " child: " << child << " (" << G_OBJECT_TYPE_NAME( child ) << ")"
            << std::endl;
        #endif

        registerChild( child );

    }

    //_____________________________________________
    void InnerShadowData::disconnect( GtkWidget* widget )
    {
        _target = 0;
        for( ChildDataMap::iterator iter = _childrenData.begin(); iter != _childrenData.end(); ++iter )
        { iter->second.disconnect( iter->first ); }

        // disconnect signals
        _exposeId.disconnect();

        // clear child data
        _childrenData.clear();
    }

    //_____________________________________________
    void InnerShadowData::registerChild( GtkWidget* widget )
    {

        #if GTK_CHECK_VERSION(2,22,0)

        // make sure widget is not already in map
        if( _childrenData.find( widget ) == _childrenData.end() )
        {

            #if OXYGEN_DEBUG
            std::cerr
                << "Oxygen::InnerShadowData::registerChild -"
                << " " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")"
                << std::endl;
            #endif

            ChildData data;
            data._unrealizeId.connect( G_OBJECT(widget), "unrealize", G_CALLBACK( childUnrealizeNotifyEvent ), this );

            GdkWindow* window(gtk_widget_get_window(widget));
            if(

                // check window
                window &&
                gdk_window_get_window_type( window ) == GDK_WINDOW_CHILD &&

                // check compositing
                gdk_display_supports_composite( gtk_widget_get_display( widget ) ) &&

                // check widget type (might move to blacklist method)
                ( G_OBJECT_TYPE_NAME(widget) != std::string("GtkPizza") ) &&

                // make sure widget is scrollable
                GTK_WIDGET_GET_CLASS( widget )->set_scroll_adjustments_signal )
            {
                data.initiallyComposited=gdk_window_get_composited(window);
                gdk_window_set_composited(window,TRUE);
            }

            _childrenData.insert( std::make_pair( widget, data ) );

        }

        #endif

    }

    //________________________________________________________________________________
    void InnerShadowData::unregisterChild( GtkWidget* widget )
    {

        ChildDataMap::iterator iter( _childrenData.find( widget ) );
        if( iter == _childrenData.end() ) return;

        #if OXYGEN_DEBUG
        std::cerr
            << "Oxygen::InnerShadowData::unregisterChild -"
            << " " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")"
            << std::endl;
        #endif

        iter->second.disconnect( widget );
        _childrenData.erase( iter );

    }

    //________________________________________________________________________________
    void InnerShadowData::ChildData::disconnect( GtkWidget* widget )
    {

        #if OXYGEN_DEBUG
        std::cerr
            << "Oxygen::InnerShadowData::ChildData::disconnect -"
            << " " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")"
            << std::endl;
        #endif

        // disconnect signals
        _unrealizeId.disconnect();

        // remove compositing flag
        GdkWindow* window( gtk_widget_get_window( widget ) );
        if( GDK_IS_WINDOW( window ) && G_OBJECT_TYPE_NAME( widget ) != std::string("GtkPizza") )
        { gdk_window_set_composited(window,initiallyComposited); }
    }

    //____________________________________________________________________________________________
    gboolean InnerShadowData::childUnrealizeNotifyEvent( GtkWidget* widget, gpointer data )
    {
        #if OXYGEN_DEBUG
        std::cerr
            << "Oxygen::InnerShadowData::childUnrealizeNotifyEvent -"
            << " " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")"
            << std::endl;
        #endif
        static_cast<InnerShadowData*>(data)->unregisterChild( widget );
        return FALSE;
    }

    //_________________________________________________________________________________________
    gboolean InnerShadowData::targetExposeEvent( GtkWidget* widget, GdkEventExpose* event, gpointer )
    {

        #if GTK_CHECK_VERSION(2,24,0)
        GtkWidget* child=gtk_bin_get_child(GTK_BIN(widget));
        GdkWindow* window=gtk_widget_get_window(child);

        #if OXYGEN_DEBUG
        std::cerr << "Oxygen::InnerShadowData::targetExposeEvent -"
            << " widget: " << widget << " (" << G_OBJECT_TYPE_NAME(widget) << ")"
            << " child: " << child << " (" << G_OBJECT_TYPE_NAME(widget) << ")"
            << " path: " << Gtk::gtk_widget_path( child )
            << " area: " << event->area
            << std::endl;
        #endif

        if(!gdk_window_get_composited(window))
        {
            #if OXYGEN_DEBUG
            std::cerr << "Oxygen::InnerShadowData::targetExposeEvent - Window isn't composite. Doing nohing\n";
            #endif
            return FALSE;
        }

        // make sure the child window doesn't contain garbage
        gdk_window_process_updates(window,TRUE);

        // get window geometry
        GtkAllocation allocation( Gtk::gdk_rectangle() );
        gdk_window_get_geometry( window, &allocation.x, &allocation.y, &allocation.width, &allocation.height, 0L );

        // create context with clipping
        Cairo::Context context(gtk_widget_get_window(widget), &allocation );

        // add event region
        gdk_cairo_region(context,event->region);
        cairo_clip(context);

        // draw child
        gdk_cairo_set_source_window( context, window, allocation.x, allocation.y );
        cairo_paint(context);

        #if OXYGEN_DEBUG_INNERSHADOWS
        // Show updated parts in random color
        cairo_rectangle(context,allocation.x,allocation.y,allocation.width,allocation.height);
        double red=((double)rand())/RAND_MAX;
        double green=((double)rand())/RAND_MAX;
        double blue=((double)rand())/RAND_MAX;
        cairo_set_source_rgba(context,red,green,blue,0.5);
        cairo_fill(context);
        #endif

        // draw the shadow
        /*
        TODO: here child widget's allocation is used instead of window geometry.
        I think this is the correct thing to do (unlike above), but this is to be double check
        */
        allocation = Gtk::gtk_widget_get_allocation( child );
        int basicOffset=2;

        // we only draw SHADOW_IN here
        if(gtk_scrolled_window_get_shadow_type(GTK_SCROLLED_WINDOW(widget)) != GTK_SHADOW_IN )
        {
            if( GTK_IS_VIEWPORT(child) && gtk_viewport_get_shadow_type(GTK_VIEWPORT(child)) == GTK_SHADOW_IN )
            {

                basicOffset=0;

            } else {

                // FIXME: do we need this special case?
                // special_case {
                // we still want to draw shadow on GtkFrames with shadow containing GtkScrolledWindow without shadow
                GtkWidget* box=gtk_widget_get_parent(widget);
                GtkWidget* frame=0;
                if(GTK_IS_BOX(box) && GTK_IS_FRAME(frame=gtk_widget_get_parent(box)) &&
                       gtk_frame_get_shadow_type(GTK_FRAME(frame))==GTK_SHADOW_IN)
                {
                    #if OXYGEN_DEBUG
                    std::cerr << "Oxygen::InnerShadowData::targetExposeEvent: Box children: " << GTK_CONTAINER(box) << std::endl;
                    #endif
                    // make sure GtkScrolledWindow is the only visible child
                    GList* children=gtk_container_get_children(GTK_CONTAINER(box));
                    for(GList* child=g_list_first(children); child; child=g_list_next(child))
                    {
                        GtkWidget* childWidget(GTK_WIDGET(child->data));
                        if(gtk_widget_get_visible(childWidget) && !GTK_IS_SCROLLED_WINDOW(childWidget))
                        {
                            g_list_free(children);
                            return FALSE;
                        }
                    }
                    int frameX, frameY;
                    GtkAllocation frameAlloc;
                    if(gtk_widget_translate_coordinates(frame,widget,0,0,&frameX,&frameY))
                    {
                        #if OXYGEN_DEBUG
                        std::cerr << "coords translation: x=" << frameX << "; y=" << frameY << std::endl;
                        #endif
                        gtk_widget_get_allocation(frame,&frameAlloc);
                        allocation.x+=frameX;
                        allocation.y+=frameY;
                        allocation.width=frameAlloc.width;
                        allocation.height=frameAlloc.height;
                        basicOffset=0;
                    }

                } else {

                    #if OXYGEN_DEBUG
                    std::cerr << "Oxygen::InnerShadowData::targetExposeEvent - Shadow type isn't GTK_SHADOW_IN, so not drawing the shadow in expose-event handler\n";
                    #endif
                    return FALSE;

                }

            }
        }

        StyleOptions options(widget,gtk_widget_get_state(widget));
        options|=NoFill;
        options &= ~(Hover|Focus);
        if( Style::instance().animations().scrolledWindowEngine().contains( widget ) )
        {
            if( Style::instance().animations().scrolledWindowEngine().focused( widget ) ) options |= Focus;
            if( Style::instance().animations().scrolledWindowEngine().hovered( widget ) ) options |= Hover;
        }

        const AnimationData data( Style::instance().animations().widgetStateEngine().get( widget, options, AnimationHover|AnimationFocus, AnimationFocus ) );

        int offsetX=basicOffset+Entry_SideMargin;
        int offsetY=basicOffset;

        // clipRect
        GdkRectangle clipRect( allocation );

        // hole background
        Style::instance().renderHoleBackground(
            gtk_widget_get_window(widget), widget, &clipRect,
            allocation.x-offsetX, allocation.y-offsetY, allocation.width+offsetX*2, allocation.height+offsetY*2 );

        // adjust offset and render hole
        offsetX -= Entry_SideMargin;
        Style::instance().renderHole(
            gtk_widget_get_window(widget), &clipRect,
            allocation.x-offsetX, allocation.y-offsetY, allocation.width+offsetX*2, allocation.height+offsetY*2,
            options, data );

        #endif // Gtk version

        // let the event propagate
        return FALSE;
    }

}
<|endoftext|>


<commit_before>
#include "ProcessingPyConf.h"
#include "xPyFunc.h"

static PyObject *PySymbolicElement(SymbolicElement *element)
{
  PyObject *dictSEClass = xPyDict_New();
  PyDict_SetItemString(dictSEClass, "source", PyString_FromFormat("%s", element->getSource()->str().c_str()));
  PyDict_SetItemString(dictSEClass, "destination", PyString_FromFormat("%s", element->getDestination()->str().c_str()));
  PyDict_SetItemString(dictSEClass, "expression", PyString_FromFormat("%s", element->getExpression()->str().c_str()));
  PyDict_SetItemString(dictSEClass, "id", PyInt_FromLong(element->getID()));
  PyDict_SetItemString(dictSEClass, "isTainted", PyBool_FromLong(element->isTainted));

  PyObject *SEClassName = xPyString_FromString("SymbolicElement");
  PyObject *SEClass  = xPyClass_New(NULL, dictSEClass, SEClassName);

  return SEClass;
}

ProcessingPyConf::ProcessingPyConf(AnalysisProcessor *ap, Trigger *analysisTrigger)
{
  this->ap = ap;
  this->analysisTrigger = analysisTrigger;
}

ProcessingPyConf::~ProcessingPyConf()
{
}

void ProcessingPyConf::startAnalysisFromAddr(IRBuilder *irb)
{
  // Check if the DSE must be start at this address
  if (PyTritonOptions::startAnalysisFromAddr.find(irb->getAddress()) != PyTritonOptions::startAnalysisFromAddr.end())
    this->analysisTrigger->update(true);
}

void ProcessingPyConf::stopAnalysisFromAddr(IRBuilder *irb)
{
  // Check if the DSE must be stop at this address
  if (PyTritonOptions::stopAnalysisFromAddr.find(irb->getAddress()) != PyTritonOptions::stopAnalysisFromAddr.end())
    this->analysisTrigger->update(false);
}

void ProcessingPyConf::taintRegFromAddr(IRBuilder *irb)
{
  // Apply this bindings only if the analysis is enable
  if (!this->analysisTrigger->getState())
    return;

  // Check if there is registers tainted via the python bindings
  std::list<uint64_t> regsTainted = PyTritonOptions::taintRegFromAddr[irb->getAddress()];
  std::list<uint64_t>::iterator it = regsTainted.begin();
  for ( ; it != regsTainted.end(); it++)
    this->ap->taintReg(*it);
}

void ProcessingPyConf::untaintRegFromAddr(IRBuilder *irb)
{
  // Apply this bindings only if the analysis is enable
  if (!this->analysisTrigger->getState())
    return;

  // Check if there is registers untainted via the python bindings
  std::list<uint64_t> regsUntainted = PyTritonOptions::untaintRegFromAddr[irb->getAddress()];
  std::list<uint64_t>::iterator it = regsUntainted.begin();
  for ( ; it != regsUntainted.end(); it++)
    this->ap->untaintReg(*it);
}

/*
 * When a callback is setup (triton.addCallback()), a class (Instruction) is
 * sent to the callback function as unique argument.
 *
 *
 * Class Instruction:
 *
 * - address (integer)
 * - assembly (string)
 * - isBranch (bool)
 * - opcode (integer)
 * - opcodeCategory (IDREF.OPCODE_CATEGORY)
 * - symbolicElements (list of SymbolicElement)
 * - threadId (integer)
 *
 *
 * Class SymbolicElement:
 *
 * - source (string)
 * - destination (string)
 * - expression (string)
 * - id (integer)
 * - isTainted (bool)
 *
 */
void ProcessingPyConf::callbackAfter(Inst *inst, AnalysisProcessor *ap)
{
  // Check if there is a callback wich must be called at each instruction instrumented
  if (this->analysisTrigger->getState() && PyTritonOptions::callbackAfter){

    /* Create the class dictionary */
    PyObject *dictInstClass = xPyDict_New();
    PyDict_SetItemString(dictInstClass, "address", PyInt_FromLong(inst->getAddress()));
    PyDict_SetItemString(dictInstClass, "threadId", PyInt_FromLong(inst->getThreadID()));
    PyDict_SetItemString(dictInstClass, "opcode", PyInt_FromLong(inst->getOpcode()));
    PyDict_SetItemString(dictInstClass, "opcodeCategory", PyInt_FromLong(inst->getOpcodeCategory()));
    PyDict_SetItemString(dictInstClass, "assembly", PyString_FromFormat("%s", inst->getDisassembly().c_str()));
    PyDict_SetItemString(dictInstClass, "isBranch", PyBool_FromLong(inst->isBranch()));

    /* Setup the symbolic element list */
    PyObject *SEList                         = xPyList_New(inst->numberOfElements());
    std::list<SymbolicElement*> symElements  = inst->getSymbolicElements();
    std::list<SymbolicElement*>::iterator it = symElements.begin();

    Py_ssize_t index = 0;
    for ( ; it != symElements.end(); it++){
      PyList_SetItem(SEList, index, PySymbolicElement(*it));
      index++;
    }

    PyDict_SetItemString(dictInstClass, "symbolicElements", SEList);

    /* Create the Instruction class */
    PyObject *instClassName = xPyString_FromString("Instruction");
    PyObject *instClass  = xPyClass_New(NULL, dictInstClass, instClassName);

    /* CallObject needs a tuple. The size of the tuple is the number of arguments.
     * Triton sends only one argument to the callback. This argument is the Instruction
     * class and contains all information. */
    PyObject *args = xPyTuple_New(1);
    PyTuple_SetItem(args, 0, instClass);
    if (PyObject_CallObject(PyTritonOptions::callbackAfter, args) == NULL){
      PyErr_Print();
      exit(1);
    }

    /* Go through all symbolicElements in SEList. */
    /* Free all items in the symbolicElement class. */
    for (index = 0; index < PyList_Size(SEList); index++){
      /* Get the object in the list */
      PyObject *o = PyList_GetItem(SEList, index);
      /* Cast the PyObject to PyClassObject */
      PyClassObject *co = reinterpret_cast<PyClassObject*>(o);
      /* Free the class name object */
      Py_DECREF(co->cl_name);
      /* Clear/Free the class dictionary items */
      PyDict_Clear(co->cl_dict);
      /* Free the class dictionary object */
      Py_DECREF(co->cl_dict);
      /* Free the initial object */
      Py_DECREF(o);
      /* Next object */
      index++;
    }

    PyDict_Clear(dictInstClass);  /* Clear all items in the dictionary */
    Py_DECREF(SEList);            /* Free the allocated symbolic element list */
    Py_DECREF(dictInstClass);     /* Free the allocated dictionary */
    Py_DECREF(instClassName);     /* Free the allocated Inst class name */
    Py_DECREF(args);              /* Free the allocated tuple */
  }
}

void ProcessingPyConf::callbackBefore(IRBuilder *irb, AnalysisProcessor *ap)
{
  // Check if there is a callback wich must be called at each instruction instrumented
  if (this->analysisTrigger->getState() && PyTritonOptions::callbackBefore){

    /* Create the class dictionary */
    PyObject *dictInstClass = xPyDict_New();
    PyDict_SetItemString(dictInstClass, "address", PyInt_FromLong(irb->getAddress()));
    PyDict_SetItemString(dictInstClass, "threadId", PyInt_FromLong(ap->getThreadID()));
    PyDict_SetItemString(dictInstClass, "opcode", PyInt_FromLong(irb->getOpcode()));
    PyDict_SetItemString(dictInstClass, "opcodeCategory", PyInt_FromLong(irb->getOpcodeCategory()));
    PyDict_SetItemString(dictInstClass, "assembly", PyString_FromFormat("%s", irb->getDisassembly().c_str()));
    PyDict_SetItemString(dictInstClass, "isBranch", PyBool_FromLong(irb->isBranch()));

    /* Before the processing, the symbolic element list is empty */
    PyObject *SEList = xPyList_New(0);
    PyDict_SetItemString(dictInstClass, "symbolicElements", SEList);

    /* Create the Instruction class */
    PyObject *instClassName = xPyString_FromString("Instruction");
    PyObject *instClass  = xPyClass_New(NULL, dictInstClass, instClassName);

    /* CallObject needs a tuple. The size of the tuple is the number of arguments.
     * Triton sends only one argument to the callback. This argument is the Instruction
     * class and contains all information. */
    PyObject *args = xPyTuple_New(1);
    PyTuple_SetItem(args, 0, instClass);
    if (PyObject_CallObject(PyTritonOptions::callbackBefore, args) == NULL){
      PyErr_Print();
      exit(1);
    }

    PyDict_Clear(dictInstClass);  /* Clear all items in the dictionary */
    Py_DECREF(SEList);            /* Free the allocated symbolic element list */
    Py_DECREF(dictInstClass);     /* Free the allocated dictionary */
    Py_DECREF(instClassName);     /* Free the allocated Inst class name */
    Py_DECREF(args);              /* Free the allocated tuple */
  }
}

void ProcessingPyConf::applyConfBeforeProcessing(IRBuilder *irb)
{
  this->startAnalysisFromAddr(irb);
  this->stopAnalysisFromAddr(irb);
  this->taintRegFromAddr(irb);
  this->untaintRegFromAddr(irb);
}

<commit_msg>Enhancement #48: routine name in Instruction<commit_after>
#include "ProcessingPyConf.h"
#include "xPyFunc.h"

static PyObject *PySymbolicElement(SymbolicElement *element)
{
  PyObject *dictSEClass = xPyDict_New();
  PyDict_SetItemString(dictSEClass, "source", PyString_FromFormat("%s", element->getSource()->str().c_str()));
  PyDict_SetItemString(dictSEClass, "destination", PyString_FromFormat("%s", element->getDestination()->str().c_str()));
  PyDict_SetItemString(dictSEClass, "expression", PyString_FromFormat("%s", element->getExpression()->str().c_str()));
  PyDict_SetItemString(dictSEClass, "id", PyInt_FromLong(element->getID()));
  PyDict_SetItemString(dictSEClass, "isTainted", PyBool_FromLong(element->isTainted));

  PyObject *SEClassName = xPyString_FromString("SymbolicElement");
  PyObject *SEClass  = xPyClass_New(NULL, dictSEClass, SEClassName);

  return SEClass;
}

ProcessingPyConf::ProcessingPyConf(AnalysisProcessor *ap, Trigger *analysisTrigger)
{
  this->ap = ap;
  this->analysisTrigger = analysisTrigger;
}

ProcessingPyConf::~ProcessingPyConf()
{
}

void ProcessingPyConf::startAnalysisFromAddr(IRBuilder *irb)
{
  // Check if the DSE must be start at this address
  if (PyTritonOptions::startAnalysisFromAddr.find(irb->getAddress()) != PyTritonOptions::startAnalysisFromAddr.end())
    this->analysisTrigger->update(true);
}

void ProcessingPyConf::stopAnalysisFromAddr(IRBuilder *irb)
{
  // Check if the DSE must be stop at this address
  if (PyTritonOptions::stopAnalysisFromAddr.find(irb->getAddress()) != PyTritonOptions::stopAnalysisFromAddr.end())
    this->analysisTrigger->update(false);
}

void ProcessingPyConf::taintRegFromAddr(IRBuilder *irb)
{
  // Apply this bindings only if the analysis is enable
  if (!this->analysisTrigger->getState())
    return;

  // Check if there is registers tainted via the python bindings
  std::list<uint64_t> regsTainted = PyTritonOptions::taintRegFromAddr[irb->getAddress()];
  std::list<uint64_t>::iterator it = regsTainted.begin();
  for ( ; it != regsTainted.end(); it++)
    this->ap->taintReg(*it);
}

void ProcessingPyConf::untaintRegFromAddr(IRBuilder *irb)
{
  // Apply this bindings only if the analysis is enable
  if (!this->analysisTrigger->getState())
    return;

  // Check if there is registers untainted via the python bindings
  std::list<uint64_t> regsUntainted = PyTritonOptions::untaintRegFromAddr[irb->getAddress()];
  std::list<uint64_t>::iterator it = regsUntainted.begin();
  for ( ; it != regsUntainted.end(); it++)
    this->ap->untaintReg(*it);
}

/*
 * When a callback is setup (triton.addCallback()), a class (Instruction) is
 * sent to the callback function as unique argument.
 *
 *
 * Class Instruction:
 *
 * - address (integer)
 * - assembly (string)
 * - isBranch (bool)
 * - opcode (integer)
 * - opcodeCategory (IDREF.OPCODE_CATEGORY)
 * - symbolicElements (list of SymbolicElement)
 * - threadId (integer)
 *
 *
 * Class SymbolicElement:
 *
 * - source (string)
 * - destination (string)
 * - expression (string)
 * - id (integer)
 * - isTainted (bool)
 *
 */
void ProcessingPyConf::callbackAfter(Inst *inst, AnalysisProcessor *ap)
{
  // Check if there is a callback wich must be called at each instruction instrumented
  if (this->analysisTrigger->getState() && PyTritonOptions::callbackAfter){

    /* Create the class dictionary */
    PyObject *dictInstClass = xPyDict_New();
    PyDict_SetItemString(dictInstClass, "address", PyInt_FromLong(inst->getAddress()));
    PyDict_SetItemString(dictInstClass, "assembly", PyString_FromFormat("%s", inst->getDisassembly().c_str()));
    PyDict_SetItemString(dictInstClass, "isBranch", PyBool_FromLong(inst->isBranch()));
    PyDict_SetItemString(dictInstClass, "opcode", PyInt_FromLong(inst->getOpcode()));
    PyDict_SetItemString(dictInstClass, "opcodeCategory", PyInt_FromLong(inst->getOpcodeCategory()));
    PyDict_SetItemString(dictInstClass, "routineName", PyString_FromFormat("%s", RTN_FindNameByAddress(inst->getAddress()).c_str()));
    PyDict_SetItemString(dictInstClass, "threadId", PyInt_FromLong(inst->getThreadID()));

    /* Setup the symbolic element list */
    PyObject *SEList                         = xPyList_New(inst->numberOfElements());
    std::list<SymbolicElement*> symElements  = inst->getSymbolicElements();
    std::list<SymbolicElement*>::iterator it = symElements.begin();

    Py_ssize_t index = 0;
    for ( ; it != symElements.end(); it++){
      PyList_SetItem(SEList, index, PySymbolicElement(*it));
      index++;
    }

    PyDict_SetItemString(dictInstClass, "symbolicElements", SEList);

    /* Create the Instruction class */
    PyObject *instClassName = xPyString_FromString("Instruction");
    PyObject *instClass  = xPyClass_New(NULL, dictInstClass, instClassName);

    /* CallObject needs a tuple. The size of the tuple is the number of arguments.
     * Triton sends only one argument to the callback. This argument is the Instruction
     * class and contains all information. */
    PyObject *args = xPyTuple_New(1);
    PyTuple_SetItem(args, 0, instClass);
    if (PyObject_CallObject(PyTritonOptions::callbackAfter, args) == NULL){
      PyErr_Print();
      exit(1);
    }

    /* Go through all symbolicElements in SEList. */
    /* Free all items in the symbolicElement class. */
    for (index = 0; index < PyList_Size(SEList); index++){
      /* Get the object in the list */
      PyObject *o = PyList_GetItem(SEList, index);
      /* Cast the PyObject to PyClassObject */
      PyClassObject *co = reinterpret_cast<PyClassObject*>(o);
      /* Free the class name object */
      Py_DECREF(co->cl_name);
      /* Clear/Free the class dictionary items */
      PyDict_Clear(co->cl_dict);
      /* Free the class dictionary object */
      Py_DECREF(co->cl_dict);
      /* Free the initial object */
      Py_DECREF(o);
      /* Next object */
      index++;
    }

    PyDict_Clear(dictInstClass);  /* Clear all items in the dictionary */
    Py_DECREF(SEList);            /* Free the allocated symbolic element list */
    Py_DECREF(dictInstClass);     /* Free the allocated dictionary */
    Py_DECREF(instClassName);     /* Free the allocated Inst class name */
    Py_DECREF(args);              /* Free the allocated tuple */
  }
}

void ProcessingPyConf::callbackBefore(IRBuilder *irb, AnalysisProcessor *ap)
{
  // Check if there is a callback wich must be called at each instruction instrumented
  if (this->analysisTrigger->getState() && PyTritonOptions::callbackBefore){

    /* Create the class dictionary */
    PyObject *dictInstClass = xPyDict_New();
    PyDict_SetItemString(dictInstClass, "address", PyInt_FromLong(irb->getAddress()));
    PyDict_SetItemString(dictInstClass, "assembly", PyString_FromFormat("%s", irb->getDisassembly().c_str()));
    PyDict_SetItemString(dictInstClass, "isBranch", PyBool_FromLong(irb->isBranch()));
    PyDict_SetItemString(dictInstClass, "opcode", PyInt_FromLong(irb->getOpcode()));
    PyDict_SetItemString(dictInstClass, "opcodeCategory", PyInt_FromLong(irb->getOpcodeCategory()));
    PyDict_SetItemString(dictInstClass, "routineName", PyString_FromFormat("%s", RTN_FindNameByAddress(irb->getAddress()).c_str()));
    PyDict_SetItemString(dictInstClass, "threadId", PyInt_FromLong(ap->getThreadID()));

    /* Before the processing, the symbolic element list is empty */
    PyObject *SEList = xPyList_New(0);
    PyDict_SetItemString(dictInstClass, "symbolicElements", SEList);

    /* Create the Instruction class */
    PyObject *instClassName = xPyString_FromString("Instruction");
    PyObject *instClass  = xPyClass_New(NULL, dictInstClass, instClassName);

    /* CallObject needs a tuple. The size of the tuple is the number of arguments.
     * Triton sends only one argument to the callback. This argument is the Instruction
     * class and contains all information. */
    PyObject *args = xPyTuple_New(1);
    PyTuple_SetItem(args, 0, instClass);
    if (PyObject_CallObject(PyTritonOptions::callbackBefore, args) == NULL){
      PyErr_Print();
      exit(1);
    }

    PyDict_Clear(dictInstClass);  /* Clear all items in the dictionary */
    Py_DECREF(SEList);            /* Free the allocated symbolic element list */
    Py_DECREF(dictInstClass);     /* Free the allocated dictionary */
    Py_DECREF(instClassName);     /* Free the allocated Inst class name */
    Py_DECREF(args);              /* Free the allocated tuple */
  }
}

void ProcessingPyConf::applyConfBeforeProcessing(IRBuilder *irb)
{
  this->startAnalysisFromAddr(irb);
  this->stopAnalysisFromAddr(irb);
  this->taintRegFromAddr(irb);
  this->untaintRegFromAddr(irb);
}

<|endoftext|>


<commit_before>/* Copyright 2009 SPARTA, Inc., dba Cobham Analytic Solutions
 *
 * This file is part of WATCHER.
 *
 *     WATCHER is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU Affero General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 *
 *     WATCHER is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU Affero General Public License for more details.
 *
 *     You should have received a copy of the GNU Affero General Public License
 *     along with Watcher.  If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * Connects to a Watcher server and writes the event stream to a KML file suitable for use
 * with Google Earth.
 *
 * @author michael.elkins@cobham.com
 */

#include <unistd.h>
#include <getopt.h>
#include <stdint.h>

#include <cassert>
#include <iostream>
#include <cstdlib>

#include "logger.h"
#include "initConfig.h"
#include "singletonConfig.h"
#include "libwatcher/messageStream.h"
#include "libwatcher/watcherGraph.h"
#include "libwatcher/playbackTimeRange.h"

#define TOOL_NAME "earthWatcher"
DECLARE_GLOBAL_LOGGER(TOOL_NAME);

using namespace watcher;

void write_kml(const WatcherGraph& graph, const std::string& outputFile); // kml.cc

namespace watcher {
    float LayerPadding = 10;
    float Lonoff = 0.0;
    float Latoff = 0.0;
    float Altoff = 0.0;
}

namespace {

//arguments to getopt_long()
const option OPTIONS[] = {
    { "latoff", required_argument, 0, 'a' },
    { "altoff", required_argument, 0, 'A' },
    { "config", required_argument, 0, 'c' },
    { "help", no_argument, 0, 'h' },
    { "output", required_argument, 0, 'o' },
    { "lonoff", required_argument, 0, 'O' },
    { "refresh", required_argument, 0, 'r' },
    { "seek", required_argument, 0, 'S' },
    { "server", required_argument, 0, 's' },
    { "speed", required_argument, 0, 'd' },
    { 0, 0, 0, 0 }
};

const char *CONFIG_FILE = TOOL_NAME ".cfg";
const char *OUTPUT_FILE = "watcher.kml";
const char *PROPERTY_FILE = TOOL_NAME ".log.properties";
const char *DEFAULT_HOST = "127.0.0.1";
const unsigned int DEFAULT_REFRESH = 1; // SECONDS

void usage()
{
    const char *SEP = "\t\t";   // separator for argument/description columns

    std::cout << "usage: earthWatcher [ -h ] [ -c FILE ]\n"
        "  -a, --latoff OFF" << SEP << "translate GPS coordinates relative to a given latitude\n"
        "  -A, --altoff OFF" << SEP << "translate GPS coordinates relative to the given altitude\n"
        "  -c, --config FILE" << SEP << "specify a configuration file (default: " << CONFIG_FILE << ")\n"
        "  -d, --speed SPEED" << SEP << "specify the event playback rate (default: 1.0)\n"
        "  -h, --help\t" << SEP << "display this help message\n"
        "  -o, --output FILE" << SEP << "specifies the output KML file (default: " << OUTPUT_FILE << ")\n"
        "  -O, --lonoff OFF" << SEP << "translate GPS coordinates relative to a given longitude\n"
        "  -r, --refresh SECS" << SEP << "write the the output every SECS seconds (default: " << DEFAULT_REFRESH << ")\n"
        "  -s, --server HOST" << SEP << "connect to the watcher server on the given host (default: " << DEFAULT_HOST << ")\n"
        "  -S, --seek POS" << SEP << "start event playback at timestamp POS (default: -1)\n"
        "\tPOS may be specified relative to the first and last timestamps in the Watcher database by prefixing the offset with + or -\n"
        "\tExample: +5000 means 5 seconds after the first event in the database.\n"
        << std::endl;
}

} // end namespace

int main(int argc, char **argv)
{
    TRACE_ENTER();

    const char *output_file = 0;
    Timestamp start_timestamp = -1 ; // default to EOF (live playback)
    unsigned int refresh = DEFAULT_REFRESH;
    float speed = 1.0;
    bool relativeTS = false; // when true, start_timestamp is relative to first or last event in the Watcher DB
    unsigned int args = 0;
    enum {
        argLayerPadding = (1<<0),
        argLonoff = (1<<1),
        argLatoff = (1<<2),
        argAltoff = (1<<3),
        argOutputFile = (1<<4),
        argServerName = (1<<5)
    };
    std::string outputFile(OUTPUT_FILE);
    std::string serverName(DEFAULT_HOST);

    for (int i; (i = getopt_long(argc, argv, "a:A:hc:d:o:O:r:S:", OPTIONS, 0)) != -1; ) {
        switch (i) {
            case 'c':
                break; //handled by initConfig()

            case 'a':
                Latoff = atof(optarg);
                args |= argLatoff;
                break;

            case 'A':
                Altoff = atof(optarg);
                args |= argAltoff;
                break;

            case 'd':
                speed = atoi(optarg);
                break;

            case 'o': // output-file
                outputFile = optarg;
                args |= argOutputFile;
                break;

            case 'O':
                Lonoff = atoi(optarg);
                args |= argLonoff;
                break;

            case 'r':
                refresh = atoi(optarg);
                break;

            case 'S':
                relativeTS = (optarg[0] == '+' || optarg[0] == '-'); // when +/- is prefix, seek relative to starting/ending event
                start_timestamp = atol(optarg);
                if (start_timestamp == -1)
                    relativeTS = false; // special case for EOF value
                break;

            case 's':
                serverName = optarg;
                args |= argServerName;

            case 'h':
            default:
                usage();
                TRACE_EXIT_RET(EXIT_SUCCESS);
                return EXIT_SUCCESS;
                break;
        }
    }

    libconfig::Config& config = SingletonConfig::instance();
    SingletonConfig::lock();
    std::string configFilename; //filled by initConfig()
    if (! watcher::initConfig(config, argc, argv, configFilename))
        std::cout << "Configuration file not found. Creating new configuration file and using default runtime values." << std::endl;
    SingletonConfig::unlock();

    std::string logConf(PROPERTY_FILE);
    std::string service("watcherd");
    struct {
        const char *configName;
        std::string *value;
        unsigned int bit;
    } ConfigString[] = {
        { "logPropertiesFile", &logConf, 0 },
        { "server", &serverName, argServerName },
        { "service", &service, 0 },
        { "outputFile", &outputFile, argOutputFile },
        { 0, 0, 0 } // terminator
    };

    for (size_t i = 0; ConfigString[i].configName != 0; ++i) {
        if ((args & ConfigString[i].bit) == 0 && !config.lookupValue(ConfigString[i].configName, *ConfigString[i].value)) {
            LOG_INFO("'" << ConfigString[i].configName << "' not found in the configuration file, using default: " << *ConfigString[i].value
                     << " and adding this to the configuration file.");
            config.getRoot().add(ConfigString[i].configName, libconfig::Setting::TypeString) = *ConfigString[i].value;
        }
    }

    LOAD_LOG_PROPS(logConf);
    LOG_INFO("Logger initialized from file \"" << logConf << "\"");

    struct {
        const char *configName;
        float* value;
        unsigned int bit;
    } ConfigFloat[] = {
        { "layerPadding", &LayerPadding, argLayerPadding },
        { "lonOff", &Lonoff, argLonoff },
        { "latOff", &Latoff, argLatoff },
        { "altOff", &Altoff, argAltoff },
        { 0, 0, 0 } // terminator
    };

    for (size_t i = 0; ConfigFloat[i].configName != 0; ++i) {
        if ((args & ConfigFloat[i].bit) == 0 && !config.lookupValue(ConfigFloat[i].configName, *ConfigFloat[i].value)) {
            LOG_INFO("'" << ConfigFloat[i].configName << "' not found in the configuration file, using default: " << *ConfigFloat[i].value
                     << " and adding this to the configuration file.");
            config.getRoot().add(ConfigFloat[i].configName, libconfig::Setting::TypeFloat) = *ConfigFloat[i].value;
        }
    }

    // open a message stream of live events for now
    MessageStreamPtr ms(MessageStream::createNewMessageStream(serverName, service, start_timestamp, speed));
    if (!ms) {
        LOG_FATAL("Unable to create new message stream to server \"" << serverName << "\" using service (or port) \"" << service);
        TRACE_EXIT_RET(EXIT_FAILURE);
        return EXIT_FAILURE;
    }

    if (relativeTS) {
        ms->getMessageTimeRange();
    } else {
        LOG_INFO("Starting event playback");
        ms->startStream();
    }

    srandom(time(0));//we use random() to select the icon below
    WatcherGraph graph;

    unsigned int messageNumber = 0;
    MessagePtr mp;
    time_t last_output = 0; // counter to allow for writing the kml file on a fixed time interval
    bool changed = false;
    bool needTimeRange = relativeTS;

    LOG_INFO("Waiting for events ");
    while (ms->getNextMessage(mp)) {
        // std::cout << "Message #" << (++messageNumber) << ": " << *mp << std::endl;

        if (needTimeRange) {
            PlaybackTimeRangeMessagePtr trp(boost::dynamic_pointer_cast<PlaybackTimeRangeMessage>(mp));
            if (trp.get() != 0) {
                LOG_INFO( "first offset=" << trp->min_ << ", last offset=" << trp->max_ );
                needTimeRange = false;

                Timestamp off = start_timestamp + (( start_timestamp >= 0 ) ? trp->min_ : trp->max_ );
                ms->setStreamTimeStart(off);

                LOG_INFO("Starting event playback");
                ms->startStream();

                continue;
            }
        }

        changed |= graph.updateGraph(mp);

        if (changed) {
            time_t now = time(0);
            if (now - last_output >= refresh) {
                graph.doMaintanence(); // expire stale links
                LOG_DEBUG("writing kml file");
                last_output = now;
                write_kml(graph, outputFile);
            }
            changed = false; // reset flag
        }
    }

    // Save any configuration changes made during the run.
    LOG_INFO("Saving last known configuration to " << configFilename);
    SingletonConfig::lock();
    config.writeFile(configFilename.c_str());

    TRACE_EXIT_RET(0);
    return 0;
}
<commit_msg>earthWatcher: break after parsing 's' option.<commit_after>/* Copyright 2009 SPARTA, Inc., dba Cobham Analytic Solutions
 *
 * This file is part of WATCHER.
 *
 *     WATCHER is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU Affero General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 *
 *     WATCHER is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU Affero General Public License for more details.
 *
 *     You should have received a copy of the GNU Affero General Public License
 *     along with Watcher.  If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * Connects to a Watcher server and writes the event stream to a KML file suitable for use
 * with Google Earth.
 *
 * @author michael.elkins@cobham.com
 */

#include <unistd.h>
#include <getopt.h>
#include <stdint.h>

#include <cassert>
#include <iostream>
#include <cstdlib>

#include "logger.h"
#include "initConfig.h"
#include "singletonConfig.h"
#include "libwatcher/messageStream.h"
#include "libwatcher/watcherGraph.h"
#include "libwatcher/playbackTimeRange.h"

#define TOOL_NAME "earthWatcher"
DECLARE_GLOBAL_LOGGER(TOOL_NAME);

using namespace watcher;

void write_kml(const WatcherGraph& graph, const std::string& outputFile); // kml.cc

namespace watcher {
    float LayerPadding = 10;
    float Lonoff = 0.0;
    float Latoff = 0.0;
    float Altoff = 0.0;
}

namespace {

//arguments to getopt_long()
const option OPTIONS[] = {
    { "latoff", required_argument, 0, 'a' },
    { "altoff", required_argument, 0, 'A' },
    { "config", required_argument, 0, 'c' },
    { "help", no_argument, 0, 'h' },
    { "output", required_argument, 0, 'o' },
    { "lonoff", required_argument, 0, 'O' },
    { "refresh", required_argument, 0, 'r' },
    { "seek", required_argument, 0, 'S' },
    { "server", required_argument, 0, 's' },
    { "speed", required_argument, 0, 'd' },
    { 0, 0, 0, 0 }
};

const char *CONFIG_FILE = TOOL_NAME ".cfg";
const char *OUTPUT_FILE = "watcher.kml";
const char *PROPERTY_FILE = TOOL_NAME ".log.properties";
const char *DEFAULT_HOST = "127.0.0.1";
const unsigned int DEFAULT_REFRESH = 1; // SECONDS

void usage()
{
    const char *SEP = "\t\t";   // separator for argument/description columns

    std::cout << "usage: earthWatcher [ -h ] [ -c FILE ]\n"
        "  -a, --latoff OFF" << SEP << "translate GPS coordinates relative to a given latitude\n"
        "  -A, --altoff OFF" << SEP << "translate GPS coordinates relative to the given altitude\n"
        "  -c, --config FILE" << SEP << "specify a configuration file (default: " << CONFIG_FILE << ")\n"
        "  -d, --speed SPEED" << SEP << "specify the event playback rate (default: 1.0)\n"
        "  -h, --help\t" << SEP << "display this help message\n"
        "  -o, --output FILE" << SEP << "specifies the output KML file (default: " << OUTPUT_FILE << ")\n"
        "  -O, --lonoff OFF" << SEP << "translate GPS coordinates relative to a given longitude\n"
        "  -r, --refresh SECS" << SEP << "write the the output every SECS seconds (default: " << DEFAULT_REFRESH << ")\n"
        "  -s, --server HOST" << SEP << "connect to the watcher server on the given host (default: " << DEFAULT_HOST << ")\n"
        "  -S, --seek POS" << SEP << "start event playback at timestamp POS (default: -1)\n"
        "\tPOS may be specified relative to the first and last timestamps in the Watcher database by prefixing the offset with + or -\n"
        "\tExample: +5000 means 5 seconds after the first event in the database.\n"
        << std::endl;
}

} // end namespace

int main(int argc, char **argv)
{
    TRACE_ENTER();

    const char *output_file = 0;
    Timestamp start_timestamp = -1 ; // default to EOF (live playback)
    unsigned int refresh = DEFAULT_REFRESH;
    float speed = 1.0;
    bool relativeTS = false; // when true, start_timestamp is relative to first or last event in the Watcher DB
    unsigned int args = 0;
    enum {
        argLayerPadding = (1<<0),
        argLonoff = (1<<1),
        argLatoff = (1<<2),
        argAltoff = (1<<3),
        argOutputFile = (1<<4),
        argServerName = (1<<5)
    };
    std::string outputFile(OUTPUT_FILE);
    std::string serverName(DEFAULT_HOST);

    for (int i; (i = getopt_long(argc, argv, "a:A:hc:d:o:O:r:S:", OPTIONS, 0)) != -1; ) {
        switch (i) {
            case 'c':
                break; //handled by initConfig()

            case 'a':
                Latoff = atof(optarg);
                args |= argLatoff;
                break;

            case 'A':
                Altoff = atof(optarg);
                args |= argAltoff;
                break;

            case 'd':
                speed = atoi(optarg);
                break;

            case 'o': // output-file
                outputFile = optarg;
                args |= argOutputFile;
                break;

            case 'O':
                Lonoff = atoi(optarg);
                args |= argLonoff;
                break;

            case 'r':
                refresh = atoi(optarg);
                break;

            case 'S':
                relativeTS = (optarg[0] == '+' || optarg[0] == '-'); // when +/- is prefix, seek relative to starting/ending event
                start_timestamp = atol(optarg);
                if (start_timestamp == -1)
                    relativeTS = false; // special case for EOF value
                break;

            case 's':
                serverName = optarg;
                args |= argServerName;
                break;

            case 'h':
            default:
                usage();
                TRACE_EXIT_RET(EXIT_SUCCESS);
                return EXIT_SUCCESS;
                break;
        }
    }

    libconfig::Config& config = SingletonConfig::instance();
    SingletonConfig::lock();
    std::string configFilename; //filled by initConfig()
    if (! watcher::initConfig(config, argc, argv, configFilename))
        std::cout << "Configuration file not found. Creating new configuration file and using default runtime values." << std::endl;
    SingletonConfig::unlock();

    std::string logConf(PROPERTY_FILE);
    std::string service("watcherd");
    struct {
        const char *configName;
        std::string *value;
        unsigned int bit;
    } ConfigString[] = {
        { "logPropertiesFile", &logConf, 0 },
        { "server", &serverName, argServerName },
        { "service", &service, 0 },
        { "outputFile", &outputFile, argOutputFile },
        { 0, 0, 0 } // terminator
    };

    for (size_t i = 0; ConfigString[i].configName != 0; ++i) {
        if ((args & ConfigString[i].bit) == 0 && !config.lookupValue(ConfigString[i].configName, *ConfigString[i].value)) {
            LOG_INFO("'" << ConfigString[i].configName << "' not found in the configuration file, using default: " << *ConfigString[i].value
                     << " and adding this to the configuration file.");
            config.getRoot().add(ConfigString[i].configName, libconfig::Setting::TypeString) = *ConfigString[i].value;
        }
    }

    LOAD_LOG_PROPS(logConf);
    LOG_INFO("Logger initialized from file \"" << logConf << "\"");

    struct {
        const char *configName;
        float* value;
        unsigned int bit;
    } ConfigFloat[] = {
        { "layerPadding", &LayerPadding, argLayerPadding },
        { "lonOff", &Lonoff, argLonoff },
        { "latOff", &Latoff, argLatoff },
        { "altOff", &Altoff, argAltoff },
        { 0, 0, 0 } // terminator
    };

    for (size_t i = 0; ConfigFloat[i].configName != 0; ++i) {
        if ((args & ConfigFloat[i].bit) == 0 && !config.lookupValue(ConfigFloat[i].configName, *ConfigFloat[i].value)) {
            LOG_INFO("'" << ConfigFloat[i].configName << "' not found in the configuration file, using default: " << *ConfigFloat[i].value
                     << " and adding this to the configuration file.");
            config.getRoot().add(ConfigFloat[i].configName, libconfig::Setting::TypeFloat) = *ConfigFloat[i].value;
        }
    }

    // open a message stream of live events for now
    MessageStreamPtr ms(MessageStream::createNewMessageStream(serverName, service, start_timestamp, speed));
    if (!ms) {
        LOG_FATAL("Unable to create new message stream to server \"" << serverName << "\" using service (or port) \"" << service);
        TRACE_EXIT_RET(EXIT_FAILURE);
        return EXIT_FAILURE;
    }

    if (relativeTS) {
        ms->getMessageTimeRange();
    } else {
        LOG_INFO("Starting event playback");
        ms->startStream();
    }

    srandom(time(0));//we use random() to select the icon below
    WatcherGraph graph;

    unsigned int messageNumber = 0;
    MessagePtr mp;
    time_t last_output = 0; // counter to allow for writing the kml file on a fixed time interval
    bool changed = false;
    bool needTimeRange = relativeTS;

    LOG_INFO("Waiting for events ");
    while (ms->getNextMessage(mp)) {
        // std::cout << "Message #" << (++messageNumber) << ": " << *mp << std::endl;

        if (needTimeRange) {
            PlaybackTimeRangeMessagePtr trp(boost::dynamic_pointer_cast<PlaybackTimeRangeMessage>(mp));
            if (trp.get() != 0) {
                LOG_INFO( "first offset=" << trp->min_ << ", last offset=" << trp->max_ );
                needTimeRange = false;

                Timestamp off = start_timestamp + (( start_timestamp >= 0 ) ? trp->min_ : trp->max_ );
                ms->setStreamTimeStart(off);

                LOG_INFO("Starting event playback");
                ms->startStream();

                continue;
            }
        }

        changed |= graph.updateGraph(mp);

        if (changed) {
            time_t now = time(0);
            if (now - last_output >= refresh) {
                graph.doMaintanence(); // expire stale links
                LOG_DEBUG("writing kml file");
                last_output = now;
                write_kml(graph, outputFile);
            }
            changed = false; // reset flag
        }
    }

    // Save any configuration changes made during the run.
    LOG_INFO("Saving last known configuration to " << configFilename);
    SingletonConfig::lock();
    config.writeFile(configFilename.c_str());

    TRACE_EXIT_RET(0);
    return 0;
}
<|endoftext|>


<commit_before>/*******************************************************************************
 * Copyright (c) 2014, 2016  IBM Corporation and others
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *******************************************************************************/

#ifndef SystemModelInBuilding_hpp
#define SystemModelInBuilding_hpp

#include <stdio.h>
#include "RandomWalker.hpp"
#include "RandomWalkerMotion.hpp"
#include "Building.hpp"

namespace loc{

    class SystemModelInBuildingProperty{
        double probabilityUp_ = 0.25;
        double probabilityDown_ = 0.25;
        double probabilityStay_ = 0.5;

        double probabilityFloorJump_ = 0.0;

        double wallCrossingAliveRate_ = 1.0; // fixed value
        double maxIncidenceAngle_ = 45/180*M_PI;

        // Field velocity rate
        double velocityRateFloor_ = 1.0;
        double velocityRateStair_ = 0.5;
        double velocityRateElevator_ = 0.5;
        double velocityRateEscalator_ = 0.5;

        double relativeVelocityEscalator_ = 0.4;

        double weightDecayRate_ = 0.9;

        int maxTrial_ = 1; // fixed value

    public:

        using Ptr = std::shared_ptr<SystemModelInBuildingProperty>;

        SystemModelInBuildingProperty& probabilityUp(double probabilityUp);
        SystemModelInBuildingProperty& probabilityDown(double probabilityDown);
        SystemModelInBuildingProperty& probabilityStay(double probabilityStay);
        SystemModelInBuildingProperty& wallCrossingAliveRate(double wallCrossingAliveRate);
        SystemModelInBuildingProperty& maxIncidenceAngle(double maxIncidenceAngle);

        SystemModelInBuildingProperty& velocityRateFloor(double velocityRateFloor);
        SystemModelInBuildingProperty& velocityRateStair(double velocityRateStair);
        SystemModelInBuildingProperty& velocityRateElevator(double velocityRateElevator);
        SystemModelInBuildingProperty& velocityRateEscalator(double velocityRateEscalator);
        SystemModelInBuildingProperty& relativeVelocityEscalator(double relativeVelocityEscalator);

        SystemModelInBuildingProperty& weightDecayRate(double weightDecayRate);
        double probabilityUp() const;
        double probabilityDown() const;
        double probabilityStay() const;
        double wallCrossingAliveRate() const;
        double maxIncidenceAngle() const;
        double velocityRateFloor() const;
        double velocityRateStair() const;
        double velocityRateElevator() const;
        double velocityRateEscalator() const;
        double relativeVelocityEscalator() const;
        double weightDecayRate() const;
        int maxTrial() const;

        SystemModelInBuildingProperty& probabilityFloorJump(double probability);
        double probabilityFloorJump() const;
    };

    template<class Tstate, class Tinput>
    class SystemModelInBuilding: public SystemModel<Tstate, Tinput>{

    public:
        using SystemModelT = SystemModel<Tstate, Tinput>;
        using Ptr = std::shared_ptr<SystemModelInBuilding>;

    private:
        RandomGenerator mRandomGenerator;
        typename SystemModel<Tstate, Tinput>::Ptr mSysModel;
        Building::Ptr mBuilding;
        SystemModelInBuildingProperty::Ptr mProperty;

        Tstate moveOnElevator(const Tstate& state, Tinput input);
        Tstate moveOnStair(const Tstate& state, Tinput input);
        Tstate moveOnEscalator(const Tstate& state, Tinput input);
        Tstate moveOnFloor(const Tstate& state, Tinput input);
        Tstate moveOnFloorRetry(const Tstate& state, const Tstate& stateNew,  Tinput input);
        Tstate moveFloorJump(const Tstate& state, Tinput input);

    public:

        SystemModelInBuilding() = default;
        virtual ~SystemModelInBuilding() = default;

        SystemModelInBuilding(typename SystemModelT::Ptr poseRandomWalker, Building::Ptr building, SystemModelInBuildingProperty::Ptr property);

        SystemModelInBuilding& systemModel(typename SystemModelT::Ptr sysModel);
        SystemModelInBuilding& building(Building::Ptr building);
        SystemModelInBuilding& property(SystemModelInBuildingProperty::Ptr property);

        Tstate predict(Tstate state, Tinput input) override;
        std::vector<Tstate> predict(std::vector<Tstate> states, Tinput input) override;

        virtual void notifyObservationUpdated() override;

    };

    // This class is retained for compatibility.
    using PoseRandomWalkerInBuildingProperty = SystemModelInBuildingProperty;

    class PoseRandomWalkerInBuilding: public SystemModelInBuilding<State, SystemModelInput>{

    public:
        using Ptr = std::shared_ptr<PoseRandomWalkerInBuilding>;

        virtual ~PoseRandomWalkerInBuilding() = default;

        virtual void poseRandomWalkerInBuildingProperty(SystemModelInBuildingProperty::Ptr property){
            SystemModelInBuilding<State, SystemModelInput>::property(property);
        }

        virtual void poseRandomWalker(typename SystemModel<State, SystemModelInput>::Ptr sysModel){
            SystemModelInBuilding<State, SystemModelInput>::systemModel(sysModel);
        }

    };
}

#endif /* SystemModelInBuilding_hpp */
<commit_msg>Updated default value of velocity parameters<commit_after>/*******************************************************************************
 * Copyright (c) 2014, 2016  IBM Corporation and others
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *******************************************************************************/

#ifndef SystemModelInBuilding_hpp
#define SystemModelInBuilding_hpp

#include <stdio.h>
#include "RandomWalker.hpp"
#include "RandomWalkerMotion.hpp"
#include "Building.hpp"

namespace loc{

    class SystemModelInBuildingProperty{
        double probabilityUp_ = 0.1;
        double probabilityDown_ = 0.1;
        double probabilityStay_ = 0.8;

        double probabilityFloorJump_ = 0.0;

        double wallCrossingAliveRate_ = 1.0; // fixed value
        double maxIncidenceAngle_ = 45/180*M_PI;

        // Field velocity rate
        double velocityRateFloor_ = 1.0;
        double velocityRateStair_ = 0.5;
        double velocityRateElevator_ = 0.5;
        double velocityRateEscalator_ = 0.5;

        double relativeVelocityEscalator_ = 0.4;

        double weightDecayRate_ = 0.9;

        int maxTrial_ = 1; // fixed value

    public:

        using Ptr = std::shared_ptr<SystemModelInBuildingProperty>;

        SystemModelInBuildingProperty& probabilityUp(double probabilityUp);
        SystemModelInBuildingProperty& probabilityDown(double probabilityDown);
        SystemModelInBuildingProperty& probabilityStay(double probabilityStay);
        SystemModelInBuildingProperty& wallCrossingAliveRate(double wallCrossingAliveRate);
        SystemModelInBuildingProperty& maxIncidenceAngle(double maxIncidenceAngle);

        SystemModelInBuildingProperty& velocityRateFloor(double velocityRateFloor);
        SystemModelInBuildingProperty& velocityRateStair(double velocityRateStair);
        SystemModelInBuildingProperty& velocityRateElevator(double velocityRateElevator);
        SystemModelInBuildingProperty& velocityRateEscalator(double velocityRateEscalator);
        SystemModelInBuildingProperty& relativeVelocityEscalator(double relativeVelocityEscalator);

        SystemModelInBuildingProperty& weightDecayRate(double weightDecayRate);
        double probabilityUp() const;
        double probabilityDown() const;
        double probabilityStay() const;
        double wallCrossingAliveRate() const;
        double maxIncidenceAngle() const;
        double velocityRateFloor() const;
        double velocityRateStair() const;
        double velocityRateElevator() const;
        double velocityRateEscalator() const;
        double relativeVelocityEscalator() const;
        double weightDecayRate() const;
        int maxTrial() const;

        SystemModelInBuildingProperty& probabilityFloorJump(double probability);
        double probabilityFloorJump() const;
    };

    template<class Tstate, class Tinput>
    class SystemModelInBuilding: public SystemModel<Tstate, Tinput>{

    public:
        using SystemModelT = SystemModel<Tstate, Tinput>;
        using Ptr = std::shared_ptr<SystemModelInBuilding>;

    private:
        RandomGenerator mRandomGenerator;
        typename SystemModel<Tstate, Tinput>::Ptr mSysModel;
        Building::Ptr mBuilding;
        SystemModelInBuildingProperty::Ptr mProperty;

        Tstate moveOnElevator(const Tstate& state, Tinput input);
        Tstate moveOnStair(const Tstate& state, Tinput input);
        Tstate moveOnEscalator(const Tstate& state, Tinput input);
        Tstate moveOnFloor(const Tstate& state, Tinput input);
        Tstate moveOnFloorRetry(const Tstate& state, const Tstate& stateNew,  Tinput input);
        Tstate moveFloorJump(const Tstate& state, Tinput input);

    public:

        SystemModelInBuilding() = default;
        virtual ~SystemModelInBuilding() = default;

        SystemModelInBuilding(typename SystemModelT::Ptr poseRandomWalker, Building::Ptr building, SystemModelInBuildingProperty::Ptr property);

        SystemModelInBuilding& systemModel(typename SystemModelT::Ptr sysModel);
        SystemModelInBuilding& building(Building::Ptr building);
        SystemModelInBuilding& property(SystemModelInBuildingProperty::Ptr property);

        Tstate predict(Tstate state, Tinput input) override;
        std::vector<Tstate> predict(std::vector<Tstate> states, Tinput input) override;

        virtual void notifyObservationUpdated() override;

    };

    // This class is retained for compatibility.
    using PoseRandomWalkerInBuildingProperty = SystemModelInBuildingProperty;

    class PoseRandomWalkerInBuilding: public SystemModelInBuilding<State, SystemModelInput>{

    public:
        using Ptr = std::shared_ptr<PoseRandomWalkerInBuilding>;

        virtual ~PoseRandomWalkerInBuilding() = default;

        virtual void poseRandomWalkerInBuildingProperty(SystemModelInBuildingProperty::Ptr property){
            SystemModelInBuilding<State, SystemModelInput>::property(property);
        }

        virtual void poseRandomWalker(typename SystemModel<State, SystemModelInput>::Ptr sysModel){
            SystemModelInBuilding<State, SystemModelInput>::systemModel(sysModel);
        }

    };
}

#endif /* SystemModelInBuilding_hpp */
<|endoftext|>


<commit_before>// Copyright (C) 2013 The Regents of the University of California (Regents).
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials provided
//       with the distribution.
//
//     * Neither the name of The Regents or University of California nor the
//       names of its contributors may be used to endorse or promote products
//       derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Please contact the author of this library if you have any questions.
// Author: Chris Sweeney (cmsweeney@cs.ucsb.edu)

#include "theia/image/keypoint_detector/sift_detector.h"

extern "C" {
#include <vl/sift.h>
}

#include <vector>

#include "theia/image/image.h"
#include "theia/image/keypoint_detector/keypoint.h"

namespace theia {
SiftDetector::~SiftDetector() {
  if (sift_filter_ != nullptr)
    vl_sift_delete(sift_filter_);
}

bool SiftDetector::DetectKeypoints(const FloatImage& image,
                                   std::vector<Keypoint>* keypoints) {
  // If the filter has been set, but is not usable for the input image (i.e. the
  // width and height are different) then we must make a new filter. Adding this
  // statement will save the function from regenerating the filter for
  // successive calls with images of the same size (e.g. a video sequence).
  if (sift_filter_ == nullptr || (sift_filter_->width != image.Cols() ||
                                  sift_filter_->height != image.Rows())) {
    vl_sift_delete(sift_filter_);
    sift_filter_ = vl_sift_new(image.Cols(), image.Rows(),
                               sift_params_.num_octaves,
                               sift_params_.num_levels,
                               sift_params_.first_octave);
    vl_sift_set_edge_thresh(sift_filter_, sift_params_.edge_threshold);
    vl_sift_set_peak_thresh(sift_filter_, sift_params_.peak_threshold);
  }

  // The VLFeat functions take in a non-const image pointer so that it can
  // calculate gaussian pyramids. Obviously, we do not want to break our const
  // input, so the best solution (for now) is to copy the image.
  FloatImage mutable_image(image.AsGrayscaleImage());

  // Calculate the first octave to process.
  int vl_status = vl_sift_process_first_octave(sift_filter_,
                                               mutable_image.Data());
  // Reserve an amount that is slightly larger than what a typical detector
  // would return.
  keypoints->reserve(2000);

  // Process octaves until you can't anymore.
  while (vl_status != VL_ERR_EOF) {
    // Detect the keypoints.
    vl_sift_detect(sift_filter_);
    // Get the keypoints.
    const VlSiftKeypoint* vl_keypoints = vl_sift_get_keypoints(sift_filter_);
    int num_keypoints = vl_sift_get_nkeypoints(sift_filter_);

    for (int i = 0; i < num_keypoints; i++) {
      // Calculate (up to 4) orientations of the keypoint.
      double angles[4];
      int num_angles = vl_sift_calc_keypoint_orientations(sift_filter_,
                                                          angles,
                                                          &vl_keypoints[i]);
      // If upright sift is enabled, only use the first keypoint at a given
      // pixel location.
      if (sift_params_.upright_sift && num_angles > 1) {
        num_angles = 1;
      }
      for (int j = 0; j < num_angles; j++) {
        Keypoint keypoint(vl_keypoints[i].x, vl_keypoints[i].y, Keypoint::SIFT);
        keypoint.set_scale(vl_keypoints[i].sigma);
        keypoint.set_orientation(angles[j]);
        keypoints->push_back(keypoint);
      }
    }
    // Attempt to process the next octave.
    vl_status = vl_sift_process_next_octave(sift_filter_);
  }
  return true;
}
}  // namespace theia
<commit_msg>Disable array-bounds diagnostics<commit_after>// Copyright (C) 2013 The Regents of the University of California (Regents).
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials provided
//       with the distribution.
//
//     * Neither the name of The Regents or University of California nor the
//       names of its contributors may be used to endorse or promote products
//       derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Please contact the author of this library if you have any questions.
// Author: Chris Sweeney (cmsweeney@cs.ucsb.edu)

#include "theia/image/keypoint_detector/sift_detector.h"

extern "C" {
#include <vl/sift.h>
}

#include <vector>

#include "theia/image/image.h"
#include "theia/image/keypoint_detector/keypoint.h"

namespace theia {
SiftDetector::~SiftDetector() {
  if (sift_filter_ != nullptr)
    vl_sift_delete(sift_filter_);
}

bool SiftDetector::DetectKeypoints(const FloatImage& image,
                                   std::vector<Keypoint>* keypoints) {
  // If the filter has been set, but is not usable for the input image (i.e. the
  // width and height are different) then we must make a new filter. Adding this
  // statement will save the function from regenerating the filter for
  // successive calls with images of the same size (e.g. a video sequence).
  if (sift_filter_ == nullptr || (sift_filter_->width != image.Cols() ||
                                  sift_filter_->height != image.Rows())) {
    vl_sift_delete(sift_filter_);
    sift_filter_ = vl_sift_new(image.Cols(), image.Rows(),
                               sift_params_.num_octaves,
                               sift_params_.num_levels,
                               sift_params_.first_octave);
    vl_sift_set_edge_thresh(sift_filter_, sift_params_.edge_threshold);
    vl_sift_set_peak_thresh(sift_filter_, sift_params_.peak_threshold);
  }

  // The VLFeat functions take in a non-const image pointer so that it can
  // calculate gaussian pyramids. Obviously, we do not want to break our const
  // input, so the best solution (for now) is to copy the image.
  FloatImage mutable_image(image.AsGrayscaleImage());

  // Calculate the first octave to process.
  int vl_status = vl_sift_process_first_octave(sift_filter_,
                                               mutable_image.Data());
  // Reserve an amount that is slightly larger than what a typical detector
  // would return.
  keypoints->reserve(2000);

  // Process octaves until you can't anymore.
  while (vl_status != VL_ERR_EOF) {
    // Detect the keypoints.
    vl_sift_detect(sift_filter_);
    // Get the keypoints.
    const VlSiftKeypoint* vl_keypoints = vl_sift_get_keypoints(sift_filter_);
    int num_keypoints = vl_sift_get_nkeypoints(sift_filter_);

    for (int i = 0; i < num_keypoints; i++) {
      // Calculate (up to 4) orientations of the keypoint.
      double angles[4];
      int num_angles = vl_sift_calc_keypoint_orientations(sift_filter_,
                                                          angles,
                                                          &vl_keypoints[i]);
      // If upright sift is enabled, only use the first keypoint at a given
      // pixel location.
      if (sift_params_.upright_sift && num_angles > 1) {
        num_angles = 1;
      }
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Warray-bounds"
      for (int j = 0; j < num_angles; j++) {
        Keypoint keypoint(vl_keypoints[i].x, vl_keypoints[i].y, Keypoint::SIFT);
        keypoint.set_scale(vl_keypoints[i].sigma);
        keypoint.set_orientation(angles[j]);
        keypoints->push_back(keypoint);
      }
#pragma GCC diagnostic pop
    }
    // Attempt to process the next octave.
    vl_status = vl_sift_process_next_octave(sift_filter_);
  }
  return true;
}
}  // namespace theia
<|endoftext|>