<commit_before>/*
    Copyright (c) 2009 Kevin Ottens <ervin@kde.org>

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

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

#include "widget.h"

#include <akonadi/collection.h>
#include <akonadi/item.h>
#include <akonadi/itemcopyjob.h>
#include <akonadi/itemmovejob.h>

#include "storagemodel.h"
#include "core/messageitem.h"
#include "core/view.h"

#include <QtCore/QTimer>

#include <QtGui/QAction>
#include <QtGui/QApplication>
#include <QtGui/QDrag>
#include <QtGui/QDragMoveEvent>
#include <QtGui/QDropEvent>

#include <KDE/KDebug>
#include <KDE/KIcon>
#include <KDE/KIconLoader>
#include <KDE/KLocale>
#include <KDE/KMenu>

namespace MessageList
{

class Widget::Private
{
public:
  Private( Widget *owner )
    : q( owner ) { }

  Akonadi::Item::List selectionAsItems() const;
  Akonadi::Item itemForRow( int row ) const;

  Widget * const q;

  int mLastSelectedMessage;
};

} // namespace MessageList

using namespace MessageList;
using namespace Akonadi;

struct DragPayload
{
  QList<Collection::Id> sourceCollections;
  QList<Item::Id> items;
  bool readOnly;

  DragPayload() : readOnly( false ) { }

  static QString mimeType()
  {
    return "x-akonadi-drag/message-list";
  }
};

QDataStream &operator<<(QDataStream &stream, const DragPayload &payload)
{
  stream << payload.sourceCollections;
  stream << payload.items;
  stream << payload.readOnly;

  return stream;
}

QDataStream &operator>>(QDataStream &stream, DragPayload &payload)
{
  stream >> payload.sourceCollections;
  stream >> payload.items;
  stream >> payload.readOnly;

  return stream;
}

Widget::Widget( QWidget *parent )
  : Core::Widget( parent ), d( new Private( this ) )
{
  QTimer::singleShot( 0, this, SLOT( populateStatusFilterCombo() ) );
}

Widget::~Widget()
{
}

bool Widget::canAcceptDrag( const QDragMoveEvent * e )
{
  Collection::List collections = static_cast<const StorageModel*>( storageModel() )->displayedCollections();

  if ( collections.size()!=1 )
    return false; // no folder here or too many (in case we can't decide where the drop will end)

  Collection c = collections.first();

  if ( ( c.rights() & Collection::CanCreateItem ) == 0 )
    return false; // no way to drag into

  if ( !e->mimeData()->hasFormat( DragPayload::mimeType() ) )
    return false; // no way to decode it

  DragPayload payload;
  QDataStream stream( e->mimeData()->data( DragPayload::mimeType() ) );
  stream >> payload;

  foreach ( Collection::Id id, payload.sourceCollections ) {
    if ( id == c.id() ) {
      return false;
    }
  }

  return true;
}

bool Widget::selectNextMessageItem( MessageList::Core::MessageTypeFilter messageTypeFilter,
                                    MessageList::Core::ExistingSelectionBehaviour existingSelectionBehaviour,
                                    bool centerItem,
                                    bool loop )
{
  return view()->selectNextMessageItem( messageTypeFilter, existingSelectionBehaviour, centerItem, loop );
}

bool Widget::selectPreviousMessageItem( MessageList::Core::MessageTypeFilter messageTypeFilter,
                                        MessageList::Core::ExistingSelectionBehaviour existingSelectionBehaviour,
                                        bool centerItem,
                                        bool loop )
{
  return view()->selectPreviousMessageItem( messageTypeFilter, existingSelectionBehaviour, centerItem, loop );
}

bool Widget::focusNextMessageItem( MessageList::Core::MessageTypeFilter messageTypeFilter, bool centerItem, bool loop )
{
  return view()->focusNextMessageItem( messageTypeFilter, centerItem, loop );
}

bool Widget::focusPreviousMessageItem( MessageList::Core::MessageTypeFilter messageTypeFilter, bool centerItem, bool loop )
{
  return view()->focusNextMessageItem( messageTypeFilter, centerItem, loop );
}

void Widget::selectFocusedMessageItem( bool centerItem )
{
  view()->selectFocusedMessageItem( centerItem );
}

bool Widget::selectFirstMessageItem( MessageList::Core::MessageTypeFilter messageTypeFilter, bool centerItem )
{
  return view()->selectFirstMessageItem( messageTypeFilter, centerItem );
}

void Widget::selectAll()
{
  view()->setAllGroupsExpanded( true );
  view()->selectAll();
}

void Widget::viewMessageSelected( MessageList::Core::MessageItem *msg )
{
  int row = -1;
  if ( msg ) {
    row = msg->currentModelIndexRow();
  }

  if ( !msg || !msg->isValid() || !storageModel() ) {
    d->mLastSelectedMessage = -1;
    emit messageSelected( Item() );
    return;
  }

  Q_ASSERT( row >= 0 );

  d->mLastSelectedMessage = row;

  emit messageSelected( d->itemForRow( row ) ); // this MAY be null
}

void Widget::viewMessageActivated( MessageList::Core::MessageItem *msg )
{
  Q_ASSERT( msg ); // must not be null
  Q_ASSERT( storageModel() );

  if ( !msg->isValid() ) {
    return;
  }

  int row = msg->currentModelIndexRow();
  Q_ASSERT( row >= 0 );

  // The assert below may fail when quickly opening and closing a non-selected thread.
  // This will actually activate the item without selecting it...
  //Q_ASSERT( d->mLastSelectedMessage == row );

  if ( d->mLastSelectedMessage != row ) {
    // Very ugly. We are activating a non selected message.
    // This is very likely a double click on the plus sign near a thread leader.
    // Dealing with mLastSelectedMessage here would be expensive: it would involve releasing the last selected,
    // emitting signals, handling recursion... ugly.
    // We choose a very simple solution: double clicking on the plus sign near a thread leader does
    // NOT activate the message (i.e open it in a toplevel window) if it isn't previously selected.
    return;
  }

  emit messageActivated( d->itemForRow( row ) ); // this MAY be null
}

void Widget::viewSelectionChanged()
{
  emit selectionChanged();
  if ( !currentMessageItem() ) {
    emit messageSelected( Item() );
  }
}

void Widget::viewMessageListContextPopupRequest( const QList< MessageList::Core::MessageItem * > &selectedItems, const QPoint &globalPos )
{
  //FIXME: To implement once the other infrastructure is ready for a KMail independent implementation
  kWarning() << "Needs to be reimplemented";
}

void Widget::viewMessageStatusChangeRequest( MessageList::Core::MessageItem *msg, const KPIM::MessageStatus &set, const KPIM::MessageStatus &clear )
{
  Q_ASSERT( msg ); // must not be null
  Q_ASSERT( storageModel() );

  if ( !msg->isValid() ) {
    return;
  }

  int row = msg->currentModelIndexRow();
  Q_ASSERT( row >= 0 );

  Item item = d->itemForRow( row );
  Q_ASSERT( item.isValid() );

  emit messageStatusChangeRequest( item, set, clear );
}

void Widget::viewGroupHeaderContextPopupRequest( MessageList::Core::GroupHeaderItem *ghi, const QPoint &globalPos )
{
  Q_UNUSED( ghi );

  KMenu menu( this );

  QAction *act;

  menu.addSeparator();

  act = menu.addAction( i18n( "Expand All Groups" ) );
  connect( act, SIGNAL( triggered( bool ) ),
           view(), SLOT( slotExpandAllGroups() ) );

  act = menu.addAction( i18n( "Collapse All Groups" ) );
  connect( act, SIGNAL( triggered( bool ) ),
           view(), SLOT( slotCollapseAllGroups() ) );

  menu.exec( globalPos );
}

void Widget::viewDragEnterEvent( QDragEnterEvent *e )
{
  if ( !canAcceptDrag( e ) ) {
    e->ignore();
    return;
  }

  e->accept();
}

void Widget::viewDragMoveEvent( QDragMoveEvent *e )
{
  if ( !canAcceptDrag( e ) ) {
    e->ignore();
    return;
  }

  e->accept();
}

enum DragMode
{
  DragCopy,
  DragMove,
  DragCancel
};

void Widget::viewDropEvent( QDropEvent *e )
{
  Collection::List collections = static_cast<const StorageModel*>( storageModel() )->displayedCollections();

  if ( collections.size()!=1 || !e->mimeData()->hasFormat( DragPayload::mimeType() ) ) {
    // no folder here or too many (in case we can't decide where the drop will end), or we can't decode
    e->ignore();
    return;
  }

  DragPayload payload;
  QDataStream stream( e->mimeData()->data( DragPayload::mimeType() ) );
  stream >> payload;

  if ( payload.items.isEmpty() ) {
    kWarning() << "Could not decode drag data!";
    e->ignore();
    return;
  }

  e->accept();

  int action;
  if ( payload.readOnly ) {
    action = DragCopy;
  } else {
    action = DragCancel;
    int keybstate = QApplication::keyboardModifiers();
    if ( keybstate & Qt::CTRL ) {
      action = DragCopy;

    } else if ( keybstate & Qt::SHIFT ) {
      action = DragMove;

    } else {
      // FIXME: This code is duplicated almost exactly in FolderView... shouldn't we share ?
      KMenu menu;
      QAction *moveAction = menu.addAction( KIcon( "go-jump"), i18n( "&Move Here" ) );
      QAction *copyAction = menu.addAction( KIcon( "edit-copy" ), i18n( "&Copy Here" ) );
      menu.addSeparator();
      menu.addAction( KIcon( "dialog-cancel" ), i18n( "C&ancel" ) );

      QAction *menuChoice = menu.exec( QCursor::pos() );
      if ( menuChoice == moveAction ) {
        action = DragMove;
      } else if ( menuChoice == copyAction ) {
        action = DragCopy;
      } else {
        action = DragCancel;
      }
    }
  }

  Collection target = collections.first();
  Item::List items;
  foreach ( Item::Id id, payload.items ) {
    items << Item( id );
  }

  if ( action == DragCopy ) {
    new ItemCopyJob( items, target, this );
  } else if ( action == DragMove ) {
    new ItemMoveJob( items, target, this );
  }
}

void Widget::viewStartDragRequest()
{
  Collection::List collections = static_cast<const StorageModel*>( storageModel() )->displayedCollections();

  if ( collections.isEmpty() )
    return; // no folder here

  QList<Item> items = d->selectionAsItems();
  if ( items.isEmpty() )
    return;

  DragPayload payload;

  foreach ( const Collection c, collections ) {
    payload.sourceCollections << c.id();
    // We won't be able to remove items from this collection
    if ( ( c.rights() & Collection::CanDeleteItem ) == 0 ) {
      // So the drag will be read-only
      payload.readOnly = true;
    }
  }

  foreach ( const Item i, items ) {
    payload.items << i.id();
  }

  QByteArray data;
  {
    QDataStream stream( &data, QIODevice::WriteOnly );
    stream << payload;
  }

  QMimeData *mimeData = new QMimeData;
  mimeData->setData( DragPayload::mimeType(), data );

  QDrag *drag = new QDrag( view()->viewport() );
  drag->setMimeData( mimeData );

  // Set pixmap
  QPixmap pixmap;
  if( items.size() == 1 ) {
    pixmap = QPixmap( DesktopIcon("mail-message", KIconLoader::SizeSmall) );
  } else {
    pixmap = QPixmap( DesktopIcon("document-multiple", KIconLoader::SizeSmall) );
  }

  // Calculate hotspot (as in Konqueror)
  if( !pixmap.isNull() ) {
    drag->setHotSpot( QPoint( pixmap.width() / 2, pixmap.height() / 2 ) );
    drag->setPixmap( pixmap );
  }

  if ( payload.readOnly )
    drag->exec( Qt::CopyAction );
  else
    drag->exec( Qt::CopyAction | Qt::MoveAction );
}

Item::List Widget::Private::selectionAsItems() const
{
  Item::List res;
  QList<Core::MessageItem *> selection = q->view()->selectionAsMessageItemList();

  foreach ( Core::MessageItem *mi, selection ) {
    Item i = itemForRow( mi->currentModelIndexRow() );
    Q_ASSERT( i.isValid() );
    res << i;
  }

  return res;
}

Item Widget::Private::itemForRow( int row ) const
{
  return static_cast<const StorageModel*>( q->storageModel() )->itemForRow( row );
}
<commit_msg>Fix mem leak<commit_after>/*
    Copyright (c) 2009 Kevin Ottens <ervin@kde.org>

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

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

#include "widget.h"

#include <akonadi/collection.h>
#include <akonadi/item.h>
#include <akonadi/itemcopyjob.h>
#include <akonadi/itemmovejob.h>

#include "storagemodel.h"
#include "core/messageitem.h"
#include "core/view.h"

#include <QtCore/QTimer>

#include <QtGui/QAction>
#include <QtGui/QApplication>
#include <QtGui/QDrag>
#include <QtGui/QDragMoveEvent>
#include <QtGui/QDropEvent>

#include <KDE/KDebug>
#include <KDE/KIcon>
#include <KDE/KIconLoader>
#include <KDE/KLocale>
#include <KDE/KMenu>

namespace MessageList
{

class Widget::Private
{
public:
  Private( Widget *owner )
    : q( owner ) { }

  Akonadi::Item::List selectionAsItems() const;
  Akonadi::Item itemForRow( int row ) const;

  Widget * const q;

  int mLastSelectedMessage;
};

} // namespace MessageList

using namespace MessageList;
using namespace Akonadi;

struct DragPayload
{
  QList<Collection::Id> sourceCollections;
  QList<Item::Id> items;
  bool readOnly;

  DragPayload() : readOnly( false ) { }

  static QString mimeType()
  {
    return "x-akonadi-drag/message-list";
  }
};

QDataStream &operator<<(QDataStream &stream, const DragPayload &payload)
{
  stream << payload.sourceCollections;
  stream << payload.items;
  stream << payload.readOnly;

  return stream;
}

QDataStream &operator>>(QDataStream &stream, DragPayload &payload)
{
  stream >> payload.sourceCollections;
  stream >> payload.items;
  stream >> payload.readOnly;

  return stream;
}

Widget::Widget( QWidget *parent )
  : Core::Widget( parent ), d( new Private( this ) )
{
  QTimer::singleShot( 0, this, SLOT( populateStatusFilterCombo() ) );
}

Widget::~Widget()
{
  delete d;
}

bool Widget::canAcceptDrag( const QDragMoveEvent * e )
{
  Collection::List collections = static_cast<const StorageModel*>( storageModel() )->displayedCollections();

  if ( collections.size()!=1 )
    return false; // no folder here or too many (in case we can't decide where the drop will end)

  Collection c = collections.first();

  if ( ( c.rights() & Collection::CanCreateItem ) == 0 )
    return false; // no way to drag into

  if ( !e->mimeData()->hasFormat( DragPayload::mimeType() ) )
    return false; // no way to decode it

  DragPayload payload;
  QDataStream stream( e->mimeData()->data( DragPayload::mimeType() ) );
  stream >> payload;

  foreach ( Collection::Id id, payload.sourceCollections ) {
    if ( id == c.id() ) {
      return false;
    }
  }

  return true;
}

bool Widget::selectNextMessageItem( MessageList::Core::MessageTypeFilter messageTypeFilter,
                                    MessageList::Core::ExistingSelectionBehaviour existingSelectionBehaviour,
                                    bool centerItem,
                                    bool loop )
{
  return view()->selectNextMessageItem( messageTypeFilter, existingSelectionBehaviour, centerItem, loop );
}

bool Widget::selectPreviousMessageItem( MessageList::Core::MessageTypeFilter messageTypeFilter,
                                        MessageList::Core::ExistingSelectionBehaviour existingSelectionBehaviour,
                                        bool centerItem,
                                        bool loop )
{
  return view()->selectPreviousMessageItem( messageTypeFilter, existingSelectionBehaviour, centerItem, loop );
}

bool Widget::focusNextMessageItem( MessageList::Core::MessageTypeFilter messageTypeFilter, bool centerItem, bool loop )
{
  return view()->focusNextMessageItem( messageTypeFilter, centerItem, loop );
}

bool Widget::focusPreviousMessageItem( MessageList::Core::MessageTypeFilter messageTypeFilter, bool centerItem, bool loop )
{
  return view()->focusNextMessageItem( messageTypeFilter, centerItem, loop );
}

void Widget::selectFocusedMessageItem( bool centerItem )
{
  view()->selectFocusedMessageItem( centerItem );
}

bool Widget::selectFirstMessageItem( MessageList::Core::MessageTypeFilter messageTypeFilter, bool centerItem )
{
  return view()->selectFirstMessageItem( messageTypeFilter, centerItem );
}

void Widget::selectAll()
{
  view()->setAllGroupsExpanded( true );
  view()->selectAll();
}

void Widget::viewMessageSelected( MessageList::Core::MessageItem *msg )
{
  int row = -1;
  if ( msg ) {
    row = msg->currentModelIndexRow();
  }

  if ( !msg || !msg->isValid() || !storageModel() ) {
    d->mLastSelectedMessage = -1;
    emit messageSelected( Item() );
    return;
  }

  Q_ASSERT( row >= 0 );

  d->mLastSelectedMessage = row;

  emit messageSelected( d->itemForRow( row ) ); // this MAY be null
}

void Widget::viewMessageActivated( MessageList::Core::MessageItem *msg )
{
  Q_ASSERT( msg ); // must not be null
  Q_ASSERT( storageModel() );

  if ( !msg->isValid() ) {
    return;
  }

  int row = msg->currentModelIndexRow();
  Q_ASSERT( row >= 0 );

  // The assert below may fail when quickly opening and closing a non-selected thread.
  // This will actually activate the item without selecting it...
  //Q_ASSERT( d->mLastSelectedMessage == row );

  if ( d->mLastSelectedMessage != row ) {
    // Very ugly. We are activating a non selected message.
    // This is very likely a double click on the plus sign near a thread leader.
    // Dealing with mLastSelectedMessage here would be expensive: it would involve releasing the last selected,
    // emitting signals, handling recursion... ugly.
    // We choose a very simple solution: double clicking on the plus sign near a thread leader does
    // NOT activate the message (i.e open it in a toplevel window) if it isn't previously selected.
    return;
  }

  emit messageActivated( d->itemForRow( row ) ); // this MAY be null
}

void Widget::viewSelectionChanged()
{
  emit selectionChanged();
  if ( !currentMessageItem() ) {
    emit messageSelected( Item() );
  }
}

void Widget::viewMessageListContextPopupRequest( const QList< MessageList::Core::MessageItem * > &selectedItems, const QPoint &globalPos )
{
  //FIXME: To implement once the other infrastructure is ready for a KMail independent implementation
  kWarning() << "Needs to be reimplemented";
}

void Widget::viewMessageStatusChangeRequest( MessageList::Core::MessageItem *msg, const KPIM::MessageStatus &set, const KPIM::MessageStatus &clear )
{
  Q_ASSERT( msg ); // must not be null
  Q_ASSERT( storageModel() );

  if ( !msg->isValid() ) {
    return;
  }

  int row = msg->currentModelIndexRow();
  Q_ASSERT( row >= 0 );

  Item item = d->itemForRow( row );
  Q_ASSERT( item.isValid() );

  emit messageStatusChangeRequest( item, set, clear );
}

void Widget::viewGroupHeaderContextPopupRequest( MessageList::Core::GroupHeaderItem *ghi, const QPoint &globalPos )
{
  Q_UNUSED( ghi );

  KMenu menu( this );

  QAction *act;

  menu.addSeparator();

  act = menu.addAction( i18n( "Expand All Groups" ) );
  connect( act, SIGNAL( triggered( bool ) ),
           view(), SLOT( slotExpandAllGroups() ) );

  act = menu.addAction( i18n( "Collapse All Groups" ) );
  connect( act, SIGNAL( triggered( bool ) ),
           view(), SLOT( slotCollapseAllGroups() ) );

  menu.exec( globalPos );
}

void Widget::viewDragEnterEvent( QDragEnterEvent *e )
{
  if ( !canAcceptDrag( e ) ) {
    e->ignore();
    return;
  }

  e->accept();
}

void Widget::viewDragMoveEvent( QDragMoveEvent *e )
{
  if ( !canAcceptDrag( e ) ) {
    e->ignore();
    return;
  }

  e->accept();
}

enum DragMode
{
  DragCopy,
  DragMove,
  DragCancel
};

void Widget::viewDropEvent( QDropEvent *e )
{
  Collection::List collections = static_cast<const StorageModel*>( storageModel() )->displayedCollections();

  if ( collections.size()!=1 || !e->mimeData()->hasFormat( DragPayload::mimeType() ) ) {
    // no folder here or too many (in case we can't decide where the drop will end), or we can't decode
    e->ignore();
    return;
  }

  DragPayload payload;
  QDataStream stream( e->mimeData()->data( DragPayload::mimeType() ) );
  stream >> payload;

  if ( payload.items.isEmpty() ) {
    kWarning() << "Could not decode drag data!";
    e->ignore();
    return;
  }

  e->accept();

  int action;
  if ( payload.readOnly ) {
    action = DragCopy;
  } else {
    action = DragCancel;
    int keybstate = QApplication::keyboardModifiers();
    if ( keybstate & Qt::CTRL ) {
      action = DragCopy;

    } else if ( keybstate & Qt::SHIFT ) {
      action = DragMove;

    } else {
      // FIXME: This code is duplicated almost exactly in FolderView... shouldn't we share ?
      KMenu menu;
      QAction *moveAction = menu.addAction( KIcon( "go-jump"), i18n( "&Move Here" ) );
      QAction *copyAction = menu.addAction( KIcon( "edit-copy" ), i18n( "&Copy Here" ) );
      menu.addSeparator();
      menu.addAction( KIcon( "dialog-cancel" ), i18n( "C&ancel" ) );

      QAction *menuChoice = menu.exec( QCursor::pos() );
      if ( menuChoice == moveAction ) {
        action = DragMove;
      } else if ( menuChoice == copyAction ) {
        action = DragCopy;
      } else {
        action = DragCancel;
      }
    }
  }

  Collection target = collections.first();
  Item::List items;
  foreach ( Item::Id id, payload.items ) {
    items << Item( id );
  }

  if ( action == DragCopy ) {
    new ItemCopyJob( items, target, this );
  } else if ( action == DragMove ) {
    new ItemMoveJob( items, target, this );
  }
}

void Widget::viewStartDragRequest()
{
  Collection::List collections = static_cast<const StorageModel*>( storageModel() )->displayedCollections();

  if ( collections.isEmpty() )
    return; // no folder here

  QList<Item> items = d->selectionAsItems();
  if ( items.isEmpty() )
    return;

  DragPayload payload;

  foreach ( const Collection c, collections ) {
    payload.sourceCollections << c.id();
    // We won't be able to remove items from this collection
    if ( ( c.rights() & Collection::CanDeleteItem ) == 0 ) {
      // So the drag will be read-only
      payload.readOnly = true;
    }
  }

  foreach ( const Item i, items ) {
    payload.items << i.id();
  }

  QByteArray data;
  {
    QDataStream stream( &data, QIODevice::WriteOnly );
    stream << payload;
  }

  QMimeData *mimeData = new QMimeData;
  mimeData->setData( DragPayload::mimeType(), data );

  QDrag *drag = new QDrag( view()->viewport() );
  drag->setMimeData( mimeData );

  // Set pixmap
  QPixmap pixmap;
  if( items.size() == 1 ) {
    pixmap = QPixmap( DesktopIcon("mail-message", KIconLoader::SizeSmall) );
  } else {
    pixmap = QPixmap( DesktopIcon("document-multiple", KIconLoader::SizeSmall) );
  }

  // Calculate hotspot (as in Konqueror)
  if( !pixmap.isNull() ) {
    drag->setHotSpot( QPoint( pixmap.width() / 2, pixmap.height() / 2 ) );
    drag->setPixmap( pixmap );
  }

  if ( payload.readOnly )
    drag->exec( Qt::CopyAction );
  else
    drag->exec( Qt::CopyAction | Qt::MoveAction );
}

Item::List Widget::Private::selectionAsItems() const
{
  Item::List res;
  QList<Core::MessageItem *> selection = q->view()->selectionAsMessageItemList();

  foreach ( Core::MessageItem *mi, selection ) {
    Item i = itemForRow( mi->currentModelIndexRow() );
    Q_ASSERT( i.isValid() );
    res << i;
  }

  return res;
}

Item Widget::Private::itemForRow( int row ) const
{
  return static_cast<const StorageModel*>( q->storageModel() )->itemForRow( row );
}
<|endoftext|>


<commit_before>#include "mediamanager.h"

#include "filtergraph.h"
#include "rtpstreamer.h"
#include "filter.h"
#include "framedsourcefilter.h"
#include "rtpsinkfilter.h"
#include "gui/videoviewfactory.h"
#include "sip/sdptypes.h"
#include "statisticsinterface.h"

#include <QHostAddress>
#include <QtEndian>
#include <QDebug>

MediaManager::MediaManager():
  stats_(nullptr),
  fg_(new FilterGraph()),
  session_(nullptr),
  streamer_(new RTPStreamer()),
  mic_(true),
  camera_(true)
{}

MediaManager::~MediaManager()
{
  fg_->running(false);
  fg_->uninit();
}

void MediaManager::init(std::shared_ptr<VideoviewFactory> viewfactory, StatisticsInterface *stats)
{
  qDebug() << "Iniating: Media manager";
  viewfactory_ = viewfactory;
  streamer_->init(stats);
  streamer_->start();
  stats_ = stats;
  fg_->init(viewfactory_->getVideo(0), stats); // 0 is the selfview index. The view should be created by GUI
}

void MediaManager::uninit()
{
  qDebug() << "Closing," << metaObject()->className();
  // first filter graph, then streamer because of the rtpfilters
  fg_->running(false);
  fg_->uninit();

  stats_ = nullptr;
  streamer_->stop();
  streamer_->uninit();
}

void MediaManager::updateSettings()
{
  fg_->updateSettings();
  fg_->camera(camera_); // kind of a hack to make sure the camera/mic state is preserved
  fg_->mic(mic_);
}

void MediaManager::addParticipant(uint32_t sessionID, std::shared_ptr<SDPMessageInfo> peerInfo,
                    const std::shared_ptr<SDPMessageInfo> localInfo)
{
  // TODO: support stop-time and start-time as recommended by RFC 4566 section 5.9

  if(peerInfo->timeDescriptions.at(0).startTime != 0 || localInfo->timeDescriptions.at(0).startTime != 0)
  {
    qWarning() << "ERROR: Non zero start-time not supported!";
  }

#if 0
  qDebug() << localInfo->media[0].connection_address << ":" << localInfo->media[0].receivePort;
  qDebug() << localInfo->media[1].connection_address << ":" << localInfo->media[1].receivePort;
  qDebug() << peerInfo->media[0].connection_address  << ":" << peerInfo->media[0].receivePort;
  qDebug() << peerInfo->media[0].connection_address  << ":" << peerInfo->media[1].receivePort << "\n";
#endif

  if(peerInfo->connection_nettype == "IN")
  {
    QHostAddress address;

    if (peerInfo->media[0].connection_address.isEmpty())
    {
      address.setAddress(peerInfo->connection_address);
    }
    else
    {
      address.setAddress(peerInfo->media[0].connection_address); // media[0] is RTP
    }

    if(stats_ != nullptr)
    {
      stats_->addParticipant(peerInfo->connection_address, "0", "0");
    }

    if(peerInfo->connection_addrtype == "IP4")
    {
      in_addr ip;
#ifdef _WIN32
      ip.S_un.S_addr = qToBigEndian(address.toIPv4Address());
#else
      ip.s_addr = qToBigEndian(address.toIPv4Address());
#endif

      // TODO: Make it possible to have a separate ip address for each mediastream by fixing this.
      if(!streamer_->addPeer(ip, sessionID))
      {
        qCritical() << "Error creating RTP peer. Simultaneous destruction?";
        return;
      }
    }
    else if(peerInfo->connection_addrtype == "IP6")
    {
      qDebug() << "ERROR: IPv6 not supported in media creation";
      return;
    }
  }
  else
  {
    qWarning() << "ERROR: What are we using if not the internet!?";
    return;
  }

  // create each agreed media stream
  for(auto media : peerInfo->media)
  {
    createOutgoingMedia(sessionID, media);
  }

  for(auto media : localInfo->media)
  {
    createIncomingMedia(sessionID, media);
  }

  // crashes at the moment.
  //fg_->print();
}

void MediaManager::createOutgoingMedia(uint32_t sessionID, const MediaInfo& remoteMedia)
{
  bool send = true;
  bool recv = true;

  transportAttributes(remoteMedia.flagAttributes, send, recv);

  // if they want to receive
  if(recv)
  {
    Q_ASSERT(remoteMedia.receivePort);
    Q_ASSERT(!remoteMedia.rtpNums.empty());

    QString codec = rtpNumberToCodec(remoteMedia);

    if(remoteMedia.proto == "RTP/AVP")
    {
      std::shared_ptr<Filter> framedSource = streamer_->addSendStream(sessionID, remoteMedia.receivePort,
                                                                      codec, remoteMedia.rtpNums.at(0));
      if(remoteMedia.type == "audio")
      {
        fg_->sendAudioTo(sessionID, std::shared_ptr<Filter>(framedSource));
      }
      else if(remoteMedia.type == "video")
      {
        fg_->sendVideoto(sessionID, std::shared_ptr<Filter>(framedSource));
      }
      else
      {
        qDebug() << "ERROR: Unsupported media type in :" << remoteMedia.type;
      }
    }
    else
    {
      qDebug() << "ERROR: SDP transport protocol not supported.";
    }
  }
  else
  {
    qDebug() << "Not creating media because they don't seem to want any according to attribute";
  }
}

void MediaManager::createIncomingMedia(uint32_t sessionID, const MediaInfo &localMedia)
{
  bool send = true;
  bool recv = true;

  transportAttributes(localMedia.flagAttributes, send, recv);
  if(recv)
  {
    Q_ASSERT(localMedia.receivePort);
    Q_ASSERT(!localMedia.rtpNums.empty());

    QString codec = rtpNumberToCodec(localMedia);

    qDebug() << "Creating incoming media with codec:" << codec;

    if(localMedia.proto == "RTP/AVP")
    {
      std::shared_ptr<Filter> rtpSink = streamer_->addReceiveStream(sessionID, localMedia.receivePort,
                                                                    codec, localMedia.rtpNums.at(0));
      if(localMedia.type == "audio")
      {
        fg_->receiveAudioFrom(sessionID, std::shared_ptr<Filter>(rtpSink));
      }
      else if(localMedia.type == "video")
      {
        fg_->receiveVideoFrom(sessionID, std::shared_ptr<Filter>(rtpSink), viewfactory_->getVideo(sessionID));
      }
      else
      {
        qDebug() << "ERROR: Unsupported media type in :" << localMedia.type;
      }
    }
    else
    {
      qDebug() << "ERROR: SDP transport protocol not supported.";
    }
  }
  else
  {
    qDebug() << "Not creating media because they don't seem to want any according to attribute";
  }
}

void MediaManager::removeParticipant(uint32_t sessionID)
{
  fg_->removeParticipant(sessionID);
  fg_->camera(camera_); // if the last participant was destroyed, restore camera state
  fg_->mic(mic_);
  streamer_->removePeer(sessionID);
  qDebug() << "Session " << sessionID << " media removed.";
}

void MediaManager::endAllCalls()
{
  fg_->removeAllParticipants();
  streamer_->removeAllPeers();

  fg_->camera(camera_); // if the last participant was destroyed, restore camera state
  fg_->mic(mic_);
}

bool MediaManager::toggleMic()
{
  mic_ = !mic_;
  fg_->mic(mic_);
  return mic_;
}

bool MediaManager::toggleCamera()
{
  camera_ = !camera_;
  fg_->camera(camera_);
  return camera_;
}

QString MediaManager::rtpNumberToCodec(const MediaInfo& info)
{
  // If we are not using raw.
  // This is the place where all other preset audio video codec numbers should be set
  // but its unlikely that we will support any besides raw pcmu.
  if(info.rtpNums.at(0) != 0)
  {
    Q_ASSERT(!info.codecs.empty());
    if(!info.codecs.empty())
    {
      return info.codecs.at(0).codec;
    }
  }
  return "pcmu";
}

void MediaManager::transportAttributes(const QList<SDPAttributeType>& attributes, bool& send, bool& recv)
{
  send = true;
  recv = true;

  for(SDPAttributeType attribute : attributes)
  {
    if(attribute == A_SENDRECV)
    {
      send = true;
      recv = true;
    }
    else if(attribute == A_SENDONLY)
    {
      send = true;
      recv = false;
    }
    else if(attribute == A_RECVONLY)
    {
      send = false;
      recv = true;
    }
    else if(attribute == A_INACTIVE)
    {
      send = false;
      recv = false;
    }
  }
}
<commit_msg>[Media] (bug_fix) The Ipv6 addresses that are actually Ipv4 address are now supported.<commit_after>#include "mediamanager.h"

#include "filtergraph.h"
#include "rtpstreamer.h"
#include "filter.h"
#include "framedsourcefilter.h"
#include "rtpsinkfilter.h"
#include "gui/videoviewfactory.h"
#include "sip/sdptypes.h"
#include "statisticsinterface.h"

#include <QHostAddress>
#include <QtEndian>
#include <QDebug>

MediaManager::MediaManager():
  stats_(nullptr),
  fg_(new FilterGraph()),
  session_(nullptr),
  streamer_(new RTPStreamer()),
  mic_(true),
  camera_(true)
{}

MediaManager::~MediaManager()
{
  fg_->running(false);
  fg_->uninit();
}

void MediaManager::init(std::shared_ptr<VideoviewFactory> viewfactory, StatisticsInterface *stats)
{
  qDebug() << "Iniating: Media manager";
  viewfactory_ = viewfactory;
  streamer_->init(stats);
  streamer_->start();
  stats_ = stats;
  fg_->init(viewfactory_->getVideo(0), stats); // 0 is the selfview index. The view should be created by GUI
}

void MediaManager::uninit()
{
  qDebug() << "Closing," << metaObject()->className();
  // first filter graph, then streamer because of the rtpfilters
  fg_->running(false);
  fg_->uninit();

  stats_ = nullptr;
  streamer_->stop();
  streamer_->uninit();
}

void MediaManager::updateSettings()
{
  fg_->updateSettings();
  fg_->camera(camera_); // kind of a hack to make sure the camera/mic state is preserved
  fg_->mic(mic_);
}

void MediaManager::addParticipant(uint32_t sessionID, std::shared_ptr<SDPMessageInfo> peerInfo,
                    const std::shared_ptr<SDPMessageInfo> localInfo)
{
  // TODO: support stop-time and start-time as recommended by RFC 4566 section 5.9

  if(peerInfo->timeDescriptions.at(0).startTime != 0 || localInfo->timeDescriptions.at(0).startTime != 0)
  {
    qWarning() << "ERROR: Non zero start-time not supported!";
  }

#if 0
  qDebug() << localInfo->media[0].connection_address << ":" << localInfo->media[0].receivePort;
  qDebug() << localInfo->media[1].connection_address << ":" << localInfo->media[1].receivePort;
  qDebug() << peerInfo->media[0].connection_address  << ":" << peerInfo->media[0].receivePort;
  qDebug() << peerInfo->media[0].connection_address  << ":" << peerInfo->media[1].receivePort << "\n";
#endif

  if(peerInfo->connection_nettype == "IN")
  {
    QHostAddress address;

    if (peerInfo->media[0].connection_address.isEmpty())
    {
      address.setAddress(peerInfo->connection_address);
    }
    else
    {
      address.setAddress(peerInfo->media[0].connection_address); // media[0] is RTP
    }

    if(stats_ != nullptr)
    {
      stats_->addParticipant(peerInfo->connection_address, "0", "0");
    }

    if(peerInfo->connection_addrtype == "IP4"
       || (peerInfo->connection_addrtype == "IP6" && address.toString().left(7) == "::ffff:"))
    {
      in_addr ip;
#ifdef _WIN32
      ip.S_un.S_addr = qToBigEndian(address.toIPv4Address());
#else
      ip.s_addr = qToBigEndian(address.toIPv4Address());
#endif

      // TODO: Make it possible to have a separate ip address for each mediastream by fixing this.
      if(!streamer_->addPeer(ip, sessionID))
      {
        qCritical() << "Error creating RTP peer. Simultaneous destruction?";
        return;
      }
    }
    else {
      qDebug() << "ERROR:" << peerInfo->connection_addrtype << "not supported in media creation:" << address;
      return;
    }
  }
  else
  {
    qWarning() << "ERROR: What are we using if not the internet!?";
    return;
  }

  // create each agreed media stream
  for(auto media : peerInfo->media)
  {
    createOutgoingMedia(sessionID, media);
  }

  for(auto media : localInfo->media)
  {
    createIncomingMedia(sessionID, media);
  }

  // crashes at the moment.
  //fg_->print();
}

void MediaManager::createOutgoingMedia(uint32_t sessionID, const MediaInfo& remoteMedia)
{
  bool send = true;
  bool recv = true;

  transportAttributes(remoteMedia.flagAttributes, send, recv);

  // if they want to receive
  if(recv)
  {
    Q_ASSERT(remoteMedia.receivePort);
    Q_ASSERT(!remoteMedia.rtpNums.empty());

    QString codec = rtpNumberToCodec(remoteMedia);

    if(remoteMedia.proto == "RTP/AVP")
    {
      std::shared_ptr<Filter> framedSource = streamer_->addSendStream(sessionID, remoteMedia.receivePort,
                                                                      codec, remoteMedia.rtpNums.at(0));
      if(remoteMedia.type == "audio")
      {
        fg_->sendAudioTo(sessionID, std::shared_ptr<Filter>(framedSource));
      }
      else if(remoteMedia.type == "video")
      {
        fg_->sendVideoto(sessionID, std::shared_ptr<Filter>(framedSource));
      }
      else
      {
        qDebug() << "ERROR: Unsupported media type in :" << remoteMedia.type;
      }
    }
    else
    {
      qDebug() << "ERROR: SDP transport protocol not supported.";
    }
  }
  else
  {
    qDebug() << "Not creating media because they don't seem to want any according to attribute";
  }
}

void MediaManager::createIncomingMedia(uint32_t sessionID, const MediaInfo &localMedia)
{
  bool send = true;
  bool recv = true;

  transportAttributes(localMedia.flagAttributes, send, recv);
  if(recv)
  {
    Q_ASSERT(localMedia.receivePort);
    Q_ASSERT(!localMedia.rtpNums.empty());

    QString codec = rtpNumberToCodec(localMedia);

    qDebug() << "Creating incoming media with codec:" << codec;

    if(localMedia.proto == "RTP/AVP")
    {
      std::shared_ptr<Filter> rtpSink = streamer_->addReceiveStream(sessionID, localMedia.receivePort,
                                                                    codec, localMedia.rtpNums.at(0));
      if(localMedia.type == "audio")
      {
        fg_->receiveAudioFrom(sessionID, std::shared_ptr<Filter>(rtpSink));
      }
      else if(localMedia.type == "video")
      {
        fg_->receiveVideoFrom(sessionID, std::shared_ptr<Filter>(rtpSink), viewfactory_->getVideo(sessionID));
      }
      else
      {
        qDebug() << "ERROR: Unsupported media type in :" << localMedia.type;
      }
    }
    else
    {
      qDebug() << "ERROR: SDP transport protocol not supported.";
    }
  }
  else
  {
    qDebug() << "Not creating media because they don't seem to want any according to attribute";
  }
}

void MediaManager::removeParticipant(uint32_t sessionID)
{
  fg_->removeParticipant(sessionID);
  fg_->camera(camera_); // if the last participant was destroyed, restore camera state
  fg_->mic(mic_);
  streamer_->removePeer(sessionID);
  qDebug() << "Session " << sessionID << " media removed.";
}

void MediaManager::endAllCalls()
{
  fg_->removeAllParticipants();
  streamer_->removeAllPeers();

  fg_->camera(camera_); // if the last participant was destroyed, restore camera state
  fg_->mic(mic_);
}

bool MediaManager::toggleMic()
{
  mic_ = !mic_;
  fg_->mic(mic_);
  return mic_;
}

bool MediaManager::toggleCamera()
{
  camera_ = !camera_;
  fg_->camera(camera_);
  return camera_;
}

QString MediaManager::rtpNumberToCodec(const MediaInfo& info)
{
  // If we are not using raw.
  // This is the place where all other preset audio video codec numbers should be set
  // but its unlikely that we will support any besides raw pcmu.
  if(info.rtpNums.at(0) != 0)
  {
    Q_ASSERT(!info.codecs.empty());
    if(!info.codecs.empty())
    {
      return info.codecs.at(0).codec;
    }
  }
  return "pcmu";
}

void MediaManager::transportAttributes(const QList<SDPAttributeType>& attributes, bool& send, bool& recv)
{
  send = true;
  recv = true;

  for(SDPAttributeType attribute : attributes)
  {
    if(attribute == A_SENDRECV)
    {
      send = true;
      recv = true;
    }
    else if(attribute == A_SENDONLY)
    {
      send = true;
      recv = false;
    }
    else if(attribute == A_RECVONLY)
    {
      send = false;
      recv = true;
    }
    else if(attribute == A_INACTIVE)
    {
      send = false;
      recv = false;
    }
  }
}
<|endoftext|>


<commit_before>#include <TF2.h>
#include <TFile.h>
#include <TChain.h>
#include <TVectorD.h>

#include "RZ.h"
#include "Units.h"

using namespace GeFiCa;

//_____________________________________________________________________________
//
#include <iostream>
using namespace std;
void RZ::SOR2(int idx,bool NotImpurityPotential)
{
   if (fIsFixed[idx])return;
   // 2nd-order Successive Over-Relaxation
   double density=fImpurity[idx]*Qe;
   double drm=fdC1m[idx]; // dr_minus
   double drp=fdC1p[idx];
   double dzm=fdC2m[idx];
   double dzp=fdC2p[idx];
   double pzm,pzp,prm,prp; // pzm: potential_z_plus
   if(idx>=n1)pzm=fPotential[idx-n1];
   else pzm=fPotential[idx];
   if(idx>=n-n1)pzp=fPotential[idx];
   else pzp=fPotential[idx+n1];
   if(idx%n1==0)prm=fPotential[idx];
   else prm=fPotential[idx-1];
   if(idx%n1==n1-1)prp=fPotential[idx];
   else prp=fPotential[idx+1];
   double tmp=(density/epsilon
         + 1/fC1[idx]*(prp-prm)/(drm+drp) +(prp/drp+prm/drm)*2/(drm+drp)
         + (pzp/dzp+pzm/dzm)*2/(dzp+dzm))/
      ((1/drm+1/drp)*2/(drm+drp)+(1/dzp+1/dzm)*2/(dzp+dzm));
   //find minmium and maxnium of all five grid, the new one should not go overthem.
   //find min
   double min=prm;
   double max=prm;
   if(min>prp)min=prp;
   if (min>pzp)min=pzp;
   if (min>pzm)min=pzm;

   //find max
   if(max<prp)max=prp;
   if (max<pzp)max=pzp;
   if (max<pzm)max=pzm;
//if tmp is greater or smaller than max and min, set tmp to it.

      //over relax
   //fPotential[idx]=Csor*(tmp-fPotential[idx])+fPotential[idx];
   //if need calculate depleted voltage
   double oldP=fPotential[idx];
      tmp=Csor*(tmp-oldP)+oldP;
   if(tmp<min)
   {
      fPotential[idx]=min;
      fIsDepleted[idx]=false;
   }
   else if(tmp>max)
   {
      fPotential[idx]=max;
      fIsDepleted[idx]=false;
   }
   else
      fIsDepleted[idx]=true;
   if(fIsDepleted[idx]||!NotImpurityPotential)
   {
      fPotential[idx]=tmp;
   }

   if (prp<0)   std::cout<<"index "<<idx<<"prm "<<prm<<"prp "<<prp<<"pzp "<<pzp<<"pzm "<<pzm<<"min "<<min<<"tmp "<<tmp<<"\n";

}
void RZ::CalculateCapacitance()
{
   /*
   http://bgaowww.physics.utoledo.edu/teaching/LectureNotes/Phys2080/Chapter16.htm
   https://en.wikipedia.org/wiki/Electric_field#Energy_in_the_electric_field
   use Energy in a charged capacitor= total energy U stored in the electric field in a given volume V
   to find capacitance
   */
   //only work when impurity are zero
   for(int i=0;i<n;i++)
   {
      if(fImpurity[i]!=0)
      {
         //impurity not clear,return
         return;
      }
   }
   double V=1*volt;
   //debug:cout<<V<<endl;
   double SumofElectricField=0;
   for(int i=0;i<n;i++)
   {
      if(fC1[i]<0)continue;
      //integral over electric field
      double e1=fE1[i];
      double e2=fE2[i];
      double dr=fdC1p[i];
      double dz=fdC2p[i];
      SumofElectricField+=(e1*e1+e2*e2)*fC1[i]*dr*dz;

   }
   double Capacitance=SumofElectricField*2*3.14159*epsilon/V/V;
   cout<<"Calculated capacitance is "<<Capacitance/pF<<endl;
}

<commit_msg>removed depleted<commit_after>#include <TF2.h>
#include <TFile.h>
#include <TChain.h>
#include <TVectorD.h>

#include "RZ.h"
#include "Units.h"

using namespace GeFiCa;

//_____________________________________________________________________________
//
#include <iostream>
using namespace std;
void RZ::SOR2(int idx,bool NotImpurityPotential)
{
   if (fIsFixed[idx])return;
   // 2nd-order Successive Over-Relaxation
   double density=fImpurity[idx]*Qe;
   double drm=fdC1m[idx]; // dr_minus
   double drp=fdC1p[idx];
   double dzm=fdC2m[idx];
   double dzp=fdC2p[idx];
   double pzm,pzp,prm,prp; // pzm: potential_z_plus
   if(idx>=n1)pzm=fPotential[idx-n1];
   else pzm=fPotential[idx];
   if(idx>=n-n1)pzp=fPotential[idx];
   else pzp=fPotential[idx+n1];
   if(idx%n1==0)prm=fPotential[idx];
   else prm=fPotential[idx-1];
   if(idx%n1==n1-1)prp=fPotential[idx];
   else prp=fPotential[idx+1];
   double tmp=(density/epsilon
         + 1/fC1[idx]*(prp-prm)/(drm+drp) +(prp/drp+prm/drm)*2/(drm+drp)
         + (pzp/dzp+pzm/dzm)*2/(dzp+dzm))/
      ((1/drm+1/drp)*2/(drm+drp)+(1/dzp+1/dzm)*2/(dzp+dzm));
   //find minmium and maxnium of all five grid, the new one should not go overthem.
   //find min
   double min=prm;
   double max=prm;
   if(min>prp)min=prp;
   if (min>pzp)min=pzp;
   if (min>pzm)min=pzm;

   //find max
   if(max<prp)max=prp;
   if (max<pzp)max=pzp;
   if (max<pzm)max=pzm;
//if tmp is greater or smaller than max and min, set tmp to it.

      //over relax
   //fPotential[idx]=Csor*(tmp-fPotential[idx])+fPotential[idx];
   //if need calculate depleted voltage
   double oldP=fPotential[idx];
   tmp=Csor*(tmp-oldP)+oldP;
   /*
      if(tmp<min)
      {
      fPotential[idx]=min;
      fIsDepleted[idx]=false;
      }
      else if(tmp>max)
      {
      fPotential[idx]=max;
      fIsDepleted[idx]=false;
      }
      else
      fIsDepleted[idx]=true;
      if(fIsDepleted[idx]||!NotImpurityPotential)
      {
      fPotential[idx]=tmp;
      }
      */

   fPotential[idx]=tmp;

}
void RZ::CalculateCapacitance()
{
   /*
http://bgaowww.physics.utoledo.edu/teaching/LectureNotes/Phys2080/Chapter16.htm
https://en.wikipedia.org/wiki/Electric_field#Energy_in_the_electric_field
use Energy in a charged capacitor= total energy U stored in the electric field in a given volume V
to find capacitance
*/
   //only work when impurity are zero
   for(int i=0;i<n;i++)
   {
      if(fImpurity[i]!=0)
      {
         //impurity not clear,return
         return;
      }
   }
   double V=1*volt;
   //debug:cout<<V<<endl;
   double SumofElectricField=0;
   for(int i=0;i<n;i++)
   {
      if(fC1[i]<0)continue;
      //integral over electric field
      double e1=fE1[i];
      double e2=fE2[i];
      double dr=fdC1p[i];
      double dz=fdC2p[i];
      SumofElectricField+=(e1*e1+e2*e2)*fC1[i]*dr*dz;

   }
   double Capacitance=SumofElectricField*2*3.14159*epsilon/V/V;
   cout<<"Calculated capacitance is "<<Capacitance/pF<<endl;
}

<|endoftext|>


<commit_before>#include "encoder.hpp"

#include <settings.hpp>
extern "C" {
#include <libavutil/imgutils.h>
#include <libavutil/opt.h>
}

inline void throwAVErr(int ret, std::string section) {
    char err[AV_ERROR_MAX_STRING_SIZE];
    av_make_error_string(err, AV_ERROR_MAX_STRING_SIZE, ret);
    std::string newString(err);
    throw std::runtime_error("Error during: " + section + ": " + newString);
}

#define OR_DEF(s, e1, e2) s ? s->e1 : e2

Encoder::Encoder(QString &targetFile, QSize res, CodecSettings *settings) {
    int ret;
    // Format
    ret = avformat_alloc_output_context2(&fc, NULL, NULL, targetFile.toLocal8Bit().constData());
    if (ret < 0) throwAVErr(ret, "format alloc");

    // Stream
    out->st = avformat_new_stream(fc, NULL);
    if (!out->st) throw std::runtime_error("Unable to allocate video context");
    out->st->id = fc->nb_streams - 1;
    if (fc->oformat->flags & AVFMT_GLOBALHEADER) fc->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
    av_dump_format(fc, 0, targetFile.toLocal8Bit().constData(), 1);

    // Codec
    if (!fc->oformat->video_codec) throw std::runtime_error("Video codec not found");
    codec = avcodec_find_encoder(fc->oformat->video_codec);
    if (!codec) throw std::runtime_error("Video codec not found");
    out->enc = avcodec_alloc_context3(codec);
    if (!out->enc) throw std::runtime_error("Unable to allocate video context");

    int fps = settings::settings().value("recording/framerate", 30).toInt();

    out->enc->codec_id = codec->id;
    out->enc->codec = codec;

    out->enc->bit_rate = OR_DEF(settings, bitrate, 400000);
    out->enc->width = res.width() % 2 ? res.width() - 1 : res.width();
    out->enc->height = res.height() % 2 ? res.height() - 1 : res.height();
    size = QSize(out->enc->width, out->enc->height);
    out->st->time_base = { 1, fps };
    out->enc->time_base = out->st->time_base;

    out->enc->gop_size = OR_DEF(settings, gopSize, 12);
    out->enc->pix_fmt = AV_PIX_FMT_YUV420P; // blaze it
    AVDictionary *dict = NULL;
    if (out->enc->codec_id == AV_CODEC_ID_GIF)
        out->enc->pix_fmt = AV_PIX_FMT_RGB8;
    else if (out->enc->codec_id == AV_CODEC_ID_H264 || out->enc->codec_id == AV_CODEC_ID_H265) {
        av_dict_set(&dict, "preset", settings->h264Profile.toLocal8Bit().constData(), 0);
        av_dict_set_int(&dict, "crf", OR_DEF(settings, h264Crf, 12), 0);
    } else if (out->enc->codec_id == AV_CODEC_ID_VP8 || out->enc->codec_id == AV_CODEC_ID_VP9)
        av_dict_set_int(&dict, "lossless", OR_DEF(settings, vp9Lossless, false), 0);

    ret = avcodec_open2(out->enc, codec, &dict);
    av_dict_free(&dict);
    if (ret < 0) throwAVErr(ret, "codec open");
    if (codec->capabilities & AV_CODEC_CAP_DR1) avcodec_align_dimensions(out->enc, &out->enc->width, &out->enc->height);

    ret = avcodec_parameters_from_context(out->st->codecpar, out->enc);
    if (ret < 0) throwAVErr(ret, "stream opt copy");

    // Frames
    out->frame = av_frame_alloc();
    if (!out->frame) {
        throw std::runtime_error("frame alloc");
    }
    out->frame->format = out->enc->pix_fmt;
    out->frame->width = out->enc->width;
    out->frame->height = out->enc->height;
    ret = av_frame_get_buffer(out->frame, 32);
    if (ret < 0) throwAVErr(ret, "frame buffer alloc");

    // Writer
    ret = avio_open(&fc->pb, targetFile.toLocal8Bit().constData(), AVIO_FLAG_WRITE);
    if (ret < 0) throwAVErr(ret, "writer open");
    ret = avformat_write_header(fc, NULL);
    if (ret < 0) throwAVErr(ret, "write header");

    success = true;
}

void Encoder::setFrameRGB(uint8_t *rgb) {
    int ret = av_frame_make_writable(out->frame);
    if (ret < 0) throwAVErr(ret, "setFrameRGB");
    int lineSize[1] = { 3 * out->enc->width };
    out->sws = sws_getCachedContext(out->sws, out->enc->width, out->enc->height, AV_PIX_FMT_RGB24, out->enc->width,
                                    out->enc->height, (AVPixelFormat)out->frame->format, 0, 0, 0, 0);
    sws_scale(out->sws, (const uint8_t *const *)&rgb, lineSize, 0, out->enc->height, out->frame->data, out->frame->linesize);
    out->frame->pts = out->nextPts++;
}

Encoder::~Encoder() {
    end();
}

bool Encoder::addFrame(QImage frm) {
    if (!success) return false;
    if (frm.size() != size) frm = frm.copy(QRect(QPoint(0, 0), size));
    if (frm.format() != QImage::Format_RGB888) frm = frm.convertToFormat(QImage::Format_RGB888);
    uint8_t *frameData = (uint8_t *)frm.bits();
    setFrameRGB(frameData);
    AVPacket pkt;
    pkt.size = 0;
    pkt.data = NULL;
    av_init_packet(&pkt);
    int gotPack = 0;
    int ret = avcodec_encode_video2(out->enc, &pkt, out->frame, &gotPack);
    if (ret < 0) {
        av_packet_unref(&pkt);
        throwAVErr(ret, "encode video");
    }

    if (gotPack) {
        av_packet_rescale_ts(&pkt, out->enc->time_base, out->st->time_base);
        pkt.stream_index = out->st->index;
        ret = av_interleaved_write_frame(fc, &pkt);
    } else
        ret = 0;
    av_packet_unref(&pkt);
    if (ret < 0) throwAVErr(ret, "write frame");
    return true;
}

bool Encoder::isRunning() {
    return success;
}

bool Encoder::end() {
    if (!success) {
        goto cleanup;
    }

    av_write_trailer(fc);
cleanup:
    avcodec_free_context(&out->enc);
    av_frame_free(&out->frame);
    sws_freeContext(out->sws);
    delete out;
    if (!(fc->oformat->flags & AVFMT_NOFILE)) //
        avio_closep(&fc->pb);
    avformat_free_context(fc);
    return success;
}
<commit_msg>Don't use deprecated libavcodec functions<commit_after>#include "encoder.hpp"

#include <settings.hpp>
extern "C" {
#include <libavutil/imgutils.h>
#include <libavutil/opt.h>
}

inline void throwAVErr(int ret, std::string section) {
    char err[AV_ERROR_MAX_STRING_SIZE];
    av_make_error_string(err, AV_ERROR_MAX_STRING_SIZE, ret);
    std::string newString(err);
    throw std::runtime_error("Error during: " + section + ": " + newString);
}

#define OR_DEF(s, e1, e2) s ? s->e1 : e2

Encoder::Encoder(QString &targetFile, QSize res, CodecSettings *settings) {
    int ret;
    // Format
    ret = avformat_alloc_output_context2(&fc, NULL, NULL, targetFile.toLocal8Bit().constData());
    if (ret < 0) throwAVErr(ret, "format alloc");

    // Stream
    out->st = avformat_new_stream(fc, NULL);
    if (!out->st) throw std::runtime_error("Unable to allocate video context");
    out->st->id = fc->nb_streams - 1;
    if (fc->oformat->flags & AVFMT_GLOBALHEADER) fc->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
    av_dump_format(fc, 0, targetFile.toLocal8Bit().constData(), 1);

    // Codec
    if (!fc->oformat->video_codec) throw std::runtime_error("Video codec not found");
    codec = avcodec_find_encoder(fc->oformat->video_codec);
    if (!codec) throw std::runtime_error("Video codec not found");
    out->enc = avcodec_alloc_context3(codec);
    if (!out->enc) throw std::runtime_error("Unable to allocate video context");

    int fps = settings::settings().value("recording/framerate", 30).toInt();

    out->enc->codec_id = codec->id;
    out->enc->codec = codec;

    out->enc->bit_rate = OR_DEF(settings, bitrate, 400000);
    out->enc->width = res.width() % 2 ? res.width() - 1 : res.width();
    out->enc->height = res.height() % 2 ? res.height() - 1 : res.height();
    size = QSize(out->enc->width, out->enc->height);
    out->st->time_base = { 1, fps };
    out->enc->time_base = out->st->time_base;

    out->enc->gop_size = OR_DEF(settings, gopSize, 12);
    out->enc->pix_fmt = AV_PIX_FMT_YUV420P; // blaze it
    AVDictionary *dict = NULL;
    if (out->enc->codec_id == AV_CODEC_ID_GIF)
        out->enc->pix_fmt = AV_PIX_FMT_RGB8;
    else if (out->enc->codec_id == AV_CODEC_ID_H264 || out->enc->codec_id == AV_CODEC_ID_H265) {
        av_dict_set(&dict, "preset", settings->h264Profile.toLocal8Bit().constData(), 0);
        av_dict_set_int(&dict, "crf", OR_DEF(settings, h264Crf, 12), 0);
    } else if (out->enc->codec_id == AV_CODEC_ID_VP8 || out->enc->codec_id == AV_CODEC_ID_VP9)
        av_dict_set_int(&dict, "lossless", OR_DEF(settings, vp9Lossless, false), 0);

    ret = avcodec_open2(out->enc, codec, &dict);
    av_dict_free(&dict);
    if (ret < 0) throwAVErr(ret, "codec open");
    if (codec->capabilities & AV_CODEC_CAP_DR1) avcodec_align_dimensions(out->enc, &out->enc->width, &out->enc->height);

    ret = avcodec_parameters_from_context(out->st->codecpar, out->enc);
    if (ret < 0) throwAVErr(ret, "stream opt copy");

    // Frames
    out->frame = av_frame_alloc();
    if (!out->frame) {
        throw std::runtime_error("frame alloc");
    }
    out->frame->format = out->enc->pix_fmt;
    out->frame->width = out->enc->width;
    out->frame->height = out->enc->height;
    ret = av_frame_get_buffer(out->frame, 32);
    if (ret < 0) throwAVErr(ret, "frame buffer alloc");

    // Writer
    ret = avio_open(&fc->pb, targetFile.toLocal8Bit().constData(), AVIO_FLAG_WRITE);
    if (ret < 0) throwAVErr(ret, "writer open");
    ret = avformat_write_header(fc, NULL);
    if (ret < 0) throwAVErr(ret, "write header");

    success = true;
}

void Encoder::setFrameRGB(uint8_t *rgb) {
    int ret = av_frame_make_writable(out->frame);
    if (ret < 0) throwAVErr(ret, "setFrameRGB");
    int lineSize[1] = { 3 * out->enc->width };
    out->sws = sws_getCachedContext(out->sws, out->enc->width, out->enc->height, AV_PIX_FMT_RGB24, out->enc->width,
                                    out->enc->height, (AVPixelFormat)out->frame->format, 0, 0, 0, 0);
    sws_scale(out->sws, (const uint8_t *const *)&rgb, lineSize, 0, out->enc->height, out->frame->data, out->frame->linesize);
    out->frame->pts = out->nextPts++;
}

Encoder::~Encoder() {
    end();
}

bool Encoder::addFrame(QImage frm) {
    if (!success) return false;
    if (frm.size() != size) frm = frm.copy(QRect(QPoint(0, 0), size));
    if (frm.format() != QImage::Format_RGB888) frm = frm.convertToFormat(QImage::Format_RGB888);
    uint8_t *frameData = (uint8_t *)frm.bits();
    setFrameRGB(frameData);
    AVPacket pkt;
    pkt.size = 0;
    pkt.data = NULL;
    av_init_packet(&pkt);
    int ret = avcodec_send_frame(out->enc, out->frame);
    if (ret == AVERROR(EAGAIN)) {
        do {
            ret = avcodec_receive_packet(out->enc, &pkt);
            if (ret < 0) {
                if (ret != AVERROR(EAGAIN))
                    throwAVErr(ret, "receive packet");
                else
                    break;
            }
            av_packet_rescale_ts(&pkt, out->enc->time_base, out->st->time_base);
            pkt.stream_index = out->st->index;
            ret = av_interleaved_write_frame(fc, &pkt);
        } while (ret >= 0);
        if (ret < 0 && ret != AVERROR(EAGAIN)) {
            av_packet_unref(&pkt);
            throwAVErr(ret, "send frame");
        }
    }
    av_packet_unref(&pkt);
    if (ret < 0 && ret != AVERROR(EAGAIN)) throwAVErr(ret, "send frame");
    return true;
}

bool Encoder::isRunning() {
    return success;
}

bool Encoder::end() {
    if (!success) {
        goto cleanup;
    }
    int ret;
    AVPacket pkt;
    pkt.size = 0;
    pkt.data = NULL;
    av_init_packet(&pkt);
    do {
        ret = avcodec_receive_packet(out->enc, &pkt);
        if (ret < 0) break;
        av_packet_rescale_ts(&pkt, out->enc->time_base, out->st->time_base);
        pkt.stream_index = out->st->index;
        av_interleaved_write_frame(fc, &pkt);
    } while (ret >= 0);
    av_write_trailer(fc);
cleanup:
    avcodec_free_context(&out->enc);
    av_frame_free(&out->frame);
    sws_freeContext(out->sws);
    delete out;
    if (!(fc->oformat->flags & AVFMT_NOFILE)) //
        avio_closep(&fc->pb);
    avformat_free_context(fc);
    return success;
}
<|endoftext|>


<commit_before>#include "ompl/control/planners/syclop/Syclop.h"
#include "ompl/base/GoalState.h"
#include "ompl/base/ProblemDefinition.h"

ompl::control::Syclop::Syclop(const SpaceInformationPtr &si, Decomposition &d) :
    ompl::base::Planner(si, "Syclop"), decomp(d), graph(decomp.getNumRegions()), covGrid(COVGRID_LENGTH, 2, d)
{
}

ompl::control::Syclop::~Syclop()
{
}

void ompl::control::Syclop::setup(void)
{
    base::Planner::setup();
    buildGraph();
    //TODO: locate start and goal states
    const base::ProblemDefinitionPtr& pdef = getProblemDefinition();
    startRegion = decomp.locateRegion(pdef->getStartState(0));
    goalRegion = decomp.locateRegion(pdef->getGoal()->as<base::GoalState>()->state);
    std::cout << "start is " << startRegion << std::endl;
    std::cout << "goal is " << goalRegion << std::endl;
    setupRegionEstimates();
    updateRegionEstimates();
    updateEdgeEstimates();
    printRegions();
    printEdges();

    std::vector<Region*> lead;
    computeLead(lead);
    std::cerr << "Lead: ";
    for (int i = 0; i < lead.size(); ++i)
        std::cerr << lead[i] << " ";
    std::cerr << std::endl;
}

bool ompl::control::Syclop::solve(const base::PlannerTerminationCondition &ptc)
{
    return false;
}

void ompl::control::Syclop::printRegions(void)
{
    for (int i = 0; i < decomp.getNumRegions(); ++i)
    {
        Region& r = graph[boost::vertex(i, graph)];
        std::cout << "Region " << r.index << ": ";
        std::cout << "nselects=" << r.numSelections << ",";
        std::cout << "vol=" << r.volume << ",";
        std::cout << "freeVol=" << r.freeVolume << ",";
        std::cout << "pcentValid=" << r.percentValidCells << ",";
        std::cout << "numCells=" << r.covGridCells.size() << ",";
        std::cout << "weight=" << r.weight << ",";
        std::cout << "alpha=" << r.alpha << "";
        std::cout << std::endl;
    }
}

void ompl::control::Syclop::printEdges(void)
{
    EdgeIter ei, end;
    VertexIndexMap index = get(boost::vertex_index, graph);
    for (boost::tie(ei,end) = boost::edges(graph); ei != end; ++ei)
    {
        const Adjacency& a = graph[*ei];
        std::cout << "Edge (" << index[boost::source(*ei, graph)] << "," << index[boost::target(*ei, graph)] << "): ";
        std::cout << "numCells=" << a.covGridCells.size() << ",";
        std::cout << "nselects=" << a.numSelections << ",";
        std::cout << "cost=" << a.cost << std::endl;
    }
}

void ompl::control::Syclop::initEdge(Adjacency& a, Region* r, Region* s)
{
    a.regions.first = r;
    a.regions.second = s;
    a.numSelections = 0;
}

void ompl::control::Syclop::updateEdgeEstimates(void)
{
    EdgeIter ei, end;
    VertexIndexMap index = get(boost::vertex_index, graph);
    for (boost::tie(ei,end) = boost::edges(graph); ei != end; ++ei)
    {
        Adjacency& a = graph[*ei];
        a.cost = (1 + a.numSelections*a.numSelections) / (1 + a.covGridCells.size());
        a.cost *= a.regions.first->alpha * a.regions.second->alpha;
    }
}

void ompl::control::Syclop::initRegion(Region& r)
{
    r.numSelections = 0;
    r.volume = 1.0;
    r.percentValidCells = 1.0;
    r.freeVolume = 1.0;
}

void ompl::control::Syclop::setupRegionEstimates(void)
{
    std::vector<int> numTotal(decomp.getNumRegions(), 0);
    std::vector<int> numValid(decomp.getNumRegions(), 0);
    base::SpaceInformationPtr si = getSpaceInformation();
    base::StateValidityCheckerPtr checker = si->getStateValidityChecker();
    base::StateSamplerPtr sampler = si->allocStateSampler();
    base::State *s = si->allocState();
    for (int i = 0; i < NUM_FREEVOL_SAMPLES; ++i)
    {
        sampler->sampleUniform(s);
        int rid = decomp.locateRegion(s);
        if (checker->isValid(s))
            ++numValid[rid];
        ++numTotal[rid];
    }
    si->freeState(s);

    for (int i = 0; i < decomp.getNumRegions(); ++i)
    {
        Region& r = graph[boost::vertex(i, graph)];
        r.volume = decomp.getRegionVolume(i);
        r.percentValidCells = ((double) numValid[i]) / numTotal[i];
        r.freeVolume = r.percentValidCells * r.volume;
    }
}

void ompl::control::Syclop::updateCoverageEstimate(Region& r, const base::State *s)
{
    const int covCell = covGrid.locateRegion(s);
    r.covGridCells.insert(covCell);
}

void ompl::control::Syclop::updateConnectionEstimate(Adjacency& a, const base::State *s)
{
    const int covCell = covGrid.locateRegion(s);
    a.covGridCells.insert(covCell);
}

void ompl::control::Syclop::updateRegionEstimates(void)
{
    for (int i = 0; i < decomp.getNumRegions(); ++i)
    {
        Region& r = graph[boost::vertex(i, graph)];
        const double f = r.freeVolume*r.freeVolume*r.freeVolume*r.freeVolume;
        r.alpha = 1 / ((1 + r.covGridCells.size()) * f);
        r.weight = f / ((1 + r.covGridCells.size())*(1 + r.numSelections*r.numSelections));
    }
}

void ompl::control::Syclop::buildGraph(void)
{
    /* The below code builds a boost::graph corresponding to the decomposition.
        It creates Region and Adjacency property objects for each vertex and edge.
        TODO: Correctly initialize the fields for each Region and Adjacency object. */
    VertexIndexMap index = get(boost::vertex_index, graph);
    VertexIter vi, vend;
    std::vector<int> neighbors;
    //Iterate over all vertices.
    for (boost::tie(vi,vend) = boost::vertices(graph); vi != vend; ++vi)
    {
        /* Initialize this vertex's Region object. */
        initRegion(graph[*vi]);
        graph[*vi].index = index[*vi];
        /* Create an edge between this vertex and each of its neighboring regions in the decomposition,
            and initialize the edge's Adjacency object. */
        decomp.getNeighbors(index[*vi], neighbors);
        for (std::vector<int>::const_iterator j = neighbors.begin(); j != neighbors.end(); ++j)
        {
            RegionGraph::edge_descriptor edge;
            bool ignore;
            boost::tie(edge, ignore) = boost::add_edge(*vi, boost::vertex(*j,graph), graph);
            initEdge(graph[edge], &graph[*vi], &graph[boost::vertex(*j,graph)]);
        }
        neighbors.clear();
    }
}

void ompl::control::Syclop::computeLead(std::vector<Region*>& lead)
{
    if (rng.uniform01() < PROB_SHORTEST_PATH)
    {
        std::vector<RegionGraph::vertex_descriptor> parents(decomp.getNumRegions());
        std::vector<double> distances(decomp.getNumRegions());
        boost::dijkstra_shortest_paths(graph, boost::vertex(startRegion, graph),
            boost::weight_map(get(&Adjacency::cost, graph)).distance_map(
                boost::make_iterator_property_map(distances.begin(), get(boost::vertex_index, graph)
            )).predecessor_map(
                boost::make_iterator_property_map(parents.begin(), get(boost::vertex_index, graph))
            )
        );
        int region = goalRegion;
        int leadLength = 1;
        while (region != startRegion)
        {
            region = parents[region];
            ++leadLength;
        }
        lead.resize(leadLength);
        region = goalRegion;
        for (int i = leadLength-1; i >= 0; --i)
        {
            lead[i] = &graph[boost::vertex(region, graph)];
            region = parents[region];
        }
    }
    //TODO Implement random DFS, in case of 1-PROB_SHORTEST_PATH
}

int ompl::control::Syclop::selectRegion(const std::set<int>& avail)
{
    return -1;
}

void ompl::control::Syclop::computeAvailableRegions(const std::vector<Region*>& lead, std::set<Region*>& avail)
{
    avail.clear();
    for (int i = lead.size()-1; i >= 0; --i)
    {
        if (!lead[i]->states.empty())
        {
            avail.insert(lead[i]);
            if (rng.uniform01() >= PROB_KEEP_ADDING_TO_AVAIL)
                return;
        }
    }
}
<commit_msg>start and goal states now get added to corresponding regions in graph<commit_after>#include "ompl/control/planners/syclop/Syclop.h"
#include "ompl/base/GoalState.h"
#include "ompl/base/ProblemDefinition.h"

ompl::control::Syclop::Syclop(const SpaceInformationPtr &si, Decomposition &d) :
    ompl::base::Planner(si, "Syclop"), decomp(d), graph(decomp.getNumRegions()), covGrid(COVGRID_LENGTH, 2, d)
{
}

ompl::control::Syclop::~Syclop()
{
}

void ompl::control::Syclop::setup(void)
{
    base::Planner::setup();
    buildGraph();
    //TODO: locate start and goal states
    const base::ProblemDefinitionPtr& pdef = getProblemDefinition();
    const base::State *start = pdef->getStartState(0);
    //Here we are temporarily assuming that the goal is of type GoalState
    const base::State *goal = pdef->getGoal()->as<base::GoalState>()->state;
    startRegion = decomp.locateRegion(start);
    goalRegion = decomp.locateRegion(goal);
    graph[boost::vertex(startRegion,graph)].states.insert(start);
    graph[boost::vertex(goalRegion,graph)].states.insert(goal);

    std::cout << "start is " << startRegion << std::endl;
    std::cout << "goal is " << goalRegion << std::endl;
    setupRegionEstimates();
    updateRegionEstimates();
    updateEdgeEstimates();
    printRegions();
    printEdges();

    std::vector<Region*> lead;
    computeLead(lead);
    std::cerr << "Lead: ";
    for (int i = 0; i < lead.size(); ++i)
        std::cerr << lead[i] << " ";
    std::cerr << std::endl;
}

bool ompl::control::Syclop::solve(const base::PlannerTerminationCondition &ptc)
{
    return false;
}

void ompl::control::Syclop::printRegions(void)
{
    for (int i = 0; i < decomp.getNumRegions(); ++i)
    {
        Region& r = graph[boost::vertex(i, graph)];
        std::cout << "Region " << r.index << ": ";
        std::cout << "nselects=" << r.numSelections << ",";
        std::cout << "vol=" << r.volume << ",";
        std::cout << "freeVol=" << r.freeVolume << ",";
        std::cout << "pcentValid=" << r.percentValidCells << ",";
        std::cout << "numCells=" << r.covGridCells.size() << ",";
        std::cout << "weight=" << r.weight << ",";
        std::cout << "alpha=" << r.alpha << "";
        std::cout << std::endl;
    }
}

void ompl::control::Syclop::printEdges(void)
{
    EdgeIter ei, end;
    VertexIndexMap index = get(boost::vertex_index, graph);
    for (boost::tie(ei,end) = boost::edges(graph); ei != end; ++ei)
    {
        const Adjacency& a = graph[*ei];
        std::cout << "Edge (" << index[boost::source(*ei, graph)] << "," << index[boost::target(*ei, graph)] << "): ";
        std::cout << "numCells=" << a.covGridCells.size() << ",";
        std::cout << "nselects=" << a.numSelections << ",";
        std::cout << "cost=" << a.cost << std::endl;
    }
}

void ompl::control::Syclop::initEdge(Adjacency& a, Region* r, Region* s)
{
    a.regions.first = r;
    a.regions.second = s;
    a.numSelections = 0;
}

void ompl::control::Syclop::updateEdgeEstimates(void)
{
    EdgeIter ei, end;
    VertexIndexMap index = get(boost::vertex_index, graph);
    for (boost::tie(ei,end) = boost::edges(graph); ei != end; ++ei)
    {
        Adjacency& a = graph[*ei];
        a.cost = (1 + a.numSelections*a.numSelections) / (1 + a.covGridCells.size());
        a.cost *= a.regions.first->alpha * a.regions.second->alpha;
    }
}

void ompl::control::Syclop::initRegion(Region& r)
{
    r.numSelections = 0;
    r.volume = 1.0;
    r.percentValidCells = 1.0;
    r.freeVolume = 1.0;
}

void ompl::control::Syclop::setupRegionEstimates(void)
{
    std::vector<int> numTotal(decomp.getNumRegions(), 0);
    std::vector<int> numValid(decomp.getNumRegions(), 0);
    base::SpaceInformationPtr si = getSpaceInformation();
    base::StateValidityCheckerPtr checker = si->getStateValidityChecker();
    base::StateSamplerPtr sampler = si->allocStateSampler();
    base::State *s = si->allocState();
    for (int i = 0; i < NUM_FREEVOL_SAMPLES; ++i)
    {
        sampler->sampleUniform(s);
        int rid = decomp.locateRegion(s);
        if (checker->isValid(s))
            ++numValid[rid];
        ++numTotal[rid];
    }
    si->freeState(s);

    for (int i = 0; i < decomp.getNumRegions(); ++i)
    {
        Region& r = graph[boost::vertex(i, graph)];
        r.volume = decomp.getRegionVolume(i);
        r.percentValidCells = ((double) numValid[i]) / numTotal[i];
        r.freeVolume = r.percentValidCells * r.volume;
    }
}

void ompl::control::Syclop::updateCoverageEstimate(Region& r, const base::State *s)
{
    const int covCell = covGrid.locateRegion(s);
    r.covGridCells.insert(covCell);
}

void ompl::control::Syclop::updateConnectionEstimate(Adjacency& a, const base::State *s)
{
    const int covCell = covGrid.locateRegion(s);
    a.covGridCells.insert(covCell);
}

void ompl::control::Syclop::updateRegionEstimates(void)
{
    for (int i = 0; i < decomp.getNumRegions(); ++i)
    {
        Region& r = graph[boost::vertex(i, graph)];
        const double f = r.freeVolume*r.freeVolume*r.freeVolume*r.freeVolume;
        r.alpha = 1 / ((1 + r.covGridCells.size()) * f);
        r.weight = f / ((1 + r.covGridCells.size())*(1 + r.numSelections*r.numSelections));
    }
}

void ompl::control::Syclop::buildGraph(void)
{
    /* The below code builds a boost::graph corresponding to the decomposition.
        It creates Region and Adjacency property objects for each vertex and edge.
        TODO: Correctly initialize the fields for each Region and Adjacency object. */
    VertexIndexMap index = get(boost::vertex_index, graph);
    VertexIter vi, vend;
    std::vector<int> neighbors;
    //Iterate over all vertices.
    for (boost::tie(vi,vend) = boost::vertices(graph); vi != vend; ++vi)
    {
        /* Initialize this vertex's Region object. */
        initRegion(graph[*vi]);
        graph[*vi].index = index[*vi];
        /* Create an edge between this vertex and each of its neighboring regions in the decomposition,
            and initialize the edge's Adjacency object. */
        decomp.getNeighbors(index[*vi], neighbors);
        for (std::vector<int>::const_iterator j = neighbors.begin(); j != neighbors.end(); ++j)
        {
            RegionGraph::edge_descriptor edge;
            bool ignore;
            boost::tie(edge, ignore) = boost::add_edge(*vi, boost::vertex(*j,graph), graph);
            initEdge(graph[edge], &graph[*vi], &graph[boost::vertex(*j,graph)]);
        }
        neighbors.clear();
    }
}

void ompl::control::Syclop::computeLead(std::vector<Region*>& lead)
{
    if (rng.uniform01() < PROB_SHORTEST_PATH)
    {
        std::vector<RegionGraph::vertex_descriptor> parents(decomp.getNumRegions());
        std::vector<double> distances(decomp.getNumRegions());
        boost::dijkstra_shortest_paths(graph, boost::vertex(startRegion, graph),
            boost::weight_map(get(&Adjacency::cost, graph)).distance_map(
                boost::make_iterator_property_map(distances.begin(), get(boost::vertex_index, graph)
            )).predecessor_map(
                boost::make_iterator_property_map(parents.begin(), get(boost::vertex_index, graph))
            )
        );
        int region = goalRegion;
        int leadLength = 1;
        while (region != startRegion)
        {
            region = parents[region];
            ++leadLength;
        }
        lead.resize(leadLength);
        region = goalRegion;
        for (int i = leadLength-1; i >= 0; --i)
        {
            lead[i] = &graph[boost::vertex(region, graph)];
            region = parents[region];
        }
    }
    //TODO Implement random DFS, in case of 1-PROB_SHORTEST_PATH
}

int ompl::control::Syclop::selectRegion(const std::set<int>& avail)
{
    return -1;
}

void ompl::control::Syclop::computeAvailableRegions(const std::vector<Region*>& lead, std::set<Region*>& avail)
{
    avail.clear();
    for (int i = lead.size()-1; i >= 0; --i)
    {
        if (!lead[i]->states.empty())
        {
            avail.insert(lead[i]);
            if (rng.uniform01() >= PROB_KEEP_ADDING_TO_AVAIL)
                return;
        }
    }
}
<|endoftext|>


<commit_before>#ifndef MJOLNIR_OMP_SYSTEM_HPP
#define MJOLNIR_OMP_SYSTEM_HPP
#include <mjolnir/util/aligned_allocator.hpp>
#include <mjolnir/core/System.hpp>
#include <mjolnir/omp/OpenMPSimulatorTraits.hpp>

namespace mjolnir
{

template<typename realT, template<typename, typename> class boundaryT>
class System<OpenMPSimulatorTraits<realT, boundaryT>>
{
  public:
    using traits_type     = OpenMPSimulatorTraits<realT, boundaryT>;
    using real_type       = typename traits_type::real_type;
    using coordinate_type = typename traits_type::coordinate_type;
    using boundary_type   = typename traits_type::boundary_type;
    using topology_type   = Topology;
    using attribute_type  = std::map<std::string, real_type>;
    using rng_type        = RandomNumberGenerator<traits_type>;

    using string_type              = std::string;
    using particle_type            = Particle<real_type, coordinate_type>;
    using particle_view_type       = ParticleView<real_type, coordinate_type>;
    using particle_const_view_type = ParticleConstView<real_type, coordinate_type>;

    using real_container_type          = std::vector<real_type>;
    using coordinate_container_type    = std::vector<coordinate_type>;

    static constexpr std::size_t cache_alignment = 64;

    template<typename T>
    using cache_aligned_allocator = aligned_allocator<T, cache_alignment>;

  public:

    System(const std::size_t num_particles, const boundary_type& bound)
        : velocity_initialized_(false), boundary_(bound),
          topology_(num_particles), attributes_(), num_particles_(num_particles),
          masses_   (num_particles), rmasses_   (num_particles),
          positions_(num_particles), velocities_(num_particles),
          forces_master_(num_particles),
          forces_threads_(omp_get_max_threads(),
              coordinate_container_type(num_particles),
              cache_aligned_allocator<coordinate_container_type>{})
    {}
    ~System() = default;

    void initialize(rng_type& rng)
    {
        MJOLNIR_GET_DEFAULT_LOGGER();
        MJOLNIR_LOG_FUNCTION();

        if(this->velocity_initialized_)
        {
            MJOLNIR_LOG_NOTICE(
                "velocity is already given, nothing to initialize in System");
            return ;
        }
        assert(this->has_attribute("temperature"));

        const real_type kB    = physics::constants<real_type>::kB();
        const real_type T_ref = this->attribute("temperature");

        MJOLNIR_LOG_NOTICE("generating velocity with T = ", T_ref, "...");

        // generate Maxwell-Boltzmann distribution
        const real_type kBT = kB * T_ref;
        for(std::size_t i=0; i<this->size(); ++i)
        {
            const auto vel_coef = std::sqrt(kBT / this->mass(i));
            math::X(this->velocity(i)) = rng.gaussian(0, vel_coef);
            math::Y(this->velocity(i)) = rng.gaussian(0, vel_coef);
            math::Z(this->velocity(i)) = rng.gaussian(0, vel_coef);
        }
        MJOLNIR_LOG_NOTICE("done.");
        return;
    }

    coordinate_type adjust_direction(coordinate_type dr) const noexcept
    {return boundary_.adjust_direction(dr);}
    coordinate_type  adjust_position(coordinate_type dr) const noexcept
    {return boundary_.adjust_position(dr);}

    std::size_t size() const noexcept {return num_particles_;}

    particle_view_type operator[](std::size_t i) noexcept
    {
        return particle_view_type{
            masses_[i],    rmasses_[i],
            positions_[i], velocities_[i], forces_master_[i],
            this->topology_.name_of (i, std::nothrow),
            this->topology_.group_of(i, std::nothrow)
        };
    }
    particle_const_view_type operator[](std::size_t i) const noexcept
    {
        return particle_const_view_type{
            masses_[i],    rmasses_[i],
            positions_[i], velocities_[i], forces_master_[i],
            this->topology_.name_of (i, std::nothrow),
            this->topology_.group_of(i, std::nothrow)
        };
    }
    particle_view_type at(std::size_t i)
    {
        return particle_view_type{
            masses_.at(i),    rmasses_.at(i),
            positions_.at(i), velocities_.at(i), forces_master_.at(i),
            topology_.name_of(i), topology_.group_of(i)
        };
    }
    particle_const_view_type at(std::size_t i) const
    {
        return particle_const_view_type{
            masses_.at(i),    rmasses_.at(i),
            positions_.at(i), velocities_.at(i), forces_master_.at(i),
            topology_.name_of(i), topology_.group_of(i)
        };
    }

    real_type  mass (std::size_t i) const noexcept {return masses_[i];}
    real_type& mass (std::size_t i)       noexcept {return masses_[i];}
    real_type  rmass(std::size_t i) const noexcept {return rmasses_[i];}
    real_type& rmass(std::size_t i)       noexcept {return rmasses_[i];}

    coordinate_type const& position(std::size_t i) const noexcept {return positions_[i];}
    coordinate_type&       position(std::size_t i)       noexcept {return positions_[i];}
    coordinate_type const& velocity(std::size_t i) const noexcept {return velocities_[i];}
    coordinate_type&       velocity(std::size_t i)       noexcept {return velocities_[i];}
    coordinate_type const& force   (std::size_t i) const noexcept {return forces_master_[i];}
    coordinate_type&       force   (std::size_t i)       noexcept {return forces_master_[i];}

    coordinate_type const&
    force_thread(std::size_t thread_num, std::size_t particle_id) const noexcept
    {
        return forces_threads_[thread_num][particle_id];
    }
    coordinate_type&
    force_thread(std::size_t thread_num, std::size_t particle_id)       noexcept
    {
        return forces_threads_[thread_num][particle_id];
    }

    void merge_forces() noexcept
    {
#pragma omp parallel for
        for(std::size_t i=0; i<this->size(); ++i)
        {
            // sumup all the thread-local forces into the main force.
            // XXX: keep the values in the main force! Some pre-omp interactions
            //      may write its force in it. Clearing main force is a task
            //      for Integrators.
            for(std::size_t thread_id=0, max_threads=omp_get_max_threads();
                    thread_id < max_threads; ++thread_id)
            {
                this->force(i) += this->force_thread(thread_id, i);
                this->force_thread(thread_id, i) =
                    math::make_coordinate<coordinate_type>(0, 0, 0);
            }
        }
        return;
    }

    string_type const& name (std::size_t i) const noexcept {return topology_.name_of(i, std::nothrow);}
    string_type&       name (std::size_t i)       noexcept {return topology_.name_of(i, std::nothrow);}
    string_type const& group(std::size_t i) const noexcept {return topology_.group_of(i, std::nothrow);}
    string_type&       group(std::size_t i)       noexcept {return topology_.group_of(i, std::nothrow);}

    boundary_type&       boundary()       noexcept {return boundary_;}
    boundary_type const& boundary() const noexcept {return boundary_;}
    topology_type&       topology()       noexcept {return topology_;}
    topology_type const& topology() const noexcept {return topology_;}

    // system attributes like `reference temperature`, `ionic strength`, ...
    // assuming it will not be called so often.
    real_type  attribute(const std::string& key) const {return attributes_.at(key);}
    real_type& attribute(const std::string& key)       {return attributes_[key];}
    bool   has_attribute(const std::string& key) const {return attributes_.count(key) == 1;}

    bool  velocity_initialized() const noexcept {return velocity_initialized_;}
    bool& velocity_initialized()       noexcept {return velocity_initialized_;}

  private:

    bool           velocity_initialized_;
    boundary_type  boundary_;
    topology_type  topology_;
    attribute_type attributes_;

    std::size_t                  num_particles_;
    real_container_type          masses_;
    real_container_type          rmasses_; // r for reciprocal
    coordinate_container_type    positions_;
    coordinate_container_type    velocities_;
    coordinate_container_type    forces_master_;
    // thread-local forces
    std::vector<coordinate_container_type,
                cache_aligned_allocator<coordinate_container_type>
        > forces_threads_;

    // names and groups are in Topology class
};

#ifdef MJOLNIR_SEPARATE_BUILD
extern template class System<OpenMPSimulatorTraits<double, UnlimitedBoundary>>;
extern template class System<OpenMPSimulatorTraits<float,  UnlimitedBoundary>>;
extern template class System<OpenMPSimulatorTraits<double, CuboidalPeriodicBoundary>>;
extern template class System<OpenMPSimulatorTraits<float,  CuboidalPeriodicBoundary>>;
#endif

} // mjolnir
#endif// MJOLNIR_SYSTEM_HPP
<commit_msg>fix: add missing include file<commit_after>#ifndef MJOLNIR_OMP_SYSTEM_HPP
#define MJOLNIR_OMP_SYSTEM_HPP
#include <mjolnir/util/aligned_allocator.hpp>
#include <mjolnir/omp/RandomNumberGenerator.hpp>
#include <mjolnir/core/System.hpp>
#include <mjolnir/omp/OpenMPSimulatorTraits.hpp>

namespace mjolnir
{

template<typename realT, template<typename, typename> class boundaryT>
class System<OpenMPSimulatorTraits<realT, boundaryT>>
{
  public:
    using traits_type     = OpenMPSimulatorTraits<realT, boundaryT>;
    using real_type       = typename traits_type::real_type;
    using coordinate_type = typename traits_type::coordinate_type;
    using boundary_type   = typename traits_type::boundary_type;
    using topology_type   = Topology;
    using attribute_type  = std::map<std::string, real_type>;
    using rng_type        = RandomNumberGenerator<traits_type>;

    using string_type              = std::string;
    using particle_type            = Particle<real_type, coordinate_type>;
    using particle_view_type       = ParticleView<real_type, coordinate_type>;
    using particle_const_view_type = ParticleConstView<real_type, coordinate_type>;

    using real_container_type          = std::vector<real_type>;
    using coordinate_container_type    = std::vector<coordinate_type>;

    static constexpr std::size_t cache_alignment = 64;

    template<typename T>
    using cache_aligned_allocator = aligned_allocator<T, cache_alignment>;

  public:

    System(const std::size_t num_particles, const boundary_type& bound)
        : velocity_initialized_(false), boundary_(bound),
          topology_(num_particles), attributes_(), num_particles_(num_particles),
          masses_   (num_particles), rmasses_   (num_particles),
          positions_(num_particles), velocities_(num_particles),
          forces_master_(num_particles),
          forces_threads_(omp_get_max_threads(),
              coordinate_container_type(num_particles),
              cache_aligned_allocator<coordinate_container_type>{})
    {}
    ~System() = default;

    void initialize(rng_type& rng)
    {
        MJOLNIR_GET_DEFAULT_LOGGER();
        MJOLNIR_LOG_FUNCTION();

        if(this->velocity_initialized_)
        {
            MJOLNIR_LOG_NOTICE(
                "velocity is already given, nothing to initialize in System");
            return ;
        }
        assert(this->has_attribute("temperature"));

        const real_type kB    = physics::constants<real_type>::kB();
        const real_type T_ref = this->attribute("temperature");

        MJOLNIR_LOG_NOTICE("generating velocity with T = ", T_ref, "...");

        // generate Maxwell-Boltzmann distribution
        const real_type kBT = kB * T_ref;
        for(std::size_t i=0; i<this->size(); ++i)
        {
            const auto vel_coef = std::sqrt(kBT / this->mass(i));
            math::X(this->velocity(i)) = rng.gaussian(0, vel_coef);
            math::Y(this->velocity(i)) = rng.gaussian(0, vel_coef);
            math::Z(this->velocity(i)) = rng.gaussian(0, vel_coef);
        }
        MJOLNIR_LOG_NOTICE("done.");
        return;
    }

    coordinate_type adjust_direction(coordinate_type dr) const noexcept
    {return boundary_.adjust_direction(dr);}
    coordinate_type  adjust_position(coordinate_type dr) const noexcept
    {return boundary_.adjust_position(dr);}

    std::size_t size() const noexcept {return num_particles_;}

    particle_view_type operator[](std::size_t i) noexcept
    {
        return particle_view_type{
            masses_[i],    rmasses_[i],
            positions_[i], velocities_[i], forces_master_[i],
            this->topology_.name_of (i, std::nothrow),
            this->topology_.group_of(i, std::nothrow)
        };
    }
    particle_const_view_type operator[](std::size_t i) const noexcept
    {
        return particle_const_view_type{
            masses_[i],    rmasses_[i],
            positions_[i], velocities_[i], forces_master_[i],
            this->topology_.name_of (i, std::nothrow),
            this->topology_.group_of(i, std::nothrow)
        };
    }
    particle_view_type at(std::size_t i)
    {
        return particle_view_type{
            masses_.at(i),    rmasses_.at(i),
            positions_.at(i), velocities_.at(i), forces_master_.at(i),
            topology_.name_of(i), topology_.group_of(i)
        };
    }
    particle_const_view_type at(std::size_t i) const
    {
        return particle_const_view_type{
            masses_.at(i),    rmasses_.at(i),
            positions_.at(i), velocities_.at(i), forces_master_.at(i),
            topology_.name_of(i), topology_.group_of(i)
        };
    }

    real_type  mass (std::size_t i) const noexcept {return masses_[i];}
    real_type& mass (std::size_t i)       noexcept {return masses_[i];}
    real_type  rmass(std::size_t i) const noexcept {return rmasses_[i];}
    real_type& rmass(std::size_t i)       noexcept {return rmasses_[i];}

    coordinate_type const& position(std::size_t i) const noexcept {return positions_[i];}
    coordinate_type&       position(std::size_t i)       noexcept {return positions_[i];}
    coordinate_type const& velocity(std::size_t i) const noexcept {return velocities_[i];}
    coordinate_type&       velocity(std::size_t i)       noexcept {return velocities_[i];}
    coordinate_type const& force   (std::size_t i) const noexcept {return forces_master_[i];}
    coordinate_type&       force   (std::size_t i)       noexcept {return forces_master_[i];}

    coordinate_type const&
    force_thread(std::size_t thread_num, std::size_t particle_id) const noexcept
    {
        return forces_threads_[thread_num][particle_id];
    }
    coordinate_type&
    force_thread(std::size_t thread_num, std::size_t particle_id)       noexcept
    {
        return forces_threads_[thread_num][particle_id];
    }

    void merge_forces() noexcept
    {
#pragma omp parallel for
        for(std::size_t i=0; i<this->size(); ++i)
        {
            // sumup all the thread-local forces into the main force.
            // XXX: keep the values in the main force! Some pre-omp interactions
            //      may write its force in it. Clearing main force is a task
            //      for Integrators.
            for(std::size_t thread_id=0, max_threads=omp_get_max_threads();
                    thread_id < max_threads; ++thread_id)
            {
                this->force(i) += this->force_thread(thread_id, i);
                this->force_thread(thread_id, i) =
                    math::make_coordinate<coordinate_type>(0, 0, 0);
            }
        }
        return;
    }

    string_type const& name (std::size_t i) const noexcept {return topology_.name_of(i, std::nothrow);}
    string_type&       name (std::size_t i)       noexcept {return topology_.name_of(i, std::nothrow);}
    string_type const& group(std::size_t i) const noexcept {return topology_.group_of(i, std::nothrow);}
    string_type&       group(std::size_t i)       noexcept {return topology_.group_of(i, std::nothrow);}

    boundary_type&       boundary()       noexcept {return boundary_;}
    boundary_type const& boundary() const noexcept {return boundary_;}
    topology_type&       topology()       noexcept {return topology_;}
    topology_type const& topology() const noexcept {return topology_;}

    // system attributes like `reference temperature`, `ionic strength`, ...
    // assuming it will not be called so often.
    real_type  attribute(const std::string& key) const {return attributes_.at(key);}
    real_type& attribute(const std::string& key)       {return attributes_[key];}
    bool   has_attribute(const std::string& key) const {return attributes_.count(key) == 1;}

    bool  velocity_initialized() const noexcept {return velocity_initialized_;}
    bool& velocity_initialized()       noexcept {return velocity_initialized_;}

  private:

    bool           velocity_initialized_;
    boundary_type  boundary_;
    topology_type  topology_;
    attribute_type attributes_;

    std::size_t                  num_particles_;
    real_container_type          masses_;
    real_container_type          rmasses_; // r for reciprocal
    coordinate_container_type    positions_;
    coordinate_container_type    velocities_;
    coordinate_container_type    forces_master_;
    // thread-local forces
    std::vector<coordinate_container_type,
                cache_aligned_allocator<coordinate_container_type>
        > forces_threads_;

    // names and groups are in Topology class
};

#ifdef MJOLNIR_SEPARATE_BUILD
extern template class System<OpenMPSimulatorTraits<double, UnlimitedBoundary>>;
extern template class System<OpenMPSimulatorTraits<float,  UnlimitedBoundary>>;
extern template class System<OpenMPSimulatorTraits<double, CuboidalPeriodicBoundary>>;
extern template class System<OpenMPSimulatorTraits<float,  CuboidalPeriodicBoundary>>;
#endif

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